chore: simplify context/page reuse in ct (#14565)
This commit is contained in:
parent
8801f79742
commit
3a3aa023ad
|
|
@ -21,51 +21,47 @@ let boundCallbacksForMount: Function[] = [];
|
|||
|
||||
export const fixtures: Fixtures<
|
||||
PlaywrightTestArgs & PlaywrightTestOptions & { mount: (component: any, options: any) => Promise<Locator> },
|
||||
PlaywrightWorkerArgs & PlaywrightWorkerOptions & { _ctWorker: { page: Page | undefined, context: BrowserContext | undefined, hash: string, isolateTests: boolean } },
|
||||
PlaywrightWorkerArgs & PlaywrightWorkerOptions & { _ctWorker: { context: BrowserContext | undefined, hash: string } },
|
||||
{ _contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext> }> = {
|
||||
|
||||
_ctWorker: [{ page: undefined, context: undefined, hash: '', isolateTests: false }, { scope: 'worker' }],
|
||||
|
||||
context: async ({ _contextFactory, playwright, browser, _ctWorker, video, trace, viewport }, use, testInfo) => {
|
||||
_ctWorker.isolateTests = shouldCaptureVideo(normalizeVideoMode(video), testInfo) || shouldCaptureTrace(normalizeTraceMode(trace), testInfo);
|
||||
if (_ctWorker.isolateTests) {
|
||||
await use(await _contextFactory());
|
||||
return;
|
||||
}
|
||||
_ctWorker: [{ context: undefined, hash: '' }, { scope: 'worker' }],
|
||||
|
||||
context: async ({ playwright, browser, _ctWorker, _contextFactory, video, trace }, use, testInfo) => {
|
||||
const isolateTests = shouldCaptureVideo(normalizeVideoMode(video), testInfo) || shouldCaptureTrace(normalizeTraceMode(trace), testInfo);
|
||||
const defaultContextOptions = (playwright.chromium as any)._defaultContextOptions as BrowserContextOptions;
|
||||
const hash = contextHash(defaultContextOptions);
|
||||
|
||||
if (!_ctWorker.page || _ctWorker.hash !== hash) {
|
||||
if (!_ctWorker.context || _ctWorker.hash !== hash || isolateTests) {
|
||||
if (_ctWorker.context)
|
||||
await _ctWorker.context.close();
|
||||
|
||||
const context = await browser.newContext();
|
||||
const page = await createPage(context);
|
||||
_ctWorker.context = context;
|
||||
_ctWorker.page = page;
|
||||
// Context factory sets up video so we want to use that for isolated contexts.
|
||||
// However, it closes the context after the test, so we don't want to use it
|
||||
// for shared contexts.
|
||||
_ctWorker.context = isolateTests ? await _contextFactory() : await browser.newContext();
|
||||
_ctWorker.hash = hash;
|
||||
await use(page.context());
|
||||
return;
|
||||
await _ctWorker.context.addInitScript('navigator.serviceWorker.register = () => {}');
|
||||
await _ctWorker.context.exposeFunction('__pw_dispatch', (ordinal: number, args: any[]) => {
|
||||
boundCallbacksForMount[ordinal](...args);
|
||||
});
|
||||
} else {
|
||||
const page = _ctWorker.page;
|
||||
await (page as any)._wrapApiCall(async () => {
|
||||
await (page as any)._resetForReuse();
|
||||
await (page.context() as any)._resetForReuse();
|
||||
await page.goto('about:blank');
|
||||
await page.setViewportSize(viewport || { width: 1280, height: 800 });
|
||||
await page.goto(process.env.PLAYWRIGHT_VITE_COMPONENTS_BASE_URL!);
|
||||
}, true);
|
||||
await use(page.context());
|
||||
await (_ctWorker.context as any)._resetForReuse();
|
||||
}
|
||||
await use(_ctWorker.context);
|
||||
},
|
||||
|
||||
page: async ({ context, _ctWorker }, use) => {
|
||||
if (_ctWorker.isolateTests) {
|
||||
await use(await createPage(context));
|
||||
return;
|
||||
}
|
||||
await use(_ctWorker.page!);
|
||||
page: async ({ context, viewport }, use) => {
|
||||
let page = context.pages()[0];
|
||||
await (context as any)._wrapApiCall(async () => {
|
||||
if (!page) {
|
||||
page = await context.newPage();
|
||||
} else {
|
||||
await (page as any)._resetForReuse();
|
||||
await page.goto('about:blank');
|
||||
await page.setViewportSize(viewport || { width: 1280, height: 800 });
|
||||
}
|
||||
await page.goto(process.env.PLAYWRIGHT_VITE_COMPONENTS_BASE_URL!);
|
||||
}, true);
|
||||
await use(page);
|
||||
},
|
||||
|
||||
mount: async ({ page }, use) => {
|
||||
|
|
@ -148,15 +144,3 @@ function contextHash(context: BrowserContextOptions): string {
|
|||
};
|
||||
return JSON.stringify(hash);
|
||||
}
|
||||
|
||||
function createPage(context: BrowserContext): Promise<Page> {
|
||||
return (context as any)._wrapApiCall(async () => {
|
||||
const page = await context.newPage();
|
||||
await page.addInitScript('navigator.serviceWorker.register = () => {}');
|
||||
await page.exposeFunction('__pw_dispatch', (ordinal: number, args: any[]) => {
|
||||
boundCallbacksForMount[ordinal](...args);
|
||||
});
|
||||
await page.goto(process.env.PLAYWRIGHT_VITE_COMPONENTS_BASE_URL!);
|
||||
return page;
|
||||
}, true);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -111,3 +111,47 @@ test('should not reuse context with trace', async ({ runInlineTest }) => {
|
|||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(2);
|
||||
});
|
||||
|
||||
test('should work with manually closed pages', async ({ runInlineTest }) => {
|
||||
const result = await runInlineTest({
|
||||
'playwright/index.html': `<script type="module" src="/playwright/index.ts"></script>`,
|
||||
'playwright/index.ts': `
|
||||
//@no-header
|
||||
`,
|
||||
|
||||
'src/button.test.tsx': `
|
||||
//@no-header
|
||||
import { test, expect } from '@playwright/experimental-ct-react';
|
||||
|
||||
test('closes page', async ({ mount, page }) => {
|
||||
let hadEvent = false;
|
||||
const component = await mount(<button onClick={e => hadEvent = true}>Submit</button>);
|
||||
await expect(component).toHaveText('Submit');
|
||||
await component.click();
|
||||
expect(hadEvent).toBe(true);
|
||||
await page.close();
|
||||
});
|
||||
|
||||
test('creates a new page', async ({ mount, page, context }) => {
|
||||
let hadEvent = false;
|
||||
const component = await mount(<button onClick={e => hadEvent = true}>Submit</button>);
|
||||
await expect(component).toHaveText('Submit');
|
||||
await component.click();
|
||||
expect(hadEvent).toBe(true);
|
||||
await page.close();
|
||||
await context.newPage();
|
||||
});
|
||||
|
||||
test('still works', async ({ mount }) => {
|
||||
let hadEvent = false;
|
||||
const component = await mount(<button onClick={e => hadEvent = true}>Submit</button>);
|
||||
await expect(component).toHaveText('Submit');
|
||||
await component.click();
|
||||
expect(hadEvent).toBe(true);
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
|
||||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(3);
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue