fix(reuse): disable trace/video when reusing the context (#19764)
Previously, we disabled reuse when trace/video was on. Component testing keeps this behavior. References #19059.
This commit is contained in:
parent
137070d889
commit
5cdf118a42
|
|
@ -24,6 +24,7 @@ import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWor
|
||||||
import { store as _baseStore } from './store';
|
import { store as _baseStore } from './store';
|
||||||
import type { TestInfoImpl } from './testInfo';
|
import type { TestInfoImpl } from './testInfo';
|
||||||
import { rootTestType, _setProjectSetup } from './testType';
|
import { rootTestType, _setProjectSetup } from './testType';
|
||||||
|
import { type ContextReuseMode } from './types';
|
||||||
export { expect } from './expect';
|
export { expect } from './expect';
|
||||||
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
|
export { addRunnerPlugin as _addRunnerPlugin } from './plugins';
|
||||||
export const _baseTest: TestType<{}, {}> = rootTestType.test;
|
export const _baseTest: TestType<{}, {}> = rootTestType.test;
|
||||||
|
|
@ -43,7 +44,7 @@ if ((process as any)['__pw_initiator__']) {
|
||||||
|
|
||||||
type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & {
|
type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & {
|
||||||
_combinedContextOptions: BrowserContextOptions,
|
_combinedContextOptions: BrowserContextOptions,
|
||||||
_contextReuseEnabled: boolean,
|
_contextReuseMode: ContextReuseMode,
|
||||||
_reuseContext: boolean,
|
_reuseContext: boolean,
|
||||||
_setupContextOptionsAndArtifacts: void;
|
_setupContextOptionsAndArtifacts: void;
|
||||||
_contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
_contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
||||||
|
|
@ -238,7 +239,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
|
|
||||||
_snapshotSuffix: [process.platform, { scope: 'worker' }],
|
_snapshotSuffix: [process.platform, { scope: 'worker' }],
|
||||||
|
|
||||||
_setupContextOptionsAndArtifacts: [async ({ playwright, _snapshotSuffix, _combinedContextOptions, _browserOptions, _artifactsDir, trace, screenshot, actionTimeout, navigationTimeout, testIdAttribute }, use, testInfo) => {
|
_setupContextOptionsAndArtifacts: [async ({ playwright, _snapshotSuffix, _combinedContextOptions, _reuseContext, _artifactsDir, trace, screenshot, actionTimeout, navigationTimeout, testIdAttribute }, use, testInfo) => {
|
||||||
if (testIdAttribute)
|
if (testIdAttribute)
|
||||||
playwrightLibrary.selectors.setTestIdAttribute(testIdAttribute);
|
playwrightLibrary.selectors.setTestIdAttribute(testIdAttribute);
|
||||||
testInfo.snapshotSuffix = _snapshotSuffix;
|
testInfo.snapshotSuffix = _snapshotSuffix;
|
||||||
|
|
@ -250,7 +251,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
const traceMode = normalizeTraceMode(trace);
|
const traceMode = normalizeTraceMode(trace);
|
||||||
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
|
const defaultTraceOptions = { screenshots: true, snapshots: true, sources: true };
|
||||||
const traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
const traceOptions = typeof trace === 'string' ? defaultTraceOptions : { ...defaultTraceOptions, ...trace, mode: undefined };
|
||||||
const captureTrace = shouldCaptureTrace(traceMode, testInfo);
|
const captureTrace = shouldCaptureTrace(traceMode, testInfo) && !_reuseContext;
|
||||||
const temporaryTraceFiles: string[] = [];
|
const temporaryTraceFiles: string[] = [];
|
||||||
const temporaryScreenshots: string[] = [];
|
const temporaryScreenshots: string[] = [];
|
||||||
const testInfoImpl = testInfo as TestInfoImpl;
|
const testInfoImpl = testInfo as TestInfoImpl;
|
||||||
|
|
@ -462,9 +463,9 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
}));
|
}));
|
||||||
}, { auto: 'all-hooks-included', _title: 'playwright configuration' } as any],
|
}, { auto: 'all-hooks-included', _title: 'playwright configuration' } as any],
|
||||||
|
|
||||||
_contextFactory: [async ({ browser, video, _artifactsDir }, use, testInfo) => {
|
_contextFactory: [async ({ browser, video, _artifactsDir, _reuseContext }, use, testInfo) => {
|
||||||
const videoMode = normalizeVideoMode(video);
|
const videoMode = normalizeVideoMode(video);
|
||||||
const captureVideo = shouldCaptureVideo(videoMode, testInfo);
|
const captureVideo = shouldCaptureVideo(videoMode, testInfo) && !_reuseContext;
|
||||||
const contexts = new Map<BrowserContext, { pages: Page[] }>();
|
const contexts = new Map<BrowserContext, { pages: Page[] }>();
|
||||||
|
|
||||||
await use(async options => {
|
await use(async options => {
|
||||||
|
|
@ -518,10 +519,11 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||||
testInfo.errors.push({ message: prependToError });
|
testInfo.errors.push({ message: prependToError });
|
||||||
}, { scope: 'test', _title: 'context' } as any],
|
}, { scope: 'test', _title: 'context' } as any],
|
||||||
|
|
||||||
_contextReuseEnabled: !!process.env.PW_TEST_REUSE_CONTEXT,
|
_contextReuseMode: process.env.PW_TEST_REUSE_CONTEXT === 'when-possible' ? 'when-possible' : (process.env.PW_TEST_REUSE_CONTEXT ? 'force' : 'none'),
|
||||||
|
|
||||||
_reuseContext: async ({ video, trace, _contextReuseEnabled }, use, testInfo) => {
|
_reuseContext: async ({ video, trace, _contextReuseMode }, use, testInfo) => {
|
||||||
const reuse = _contextReuseEnabled && !shouldCaptureVideo(normalizeVideoMode(video), testInfo) && !shouldCaptureTrace(normalizeTraceMode(trace), testInfo);
|
const reuse = _contextReuseMode === 'force' ||
|
||||||
|
(_contextReuseMode === 'when-possible' && !shouldCaptureVideo(normalizeVideoMode(video), testInfo) && !shouldCaptureTrace(normalizeTraceMode(trace), testInfo));
|
||||||
await use(reuse);
|
await use(reuse);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -602,7 +604,7 @@ export function normalizeVideoMode(video: VideoMode | 'retry-with-video' | { mod
|
||||||
return videoMode;
|
return videoMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldCaptureVideo(videoMode: VideoMode, testInfo: TestInfo) {
|
function shouldCaptureVideo(videoMode: VideoMode, testInfo: TestInfo) {
|
||||||
return (videoMode === 'on' || videoMode === 'retain-on-failure' || (videoMode === 'on-first-retry' && testInfo.retry === 1));
|
return (videoMode === 'on' || videoMode === 'retain-on-failure' || (videoMode === 'on-first-retry' && testInfo.retry === 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -615,7 +617,7 @@ export function normalizeTraceMode(trace: TraceMode | 'retry-with-trace' | { mod
|
||||||
return traceMode;
|
return traceMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function shouldCaptureTrace(traceMode: TraceMode, testInfo: TestInfo) {
|
function shouldCaptureTrace(traceMode: TraceMode, testInfo: TestInfo) {
|
||||||
return traceMode === 'on' || traceMode === 'retain-on-failure' || (traceMode === 'on-first-retry' && testInfo.retry === 1);
|
return traceMode === 'on' || traceMode === 'retain-on-failure' || (traceMode === 'on-first-retry' && testInfo.retry === 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { Fixtures, Locator, Page, BrowserContextOptions, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, BrowserContext } from './types';
|
import type { Fixtures, Locator, Page, BrowserContextOptions, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, BrowserContext, ContextReuseMode } from './types';
|
||||||
import type { Component, JsxComponent, MountOptions } from '../types/component';
|
import type { Component, JsxComponent, MountOptions } from '../types/component';
|
||||||
|
|
||||||
let boundCallbacksForMount: Function[] = [];
|
let boundCallbacksForMount: Function[] = [];
|
||||||
|
|
@ -29,9 +29,9 @@ export const fixtures: Fixtures<
|
||||||
mount: (component: any, options: any) => Promise<MountResult>;
|
mount: (component: any, options: any) => Promise<MountResult>;
|
||||||
},
|
},
|
||||||
PlaywrightWorkerArgs & PlaywrightWorkerOptions & { _ctWorker: { context: BrowserContext | undefined, hash: string } },
|
PlaywrightWorkerArgs & PlaywrightWorkerOptions & { _ctWorker: { context: BrowserContext | undefined, hash: string } },
|
||||||
{ _contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>, _contextReuseEnabled: boolean }> = {
|
{ _contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>, _contextReuseMode: ContextReuseMode }> = {
|
||||||
|
|
||||||
_contextReuseEnabled: true,
|
_contextReuseMode: 'when-possible',
|
||||||
|
|
||||||
serviceWorkers: 'block',
|
serviceWorkers: 'block',
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -76,3 +76,5 @@ export interface FullProjectInternal extends FullProjectPublic {
|
||||||
export interface ReporterInternal extends Reporter {
|
export interface ReporterInternal extends Reporter {
|
||||||
_onExit?(): void | Promise<void>;
|
_onExit?(): void | Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ContextReuseMode = 'none' | 'force' | 'when-possible';
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { test, expect } from './playwright-test-fixtures';
|
import { test, expect } from './playwright-test-fixtures';
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
test('should reuse context', async ({ runInlineTest }) => {
|
test('should reuse context', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
|
|
@ -56,7 +57,7 @@ test('should reuse context', async ({ runInlineTest }) => {
|
||||||
expect(result.passed).toBe(5);
|
expect(result.passed).toBe(5);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not reuse context with video', async ({ runInlineTest }) => {
|
test('should not reuse context with video if mode=when-possible', async ({ runInlineTest }, testInfo) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -65,23 +66,54 @@ test('should not reuse context with video', async ({ runInlineTest }) => {
|
||||||
`,
|
`,
|
||||||
'src/reuse.test.ts': `
|
'src/reuse.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
let lastContext;
|
let lastContextGuid;
|
||||||
|
|
||||||
test('one', async ({ context }) => {
|
test('one', async ({ context }) => {
|
||||||
lastContext = context;
|
lastContextGuid = context._guid;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('two', async ({ context }) => {
|
test('two', async ({ context }) => {
|
||||||
expect(context).not.toBe(lastContext);
|
expect(context._guid).not.toBe(lastContextGuid);
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
}, { workers: 1 }, { PW_TEST_REUSE_CONTEXT: 'when-possible' });
|
||||||
|
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.passed).toBe(2);
|
||||||
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'reuse-one', 'video.webm'))).toBeFalsy();
|
||||||
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'reuse-two', 'video.webm'))).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should reuse context and disable video if mode=force', async ({ runInlineTest }, testInfo) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.ts': `
|
||||||
|
export default {
|
||||||
|
use: { video: 'on' },
|
||||||
|
};
|
||||||
|
`,
|
||||||
|
'reuse.test.ts': `
|
||||||
|
const { test } = pwt;
|
||||||
|
let lastContextGuid;
|
||||||
|
|
||||||
|
test('one', async ({ context, page }) => {
|
||||||
|
lastContextGuid = context._guid;
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('two', async ({ context, page }) => {
|
||||||
|
expect(context._guid).toBe(lastContextGuid);
|
||||||
|
await page.waitForTimeout(2000);
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { workers: 1 }, { PW_TEST_REUSE_CONTEXT: '1' });
|
}, { workers: 1 }, { PW_TEST_REUSE_CONTEXT: '1' });
|
||||||
|
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(2);
|
expect(result.passed).toBe(2);
|
||||||
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'reuse-one', 'video.webm'))).toBeFalsy();
|
||||||
|
expect(fs.existsSync(testInfo.outputPath('test-results', 'reuse-two', 'video.webm'))).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should not reuse context with trace', async ({ runInlineTest }) => {
|
test('should not reuse context with trace if mode=when-possible', async ({ runInlineTest }) => {
|
||||||
const result = await runInlineTest({
|
const result = await runInlineTest({
|
||||||
'playwright.config.ts': `
|
'playwright.config.ts': `
|
||||||
export default {
|
export default {
|
||||||
|
|
@ -90,17 +122,17 @@ test('should not reuse context with trace', async ({ runInlineTest }) => {
|
||||||
`,
|
`,
|
||||||
'src/reuse.test.ts': `
|
'src/reuse.test.ts': `
|
||||||
const { test } = pwt;
|
const { test } = pwt;
|
||||||
let lastContext;
|
let lastContextGuid;
|
||||||
|
|
||||||
test('one', async ({ context }) => {
|
test('one', async ({ context }) => {
|
||||||
lastContext = context;
|
lastContextGuid = context._guid;
|
||||||
});
|
});
|
||||||
|
|
||||||
test('two', async ({ context }) => {
|
test('two', async ({ context }) => {
|
||||||
expect(context).not.toBe(lastContext);
|
expect(context._guid).not.toBe(lastContextGuid);
|
||||||
});
|
});
|
||||||
`,
|
`,
|
||||||
}, { workers: 1 }, { PW_TEST_REUSE_CONTEXT: '1' });
|
}, { workers: 1 }, { PW_TEST_REUSE_CONTEXT: 'when-possible' });
|
||||||
|
|
||||||
expect(result.exitCode).toBe(0);
|
expect(result.exitCode).toBe(0);
|
||||||
expect(result.passed).toBe(2);
|
expect(result.passed).toBe(2);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue