From a30e220dcc21ac98860e8990bb41db51b7583975 Mon Sep 17 00:00:00 2001 From: Patrick Sullivan Date: Mon, 2 Mar 2026 11:00:17 -0800 Subject: [PATCH] @W-21386533 MCP MRT Push now uses correct defaults based on detected project type --- .changeset/early-clubs-eat.md | 6 + docs/mcp/tools/mrt-bundle-push.md | 28 ++- packages/b2c-dx-mcp/src/tools/mrt/index.ts | 131 +++++++++- .../b2c-dx-mcp/test/tools/mrt/index.test.ts | 225 ++++++++++++++++-- 4 files changed, 364 insertions(+), 26 deletions(-) create mode 100644 .changeset/early-clubs-eat.md diff --git a/.changeset/early-clubs-eat.md b/.changeset/early-clubs-eat.md new file mode 100644 index 00000000..caa173e0 --- /dev/null +++ b/.changeset/early-clubs-eat.md @@ -0,0 +1,6 @@ +--- +'@salesforce/b2c-dx-mcp': patch +'@salesforce/b2c-dx-docs': patch +--- + +MCP MRT Push now uses correct defaults based on detected project type diff --git a/docs/mcp/tools/mrt-bundle-push.md b/docs/mcp/tools/mrt-bundle-push.md index 66d15dca..d5c2aa94 100644 --- a/docs/mcp/tools/mrt-bundle-push.md +++ b/docs/mcp/tools/mrt-bundle-push.md @@ -30,14 +30,38 @@ Requires Managed Runtime (MRT) credentials. See [MRT Credentials](../configurati ## Parameters +Defaults for `buildDirectory`, `ssrOnly`, and `ssrShared` are chosen by detected project type (Storefront Next, PWA Kit v3, or generic). Explicit parameters override the project-type defaults. + | Parameter | Type | Required | Default | Description | |-----------|------|----------|---------|-------------| | `buildDirectory` | string | No | `./build` | Path to build directory containing the built project files. Can be absolute or relative to the project directory. | | `message` | string | No | None | Deployment message to include with the bundle push. Useful for tracking deployments. | -| `ssrOnly` | string | No | `ssr.js,ssr.mjs,server/**/*` | Comma-separated glob patterns for server-only files (SSR). These files are only included in the server bundle. | -| `ssrShared` | string | No | `static/**/*,client/**/*` | Comma-separated glob patterns for shared files. These files are included in both server and client bundles. | +| `ssrOnly` | string | No | Varies by project type | Glob patterns for server-only files (SSR), comma-separated or JSON array. These files are only included in the server bundle. | +| `ssrShared` | string | No | Varies by project type | Glob patterns for shared files, comma-separated or JSON array. These files are included in both server and client bundles. | | `deploy` | boolean | No | `false` | Whether to deploy to an environment after push. When `true`, `environment` must be provided via `--environment` flag or `MRT_ENVIRONMENT`. | +### Default values by project type + +When `buildDirectory`, `ssrOnly`, or `ssrShared` are omitted, the tool detects the project type and applies these defaults: + +**Generic** (used when no project type is detected; matches CLI `b2c mrt bundle deploy` defaults): + +- `buildDirectory`: `./build` +- `ssrOnly`: `ssr.js`, `ssr.mjs`, `server/**/*` +- `ssrShared`: `static/**/*`, `client/**/*` + +**PWA Kit v3**: + +- `buildDirectory`: `./build` +- `ssrOnly`: `ssr.js`, `ssr.js.map`, `node_modules/**/*.*` +- `ssrShared`: `static/ico/favicon.ico`, `static/robots.txt`, `**/*.js`, `**/*.js.map`, `**/*.json` + +**Storefront Next**: + +- `buildDirectory`: `./build` +- `ssrOnly`: `server/**/*`, `loader.js`, `streamingHandler.{js,mjs,cjs}`, `streamingHandler.{js,mjs,cjs}.map`, `ssr.{js,mjs,cjs}`, `ssr.{js,mjs,cjs}.map`, `!static/**/*`, `sfnext-server-*.mjs`, plus exclusions for Storybook and test files +- `ssrShared`: `client/**/*`, `static/**/*`, `**/*.css`, image/font extensions, plus exclusions for Storybook and test files + ## Usage Examples ### Push Bundle Only diff --git a/packages/b2c-dx-mcp/src/tools/mrt/index.ts b/packages/b2c-dx-mcp/src/tools/mrt/index.ts index 9a599425..a70bddde 100644 --- a/packages/b2c-dx-mcp/src/tools/mrt/index.ts +++ b/packages/b2c-dx-mcp/src/tools/mrt/index.ts @@ -19,8 +19,106 @@ import {createToolAdapter, jsonResult} from '../adapter.js'; import {pushBundle} from '@salesforce/b2c-tooling-sdk/operations/mrt'; import type {PushResult, PushOptions} from '@salesforce/b2c-tooling-sdk/operations/mrt'; import type {AuthStrategy} from '@salesforce/b2c-tooling-sdk/auth'; +import {detectWorkspaceType, type ProjectType} from '@salesforce/b2c-tooling-sdk/discovery'; import {getLogger} from '@salesforce/b2c-tooling-sdk/logging'; +/** + * Parses a glob pattern string into an array of patterns. + * Accepts either a JSON array (e.g. '["server/**\/*", "ssr.{js,mjs}"]') + * or a comma-separated string (e.g. 'server/**\/*,ssr.js'). + * JSON array format supports brace expansion in individual patterns. + */ +function parseGlobPatterns(value: string): string[] { + const trimmed = value.trim(); + if (trimmed.startsWith('[')) { + const parsed: unknown = JSON.parse(trimmed); + if (!Array.isArray(parsed) || !parsed.every((item) => typeof item === 'string')) { + throw new Error('Invalid glob pattern array: expected an array of strings'); + } + return parsed.map((s: string) => (s as string).trim()).filter(Boolean); + } + return trimmed + .split(',') + .map((s) => s.trim()) + .filter(Boolean); +} + +interface MrtDefaults { + ssrOnly: string[]; + ssrShared: string[]; + buildDirectory: string; +} + +const MRT_DEFAULTS: Record<'default' | 'pwa-kit-v3' | 'storefront-next', MrtDefaults> = { + 'storefront-next': { + // ssrEntryPoint is 'streamingHandler' (production + MRT_BUNDLE_TYPE!=='ssr') or 'ssr' otherwise. + // Include both patterns so the bundle works regardless of MRT_BUNDLE_TYPE / mode. + ssrOnly: [ + 'server/**/*', + 'loader.js', + 'streamingHandler.{js,mjs,cjs}', + 'streamingHandler.{js,mjs,cjs}.map', + 'ssr.{js,mjs,cjs}', + 'ssr.{js,mjs,cjs}.map', + '!static/**/*', + 'sfnext-server-*.mjs', + '!**/*.stories.tsx', + '!**/*.stories.ts', + '!**/*-snapshot.tsx', + '!.storybook/**/*', + '!storybook-static/**/*', + '!**/__mocks__/**/*', + '!**/__snapshots__/**/*', + ], + ssrShared: [ + 'client/**/*', + 'static/**/*', + '**/*.css', + '**/*.png', + '**/*.jpg', + '**/*.jpeg', + '**/*.gif', + '**/*.svg', + '**/*.ico', + '**/*.woff', + '**/*.woff2', + '**/*.ttf', + '**/*.eot', + '!**/*.stories.tsx', + '!**/*.stories.ts', + '!**/*-snapshot.tsx', + '!.storybook/**/*', + '!storybook-static/**/*', + '!**/__mocks__/**/*', + '!**/__snapshots__/**/*', + ], + buildDirectory: 'build', + }, + 'pwa-kit-v3': { + ssrOnly: ['ssr.js', 'ssr.js.map', 'node_modules/**/*.*'], + ssrShared: ['static/ico/favicon.ico', 'static/robots.txt', '**/*.js', '**/*.js.map', '**/*.json'], + buildDirectory: 'build', + }, + default: { + ssrOnly: ['ssr.js', 'ssr.mjs', 'server/**/*'], + ssrShared: ['static/**/*', 'client/**/*'], + buildDirectory: 'build', + }, +}; + +/** + * Returns MRT bundle defaults for the given project types. + * For hybrid projects (multiple types detected), prefers storefront-next over pwa-kit-v3. + * + * @param projectTypes - Detected project types from workspace discovery + * @returns Defaults for ssrOnly, ssrShared, and buildDirectory + */ +function getDefaultsForProjectTypes(projectTypes: ProjectType[]): MrtDefaults { + if (projectTypes.includes('storefront-next')) return MRT_DEFAULTS['storefront-next']; + if (projectTypes.includes('pwa-kit-v3')) return MRT_DEFAULTS['pwa-kit-v3']; + return MRT_DEFAULTS.default; +} + /** * Input type for mrt_bundle_push tool. */ @@ -43,6 +141,8 @@ interface MrtBundlePushInput { interface MrtToolInjections { /** Mock pushBundle function for testing */ pushBundle?: (options: PushOptions, auth: AuthStrategy) => Promise; + /** Mock detectWorkspaceType function for testing */ + detectWorkspaceType?: (path: string) => Promise<{projectTypes: ProjectType[]}>; } /** @@ -59,6 +159,7 @@ interface MrtToolInjections { */ function createMrtBundlePushTool(loadServices: () => Services, injections?: MrtToolInjections): McpTool { const pushBundleFn = injections?.pushBundle || pushBundle; + const detectWorkspaceTypeFn = injections?.detectWorkspaceType ?? detectWorkspaceType; return createToolAdapter( { name: 'mrt_bundle_push', @@ -69,16 +170,25 @@ function createMrtBundlePushTool(loadServices: () => Services, injections?: MrtT // MRT operations use ApiKeyStrategy from MRT_API_KEY or ~/.mobify requiresMrtAuth: true, inputSchema: { - buildDirectory: z.string().optional().describe('Path to build directory (default: ./build)'), + buildDirectory: z + .string() + .optional() + .describe( + 'Path to build directory. Defaults vary by project type: Storefront Next, PWA Kit v3, or generic (./build).', + ), message: z.string().optional().describe('Deployment message'), ssrOnly: z .string() .optional() - .describe('Glob patterns for server-only files, comma-separated (default: ssr.js,ssr.mjs,server/**/*)'), + .describe( + 'Glob patterns for server-only files (comma-separated or JSON array). Defaults vary by project type: Storefront Next, PWA Kit v3, or generic.', + ), ssrShared: z .string() .optional() - .describe('Glob patterns for shared files, comma-separated (default: static/**/*,client/**/*)'), + .describe( + 'Glob patterns for shared files (comma-separated or JSON array). Defaults vary by project type: Storefront Next, PWA Kit v3, or generic.', + ), deploy: z .boolean() .optional() @@ -111,10 +221,16 @@ function createMrtBundlePushTool(loadServices: () => Services, injections?: MrtT // Get origin from --cloud-origin flag or mrtOrigin config (optional) const origin = context.mrtConfig?.origin; - // Parse comma-separated glob patterns (same as CLI defaults) - const ssrOnly = (args.ssrOnly || 'ssr.js,ssr.mjs,server/**/*').split(',').map((s) => s.trim()); - const ssrShared = (args.ssrShared || 'static/**/*,client/**/*').split(',').map((s) => s.trim()); - const buildDirectory = context.services.resolveWithProjectDirectory(args.buildDirectory || 'build'); + // Detect project type and get project-type-aware defaults + const projectDir = context.services.resolveWithProjectDirectory(); + const {projectTypes} = await detectWorkspaceTypeFn(projectDir); + const defaults = getDefaultsForProjectTypes(projectTypes); + + const ssrOnly = args.ssrOnly ? parseGlobPatterns(args.ssrOnly) : defaults.ssrOnly; + const ssrShared = args.ssrShared ? parseGlobPatterns(args.ssrShared) : defaults.ssrShared; + const buildDirectory = context.services.resolveWithProjectDirectory( + args.buildDirectory ?? defaults.buildDirectory, + ); // Log all computed variables before pushing bundle const logger = getLogger(); @@ -125,6 +241,7 @@ function createMrtBundlePushTool(loadServices: () => Services, injections?: MrtT origin, buildDirectory, message: args.message, + projectTypes, ssrOnly, ssrShared, }, diff --git a/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts b/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts index dfaba889..faa4c13f 100644 --- a/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts +++ b/packages/b2c-dx-mcp/test/tools/mrt/index.test.ts @@ -95,6 +95,16 @@ function createMockLoadServicesWrapper(options?: { return () => services; } +/** Project types from SDK discovery */ +type ProjectType = 'cartridges' | 'pwa-kit-v3' | 'storefront-next'; + +/** + * Creates a stub for detectWorkspaceType that returns the given project types. + */ +function createDetectWorkspaceTypeStub(projectTypes: ProjectType[] = []) { + return async () => ({projectTypes}); +} + describe('tools/mrt', () => { let sandbox: sinon.SinonSandbox; let pushBundleStub: sinon.SinonStub; @@ -124,7 +134,7 @@ describe('tools/mrt', () => { beforeEach(() => { loadServices = createMockLoadServicesWrapper({mrtAuth: new MockAuthStrategy(), mrtProject: 'test-project'}); - tool = createMrtTools(loadServices)[0]; + tool = createMrtTools(loadServices, {detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3'])})[0]; }); it('should have correct tool name', () => { @@ -169,7 +179,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({buildDirectory: buildDir}); @@ -202,7 +215,10 @@ describe('tools/mrt', () => { mrtEnvironment: 'staging', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({buildDirectory: buildDir}); @@ -235,7 +251,10 @@ describe('tools/mrt', () => { mrtEnvironment: 'staging', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({buildDirectory: buildDir, deploy: false}); @@ -269,7 +288,10 @@ describe('tools/mrt', () => { mrtEnvironment: 'staging', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({buildDirectory: buildDir, deploy: true}); @@ -304,7 +326,10 @@ describe('tools/mrt', () => { mrtOrigin: customOrigin, projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({buildDirectory: buildDir}); @@ -336,7 +361,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; await tool.handler({buildDirectory: buildDir, message: 'Custom deployment message'}); @@ -364,7 +392,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({buildDirectory: buildDir, message: 'Release v1.0.0'}); @@ -399,7 +430,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; // eslint-disable-next-line no-await-in-loop await tool.handler({buildDirectory: relativePath}); @@ -433,7 +467,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; // eslint-disable-next-line no-await-in-loop await tool.handler({buildDirectory: absolutePath}); @@ -461,7 +498,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; await tool.handler({}); @@ -487,7 +527,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', // No projectDirectory provided - should fall back to process.cwd() }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; await tool.handler({buildDirectory: buildDir}); @@ -503,7 +546,9 @@ describe('tools/mrt', () => { mrtAuth: new MockAuthStrategy(), // No project configured }); - const tool = createMrtTools(loadServices)[0]; + const tool = createMrtTools(loadServices, { + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({}); @@ -520,7 +565,9 @@ describe('tools/mrt', () => { mrtProject: 'my-project', // No environment configured }); - const tool = createMrtTools(loadServices)[0]; + const tool = createMrtTools(loadServices, { + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({deploy: true}); @@ -539,7 +586,9 @@ describe('tools/mrt', () => { // No auth configured mrtProject: 'my-project', }); - const tool = createMrtTools(loadServices)[0]; + const tool = createMrtTools(loadServices, { + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({}); @@ -562,7 +611,10 @@ describe('tools/mrt', () => { mrtProject: 'my-project', projectDirectory: projectDir, }); - const tool = createMrtTools(loadServices, {pushBundle: pushBundleStub})[0]; + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; const result = await tool.handler({buildDirectory: buildDir}); @@ -573,13 +625,152 @@ describe('tools/mrt', () => { }); }); + describe('mrt_bundle_push project-type defaults', () => { + it('should use Storefront Next defaults when storefront-next is detected and args omitted', async () => { + const projectDir = '/path/to/sfnext-project'; + const expectedResolvedPath = path.join(projectDir, 'build'); + + const mockResult: PushResult = { + bundleId: 100, + projectSlug: 'my-project', + deployed: false, + message: 'Test', + }; + pushBundleStub.resolves(mockResult); + + const loadServices = createMockLoadServicesWrapper({ + mrtAuth: new MockAuthStrategy(), + mrtProject: 'my-project', + projectDirectory: projectDir, + }); + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['storefront-next']), + })[0]; + + await tool.handler({}); + + expect(pushBundleStub.calledOnce).to.be.true; + const [options] = pushBundleStub.firstCall.args as [PushOptions]; + expect(options.buildDirectory).to.equal(expectedResolvedPath); + expect(options.ssrOnly).to.include('server/**/*'); + expect(options.ssrOnly).to.include('loader.js'); + expect(options.ssrOnly).to.include('streamingHandler.{js,mjs,cjs}'); + expect(options.ssrShared).to.include('client/**/*'); + expect(options.ssrShared).to.include('static/**/*'); + }); + + it('should use PWA Kit v3 defaults when pwa-kit-v3 is detected and args omitted', async () => { + const projectDir = '/path/to/pwakit-project'; + const expectedResolvedPath = path.join(projectDir, 'build'); + + const mockResult: PushResult = { + bundleId: 101, + projectSlug: 'my-project', + deployed: false, + message: 'Test', + }; + pushBundleStub.resolves(mockResult); + + const loadServices = createMockLoadServicesWrapper({ + mrtAuth: new MockAuthStrategy(), + mrtProject: 'my-project', + projectDirectory: projectDir, + }); + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3']), + })[0]; + + await tool.handler({}); + + expect(pushBundleStub.calledOnce).to.be.true; + const [options] = pushBundleStub.firstCall.args as [PushOptions]; + expect(options.buildDirectory).to.equal(expectedResolvedPath); + expect(options.ssrOnly).to.deep.include('ssr.js'); + expect(options.ssrOnly).to.deep.include('ssr.js.map'); + expect(options.ssrOnly).to.deep.include('node_modules/**/*.*'); + expect(options.ssrShared).to.deep.include('static/ico/favicon.ico'); + expect(options.ssrShared).to.deep.include('**/*.js'); + }); + + it('should use generic defaults when no project type detected', async () => { + const projectDir = '/path/to/unknown-project'; + const expectedResolvedPath = path.join(projectDir, 'build'); + + const mockResult: PushResult = { + bundleId: 102, + projectSlug: 'my-project', + deployed: false, + message: 'Test', + }; + pushBundleStub.resolves(mockResult); + + const loadServices = createMockLoadServicesWrapper({ + mrtAuth: new MockAuthStrategy(), + mrtProject: 'my-project', + projectDirectory: projectDir, + }); + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub([]), + })[0]; + + await tool.handler({}); + + expect(pushBundleStub.calledOnce).to.be.true; + const [options] = pushBundleStub.firstCall.args as [PushOptions]; + expect(options.buildDirectory).to.equal(expectedResolvedPath); + expect(options.ssrOnly).to.deep.include('ssr.js'); + expect(options.ssrOnly).to.deep.include('ssr.mjs'); + expect(options.ssrOnly).to.deep.include('server/**/*'); + expect(options.ssrShared).to.deep.include('static/**/*'); + expect(options.ssrShared).to.deep.include('client/**/*'); + }); + + it('should use explicit ssrOnly/ssrShared over project-type defaults', async () => { + const projectDir = '/path/to/project'; + const customSsrOnly = 'custom-server/**/*,ssr.js'; + const customSsrShared = 'custom-static/**/*,client/**/*'; + + const mockResult: PushResult = { + bundleId: 103, + projectSlug: 'my-project', + deployed: false, + message: 'Test', + }; + pushBundleStub.resolves(mockResult); + + const loadServices = createMockLoadServicesWrapper({ + mrtAuth: new MockAuthStrategy(), + mrtProject: 'my-project', + projectDirectory: projectDir, + }); + const tool = createMrtTools(loadServices, { + pushBundle: pushBundleStub, + detectWorkspaceType: createDetectWorkspaceTypeStub(['storefront-next']), + })[0]; + + await tool.handler({ + buildDirectory: './build', + ssrOnly: customSsrOnly, + ssrShared: customSsrShared, + }); + + expect(pushBundleStub.calledOnce).to.be.true; + const [options] = pushBundleStub.firstCall.args as [PushOptions]; + expect(options.ssrOnly).to.deep.equal(['custom-server/**/*', 'ssr.js']); + expect(options.ssrShared).to.deep.equal(['custom-static/**/*', 'client/**/*']); + }); + }); + describe('mrt_bundle_push input validation', () => { let loadServices: () => Services; let tool: ReturnType[0]; beforeEach(() => { loadServices = createMockLoadServicesWrapper({mrtAuth: new MockAuthStrategy(), mrtProject: 'my-project'}); - tool = createMrtTools(loadServices)[0]; + tool = createMrtTools(loadServices, {detectWorkspaceType: createDetectWorkspaceTypeStub(['pwa-kit-v3'])})[0]; }); it('should validate input schema', async () => {