chore: create artifacts dir in the test runner (#26594)
This commit is contained in:
parent
fe7b956c3b
commit
1ceaa923ea
|
|
@ -62,6 +62,7 @@ export type WorkerInitParams = {
|
|||
repeatEachIndex: number;
|
||||
projectId: string;
|
||||
config: SerializedConfig;
|
||||
artifactsDir: string;
|
||||
};
|
||||
|
||||
export type TestBeginPayload = {
|
||||
|
|
|
|||
|
|
@ -18,12 +18,11 @@ import * as fs from 'fs';
|
|||
import * as path from 'path';
|
||||
import type { APIRequestContext, BrowserContext, Browser, BrowserContextOptions, LaunchOptions, Page, Tracing, Video } from 'playwright-core';
|
||||
import * as playwrightLibrary from 'playwright-core';
|
||||
import { createGuid, debugMode, addInternalStackPrefix, mergeTraceFiles, saveTraceFile, removeFolders, isString, asLocator, jsonStringifyForceASCII } from 'playwright-core/lib/utils';
|
||||
import { createGuid, debugMode, addInternalStackPrefix, mergeTraceFiles, saveTraceFile, isString, asLocator, jsonStringifyForceASCII } from 'playwright-core/lib/utils';
|
||||
import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, TraceMode, VideoMode } from '../types/test';
|
||||
import type { TestInfoImpl } from './worker/testInfo';
|
||||
import { rootTestType } from './common/testType';
|
||||
import type { ContextReuseMode } from './common/config';
|
||||
import { artifactsFolderName } from './isomorphic/folders';
|
||||
import type { ClientInstrumentation, ClientInstrumentationListener } from '../../playwright-core/src/client/clientInstrumentation';
|
||||
import type { ParsedStackTrace } from '../../playwright-core/src/utils/stackTrace';
|
||||
import { currentTestInfo } from './common/globals';
|
||||
|
|
@ -55,7 +54,7 @@ type TestFixtures = PlaywrightTestArgs & PlaywrightTestOptions & {
|
|||
};
|
||||
type WorkerFixtures = PlaywrightWorkerArgs & PlaywrightWorkerOptions & {
|
||||
_browserOptions: LaunchOptions;
|
||||
_artifactsDir: () => string;
|
||||
_artifactsDir: string;
|
||||
};
|
||||
|
||||
const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
||||
|
|
@ -78,17 +77,8 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
video: ['off', { scope: 'worker', option: true }],
|
||||
trace: ['off', { scope: 'worker', option: true }],
|
||||
|
||||
_artifactsDir: [async ({}, use, workerInfo) => {
|
||||
let dir: string | undefined;
|
||||
await use(() => {
|
||||
if (!dir) {
|
||||
dir = path.join(workerInfo.project.outputDir, artifactsFolderName(workerInfo.workerIndex));
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
return dir;
|
||||
});
|
||||
if (dir)
|
||||
await removeFolders([dir]);
|
||||
_artifactsDir: [async ({}, use) => {
|
||||
await use(process.env.TEST_ARTIFACTS_DIR!);
|
||||
}, { scope: 'worker', _title: 'playwright configuration' } as any],
|
||||
|
||||
_browserOptions: [async ({ playwright, headless, channel, launchOptions, connectOptions, _artifactsDir }, use) => {
|
||||
|
|
@ -100,7 +90,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
options.headless = headless;
|
||||
if (channel !== undefined)
|
||||
options.channel = channel;
|
||||
options.tracesDir = path.join(_artifactsDir(), 'traces');
|
||||
options.tracesDir = path.join(_artifactsDir, 'traces');
|
||||
|
||||
for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit]) {
|
||||
(browserType as any)._defaultLaunchOptions = options;
|
||||
|
|
@ -256,7 +246,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
(browserType as any)._defaultContextNavigationTimeout = navigationTimeout || 0;
|
||||
}
|
||||
(playwright.request as any)._defaultContextOptions = { ..._combinedContextOptions };
|
||||
(playwright.request as any)._defaultContextOptions.tracesDir = path.join(_artifactsDir(), 'traces');
|
||||
(playwright.request as any)._defaultContextOptions.tracesDir = path.join(_artifactsDir, 'traces');
|
||||
(playwright.request as any)._defaultContextOptions.timeout = actionTimeout || 0;
|
||||
await use();
|
||||
(playwright.request as any)._defaultContextOptions = undefined;
|
||||
|
|
@ -268,7 +258,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
}, { auto: 'all-hooks-included', _title: 'context configuration' } as any],
|
||||
|
||||
_setupArtifacts: [async ({ playwright, _artifactsDir, trace, screenshot }, use, testInfo) => {
|
||||
const artifactsRecorder = new ArtifactsRecorder(playwright, _artifactsDir(), trace, screenshot);
|
||||
const artifactsRecorder = new ArtifactsRecorder(playwright, _artifactsDir, trace, screenshot);
|
||||
await artifactsRecorder.willStartTest(testInfo as TestInfoImpl);
|
||||
const csiListener: ClientInstrumentationListener = {
|
||||
onApiCallBegin: (apiName: string, params: Record<string, any>, stackTrace: ParsedStackTrace | null, wallTime: number, userData: any) => {
|
||||
|
|
@ -337,7 +327,7 @@ const playwrightFixtures: Fixtures<TestFixtures, WorkerFixtures> = ({
|
|||
}
|
||||
const videoOptions: BrowserContextOptions = captureVideo ? {
|
||||
recordVideo: {
|
||||
dir: _artifactsDir(),
|
||||
dir: _artifactsDir,
|
||||
size: typeof video === 'string' ? undefined : video.size,
|
||||
}
|
||||
} : {};
|
||||
|
|
|
|||
|
|
@ -464,7 +464,9 @@ export class Dispatcher {
|
|||
}
|
||||
|
||||
_createWorker(testGroup: TestGroup, parallelIndex: number, loaderData: SerializedConfig) {
|
||||
const worker = new WorkerHost(testGroup, parallelIndex, loaderData, this._extraEnvByProjectId.get(testGroup.projectId) || {});
|
||||
const projectConfig = this._config.projects.find(p => p.id === testGroup.projectId)!;
|
||||
const outputDir = projectConfig.project.outputDir;
|
||||
const worker = new WorkerHost(testGroup, parallelIndex, loaderData, this._extraEnvByProjectId.get(testGroup.projectId) || {}, outputDir);
|
||||
const handleOutput = (params: TestOutputPayload) => {
|
||||
const chunk = chunkFromParams(params);
|
||||
if (worker.didFail()) {
|
||||
|
|
|
|||
|
|
@ -14,9 +14,13 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import type { TestGroup } from './testGroups';
|
||||
import type { RunPayload, SerializedConfig, WorkerInitParams } from '../common/ipc';
|
||||
import { ProcessHost } from './processHost';
|
||||
import { artifactsFolderName } from '../isomorphic/folders';
|
||||
import { removeFolders } from 'playwright-core/lib/utils';
|
||||
|
||||
let lastWorkerIndex = 0;
|
||||
|
||||
|
|
@ -27,7 +31,7 @@ export class WorkerHost extends ProcessHost {
|
|||
currentTestId: string | null = null;
|
||||
private _params: WorkerInitParams;
|
||||
|
||||
constructor(testGroup: TestGroup, parallelIndex: number, config: SerializedConfig, extraEnv: Record<string, string | undefined>) {
|
||||
constructor(testGroup: TestGroup, parallelIndex: number, config: SerializedConfig, extraEnv: Record<string, string | undefined>, outputDir: string) {
|
||||
const workerIndex = lastWorkerIndex++;
|
||||
super(require.resolve('../worker/workerMain.js'), `worker-${workerIndex}`, {
|
||||
...extraEnv,
|
||||
|
|
@ -44,13 +48,20 @@ export class WorkerHost extends ProcessHost {
|
|||
repeatEachIndex: testGroup.repeatEachIndex,
|
||||
projectId: testGroup.projectId,
|
||||
config,
|
||||
artifactsDir: path.join(outputDir, artifactsFolderName(workerIndex))
|
||||
};
|
||||
}
|
||||
|
||||
async start() {
|
||||
await fs.promises.mkdir(this._params.artifactsDir, { recursive: true });
|
||||
await this.startRunner(this._params, false);
|
||||
}
|
||||
|
||||
override async stop(didFail?: boolean) {
|
||||
await super.stop(didFail);
|
||||
await removeFolders([this._params.artifactsDir]);
|
||||
}
|
||||
|
||||
runTestGroup(runPayload: RunPayload) {
|
||||
this.sendMessageNoReply({ method: 'runTestGroup', params: runPayload });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ export class WorkerMain extends ProcessRunner {
|
|||
super();
|
||||
process.env.TEST_WORKER_INDEX = String(params.workerIndex);
|
||||
process.env.TEST_PARALLEL_INDEX = String(params.parallelIndex);
|
||||
process.env.TEST_ARTIFACTS_DIR = params.artifactsDir;
|
||||
setIsWorkerProcess();
|
||||
|
||||
this._params = params;
|
||||
|
|
|
|||
|
|
@ -801,28 +801,3 @@ test('should use actionTimeout for APIRequestContext', async ({ runInlineTest, s
|
|||
expect(result.exitCode).toBe(0);
|
||||
expect(result.passed).toBe(3);
|
||||
});
|
||||
|
||||
test('should cancel apiRequests if test will timeout', async ({ runInlineTest, server }) => {
|
||||
server.setRoute('/stall', (req, res) => {});
|
||||
const result = await runInlineTest({
|
||||
'playwright.config.js': `
|
||||
module.exports = {
|
||||
timeout: 1000,
|
||||
use: {
|
||||
baseURL: '${server.PREFIX}',
|
||||
}
|
||||
};
|
||||
`,
|
||||
'a.test.ts': `
|
||||
import { test, expect } from '@playwright/test';
|
||||
test('pass', async ({ request }) => {
|
||||
await request.get('/stall')
|
||||
});
|
||||
`,
|
||||
}, { workers: 1 });
|
||||
expect(result.exitCode).toBe(1);
|
||||
expect(result.passed).toBe(0);
|
||||
expect(result.failed).toBe(1);
|
||||
expect(result.output).toContain('apiRequestContext.get: Request context disposed.');
|
||||
expect(result.output).toContain('Test timeout of 1000ms exceeded.');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -424,7 +424,7 @@ for (const mode of ['off', 'retain-on-failure', 'on-first-retry', 'on-all-retrie
|
|||
// Override locale fixture to check in teardown that no temporary trace zip was created.
|
||||
locale: [async ({ locale, _artifactsDir }, use) => {
|
||||
await use(locale);
|
||||
const entries = fs.readdirSync(_artifactsDir());
|
||||
const entries = fs.readdirSync(_artifactsDir);
|
||||
expect(entries.filter(e => e.endsWith('.zip'))).toEqual([]);
|
||||
}, { option: true }],
|
||||
});
|
||||
|
|
@ -449,7 +449,7 @@ for (const mode of ['off', 'retain-on-failure', 'on-first-retry', 'on-all-retrie
|
|||
// Override locale fixture to check in teardown that no temporary trace zip was created.
|
||||
locale: [async ({ locale, _artifactsDir }, use) => {
|
||||
await use(locale);
|
||||
const entries = fs.readdirSync(_artifactsDir());
|
||||
const entries = fs.readdirSync(_artifactsDir);
|
||||
expect(entries.filter(e => e.endsWith('.zip'))).toEqual([]);
|
||||
}, { option: true }],
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue