diff --git a/.github/workflows/tests_electron.yml b/.github/workflows/tests_electron.yml index 51eade0776..82b7bc9bc4 100644 --- a/.github/workflows/tests_electron.yml +++ b/.github/workflows/tests_electron.yml @@ -44,8 +44,6 @@ jobs: if: matrix.os == 'ubuntu-latest' - run: npm run etest if: matrix.os != 'ubuntu-latest' - - run: node tests/config/checkCoverage.js electron - if: ${{ !cancelled() && matrix.os == 'ubuntu-latest' }} - name: Azure Login uses: azure/login@v2 if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} diff --git a/.github/workflows/tests_primary.yml b/.github/workflows/tests_primary.yml index 430c165522..19ec1c046e 100644 --- a/.github/workflows/tests_primary.yml +++ b/.github/workflows/tests_primary.yml @@ -59,7 +59,6 @@ jobs: - run: npm run build - run: npx playwright install --with-deps ${{ matrix.browser }} chromium - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project=${{ matrix.browser }}-* - - run: node tests/config/checkCoverage.js ${{ matrix.browser }} - name: Azure Login uses: azure/login@v2 if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} diff --git a/.github/workflows/tests_secondary.yml b/.github/workflows/tests_secondary.yml index 4fbbe8a459..9bd0709081 100644 --- a/.github/workflows/tests_secondary.yml +++ b/.github/workflows/tests_secondary.yml @@ -47,7 +47,6 @@ jobs: - run: npm run build - run: npx playwright install --with-deps ${{ matrix.browser }} chromium - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project=${{ matrix.browser }}-* - - run: node tests/config/checkCoverage.js ${{ matrix.browser }} - name: Azure Login uses: azure/login@v2 if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} @@ -1099,7 +1098,6 @@ jobs: - run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --project=chromium-* env: PLAYWRIGHT_CHROMIUM_USE_HEADLESS_NEW: 1 - - run: node tests/config/checkCoverage.js chromium - name: Azure Login uses: azure/login@v2 if: ${{ !cancelled() && github.event_name == 'push' && github.repository == 'microsoft/playwright' }} diff --git a/packages/playwright-core/src/utils/stackTrace.ts b/packages/playwright-core/src/utils/stackTrace.ts index 3f0f18ecd6..2864d1ec81 100644 --- a/packages/playwright-core/src/utils/stackTrace.ts +++ b/packages/playwright-core/src/utils/stackTrace.ts @@ -30,7 +30,6 @@ export function rewriteErrorMessage(e: E, newMessage: string): } const CORE_DIR = path.resolve(__dirname, '..', '..'); -const COVERAGE_PATH = path.join(CORE_DIR, '..', '..', 'tests', 'config', 'coverage.js'); const internalStackPrefixes = [ CORE_DIR, @@ -61,8 +60,6 @@ export function captureLibraryStackTrace(): { frames: StackFrame[], apiName: str const frame = parseStackTraceLine(line); if (!frame || !frame.file) return null; - if (!process.env.PWDEBUGIMPL && isTesting && frame.file.includes(COVERAGE_PATH)) - return null; const isPlaywrightLibrary = frame.file.startsWith(CORE_DIR); const parsed: ParsedFrame = { frame, diff --git a/packages/playwright/src/transform/compilationCache.ts b/packages/playwright/src/transform/compilationCache.ts index e0154840b0..8c975af443 100644 --- a/packages/playwright/src/transform/compilationCache.ts +++ b/packages/playwright/src/transform/compilationCache.ts @@ -244,19 +244,16 @@ export function dependenciesForTestFile(filename: string): Set { return result; } -// These two are only used in the dev mode, they are specifically excluding +// This is only used in the dev mode, specifically excluding // files from packages/playwright*. In production mode, node_modules covers // that. const kPlaywrightInternalPrefix = path.resolve(__dirname, '../../../playwright'); -const kPlaywrightCoveragePrefix = path.resolve(__dirname, '../../../../tests/config/coverage.js'); export function belongsToNodeModules(file: string) { if (file.includes(`${path.sep}node_modules${path.sep}`)) return true; if (file.startsWith(kPlaywrightInternalPrefix) && (file.endsWith('.js') || file.endsWith('.mjs'))) return true; - if (file.startsWith(kPlaywrightCoveragePrefix) && (file.endsWith('.js') || file.endsWith('.mjs'))) - return true; return false; } diff --git a/tests/config/baseTest.ts b/tests/config/baseTest.ts index 7401e0f017..a71878c1c1 100644 --- a/tests/config/baseTest.ts +++ b/tests/config/baseTest.ts @@ -20,13 +20,12 @@ import type { CommonFixtures, CommonWorkerFixtures } from './commonFixtures'; import { commonFixtures } from './commonFixtures'; import type { ServerFixtures, ServerWorkerOptions } from './serverFixtures'; import { serverFixtures } from './serverFixtures'; -import { coverageTest } from './coverageFixtures'; import { platformTest } from './platformFixtures'; import { testModeTest } from './testModeFixtures'; export const base = test; -export const baseTest = mergeTests(base, coverageTest, platformTest, testModeTest) +export const baseTest = mergeTests(base, platformTest, testModeTest) .extend(commonFixtures) .extend(serverFixtures); diff --git a/tests/config/checkCoverage.js b/tests/config/checkCoverage.js deleted file mode 100644 index 52236eb8d1..0000000000 --- a/tests/config/checkCoverage.js +++ /dev/null @@ -1,87 +0,0 @@ -/** - * Copyright Microsoft Corporation. All rights reserved. - * - * 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. - */ -const path = require('path'); -const fs = require('fs'); -const {installCoverageHooks} = require('./coverage'); - -const browserName = process.argv[2] || 'chromium'; - -let api = new Set(installCoverageHooks(browserName).coverage.keys()); - -// coverage exceptions - -if (browserName === 'chromium') { - // Sometimes we already have a background page while launching, before adding a listener. - api.delete('browserContext.emit("backgroundpage")'); -} - -if (browserName !== 'chromium') { - // we don't have CDPSession in non-chromium browsers - api.delete('browser.newBrowserCDPSession'); - api.delete('browser.startTracing'); - api.delete('browser.stopTracing'); - api.delete('browserContext.backgroundPages'); - api.delete('browserContext.serviceWorkers'); - api.delete('browserContext.newCDPSession'); - api.delete('browserContext.emit("backgroundpage")'); - api.delete('browserContext.emit("serviceworker")'); - api.delete('cDPSession.send'); - api.delete('cDPSession.detach'); - api.delete('coverage.startJSCoverage'); - api.delete('coverage.stopJSCoverage'); - api.delete('coverage.startCSSCoverage'); - api.delete('coverage.stopCSSCoverage'); - api.delete('page.pdf'); -} - -// Some permissions tests are disabled in webkit. See permissions.jest.js -if (browserName === 'webkit') - api.delete('browserContext.clearPermissions'); - -// Response interception is not implemented in Firefox yet. -if (browserName === 'firefox') - api.delete('route.intercept'); - -const coverageDir = path.join(__dirname, '..', 'coverage-report'); - -const coveredMethods = new Set(); -for (const file of getCoverageFiles(coverageDir)) { - for (const method of JSON.parse(fs.readFileSync(file, 'utf8'))) - coveredMethods.add(method); -} - - -let success = true; -for (const method of api) { - if (coveredMethods.has(method)) - continue; - // [Symbol.asyncDispose] - if (method.endsWith('.undefined')) - continue; - success = false; - console.log(`ERROR: Missing coverage for "${method}"`) -} - -process.exit(success ? 0 : 1); - -function * getCoverageFiles(dir) { - for (const entry of fs.readdirSync(dir, {withFileTypes: true})) { - if (entry.isDirectory()) - yield * getCoverageFiles(path.join(dir, entry.name)) - else - yield path.join(dir, entry.name); - } -} diff --git a/tests/config/coverage.js b/tests/config/coverage.js deleted file mode 100644 index 6c2d46fc7f..0000000000 --- a/tests/config/coverage.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * Copyright 2017 Google Inc. All rights reserved. - * Modifications 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. - */ - -/** - * @param {Map} apiCoverage - * @param {Object} events - * @param {string} className - * @param {!Object} classType - */ -function traceAPICoverage(apiCoverage, api, events) { - const uninstalls = []; - for (const [name, classType] of Object.entries(api)) { - const className = name.substring(0, 1).toLowerCase() + name.substring(1); - for (const methodName of Reflect.ownKeys(classType.prototype)) { - const method = Reflect.get(classType.prototype, methodName); - if (methodName === 'constructor' || typeof methodName !== 'string' || methodName.startsWith('_') || typeof method !== 'function') - continue; - - apiCoverage.set(`${className}.${methodName}`, false); - const override = function(...args) { - apiCoverage.set(`${className}.${methodName}`, true); - return method.call(this, ...args); - }; - Object.defineProperty(override, 'name', { writable: false, value: methodName }); - Reflect.set(classType.prototype, methodName, override); - uninstalls.push(() => Reflect.set(classType.prototype, methodName, method)); - } - if (events[name]) { - for (const event of Object.values(events[name])) { - if (typeof event !== 'symbol') - apiCoverage.set(`${className}.emit(${JSON.stringify(event)})`, false); - } - const method = Reflect.get(classType.prototype, 'emit'); - Reflect.set(classType.prototype, 'emit', function(event, ...args) { - if (typeof event !== 'symbol' && this.listenerCount(event)) - apiCoverage.set(`${className}.emit(${JSON.stringify(event)})`, true); - return method.call(this, event, ...args); - }); - uninstalls.push(() => Reflect.set(classType.prototype, 'emit', method)); - } - } - return () => uninstalls.forEach(u => u()); -} - -/** - * @param {string} browserName - */ -function apiForBrowser(browserName) { - const events = require('../../packages/playwright-core/lib/client/events').Events; - const api = require('../../packages/playwright-core/lib/client/api'); - const otherBrowsers = ['chromium', 'webkit', 'firefox'].filter(name => name.toLowerCase() !== browserName.toLowerCase()); - const filteredKeys = Object.keys(api).filter(apiName => { - if (apiName.toLowerCase().startsWith('android')) - return browserName === 'android'; - if (apiName.toLowerCase().startsWith('electron')) - return browserName === 'electron'; - return browserName !== 'electron' && browserName !== 'android' && - !otherBrowsers.some(otherName => apiName.toLowerCase().startsWith(otherName)); - }); - const filteredAPI = {}; - for (const key of filteredKeys) - filteredAPI[key] = api[key]; - return { - api: filteredAPI, - events - } -} - -/** - * @param {string} browserName - */ -function installCoverageHooks(browserName) { - const {api, events} = apiForBrowser(browserName); - const coverage = new Map(); - const uninstall = traceAPICoverage(coverage, api, events); - return {coverage, uninstall}; -} - -module.exports = { - installCoverageHooks, -}; diff --git a/tests/config/coverageFixtures.ts b/tests/config/coverageFixtures.ts deleted file mode 100644 index 47f4aa98d1..0000000000 --- a/tests/config/coverageFixtures.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * 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 * as fs from 'fs'; -import * as path from 'path'; -import { installCoverageHooks } from './coverage'; -import { test } from '@playwright/test'; - -export type CoverageWorkerOptions = { - coverageName?: string; -}; - -export const coverageTest = test.extend<{}, { __collectCoverage: void } & CoverageWorkerOptions>({ - coverageName: [undefined, { scope: 'worker', option: true }], - __collectCoverage: [async ({ coverageName }, run, workerInfo) => { - if (!coverageName) { - await run(); - return; - } - - const { coverage, uninstall } = installCoverageHooks(coverageName); - await run(); - uninstall(); - const coveragePath = path.join(__dirname, '..', 'coverage-report', workerInfo.workerIndex + '.json'); - const coverageJSON = Array.from(coverage.keys()).filter(key => coverage.get(key)); - await fs.promises.mkdir(path.dirname(coveragePath), { recursive: true }); - await fs.promises.writeFile(coveragePath, JSON.stringify(coverageJSON, undefined, 2), 'utf8'); - }, { scope: 'worker', auto: true }], -}); diff --git a/tests/electron/playwright.config.ts b/tests/electron/playwright.config.ts index 4807a7f919..562e2ae6a1 100644 --- a/tests/electron/playwright.config.ts +++ b/tests/electron/playwright.config.ts @@ -19,13 +19,12 @@ loadEnv({ path: path.join(__dirname, '..', '..', '.env') }); import type { Config, PlaywrightTestOptions, PlaywrightWorkerOptions } from '@playwright/test'; import * as path from 'path'; -import type { CoverageWorkerOptions } from '../config/coverageFixtures'; process.env.PWPAGE_IMPL = 'electron'; const outputDir = path.join(__dirname, '..', '..', 'test-results'); const testDir = path.join(__dirname, '..'); -const config: Config = { +const config: Config = { testDir, outputDir, timeout: 30000, @@ -54,7 +53,6 @@ config.projects.push({ name: 'electron-api', use: { browserName: 'chromium', - coverageName: 'electron', }, testDir: path.join(testDir, 'electron'), metadata, @@ -66,7 +64,6 @@ config.projects.push({ snapshotPathTemplate: '{testDir}/{testFileDir}/{testFileName}-snapshots/{arg}-chromium{ext}', use: { browserName: 'chromium', - coverageName: 'electron', }, testDir: path.join(testDir, 'page'), metadata, diff --git a/tests/library/playwright.config.ts b/tests/library/playwright.config.ts index 568bf6f8aa..b5e3ef44f1 100644 --- a/tests/library/playwright.config.ts +++ b/tests/library/playwright.config.ts @@ -21,7 +21,6 @@ import { type Config, type PlaywrightTestOptions, type PlaywrightWorkerOptions, import * as path from 'path'; import type { TestModeWorkerOptions } from '../config/testModeFixtures'; import type { TestModeName } from '../config/testMode'; -import type { CoverageWorkerOptions } from '../config/coverageFixtures'; type BrowserName = 'chromium' | 'firefox' | 'webkit'; @@ -79,7 +78,7 @@ if (mode === 'service2') { }; } -const config: Config = { +const config: Config = { testDir, outputDir, expect: { @@ -124,7 +123,6 @@ for (const browserName of browserNames) { devtools }, trace: trace ? 'on' : undefined, - coverageName: browserName, }, metadata: { platform: process.platform, diff --git a/tests/webview2/playwright.config.ts b/tests/webview2/playwright.config.ts index 052007b91d..1bdd704a35 100644 --- a/tests/webview2/playwright.config.ts +++ b/tests/webview2/playwright.config.ts @@ -19,13 +19,12 @@ loadEnv({ path: path.join(__dirname, '..', '..', '.env') }); import type { Config, PlaywrightTestOptions, PlaywrightWorkerOptions } from '@playwright/test'; import * as path from 'path'; -import type { CoverageWorkerOptions } from '../config/coverageFixtures'; process.env.PWPAGE_IMPL = 'webview2'; const outputDir = path.join(__dirname, '..', '..', 'test-results'); const testDir = path.join(__dirname, '..'); -const config: Config = { +const config: Config = { testDir, outputDir, timeout: 30000, @@ -56,7 +55,6 @@ config.projects.push({ snapshotPathTemplate: '{testDir}/{testFileDir}/{testFileName}-snapshots/{arg}-chromium{ext}', use: { browserName: 'chromium', - coverageName: 'webview2', }, testDir: path.join(testDir, 'page'), metadata,