import assert from 'node:assert/strict'; import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'; import { tmpdir } from 'node:os'; import { resolve } from 'node:path'; import test from 'node:test'; import { buildSpecFilter, buildTagGrep, combineGreps, parseE2eArgs } from './runE2eArgs.ts'; function withSpecs(callback: (specsDir: string) => void): void { const tempDir = mkdtempSync(resolve(tmpdir(), 'cabloy-e2e-args-')); try { const specsDir = resolve(tempDir, 'specs'); mkdirSync(specsDir); for (const name of ['account', 'a-commerce', 'cabloy-basic']) { writeFileSync(resolve(specsDir, `${name}.spec.ts`), ''); } callback(specsDir); } finally { rmSync(tempDir, { recursive: true, force: true }); } } test('parses multiple specs and repeatable tags', () => { withSpecs(specsDir => { assert.deepEqual( parseE2eArgs(['cabloy-basic', 'account', '--tag', '@web', '--tag=@smoke'], specsDir), { specNames: ['cabloy-basic', 'account'], playwrightArgs: [], tags: ['@web', '@smoke'], }, ); }); }); test('allows no spec names and forwards Playwright filters', () => { withSpecs(specsDir => { assert.deepEqual(parseE2eArgs(['--grep', '@flow'], specsDir), { specNames: [], playwrightArgs: ['--grep', '@flow'], tags: [], }); }); }); test('rejects invalid or unknown specs and managed config overrides', () => { withSpecs(specsDir => { assert.throws(() => parseE2eArgs(['../account'], specsDir), /Invalid E2E spec name/); assert.throws(() => parseE2eArgs(['missing'], specsDir), /Unknown E2E spec/); for (const args of [ ['--config', 'other.ts'], ['--config=other.ts'], ['-c', 'other.ts'], ['-c=other.ts'], ['-cother.ts'], ]) { assert.throws(() => parseE2eArgs(args, specsDir), /manages --config/); } for (const args of [['--workers', '2'], ['--workers=2'], ['-j', '2'], ['-j=2'], ['-j2']]) { assert.throws(() => parseE2eArgs(args, specsDir), /manages --workers/); } }); }); test('rejects removed clean and fast options', () => { withSpecs(specsDir => { for (const option of ['--clean', '--fast', '--clean=true', '--fast=false']) { assert.throws(() => parseE2eArgs(['account', option], specsDir), /Unsupported E2E option/); } }); }); test('spec filters normalize Windows paths and escape regex syntax literally', () => { for (const specPath of [ '/synthetic/café 中文 [work]+(tree).$/specs/cabloy-basic.spec.ts', 'C:\\synthetic\\café 中文 [work]+(tree).$\\specs\\cabloy-basic.spec.ts', '\\\\server\\share with spaces\\café [work]\\specs\\a-commerce.spec.ts', ]) { const normalized = specPath.replaceAll('\\', '/'); const filter = new RegExp(buildSpecFilter(specPath)); assert.match(normalized, filter); assert.doesNotMatch(`${normalized}.unselected`, filter); assert.doesNotMatch(`prefix${normalized}`, filter); assert.doesNotMatch(normalized.replace('.spec.ts', 'XspecXts'), filter); } }); test('combines tags with an existing grep expression', () => { assert.equal(buildTagGrep(['@web', '@smoke']), '(?=.*@web)(?=.*@smoke)'); assert.deepEqual(combineGreps(['--grep', '@flow'], ['@web', '@smoke']), [ '--grep', '(?=.*(?:@flow))(?=.*@web)(?=.*@smoke)', ]); });