mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 13:46:16 -08:00
test(e2e): fail the task-graph check when an expected target is not inferred
The check validated only the targets the plugin tags as Playwright ones, so a web target that dropped out of the inference passed unchecked while the Electron targets kept the count above zero. Require e2e plus one e2e-ci-- target per *.e2e.ts spec in both E2E projects, in each mode. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c608938f0e
commit
12339a1dbb
2 files changed
+79
-6
No files matched your search
@@ -1,4 +1,6 @@
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { readdirSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
/**
|
||||
@@ -18,6 +20,47 @@ export const MODES = {
|
||||
ci: { CI: 'true' },
|
||||
};
|
||||
|
||||
/**
|
||||
* The Playwright projects whose targets must be inferred. The check only sees
|
||||
* targets the plugin tags as Playwright ones, so a target that drops out of
|
||||
* the inference would otherwise pass unchecked.
|
||||
*/
|
||||
export const E2E_PROJECTS = {
|
||||
'web-e2e': 'apps/web-e2e',
|
||||
'electron-backend-e2e': 'apps/electron-backend-e2e',
|
||||
};
|
||||
|
||||
/** `e2e` plus one atomized target per spec, as the plugin names them. */
|
||||
export function expectedPlaywrightTargets(specFilesByProject) {
|
||||
return Object.entries(specFilesByProject).flatMap(([project, specs]) => [
|
||||
`${project}:e2e`,
|
||||
...specs.map((spec) => `${project}:e2e-ci--${spec}`),
|
||||
]);
|
||||
}
|
||||
|
||||
export function findMissingTargets(projectGraph, expectedTargets) {
|
||||
const inferred = new Set(
|
||||
playwrightTargets(projectGraph).map(
|
||||
({ project, target }) => `${project}:${target}`
|
||||
)
|
||||
);
|
||||
return expectedTargets.filter((task) => !inferred.has(task));
|
||||
}
|
||||
|
||||
function readSpecFiles(workspaceRoot) {
|
||||
return Object.fromEntries(
|
||||
Object.entries(E2E_PROJECTS).map(([project, root]) => [
|
||||
project,
|
||||
readdirSync(path.join(workspaceRoot, root, 'src'), {
|
||||
recursive: true,
|
||||
})
|
||||
.filter((file) => file.endsWith('.e2e.ts'))
|
||||
.map((file) => `src/${file.split(path.sep).join('/')}`)
|
||||
.sort(),
|
||||
])
|
||||
);
|
||||
}
|
||||
|
||||
export function playwrightTargets(projectGraph) {
|
||||
return Object.values(projectGraph.nodes)
|
||||
.flatMap((node) =>
|
||||
@@ -67,11 +110,18 @@ function childEnv(mode) {
|
||||
}
|
||||
|
||||
async function checkCurrentEnvironment() {
|
||||
const { createProjectGraphAsync } = await import('@nx/devkit');
|
||||
const { createProjectGraphAsync, workspaceRoot } =
|
||||
await import('@nx/devkit');
|
||||
const projectGraph = await createProjectGraphAsync({ exitOnError: true });
|
||||
const failures = await findInvalidTaskGraphs(projectGraph);
|
||||
const checked = playwrightTargets(projectGraph).length;
|
||||
console.log(`${RESULT_PREFIX}${JSON.stringify({ checked, failures })}`);
|
||||
const missing = findMissingTargets(
|
||||
projectGraph,
|
||||
expectedPlaywrightTargets(readSpecFiles(workspaceRoot))
|
||||
);
|
||||
console.log(
|
||||
`${RESULT_PREFIX}${JSON.stringify({ checked, failures, missing })}`
|
||||
);
|
||||
}
|
||||
|
||||
function main() {
|
||||
@@ -89,12 +139,14 @@ function main() {
|
||||
const result = output
|
||||
.split('\n')
|
||||
.find((line) => line.startsWith(RESULT_PREFIX));
|
||||
const { checked, failures } = JSON.parse(
|
||||
const { checked, failures, missing } = JSON.parse(
|
||||
result.slice(RESULT_PREFIX.length)
|
||||
);
|
||||
if (checked === 0) {
|
||||
for (const task of missing) {
|
||||
failed = true;
|
||||
console.error(`[${mode}] no Playwright targets were inferred`);
|
||||
console.error(
|
||||
`[${mode}] ${task} was not inferred as a Playwright target`
|
||||
);
|
||||
}
|
||||
for (const { task, message } of failures) {
|
||||
failed = true;
|
||||
@@ -102,7 +154,7 @@ function main() {
|
||||
`[${mode}] ${task}\n ${message.replace(/\n/g, '\n ')}`
|
||||
);
|
||||
}
|
||||
if (failures.length === 0 && checked > 0) {
|
||||
if (failures.length === 0 && missing.length === 0) {
|
||||
console.log(
|
||||
`[${mode}] ${checked} Playwright task graphs are valid`
|
||||
);
|
||||
|
||||
@@ -2,7 +2,9 @@ import assert from 'node:assert/strict';
|
||||
import { test } from 'node:test';
|
||||
|
||||
import {
|
||||
expectedPlaywrightTargets,
|
||||
findInvalidTaskGraphs,
|
||||
findMissingTargets,
|
||||
MODES,
|
||||
playwrightTargets,
|
||||
} from './check-e2e-task-graphs.mjs';
|
||||
@@ -76,3 +78,22 @@ test('accepts a non-parallel e2e target whose servers Playwright starts', async
|
||||
test('validates both the local and the CI plugin inference', () => {
|
||||
assert.deepEqual(MODES, { local: { CI: undefined }, ci: { CI: 'true' } });
|
||||
});
|
||||
|
||||
test('expects the e2e target and one atomized target per spec', () => {
|
||||
assert.deepEqual(
|
||||
expectedPlaywrightTargets({ 'web-e2e': ['src/basic.e2e.ts'] }),
|
||||
['web-e2e:e2e', 'web-e2e:e2e-ci--src/basic.e2e.ts']
|
||||
);
|
||||
});
|
||||
|
||||
test('reports expected targets the plugin no longer infers', () => {
|
||||
const graph = graphWithE2eTarget({ parallelism: false, dependsOn: [] });
|
||||
|
||||
assert.deepEqual(
|
||||
findMissingTargets(graph, [
|
||||
'web-e2e:e2e',
|
||||
'web-e2e:e2e-ci--src/basic.e2e.ts',
|
||||
]),
|
||||
['web-e2e:e2e-ci--src/basic.e2e.ts']
|
||||
);
|
||||
});
|
||||
Reference in new issue
Block a user