diff --git a/dev-packages/browser-integration-tests/README.md b/dev-packages/browser-integration-tests/README.md index b24bdfb86ee3..0d943e8de5f0 100644 --- a/dev-packages/browser-integration-tests/README.md +++ b/dev-packages/browser-integration-tests/README.md @@ -14,7 +14,7 @@ or `init.js` is not defined in a case folder. `subject.js` contains the logic that sets up the environment to be tested. It also can be defined locally and as a group fallback. Unlike `template.hbs` and `init.js`, it's not required to be defined for a group, as there may be cases that -does not require a subject, instead the logic is injected using `injectScriptAndGetEvents` from `utils/helpers.ts`. +does not require a subject. `test.ts` is required for each test case, which contains the assertions (and if required the script injection logic). For every case, any set of `init.js`, `template.hbs` and `subject.js` can be defined locally, and each one of them will @@ -22,8 +22,8 @@ have precedence over the default definitions of the test group. To test page multi-page navigations, you can specify additional `page-*.html` (e.g. `page-0.html`, `page-1.html`) files. These will also be compiled and initialized with the same `init.js` and `subject.js` files that are applied to -`template.hbs/html`. Note: `page-*.html` file lookup **doesn not** fall back to the parent directories, meaning that -page files have to be directly in the `test.ts` directory. +`template.hbs/html`. Note: `page-*.html` file lookup **does not** fall back to the parent directories, meaning that page +files have to be directly in the `test.ts` directory. ``` suites/ diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/non-string-arg/subject.js b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/non-string-arg/subject.js deleted file mode 100644 index ad794db023df..000000000000 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/non-string-arg/subject.js +++ /dev/null @@ -1,8 +0,0 @@ -function run() { - window.onerror({ - type: 'error', - otherKey: 'hi', - }); -} - -run(); diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/non-string-arg/test.ts b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/non-string-arg/test.ts index ed2399a43790..9013c744333d 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/non-string-arg/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/non-string-arg/test.ts @@ -2,14 +2,25 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; +import { getFirstSentryEnvelopeRequest, runScriptInSandbox } from '../../../../../utils/helpers'; sentryTest( 'should catch onerror calls with non-string first argument gracefully', async ({ getLocalTestPath, page }) => { const url = await getLocalTestPath({ testDir: __dirname }); - const eventData = await getFirstSentryEnvelopeRequest(page, url); + await page.goto(url); + + runScriptInSandbox(page, { + content: ` + throw { + type: 'Error', + otherKey: 'otherValue', + }; + `, + }); + + const eventData = await getFirstSentryEnvelopeRequest(page); expect(eventData.exception?.values).toHaveLength(1); expect(eventData.exception?.values?.[0]).toMatchObject({ diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/rethrown/subject.js b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/rethrown/subject.js deleted file mode 100644 index 44a6e2d739c5..000000000000 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/rethrown/subject.js +++ /dev/null @@ -1,17 +0,0 @@ -function run() { - try { - try { - foo(); - } catch (e) { - Sentry.captureException(e); - throw e; // intentionally re-throw - } - } catch (e) { - // simulate window.onerror without generating a Script error - window.onerror('error', 'file.js', 1, 1, e); - } -} - -run(); - -Sentry.captureException(new Error('error 2')); diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/rethrown/test.ts b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/rethrown/test.ts index 9c6209d6ea61..d81e954c55ec 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/rethrown/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/rethrown/test.ts @@ -2,14 +2,27 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../../utils/fixtures'; -import { getMultipleSentryEnvelopeRequests } from '../../../../../utils/helpers'; +import { getMultipleSentryEnvelopeRequests, runScriptInSandbox } from '../../../../../utils/helpers'; sentryTest( 'should NOT catch an exception already caught [but rethrown] via Sentry.captureException', async ({ getLocalTestPath, page }) => { const url = await getLocalTestPath({ testDir: __dirname }); - const events = await getMultipleSentryEnvelopeRequests(page, 2, { url }); + await page.goto(url); + + runScriptInSandbox(page, { + content: ` + try { + foo(); + } catch (e) { + Sentry.captureException(e); + throw e; + } + `, + }); + + const events = await getMultipleSentryEnvelopeRequests(page, 1); expect(events[0].exception?.values).toHaveLength(1); expect(events[0].exception?.values?.[0]).toMatchObject({ @@ -24,19 +37,5 @@ sentryTest( frames: expect.any(Array), }, }); - - // This is not a refernece error, but another generic error - expect(events[1].exception?.values).toHaveLength(1); - expect(events[1].exception?.values?.[0]).toMatchObject({ - type: 'Error', - value: 'error 2', - mechanism: { - type: 'generic', - handled: true, - }, - stacktrace: { - frames: expect.any(Array), - }, - }); }, ); diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/syntax-errors/subject.js b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/syntax-errors/subject.js deleted file mode 100644 index ece68fe4890e..000000000000 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/syntax-errors/subject.js +++ /dev/null @@ -1,10 +0,0 @@ -function run() { - try { - eval('foo{};'); - } catch (e) { - // simulate window.onerror without generating a Script error - window.onerror('error', 'file.js', 1, 1, e); - } -} - -run(); diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/syntax-errors/test.ts b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/syntax-errors/test.ts index 4d55130e7190..d163e4071c8e 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/syntax-errors/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/syntax-errors/test.ts @@ -2,12 +2,20 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; +import { getFirstSentryEnvelopeRequest, runScriptInSandbox } from '../../../../../utils/helpers'; sentryTest('should catch syntax errors', async ({ getLocalTestPath, page }) => { const url = await getLocalTestPath({ testDir: __dirname }); - const eventData = await getFirstSentryEnvelopeRequest(page, url); + await page.goto(url); + + runScriptInSandbox(page, { + content: ` + foo{}; // SyntaxError + `, + }); + + const eventData = await getFirstSentryEnvelopeRequest(page); expect(eventData.exception?.values).toHaveLength(1); expect(eventData.exception?.values?.[0]).toMatchObject({ diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-errors/subject.js b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-errors/subject.js deleted file mode 100644 index 03dd4333efc5..000000000000 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-errors/subject.js +++ /dev/null @@ -1,10 +0,0 @@ -function run() { - try { - throw new Error('realError'); - } catch (e) { - // simulate window.onerror without generating a Script error - window.onerror('error', 'file.js', 1, 1, e); - } -} - -run(); diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-errors/test.ts b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-errors/test.ts index d9b574fadfc5..2a1f9638b4a3 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-errors/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-errors/test.ts @@ -2,12 +2,20 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; +import { getFirstSentryEnvelopeRequest, runScriptInSandbox } from '../../../../../utils/helpers'; sentryTest('should catch thrown errors', async ({ getLocalTestPath, page }) => { const url = await getLocalTestPath({ testDir: __dirname }); - const eventData = await getFirstSentryEnvelopeRequest(page, url); + await page.goto(url); + + runScriptInSandbox(page, { + content: ` + throw new Error('realError'); + `, + }); + + const eventData = await getFirstSentryEnvelopeRequest(page); expect(eventData.exception?.values).toHaveLength(1); expect(eventData.exception?.values?.[0]).toMatchObject({ diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-objects/subject.js b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-objects/subject.js deleted file mode 100644 index 1fb30ff3e221..000000000000 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-objects/subject.js +++ /dev/null @@ -1,10 +0,0 @@ -function run() { - try { - throw { error: 'stuff is broken', somekey: 'ok' }; - } catch (e) { - // simulate window.onerror without generating a Script error - window.onerror('error', 'file.js', 1, 1, e); - } -} - -run(); diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-objects/test.ts b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-objects/test.ts index 326d7daa41fc..86d409f850fd 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-objects/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-objects/test.ts @@ -2,12 +2,22 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; +import { getFirstSentryEnvelopeRequest, runScriptInSandbox } from '../../../../../utils/helpers'; sentryTest('should catch thrown objects', async ({ getLocalTestPath, page }) => { const url = await getLocalTestPath({ testDir: __dirname }); - const eventData = await getFirstSentryEnvelopeRequest(page, url); + await page.goto(url); + + runScriptInSandbox(page, { + content: ` + throw { + error: 'stuff is broken', + somekey: 'ok' + };`, + }); + + const eventData = await getFirstSentryEnvelopeRequest(page); expect(eventData.exception?.values).toHaveLength(1); expect(eventData.exception?.values?.[0]).toMatchObject({ diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-strings/subject.js b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-strings/subject.js deleted file mode 100644 index 9704f713714f..000000000000 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-strings/subject.js +++ /dev/null @@ -1,10 +0,0 @@ -function run() { - try { - throw 'stringError'; - } catch (e) { - // simulate window.onerror without generating a Script error - window.onerror('error', 'file.js', 1, 1, e); - } -} - -run(); diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-strings/test.ts b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-strings/test.ts index a52d70f30095..7e557e2046d0 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-strings/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/onError/thrown-strings/test.ts @@ -2,12 +2,20 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../../utils/fixtures'; -import { getFirstSentryEnvelopeRequest } from '../../../../../utils/helpers'; +import { getFirstSentryEnvelopeRequest, runScriptInSandbox } from '../../../../../utils/helpers'; sentryTest('should catch thrown strings', async ({ getLocalTestPath, page }) => { const url = await getLocalTestPath({ testDir: __dirname }); - const eventData = await getFirstSentryEnvelopeRequest(page, url); + await page.goto(url); + + runScriptInSandbox(page, { + content: ` + throw 'stringError'; + `, + }); + + const eventData = await getFirstSentryEnvelopeRequest(page); expect(eventData.exception?.values).toHaveLength(1); expect(eventData.exception?.values?.[0]).toMatchObject({ diff --git a/dev-packages/browser-integration-tests/suites/public-api/startSpan/error-sync/subject.js b/dev-packages/browser-integration-tests/suites/public-api/startSpan/error-sync/subject.js deleted file mode 100644 index 55d9bf76d224..000000000000 --- a/dev-packages/browser-integration-tests/suites/public-api/startSpan/error-sync/subject.js +++ /dev/null @@ -1,9 +0,0 @@ -function run() { - Sentry.startSpan({ name: 'parent_span' }, () => { - throw new Error('Sync Error'); - }); -} - -// using `setTimeout` here because otherwise the thrown error will be -// thrown as a generic "Script Error." instead of the actual error". -setTimeout(run); diff --git a/dev-packages/browser-integration-tests/suites/public-api/startSpan/error-sync/test.ts b/dev-packages/browser-integration-tests/suites/public-api/startSpan/error-sync/test.ts index 2c1d92ebbe00..5bf693f9d543 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/startSpan/error-sync/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/startSpan/error-sync/test.ts @@ -2,7 +2,11 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../utils/fixtures'; -import { getMultipleSentryEnvelopeRequests, shouldSkipTracingTest } from '../../../../utils/helpers'; +import { + getMultipleSentryEnvelopeRequests, + runScriptInSandbox, + shouldSkipTracingTest, +} from '../../../../utils/helpers'; sentryTest('should capture an error within a sync startSpan callback', async ({ getLocalTestPath, page }) => { if (shouldSkipTracingTest()) { @@ -10,10 +14,22 @@ sentryTest('should capture an error within a sync startSpan callback', async ({ } const url = await getLocalTestPath({ testDir: __dirname }); - const gotoPromise = page.goto(url); - const envelopePromise = getMultipleSentryEnvelopeRequests(page, 2); + await page.goto(url); + + runScriptInSandbox(page, { + content: ` + function run() { + Sentry.startSpan({ name: 'parent_span' }, () => { + throw new Error('Sync Error'); + }); + } + + setTimeout(run); + `, + }); + + const events = await getMultipleSentryEnvelopeRequests(page, 2); - const [, events] = await Promise.all([gotoPromise, envelopePromise]); const txn = events.find(event => event.type === 'transaction'); const err = events.find(event => !event.type); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/error/subject.js b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/error/subject.js deleted file mode 100644 index 2bb2bba64d9e..000000000000 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/error/subject.js +++ /dev/null @@ -1,3 +0,0 @@ -setTimeout(() => { - throw new Error('Error during pageload'); -}, 100); diff --git a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/error/test.ts b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/error/test.ts index df684872e7c0..22031cf7976f 100644 --- a/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/error/test.ts +++ b/dev-packages/browser-integration-tests/suites/tracing/browserTracingIntegration/error/test.ts @@ -1,7 +1,11 @@ import { expect } from '@playwright/test'; import type { Event } from '@sentry/types'; import { sentryTest } from '../../../../utils/fixtures'; -import { getMultipleSentryEnvelopeRequests, shouldSkipTracingTest } from '../../../../utils/helpers'; +import { + getMultipleSentryEnvelopeRequests, + runScriptInSandbox, + shouldSkipTracingTest, +} from '../../../../utils/helpers'; sentryTest( 'should put the pageload transaction name onto an error event caught during pageload', @@ -14,6 +18,12 @@ sentryTest( await page.goto(url); + runScriptInSandbox(page, { + content: ` + throw new Error('Error during pageload'); + `, + }); + const [e1, e2] = await getMultipleSentryEnvelopeRequests(page, 2); const pageloadTxnEvent = e1.type === 'transaction' ? e1 : e2; diff --git a/dev-packages/browser-integration-tests/utils/helpers.ts b/dev-packages/browser-integration-tests/utils/helpers.ts index d1e27f194e12..206b279e0033 100644 --- a/dev-packages/browser-integration-tests/utils/helpers.ts +++ b/dev-packages/browser-integration-tests/utils/helpers.ts @@ -141,11 +141,17 @@ export const countEnvelopes = async ( * Run script at the given path inside the test environment. * * @param {Page} page - * @param {string} path + * @param {{ path?: string; content?: string }} impl * @return {*} {Promise} */ -async function runScriptInSandbox(page: Page, path: string): Promise { - await page.addScriptTag({ path }); +async function runScriptInSandbox( + page: Page, + impl: { + path?: string; + content?: string; + }, +): Promise { + await page.addScriptTag({ path: impl.path, content: impl.content }); } /** @@ -333,26 +339,11 @@ async function getFirstSentryEnvelopeRequest( } /** - * Manually inject a script into the page of given URL. - * This function is useful to create more complex test subjects that can't be achieved by pre-built pages. - * The given script should be vanilla browser JavaScript + * Trigger an error in the page context. + * This function is useful to test error handling in the page. * * @param {Page} page - * @param {string} url - * @param {string} scriptPath - * @return {*} {Promise>} + * @param {unknown} error */ -async function injectScriptAndGetEvents(page: Page, url: string, scriptPath: string): Promise> { - await page.goto(url); - await runScriptInSandbox(page, scriptPath); - return getSentryEvents(page); -} - -export { - runScriptInSandbox, - getMultipleSentryEnvelopeRequests, - getFirstSentryEnvelopeRequest, - getSentryEvents, - injectScriptAndGetEvents, -}; +export { runScriptInSandbox, getMultipleSentryEnvelopeRequests, getFirstSentryEnvelopeRequest, getSentryEvents };