feat(ui): run deps in UI mode if dep projects are checked (#24245)

This commit is contained in:
Pavel Feldman 2023-07-15 15:11:31 -07:00 committed by GitHub
parent d92db9a513
commit 49c1f9eb02
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 111 additions and 15 deletions

View file

@ -32,7 +32,7 @@ import { dependenciesForTestFile } from '../transform/compilationCache';
import { sourceMapSupport } from '../utilsBundle';
import type { RawSourceMap } from 'source-map';
export async function collectProjectsAndTestFiles(testRun: TestRun, additionalFileMatcher: Matcher | undefined) {
export async function collectProjectsAndTestFiles(testRun: TestRun, doNotRunTestsOutsideProjectFilter: boolean, additionalFileMatcher: Matcher | undefined) {
const config = testRun.config;
const fsCache = new Map();
const sourceMapCache = new Map();
@ -40,7 +40,8 @@ export async function collectProjectsAndTestFiles(testRun: TestRun, additionalFi
// First collect all files for the projects in the command line, don't apply any file filters.
const allFilesForProject = new Map<FullProjectInternal, string[]>();
for (const project of filterProjects(config.projects, config.cliProjectFilter)) {
const filteredProjects = filterProjects(config.projects, config.cliProjectFilter);
for (const project of filteredProjects) {
const files = await collectFilesForProject(project, fsCache);
allFilesForProject.set(project, files);
}
@ -68,7 +69,8 @@ export async function collectProjectsAndTestFiles(testRun: TestRun, additionalFi
for (const [project, type] of projectClosure) {
if (type === 'dependency') {
filesToRunByProject.delete(project);
const files = allFilesForProject.get(project) || await collectFilesForProject(project, fsCache);
const treatProjectAsEmpty = doNotRunTestsOutsideProjectFilter && !filteredProjects.includes(project);
const files = treatProjectAsEmpty ? [] : allFilesForProject.get(project) || await collectFilesForProject(project, fsCache);
filesToRunByProject.set(project, files);
}
}

View file

@ -76,7 +76,7 @@ export function createTaskRunnerForWatchSetup(config: FullConfigInternal, report
export function createTaskRunnerForWatch(config: FullConfigInternal, reporter: ReporterV2, additionalFileMatcher?: Matcher): TaskRunner<TestRun> {
const taskRunner = new TaskRunner<TestRun>(reporter, 0);
taskRunner.addTask('load tests', createLoadTask('out-of-process', { filterOnly: true, failOnLoadErrors: false, additionalFileMatcher }));
taskRunner.addTask('load tests', createLoadTask('out-of-process', { filterOnly: true, failOnLoadErrors: false, doNotRunTestsOutsideProjectFilter: true, additionalFileMatcher }));
addRunTasks(taskRunner, config);
return taskRunner;
}
@ -171,9 +171,9 @@ function createRemoveOutputDirsTask(): Task<TestRun> {
};
}
function createLoadTask(mode: 'out-of-process' | 'in-process', options: { filterOnly: boolean, failOnLoadErrors: boolean, additionalFileMatcher?: Matcher }): Task<TestRun> {
function createLoadTask(mode: 'out-of-process' | 'in-process', options: { filterOnly: boolean, failOnLoadErrors: boolean, doNotRunTestsOutsideProjectFilter?: boolean, additionalFileMatcher?: Matcher }): Task<TestRun> {
return async (testRun, errors, softErrors) => {
await collectProjectsAndTestFiles(testRun, options.additionalFileMatcher);
await collectProjectsAndTestFiles(testRun, !!options.doNotRunTestsOutsideProjectFilter, options.additionalFileMatcher);
await loadFileSuites(testRun, mode, options.failOnLoadErrors ? errors : softErrors);
testRun.rootSuite = await createRootSuite(testRun, options.failOnLoadErrors ? errors : softErrors, !!options.filterOnly);
// Fail when no tests.

View file

@ -45,10 +45,6 @@ class UIMode {
process.env.PW_LIVE_TRACE_STACKS = '1';
config.cliListOnly = false;
config.cliPassWithNoTests = true;
for (const project of config.projects) {
project.deps = [];
project.teardown = undefined;
}
for (const p of config.projects) {
p.project.retries = 0;
@ -153,7 +149,7 @@ class UIMode {
if (method === 'list')
await this._listTests();
if (method === 'run')
await this._runTests(params.testIds);
await this._runTests(params.testIds, params.projects);
}
private _dispatchEvent(method: string, params?: any) {
@ -178,11 +174,12 @@ class UIMode {
this._globalWatcher.update([...projectDirs], false);
}
private async _runTests(testIds: string[]) {
private async _runTests(testIds: string[], projects: string[]) {
await this._stopTests();
const testIdSet = testIds ? new Set<string>(testIds) : null;
this._config.cliListOnly = false;
this._config.cliProjectFilter = projects.length ? projects : undefined;
this._config.testIdMatcher = id => !testIdSet || testIdSet.has(id);
const reporters = await createReporters(this._config, 'ui');

View file

@ -153,7 +153,7 @@ export const UIModeView: React.FC<{}> = ({
setProgress({ total: testIds.size, passed: 0, failed: 0, skipped: 0 });
setRunningState({ testIds });
await sendMessage('run', { testIds: [...testIds] });
await sendMessage('run', { testIds: [...testIds], projects: [...projectFilters].filter(([_, v]) => v).map(([p]) => p) });
// Clear pending tests in case of interrupt.
for (const test of testModel.rootSuite?.allTests() || []) {
if (test.results[0]?.duration === -1)
@ -162,7 +162,7 @@ export const UIModeView: React.FC<{}> = ({
setTestModel({ ...testModel });
setRunningState(undefined);
});
}, [runningState, testModel]);
}, [projectFilters, runningState, testModel]);
const isRunningTest = !!runningState;

View file

@ -14,7 +14,7 @@
* limitations under the License.
*/
import { test, expect, retries } from './ui-mode-fixtures';
import { test, expect, retries, dumpTestTree } from './ui-mode-fixtures';
test.describe.configure({ mode: 'parallel', retries });
@ -76,3 +76,100 @@ test('should teardown on sigint', async ({ runUITest }) => {
'from-global-teardown',
]);
});
const testsWithSetup = {
'playwright.config.ts': `
import { defineConfig } from '@playwright/test';
export default defineConfig({
projects: [
{ name: 'setup', teardown: 'teardown', testMatch: 'setup.ts' },
{ name: 'test', testMatch: 'test.ts', dependencies: ['setup'] },
{ name: 'teardown', testMatch: 'teardown.ts' },
]
});
`,
'setup.ts': `
import { test, expect } from '@playwright/test';
test('setup', async ({}) => {
console.log('from-setup');
});
`,
'test.ts': `
import { test, expect } from '@playwright/test';
test('test', async ({}) => {
console.log('from-test');
});
`,
'teardown.ts': `
import { test, expect } from '@playwright/test';
test('teardown', async ({}) => {
console.log('from-teardown');
});
`,
};
test('should run setup and teardown projects (1)', async ({ runUITest }) => {
const { page } = await runUITest(testsWithSetup);
await page.getByText('Status:').click();
await page.getByLabel('setup').setChecked(false);
await page.getByLabel('teardown').setChecked(false);
await page.getByLabel('test').setChecked(false);
await page.getByTitle('Run all').click();
await expect.poll(dumpTestTree(page)).toBe(`
setup.ts
setup
teardown.ts
teardown
test.ts
test
`);
await page.getByTitle('Toggle output').click();
await expect(page.getByTestId('output')).toContainText(`from-setup`);
await expect(page.getByTestId('output')).toContainText(`from-test`);
await expect(page.getByTestId('output')).toContainText(`from-teardown`);
});
test('should run setup and teardown projects (2)', async ({ runUITest }) => {
const { page } = await runUITest(testsWithSetup);
await page.getByText('Status:').click();
await page.getByLabel('setup').setChecked(false);
await page.getByLabel('teardown').setChecked(true);
await page.getByLabel('test').setChecked(true);
await page.getByTitle('Run all').click();
await expect.poll(dumpTestTree(page)).toBe(`
teardown.ts
teardown
test.ts
test
`);
await page.getByTitle('Toggle output').click();
await expect(page.getByTestId('output')).toContainText(`from-test`);
await expect(page.getByTestId('output')).toContainText(`from-teardown`);
await expect(page.getByTestId('output')).not.toContainText(`from-setup`);
});
test('should run setup and teardown projects (3)', async ({ runUITest }) => {
const { page } = await runUITest(testsWithSetup);
await page.getByText('Status:').click();
await page.getByLabel('setup').setChecked(false);
await page.getByLabel('teardown').setChecked(false);
await page.getByLabel('test').setChecked(true);
await page.getByTitle('Run all').click();
await expect.poll(dumpTestTree(page)).toBe(`
test.ts
test
`);
await page.getByTitle('Toggle output').click();
await expect(page.getByTestId('output')).toContainText(`from-test`);
await expect(page.getByTestId('output')).not.toContainText(`from-setup`);
await expect(page.getByTestId('output')).not.toContainText(`from-teardown`);
});

0
utils/limits.sh Normal file → Executable file
View file