diff --git a/apps/xtream-mock-server/src/app/project-config.spec.ts b/apps/xtream-mock-server/src/app/project-config.spec.ts index c3b19a1f6..740a1ee5c 100644 --- a/apps/xtream-mock-server/src/app/project-config.spec.ts +++ b/apps/xtream-mock-server/src/app/project-config.spec.ts @@ -89,22 +89,55 @@ describe('Playwright mock-server launch', () => { }); describe('Nx E2E task dependencies', () => { - type Dependency = string | { projects?: string | string[] }; - type TargetConfig = { dependsOn?: Dependency[] }; + type Dependency = + | string + | { + projects?: string | string[]; + dependencies?: boolean; + target?: string; + }; + type TargetConfig = { + dependsOn?: Dependency[]; + continuous?: boolean; + filter?: { projects?: string[] }; + }; + type ProjectJson = { targets: Record }; const readJson = (path: string) => JSON.parse(readFileSync(join(process.cwd(), path), 'utf8')) as T; const nxJson = readJson<{ targetDefaults: Record; }>('nx.json'); - const e2eProjectFiles = readdirSync(join(process.cwd(), 'apps')) + const appNames = readdirSync(join(process.cwd(), 'apps')); + const e2eProjectFiles = appNames .filter((name) => name.endsWith('-e2e')) .map((name) => `apps/${name}/project.json`); + // The E2E projects list the mocks as implicit dependencies, so a `^serve` + // dependency schedules the mock serve tasks as well. + const mockContinuousTargets = new Set( + appNames + .filter((name) => name.endsWith('-mock-server')) + .flatMap((name) => + Object.entries( + readJson(`apps/${name}/project.json`).targets + ) + .filter(([, target]) => target.continuous) + .map(([targetName]) => targetName) + ) + ); const dependsOnMock = (dependency: Dependency) => typeof dependency === 'string' - ? dependency.includes('-mock-server:') + ? dependency.includes('-mock-server:') || + (dependency.startsWith('^') && + mockContinuousTargets.has(dependency.slice(1))) : [dependency.projects ?? []] .flat() - .some((project) => project.includes('-mock-server')); + .some((project) => project.includes('-mock-server')) || + (dependency.dependencies === true && + mockContinuousTargets.has(dependency.target ?? '')); + const perFileDefaultFor = (project: string) => + [nxJson.targetDefaults['e2e-ci--src/*.e2e.ts'] ?? []] + .flat() + .find((entry) => entry.filter?.projects?.includes(project)); // The Playwright configs start the mocks themselves, so @nx/playwright // infers their E2E targets as non-parallel, and Nx refuses to run a @@ -119,13 +152,12 @@ describe('Nx E2E task dependencies', () => { })) ); const e2eProjectTargets = e2eProjectFiles.flatMap((path) => - Object.entries( - readJson<{ targets: Record }>(path) - .targets - ).map(([targetName, config]) => ({ - source: `${path} ${targetName}`, - config, - })) + Object.entries(readJson(path).targets).map( + ([targetName, config]) => ({ + source: `${path} ${targetName}`, + config, + }) + ) ); const mockDependencies = [...e2eDefaults, ...e2eProjectTargets] .map(({ source, config }) => ({ @@ -140,16 +172,14 @@ describe('Nx E2E task dependencies', () => { 'apps/web-e2e/project.json', ]) ); + expect([...mockContinuousTargets]).toContain('serve'); expect(mockDependencies).toEqual([]); }); - it('still builds the Electron app before each per-file E2E target', () => { - expect( - (nxJson.targetDefaults['e2e-ci--src/*.e2e.ts'] as TargetConfig) - .dependsOn - ).toContainEqual({ - projects: ['electron-backend'], - target: 'build-e2e', - }); + it('builds the Electron app only before Electron per-file E2E targets', () => { + expect(perFileDefaultFor('electron-backend-e2e')?.dependsOn).toEqual([ + { projects: ['electron-backend'], target: 'build-e2e' }, + ]); + expect(perFileDefaultFor('web-e2e')?.dependsOn).toEqual([]); }); }); diff --git a/nx.json b/nx.json index 6ae3b7f96..2f36ffe99 100644 --- a/nx.json +++ b/nx.json @@ -68,14 +68,21 @@ "dependsOn": ["^build"], "inputs": ["production", "^production"] }, - "e2e-ci--src/*.e2e.ts": { - "dependsOn": [ - { - "projects": ["electron-backend"], - "target": "build-e2e" - } - ] - } + "e2e-ci--src/*.e2e.ts": [ + { + "filter": { "projects": ["electron-backend-e2e"] }, + "dependsOn": [ + { + "projects": ["electron-backend"], + "target": "build-e2e" + } + ] + }, + { + "filter": { "projects": ["web-e2e"] }, + "dependsOn": [] + } + ] }, "plugins": [ {