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<
|
export const fixtures: Fixtures<
|
||||||
PlaywrightTestArgs & PlaywrightTestOptions & { mount: (component: any, options: any) => Promise<Locator> },
|
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> }> = {
|
{ _contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext> }> = {
|
||||||
|
|
||||||
_ctWorker: [{ page: undefined, context: undefined, hash: '', isolateTests: false }, { scope: 'worker' }],
|
_ctWorker: [{ context: undefined, hash: '' }, { 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
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 defaultContextOptions = (playwright.chromium as any)._defaultContextOptions as BrowserContextOptions;
|
||||||
const hash = contextHash(defaultContextOptions);
|
const hash = contextHash(defaultContextOptions);
|
||||||
|
|
||||||
if (!_ctWorker.page || _ctWorker.hash !== hash) {
|
if (!_ctWorker.context || _ctWorker.hash !== hash || isolateTests) {
|
||||||
if (_ctWorker.context)
|
if (_ctWorker.context)
|
||||||
await _ctWorker.context.close();
|
await _ctWorker.context.close();
|
||||||
|
// Context factory sets up video so we want to use that for isolated contexts.
|
||||||
const context = await browser.newContext();
|
// However, it closes the context after the test, so we don't want to use it
|
||||||
const page = await createPage(context);
|
// for shared contexts.
|
||||||
_ctWorker.context = context;
|
_ctWorker.context = isolateTests ? await _contextFactory() : await browser.newContext();
|
||||||
_ctWorker.page = page;
|
|
||||||
_ctWorker.hash = hash;
|
_ctWorker.hash = hash;
|
||||||
await use(page.context());
|
await _ctWorker.context.addInitScript('navigator.serviceWorker.register = () => {}');
|
||||||
return;
|
await _ctWorker.context.exposeFunction('__pw_dispatch', (ordinal: number, args: any[]) => {
|
||||||
|
boundCallbacksForMount[ordinal](...args);
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
const page = _ctWorker.page;
|
await (_ctWorker.context as any)._resetForReuse();
|
||||||
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 use(_ctWorker.context);
|
||||||
},
|
},
|
||||||
|
|
||||||
page: async ({ context, _ctWorker }, use) => {
|
page: async ({ context, viewport }, use) => {
|
||||||
if (_ctWorker.isolateTests) {
|
let page = context.pages()[0];
|
||||||
await use(await createPage(context));
|
await (context as any)._wrapApiCall(async () => {
|
||||||
return;
|
if (!page) {
|
||||||
}
|
page = await context.newPage();
|
||||||
await use(_ctWorker.page!);
|
} 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) => {
|
mount: async ({ page }, use) => {
|
||||||
|
|
@ -148,15 +144,3 @@ function contextHash(context: BrowserContextOptions): string {
|
||||||
};
|
};
|
||||||
return JSON.stringify(hash);
|
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.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(2);
|
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