From 9cd33a752d4fe8ee07bde97464d9a372bc2e4ef2 Mon Sep 17 00:00:00 2001 From: vitalets Date: Wed, 15 Jan 2025 11:53:30 +0400 Subject: [PATCH 1/5] Add new config prop populateGitInfo, see #34094 --- packages/playwright/src/common/config.ts | 5 ++++ .../playwright/src/isomorphic/teleReceiver.ts | 1 + packages/playwright/types/test.d.ts | 22 ++++++++++++++++ tests/playwright-test/reporter-html.spec.ts | 25 ++++++++++++++++--- 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/packages/playwright/src/common/config.ts b/packages/playwright/src/common/config.ts index 443cb583196fb..9f909e8e206a7 100644 --- a/packages/playwright/src/common/config.ts +++ b/packages/playwright/src/common/config.ts @@ -20,6 +20,7 @@ import os from 'os'; import type { Config, Fixtures, Project, ReporterDescription } from '../../types/test'; import type { Location } from '../../types/testReporter'; import type { TestRunnerPluginRegistration } from '../plugins'; +import { gitCommitInfo } from '../plugins/gitCommitInfoPlugin'; import { getPackageJsonPath, mergeObjects } from '../util'; import type { Matcher } from '../util'; import type { ConfigCLIOverrides } from './ipc'; @@ -91,6 +92,7 @@ export class FullConfigInternal { grepInvert: takeFirst(userConfig.grepInvert, null), maxFailures: takeFirst(configCLIOverrides.debug ? 1 : undefined, configCLIOverrides.maxFailures, userConfig.maxFailures, 0), metadata: takeFirst(userConfig.metadata, {}), + populateGitInfo: takeFirst(userConfig.populateGitInfo, false), preserveOutput: takeFirst(userConfig.preserveOutput, 'always'), reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]), reportSlowTests: takeFirst(userConfig.reportSlowTests, { max: 5, threshold: 15000 }), @@ -134,6 +136,9 @@ export class FullConfigInternal { this.webServers = []; } + if (this.config.populateGitInfo) + this.plugins.push({ factory: gitCommitInfo }); + const projectConfigs = configCLIOverrides.projects || userConfig.projects || [userConfig]; this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir)); resolveProjectDependencies(this.projects); diff --git a/packages/playwright/src/isomorphic/teleReceiver.ts b/packages/playwright/src/isomorphic/teleReceiver.ts index 1d41b793cd80e..7079017bc6878 100644 --- a/packages/playwright/src/isomorphic/teleReceiver.ts +++ b/packages/playwright/src/isomorphic/teleReceiver.ts @@ -596,6 +596,7 @@ export const baseFullConfig: reporterTypes.FullConfig = { grepInvert: null, maxFailures: 0, metadata: {}, + populateGitInfo: false, preserveOutput: 'always', projects: [], reporter: [[process.env.CI ? 'dot' : 'list']], diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index 501d1bcdb1bf6..3d047edde45bb 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -1293,6 +1293,23 @@ interface TestConfig { */ outputDir?: string; + /** + * Whether to populate [metadata](https://playwright.dev/docs/api/class-testconfig#test-config-output-metadata) with Git info. + * + * **Usage** + * + * ```js + * // playwright.config.ts + * import { defineConfig } from '@playwright/test'; + * + * export default defineConfig({ + * populateGitInfo: !!process.env.CI, + * }); + * ``` + * + */ + populateGitInfo?: boolean; + /** * Whether to preserve test output in the * [testConfig.outputDir](https://playwright.dev/docs/api/class-testconfig#test-config-output-dir). Defaults to @@ -1796,6 +1813,11 @@ export interface FullConfig { */ metadata: Metadata; + /** + * See [testConfig.populateGitInfo](https://playwright.dev/docs/api/class-testconfig#test-config-populategitinfo). + */ + populateGitInfo: boolean; + /** * See [testConfig.preserveOutput](https://playwright.dev/docs/api/class-testconfig#test-config-preserve-output). */ diff --git a/tests/playwright-test/reporter-html.spec.ts b/tests/playwright-test/reporter-html.spec.ts index 2640cb61c9d7e..de01207873a80 100644 --- a/tests/playwright-test/reporter-html.spec.ts +++ b/tests/playwright-test/reporter-html.spec.ts @@ -1144,14 +1144,12 @@ for (const useIntermediateMergeReport of [true, false] as const) { }); test.describe('gitCommitInfo plugin', () => { - test('should include metadata', async ({ runInlineTest, writeFiles, showReport, page }) => { + test('should include metadata with populateGitInfo = true', async ({ runInlineTest, writeFiles, showReport, page }) => { const files = { 'uncommitted.txt': `uncommitted file`, 'playwright.config.ts': ` - import { gitCommitInfo } from 'playwright/lib/plugins'; import { test, expect } from '@playwright/test'; - const plugins = [gitCommitInfo()]; - export default { '@playwright/test': { plugins } }; + export default { populateGitInfo: true }; `, 'example.spec.ts': ` import { test, expect } from '@playwright/test'; @@ -1197,6 +1195,25 @@ for (const useIntermediateMergeReport of [true, false] as const) { await expect.soft(page.getByTestId('metadata-error')).not.toBeVisible(); }); + test('should not include metadata with populateGitInfo = false', async ({ runInlineTest, showReport, page }) => { + const result = await runInlineTest({ + 'uncommitted.txt': `uncommitted file`, + 'playwright.config.ts': ` + export default { populateGitInfo: false }; + `, + 'example.spec.ts': ` + import { test, expect } from '@playwright/test'; + test('my sample test', async ({}) => { expect(2).toBe(2); }); + `, + }, { reporter: 'dot,html' }, { PLAYWRIGHT_HTML_OPEN: 'never' }, undefined); + + await showReport(); + + expect(result.exitCode).toBe(0); + await expect.soft(page.locator('text="my sample test"')).toBeVisible(); + await expect.soft(page.getByTestId('metadata-error')).not.toBeVisible(); + await expect.soft(page.getByTestId('metadata-chip')).not.toBeVisible(); + }); test('should use explicitly supplied metadata', async ({ runInlineTest, showReport, page }) => { const result = await runInlineTest({ From 2a7ec73ad0ee2e987c1d4e6cd79782ec6a4d48b5 Mon Sep 17 00:00:00 2001 From: vitalets Date: Thu, 16 Jan 2025 11:01:54 +0400 Subject: [PATCH 2/5] use markdown-first way and inverse deps --- docs/src/test-api/class-fullconfig.md | 6 ++++++ docs/src/test-api/class-testconfig.md | 16 ++++++++++++++++ packages/playwright/src/common/config.ts | 4 ---- .../src/plugins/gitCommitInfoPlugin.ts | 6 ++++++ packages/playwright/src/runner/runner.ts | 3 +++ packages/playwright/types/test.d.ts | 5 +++-- 6 files changed, 34 insertions(+), 6 deletions(-) diff --git a/docs/src/test-api/class-fullconfig.md b/docs/src/test-api/class-fullconfig.md index 923c9fa858fe2..edf7c3a3daf7a 100644 --- a/docs/src/test-api/class-fullconfig.md +++ b/docs/src/test-api/class-fullconfig.md @@ -64,6 +64,12 @@ See [`property: TestConfig.maxFailures`]. See [`property: TestConfig.metadata`]. +## property: FullConfig.populateGitInfo +* since: v1.50 +- type: <[boolean]> + +See [`property: TestConfig.populateGitInfo`]. + ## property: FullConfig.preserveOutput * since: v1.10 - type: <[PreserveOutput]<"always"|"never"|"failures-only">> diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index 5a67ea36d4649..59fa3f50b6747 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -321,6 +321,22 @@ This path will serve as the base directory for each test file snapshot directory ## property: TestConfig.snapshotPathTemplate = %%-test-config-snapshot-path-template-%% * since: v1.28 +## property: TestConfig.populateGitInfo +* since: v1.50 +- type: ?<[boolean]> + +Whether to populate [`property: TestConfig.metadata`] with Git info. + +**Usage** + +```js title="playwright.config.ts" +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + populateGitInfo: !!process.env.CI, +}); +``` + ## property: TestConfig.preserveOutput * since: v1.10 - type: ?<[PreserveOutput]<"always"|"never"|"failures-only">> diff --git a/packages/playwright/src/common/config.ts b/packages/playwright/src/common/config.ts index 9f909e8e206a7..2e79cac61fb31 100644 --- a/packages/playwright/src/common/config.ts +++ b/packages/playwright/src/common/config.ts @@ -20,7 +20,6 @@ import os from 'os'; import type { Config, Fixtures, Project, ReporterDescription } from '../../types/test'; import type { Location } from '../../types/testReporter'; import type { TestRunnerPluginRegistration } from '../plugins'; -import { gitCommitInfo } from '../plugins/gitCommitInfoPlugin'; import { getPackageJsonPath, mergeObjects } from '../util'; import type { Matcher } from '../util'; import type { ConfigCLIOverrides } from './ipc'; @@ -136,9 +135,6 @@ export class FullConfigInternal { this.webServers = []; } - if (this.config.populateGitInfo) - this.plugins.push({ factory: gitCommitInfo }); - const projectConfigs = configCLIOverrides.projects || userConfig.projects || [userConfig]; this.projects = projectConfigs.map(p => new FullProjectInternal(configDir, userConfig, this, p, this.configCLIOverrides, packageJsonDir)); resolveProjectDependencies(this.projects); diff --git a/packages/playwright/src/plugins/gitCommitInfoPlugin.ts b/packages/playwright/src/plugins/gitCommitInfoPlugin.ts index 4c55a3eab33b3..9422bcb4d89df 100644 --- a/packages/playwright/src/plugins/gitCommitInfoPlugin.ts +++ b/packages/playwright/src/plugins/gitCommitInfoPlugin.ts @@ -17,9 +17,15 @@ import { createGuid, spawnAsync } from 'playwright-core/lib/utils'; import type { TestRunnerPlugin } from './'; import type { FullConfig } from '../../types/testReporter'; +import type { FullConfigInternal } from '../common/config'; const GIT_OPERATIONS_TIMEOUT_MS = 1500; +export const addGitCommitInfoPlugin = (fullConfig: FullConfigInternal) => { + if (fullConfig.config.populateGitInfo) + fullConfig.plugins.push({ factory: gitCommitInfo }); +}; + export const gitCommitInfo = (options?: GitCommitInfoPluginOptions): TestRunnerPlugin => { return { name: 'playwright:git-commit-info', diff --git a/packages/playwright/src/runner/runner.ts b/packages/playwright/src/runner/runner.ts index a1e73657c9307..51eb15e29909a 100644 --- a/packages/playwright/src/runner/runner.ts +++ b/packages/playwright/src/runner/runner.ts @@ -17,6 +17,7 @@ import type { FullResult, TestError } from '../../types/testReporter'; import { webServerPluginsForConfig } from '../plugins/webServerPlugin'; +import { addGitCommitInfoPlugin } from '../plugins/gitCommitInfoPlugin'; import { collectFilesForProject, filterProjects } from './projectUtils'; import { createErrorCollectingReporter, createReporters } from './reporters'; import { TestRun, createApplyRebaselinesTask, createClearCacheTask, createGlobalSetupTasks, createLoadTask, createPluginSetupTasks, createReportBeginTask, createRunTestsTasks, createStartDevServerTask, runTasks } from './tasks'; @@ -70,6 +71,8 @@ export class Runner { const config = this._config; const listOnly = config.cliListOnly; + addGitCommitInfoPlugin(config); + // Legacy webServer support. webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p })); diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index 3d047edde45bb..8e1ca2f44750d 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -1294,7 +1294,8 @@ interface TestConfig { outputDir?: string; /** - * Whether to populate [metadata](https://playwright.dev/docs/api/class-testconfig#test-config-output-metadata) with Git info. + * Whether to populate [testConfig.metadata](https://playwright.dev/docs/api/class-testconfig#test-config-metadata) + * with Git info. * * **Usage** * @@ -1814,7 +1815,7 @@ export interface FullConfig { metadata: Metadata; /** - * See [testConfig.populateGitInfo](https://playwright.dev/docs/api/class-testconfig#test-config-populategitinfo). + * See [testConfig.populateGitInfo](https://playwright.dev/docs/api/class-testconfig#test-config-populate-git-info). */ populateGitInfo: boolean; From 7355ed3e451028fc6031354fa0f312c492a011fb Mon Sep 17 00:00:00 2001 From: vitalets Date: Sat, 18 Jan 2025 18:43:40 +0400 Subject: [PATCH 3/5] removed from full config, set ver 1.51 and handle ui mode --- docs/src/test-api/class-fullconfig.md | 6 ---- docs/src/test-api/class-testconfig.md | 4 +-- packages/playwright/src/common/config.ts | 3 +- .../playwright/src/isomorphic/teleReceiver.ts | 1 - .../src/plugins/gitCommitInfoPlugin.ts | 2 +- packages/playwright/src/runner/testServer.ts | 2 ++ packages/playwright/types/test.d.ts | 7 +--- .../playwright-test/ui-mode-metadata.spec.ts | 35 +++++++++++++++++++ 8 files changed, 43 insertions(+), 17 deletions(-) create mode 100644 tests/playwright-test/ui-mode-metadata.spec.ts diff --git a/docs/src/test-api/class-fullconfig.md b/docs/src/test-api/class-fullconfig.md index edf7c3a3daf7a..923c9fa858fe2 100644 --- a/docs/src/test-api/class-fullconfig.md +++ b/docs/src/test-api/class-fullconfig.md @@ -64,12 +64,6 @@ See [`property: TestConfig.maxFailures`]. See [`property: TestConfig.metadata`]. -## property: FullConfig.populateGitInfo -* since: v1.50 -- type: <[boolean]> - -See [`property: TestConfig.populateGitInfo`]. - ## property: FullConfig.preserveOutput * since: v1.10 - type: <[PreserveOutput]<"always"|"never"|"failures-only">> diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index 59fa3f50b6747..bfcf5a260f948 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -322,10 +322,10 @@ This path will serve as the base directory for each test file snapshot directory * since: v1.28 ## property: TestConfig.populateGitInfo -* since: v1.50 +* since: v1.51 - type: ?<[boolean]> -Whether to populate [`property: TestConfig.metadata`] with Git info. +Whether to populate [`property: TestConfig.metadata`] with Git info. The metadata will automatically appear in the HTML report and is available in Reporter API. **Usage** diff --git a/packages/playwright/src/common/config.ts b/packages/playwright/src/common/config.ts index 2e79cac61fb31..2248dfb79d8bc 100644 --- a/packages/playwright/src/common/config.ts +++ b/packages/playwright/src/common/config.ts @@ -46,6 +46,7 @@ export class FullConfigInternal { readonly plugins: TestRunnerPluginRegistration[]; readonly projects: FullProjectInternal[] = []; readonly singleTSConfigPath?: string; + readonly populateGitInfo: boolean; cliArgs: string[] = []; cliGrep: string | undefined; cliGrepInvert: string | undefined; @@ -75,6 +76,7 @@ export class FullConfigInternal { const privateConfiguration = (userConfig as any)['@playwright/test']; this.plugins = (privateConfiguration?.plugins || []).map((p: any) => ({ factory: p })); this.singleTSConfigPath = pathResolve(configDir, userConfig.tsconfig); + this.populateGitInfo = takeFirst(userConfig.populateGitInfo, false); this.globalSetups = (Array.isArray(userConfig.globalSetup) ? userConfig.globalSetup : [userConfig.globalSetup]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined); this.globalTeardowns = (Array.isArray(userConfig.globalTeardown) ? userConfig.globalTeardown : [userConfig.globalTeardown]).map(s => resolveScript(s, configDir)).filter(script => script !== undefined); @@ -91,7 +93,6 @@ export class FullConfigInternal { grepInvert: takeFirst(userConfig.grepInvert, null), maxFailures: takeFirst(configCLIOverrides.debug ? 1 : undefined, configCLIOverrides.maxFailures, userConfig.maxFailures, 0), metadata: takeFirst(userConfig.metadata, {}), - populateGitInfo: takeFirst(userConfig.populateGitInfo, false), preserveOutput: takeFirst(userConfig.preserveOutput, 'always'), reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]), reportSlowTests: takeFirst(userConfig.reportSlowTests, { max: 5, threshold: 15000 }), diff --git a/packages/playwright/src/isomorphic/teleReceiver.ts b/packages/playwright/src/isomorphic/teleReceiver.ts index 7079017bc6878..1d41b793cd80e 100644 --- a/packages/playwright/src/isomorphic/teleReceiver.ts +++ b/packages/playwright/src/isomorphic/teleReceiver.ts @@ -596,7 +596,6 @@ export const baseFullConfig: reporterTypes.FullConfig = { grepInvert: null, maxFailures: 0, metadata: {}, - populateGitInfo: false, preserveOutput: 'always', projects: [], reporter: [[process.env.CI ? 'dot' : 'list']], diff --git a/packages/playwright/src/plugins/gitCommitInfoPlugin.ts b/packages/playwright/src/plugins/gitCommitInfoPlugin.ts index 9422bcb4d89df..2244d80a9c090 100644 --- a/packages/playwright/src/plugins/gitCommitInfoPlugin.ts +++ b/packages/playwright/src/plugins/gitCommitInfoPlugin.ts @@ -22,7 +22,7 @@ import type { FullConfigInternal } from '../common/config'; const GIT_OPERATIONS_TIMEOUT_MS = 1500; export const addGitCommitInfoPlugin = (fullConfig: FullConfigInternal) => { - if (fullConfig.config.populateGitInfo) + if (fullConfig.populateGitInfo) fullConfig.plugins.push({ factory: gitCommitInfo }); }; diff --git a/packages/playwright/src/runner/testServer.ts b/packages/playwright/src/runner/testServer.ts index e3a61329e2a8c..e4ff3a7a2ffc6 100644 --- a/packages/playwright/src/runner/testServer.ts +++ b/packages/playwright/src/runner/testServer.ts @@ -39,6 +39,7 @@ import { baseFullConfig } from '../isomorphic/teleReceiver'; import { InternalReporter } from '../reporters/internalReporter'; import type { ReporterV2 } from '../reporters/reporterV2'; import { internalScreen } from '../reporters/base'; +import { addGitCommitInfoPlugin } from '../plugins/gitCommitInfoPlugin'; const originalStdoutWrite = process.stdout.write; const originalStderrWrite = process.stderr.write; @@ -406,6 +407,7 @@ export class TestServerDispatcher implements TestServerInterface { // Preserve plugin instances between setup and build. if (!this._plugins) { webServerPluginsForConfig(config).forEach(p => config.plugins.push({ factory: p })); + addGitCommitInfoPlugin(config); this._plugins = config.plugins || []; } else { config.plugins.splice(0, config.plugins.length, ...this._plugins); diff --git a/packages/playwright/types/test.d.ts b/packages/playwright/types/test.d.ts index ce5b78959a8de..4310bc3ad991f 100644 --- a/packages/playwright/types/test.d.ts +++ b/packages/playwright/types/test.d.ts @@ -1295,7 +1295,7 @@ interface TestConfig { /** * Whether to populate [testConfig.metadata](https://playwright.dev/docs/api/class-testconfig#test-config-metadata) - * with Git info. + * with Git info. The metadata will automatically appear in the HTML report and is available in Reporter API. * * **Usage** * @@ -1814,11 +1814,6 @@ export interface FullConfig { */ metadata: Metadata; - /** - * See [testConfig.populateGitInfo](https://playwright.dev/docs/api/class-testconfig#test-config-populate-git-info). - */ - populateGitInfo: boolean; - /** * See [testConfig.preserveOutput](https://playwright.dev/docs/api/class-testconfig#test-config-preserve-output). */ diff --git a/tests/playwright-test/ui-mode-metadata.spec.ts b/tests/playwright-test/ui-mode-metadata.spec.ts new file mode 100644 index 0000000000000..5466d4f0070f8 --- /dev/null +++ b/tests/playwright-test/ui-mode-metadata.spec.ts @@ -0,0 +1,35 @@ +/** + * Copyright (c) Microsoft Corporation. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { test } from './ui-mode-fixtures'; + +test.only('should display git info metadata', async ({ runUITest }) => { + const { page } = await runUITest({ + 'playwright.config.ts': ` + import { defineConfig } from '@playwright/test'; + export default defineConfig({ + populateGitInfo: true, + }); + `, + 'a.test.js': ` + import { test, expect } from '@playwright/test'; + test('should work', async ({}) => {}); + ` + }); + await page.getByTitle('Run all').click(); + + // todo: what to check? +}); From 6042395537628186e11f7482981b538054f2a750 Mon Sep 17 00:00:00 2001 From: vitalets Date: Sat, 18 Jan 2025 21:03:19 +0400 Subject: [PATCH 4/5] fix lint --- tests/playwright-test/ui-mode-metadata.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/playwright-test/ui-mode-metadata.spec.ts b/tests/playwright-test/ui-mode-metadata.spec.ts index 5466d4f0070f8..8097dfe5f9856 100644 --- a/tests/playwright-test/ui-mode-metadata.spec.ts +++ b/tests/playwright-test/ui-mode-metadata.spec.ts @@ -30,6 +30,6 @@ test.only('should display git info metadata', async ({ runUITest }) => { ` }); await page.getByTitle('Run all').click(); - + // todo: what to check? }); From 55fd34a92c1224b6ff805c61229944ecd068ad96 Mon Sep 17 00:00:00 2001 From: vitalets Date: Sat, 18 Jan 2025 21:04:09 +0400 Subject: [PATCH 5/5] remove test.only --- tests/playwright-test/ui-mode-metadata.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/playwright-test/ui-mode-metadata.spec.ts b/tests/playwright-test/ui-mode-metadata.spec.ts index 8097dfe5f9856..085655ba87931 100644 --- a/tests/playwright-test/ui-mode-metadata.spec.ts +++ b/tests/playwright-test/ui-mode-metadata.spec.ts @@ -16,7 +16,7 @@ import { test } from './ui-mode-fixtures'; -test.only('should display git info metadata', async ({ runUITest }) => { +test('should display git info metadata', async ({ runUITest }) => { const { page } = await runUITest({ 'playwright.config.ts': ` import { defineConfig } from '@playwright/test';