diff --git a/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts b/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts index 201b3f999d..f53b160ccf 100644 --- a/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts +++ b/packages/playwright-core/src/server/bidi/bidiExecutionContext.ts @@ -77,10 +77,6 @@ export class BidiExecutionContext implements js.ExecutionContextDelegate { throw new js.JavaScriptErrorInEvaluate('Unexpected response type: ' + JSON.stringify(response)); } - rawCallFunctionNoReply(func: Function, ...args: any[]) { - throw new Error('Method not implemented.'); - } - async evaluateWithArguments(functionDeclaration: string, returnByValue: boolean, utilityScript: js.JSHandle, values: any[], objectIds: string[]): Promise { const response = await this._session.send('script.callFunction', { functionDeclaration, diff --git a/packages/playwright-core/src/server/chromium/crExecutionContext.ts b/packages/playwright-core/src/server/chromium/crExecutionContext.ts index d54505d283..1cd58de7af 100644 --- a/packages/playwright-core/src/server/chromium/crExecutionContext.ts +++ b/packages/playwright-core/src/server/chromium/crExecutionContext.ts @@ -53,16 +53,6 @@ export class CRExecutionContext implements js.ExecutionContextDelegate { return remoteObject.objectId!; } - rawCallFunctionNoReply(func: Function, ...args: any[]) { - this._client.send('Runtime.callFunctionOn', { - functionDeclaration: func.toString(), - arguments: args.map(a => a instanceof js.JSHandle ? { objectId: a._objectId } : { value: a }), - returnByValue: true, - executionContextId: this._contextId, - userGesture: true - }).catch(() => {}); - } - async evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: js.JSHandle, values: any[], objectIds: string[]): Promise { const { exceptionDetails, result: remoteObject } = await this._client.send('Runtime.callFunctionOn', { functionDeclaration: expression, diff --git a/packages/playwright-core/src/server/dom.ts b/packages/playwright-core/src/server/dom.ts index 05a8b4fda2..c2ed979fbe 100644 --- a/packages/playwright-core/src/server/dom.ts +++ b/packages/playwright-core/src/server/dom.ts @@ -421,7 +421,7 @@ export class ElementHandle extends js.JSHandle { return maybePoint; const point = roundPoint(maybePoint); progress.metadata.point = point; - await progress.beforeInputAction(this); + await this.instrumentation.onBeforeInputAction(this, progress.metadata); let hitTargetInterceptionHandle: js.JSHandle | undefined; if (force) { @@ -490,9 +490,19 @@ export class ElementHandle extends js.JSHandle { return 'done'; } + private async _markAsTargetElement(metadata: CallMetadata) { + if (!metadata.id) + return; + await this.evaluateInUtility(([injected, node, callId]) => { + if (node.nodeType === 1 /* Node.ELEMENT_NODE */) + injected.markTargetElements(new Set([node as Node as Element]), callId); + }, metadata.id); + } + async hover(metadata: CallMetadata, options: types.PointerActionOptions & types.PointerActionWaitOptions): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._hover(progress, options); return assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(options)); @@ -505,6 +515,7 @@ export class ElementHandle extends js.JSHandle { async click(metadata: CallMetadata, options: { noWaitAfter?: boolean } & types.MouseClickOptions & types.PointerActionWaitOptions = {}): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._click(progress, { ...options, waitAfter: !options.noWaitAfter }); return assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(options)); @@ -517,6 +528,7 @@ export class ElementHandle extends js.JSHandle { async dblclick(metadata: CallMetadata, options: types.MouseMultiClickOptions & types.PointerActionWaitOptions): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._dblclick(progress, options); return assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(options)); @@ -529,6 +541,7 @@ export class ElementHandle extends js.JSHandle { async tap(metadata: CallMetadata, options: types.PointerActionWaitOptions = {}): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._tap(progress, options); return assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(options)); @@ -541,6 +554,7 @@ export class ElementHandle extends js.JSHandle { async selectOption(metadata: CallMetadata, elements: ElementHandle[], values: types.SelectOption[], options: types.CommonActionOptions): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._selectOption(progress, elements, values, options); return throwRetargetableDOMError(result); }, this._page._timeoutSettings.timeout(options)); @@ -549,7 +563,7 @@ export class ElementHandle extends js.JSHandle { async _selectOption(progress: Progress, elements: ElementHandle[], values: types.SelectOption[], options: types.CommonActionOptions): Promise { let resultingOptions: string[] = []; await this._retryAction(progress, 'select option', async () => { - await progress.beforeInputAction(this); + await this.instrumentation.onBeforeInputAction(this, progress.metadata); if (!options.force) progress.log(` waiting for element to be visible and enabled`); const optionsToSelect = [...elements, ...values]; @@ -574,6 +588,7 @@ export class ElementHandle extends js.JSHandle { async fill(metadata: CallMetadata, value: string, options: types.CommonActionOptions = {}): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._fill(progress, value, options); assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(options)); @@ -582,7 +597,7 @@ export class ElementHandle extends js.JSHandle { async _fill(progress: Progress, value: string, options: types.CommonActionOptions): Promise<'error:notconnected' | 'done'> { progress.log(` fill("${value}")`); return await this._retryAction(progress, 'fill', async () => { - await progress.beforeInputAction(this); + await this.instrumentation.onBeforeInputAction(this, progress.metadata); if (!options.force) progress.log(' waiting for element to be visible, enabled and editable'); const result = await this.evaluateInUtility(async ([injected, node, { value, force }]) => { @@ -629,6 +644,7 @@ export class ElementHandle extends js.JSHandle { const inputFileItems = await prepareFilesForUpload(this._frame, params); const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._setInputFiles(progress, inputFileItems); return assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(params)); @@ -655,7 +671,7 @@ export class ElementHandle extends js.JSHandle { if (result === 'error:notconnected' || !result.asElement()) return 'error:notconnected'; const retargeted = result.asElement() as ElementHandle; - await progress.beforeInputAction(this); + await this.instrumentation.onBeforeInputAction(this, progress.metadata); progress.throwIfAborted(); // Avoid action that has side-effects. if (localPaths || localDirectory) { const localPathsOrDirectory = localDirectory ? [localDirectory] : localPaths!; @@ -677,6 +693,7 @@ export class ElementHandle extends js.JSHandle { async focus(metadata: CallMetadata): Promise { const controller = new ProgressController(metadata, this); await controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._focus(progress); return assertDone(throwRetargetableDOMError(result)); }, 0); @@ -695,6 +712,7 @@ export class ElementHandle extends js.JSHandle { async type(metadata: CallMetadata, text: string, options: { delay?: number } & types.TimeoutOptions & types.StrictOptions): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._type(progress, text, options); return assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(options)); @@ -702,7 +720,7 @@ export class ElementHandle extends js.JSHandle { async _type(progress: Progress, text: string, options: { delay?: number } & types.TimeoutOptions & types.StrictOptions): Promise<'error:notconnected' | 'done'> { progress.log(`elementHandle.type("${text}")`); - await progress.beforeInputAction(this); + await this.instrumentation.onBeforeInputAction(this, progress.metadata); const result = await this._focus(progress, true /* resetSelectionIfNotFocused */); if (result !== 'done') return result; @@ -714,6 +732,7 @@ export class ElementHandle extends js.JSHandle { async press(metadata: CallMetadata, key: string, options: { delay?: number, noWaitAfter?: boolean } & types.TimeoutOptions & types.StrictOptions): Promise { const controller = new ProgressController(metadata, this); return controller.run(async progress => { + await this._markAsTargetElement(metadata); const result = await this._press(progress, key, options); return assertDone(throwRetargetableDOMError(result)); }, this._page._timeoutSettings.timeout(options)); @@ -721,7 +740,7 @@ export class ElementHandle extends js.JSHandle { async _press(progress: Progress, key: string, options: { delay?: number, noWaitAfter?: boolean } & types.TimeoutOptions & types.StrictOptions): Promise<'error:notconnected' | 'done'> { progress.log(`elementHandle.press("${key}")`); - await progress.beforeInputAction(this); + await this.instrumentation.onBeforeInputAction(this, progress.metadata); return this._page._frameManager.waitForSignalsCreatedBy(progress, !options.noWaitAfter, async () => { const result = await this._focus(progress, true /* resetSelectionIfNotFocused */); if (result !== 'done') @@ -753,6 +772,7 @@ export class ElementHandle extends js.JSHandle { const result = await this.evaluateInUtility(([injected, node]) => injected.elementState(node, 'checked'), {}); return throwRetargetableDOMError(result); }; + await this._markAsTargetElement(progress.metadata); if (await isChecked() === state) return 'done'; const result = await this._click(progress, { ...options, waitAfter: 'disabled' }); diff --git a/packages/playwright-core/src/server/firefox/ffExecutionContext.ts b/packages/playwright-core/src/server/firefox/ffExecutionContext.ts index ba981da942..c7a3f106f8 100644 --- a/packages/playwright-core/src/server/firefox/ffExecutionContext.ts +++ b/packages/playwright-core/src/server/firefox/ffExecutionContext.ts @@ -51,15 +51,6 @@ export class FFExecutionContext implements js.ExecutionContextDelegate { return payload.result!.objectId!; } - rawCallFunctionNoReply(func: Function, ...args: any[]) { - this._session.send('Runtime.callFunction', { - functionDeclaration: func.toString(), - args: args.map(a => a instanceof js.JSHandle ? { objectId: a._objectId } : { value: a }) as any, - returnByValue: true, - executionContextId: this._executionContextId - }).catch(() => {}); - } - async evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: js.JSHandle, values: any[], objectIds: string[]): Promise { const payload = await this._session.send('Runtime.callFunction', { functionDeclaration: expression, diff --git a/packages/playwright-core/src/server/frames.ts b/packages/playwright-core/src/server/frames.ts index b7b626d09f..7dc992813b 100644 --- a/packages/playwright-core/src/server/frames.ts +++ b/packages/playwright-core/src/server/frames.ts @@ -1124,8 +1124,10 @@ export class Frame extends SdkObject { progress.throwIfAborted(); if (!resolved) return continuePolling; - const result = await resolved.injected.evaluateHandle((injected, { info }) => { + const result = await resolved.injected.evaluateHandle((injected, { info, callId }) => { const elements = injected.querySelectorAll(info.parsed, document); + if (callId) + injected.markTargetElements(new Set(elements), callId); const element = elements[0] as Element | undefined; let log = ''; if (elements.length > 1) { @@ -1136,7 +1138,7 @@ export class Frame extends SdkObject { log = ` locator resolved to ${injected.previewNode(element)}`; } return { log, success: !!element, element }; - }, { info: resolved.info }); + }, { info: resolved.info, callId: progress.metadata.id }); const { log, success } = await result.evaluate(r => ({ log: r.log, success: r.success })); if (log) progress.log(log); @@ -1478,6 +1480,8 @@ export class Frame extends SdkObject { const { log, matches, received, missingReceived } = await injected.evaluate(async (injected, { info, options, callId }) => { const elements = info ? injected.querySelectorAll(info.parsed, document) : []; + if (callId) + injected.markTargetElements(new Set(elements), callId); const isArray = options.expression === 'to.have.count' || options.expression.endsWith('.array'); let log = ''; if (isArray) @@ -1486,8 +1490,6 @@ export class Frame extends SdkObject { throw injected.strictModeViolationError(info!.parsed, elements); else if (elements.length) log = ` locator resolved to ${injected.previewNode(elements[0])}`; - if (callId) - injected.markTargetElements(new Set(elements), callId); return { log, ...await injected.expect(elements[0], options, elements) }; }, { info, options, callId: progress.metadata.id }); diff --git a/packages/playwright-core/src/server/instrumentation.ts b/packages/playwright-core/src/server/instrumentation.ts index 4d29be0284..2a384fb169 100644 --- a/packages/playwright-core/src/server/instrumentation.ts +++ b/packages/playwright-core/src/server/instrumentation.ts @@ -20,7 +20,6 @@ import type { APIRequestContext } from './fetch'; import type { Browser } from './browser'; import type { BrowserContext } from './browserContext'; import type { BrowserType } from './browserType'; -import type { ElementHandle } from './dom'; import type { Frame } from './frames'; import type { Page } from './page'; import type { Playwright } from './playwright'; @@ -57,7 +56,7 @@ export interface Instrumentation { addListener(listener: InstrumentationListener, context: BrowserContext | APIRequestContext | null): void; removeListener(listener: InstrumentationListener): void; onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata): Promise; - onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata, element: ElementHandle): Promise; + onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata): Promise; onCallLog(sdkObject: SdkObject, metadata: CallMetadata, logName: string, message: string): void; onAfterCall(sdkObject: SdkObject, metadata: CallMetadata): Promise; onPageOpen(page: Page): void; @@ -70,7 +69,7 @@ export interface Instrumentation { export interface InstrumentationListener { onBeforeCall?(sdkObject: SdkObject, metadata: CallMetadata): Promise; - onBeforeInputAction?(sdkObject: SdkObject, metadata: CallMetadata, element: ElementHandle): Promise; + onBeforeInputAction?(sdkObject: SdkObject, metadata: CallMetadata): Promise; onCallLog?(sdkObject: SdkObject, metadata: CallMetadata, logName: string, message: string): void; onAfterCall?(sdkObject: SdkObject, metadata: CallMetadata): Promise; onPageOpen?(page: Page): void; diff --git a/packages/playwright-core/src/server/javascript.ts b/packages/playwright-core/src/server/javascript.ts index 40dee4888a..dbbe89d5c2 100644 --- a/packages/playwright-core/src/server/javascript.ts +++ b/packages/playwright-core/src/server/javascript.ts @@ -53,7 +53,6 @@ export type SmartHandle = T extends Node ? dom.ElementHandle : JSHandle export interface ExecutionContextDelegate { rawEvaluateJSON(expression: string): Promise; rawEvaluateHandle(expression: string): Promise; - rawCallFunctionNoReply(func: Function, ...args: any[]): void; evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: JSHandle, values: any[], objectIds: ObjectId[]): Promise; getProperties(context: ExecutionContext, objectId: ObjectId): Promise>; createHandle(context: ExecutionContext, remoteObject: RemoteObject): JSHandle; @@ -88,10 +87,6 @@ export class ExecutionContext extends SdkObject { return this._raceAgainstContextDestroyed(this._delegate.rawEvaluateHandle(expression)); } - rawCallFunctionNoReply(func: Function, ...args: any[]): void { - this._delegate.rawCallFunctionNoReply(func, ...args); - } - evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: JSHandle, values: any[], objectIds: ObjectId[]): Promise { return this._raceAgainstContextDestroyed(this._delegate.evaluateWithArguments(expression, returnByValue, utilityScript, values, objectIds)); } @@ -151,10 +146,6 @@ export class JSHandle extends SdkObject { (globalThis as any).leakedJSHandles.set(this, new Error('Leaked JSHandle')); } - callFunctionNoReply(func: Function, arg: any) { - this._context.rawCallFunctionNoReply(func, this, arg); - } - async evaluate(pageFunction: FuncOn, arg?: Arg): Promise { return evaluate(this._context, true /* returnByValue */, pageFunction, this, arg); } diff --git a/packages/playwright-core/src/server/progress.ts b/packages/playwright-core/src/server/progress.ts index 70de43b944..d92c5ed226 100644 --- a/packages/playwright-core/src/server/progress.ts +++ b/packages/playwright-core/src/server/progress.ts @@ -18,7 +18,6 @@ import { TimeoutError } from './errors'; import { assert, monotonicTime } from '../utils'; import type { LogName } from '../utils/debugLogger'; import type { CallMetadata, Instrumentation, SdkObject } from './instrumentation'; -import type { ElementHandle } from './dom'; import { ManualPromise } from '../utils/manualPromise'; export interface Progress { @@ -27,7 +26,6 @@ export interface Progress { isRunning(): boolean; cleanupWhenAborted(cleanup: () => any): void; throwIfAborted(): void; - beforeInputAction(element: ElementHandle): Promise; metadata: CallMetadata; } @@ -89,9 +87,6 @@ export class ProgressController { if (this._state === 'aborted') throw new AbortedError(); }, - beforeInputAction: async (element: ElementHandle) => { - await this.instrumentation.onBeforeInputAction(this.sdkObject, this.metadata, element); - }, metadata: this.metadata }; diff --git a/packages/playwright-core/src/server/trace/recorder/snapshotter.ts b/packages/playwright-core/src/server/trace/recorder/snapshotter.ts index d552c397e0..115cd3dd94 100644 --- a/packages/playwright-core/src/server/trace/recorder/snapshotter.ts +++ b/packages/playwright-core/src/server/trace/recorder/snapshotter.ts @@ -24,7 +24,6 @@ import type { SnapshotData } from './snapshotterInjected'; import { frameSnapshotStreamer } from './snapshotterInjected'; import { calculateSha1, createGuid, monotonicTime } from '../../../utils'; import type { FrameSnapshot } from '@trace/snapshot'; -import type { ElementHandle } from '../../dom'; import { mime } from '../../../utilsBundle'; export type SnapshotterBlob = { @@ -105,21 +104,10 @@ export class Snapshotter { eventsHelper.removeEventListeners(this._eventListeners); } - async captureSnapshot(page: Page, callId: string, snapshotName: string, element?: ElementHandle): Promise { + async captureSnapshot(page: Page, callId: string, snapshotName: string): Promise { // Prepare expression synchronously. const expression = `window["${this._snapshotStreamer}"].captureSnapshot(${JSON.stringify(snapshotName)})`; - // In a best-effort manner, without waiting for it, mark target element. - element?.callFunctionNoReply((element: Element, callId: string) => { - const customEvent = new CustomEvent('__playwright_target__', { - bubbles: true, - cancelable: true, - detail: callId, - composed: true, - }); - element.dispatchEvent(customEvent); - }, callId); - // In each frame, in a non-stalling manner, capture the snapshots. const snapshots = page.frames().map(async frame => { const data = await frame.nonStallingRawEvaluateInExistingMainContext(expression).catch(e => debugLogger.log('error', e)) as SnapshotData; diff --git a/packages/playwright-core/src/server/trace/recorder/tracing.ts b/packages/playwright-core/src/server/trace/recorder/tracing.ts index c3317fcab4..97476d4b31 100644 --- a/packages/playwright-core/src/server/trace/recorder/tracing.ts +++ b/packages/playwright-core/src/server/trace/recorder/tracing.ts @@ -23,7 +23,6 @@ import { commandsWithTracingSnapshots } from '../../../protocol/debug'; import { assert, createGuid, monotonicTime, SerializedFS, removeFolders, eventsHelper, type RegisteredListener } from '../../../utils'; import { Artifact } from '../../artifact'; import { BrowserContext } from '../../browserContext'; -import type { ElementHandle } from '../../dom'; import type { APIRequestContext } from '../../fetch'; import type { CallMetadata, InstrumentationListener } from '../../instrumentation'; import { SdkObject } from '../../instrumentation'; @@ -341,7 +340,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps return { artifact }; } - async _captureSnapshot(snapshotName: string, sdkObject: SdkObject, metadata: CallMetadata, element?: ElementHandle): Promise { + async _captureSnapshot(snapshotName: string, sdkObject: SdkObject, metadata: CallMetadata): Promise { if (!this._snapshotter) return; if (!sdkObject.attribution.page) @@ -350,7 +349,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps return; if (!shouldCaptureSnapshot(metadata)) return; - await this._snapshotter.captureSnapshot(sdkObject.attribution.page, metadata.id, snapshotName, element).catch(() => {}); + await this._snapshotter.captureSnapshot(sdkObject.attribution.page, metadata.id, snapshotName).catch(() => {}); } onBeforeCall(sdkObject: SdkObject, metadata: CallMetadata) { @@ -365,7 +364,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps return this._captureSnapshot(event.beforeSnapshot, sdkObject, metadata); } - onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata, element: ElementHandle) { + onBeforeInputAction(sdkObject: SdkObject, metadata: CallMetadata) { if (!this._state?.callIds.has(metadata.id)) return Promise.resolve(); // IMPORTANT: no awaits before this._appendTraceEvent in this method. @@ -375,7 +374,7 @@ export class Tracing extends SdkObject implements InstrumentationListener, Snaps sdkObject.attribution.page?.temporarilyDisableTracingScreencastThrottling(); event.inputSnapshot = `input@${metadata.id}`; this._appendTraceEvent(event); - return this._captureSnapshot(event.inputSnapshot, sdkObject, metadata, element); + return this._captureSnapshot(event.inputSnapshot, sdkObject, metadata); } onCallLog(sdkObject: SdkObject, metadata: CallMetadata, logName: string, message: string) { diff --git a/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts b/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts index f7461599aa..f28c5ef03b 100644 --- a/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts +++ b/packages/playwright-core/src/server/trace/test/inMemorySnapshotter.ts @@ -21,7 +21,6 @@ import type { SnapshotRenderer } from '../../../../../trace-viewer/src/sw/snapsh import { SnapshotStorage } from '../../../../../trace-viewer/src/sw/snapshotStorage'; import type { SnapshotterBlob, SnapshotterDelegate } from '../recorder/snapshotter'; import { Snapshotter } from '../recorder/snapshotter'; -import type { ElementHandle } from '../../dom'; import type { HarTracerDelegate } from '../../har/harTracer'; import { HarTracer } from '../../har/harTracer'; import type * as har from '@trace/har'; @@ -59,11 +58,11 @@ export class InMemorySnapshotter implements SnapshotterDelegate, HarTracerDelega this._harTracer.stop(); } - async captureSnapshot(page: Page, callId: string, snapshotName: string, element?: ElementHandle): Promise { + async captureSnapshot(page: Page, callId: string, snapshotName: string): Promise { if (this._snapshotReadyPromises.has(snapshotName)) throw new Error('Duplicate snapshot name: ' + snapshotName); - this._snapshotter.captureSnapshot(page, callId, snapshotName, element).catch(() => {}); + this._snapshotter.captureSnapshot(page, callId, snapshotName).catch(() => {}); const promise = new ManualPromise(); this._snapshotReadyPromises.set(snapshotName, promise); return promise; diff --git a/packages/playwright-core/src/server/webkit/wkExecutionContext.ts b/packages/playwright-core/src/server/webkit/wkExecutionContext.ts index 4416df7a9e..52b8ba3677 100644 --- a/packages/playwright-core/src/server/webkit/wkExecutionContext.ts +++ b/packages/playwright-core/src/server/webkit/wkExecutionContext.ts @@ -60,16 +60,6 @@ export class WKExecutionContext implements js.ExecutionContextDelegate { } } - rawCallFunctionNoReply(func: Function, ...args: any[]) { - this._session.send('Runtime.callFunctionOn', { - functionDeclaration: func.toString(), - objectId: args.find(a => a instanceof js.JSHandle)!._objectId!, - arguments: args.map(a => a instanceof js.JSHandle ? { objectId: a._objectId } : { value: a }), - returnByValue: true, - emulateUserGesture: true - }).catch(() => {}); - } - async evaluateWithArguments(expression: string, returnByValue: boolean, utilityScript: js.JSHandle, values: any[], objectIds: string[]): Promise { try { const response = await this._session.send('Runtime.callFunctionOn', { diff --git a/tests/library/snapshotter.spec.ts b/tests/library/snapshotter.spec.ts index b6c45b9252..7ada643dcc 100644 --- a/tests/library/snapshotter.spec.ts +++ b/tests/library/snapshotter.spec.ts @@ -215,20 +215,6 @@ it.describe('snapshots', () => { } }); - it('should capture snapshot target', async ({ page, toImpl, snapshotter }) => { - await page.setContent(''); - { - const handle = await page.$('text=Hello'); - const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'call@1', 'snapshot@call@1', toImpl(handle)); - expect(distillSnapshot(snapshot, false /* distillTarget */)).toBe(''); - } - { - const handle = await page.$('text=World'); - const snapshot = await snapshotter.captureSnapshot(toImpl(page), 'call@2', 'snapshot@call@2', toImpl(handle)); - expect(distillSnapshot(snapshot, false /* distillTarget */)).toBe(''); - } - }); - it('should collect on attribute change', async ({ page, toImpl, snapshotter }) => { await page.setContent(''); { diff --git a/tests/library/trace-viewer.spec.ts b/tests/library/trace-viewer.spec.ts index 71689fa4c1..e8863b0e1e 100644 --- a/tests/library/trace-viewer.spec.ts +++ b/tests/library/trace-viewer.spec.ts @@ -776,6 +776,8 @@ test('should highlight target elements', async ({ page, runAndTrace, browserName await expect(page.locator('text=t6')).toHaveText(/t6/i); await expect(page.locator('text=multi')).toHaveText(['a', 'b'], { timeout: 1000 }).catch(() => {}); await page.mouse.move(123, 234); + await page.getByText(/^t\d$/).click().catch(() => {}); + await expect(page.getByText(/t3|t4/)).toBeVisible().catch(() => {}); }); async function highlightedDivs(frameLocator: FrameLocator) { @@ -817,6 +819,12 @@ test('should highlight target elements', async ({ page, runAndTrace, browserName const frameMouseMove = await traceViewer.snapshotFrame('mouse.move'); await expect(frameMouseMove.locator('x-pw-pointer')).toBeVisible(); + + const frameClickStrictViolation = await traceViewer.snapshotFrame('locator.click'); + await expect.poll(() => highlightedDivs(frameClickStrictViolation)).toEqual(['t1', 't2', 't3', 't4', 't5', 't6']); + + const frameExpectStrictViolation = await traceViewer.snapshotFrame('expect.toBeVisible'); + await expect.poll(() => highlightedDivs(frameExpectStrictViolation)).toEqual(['t3', 't4']); }); test('should highlight target element in shadow dom', async ({ page, server, runAndTrace }) => {