From 30d7444866cc39483c6a91358b786015f1c12487 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Thu, 20 Apr 2023 16:15:20 +0200 Subject: [PATCH] add tests --- .../replay/captureConsoleLog/template.html | 39 ++++++ .../suites/replay/captureConsoleLog/test.ts | 123 ++++++++++++++++++ .../utils/replayHelpers.ts | 48 +++---- 3 files changed, 188 insertions(+), 22 deletions(-) create mode 100644 packages/browser-integration-tests/suites/replay/captureConsoleLog/template.html create mode 100644 packages/browser-integration-tests/suites/replay/captureConsoleLog/test.ts diff --git a/packages/browser-integration-tests/suites/replay/captureConsoleLog/template.html b/packages/browser-integration-tests/suites/replay/captureConsoleLog/template.html new file mode 100644 index 000000000000..c3c45a1dcffc --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/captureConsoleLog/template.html @@ -0,0 +1,39 @@ + + + + + + + + + + + + diff --git a/packages/browser-integration-tests/suites/replay/captureConsoleLog/test.ts b/packages/browser-integration-tests/suites/replay/captureConsoleLog/test.ts new file mode 100644 index 000000000000..018af95dfc6e --- /dev/null +++ b/packages/browser-integration-tests/suites/replay/captureConsoleLog/test.ts @@ -0,0 +1,123 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../utils/fixtures'; +import { getCustomRecordingEvents, shouldSkipReplayTest, waitForReplayRequest } from '../../../utils/replayHelpers'; + +sentryTest('should capture console messages in replay', async ({ getLocalTestPath, page, forceFlushReplay }) => { + // console integration is not used in bundles/loader + const bundle = process.env.PW_BUNDLE || ''; + if (shouldSkipReplayTest() || bundle.startsWith('bundle_') || bundle.startsWith('loader_')) { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestPath({ testDir: __dirname }); + + await page.goto(url); + await reqPromise0; + + const reqPromise1 = waitForReplayRequest( + page, + (_event, res) => { + const { breadcrumbs } = getCustomRecordingEvents(res); + + return breadcrumbs.filter(breadcrumb => breadcrumb.category === 'console').length > 0; + }, + 5_000, + ); + + await page.click('[data-log]'); + + await forceFlushReplay(); + + const { breadcrumbs } = getCustomRecordingEvents(await reqPromise1); + + expect(breadcrumbs.filter(breadcrumb => breadcrumb.category === 'console')).toEqual([ + { + timestamp: expect.any(Number), + type: 'default', + category: 'console', + data: { arguments: ['Test log', '[HTMLElement: HTMLBodyElement]'], logger: 'console' }, + level: 'log', + message: 'Test log [object HTMLBodyElement]', + }, + ]); +}); + +sentryTest('should capture very large console logs', async ({ getLocalTestPath, page, forceFlushReplay }) => { + // console integration is not used in bundles/loader + const bundle = process.env.PW_BUNDLE || ''; + if (shouldSkipReplayTest() || bundle.startsWith('bundle_') || bundle.startsWith('loader_')) { + sentryTest.skip(); + } + + const reqPromise0 = waitForReplayRequest(page, 0); + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestPath({ testDir: __dirname }); + + await page.goto(url); + await reqPromise0; + + const reqPromise1 = waitForReplayRequest( + page, + (_event, res) => { + const { breadcrumbs } = getCustomRecordingEvents(res); + + return breadcrumbs.filter(breadcrumb => breadcrumb.category === 'console').length > 0; + }, + 5_000, + ); + + await page.click('[data-log-large]'); + + await forceFlushReplay(); + + const { breadcrumbs } = getCustomRecordingEvents(await reqPromise1); + + expect(breadcrumbs.filter(breadcrumb => breadcrumb.category === 'console')).toEqual([ + { + timestamp: expect.any(Number), + type: 'default', + category: 'console', + data: { + arguments: [ + expect.objectContaining({ + 'item-0': { + aa: expect.objectContaining({ + 'item-0': { + aa: expect.any(Object), + bb: expect.any(String), + cc: expect.any(String), + dd: expect.any(String), + }, + }), + bb: expect.any(String), + cc: expect.any(String), + dd: expect.any(String), + }, + }), + ], + logger: 'console', + }, + level: 'log', + message: '[object Object]', + }, + ]); +}); diff --git a/packages/browser-integration-tests/utils/replayHelpers.ts b/packages/browser-integration-tests/utils/replayHelpers.ts index bd7696ebd927..b1448dc97d85 100644 --- a/packages/browser-integration-tests/utils/replayHelpers.ts +++ b/packages/browser-integration-tests/utils/replayHelpers.ts @@ -49,38 +49,42 @@ export type RecordingSnapshot = FullRecordingSnapshot | IncrementalRecordingSnap export function waitForReplayRequest( page: Page, segmentIdOrCallback?: number | ((event: ReplayEvent, res: Response) => boolean), + timeout?: number, ): Promise { const segmentId = typeof segmentIdOrCallback === 'number' ? segmentIdOrCallback : undefined; const callback = typeof segmentIdOrCallback === 'function' ? segmentIdOrCallback : undefined; - return page.waitForResponse(res => { - const req = res.request(); + return page.waitForResponse( + res => { + const req = res.request(); - const postData = req.postData(); - if (!postData) { - return false; - } - - try { - const event = envelopeRequestParser(req); - - if (!isReplayEvent(event)) { + const postData = req.postData(); + if (!postData) { return false; } - if (callback) { - return callback(event, res); - } + try { + const event = envelopeRequestParser(req); - if (segmentId !== undefined) { - return event.segment_id === segmentId; - } + if (!isReplayEvent(event)) { + return false; + } - return true; - } catch { - return false; - } - }); + if (callback) { + return callback(event, res); + } + + if (segmentId !== undefined) { + return event.segment_id === segmentId; + } + + return true; + } catch { + return false; + } + }, + timeout ? { timeout } : undefined, + ); } export function isReplayEvent(event: Event): event is ReplayEvent {