diff --git a/docs/src/release-notes-js.md b/docs/src/release-notes-js.md index 824a0bdd9e..9718a37d51 100644 --- a/docs/src/release-notes-js.md +++ b/docs/src/release-notes-js.md @@ -637,7 +637,7 @@ This version was also tested against the following stable channels: Call log: - expect.toBeVisible with timeout 5000ms - - waiting for selector "text=Name" + - waiting for "getByText('Name')" 2 | diff --git a/docs/src/test-assertions-js.md b/docs/src/test-assertions-js.md index 645e6b8b8b..00a417a601 100644 --- a/docs/src/test-assertions-js.md +++ b/docs/src/test-assertions-js.md @@ -73,7 +73,7 @@ The error would look like this: Call log: - expect.toBeVisible with timeout 5000ms - - waiting for selector "text=Name" + - waiting for "getByText('Name')" 2 | diff --git a/docs/src/test-timeouts-js.md b/docs/src/test-timeouts-js.md index 88e5d46a94..0e389a947e 100644 --- a/docs/src/test-timeouts-js.md +++ b/docs/src/test-timeouts-js.md @@ -146,7 +146,7 @@ Expected string: "my text" Received string: "" Call log: - expect.toHaveText with timeout 5000ms - - waiting for selector "button" + - waiting for "locator('button')" ``` ### Set expect timeout in the config @@ -206,7 +206,7 @@ example.spec.ts:3:1 › basic test =========================== locator.click: Timeout 1000ms exceeded. =========================== logs =========================== -waiting for selector "button" +waiting for "locator('button')" ============================================================ ``` diff --git a/packages/playwright-core/src/protocol/validator.ts b/packages/playwright-core/src/protocol/validator.ts index d595a8dd44..c7efd8053f 100644 --- a/packages/playwright-core/src/protocol/validator.ts +++ b/packages/playwright-core/src/protocol/validator.ts @@ -257,7 +257,7 @@ scheme.LocalUtilsConnectResult = tObject({ }); scheme.RootInitializer = tOptional(tObject({})); scheme.RootInitializeParams = tObject({ - sdkLanguage: tString, + sdkLanguage: tEnum(['javascript', 'python', 'java', 'csharp']), }); scheme.RootInitializeResult = tObject({ playwright: tChannel(['Playwright']), diff --git a/packages/playwright-core/src/server/browser.ts b/packages/playwright-core/src/server/browser.ts index 2ed70add5a..ce709e315a 100644 --- a/packages/playwright-core/src/server/browser.ts +++ b/packages/playwright-core/src/server/browser.ts @@ -26,6 +26,7 @@ import type { CallMetadata } from './instrumentation'; import { SdkObject } from './instrumentation'; import { Artifact } from './artifact'; import type { Selectors } from './selectors'; +import type { Language } from './isomorphic/locatorGenerators'; export interface BrowserProcess { onclose?: ((exitCode: number | null, signal: string | null) => void); @@ -38,7 +39,7 @@ export type PlaywrightOptions = { rootSdkObject: SdkObject; selectors: Selectors; socksProxyPort?: number; - sdkLanguage: string, + sdkLanguage: Language, }; export type BrowserOptions = PlaywrightOptions & { diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index 10d5a816ed..f39df5ab84 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -42,6 +42,7 @@ import { isInvalidSelectorError, splitSelectorByFrame, stringifySelector } from import type { SelectorInfo } from './selectors'; import type { ScreenshotOptions } from './screenshotter'; import type { InputFilesItems } from './dom'; +import { asLocator } from './isomorphic/locatorGenerators'; type ContextData = { contextPromise: ManualPromise; @@ -797,7 +798,7 @@ export class Frame extends SdkObject { if (!['attached', 'detached', 'visible', 'hidden'].includes(state)) throw new Error(`state: expected one of (attached|detached|visible|hidden)`); return controller.run(async progress => { - progress.log(`waiting for selector "${selector}"${state === 'attached' ? '' : ' to be ' + state}`); + progress.log(`waiting for "${this._asLocator(selector)}"${state === 'attached' ? '' : ' to be ' + state}`); return this.retryWithProgress(progress, selector, options, async (selectorInFrame, continuePolling) => { // Be careful, |this| can be different from |frame|. // We did not pass omitAttached, so it is non-null. @@ -1107,7 +1108,7 @@ export class Frame extends SdkObject { const { frame, info } = selectorInFrame!; // Be careful, |this| can be different from |frame|. const task = dom.waitForSelectorTask(info, 'attached'); - progress.log(`waiting for selector "${selector}"`); + progress.log(`waiting for "${this._asLocator(selector)}"`); const handle = await frame._scheduleRerunnableHandleTask(progress, info.world, task); const element = handle.asElement() as dom.ElementHandle; try { @@ -1500,7 +1501,7 @@ export class Frame extends SdkObject { const callbackText = body.toString(); return this.retryWithProgress(progress, selector, options, async selectorInFrame => { // Be careful, |this| can be different from |frame|. - progress.log(`waiting for selector "${selector}"`); + progress.log(`waiting for "${this._asLocator(selector)}"`); const { frame, info } = selectorInFrame || { frame: this, info: { parsed: { parts: [{ name: 'internal:control', body: 'return-empty', source: 'internal:control=return-empty' }] }, world: 'utility', strict: !!options.strict } }; return await frame._scheduleRerunnableTaskInFrame(progress, info, callbackText, taskData, options); }); @@ -1694,7 +1695,7 @@ export class Frame extends SdkObject { progress.cleanupWhenAborted(() => result.dispose()); return result; } catch (e) { - throw new Error(`Error: frame navigated while waiting for selector "${selector}"`); + throw new Error(`Error: frame navigated while waiting for "${this._asLocator(selector)}"`); } } @@ -1721,6 +1722,10 @@ export class Frame extends SdkObject { } }, { ls: newStorage?.localStorage }).catch(() => {}); } + + private _asLocator(selector: string) { + return asLocator(this._page.context()._browser.options.sdkLanguage, selector); + } } class RerunnableTask { diff --git a/packages/playwright-core/src/server/playwright.ts b/packages/playwright-core/src/server/playwright.ts index 492981af8d..6c9da633e9 100644 --- a/packages/playwright-core/src/server/playwright.ts +++ b/packages/playwright-core/src/server/playwright.ts @@ -27,6 +27,7 @@ import { createInstrumentation, SdkObject } from './instrumentation'; import { debugLogger } from '../common/debugLogger'; import type { Page } from './page'; import { DebugController } from './debugController'; +import type { Language } from './isomorphic/locatorGenerators'; export class Playwright extends SdkObject { readonly selectors: Selectors; @@ -40,7 +41,7 @@ export class Playwright extends SdkObject { private _allPages = new Set(); private _allBrowsers = new Set(); - constructor(sdkLanguage: string, isInternalPlaywright: boolean) { + constructor(sdkLanguage: Language, isInternalPlaywright: boolean) { super({ attribution: { isInternalPlaywright }, instrumentation: createInstrumentation() } as any, undefined, 'Playwright'); this.instrumentation.addListener({ onBrowserOpen: browser => this._allBrowsers.add(browser), @@ -78,6 +79,6 @@ export class Playwright extends SdkObject { } } -export function createPlaywright(sdkLanguage: string, isInternalPlaywright: boolean = false) { +export function createPlaywright(sdkLanguage: Language, isInternalPlaywright: boolean = false) { return new Playwright(sdkLanguage, isInternalPlaywright); } diff --git a/packages/protocol/src/channels.ts b/packages/protocol/src/channels.ts index 408f568914..b550b98d46 100644 --- a/packages/protocol/src/channels.ts +++ b/packages/protocol/src/channels.ts @@ -472,7 +472,7 @@ export interface RootChannel extends RootEventTarget, Channel { initialize(params: RootInitializeParams, metadata?: Metadata): Promise; } export type RootInitializeParams = { - sdkLanguage: string, + sdkLanguage: 'javascript' | 'python' | 'java' | 'csharp', }; export type RootInitializeOptions = { diff --git a/packages/protocol/src/protocol.yml b/packages/protocol/src/protocol.yml index b73f6bde62..a8b7e8e8ce 100644 --- a/packages/protocol/src/protocol.yml +++ b/packages/protocol/src/protocol.yml @@ -545,7 +545,13 @@ Root: initialize: parameters: - sdkLanguage: string + sdkLanguage: + type: enum + literals: + - javascript + - python + - java + - csharp returns: playwright: Playwright diff --git a/packages/recorder/src/DEPS.list b/packages/recorder/src/DEPS.list index 3bc0094942..6f3acbfe52 100644 --- a/packages/recorder/src/DEPS.list +++ b/packages/recorder/src/DEPS.list @@ -1,2 +1,3 @@ [*] @web/** +@isomorphic/** diff --git a/packages/recorder/src/callLog.tsx b/packages/recorder/src/callLog.tsx index 553232afba..aa73853e74 100644 --- a/packages/recorder/src/callLog.tsx +++ b/packages/recorder/src/callLog.tsx @@ -18,12 +18,16 @@ import './callLog.css'; import * as React from 'react'; import type { CallLog } from './recorderTypes'; import { msToString } from '@web/uiUtils'; +import { asLocator } from '@isomorphic/locatorGenerators'; +import type { Language } from '@isomorphic/locatorGenerators'; -export interface CallLogProps { - log: CallLog[], -} +export type CallLogProps = { + language: Language; + log: CallLog[]; +}; export const CallLogView: React.FC = ({ + language, log, }) => { const messagesEndRef = React.createRef(); @@ -36,6 +40,20 @@ export const CallLogView: React.FC = ({ {log.map(callLog => { const expandOverride = expandOverrides.get(callLog.id); const isExpanded = typeof expandOverride === 'boolean' ? expandOverride : callLog.status !== 'done'; + const locator = callLog.params.selector ? asLocator(language, callLog.params.selector, false) : null; + const locatorCall = `page.${locator}`; + let titlePrefix = callLog.title; + let titleSuffix = ''; + if (callLog.title.startsWith('expect.to')) { + titlePrefix = 'expect('; + titleSuffix = `).${callLog.title.substring('expect.'.length)}()`; + } else if (callLog.title.startsWith('locator.')) { + titlePrefix = ''; + titleSuffix = `.${callLog.title.substring('locator.'.length)}()`; + } else if (locator || callLog.params.url) { + titlePrefix = callLog.title + '('; + titleSuffix = ')'; + } return
{ @@ -43,9 +61,10 @@ export const CallLogView: React.FC = ({ newOverrides.set(callLog.id, !isExpanded); setExpandOverrides(newOverrides); }}> - { callLog.title } - { callLog.params.url ? ({callLog.params.url}) : undefined } - { callLog.params.selector ? ({callLog.params.selector}) : undefined } + { titlePrefix } + { callLog.params.url ? {callLog.params.url} : undefined } + { locator ? {locatorCall} : undefined } + { titleSuffix } { typeof callLog.duration === 'number' ? — {msToString(callLog.duration)} : undefined}
diff --git a/packages/recorder/src/recorder.tsx b/packages/recorder/src/recorder.tsx index f5cf8740e2..fb97862c57 100644 --- a/packages/recorder/src/recorder.tsx +++ b/packages/recorder/src/recorder.tsx @@ -153,7 +153,7 @@ export const Recorder: React.FC = ({ copy(selectorInputRef.current?.value || ''); }}> - +
; diff --git a/packages/recorder/src/recorderTypes.ts b/packages/recorder/src/recorderTypes.ts index 5abbb2ec26..ac8993e210 100644 --- a/packages/recorder/src/recorderTypes.ts +++ b/packages/recorder/src/recorderTypes.ts @@ -14,6 +14,8 @@ limitations under the License. */ +import type { Language } from '../../playwright-core/src/server/isomorphic/locatorGenerators'; + export type Point = { x: number, y: number }; export type Mode = 'inspecting' | 'recording' | 'none'; @@ -56,7 +58,7 @@ export type Source = { id: string; label: string; text: string; - language: string; + language: Language; highlight: SourceHighlight[]; revealLine?: number; // used to group the language generators diff --git a/packages/recorder/tsconfig.json b/packages/recorder/tsconfig.json index 57873b3184..405e2994b2 100644 --- a/packages/recorder/tsconfig.json +++ b/packages/recorder/tsconfig.json @@ -17,6 +17,7 @@ "baseUrl": ".", "useUnknownInCatchVariables": false, "paths": { + "@isomorphic/*": ["../playwright-core/src/server/isomorphic/*"], "@protocol/*": ["../protocol/src/*"], "@web/*": ["../web/src/*"], } diff --git a/packages/recorder/vite.config.ts b/packages/recorder/vite.config.ts index 95b7ab9d45..80d1b4e67b 100644 --- a/packages/recorder/vite.config.ts +++ b/packages/recorder/vite.config.ts @@ -25,6 +25,7 @@ export default defineConfig({ ], resolve: { alias: { + '@isomorphic': path.resolve(__dirname, '../playwright-core/src/server/isomorphic'), '@protocol': path.resolve(__dirname, '../protocol/src'), '@web': path.resolve(__dirname, '../web/src'), }, diff --git a/tests/library/inspector/pause.spec.ts b/tests/library/inspector/pause.spec.ts index d152d2697b..1b497d995a 100644 --- a/tests/library/inspector/pause.spec.ts +++ b/tests/library/inspector/pause.spec.ts @@ -194,7 +194,7 @@ it.describe('pause', () => { await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")'); expect(await sanitizeLog(recorderPage)).toEqual([ 'page.pause- XXms', - 'page.click(button)- XXms', + 'page.click(page.locator(\'button\'))- XXms', 'page.pause', ]); await recorderPage.click('[title="Resume (F8)"]'); @@ -237,7 +237,7 @@ it.describe('pause', () => { await recorderPage.waitForSelector('.source-line-paused:has-text("page.pause(); // 2")'); expect(await sanitizeLog(recorderPage)).toEqual([ 'page.pause- XXms', - 'expect.toHaveText(button)- XXms', + 'expect(page.locator(\'button\')).toHaveText()- XXms', 'page.pause', ]); await recorderPage.click('[title="Resume (F8)"]'); @@ -267,7 +267,7 @@ it.describe('pause', () => { await page.pause(); await Promise.all([ page.waitForEvent('console'), - page.click('button'), + page.getByRole('button', { name: 'Submit' }).click(), ]); await page.pause(); // 2 })(); @@ -277,7 +277,7 @@ it.describe('pause', () => { expect(await sanitizeLog(recorderPage)).toEqual([ 'page.pause- XXms', 'page.waitForEvent(console)', - 'page.click(button)- XXms', + 'page.getByRole(\'button\', { name: \'Submit\' }).click()- XXms', 'page.pause', ]); await recorderPage.click('[title="Resume (F8)"]'); @@ -288,15 +288,15 @@ it.describe('pause', () => { await page.setContent(''); const scriptPromise = (async () => { await page.pause(); - await page.isChecked('button'); + await page.getByRole('button').isChecked(); })().catch(e => e); const recorderPage = await recorderPageGetter(); await recorderPage.click('[title="Resume (F8)"]'); await recorderPage.waitForSelector('.source-line-error'); expect(await sanitizeLog(recorderPage)).toEqual([ 'page.pause- XXms', - 'page.isChecked(button)- XXms', - 'waiting for selector "button"', + 'page.getByRole(\'button\').isChecked()- XXms', + 'waiting for \"getByRole(\'button\')"', 'selector resolved to ', 'error: Error: Not a checkbox or radio button', ]); diff --git a/tests/page/expect-boolean.spec.ts b/tests/page/expect-boolean.spec.ts index 205183aff3..03343dd181 100644 --- a/tests/page/expect-boolean.spec.ts +++ b/tests/page/expect-boolean.spec.ts @@ -74,7 +74,7 @@ test.describe('toBeChecked', () => { const locator2 = page.locator('input2'); const error = await expect(locator2).not.toBeChecked({ timeout: 1000 }).catch(e => e); expect(error.message).toContain(`expect.toBeChecked with timeout 1000ms`); - expect(error.message).toContain('waiting for selector "input2"'); + expect(error.message).toContain('waiting for "locator(\'input2\')"'); }); }); diff --git a/tests/page/expect-to-have-text.spec.ts b/tests/page/expect-to-have-text.spec.ts index c55e4150bc..ffca1c3fcf 100644 --- a/tests/page/expect-to-have-text.spec.ts +++ b/tests/page/expect-to-have-text.spec.ts @@ -152,7 +152,7 @@ test.describe('not.toHaveText', () => { const error = await expect(page.locator('span')).not.toHaveText('hello', { timeout: 1000 }).catch(e => e); expect(stripAnsi(error.message)).toContain('Expected string: not "hello"'); expect(stripAnsi(error.message)).toContain('Received string: ""'); - expect(stripAnsi(error.message)).toContain('waiting for selector "span"'); + expect(stripAnsi(error.message)).toContain('waiting for "locator(\'span\')"'); }); }); @@ -217,7 +217,7 @@ test.describe('toHaveText with array', () => { const error = await expect(locator).toHaveText(['Text 1', /Text \d/, 'Extra'], { timeout: 1000 }).catch(e => e); expect(stripAnsi(error.message)).toContain('- "Extra"'); expect(error.message).toContain('expect.toHaveText with timeout 1000ms'); - expect(error.message).toContain('waiting for selector "div"'); + expect(error.message).toContain('waiting for "locator(\'div\')"'); expect(error.message).toContain('selector resolved to 2 elements'); }); diff --git a/tests/page/locator-convenience.spec.ts b/tests/page/locator-convenience.spec.ts index 1208b6324a..31966b4b93 100644 --- a/tests/page/locator-convenience.spec.ts +++ b/tests/page/locator-convenience.spec.ts @@ -85,7 +85,7 @@ it('innerText should produce log', async ({ page, server }) => { await page.setContent(`
Hello
`); const locator = page.locator('span'); const error = await locator.innerText({ timeout: 1000 }).catch(e => e); - expect(error.message).toContain('waiting for selector "span"'); + expect(error.message).toContain('waiting for "locator(\'span\')"'); }); it('textContent should work', async ({ page, server }) => { diff --git a/tests/page/page-wait-for-selector-1.spec.ts b/tests/page/page-wait-for-selector-1.spec.ts index 2c2b82b553..3476da8e87 100644 --- a/tests/page/page-wait-for-selector-1.spec.ts +++ b/tests/page/page-wait-for-selector-1.spec.ts @@ -81,8 +81,8 @@ it('elementHandle.waitForSelector should throw on navigation', async ({ page, se await page.evaluate(() => 1); await page.goto(server.EMPTY_PAGE); const error = await promise; - expect(error.message).toContain('Error: frame navigated while waiting for selector'); - expect(error.message).toContain('span'); + expect(error.message).toContain('Error: frame navigated while waiting for'); + expect(error.message).toContain('"locator(\'span\')"'); }); it('should work with removed MutationObserver', async ({ page, server }) => { @@ -134,7 +134,7 @@ it('should report logs while waiting for visible', async ({ page, server }) => { const error = await watchdog.catch(e => e); expect(error.message).toContain(`frame.waitForSelector: Timeout 5000ms exceeded.`); - expect(error.message).toContain(`waiting for selector "div" to be visible`); + expect(error.message).toContain(`waiting for "locator(\'div\')" to be visible`); expect(error.message).toContain(`selector resolved to hidden
`); @@ -165,7 +165,7 @@ it('should report logs while waiting for hidden', async ({ page, server }) => { const error = await watchdog.catch(e => e); expect(error.message).toContain(`frame.waitForSelector: Timeout 5000ms exceeded.`); - expect(error.message).toContain(`waiting for selector "div" to be hidden`); + expect(error.message).toContain(`waiting for "locator(\'div\')" to be hidden`); expect(error.message).toContain(`selector resolved to visible
hello
`); expect(error.message).toContain(`selector resolved to visible
hello
`); }); diff --git a/tests/page/page-wait-for-selector-2.spec.ts b/tests/page/page-wait-for-selector-2.spec.ts index f242744a29..33f2f83691 100644 --- a/tests/page/page-wait-for-selector-2.spec.ts +++ b/tests/page/page-wait-for-selector-2.spec.ts @@ -131,7 +131,7 @@ it('should respect timeout', async ({ page, playwright }) => { await page.waitForSelector('div', { timeout: 3000, state: 'attached' }).catch(e => error = e); expect(error).toBeTruthy(); expect(error.message).toContain('page.waitForSelector: Timeout 3000ms exceeded'); - expect(error.message).toContain('waiting for selector "div"'); + expect(error.message).toContain('waiting for "locator(\'div\')"'); expect(error).toBeInstanceOf(playwright.errors.TimeoutError); }); @@ -141,7 +141,7 @@ it('should have an error message specifically for awaiting an element to be hidd await page.waitForSelector('div', { state: 'hidden', timeout: 1000 }).catch(e => error = e); expect(error).toBeTruthy(); expect(error.message).toContain('page.waitForSelector: Timeout 1000ms exceeded'); - expect(error.message).toContain('waiting for selector "div" to be hidden'); + expect(error.message).toContain('waiting for "locator(\'div\')" to be hidden'); }); it('should respond to node attribute mutation', async ({ page, server }) => { @@ -233,7 +233,7 @@ it('should respect timeout xpath', async ({ page, playwright }) => { await page.waitForSelector('//div', { state: 'attached', timeout: 3000 }).catch(e => error = e); expect(error).toBeTruthy(); expect(error.message).toContain('page.waitForSelector: Timeout 3000ms exceeded'); - expect(error.message).toContain('waiting for selector "//div"'); + expect(error.message).toContain('waiting for "locator(\'xpath=//div\')"'); expect(error).toBeInstanceOf(playwright.errors.TimeoutError); }); @@ -326,6 +326,6 @@ it('should fail when navigating while on handle', async ({ page, mode, server }) const body = await page.waitForSelector('body'); const error = await body.waitForSelector('div', { __testHookBeforeAdoptNode } as any).catch(e => e); - expect(error.message).toContain('Error: frame navigated while waiting for selector'); - expect(error.message).toContain('"div"'); + expect(error.message).toContain('Error: frame navigated while waiting for'); + expect(error.message).toContain('"locator(\'div\')"'); }); diff --git a/tests/playwright-test/expect.spec.ts b/tests/playwright-test/expect.spec.ts index d6b457b73f..583a63a25f 100644 --- a/tests/playwright-test/expect.spec.ts +++ b/tests/playwright-test/expect.spec.ts @@ -507,7 +507,7 @@ test('should print pending operations for toHaveText', async ({ runInlineTest }) expect(output).toContain('Error: expect(received).toHaveText(expected)'); expect(output).toContain('Expected string: "Text"'); expect(output).toContain('Received string: ""'); - expect(output).toContain('waiting for selector "no-such-thing"'); + expect(output).toContain('waiting for "locator(\'no-such-thing\')"'); }); test('should print expected/received on Ctrl+C', async ({ runInlineTest }) => { diff --git a/tests/playwright-test/playwright.spec.ts b/tests/playwright-test/playwright.spec.ts index 834e603416..831eb58959 100644 --- a/tests/playwright-test/playwright.spec.ts +++ b/tests/playwright-test/playwright.spec.ts @@ -329,8 +329,8 @@ test('should report error and pending operations on timeout', async ({ runInline test('timedout', async ({ page }) => { await page.setContent('
Click me
'); await Promise.all([ - page.click('text=Missing'), - page.textContent('text=More missing'), + page.getByText('Missing').click(), + page.getByText('More missing').textContent(), ]); }); `, @@ -340,10 +340,10 @@ test('should report error and pending operations on timeout', async ({ runInline expect(result.passed).toBe(0); expect(result.failed).toBe(1); expect(result.output).toContain('Pending operations:'); - expect(result.output).toContain('- page.click at a.test.ts:9:16'); - expect(result.output).toContain('- page.textContent at a.test.ts:10:16'); - expect(result.output).toContain('waiting for selector'); - expect(stripAnsi(result.output)).toContain(`10 | page.textContent('text=More missing'),`); + expect(result.output).toContain('- locator.click at a.test.ts:9:37'); + expect(result.output).toContain('- locator.textContent at a.test.ts:10:42'); + expect(result.output).toContain('waiting for'); + expect(stripAnsi(result.output)).toContain(`10 | page.getByText('More missing').textContent(),`); }); test('should report error on timeout with shared page', async ({ runInlineTest }, testInfo) => { @@ -358,7 +358,7 @@ test('should report error on timeout with shared page', async ({ runInlineTest } await page.setContent('
Click me
'); }); test('timedout', async () => { - await page.click('text=Missing'); + await page.getByText('Missing').click(); }); `, }, { workers: 1, timeout: 2000 }); @@ -366,8 +366,8 @@ test('should report error on timeout with shared page', async ({ runInlineTest } expect(result.exitCode).toBe(1); expect(result.passed).toBe(1); expect(result.failed).toBe(1); - expect(result.output).toContain('waiting for selector "text=Missing"'); - expect(stripAnsi(result.output)).toContain(`14 | await page.click('text=Missing');`); + expect(result.output).toContain('waiting for "getByText(\'Missing\')"'); + expect(stripAnsi(result.output)).toContain(`14 | await page.getByText('Missing').click();`); }); test('should report error from beforeAll timeout', async ({ runInlineTest }, testInfo) => { @@ -378,8 +378,8 @@ test('should report error from beforeAll timeout', async ({ runInlineTest }, tes const page = await browser.newPage(); await page.setContent('
Click me
'); await Promise.all([ - page.click('text=Missing'), - page.textContent('text=More missing'), + page.getByText('Missing').click(), + page.getByText('More missing').textContent(), ]); }); test('ignored', () => {}); @@ -390,8 +390,8 @@ test('should report error from beforeAll timeout', async ({ runInlineTest }, tes expect(result.passed).toBe(0); expect(result.failed).toBe(1); expect(result.output).toContain('"beforeAll" hook timeout of 2000ms exceeded.'); - expect(result.output).toContain('waiting for selector'); - expect(stripAnsi(result.output)).toContain(`11 | page.textContent('text=More missing'),`); + expect(result.output).toContain('waiting for'); + expect(stripAnsi(result.output)).toContain(`11 | page.getByText('More missing').textContent(),`); }); test('should not report waitForEventInfo as pending', async ({ runInlineTest }, testInfo) => { diff --git a/tests/playwright-test/reporter.spec.ts b/tests/playwright-test/reporter.spec.ts index e26a2d1262..91f855fa99 100644 --- a/tests/playwright-test/reporter.spec.ts +++ b/tests/playwright-test/reporter.spec.ts @@ -394,7 +394,7 @@ test('should report api step failure', async ({ runInlineTest }) => { `%% begin {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`, `%% end {\"title\":\"page.setContent\",\"category\":\"pw:api\"}`, `%% begin {\"title\":\"page.click(input)\",\"category\":\"pw:api\"}`, - `%% end {\"title\":\"page.click(input)\",\"category\":\"pw:api\",\"error\":{\"message\":\"page.click: Timeout 1ms exceeded.\\n=========================== logs ===========================\\nwaiting for selector \\\"input\\\"\\n============================================================\",\"stack\":\"\"}}`, + `%% end {\"title\":\"page.click(input)\",\"category\":\"pw:api\",\"error\":{\"message\":\"page.click: Timeout 1ms exceeded.\\n=========================== logs ===========================\\nwaiting for \\\"locator('input')\\\"\\n============================================================\",\"stack\":\"\"}}`, `%% begin {\"title\":\"After Hooks\",\"category\":\"hook\"}`, `%% begin {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`, `%% end {\"title\":\"browserContext.close\",\"category\":\"pw:api\"}`, diff --git a/utils/check_deps.js b/utils/check_deps.js index d91f1bbb4c..09cb33852d 100644 --- a/utils/check_deps.js +++ b/utils/check_deps.js @@ -23,7 +23,12 @@ const ts = require('typescript'); const path = require('path'); const packagesDir = path.normalize(path.join(__dirname, '..', 'packages')); -const packages = fs.readdirSync(packagesDir); + +const packages = new Map(); +for (const package of fs.readdirSync(packagesDir)) + packages.set(package, packagesDir + '/' + package + '/src/'); +packages.set('isomorphic', packagesDir + '/playwright-core/src/server/isomorphic/'); + const peerDependencies = ['electron', 'react', 'react-dom', '@zip.js/zip.js']; const depsCache = {}; @@ -106,8 +111,8 @@ async function innerCheckDeps(root, checkDepsFile, checkPackageJson) { } else if (importName.startsWith('@')) { const tokens = importName.substring(1).split('/'); const package = tokens[0]; - if (packages.includes(package)) - importPath = packagesDir + '/' + tokens[0] + '/src/' + tokens.slice(1).join('/'); + if (packages.has(package)) + importPath = packages.get(package) + tokens.slice(1).join('/'); } if (importPath) { @@ -161,7 +166,7 @@ async function innerCheckDeps(root, checkDepsFile, checkPackageJson) { continue; } if (line.startsWith('@')) - group.push(line.replace(/@([\w-]+)\/(.*)/, path.join(packagesDir, '$1', 'src', '$2'))); + group.push(line.replace(/@([\w-]+)\/(.*)/, (_, arg1, arg2) => packages.get(arg1) + arg2)); else group.push(path.resolve(depsDirectory, line)); }