From 432b3689c18b566258d0cd929d4988b41d75ac37 Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Tue, 7 Nov 2023 22:51:41 +0000 Subject: [PATCH] chore: adjust to playwright 1.40 --- examples/recorder-crx/src/background.ts | 4 +- examples/recorder-crx/src/contentscript.ts | 2 +- package-lock.json | 164 +++++++++------------ package.json | 2 +- src/client/crx.ts | 3 +- src/protocol/channels.ts | 2 +- src/protocol/validator.ts | 4 +- src/server/recorder/crxPlayer.ts | 2 +- src/server/recorder/crxRecorderApp.ts | 26 ++-- src/types/test.d.ts | 107 ++++++++------ src/types/types.d.ts | 16 +- tests/crx/crxRecorderTest.ts | 5 +- 12 files changed, 169 insertions(+), 168 deletions(-) diff --git a/examples/recorder-crx/src/background.ts b/examples/recorder-crx/src/background.ts index 8668384f6..96dabfad9 100644 --- a/examples/recorder-crx/src/background.ts +++ b/examples/recorder-crx/src/background.ts @@ -17,12 +17,14 @@ import type { CrxApplication } from 'playwright-crx'; import { crx, _debug, _setUnderTest } from 'playwright-crx'; +type Mode = 'none' | 'recording' | 'inspecting' | 'assertingText' | 'recording-inspecting' | 'standby' | 'assertingVisibility' | 'assertingValue'; + // we must lazy initialize it let crxAppPromise: Promise | undefined; const attachedTabIds = new Set(); -async function changeAction(tabId: number, mode: 'none' | 'recording' | 'inspecting' | 'detached') { +async function changeAction(tabId: number, mode: Mode | 'detached') { // detached basically implies recorder windows was closed if (mode === 'detached' || mode === 'none') { await Promise.all([ diff --git a/examples/recorder-crx/src/contentscript.ts b/examples/recorder-crx/src/contentscript.ts index 13dcb063a..3242f02fe 100644 --- a/examples/recorder-crx/src/contentscript.ts +++ b/examples/recorder-crx/src/contentscript.ts @@ -35,7 +35,7 @@ if (typeof chrome !== 'undefined' && chrome.runtime) { case 'setMode': wnd.playwrightSetMode(msg.mode); break; case 'setSources': wnd.playwrightSetSources(msg.sources); break; case 'updateCallLogs': wnd.playwrightUpdateLogs(msg.callLogs); break; - case 'setSelector': wnd.playwrightSetSelector(msg.selector, msg.focus); break; + case 'setSelector': wnd.playwrightSetSelector(msg.selector, msg.userGesture); break; case 'setFileIfNeeded': wnd.playwrightSetFileIfNeeded(msg.file); break; } }); diff --git a/package-lock.json b/package-lock.json index 7d6c65222..f0d6bbe6a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -109,19 +109,19 @@ } }, "node_modules/@babel/core": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz", - "integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz", + "integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", "@babel/helper-compilation-targets": "^7.22.15", "@babel/helper-module-transforms": "^7.23.0", - "@babel/helpers": "^7.23.0", + "@babel/helpers": "^7.23.2", "@babel/parser": "^7.23.0", "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", @@ -364,12 +364,12 @@ } }, "node_modules/@babel/helpers": { - "version": "7.23.1", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz", - "integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz", + "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==", "dependencies": { "@babel/template": "^7.22.15", - "@babel/traverse": "^7.23.0", + "@babel/traverse": "^7.23.2", "@babel/types": "^7.23.0" }, "engines": { @@ -416,6 +416,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-proposal-explicit-resource-management": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-explicit-resource-management/-/plugin-proposal-explicit-resource-management-7.23.0.tgz", + "integrity": "sha512-wu5/1COnSuGj78UBhTpxmESzV/xEcWIjkM54PZ8mhmwHrDBriro0o8LAkbbTXDAsQjwlqkqvIyXzOSykHrDiSg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-explicit-resource-management": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-class-static-block": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", @@ -455,6 +470,20 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-explicit-resource-management": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-explicit-resource-management/-/plugin-syntax-explicit-resource-management-7.22.5.tgz", + "integrity": "sha512-vokH/rTR4m9hlcxXXL0CPnpoGHUbZ6gfI3kq/UZSwrF9qGo/LxWqEP0qWYqkt5kc6/jrCOTaBeYw+lYleEFtLA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-export-namespace-from": { "version": "7.8.3", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", @@ -832,8 +861,9 @@ } }, "node_modules/@babel/traverse": { - "version": "7.23.0", - "license": "MIT", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", "dependencies": { "@babel/code-frame": "^7.22.13", "@babel/generator": "^7.23.0", @@ -971,6 +1001,12 @@ "rollup": "^1.20.0||^2.0.0" } }, + "node_modules/@types/babel__code-frame": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/@types/babel__code-frame/-/babel__code-frame-7.0.6.tgz", + "integrity": "sha512-Anitqkl3+KrzcW2k77lRlg/GfLZLWXBuNgbEcIOU6M92yw42vsd3xV/Z/yAHEj8m+KUjL6bWOVOFqX8PFPJ4LA==", + "dev": true + }, "node_modules/@types/babel__core": { "version": "7.20.2", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.2.tgz", @@ -993,6 +1029,15 @@ "@babel/types": "^7.0.0" } }, + "node_modules/@types/babel__helper-plugin-utils": { + "version": "7.10.3", + "resolved": "https://registry.npmjs.org/@types/babel__helper-plugin-utils/-/babel__helper-plugin-utils-7.10.3.tgz", + "integrity": "sha512-FcLBBPXInqKfULB2nvOBskQPcnSMZ0s1Y2q76u9H1NPPWaLcTeq38xBeKfF/RBUECK333qeaqRdYoPSwW7rTNQ==", + "dev": true, + "dependencies": { + "@types/babel__core": "*" + } + }, "node_modules/@types/babel__template": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.2.tgz", @@ -1205,6 +1250,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -1417,10 +1463,10 @@ "safe-buffer": "^5.0.1" } }, - "node_modules/codemirror": { - "version": "5.65.15", - "resolved": "https://registry.npmjs.org/codemirror/-/codemirror-5.65.15.tgz", - "integrity": "sha512-YC4EHbbwQeubZzxLl5G4nlbLc1T21QTrKGaOal/Pkm9dVDMZXMH7+ieSPEOZCtO9I68i8/oteJKOxzHC2zR+0g==", + "node_modules/codemirror-shadow-1": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/codemirror-shadow-1/-/codemirror-shadow-1-0.0.1.tgz", + "integrity": "sha512-kD3OZpCCHr3LHRKfbGx5IogHTWq4Uo9jH2bXPVa7/n6ppkgI66rx4tniQY1BpqWp/JNhQmQsXhQoaZ1TH6t0xQ==", "dev": true }, "node_modules/color-convert": { @@ -2170,6 +2216,7 @@ }, "node_modules/lru-cache": { "version": "10.0.1", + "dev": true, "license": "ISC", "engines": { "node": "14 || >=16.14" @@ -2243,6 +2290,7 @@ }, "node_modules/minipass": { "version": "7.0.4", + "dev": true, "license": "ISC", "engines": { "node": ">=16 || 14 >=14.17" @@ -2377,6 +2425,7 @@ }, "node_modules/path-scurry": { "version": "1.10.1", + "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "lru-cache": "^9.1.1 || ^10.0.0", @@ -3312,7 +3361,6 @@ "progress": "2.0.3", "proxy-from-env": "1.1.0", "retry": "0.12.0", - "rimraf": "^4.4.1", "signal-exit": "3.0.7", "socks-proxy-agent": "6.1.1", "stack-utils": "2.0.5", @@ -3428,39 +3476,6 @@ "node": ">=8" } }, - "playwright/packages/playwright-core/bundles/utils/node_modules/fs.realpath": { - "version": "1.0.0", - "license": "ISC" - }, - "playwright/packages/playwright-core/bundles/utils/node_modules/glob": { - "version": "9.3.5", - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "minimatch": "^8.0.2", - "minipass": "^4.2.4", - "path-scurry": "^1.6.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "playwright/packages/playwright-core/bundles/utils/node_modules/glob/node_modules/minimatch": { - "version": "8.0.4", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "playwright/packages/playwright-core/bundles/utils/node_modules/graceful-fs": { "version": "4.2.10", "license": "ISC" @@ -3536,13 +3551,6 @@ "concat-map": "0.0.1" } }, - "playwright/packages/playwright-core/bundles/utils/node_modules/minipass": { - "version": "4.2.8", - "license": "ISC", - "engines": { - "node": ">=8" - } - }, "playwright/packages/playwright-core/bundles/utils/node_modules/open": { "version": "8.4.0", "license": "MIT", @@ -3583,22 +3591,6 @@ "node": ">= 4" } }, - "playwright/packages/playwright-core/bundles/utils/node_modules/rimraf": { - "version": "4.4.1", - "license": "ISC", - "dependencies": { - "glob": "^9.2.0" - }, - "bin": { - "rimraf": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "playwright/packages/playwright-core/bundles/utils/node_modules/signal-exit": { "version": "3.0.7", "license": "ISC" @@ -3788,10 +3780,11 @@ "version": "0.0.1", "dependencies": { "@babel/code-frame": "^7.22.13", - "@babel/core": "^7.23.0", + "@babel/core": "^7.23.2", "@babel/helper-plugin-utils": "^7.22.5", "@babel/parser": "^7.23.0", - "@babel/plugin-proposal-decorators": "^7.23.0", + "@babel/plugin-proposal-decorators": "^7.23.2", + "@babel/plugin-proposal-explicit-resource-management": "^7.23.0", "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-import-assertions": "^7.22.5", "@babel/plugin-syntax-json-strings": "^7.8.3", @@ -3809,12 +3802,12 @@ "@babel/plugin-transform-private-methods": "^7.22.5", "@babel/plugin-transform-private-property-in-object": "^7.22.11", "@babel/plugin-transform-react-jsx": "^7.22.15", - "@babel/preset-typescript": "^7.23.0" + "@babel/preset-typescript": "^7.23.2" }, "devDependencies": { - "@types/babel__code-frame": "^7.0.3", - "@types/babel__core": "^7.20.0", - "@types/babel__helper-plugin-utils": "^7.10.0", + "@types/babel__code-frame": "^7.0.4", + "@types/babel__core": "^7.20.2", + "@types/babel__helper-plugin-utils": "^7.10.1", "@types/babel__traverse": "^7.20.2" } }, @@ -3858,19 +3851,6 @@ "@babel/core": "^7.0.0-0" } }, - "playwright/packages/playwright/bundles/babel/node_modules/@types/babel__code-frame": { - "version": "7.0.3", - "dev": true, - "license": "MIT" - }, - "playwright/packages/playwright/bundles/babel/node_modules/@types/babel__helper-plugin-utils": { - "version": "7.10.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/babel__core": "*" - } - }, "playwright/packages/playwright/bundles/expect": { "name": "expect-bundle", "version": "0.0.1", @@ -4421,7 +4401,7 @@ "version": "0.0.0", "dev": true, "dependencies": { - "codemirror": "^5.65.9", + "codemirror-shadow-1": "0.0.1", "xterm": "^5.1.0", "xterm-addon-fit": "^0.7.0" } diff --git a/package.json b/package.json index 7ecaf71cd..0beb352e1 100644 --- a/package.json +++ b/package.json @@ -31,7 +31,7 @@ "clean": "npm run clean:pw && npm run clean:examples && npm run clean:tests && npm run clean:crx", "test:install": "cd ./tests && npx playwright install --with-deps chromium", "test": "cd ./tests && npx playwright test", - "test-ui": "cd ./tests && npx playwright test --ui" + "test-ui": "cd ./tests && npx playwright test --ui --timeout 0" }, "workspaces": [ "examples/recorder-crx", diff --git a/src/client/crx.ts b/src/client/crx.ts index 33a04b702..899a4de29 100644 --- a/src/client/crx.ts +++ b/src/client/crx.ts @@ -20,6 +20,7 @@ import type * as api from '../types/types'; import type * as channels from '../protocol/channels'; import { Page } from 'playwright-core/lib/client/page'; import type { BrowserContext } from 'playwright-core/lib/client/browserContext'; +import { Mode } from '@recorder/recorderTypes'; function from(obj: any): T { return obj._object as T; @@ -48,7 +49,7 @@ export class Crx extends ChannelOwner implements api.Crx { export class CrxRecorder extends EventEmitter { private _channel: channels.CrxApplicationChannel; private _hidden: boolean = true; - private _mode: 'none' | 'recording' | 'inspecting' = 'none'; + private _mode: Mode = 'none'; constructor(channel: channels.CrxApplicationChannel) { super(); diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index a1f8a6dc0..a7236b10a 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -72,7 +72,7 @@ export type CrxApplicationDetachedEvent = { tabId: number, }; export type CrxApplicationModeChangedEvent = { - mode: 'none' | 'recording' | 'inspecting', + mode: 'none' | 'recording' | 'inspecting' | 'assertingText' | 'recording-inspecting' | 'standby' | 'assertingVisibility' | 'assertingValue', }; export type CrxApplicationAttachParams = { tabId: number, diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index 27996421d..fc9f4cce0 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -71,7 +71,7 @@ scheme.CrxApplicationDetachedEvent = tObject({ tabId: tNumber, }); scheme.CrxApplicationModeChangedEvent = tObject({ - mode: tEnum(['none', 'recording', 'inspecting']), + mode: tEnum(['none', 'recording', 'inspecting', 'assertingText', 'recording-inspecting', 'standby', 'assertingVisibility', 'assertingValue']), }); scheme.CrxApplicationAttachParams = tObject({ tabId: tNumber, @@ -120,7 +120,7 @@ scheme.CrxApplicationNewPageResult = tObject({ page: tChannel(['Page']), }); scheme.CrxApplicationShowRecorderParams = tObject({ - mode: tOptional(tEnum(['none', 'recording', 'inspecting'])), + mode: tOptional(tEnum(['none', 'recording', 'inspecting', 'assertingText', 'recording-inspecting', 'standby', 'assertingVisibility', 'assertingValue'])), language: tOptional(tString), testIdAttributeName: tOptional(tString), }); diff --git a/src/server/recorder/crxPlayer.ts b/src/server/recorder/crxPlayer.ts index 792977f81..1ab9b8940 100644 --- a/src/server/recorder/crxPlayer.ts +++ b/src/server/recorder/crxPlayer.ts @@ -16,7 +16,7 @@ import type { CallMetadata } from '@protocol/callMetadata'; import EventEmitter from 'events'; -import { serializeError } from 'playwright-core/lib/protocol/serializers'; +import { serializeError } from 'playwright-core/lib/server/errors'; import { BrowserContext } from 'playwright-core/lib/server/browserContext'; import { Frame } from 'playwright-core/lib/server/frames'; import type { Page } from 'playwright-core/lib/server/page'; diff --git a/src/server/recorder/crxRecorderApp.ts b/src/server/recorder/crxRecorderApp.ts index 7eb5d466a..eb062cbec 100644 --- a/src/server/recorder/crxRecorderApp.ts +++ b/src/server/recorder/crxRecorderApp.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { CallLog, EventData, Source } from '@recorder/recorderTypes'; +import type { CallLog, EventData, Mode, Source } from '@recorder/recorderTypes'; import { EventEmitter } from 'events'; import { BrowserContext } from 'playwright-core/lib/server/browserContext'; import type { Recorder } from 'playwright-core/lib/server/recorder'; @@ -31,10 +31,10 @@ type ChromeWindow = chrome.windows.Window; export type RecorderMessage = { type: 'recorder' } & ( | { method: 'updateCallLogs', callLogs: CallLog[] } | { method: 'setPaused', paused: boolean } - | { method: 'setMode', mode: 'none' | 'recording' | 'inspecting' } + | { method: 'setMode', mode: Mode } | { method: 'setSources', sources: Source[] } | { method: 'setFileIfNeeded', file: string } - | { method: 'setSelector', selector: string, focus?: boolean } + | { method: 'setSelector', selector: string, userGesture: string } ); export class CrxRecorderApp extends EventEmitter implements IRecorderApp { @@ -110,7 +110,7 @@ export class CrxRecorderApp extends EventEmitter implements IRecorderApp { await this._sendMessage({ type: 'recorder', method: 'setPaused', paused }); } - async setMode(mode: 'none' | 'recording' | 'inspecting') { + async setMode(mode: Mode) { await this._sendMessage({ type: 'recorder', method: 'setMode', mode }); } @@ -118,10 +118,16 @@ export class CrxRecorderApp extends EventEmitter implements IRecorderApp { await this._sendMessage({ type: 'recorder', method: 'setFileIfNeeded', file }); } - async setSelector(selector: string, focus?: boolean) { - if (focus) - this._recorder.setMode('none'); - await this._sendMessage({ type: 'recorder', method: 'setSelector', selector, focus }); + async setSelector(selector: string, userGesture?: boolean) { + if (userGesture) { + if (this._recorder.mode() === 'inspecting') { + this._recorder.setMode('standby'); + if (this._window?.id) chrome.windows.update(this._window.id, { focused: true, drawAttention: true }); + } else { + this._recorder.setMode('recording'); + } + } + await this._sendMessage({ type: 'recorder', method: 'setSelector', selector, userGesture }); } async updateCallLogs(callLogs: CallLog[]) { @@ -133,7 +139,7 @@ export class CrxRecorderApp extends EventEmitter implements IRecorderApp { await this._sendMessage({ type: 'recorder', method: 'setSources', sources }); } - private _onMessage = ({ type, event, params }: (EventData | SaveEventData) & { type: string }) => { + private _onMessage = ({ type, event, params }: EventData & { type: string }) => { if (type === 'recorderEvent') { switch (event) { case 'fileChanged': @@ -144,7 +150,7 @@ export class CrxRecorderApp extends EventEmitter implements IRecorderApp { this._player.play(this._getActionsWithContext()).catch(() => {}); break; case 'setMode': - if (params.mode === 'none') { + if (['none', 'standby'].includes(params.mode)) { this._player.pause().catch(() => {}); } else { this._player.stop().catch(() => {}); diff --git a/src/types/test.d.ts b/src/types/test.d.ts index 8e05ef2ca..e54b6baaa 100644 --- a/src/types/test.d.ts +++ b/src/types/test.d.ts @@ -624,7 +624,7 @@ interface TestConfig { /** * Configuration for the - * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) * method. */ toHaveScreenshot?: { @@ -667,7 +667,7 @@ interface TestConfig { /** * Configuration for the - * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1) + * [expect(value).toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1) * method. */ toMatchSnapshot?: { @@ -1133,9 +1133,9 @@ interface TestConfig { /** * This option configures a template controlling location of snapshots generated by - * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) * and - * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). + * [expect(value).toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). * * **Usage** * @@ -4595,7 +4595,7 @@ interface AsymmetricMatchers { /** * `expect.any()` matches any object instance created from the `constructor` or a corresponding primitive type. Use it * inside - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * to perform pattern matching. * * **Usage** @@ -4617,7 +4617,7 @@ interface AsymmetricMatchers { any(sample: unknown): AsymmetricMatcher; /** * `expect.anything()` matches everything except `null` and `undefined`. Use it inside - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * to perform pattern matching. * * **Usage** @@ -4635,7 +4635,7 @@ interface AsymmetricMatchers { * Note that received array may be a superset of the expected array and contain some extra elements. * * Use this method inside - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * to perform pattern matching. * * **Usage** @@ -4650,9 +4650,9 @@ interface AsymmetricMatchers { arrayContaining(sample: Array): AsymmetricMatcher; /** * Compares floating point numbers for approximate equality. Use this method inside - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * to perform pattern matching. When just comparing two numbers, prefer - * [genericAssertions.toBeCloseTo(expected[, numDigits])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be-close-to). + * [expect(value).toBeCloseTo(expected[, numDigits])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be-close-to). * * **Usage** * @@ -4670,7 +4670,7 @@ interface AsymmetricMatchers { * object. Note that received object may be a superset of the expected object and contain some extra properties. * * Use this method inside - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * to perform pattern matching. Object properties can be matchers to further relax the expectation. See examples. * * **Usage** @@ -4698,7 +4698,7 @@ interface AsymmetricMatchers { objectContaining(sample: Record): AsymmetricMatcher; /** * `expect.stringContaining()` matches a string that contains the expected substring. Use this method inside - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * to perform pattern matching. * * **Usage** @@ -4713,7 +4713,7 @@ interface AsymmetricMatchers { /** * `expect.stringMatching()` matches a received string that in turn matches the expected pattern. Use this method * inside - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * to perform pattern matching. * * **Usage** @@ -4780,7 +4780,7 @@ interface GenericAssertions { toBe(expected: unknown): R; /** * Compares floating point numbers for approximate equality. Use this method instead of - * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be) + * [expect(value).toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be) * when comparing floating point numbers. * * **Usage** @@ -4968,10 +4968,10 @@ interface GenericAssertions { * * For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as * performed by - * [genericAssertions.toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). + * [expect(value).toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). * * For primitive values, this method is equivalent to - * [genericAssertions.toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). + * [expect(value).toContain(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-contain-2). * * **Usage** * @@ -4993,10 +4993,10 @@ interface GenericAssertions { * * For objects, this method recursively checks equality of all fields, rather than comparing objects by reference as * performed by - * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). + * [expect(value).toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). * * For primitive values, this method is equivalent to - * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). + * [expect(value).toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be). * * **Usage** * @@ -5007,29 +5007,29 @@ interface GenericAssertions { * * **Non-strict equality** * - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * performs deep equality check that compares contents of the received and expected values. To ensure two objects * reference the same instance, use - * [genericAssertions.toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be) + * [expect(value).toBe(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-be) * instead. * - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * ignores `undefined` properties and array items, and does not insist on object types being equal. For stricter * matching, use - * [genericAssertions.toStrictEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-strict-equal). + * [expect(value).toStrictEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-strict-equal). * * **Pattern matching** * - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal) * can be also used to perform pattern matching on objects, arrays and primitive types, with the help of the following * matchers: - * - [genericAssertions.any(constructor)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-any) - * - [genericAssertions.anything()](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-anything) - * - [genericAssertions.arrayContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-array-containing) - * - [genericAssertions.closeTo(expected[, numDigits])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-close-to) - * - [genericAssertions.objectContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-object-containing) - * - [genericAssertions.stringContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-string-containing) - * - [genericAssertions.stringMatching(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-string-matching) + * - [expect(value).any(constructor)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-any) + * - [expect(value).anything()](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-anything) + * - [expect(value).arrayContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-array-containing) + * - [expect(value).closeTo(expected[, numDigits])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-close-to) + * - [expect(value).objectContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-object-containing) + * - [expect(value).stringContaining(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-string-containing) + * - [expect(value).stringMatching(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-string-matching) * * Here is an example that asserts some of the values inside a complex object: * @@ -5063,7 +5063,7 @@ interface GenericAssertions { /** * Ensures that property at provided `keyPath` exists on the object and optionally checks that property is equal to * the `expected`. Equality is checked recursively, similarly to - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal). + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal). * * **Usage** * @@ -5102,7 +5102,7 @@ interface GenericAssertions { /** * Compares contents of the value with contents of `expected`, performing "deep equality" check. Allows extra * properties to be present in the value, unlike - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal), + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal), * so you can check just a subset of object properties. * * When comparing arrays, the number of items must match, and each item is checked recursively. @@ -5128,7 +5128,7 @@ interface GenericAssertions { * Compares contents of the value with contents of `expected` **and** their types. * * Differences from - * [genericAssertions.toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal): + * [expect(value).toEqual(expected)](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-equal): * - Keys with undefined properties are checked. For example, `{ a: undefined, b: 2 }` does not match `{ b: 2 }`. * - Array sparseness is checked. For example, `[, 1]` does not match `[undefined, 1]`. * - Object types are checked to be equal. For example, a class instance with fields `a` and `b` will not equal a @@ -5174,7 +5174,7 @@ interface GenericAssertions { toThrow(error?: unknown): R; /** * An alias for - * [genericAssertions.toThrow([expected])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-throw). + * [expect(value).toThrow([expected])](https://playwright.dev/docs/api/class-genericassertions#generic-assertions-to-throw). * * **Usage** * @@ -5237,7 +5237,7 @@ export interface ExpectMatcherUtils { stringify(object: unknown, maxDepth?: number, maxWidth?: number): string; } -type State = { +export type ExpectMatcherState = { isNot: boolean; promise: 'rejects' | 'resolves' | ''; utils: ExpectMatcherUtils; @@ -5269,7 +5269,7 @@ type MakeMatchers = { rejects: MakeMatchers, any, ExtendedMatchers>; } & IfAny, SpecificMatchers & ToUserMatcherObject>; -export type Expect = { +export type Expect = { (actual: T, messageOrOptions?: string | { message?: string }): MakeMatchers; soft: (actual: T, messageOrOptions?: string | { message?: string }) => MakeMatchers; poll: (actual: () => T | Promise, messageOrOptions?: string | { message?: string, timeout?: number, intervals?: number[] }) => BaseMatchers, T> & { @@ -5278,18 +5278,13 @@ export type Expect = { */ not: BaseMatchers, T>; }; - extend MatcherReturnType | Promise>>(matchers: MoreMatchers): Expect; + extend MatcherReturnType | Promise>>(matchers: MoreMatchers): Expect; configure: (configuration: { message?: string, timeout?: number, soft?: boolean, }) => Expect; - getState(): { - expand?: boolean; - isNot?: boolean; - promise?: string; - utils: any; - }; + getState(): ExpectMatcherState; not: Omit; } & AsymmetricMatchers; @@ -5633,6 +5628,11 @@ interface LocatorAssertions { * Ensures the {@link Locator} points to an element that contains the given text. You can use regular expressions for * the value as well. * + * **Details** + * + * When `expected` parameter is a string, Playwright will normalize whitespaces and line breaks both in the actual + * text and in the expected string before matching. When regular expression is used, the actual text is matched as is. + * * **Usage** * * ```js @@ -5709,6 +5709,12 @@ interface LocatorAssertions { * @param options */ toHaveAttribute(name: string, value: string|RegExp, options?: { + /** + * Whether to perform case-insensitive match. `ignoreCase` option takes precedence over the corresponding regular + * expression flag if specified. + */ + ignoreCase?: boolean; + /** * Time to retry the assertion for in milliseconds. Defaults to `timeout` in `TestConfig.expect`. */ @@ -6022,6 +6028,11 @@ interface LocatorAssertions { * Ensures the {@link Locator} points to an element with the given text. You can use regular expressions for the value * as well. * + * **Details** + * + * When `expected` parameter is a string, Playwright will normalize whitespaces and line breaks both in the actual + * text and in the expected string before matching. When regular expression is used, the actual text is matched as is. + * * **Usage** * * ```js @@ -6451,7 +6462,7 @@ interface PageAssertions { interface SnapshotAssertions { /** * **NOTE** To compare screenshots, use - * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) * instead. * * Ensures that passed value, either a [string] or a [Buffer], matches the expected snapshot stored in the test @@ -6505,7 +6516,7 @@ interface SnapshotAssertions { /** * **NOTE** To compare screenshots, use - * [pageAssertions.toHaveScreenshot([options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-2) + * [expect(page).toHaveScreenshot([options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-2) * instead. * * Ensures that passed value, either a [string] or a [Buffer], matches the expected snapshot stored in the test @@ -6688,7 +6699,7 @@ interface TestProject { /** * Configuration for the - * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) * method. */ toHaveScreenshot?: { @@ -6731,7 +6742,7 @@ interface TestProject { /** * Configuration for the - * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1) + * [expect(value).toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1) * method. */ toMatchSnapshot?: { @@ -6857,9 +6868,9 @@ interface TestProject { /** * This option configures a template controlling location of snapshots generated by - * [pageAssertions.toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) + * [expect(page).toHaveScreenshot(name[, options])](https://playwright.dev/docs/api/class-pageassertions#page-assertions-to-have-screenshot-1) * and - * [snapshotAssertions.toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). + * [expect(value).toMatchSnapshot(name[, options])](https://playwright.dev/docs/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1). * * **Usage** * diff --git a/src/types/types.d.ts b/src/types/types.d.ts index c8c59eb8f..0007788c8 100644 --- a/src/types/types.d.ts +++ b/src/types/types.d.ts @@ -339,7 +339,7 @@ export interface CrxRecorder { /** * mode */ - mode: "none"|"recording"|"inspecting"; + mode: "none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; }) => void): this; /** @@ -359,7 +359,7 @@ export interface CrxRecorder { /** * mode */ - mode: "none"|"recording"|"inspecting"; + mode: "none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; }) => void): this; /** @@ -379,7 +379,7 @@ export interface CrxRecorder { /** * mode */ - mode: "none"|"recording"|"inspecting"; + mode: "none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; }) => void): this; /** @@ -399,7 +399,7 @@ export interface CrxRecorder { /** * mode */ - mode: "none"|"recording"|"inspecting"; + mode: "none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; }) => void): this; /** @@ -419,7 +419,7 @@ export interface CrxRecorder { /** * mode */ - mode: "none"|"recording"|"inspecting"; + mode: "none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; }) => void): this; /** @@ -439,7 +439,7 @@ export interface CrxRecorder { /** * mode */ - mode: "none"|"recording"|"inspecting"; + mode: "none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; }) => void): this; hide(): Promise; @@ -452,10 +452,10 @@ export interface CrxRecorder { show(options?: { language?: null|string; - mode?: null|"none"|"recording"|"inspecting"; + mode?: null|"none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; testIdAttributeName?: null|string; }): Promise; - mode: "none"|"recording"|"inspecting"; + mode: "none"|"recording"|"inspecting"|"assertingText"|"recording-inspecting"|"standby"|"assertingVisibility"|"assertingValue"; } diff --git a/tests/crx/crxRecorderTest.ts b/tests/crx/crxRecorderTest.ts index 6348e1daf..eeab14f35 100644 --- a/tests/crx/crxRecorderTest.ts +++ b/tests/crx/crxRecorderTest.ts @@ -90,8 +90,9 @@ export const test = crxTest.extend<{ recorderPage = recorderPage ?? (await recorderPagePromise)!; + const locator = page.locator('x-pw-glass').first(); try { - await page.locator('x-pw-glass').waitFor({ state: 'attached', timeout: 100 }); + await locator.waitFor({ state: 'attached', timeout: 100 }); } catch(e) { if (await recorderPage.getByTitle('Record').evaluate(e => e.classList.contains('toggled'))) { await recorderPage.getByTitle('Record').click(); @@ -100,7 +101,7 @@ export const test = crxTest.extend<{ } else { await page.reload(); } - await page.locator('x-pw-glass').waitFor({ state: 'attached', timeout: 100 }); + await locator.waitFor({ state: 'attached', timeout: 100 }); } return recorderPage;