test: add a ui teardown test (#22010)

This commit is contained in:
Pavel Feldman 2023-03-29 13:57:19 -07:00 committed by GitHub
parent f7244a7e34
commit 8b7dc2cf7a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 137 additions and 43 deletions

View file

@ -37,7 +37,8 @@ class UIMode {
globalCleanup: (() => Promise<FullResult['status']>) | undefined;
private _globalWatcher: Watcher;
private _testWatcher: Watcher;
private _originalStderr: (buffer: string | Uint8Array) => void;
private _originalStdoutWrite: NodeJS.WriteStream['write'];
private _originalStderrWrite: NodeJS.WriteStream['write'];
constructor(config: FullConfigInternal) {
this._config = config;
@ -57,7 +58,8 @@ class UIMode {
config._internal.configCLIOverrides.use = config._internal.configCLIOverrides.use || {};
config._internal.configCLIOverrides.use.trace = { mode: 'on', sources: false };
this._originalStderr = process.stderr.write.bind(process.stderr);
this._originalStdoutWrite = process.stdout.write;
this._originalStderrWrite = process.stderr.write;
this._globalWatcher = new Watcher('deep', () => this._dispatchEvent({ method: 'listChanged' }));
this._testWatcher = new Watcher('flat', events => {
const collector = new Set<string>();
@ -111,7 +113,7 @@ class UIMode {
return;
}
if (method === 'open' && params.location) {
open('vscode://file/' + params.location).catch(e => this._originalStderr(String(e)));
open('vscode://file/' + params.location).catch(e => this._originalStderrWrite.call(process.stderr, String(e)));
return;
}
if (method === 'resizeTerminal') {
@ -129,6 +131,11 @@ class UIMode {
await queue;
});
await exitPromise;
if (!process.env.PWTEST_DEBUG) {
process.stdout.write = this._originalStdoutWrite;
process.stderr.write = this._originalStderrWrite;
}
}
private async _queueListOrRun(method: string, params: any) {
@ -140,7 +147,7 @@ class UIMode {
private _dispatchEvent(message: any) {
// eslint-disable-next-line no-console
this._page.mainFrame().evaluateExpression(dispatchFuncSource, true, message).catch(e => this._originalStderr(String(e)));
this._page.mainFrame().evaluateExpression(dispatchFuncSource, true, message).catch(e => this._originalStderrWrite.call(process.stderr, String(e)));
}
private async _listTests() {

View file

@ -81,6 +81,11 @@ export class TestChildProcess {
this.exitCode = this.exited.then(r => r.exitCode);
}
outputLines(): string[] {
const strippedOutput = stripAnsi(this.output);
return strippedOutput.split('\n').filter(line => line.startsWith('%%')).map(line => line.substring(2).trim());
}
async close() {
if (!this.process.killed)
this._killProcessGroup('SIGINT');

View file

@ -16,6 +16,8 @@
import { test, expect } from './playwright-test-fixtures';
test.slow();
test('basics should work', async ({ runTSC }) => {
const result = await runTSC({
'a.spec.ts': `

View file

@ -16,6 +16,8 @@
import { test, expect } from './playwright-test-fixtures';
test.slow();
test('should check types of fixtures', async ({ runTSC }) => {
const result = await runTSC({
'helper.ts': `

View file

@ -30,7 +30,7 @@ type Latch = {
};
type Fixtures = {
runUITest: (files: Files, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise<Page>;
runUITest: (files: Files, env?: NodeJS.ProcessEnv, options?: RunOptions) => Promise<{ page: Page, testProcess: TestChildProcess }>;
createLatch: () => Latch;
};
@ -106,7 +106,7 @@ export const test = base
browser = await playwright.chromium.connectOverCDP(wsEndpoint);
const [context] = browser.contexts();
const [page] = context.pages();
return page;
return { page, testProcess };
});
await browser?.close();
await testProcess?.close();

View file

@ -36,7 +36,7 @@ const basicTestTree = {
};
test('should filter by title', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await page.getByPlaceholder('Filter').fill('inner');
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toBe(`
a.test.ts
@ -47,7 +47,7 @@ test('should filter by title', async ({ runUITest }) => {
});
test('should filter by status', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await page.getByTitle('Run all').click();
@ -91,7 +91,7 @@ test('should filter by status', async ({ runUITest }) => {
});
test('should filter by project', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
...basicTestTree,
'playwright.config.ts': `
import { defineConfig } from '@playwright/test';
@ -151,7 +151,7 @@ test('should filter by project', async ({ runUITest }) => {
test('should not hide filtered while running', async ({ runUITest, createLatch }) => {
const latch = createLatch();
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});
@ -180,7 +180,7 @@ test('should not hide filtered while running', async ({ runUITest, createLatch }
});
test('should filter skipped', async ({ runUITest, createLatch }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});

View file

@ -19,7 +19,7 @@ import { test, expect } from './ui-mode-fixtures';
test.describe.configure({ mode: 'parallel' });
test('should print load errors', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('syntax error', () => {
@ -32,7 +32,7 @@ test('should print load errors', async ({ runUITest }) => {
});
test('should work after theme switch', async ({ runUITest, writeFiles }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('syntax error', async () => {

View file

@ -32,7 +32,7 @@ test('should update trace live', async ({ runUITest, server }) => {
res.end('<html>Two</html>');
});
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('live test', async ({ page }) => {

View file

@ -40,7 +40,7 @@ const basicTestTree = {
};
test('should run visible', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toContain(`
a.test.ts
`);
@ -64,7 +64,7 @@ test('should run visible', async ({ runUITest }) => {
});
test('should show running progress', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('test 1', async () => {});
@ -83,7 +83,7 @@ test('should show running progress', async ({ runUITest }) => {
});
test('should run on hover', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});
@ -102,7 +102,7 @@ test('should run on hover', async ({ runUITest }) => {
});
test('should run on double click', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});
@ -120,7 +120,7 @@ test('should run on double click', async ({ runUITest }) => {
});
test('should run on Enter', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});
@ -139,7 +139,7 @@ test('should run on Enter', async ({ runUITest }) => {
});
test('should run by project', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
...basicTestTree,
'playwright.config.ts': `
import { defineConfig } from '@playwright/test';
@ -218,7 +218,7 @@ test('should run by project', async ({ runUITest }) => {
});
test('should stop', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('test 0', () => { test.skip(); });
@ -256,7 +256,7 @@ test('should stop', async ({ runUITest }) => {
});
test('should run folder', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a/folder-b/folder-c/inC.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});
@ -284,7 +284,7 @@ test('should run folder', async ({ runUITest }) => {
});
test('should show time', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toContain(`
a.test.ts
`);

View file

@ -0,0 +1,78 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { test, expect } from './ui-mode-fixtures';
test.describe.configure({ mode: 'parallel' });
test('should run global setup and teardown', async ({ runUITest }) => {
const { page, testProcess } = await runUITest({
'playwright.config.ts': `
import { defineConfig } from '@playwright/test';
export default defineConfig({
globalSetup: './globalSetup',
globalTeardown: './globalTeardown.ts',
});
`,
'globalSetup.ts': `
export default () => console.log('\\n%%from-global-setup');
`,
'globalTeardown.ts': `
export default () => console.log('\\n%%from-global-teardown');
`,
'a.test.js': `
import { test, expect } from '@playwright/test';
test('should work', async ({}) => {});
`
});
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)', { timeout: 15000 });
await page.close();
await expect.poll(() => testProcess.outputLines(), { timeout: 15000 }).toEqual([
'from-global-setup',
'from-global-teardown',
]);
});
test('should teardown on sigint', async ({ runUITest }) => {
test.skip(process.platform === 'win32', 'No sending SIGINT on Windows');
const { page, testProcess } = await runUITest({
'playwright.config.ts': `
import { defineConfig } from '@playwright/test';
export default defineConfig({
globalSetup: './globalSetup',
globalTeardown: './globalTeardown.ts',
});
`,
'globalSetup.ts': `
export default () => console.log('\\n%%from-global-setup');
`,
'globalTeardown.ts': `
export default () => console.log('\\n%%from-global-teardown');
`,
'a.test.js': `
import { test, expect } from '@playwright/test';
test('should work', async ({}) => {});
`
});
await page.getByTitle('Run all').click();
await expect(page.getByTestId('status-line')).toHaveText('1/1 passed (100%)', { timeout: 15000 });
testProcess.process.kill('SIGINT');
await expect.poll(() => testProcess.outputLines(), { timeout: 15000 }).toEqual([
'from-global-setup',
'from-global-teardown',
]);
});

View file

@ -31,7 +31,7 @@ const basicTestTree = {
};
test('should show selected test in sources', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toBe(`
a.test.ts
first

View file

@ -36,7 +36,7 @@ const basicTestTree = {
};
test('should list tests', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toBe(`
a.test.ts
passes
@ -49,7 +49,7 @@ test('should list tests', async ({ runUITest }) => {
});
test('should traverse up/down', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await page.getByText('a.test.ts').click();
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toContain(`
a.test.ts <=
@ -83,7 +83,7 @@ test('should traverse up/down', async ({ runUITest }) => {
});
test('should expand / collapse groups', async ({ runUITest }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await page.getByTestId('test-tree').getByText('suite').click();
await page.keyboard.press('ArrowRight');
@ -119,7 +119,7 @@ test('should expand / collapse groups', async ({ runUITest }) => {
});
test('should merge folder trees', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a/b/c/inC.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});
@ -144,7 +144,7 @@ test('should merge folder trees', async ({ runUITest }) => {
});
test('should list parametrized tests', async ({ runUITest }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test } from '@playwright/test';
test.describe('cookies', () => {
@ -173,7 +173,7 @@ test('should list parametrized tests', async ({ runUITest }) => {
});
test('should update parametrized tests', async ({ runUITest, writeFiles }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test } from '@playwright/test';
test.describe('cookies', () => {

View file

@ -36,7 +36,7 @@ const basicTestTree = {
};
test('should pick new / deleted files', async ({ runUITest, writeFiles, deleteFile }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toBe(`
a.test.ts
passes
@ -81,7 +81,7 @@ test('should pick new / deleted files', async ({ runUITest, writeFiles, deleteFi
});
test('should pick new / deleted tests', async ({ runUITest, writeFiles, deleteFile }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toBe(`
a.test.ts
passes
@ -130,7 +130,7 @@ test('should pick new / deleted tests', async ({ runUITest, writeFiles, deleteFi
});
test('should pick new / deleted nested tests', async ({ runUITest, writeFiles, deleteFile }) => {
const page = await runUITest(basicTestTree);
const { page } = await runUITest(basicTestTree);
await expect.poll(dumpTestTree(page), { timeout: 15000 }).toContain(`
a.test.ts
passes
@ -170,7 +170,7 @@ test('should pick new / deleted nested tests', async ({ runUITest, writeFiles, d
});
test('should update test locations', async ({ runUITest, writeFiles, deleteFile }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});

View file

@ -19,7 +19,7 @@ import { test, expect, dumpTestTree } from './ui-mode-fixtures';
test.describe.configure({ mode: 'parallel' });
test('should watch files', async ({ runUITest, writeFiles }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('passes', () => {});
@ -59,7 +59,7 @@ test('should watch files', async ({ runUITest, writeFiles }) => {
});
test('should watch e2e deps', async ({ runUITest, writeFiles }) => {
const page = await runUITest({
const { page } = await runUITest({
'playwright.config.ts': `
import { defineConfig } from '@playwright/test';
export default defineConfig({ testDir: 'tests' });
@ -94,7 +94,7 @@ test('should watch e2e deps', async ({ runUITest, writeFiles }) => {
});
test('should batch watch updates', async ({ runUITest, writeFiles }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
'b.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
'c.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
@ -143,7 +143,7 @@ test('should batch watch updates', async ({ runUITest, writeFiles }) => {
});
test('should watch all', async ({ runUITest, writeFiles }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
'b.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
'c.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
@ -182,7 +182,7 @@ test('should watch all', async ({ runUITest, writeFiles }) => {
});
test('should watch new file', async ({ runUITest, writeFiles }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
});
@ -222,7 +222,7 @@ test('should watch new file', async ({ runUITest, writeFiles }) => {
test('should queue watches', async ({ runUITest, writeFiles, createLatch }) => {
const latch = createLatch();
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `import { test } from '@playwright/test'; test('test', () => {});`,
'b.test.ts': `import { test } from '@playwright/test'; test('test', async () => {
${latch.blockingCode}

View file

@ -18,7 +18,7 @@ import { test, expect } from './ui-mode-fixtures';
test.describe.configure({ mode: 'parallel' });
test('should merge trace events', async ({ runUITest, server }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('trace test', async ({ page }) => {
@ -46,7 +46,7 @@ test('should merge trace events', async ({ runUITest, server }) => {
});
test('should locate sync assertions in source', async ({ runUITest, server }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('trace test', async ({}) => {
@ -64,7 +64,7 @@ test('should locate sync assertions in source', async ({ runUITest, server }) =>
});
test('should show snapshots for sync assertions', async ({ runUITest, server }) => {
const page = await runUITest({
const { page } = await runUITest({
'a.test.ts': `
import { test, expect } from '@playwright/test';
test('trace test', async ({ page }) => {