Skip to content

Commit fb90797

Browse files
authored
fix(last-run): remove globalOutputDir (#30571)
1 parent 96f3d19 commit fb90797

File tree

3 files changed

+24
-13
lines changed

3 files changed

+24
-13
lines changed

packages/playwright/src/common/config.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,8 @@ export const defaultTimeout = 30000;
4141

4242
export class FullConfigInternal {
4343
readonly config: FullConfig;
44-
readonly globalOutputDir: string;
4544
readonly configDir: string;
4645
readonly configCLIOverrides: ConfigCLIOverrides;
47-
readonly preserveOutputDir: boolean;
4846
readonly webServers: NonNullable<FullConfig['webServer']>[];
4947
readonly plugins: TestRunnerPluginRegistration[];
5048
readonly projects: FullProjectInternal[] = [];
@@ -63,13 +61,10 @@ export class FullConfigInternal {
6361

6462
const { resolvedConfigFile, configDir } = location;
6563
const packageJsonPath = getPackageJsonPath(configDir);
66-
const packageJsonDir = packageJsonPath ? path.dirname(packageJsonPath) : undefined;
67-
const throwawayArtifactsPath = packageJsonDir || process.cwd();
64+
const packageJsonDir = packageJsonPath ? path.dirname(packageJsonPath) : process.cwd();
6865

6966
this.configDir = configDir;
7067
this.configCLIOverrides = configCLIOverrides;
71-
this.globalOutputDir = takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, userConfig.outputDir), throwawayArtifactsPath, path.resolve(process.cwd()));
72-
this.preserveOutputDir = configCLIOverrides.preserveOutputDir || false;
7368
const privateConfiguration = (userConfig as any)['@playwright/test'];
7469
this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p }));
7570

@@ -128,7 +123,7 @@ export class FullConfigInternal {
128123
}
129124

130125
const projectConfigs = configCLIOverrides.projects || userConfig.projects || [userConfig];
131-
this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, throwawayArtifactsPath));
126+
this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir));
132127
resolveProjectDependencies(this.projects);
133128
this._assignUniqueProjectIds(this.projects);
134129
setTransformConfig({
@@ -167,7 +162,7 @@ export class FullProjectInternal {
167162
deps: FullProjectInternal[] = [];
168163
teardown: FullProjectInternal | undefined;
169164

170-
constructor(configDir: string, config: Config, fullConfig: FullConfigInternal, projectConfig: Project, configCLIOverrides: ConfigCLIOverrides, throwawayArtifactsPath: string) {
165+
constructor(configDir: string, config: Config, fullConfig: FullConfigInternal, projectConfig: Project, configCLIOverrides: ConfigCLIOverrides, packageJsonDir: string) {
171166
this.fullConfig = fullConfig;
172167
const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
173168
const defaultSnapshotPathTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}';
@@ -176,7 +171,7 @@ export class FullProjectInternal {
176171
this.project = {
177172
grep: takeFirst(projectConfig.grep, config.grep, defaultGrep),
178173
grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null),
179-
outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), path.join(throwawayArtifactsPath, 'test-results')),
174+
outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), path.join(packageJsonDir, 'test-results')),
180175
// Note: we either apply the cli override for repeatEach or not, depending on whether the
181176
// project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils.
182177
repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1),

packages/playwright/src/runner/runner.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -154,18 +154,26 @@ export type LastRunInfo = {
154154
};
155155

156156
async function writeLastRunInfo(testRun: TestRun, status: FullResult['status']) {
157-
await fs.promises.mkdir(testRun.config.globalOutputDir, { recursive: true });
158-
const lastRunReportFile = path.join(testRun.config.globalOutputDir, 'last-run.json');
157+
const [project] = filterProjects(testRun.config.projects, testRun.config.cliProjectFilter);
158+
if (!project)
159+
return;
160+
const outputDir = project.project.outputDir;
161+
await fs.promises.mkdir(outputDir, { recursive: true });
162+
const lastRunReportFile = path.join(outputDir, '.last-run.json');
159163
const failedTests = testRun.rootSuite?.allTests().filter(t => !t.ok()).map(t => t.id);
160164
const lastRunReport = JSON.stringify({ status, failedTests }, undefined, 2);
161165
await fs.promises.writeFile(lastRunReportFile, lastRunReport);
162166
}
163167

164168
export async function readLastRunInfo(config: FullConfigInternal): Promise<LastRunInfo> {
165-
const lastRunReportFile = path.join(config.globalOutputDir, 'last-run.json');
169+
const [project] = filterProjects(config.projects, config.cliProjectFilter);
170+
if (!project)
171+
return { status: 'passed', failedTests: [] };
172+
const outputDir = project.project.outputDir;
166173
try {
174+
const lastRunReportFile = path.join(outputDir, '.last-run.json');
167175
return JSON.parse(await fs.promises.readFile(lastRunReportFile, 'utf8')) as LastRunInfo;
168-
} catch (e) {
176+
} catch {
169177
}
170178
return { status: 'passed', failedTests: [] };
171179
}

tests/playwright-test/playwright.artifacts.spec.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,7 @@ test('should work with screenshot: on', async ({ runInlineTest }, testInfo) => {
136136
expect(result.passed).toBe(5);
137137
expect(result.failed).toBe(5);
138138
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
139+
'.last-run.json',
139140
'artifacts-failing',
140141
' test-failed-1.png',
141142
'artifacts-own-context-failing',
@@ -175,6 +176,7 @@ test('should work with screenshot: only-on-failure', async ({ runInlineTest }, t
175176
expect(result.passed).toBe(5);
176177
expect(result.failed).toBe(5);
177178
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
179+
'.last-run.json',
178180
'artifacts-failing',
179181
' test-failed-1.png',
180182
'artifacts-own-context-failing',
@@ -209,6 +211,7 @@ test('should work with screenshot: only-on-failure & fullPage', async ({ runInli
209211
expect(result.passed).toBe(0);
210212
expect(result.failed).toBe(1);
211213
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
214+
'.last-run.json',
212215
'artifacts-should-fail-and-take-fullPage-screenshots',
213216
' test-failed-1.png',
214217
]);
@@ -230,6 +233,7 @@ test('should work with trace: on', async ({ runInlineTest }, testInfo) => {
230233
expect(result.passed).toBe(5);
231234
expect(result.failed).toBe(5);
232235
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
236+
'.last-run.json',
233237
'artifacts-failing',
234238
' trace.zip',
235239
'artifacts-own-context-failing',
@@ -265,6 +269,7 @@ test('should work with trace: retain-on-failure', async ({ runInlineTest }, test
265269
expect(result.passed).toBe(5);
266270
expect(result.failed).toBe(5);
267271
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
272+
'.last-run.json',
268273
'artifacts-failing',
269274
' trace.zip',
270275
'artifacts-own-context-failing',
@@ -290,6 +295,7 @@ test('should work with trace: on-first-retry', async ({ runInlineTest }, testInf
290295
expect(result.passed).toBe(5);
291296
expect(result.failed).toBe(5);
292297
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
298+
'.last-run.json',
293299
'artifacts-failing-retry1',
294300
' trace.zip',
295301
'artifacts-own-context-failing-retry1',
@@ -315,6 +321,7 @@ test('should work with trace: on-all-retries', async ({ runInlineTest }, testInf
315321
expect(result.passed).toBe(5);
316322
expect(result.failed).toBe(5);
317323
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
324+
'.last-run.json',
318325
'artifacts-failing-retry1',
319326
' trace.zip',
320327
'artifacts-failing-retry2',
@@ -350,6 +357,7 @@ test('should work with trace: retain-on-first-failure', async ({ runInlineTest }
350357
expect(result.passed).toBe(5);
351358
expect(result.failed).toBe(5);
352359
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
360+
'.last-run.json',
353361
'artifacts-failing',
354362
' trace.zip',
355363
'artifacts-own-context-failing',

0 commit comments

Comments
 (0)