| 1 |
#!/usr/bin/env node |
| 2 |
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs'; |
| 3 |
import { dirname, join, relative, sep } from 'node:path'; |
| 4 |
|
| 5 |
const TEST_DIR = 'tests/playwright'; |
| 6 |
|
| 7 |
const walk = (dir) => |
| 8 |
readdirSync(dir).flatMap((entry) => { |
| 9 |
const full = join(dir, entry); |
| 10 |
return statSync(full).isDirectory() |
| 11 |
? walk(full) |
| 12 |
: entry.endsWith('.spec.ts') |
| 13 |
? [full] |
| 14 |
: []; |
| 15 |
}); |
| 16 |
|
| 17 |
const hasBlueprint = (spec) => { |
| 18 |
let dir = dirname(spec); |
| 19 |
while (dir.startsWith(TEST_DIR) || dir === TEST_DIR) { |
| 20 |
if (existsSync(join(dir, 'blueprint.json'))) return true; |
| 21 |
if (dir === TEST_DIR) return false; |
| 22 |
dir = dirname(dir); |
| 23 |
} |
| 24 |
return false; |
| 25 |
}; |
| 26 |
|
| 27 |
// A first-line `// e2e:disabled` marker keeps a spec on disk but out of the CI |
| 28 |
// matrix — the equivalent of a commented-out entry in cypress-push.yml. |
| 29 |
const isDisabled = (spec) => |
| 30 |
readFileSync(spec, 'utf8').split('\n', 1)[0].includes('e2e:disabled'); |
| 31 |
|
| 32 |
const projects = existsSync(TEST_DIR) |
| 33 |
? walk(TEST_DIR) |
| 34 |
.filter(hasBlueprint) |
| 35 |
.filter((s) => !isDisabled(s)) |
| 36 |
.map((s) => |
| 37 |
relative(TEST_DIR, s) |
| 38 |
.replace(/\.spec\.ts$/, '') |
| 39 |
.split(sep) |
| 40 |
.join('/'), |
| 41 |
) |
| 42 |
: []; |
| 43 |
|
| 44 |
process.stdout.write(JSON.stringify(projects)); |
| 45 |
|