fix(last-run): remove globalOutputDir (#30571)

This commit is contained in:
Pavel Feldman 2024-04-29 09:02:54 -07:00 committed by GitHub
parent 96f3d19819
commit fb90797d73
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 24 additions and 13 deletions

View File

@ -41,10 +41,8 @@ export const defaultTimeout = 30000;
export class FullConfigInternal { export class FullConfigInternal {
readonly config: FullConfig; readonly config: FullConfig;
readonly globalOutputDir: string;
readonly configDir: string; readonly configDir: string;
readonly configCLIOverrides: ConfigCLIOverrides; readonly configCLIOverrides: ConfigCLIOverrides;
readonly preserveOutputDir: boolean;
readonly webServers: NonNullable<FullConfig['webServer']>[]; readonly webServers: NonNullable<FullConfig['webServer']>[];
readonly plugins: TestRunnerPluginRegistration[]; readonly plugins: TestRunnerPluginRegistration[];
readonly projects: FullProjectInternal[] = []; readonly projects: FullProjectInternal[] = [];
@ -63,13 +61,10 @@ export class FullConfigInternal {
const { resolvedConfigFile, configDir } = location; const { resolvedConfigFile, configDir } = location;
const packageJsonPath = getPackageJsonPath(configDir); const packageJsonPath = getPackageJsonPath(configDir);
const packageJsonDir = packageJsonPath ? path.dirname(packageJsonPath) : undefined; const packageJsonDir = packageJsonPath ? path.dirname(packageJsonPath) : process.cwd();
const throwawayArtifactsPath = packageJsonDir || process.cwd();
this.configDir = configDir; this.configDir = configDir;
this.configCLIOverrides = configCLIOverrides; this.configCLIOverrides = configCLIOverrides;
this.globalOutputDir = takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, userConfig.outputDir), throwawayArtifactsPath, path.resolve(process.cwd()));
this.preserveOutputDir = configCLIOverrides.preserveOutputDir || false;
const privateConfiguration = (userConfig as any)['@playwright/test']; const privateConfiguration = (userConfig as any)['@playwright/test'];
this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p })); this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p }));
@ -128,7 +123,7 @@ export class FullConfigInternal {
} }
const projectConfigs = configCLIOverrides.projects || userConfig.projects || [userConfig]; const projectConfigs = configCLIOverrides.projects || userConfig.projects || [userConfig];
this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, throwawayArtifactsPath)); this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir));
resolveProjectDependencies(this.projects); resolveProjectDependencies(this.projects);
this._assignUniqueProjectIds(this.projects); this._assignUniqueProjectIds(this.projects);
setTransformConfig({ setTransformConfig({
@ -167,7 +162,7 @@ export class FullProjectInternal {
deps: FullProjectInternal[] = []; deps: FullProjectInternal[] = [];
teardown: FullProjectInternal | undefined; teardown: FullProjectInternal | undefined;
constructor(configDir: string, config: Config, fullConfig: FullConfigInternal, projectConfig: Project, configCLIOverrides: ConfigCLIOverrides, throwawayArtifactsPath: string) { constructor(configDir: string, config: Config, fullConfig: FullConfigInternal, projectConfig: Project, configCLIOverrides: ConfigCLIOverrides, packageJsonDir: string) {
this.fullConfig = fullConfig; this.fullConfig = fullConfig;
const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir); const testDir = takeFirst(pathResolve(configDir, projectConfig.testDir), pathResolve(configDir, config.testDir), fullConfig.configDir);
const defaultSnapshotPathTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}'; const defaultSnapshotPathTemplate = '{snapshotDir}/{testFileDir}/{testFileName}-snapshots/{arg}{-projectName}{-snapshotSuffix}{ext}';
@ -176,7 +171,7 @@ export class FullProjectInternal {
this.project = { this.project = {
grep: takeFirst(projectConfig.grep, config.grep, defaultGrep), grep: takeFirst(projectConfig.grep, config.grep, defaultGrep),
grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null), grepInvert: takeFirst(projectConfig.grepInvert, config.grepInvert, null),
outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), path.join(throwawayArtifactsPath, 'test-results')), outputDir: takeFirst(configCLIOverrides.outputDir, pathResolve(configDir, projectConfig.outputDir), pathResolve(configDir, config.outputDir), path.join(packageJsonDir, 'test-results')),
// Note: we either apply the cli override for repeatEach or not, depending on whether the // Note: we either apply the cli override for repeatEach or not, depending on whether the
// project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils. // project is top-level vs dependency. See collectProjectsAndTestFiles in loadUtils.
repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1), repeatEach: takeFirst(projectConfig.repeatEach, config.repeatEach, 1),

View File

@ -154,18 +154,26 @@ export type LastRunInfo = {
}; };
async function writeLastRunInfo(testRun: TestRun, status: FullResult['status']) { async function writeLastRunInfo(testRun: TestRun, status: FullResult['status']) {
await fs.promises.mkdir(testRun.config.globalOutputDir, { recursive: true }); const [project] = filterProjects(testRun.config.projects, testRun.config.cliProjectFilter);
const lastRunReportFile = path.join(testRun.config.globalOutputDir, 'last-run.json'); if (!project)
return;
const outputDir = project.project.outputDir;
await fs.promises.mkdir(outputDir, { recursive: true });
const lastRunReportFile = path.join(outputDir, '.last-run.json');
const failedTests = testRun.rootSuite?.allTests().filter(t => !t.ok()).map(t => t.id); const failedTests = testRun.rootSuite?.allTests().filter(t => !t.ok()).map(t => t.id);
const lastRunReport = JSON.stringify({ status, failedTests }, undefined, 2); const lastRunReport = JSON.stringify({ status, failedTests }, undefined, 2);
await fs.promises.writeFile(lastRunReportFile, lastRunReport); await fs.promises.writeFile(lastRunReportFile, lastRunReport);
} }
export async function readLastRunInfo(config: FullConfigInternal): Promise<LastRunInfo> { export async function readLastRunInfo(config: FullConfigInternal): Promise<LastRunInfo> {
const lastRunReportFile = path.join(config.globalOutputDir, 'last-run.json'); const [project] = filterProjects(config.projects, config.cliProjectFilter);
if (!project)
return { status: 'passed', failedTests: [] };
const outputDir = project.project.outputDir;
try { try {
const lastRunReportFile = path.join(outputDir, '.last-run.json');
return JSON.parse(await fs.promises.readFile(lastRunReportFile, 'utf8')) as LastRunInfo; return JSON.parse(await fs.promises.readFile(lastRunReportFile, 'utf8')) as LastRunInfo;
} catch (e) { } catch {
} }
return { status: 'passed', failedTests: [] }; return { status: 'passed', failedTests: [] };
} }

View File

@ -136,6 +136,7 @@ test('should work with screenshot: on', async ({ runInlineTest }, testInfo) => {
expect(result.passed).toBe(5); expect(result.passed).toBe(5);
expect(result.failed).toBe(5); expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing', 'artifacts-failing',
' test-failed-1.png', ' test-failed-1.png',
'artifacts-own-context-failing', 'artifacts-own-context-failing',
@ -175,6 +176,7 @@ test('should work with screenshot: only-on-failure', async ({ runInlineTest }, t
expect(result.passed).toBe(5); expect(result.passed).toBe(5);
expect(result.failed).toBe(5); expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing', 'artifacts-failing',
' test-failed-1.png', ' test-failed-1.png',
'artifacts-own-context-failing', 'artifacts-own-context-failing',
@ -209,6 +211,7 @@ test('should work with screenshot: only-on-failure & fullPage', async ({ runInli
expect(result.passed).toBe(0); expect(result.passed).toBe(0);
expect(result.failed).toBe(1); expect(result.failed).toBe(1);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-should-fail-and-take-fullPage-screenshots', 'artifacts-should-fail-and-take-fullPage-screenshots',
' test-failed-1.png', ' test-failed-1.png',
]); ]);
@ -230,6 +233,7 @@ test('should work with trace: on', async ({ runInlineTest }, testInfo) => {
expect(result.passed).toBe(5); expect(result.passed).toBe(5);
expect(result.failed).toBe(5); expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing', 'artifacts-failing',
' trace.zip', ' trace.zip',
'artifacts-own-context-failing', 'artifacts-own-context-failing',
@ -265,6 +269,7 @@ test('should work with trace: retain-on-failure', async ({ runInlineTest }, test
expect(result.passed).toBe(5); expect(result.passed).toBe(5);
expect(result.failed).toBe(5); expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing', 'artifacts-failing',
' trace.zip', ' trace.zip',
'artifacts-own-context-failing', 'artifacts-own-context-failing',
@ -290,6 +295,7 @@ test('should work with trace: on-first-retry', async ({ runInlineTest }, testInf
expect(result.passed).toBe(5); expect(result.passed).toBe(5);
expect(result.failed).toBe(5); expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing-retry1', 'artifacts-failing-retry1',
' trace.zip', ' trace.zip',
'artifacts-own-context-failing-retry1', 'artifacts-own-context-failing-retry1',
@ -315,6 +321,7 @@ test('should work with trace: on-all-retries', async ({ runInlineTest }, testInf
expect(result.passed).toBe(5); expect(result.passed).toBe(5);
expect(result.failed).toBe(5); expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing-retry1', 'artifacts-failing-retry1',
' trace.zip', ' trace.zip',
'artifacts-failing-retry2', 'artifacts-failing-retry2',
@ -350,6 +357,7 @@ test('should work with trace: retain-on-first-failure', async ({ runInlineTest }
expect(result.passed).toBe(5); expect(result.passed).toBe(5);
expect(result.failed).toBe(5); expect(result.failed).toBe(5);
expect(listFiles(testInfo.outputPath('test-results'))).toEqual([ expect(listFiles(testInfo.outputPath('test-results'))).toEqual([
'.last-run.json',
'artifacts-failing', 'artifacts-failing',
' trace.zip', ' trace.zip',
'artifacts-own-context-failing', 'artifacts-own-context-failing',