From 8b9a2afd3d69154698fbebf9f2368f4e2c21cbe2 Mon Sep 17 00:00:00 2001 From: Pavel Feldman Date: Sat, 13 Feb 2021 22:13:51 -0800 Subject: [PATCH] feat(inspector): render errors (#5459) --- index.js | 1 - src/dispatchers/dispatcher.ts | 1 + src/server/browserContext.ts | 4 +- src/server/instrumentation.ts | 2 +- src/server/supplements/injected/recorder.ts | 6 +- .../supplements/recorder/recorderApp.ts | 36 ++++-- .../supplements/recorder/recorderTypes.ts | 3 +- src/server/supplements/recorderSupplement.ts | 10 +- src/trace/tracer.ts | 2 +- src/utils/debugLogger.ts | 4 +- src/web/components/source.css | 12 +- src/web/components/source.tsx | 2 +- src/web/recorder/recorder.css | 36 ++++-- src/web/recorder/recorder.tsx | 11 +- test/cli/cli.fixtures.ts | 16 +-- test/pause.spec.ts | 105 ++++++++++++++---- test/recorder.fixtures.ts | 20 ++-- 17 files changed, 191 insertions(+), 80 deletions(-) diff --git a/index.js b/index.js index 0bce8a7abc0c5..4b9607bba49b7 100644 --- a/index.js +++ b/index.js @@ -14,5 +14,4 @@ * limitations under the License. */ -const { setUnderTest } = require('./lib/utils/utils'); module.exports = require('./lib/inprocess'); diff --git a/src/dispatchers/dispatcher.ts b/src/dispatchers/dispatcher.ts index eb9cfe9586f01..c3e1a56c8bf72 100644 --- a/src/dispatchers/dispatcher.ts +++ b/src/dispatchers/dispatcher.ts @@ -214,6 +214,7 @@ export class DispatcherConnection { this.onmessage({ id, result: this._replaceDispatchersWithGuids(result) }); } catch (e) { // Dispatching error + callMetadata.error = e.message; if (callMetadata.log.length) rewriteErrorMessage(e, e.message + formatLogRecording(callMetadata.log) + kLoggingNote); this.onmessage({ id, error: serializeError(e) }); diff --git a/src/server/browserContext.ts b/src/server/browserContext.ts index 6bf085489b1b5..2b0f52f9db102 100644 --- a/src/server/browserContext.ts +++ b/src/server/browserContext.ts @@ -345,8 +345,8 @@ export abstract class BrowserContext extends SdkObject { } } - async extendInjectedScript(source: string) { - const installInFrame = (frame: frames.Frame) => frame.extendInjectedScript(source).catch(e => {}); + async extendInjectedScript(source: string, arg?: any) { + const installInFrame = (frame: frames.Frame) => frame.extendInjectedScript(source, arg).catch(() => {}); const installInPage = (page: Page) => { page.on(Page.Events.InternalFrameNavigatedToNewDocument, installInFrame); return Promise.all(page.frames().map(installInFrame)); diff --git a/src/server/instrumentation.ts b/src/server/instrumentation.ts index 2b63c06e68a2b..5544d779dfc17 100644 --- a/src/server/instrumentation.ts +++ b/src/server/instrumentation.ts @@ -39,7 +39,7 @@ export type CallMetadata = { params: any; stack?: StackFrame[]; log: string[]; - error?: Error; + error?: string; point?: Point; }; diff --git a/src/server/supplements/injected/recorder.ts b/src/server/supplements/injected/recorder.ts index c4313eeac6004..80bde3de35491 100644 --- a/src/server/supplements/injected/recorder.ts +++ b/src/server/supplements/injected/recorder.ts @@ -51,8 +51,10 @@ export class Recorder { private _actionPointElement: HTMLElement; private _actionPoint: Point | undefined; private _actionSelector: string | undefined; + private _params: { isUnderTest: boolean; }; - constructor(injectedScript: InjectedScript) { + constructor(injectedScript: InjectedScript, params: { isUnderTest: boolean }) { + this._params = params; this._injectedScript = injectedScript; this._outerGlassPaneElement = html` { + await page.setContent(''); + const scriptPromise = (async () => { + await page.pause(); + await page.click('button'); + })(); + const recorderPage = await recorderPageGetter(); + const source = await recorderPage.textContent('.source-line-paused'); + expect(source).toContain('page.pause();'); + + await recorderPage.click('[title="Step over"]'); + await recorderPage.waitForSelector('.source-line-paused :has-text("page.click")'); + + await recorderPage.click('[title=Resume]'); + await scriptPromise; + }); + + it('should highlight pointer', async ({page, recorderPageGetter}) => { + await page.setContent(''); + const scriptPromise = (async () => { + await page.pause(); + await page.click('button'); + })(); + const recorderPage = await recorderPageGetter(); + await recorderPage.click('[title="Step over"]'); + + const point = await page.waitForSelector('x-pw-action-point'); + const button = await page.waitForSelector('button'); + const box1 = await button.boundingBox(); + const box2 = await point.boundingBox(); + + const x1 = box1.x + box1.width / 2; + const y1 = box1.y + box1.height / 2; + const x2 = box2.x + box2.width / 2; + const y2 = box2.y + box2.height / 2; + + expect(Math.abs(x1 - x2) < 2).toBeTruthy(); + expect(Math.abs(y1 - y2) < 2).toBeTruthy(); + + await recorderPage.click('[title="Step over"]'); + await scriptPromise; }); }); diff --git a/test/recorder.fixtures.ts b/test/recorder.fixtures.ts index 7e690653d7b29..952a5c2296542 100644 --- a/test/recorder.fixtures.ts +++ b/test/recorder.fixtures.ts @@ -15,25 +15,21 @@ */ import { folio as baseFolio } from './fixtures'; -import { internalCallMetadata } from '../lib/server/instrumentation'; +import { Page } from '..'; +import { chromium } from '../index'; const fixtures = baseFolio.extend<{ - recorderFrame: () => Promise, - recorderClick: (selector: string) => Promise + recorderPageGetter: () => Promise, }>(); -fixtures.recorderFrame.init(async ({context, toImpl}, runTest) => { +fixtures.recorderPageGetter.init(async ({context, toImpl}, runTest) => { await runTest(async () => { while (!toImpl(context).recorderAppForTest) await new Promise(f => setTimeout(f, 100)); - return toImpl(context).recorderAppForTest._page.mainFrame(); - }); -}); - -fixtures.recorderClick.init(async ({ recorderFrame }, runTest) => { - await runTest(async (selector: string) => { - const frame = await recorderFrame(); - await frame.click(internalCallMetadata(), selector, {}); + const wsEndpoint = toImpl(context).recorderAppForTest.wsEndpoint; + const browser = await chromium.connectOverCDP({ wsEndpoint }); + const c = browser.contexts()[0]; + return c.pages()[0] || await c.waitForEvent('page'); }); });