Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions packages/playwright/src/program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import { runAllTestsWithConfig, TestRunner } from './runner/testRunner';
import { createErrorCollectingReporter } from './runner/reporters';
import { TestServerBackend, testServerBackendTools } from './mcp/test/testBackend';
import { ClaudeGenerator, OpencodeGenerator, VSCodeGenerator, CopilotGenerator } from './agents/generateAgents';
import { loadTestList } from './runner/loadUtils';

import type { ConfigCLIOverrides } from './common/ipc';
import type { TraceMode } from '../types/test';
Expand Down Expand Up @@ -208,6 +209,12 @@ async function runTests(args: string[], opts: { [key: string]: any }) {
config.cliTestList = opts.testList ? path.resolve(process.cwd(), opts.testList) : undefined;
config.cliTestListInvert = opts.testListInvert ? path.resolve(process.cwd(), opts.testListInvert) : undefined;

if (config.cliTestList) {
const { files } = await loadTestList(config, config.cliTestList);
for (const project of config.projects)
project.project.testMatch = files;
}

// Evaluate project filters against config before starting execution. This enables a consistent error message across run modes
filterProjects(config.projects, config.cliProjectFilter);

Expand Down
7 changes: 4 additions & 3 deletions packages/playwright/src/runner/loadUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,7 @@ function sourceMapSources(file: string, cache: Map<string, string[]>): string[]
}
}

export async function loadTestList(config: FullConfigInternal, filePath: string): Promise<TestCaseFilter> {
export async function loadTestList(config: FullConfigInternal, filePath: string): Promise<TestCaseFilter & { files: string[] }> {
try {
const content = await fs.promises.readFile(filePath, 'utf-8');
const lines = content.split('\n').map(line => line.trim()).filter(line => line && !line.startsWith('#'));
Expand All @@ -366,8 +366,7 @@ export async function loadTestList(config: FullConfigInternal, filePath: string)
}
return { project, file: toPosixPath(parseLocationArg(tokens[0]).file), titlePath: tokens.slice(1) };
});
return (test: TestCase) => descriptions.some(d => {
// Note: there is no root yet at the time of filtering.
const filter = (test: TestCase) => descriptions.some(d => {
const [projectName, , ...titles] = test.titlePath();
if (d.project !== undefined && d.project !== projectName)
return false;
Expand All @@ -376,6 +375,8 @@ export async function loadTestList(config: FullConfigInternal, filePath: string)
return false;
return d.titlePath.length <= titles.length && d.titlePath.every((_, index) => titles[index] === d.titlePath[index]);
});
filter.files = [...new Set(descriptions.map(d => d.file))];
return filter;
} catch (e) {
throw errorWithFile(filePath, 'Cannot read test list file: ' + e.message);
}
Expand Down
25 changes: 25 additions & 0 deletions tests/playwright-test/test-list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,28 @@ test('--test-list with nested group entry should run only tests in that nested g
'd-test2-p2',
]);
});

test('--test-list should not load files not in the list', async ({ runInlineTest }) => {
const result = await runInlineTest({
'playwright.config.ts': `
module.exports = { testDir: '.' };
`,
'test.list': `
good.test.ts
`,
'good.test.ts': `
import { test, expect } from '@playwright/test';
test('good test', async () => { console.log('\\n%%good-test'); });
`,
'broken.test.ts': `
// This file uses invalid syntax that would crash if loaded
describe('broken', () => {
it('should fail', () => {});
});
`,
}, { 'workers': 1, 'test-list': 'test.list' });
// Should succeed without loading broken.test.ts
expect(result.exitCode).toBe(0);
expect(result.passed).toBe(1);
expect(result.outputLines).toEqual(['good-test']);
});