From cfeb509ae59d121c0e989dd9cf674d4184cd5500 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Fri, 5 Apr 2024 10:33:02 -0400 Subject: [PATCH] test: Port breadcrumb tests from karma runner (#11436) I want to remove the karma/mocha based tests in the browser package. To accomplish this, I'll be porting 1 test suite a day from the old integration tests to playwright. Today is Day 2: `packages/browser/test/integration/suites/breadcrumbs.js` This adds console and history breadcrumb tests (which didn't exist before), and expands upon the dom and xhr/fetch tests, and cleans up some code here and there as well. ref https://github.com/getsentry/sentry-javascript/issues/11084 day 1: https://github.com/getsentry/sentry-javascript/pull/11412 --- .../Breadcrumbs/console/capture/subject.js | 10 + .../Breadcrumbs/console/capture/test.ts | 45 + .../integrations/Breadcrumbs/console/init.js | 10 + .../Breadcrumbs/dom/clickWithError/subject.js | 7 + .../dom/clickWithError/template.html | 10 + .../Breadcrumbs/dom/clickWithError/test.ts | 32 + .../Breadcrumbs/dom/customEvent/subject.js | 9 + .../Breadcrumbs/dom/customEvent/template.html | 12 + .../Breadcrumbs/dom/customEvent/test.ts | 19 + .../dom/multipleTypes/template.html | 10 + .../Breadcrumbs/dom/multipleTypes/test.ts | 50 ++ .../Breadcrumbs/fetch/get/subject.js | 2 - .../fetch/getWithRequestObj/subject.js | 3 + .../fetch/getWithRequestObj/test.ts | 37 + .../Breadcrumbs/fetch/post/subject.js | 2 - .../integrations/Breadcrumbs/history/init.js | 10 + .../Breadcrumbs/history/navigation/subject.js | 7 + .../Breadcrumbs/history/navigation/test.ts | 46 + .../test/integration/suites/breadcrumbs.js | 786 ------------------ .../browser/test/integration/suites/shell.js | 1 - 20 files changed, 317 insertions(+), 791 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/init.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/template.html create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/template.html create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/template.html create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/init.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/test.ts delete mode 100644 packages/browser/test/integration/suites/breadcrumbs.js diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/subject.js new file mode 100644 index 000000000000..d9ee50bf556f --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/subject.js @@ -0,0 +1,10 @@ +console.log('One'); +console.warn('Two', { a: 1 }); +console.error('Error 2', { b: { c: [] } }); + +// Passed assertions _should not_ be captured +console.assert(1 + 1 === 2, 'math works'); +// Failed assertions _should_ be captured +console.assert(1 + 1 === 3, 'math broke'); + +Sentry.captureException('test exception'); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/test.ts new file mode 100644 index 000000000000..de53e2cee485 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/capture/test.ts @@ -0,0 +1,45 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/browser'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +sentryTest('should capture console breadcrumbs', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.breadcrumbs).toEqual([ + { + category: 'console', + data: { arguments: ['One'], logger: 'console' }, + level: 'log', + message: 'One', + timestamp: expect.any(Number), + }, + { + category: 'console', + data: { arguments: ['Two', { a: 1 }], logger: 'console' }, + level: 'warning', + message: 'Two [object Object]', + timestamp: expect.any(Number), + }, + { + category: 'console', + data: { arguments: ['Error 2', { b: '[Object]' }], logger: 'console' }, + level: 'error', + message: 'Error 2 [object Object]', + timestamp: expect.any(Number), + }, + { + category: 'console', + data: { + arguments: ['math broke'], + logger: 'console', + }, + level: 'log', + message: 'Assertion failed: math broke', + timestamp: expect.any(Number), + }, + ]); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/init.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/init.js new file mode 100644 index 000000000000..36806d01c6d0 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/console/init.js @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + defaultIntegrations: false, + integrations: [Sentry.breadcrumbsIntegration()], + sampleRate: 1, +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/subject.js new file mode 100644 index 000000000000..9a0c89788ea7 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/subject.js @@ -0,0 +1,7 @@ +const click = new MouseEvent('click'); +function kaboom() { + throw new Error('lol'); +} +Object.defineProperty(click, 'target', { get: kaboom }); +const input = document.getElementById('input1'); +input.dispatchEvent(click); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/template.html b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/template.html new file mode 100644 index 000000000000..cba1da8d531d --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/template.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/test.ts new file mode 100644 index 000000000000..d965a4ac0d7d --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/clickWithError/test.ts @@ -0,0 +1,32 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/browser'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +// see: https://github.com/getsentry/sentry-javascript/issues/768 +sentryTest( + 'should record breadcrumb if accessing the target property of an event throws an exception', + async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const promise = getFirstSentryEnvelopeRequest(page); + + await page.locator('#input1').pressSequentially('test', { delay: 1 }); + + await page.evaluate('Sentry.captureException("test exception")'); + + const eventData = await promise; + + expect(eventData.breadcrumbs).toHaveLength(1); + expect(eventData.breadcrumbs).toEqual([ + { + category: 'ui.input', + message: 'body > input#input1[type="text"]', + timestamp: expect.any(Number), + }, + ]); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/subject.js new file mode 100644 index 000000000000..ca08cace4134 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/subject.js @@ -0,0 +1,9 @@ +const input = document.getElementsByTagName('input')[0]; +input.addEventListener('build', function (evt) { + evt.stopPropagation(); +}); + +const customEvent = new CustomEvent('build', { detail: 1 }); +input.dispatchEvent(customEvent); + +Sentry.captureException('test exception'); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/template.html b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/template.html new file mode 100644 index 000000000000..a16ca41e45da --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/template.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/test.ts new file mode 100644 index 000000000000..83cd53f8acba --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/customEvent/test.ts @@ -0,0 +1,19 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/types'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +sentryTest('breadcrumbs listener should not fail with custom event', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + let error = undefined; + page.on('pageerror', err => { + error = err; + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + expect(eventData.exception?.values).toHaveLength(1); + expect(eventData.breadcrumbs).toBeUndefined(); + expect(error).toBeUndefined(); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/template.html b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/template.html new file mode 100644 index 000000000000..cba1da8d531d --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/template.html @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/test.ts new file mode 100644 index 000000000000..53372fcacc97 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/dom/multipleTypes/test.ts @@ -0,0 +1,50 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/browser'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +sentryTest( + 'should correctly capture multiple consecutive breadcrumbs if they are of different type', + async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.goto(url); + + const promise = getFirstSentryEnvelopeRequest(page); + + // These inputs will be debounced + await page.locator('#input1').pressSequentially('abc', { delay: 1 }); + await page.locator('#input1').pressSequentially('def', { delay: 1 }); + await page.locator('#input1').pressSequentially('ghi', { delay: 1 }); + + await page.locator('#input1').click(); + await page.locator('#input1').click(); + await page.locator('#input1').click(); + + // This input should not be debounced + await page.locator('#input1').pressSequentially('jkl', { delay: 1 }); + + await page.evaluate('Sentry.captureException("test exception")'); + + const eventData = await promise; + + expect(eventData.breadcrumbs).toEqual([ + { + category: 'ui.input', + message: 'body > input#input1[type="text"]', + timestamp: expect.any(Number), + }, + { + category: 'ui.click', + message: 'body > input#input1[type="text"]', + timestamp: expect.any(Number), + }, + { + category: 'ui.input', + message: 'body > input#input1[type="text"]', + timestamp: expect.any(Number), + }, + ]); + }, +); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/subject.js index fc9ffd720768..f6e1e21e4611 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/subject.js +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/get/subject.js @@ -1,5 +1,3 @@ -const xhr = new XMLHttpRequest(); - fetch('http://localhost:7654/foo').then(() => { Sentry.captureException('test error'); }); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/subject.js new file mode 100644 index 000000000000..0ca20f1b5acb --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/subject.js @@ -0,0 +1,3 @@ +fetch(new Request('http://localhost:7654/foo')).then(() => { + Sentry.captureException('test error'); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts new file mode 100644 index 000000000000..3ffa68776fd2 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/getWithRequestObj/test.ts @@ -0,0 +1,37 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/types'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +sentryTest('captures Breadcrumb for basic GET request that uses request object', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route('**/foo', route => { + return route.fulfill({ + status: 200, + body: JSON.stringify({ + userNames: ['John', 'Jane'], + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + + expect(eventData?.breadcrumbs?.length).toBe(1); + expect(eventData!.breadcrumbs![0]).toEqual({ + timestamp: expect.any(Number), + category: 'fetch', + type: 'http', + data: { + method: 'GET', + status_code: 200, + url: 'http://localhost:7654/foo', + }, + }); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/subject.js index 595e9395aa80..ea1bf44bc905 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/subject.js +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/fetch/post/subject.js @@ -1,5 +1,3 @@ -const xhr = new XMLHttpRequest(); - fetch('http://localhost:7654/foo', { method: 'POST', body: '{"my":"body"}', diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/init.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/init.js new file mode 100644 index 000000000000..36806d01c6d0 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/init.js @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + defaultIntegrations: false, + integrations: [Sentry.breadcrumbsIntegration()], + sampleRate: 1, +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/subject.js b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/subject.js new file mode 100644 index 000000000000..dd1d47ef4dff --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/subject.js @@ -0,0 +1,7 @@ +history.pushState({}, '', '/foo'); +history.pushState({}, '', '/bar?a=1#fragment'); +history.pushState({}, '', {}); +history.pushState({}, '', null); +history.replaceState({}, '', '/bar?a=1#fragment'); + +Sentry.captureException('test exception'); diff --git a/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/test.ts b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/test.ts new file mode 100644 index 000000000000..91bd6faaf083 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/Breadcrumbs/history/navigation/test.ts @@ -0,0 +1,46 @@ +import { expect } from '@playwright/test'; +import type { Event } from '@sentry/browser'; + +import { sentryTest } from '../../../../../utils/fixtures'; +import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; + +sentryTest('should record history changes as navigation breadcrumbs', async ({ getLocalTestUrl, page }) => { + const url = await getLocalTestUrl({ testDir: __dirname }); + + const eventData = await getFirstSentryEnvelopeRequest(page, url); + + expect(eventData.breadcrumbs).toEqual([ + { + category: 'navigation', + data: { + from: '/index.html', + to: '/foo', + }, + timestamp: expect.any(Number), + }, + { + category: 'navigation', + data: { + from: '/foo', + to: '/bar?a=1#fragment', + }, + timestamp: expect.any(Number), + }, + { + category: 'navigation', + data: { + from: '/bar?a=1#fragment', + to: '[object Object]', + }, + timestamp: expect.any(Number), + }, + { + category: 'navigation', + data: { + from: '[object Object]', + to: '/bar?a=1#fragment', + }, + timestamp: expect.any(Number), + }, + ]); +}); diff --git a/packages/browser/test/integration/suites/breadcrumbs.js b/packages/browser/test/integration/suites/breadcrumbs.js deleted file mode 100644 index f0a0395bbe3f..000000000000 --- a/packages/browser/test/integration/suites/breadcrumbs.js +++ /dev/null @@ -1,786 +0,0 @@ -describe('breadcrumbs', function () { - it(optional('should record an XMLHttpRequest with a handler', IS_LOADER), function () { - return runInSandbox(sandbox, { manual: true }, function () { - var xhr = new XMLHttpRequest(); - xhr.open('GET', '/base/subjects/example.json'); - xhr.onreadystatechange = function () {}; - xhr.send(); - waitForXHR(xhr, function () { - Sentry.captureMessage('test'); - window.finalizeManualTest(); - }); - }).then(function (summary) { - // The async loader doesn't wrap XHR - if (IS_LOADER) { - return; - } - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'xhr'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - }); - }); - - it(optional('should record an XMLHttpRequest with a handler attached after send was called', IS_LOADER), function () { - return runInSandbox(sandbox, { manual: true }, function () { - var xhr = new XMLHttpRequest(); - xhr.open('GET', '/base/subjects/example.json'); - xhr.send(); - xhr.onreadystatechange = function () { - window.handlerCalled = true; - }; - waitForXHR(xhr, function () { - Sentry.captureMessage('test'); - window.finalizeManualTest(); - }); - }).then(function (summary) { - // The async loader doesn't wrap XHR - if (IS_LOADER) { - return; - } - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'xhr'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - assert.typeOf(summary.breadcrumbs[0].timestamp, 'number'); - assert.isTrue(summary.window.handlerCalled); - delete summary.window.handlerCalled; - }); - }); - - it(optional('should record an XMLHttpRequest without any handlers set', IS_LOADER), function () { - return runInSandbox(sandbox, { manual: true }, function () { - var xhr = new XMLHttpRequest(); - xhr.open('get', '/base/subjects/example.json'); - xhr.send(); - waitForXHR(xhr, function () { - Sentry.captureMessage('test'); - window.finalizeManualTest(); - }); - }).then(function (summary) { - // The async loader doesn't wrap XHR - if (IS_LOADER) { - return; - } - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'xhr'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - assert.isUndefined(summary.breadcrumbs[0].data.input); - // To make sure that we are not providing this key for non-post requests - assert.equal(summary.breadcrumbHints[0].input, undefined); - }); - }); - - it(optional('should give access to request body for XMLHttpRequest POST requests', IS_LOADER), function () { - return runInSandbox(sandbox, { manual: true }, function () { - var xhr = new XMLHttpRequest(); - xhr.open('POST', '/base/subjects/example.json'); - xhr.send('{"foo":"bar"}'); - waitForXHR(xhr, function () { - Sentry.captureMessage('test'); - window.finalizeManualTest(); - }); - }).then(function (summary) { - // The async loader doesn't wrap XHR - if (IS_LOADER) { - return; - } - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'xhr'); - assert.equal(summary.breadcrumbs[0].data.method, 'POST'); - assert.isUndefined(summary.breadcrumbs[0].data.input); - assert.equal(summary.breadcrumbHints[0].input, '{"foo":"bar"}'); - }); - }); - - it('should record a fetch request', function () { - return runInSandbox(sandbox, { manual: true }, function () { - fetch('/base/subjects/example.json', { - method: 'Get', - }) - .then( - function () { - Sentry.captureMessage('test'); - }, - function () { - Sentry.captureMessage('test'); - }, - ) - .then(function () { - window.finalizeManualTest(); - }) - .catch(function () { - window.finalizeManualTest(); - }); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap fetch, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - if (summary.window.supportsNativeFetch()) { - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'fetch'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - assert.equal(summary.breadcrumbs[0].data.url, '/base/subjects/example.json'); - } else { - // otherwise we use a fetch polyfill based on xhr - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'xhr'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - assert.equal(summary.breadcrumbs[0].data.url, '/base/subjects/example.json'); - } - } - }); - }); - - it('should record a fetch request with Request obj instead of URL string', function () { - return runInSandbox(sandbox, { manual: true }, function () { - fetch(new Request('/base/subjects/example.json')) - .then( - function () { - Sentry.captureMessage('test'); - }, - function () { - Sentry.captureMessage('test'); - }, - ) - .then(function () { - window.finalizeManualTest(); - }) - .catch(function () { - window.finalizeManualTest(); - }); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap fetch, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - if (summary.window.supportsNativeFetch()) { - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'fetch'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - // Request constructor normalizes the url - assert.ok(summary.breadcrumbs[0].data.url.indexOf('/base/subjects/example.json') !== -1); - } else { - // otherwise we use a fetch polyfill based on xhr - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'xhr'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - assert.ok(summary.breadcrumbs[0].data.url.indexOf('/base/subjects/example.json') !== -1); - } - } - }); - }); - - it('should record a fetch request with an arbitrary type argument', function () { - return runInSandbox(sandbox, { manual: true }, function () { - fetch(123) - .then( - function () { - Sentry.captureMessage('test'); - }, - function () { - Sentry.captureMessage('test'); - }, - ) - .then(function () { - window.finalizeManualTest(); - }) - .catch(function () { - window.finalizeManualTest(); - }); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap fetch, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - if (summary.window.supportsNativeFetch()) { - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'fetch'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - assert.ok(summary.breadcrumbs[0].data.url.indexOf('123') !== -1); - } else { - // otherwise we use a fetch polyfill based on xhr - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].type, 'http'); - assert.equal(summary.breadcrumbs[0].category, 'xhr'); - assert.equal(summary.breadcrumbs[0].data.method, 'GET'); - assert.ok(summary.breadcrumbs[0].data.url.indexOf('123') !== -1); - } - } - }); - }); - - it('should provide a hint for dom events that includes event name and event itself', function () { - return runInSandbox(sandbox, function () { - var input = document.getElementsByTagName('input')[0]; - var clickHandler = function () {}; - input.addEventListener('click', clickHandler); - var click = new MouseEvent('click'); - input.dispatchEvent(click); - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbHints.length, 1); - assert.equal(summary.breadcrumbHints[0].name, 'click'); - assert.equal(summary.breadcrumbHints[0].event.target.tagName, 'INPUT'); - } - }); - }); - - it('should not fail with click or keypress handler with no callback', function () { - return runInSandbox(sandbox, function () { - var input = document.getElementsByTagName('input')[0]; - input.addEventListener('click', undefined); - input.addEventListener('keypress', undefined); - - var click = new MouseEvent('click'); - input.dispatchEvent(click); - - var keypress = new KeyboardEvent('keypress'); - input.dispatchEvent(keypress); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 2); - - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - - assert.equal(summary.breadcrumbs[1].category, 'ui.input'); - assert.equal(summary.breadcrumbs[1].message, 'body > form#foo-form > input[name="foo"]'); - } - }); - }); - - it('should not fail with custom event', function () { - return runInSandbox(sandbox, function () { - var input = document.getElementsByTagName('input')[0]; - input.addEventListener('build', function (evt) { - evt.stopPropagation(); - }); - - var customEvent = new CustomEvent('build', { detail: 1 }); - input.dispatchEvent(customEvent); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 0); - } - }); - }); - - it('should not fail with custom event and handler with no callback', function () { - return runInSandbox(sandbox, function () { - var input = document.getElementsByTagName('input')[0]; - input.addEventListener('build', undefined); - - var customEvent = new CustomEvent('build', { detail: 1 }); - input.dispatchEvent(customEvent); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 0); - } - }); - }); - - it('should record a mouse click on element WITH click handler present', function () { - return runInSandbox(sandbox, function () { - // add an event listener to the input. we want to make sure that - // our breadcrumbs still work even if the page has an event listener - // on an element that cancels event bubbling - var input = document.getElementsByTagName('input')[0]; - var clickHandler = function (evt) { - evt.stopPropagation(); // don't bubble - }; - input.addEventListener('click', clickHandler); - - // click - var click = new MouseEvent('click'); - input.dispatchEvent(click); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - } - }); - }); - - it('should record a mouse click on element WITHOUT click handler present', function () { - return runInSandbox(sandbox, function () { - // click - var click = new MouseEvent('click'); - var input = document.getElementsByTagName('input')[0]; - input.dispatchEvent(click); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - } - }); - }); - - it('should only record a SINGLE mouse click for a tree of elements with event listeners', function () { - return runInSandbox(sandbox, function () { - var clickHandler = function () {}; - - // mousemove event shouldnt clobber subsequent "breadcrumbed" events (see #724) - document.querySelector('.a').addEventListener('mousemove', clickHandler); - - document.querySelector('.a').addEventListener('click', clickHandler); - document.querySelector('.b').addEventListener('click', clickHandler); - document.querySelector('.c').addEventListener('click', clickHandler); - - // click - var click = new MouseEvent('click'); - var input = document.querySelector('.a'); // leaf node - input.dispatchEvent(click); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > div.c > div.b > div.a'); - } - }); - }); - - it('should bail out if accessing the `target` property of an event throws an exception', function () { - // see: https://github.com/getsentry/sentry-javascript/issues/768 - return runInSandbox(sandbox, function () { - // click - var click = new MouseEvent('click'); - function kaboom() { - throw new Error('lol'); - } - Object.defineProperty(click, 'target', { get: kaboom }); - - var input = document.querySelector('.a'); // leaf node - - Sentry.captureMessage('test'); - input.dispatchEvent(click); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, ''); - } - }); - }); - - it('should record consecutive keypress events into a single "input" breadcrumb', function () { - return runInSandbox(sandbox, function () { - // keypress twice - var keypress1 = new KeyboardEvent('keypress'); - var keypress2 = new KeyboardEvent('keypress'); - - var input = document.getElementsByTagName('input')[0]; - input.dispatchEvent(keypress1); - input.dispatchEvent(keypress2); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - - assert.equal(summary.breadcrumbs[0].category, 'ui.input'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - } - }); - }); - - it('should correctly capture multiple consecutive breadcrumbs if they are of different type', function () { - return runInSandbox(sandbox, function () { - var input = document.getElementsByTagName('input')[0]; - - var clickHandler = function () {}; - input.addEventListener('click', clickHandler); - var keypressHandler = function () {}; - input.addEventListener('keypress', keypressHandler); - - input.dispatchEvent(new MouseEvent('click')); - input.dispatchEvent(new KeyboardEvent('keypress')); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - // Breadcrumb should be captured by the global event listeners, not a specific one - assert.equal(summary.breadcrumbs.length, 2); - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - assert.equal(summary.breadcrumbs[1].category, 'ui.input'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - assert.equal(summary.breadcrumbHints[0].global, false); - assert.equal(summary.breadcrumbHints[1].global, false); - } - }); - }); - - it('should debounce multiple consecutive identical breadcrumbs but allow for switching to a different type', function () { - return runInSandbox(sandbox, function () { - var input = document.getElementsByTagName('input')[0]; - - var clickHandler = function () {}; - input.addEventListener('click', clickHandler); - var keypressHandler = function () {}; - input.addEventListener('keypress', keypressHandler); - - input.dispatchEvent(new MouseEvent('click')); - input.dispatchEvent(new MouseEvent('click')); - input.dispatchEvent(new MouseEvent('click')); - input.dispatchEvent(new KeyboardEvent('keypress')); - input.dispatchEvent(new KeyboardEvent('keypress')); - input.dispatchEvent(new KeyboardEvent('keypress')); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - // Breadcrumb should be captured by the global event listeners, not a specific one - assert.equal(summary.breadcrumbs.length, 2); - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - assert.equal(summary.breadcrumbs[1].category, 'ui.input'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - assert.equal(summary.breadcrumbHints[0].global, false); - assert.equal(summary.breadcrumbHints[1].global, false); - } - }); - }); - - it('should debounce multiple consecutive identical breadcrumbs but allow for switching to a different target', function () { - return runInSandbox(sandbox, function () { - var input = document.querySelector('#foo-form input'); - var div = document.querySelector('#foo-form div'); - - var clickHandler = function () {}; - input.addEventListener('click', clickHandler); - div.addEventListener('click', clickHandler); - - input.dispatchEvent(new MouseEvent('click')); - div.dispatchEvent(new MouseEvent('click')); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - // Breadcrumb should be captured by the global event listeners, not a specific one - assert.equal(summary.breadcrumbs.length, 2); - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - assert.equal(summary.breadcrumbs[1].category, 'ui.click'); - assert.equal(summary.breadcrumbs[1].message, 'body > form#foo-form > div.contenteditable'); - assert.equal(summary.breadcrumbHints[0].global, false); - assert.equal(summary.breadcrumbHints[1].global, false); - } - }); - }); - - it(optional('should flush keypress breadcrumbs when an error is thrown', IS_LOADER), function () { - return runInSandbox(sandbox, function () { - // keypress - var keypress = new KeyboardEvent('keypress'); - var input = document.getElementsByTagName('input')[0]; - input.dispatchEvent(keypress); - foo(); // throw exception - }).then(function (summary) { - if (IS_LOADER) { - return; - } - // TODO: don't really understand what's going on here - // Why do we not catch an error here - - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].category, 'ui.input'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - }); - }); - - it('should flush keypress breadcrumb when input event occurs immediately after', function () { - return runInSandbox(sandbox, function () { - // 1st keypress - var keypress1 = new KeyboardEvent('keypress'); - // click - var click = new MouseEvent('click'); - // 2nd keypress - var keypress2 = new KeyboardEvent('keypress'); - - var input = document.getElementsByTagName('input')[0]; - input.dispatchEvent(keypress1); - input.dispatchEvent(click); - input.dispatchEvent(keypress2); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 3); - - assert.equal(summary.breadcrumbs[0].category, 'ui.input'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - - assert.equal(summary.breadcrumbs[1].category, 'ui.click'); - assert.equal(summary.breadcrumbs[1].message, 'body > form#foo-form > input[name="foo"]'); - - assert.equal(summary.breadcrumbs[2].category, 'ui.input'); - assert.equal(summary.breadcrumbs[2].message, 'body > form#foo-form > input[name="foo"]'); - } - }); - }); - - it('should record consecutive keypress events in a contenteditable into a single "input" breadcrumb', function () { - return runInSandbox(sandbox, function () { - // keypress twice - var keypress1 = new KeyboardEvent('keypress'); - var keypress2 = new KeyboardEvent('keypress'); - - var div = document.querySelector('[contenteditable]'); - div.dispatchEvent(keypress1); - div.dispatchEvent(keypress2); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - - assert.equal(summary.breadcrumbs[0].category, 'ui.input'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > div.contenteditable'); - } - }); - }); - - it('should record click events that were handled using an object with handleEvent property and call original callback', function () { - return runInSandbox(sandbox, function () { - window.handleEventCalled = false; - - var input = document.getElementsByTagName('input')[0]; - input.addEventListener('click', { - handleEvent: function () { - window.handleEventCalled = true; - }, - }); - input.dispatchEvent(new MouseEvent('click')); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].category, 'ui.click'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - - assert.equal(summary.window.handleEventCalled, true); - } - }); - }); - - it('should record keypress events that were handled using an object with handleEvent property and call original callback', function () { - return runInSandbox(sandbox, function () { - window.handleEventCalled = false; - - var input = document.getElementsByTagName('input')[0]; - input.addEventListener('keypress', { - handleEvent: function () { - window.handleEventCalled = true; - }, - }); - input.dispatchEvent(new KeyboardEvent('keypress')); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - assert.equal(summary.breadcrumbs.length, 1); - assert.equal(summary.breadcrumbs[0].category, 'ui.input'); - assert.equal(summary.breadcrumbs[0].message, 'body > form#foo-form > input[name="foo"]'); - - assert.equal(summary.window.handleEventCalled, true); - } - }); - }); - - it('should remove breadcrumb instrumentation when all event listeners are detached', function () { - return runInSandbox(sandbox, function () { - var input = document.getElementsByTagName('input')[0]; - - var clickHandler = function () {}; - var otherClickHandler = function () {}; - input.addEventListener('click', clickHandler); - input.addEventListener('click', otherClickHandler); - input.removeEventListener('click', clickHandler); - input.removeEventListener('click', otherClickHandler); - - var keypressHandler = function () {}; - var otherKeypressHandler = function () {}; - input.addEventListener('keypress', keypressHandler); - input.addEventListener('keypress', otherKeypressHandler); - input.removeEventListener('keypress', keypressHandler); - input.removeEventListener('keypress', otherKeypressHandler); - - input.dispatchEvent(new MouseEvent('click')); - input.dispatchEvent(new KeyboardEvent('keypress')); - - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap event listeners, but we should receive the event without breadcrumbs - assert.lengthOf(summary.events, 1); - } else { - // Breadcrumb should be captured by the global event listeners, not a specific one - assert.equal(summary.breadcrumbs.length, 2); - assert.equal(summary.breadcrumbHints[0].global, true); - assert.equal(summary.breadcrumbHints[1].global, true); - } - }); - }); - - it( - optional('should record history.[pushState|replaceState] changes as navigation breadcrumbs', IS_LOADER), - function () { - return runInSandbox(sandbox, function () { - history.pushState({}, '', '/foo'); - history.pushState({}, '', '/bar?a=1#fragment'); - history.pushState({}, '', {}); // pushState calls toString on non-string args - history.pushState({}, '', null); // does nothing / no-op - // can't call history.back() because it will change url of parent document - // (e.g. document running mocha) ... instead just "emulate" a back button - // press by calling replaceState - history.replaceState({}, '', '/bar?a=1#fragment'); - Sentry.captureMessage('test'); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't wrap history - return; - } - assert.equal(summary.breadcrumbs.length, 4); - assert.equal(summary.breadcrumbs[0].category, 'navigation'); // (start) => foo - assert.equal(summary.breadcrumbs[1].category, 'navigation'); // foo => bar?a=1#fragment - assert.equal(summary.breadcrumbs[2].category, 'navigation'); // bar?a=1#fragment => [object%20Object] - assert.equal(summary.breadcrumbs[3].category, 'navigation'); // [object%20Object] => bar?a=1#fragment (back button) - - assert.ok(/\/base\/variants\/.*\.html$/.test(summary.breadcrumbs[0].data.from), "'from' url is incorrect"); - assert.ok(/\/foo$/.test(summary.breadcrumbs[0].data.to), "'to' url is incorrect"); - - assert.ok(/\/foo$/.test(summary.breadcrumbs[1].data.from), "'from' url is incorrect"); - assert.ok(/\/bar\?a=1#fragment$/.test(summary.breadcrumbs[1].data.to), "'to' url is incorrect"); - - assert.ok(/\/bar\?a=1#fragment$/.test(summary.breadcrumbs[2].data.from), "'from' url is incorrect"); - assert.ok(/\[object Object\]$/.test(summary.breadcrumbs[2].data.to), "'to' url is incorrect"); - - assert.ok(/\[object Object\]$/.test(summary.breadcrumbs[3].data.from), "'from' url is incorrect"); - assert.ok(/\/bar\?a=1#fragment/.test(summary.breadcrumbs[3].data.to), "'to' url is incorrect"); - }); - }, - ); - - it(optional('should preserve native code detection compatibility', IS_LOADER), function () { - return runInSandbox(sandbox, { manual: true }, function () { - window.resolveTest(); - }).then(function () { - if (IS_LOADER) { - // The async loader doesn't wrap anything - return; - } - assert.include(Function.prototype.toString.call(window.setTimeout), '[native code]'); - assert.include(Function.prototype.toString.call(window.setInterval), '[native code]'); - assert.include(Function.prototype.toString.call(window.addEventListener), '[native code]'); - assert.include(Function.prototype.toString.call(window.removeEventListener), '[native code]'); - assert.include(Function.prototype.toString.call(window.requestAnimationFrame), '[native code]'); - if ('fetch' in window) { - assert.include(Function.prototype.toString.call(window.fetch), '[native code]'); - } - }); - }); - - it('should capture console breadcrumbs', function () { - return runInSandbox(sandbox, { manual: true }, function () { - window.allowConsoleBreadcrumbs = true; - var logs = document.createElement('script'); - logs.src = '/base/subjects/console-logs.js'; - logs.onload = function () { - window.finalizeManualTest(); - }; - document.head.appendChild(logs); - }).then(function (summary) { - if (IS_LOADER) { - // The async loader doesn't capture breadcrumbs, but we should receive the event without them - assert.lengthOf(summary.events, 1); - } else { - if ('assert' in console) { - assert.lengthOf(summary.breadcrumbs, 4); - assert.deepEqual(summary.breadcrumbs[3].data.arguments, ['math broke']); - } else { - assert.lengthOf(summary.breadcrumbs, 3); - } - - assert.deepEqual(summary.breadcrumbs[0].data.arguments, ['One']); - assert.deepEqual(summary.breadcrumbs[1].data.arguments, ['Two', { a: 1 }]); - assert.deepEqual(summary.breadcrumbs[2].data.arguments, ['Error 2', { b: { c: [] } }]); - } - }); - }); -}); diff --git a/packages/browser/test/integration/suites/shell.js b/packages/browser/test/integration/suites/shell.js index 2a3ef36b5df5..e1555623b495 100644 --- a/packages/browser/test/integration/suites/shell.js +++ b/packages/browser/test/integration/suites/shell.js @@ -26,7 +26,6 @@ function runVariant(variant) { {{ suites/onerror.js }} // biome-ignore format: No trailing commas {{ suites/onunhandledrejection.js }} // biome-ignore format: No trailing commas {{ suites/builtins.js }} // biome-ignore format: No trailing commas - {{ suites/breadcrumbs.js }} // biome-ignore format: No trailing commas {{ suites/loader.js }} // biome-ignore format: No trailing commas }); }