diff --git a/packages/playwright/src/matchers/DEPS.list b/packages/playwright/src/matchers/DEPS.list index 73e44a39d451c..ec1f3bf85bfbf 100644 --- a/packages/playwright/src/matchers/DEPS.list +++ b/packages/playwright/src/matchers/DEPS.list @@ -6,3 +6,4 @@ ../util.ts ../worker/testInfo.ts node_modules/colors/safe +../package.ts diff --git a/packages/playwright/src/matchers/expect.ts b/packages/playwright/src/matchers/expect.ts index c938fd4abe67f..bc4b2724a5eec 100644 --- a/packages/playwright/src/matchers/expect.ts +++ b/packages/playwright/src/matchers/expect.ts @@ -23,6 +23,7 @@ import { currentZone } from '@utils/zones'; import { ExpectError, isJestError } from './matcherHint'; import { computeMatcherTitleSuffix, + defaultDeadlineForMatcher, toBeAttached, toBeChecked, toBeDisabled, @@ -57,7 +58,7 @@ import { toMatchAriaSnapshot } from './toMatchAriaSnapshot'; import { toHaveScreenshot, toMatchSnapshot } from './toMatchSnapshot'; import { expect as expectLibrary, -} from '../common/expectBundle'; +} from './expectBundle'; import { currentTestInfo } from '../common/globals'; import { filteredStackTrace } from '../util'; import { TestInfoImpl } from '../worker/testInfo'; @@ -366,7 +367,7 @@ async function pollMatcher(qualifiedMatcherName: string, info: ExpectMetaInfo, p const testInfo = currentTestInfo(); const poll = info.poll!; const timeout = poll.timeout ?? info.timeout ?? testInfo?._projectInternal?.expect?.timeout ?? defaultExpectTimeout; - const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : TestInfoImpl._defaultDeadlineForMatcher(timeout); + const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : defaultDeadlineForMatcher(timeout); const result = await pollAgainstDeadline(async () => { if (testInfo && currentTestInfo() !== testInfo) diff --git a/packages/playwright/src/common/expectBundle.ts b/packages/playwright/src/matchers/expectBundle.ts similarity index 89% rename from packages/playwright/src/common/expectBundle.ts rename to packages/playwright/src/matchers/expectBundle.ts index 620ec16d93212..ffca5ad7b5083 100644 --- a/packages/playwright/src/common/expectBundle.ts +++ b/packages/playwright/src/matchers/expectBundle.ts @@ -15,4 +15,4 @@ */ import { libPath } from '../package'; -export const expect: typeof import('../../bundles/expect/node_modules/expect/build').expect = require(libPath('common', 'expectBundleImpl')).expect; +export const expect: typeof import('../../bundles/expect/node_modules/expect/build').expect = require(libPath('matchers', 'expectBundleImpl')).expect; diff --git a/packages/playwright/src/matchers/matchers.ts b/packages/playwright/src/matchers/matchers.ts index 990fc05f3343c..a8ef78fa04a7b 100644 --- a/packages/playwright/src/matchers/matchers.ts +++ b/packages/playwright/src/matchers/matchers.ts @@ -22,6 +22,7 @@ import { isString } from '@isomorphic/stringUtils'; import { pollAgainstDeadline } from '@isomorphic/timeoutRunner'; import { constructURLBasedOnBaseURL, isURLPattern } from '@isomorphic/urlMatch'; import { formatMatcherMessage, serializeExpectedTextValues } from '@utils/expectUtils'; +import { monotonicTime } from '@isomorphic/index'; import { expectTypes } from '../util'; import { toBeTruthy } from './toBeTruthy'; @@ -31,7 +32,6 @@ import { toMatchText } from './toMatchText'; import { toHaveScreenshotStepTitle } from './toMatchSnapshot'; import { takeFirst } from '../common/config'; import { currentTestInfo } from '../common/globals'; -import { TestInfoImpl } from '../worker/testInfo'; import { MatcherResult } from './matcherHint'; import type { ExpectMatcherState } from '../../types/test'; @@ -487,7 +487,7 @@ export async function toPass( const timeout = takeFirst(options.timeout, testInfo?._projectInternal.expect?.toPass?.timeout, 0); const intervals = takeFirst(options.intervals, testInfo?._projectInternal.expect?.toPass?.intervals, [100, 250, 500, 1000]); - const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : TestInfoImpl._defaultDeadlineForMatcher(timeout); + const { deadline, timeoutMessage } = testInfo ? testInfo._deadlineForMatcher(timeout) : defaultDeadlineForMatcher(timeout); const result = await pollAgainstDeadline(async () => { if (testInfo && currentTestInfo() !== testInfo) return { continuePolling: false, result: undefined }; @@ -524,3 +524,7 @@ export function computeMatcherTitleSuffix(matcherName: string, receiver: any, ar } return {}; } + +export function defaultDeadlineForMatcher(timeout: number): { deadline: any; timeoutMessage: any; } { + return { deadline: (timeout ? monotonicTime() + timeout : 0), timeoutMessage: `Timeout ${timeout}ms exceeded while waiting on the predicate` }; +} diff --git a/packages/playwright/src/worker/testInfo.ts b/packages/playwright/src/worker/testInfo.ts index 0e12f50a58d34..025e5742eff63 100644 --- a/packages/playwright/src/worker/testInfo.ts +++ b/packages/playwright/src/worker/testInfo.ts @@ -171,10 +171,6 @@ export class TestInfoImpl implements TestInfo { return { deadline: Math.min(testDeadline, matcherDeadline), timeoutMessage: testDeadline < matcherDeadline ? testMessage : matcherMessage }; } - static _defaultDeadlineForMatcher(timeout: number): { deadline: any; timeoutMessage: any; } { - return { deadline: (timeout ? monotonicTime() + timeout : 0), timeoutMessage: `Timeout ${timeout}ms exceeded while waiting on the predicate` }; - } - constructor( configInternal: FullConfigInternal, projectInternal: FullProjectInternal, diff --git a/utils/build/build.js b/utils/build/build.js index b7e495fb37d86..7fb905db40781 100644 --- a/utils/build/build.js +++ b/utils/build/build.js @@ -267,7 +267,7 @@ bundles.push({ bundles.push({ modulePath: 'packages/playwright/bundles/expect', - outdir: 'packages/playwright/lib/common', + outdir: 'packages/playwright/lib/matchers', entryPoints: ['src/expectBundleImpl.ts'], }); @@ -580,7 +580,7 @@ for (const pkg of workspace.packages()) { // playwright-client is built as a bundle. if (['@playwright/client'].includes(pkg.name)) continue; - if (pkg.name === 'playwright-core') + if (pkg.name === 'playwright-core' || pkg.name === 'playwright') continue; steps.push(new EsbuildStep({ @@ -669,7 +669,7 @@ function assertCoreBundleHasNoNodeModules() { steps.push(new CustomCallbackStep(assertCoreBundleHasNoNodeModules)); -// playwright/lib/transform/esmLoader2.js — bundled ESM loader registered by +// playwright/lib/transform/esmLoader.js — bundled ESM loader registered by // common/esmLoaderHost.ts via node:module register. Same externalization // rules as the worker bundle. { @@ -689,6 +689,48 @@ steps.push(new CustomCallbackStep(assertCoreBundleHasNoNodeModules)); }, [playwrightSrc])); } +// Build playwright entry points (per-file), excluding matchers/* which is +// produced by the bundle step below. +steps.push(new EsbuildStep({ + entryPoints: [ + filePath('packages/playwright/src/*.ts'), + filePath('packages/playwright/src/agents/**/*.ts'), + filePath('packages/playwright/src/cli/**/*.ts'), + filePath('packages/playwright/src/common/**/*.ts'), + filePath('packages/playwright/src/isomorphic/**/*.ts'), + filePath('packages/playwright/src/loader/**/*.ts'), + filePath('packages/playwright/src/mcp/**/*.ts'), + filePath('packages/playwright/src/plugins/**/*.ts'), + filePath('packages/playwright/src/reporters/**/*.ts'), + filePath('packages/playwright/src/runner/**/*.ts'), + filePath('packages/playwright/src/transform/**/*.ts'), + filePath('packages/playwright/src/worker/**/*.ts'), + ], + outdir: filePath('packages/playwright/lib'), + sourcemap: withSourceMaps ? 'linked' : false, + platform: 'node', + format: 'cjs', + plugins: [dynamicImportToRequirePlugin], +})); + +// playwright/lib/matchers/expect.js — bundled jest expect facade. +steps.push(new EsbuildStep({ + bundle: true, + entryPoints: [filePath('packages/playwright/src/matchers/expect.ts')], + outfile: filePath('packages/playwright/lib/matchers/expect.js'), + sourcemap: withSourceMaps ? 'linked' : false, + platform: 'node', + format: 'cjs', + external: [ + 'playwright-core', + 'playwright-core/*', + '../common/*', + '../util', + '../package', + ], + plugins: [dynamicImportToRequirePlugin], +}, [filePath('packages/playwright/src')])); + // Build the Electron preload loader as a standalone CJS file. It runs inside // the Electron process (via `electron -r loader.js`) and must not depend on // coreBundle. `electron` is resolved at runtime by the Electron process.