From 7d84dc31717f5323ddbd204a5386088b1516f021 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Fri, 17 Dec 2021 20:26:07 +0000 Subject: [PATCH] Add initial integration tests for `@sentry/browser` public API. --- .../suites/demo/tmp/subject.js | 1 - .../integration-tests/suites/demo/tmp/test.ts | 12 --- .../addBreadcrumb/empty_obj/subject.js | 3 + .../addBreadcrumb/empty_obj/test.ts | 20 +++++ .../addBreadcrumb}/init.js | 0 .../multiple_breadcrumbs/subject.js | 11 +++ .../multiple_breadcrumbs/test.ts | 21 +++++ .../simple_breadcrumb/subject.js | 7 ++ .../addBreadcrumb/simple_breadcrumb/test.ts | 18 +++++ .../addBreadcrumb}/template.hbs | 0 .../addBreadcrumb/undefined_arg/subject.js | 3 + .../addBreadcrumb/undefined_arg/test.ts | 20 +++++ .../captureException/empty_obj/subject.js | 1 + .../captureException/empty_obj/test.ts | 20 +++++ .../public-api/captureException/init.js | 7 ++ .../captureException/simple_error/subject.js | 5 ++ .../captureException/simple_error/test.ts | 23 ++++++ .../public-api/captureException/template.hbs | 11 +++ .../captureException/undefined_arg/subject.js | 1 + .../captureException/undefined_arg/test.ts | 20 +++++ .../captureException/with_context/init.js | 11 +++ .../captureException/with_context/subject.js | 5 ++ .../captureException/with_context/test.ts | 27 +++++++ .../suites/public-api/captureMessage/init.js | 7 ++ .../captureMessage/simple_message/subject.js | 1 + .../captureMessage/simple_message/test.ts | 13 ++++ .../public-api/captureMessage/template.hbs | 11 +++ .../captureMessage/with_context/init.js | 11 +++ .../captureMessage/with_context/subject.js | 1 + .../captureMessage/with_context/test.ts | 17 ++++ .../captureMessage/with_level/init.js | 11 +++ .../captureMessage/with_level/subject.js | 7 ++ .../captureMessage/with_level/test.ts | 31 ++++++++ .../configureScope/clear_scope/subject.js | 8 ++ .../configureScope/clear_scope/test.ts | 15 ++++ .../suites/public-api/configureScope/init.js | 7 ++ .../configureScope/set_properties/subject.js | 7 ++ .../configureScope/set_properties/test.ts | 15 ++++ .../public-api/configureScope/template.hbs | 11 +++ .../suites/public-api/setContext/init.js | 7 ++ .../setContext/multiple_contexts/subject.js | 18 +++++ .../setContext/multiple_contexts/test.ts | 22 ++++++ .../non_serializable_context/subject.js | 5 ++ .../non_serializable_context/test.ts | 13 ++++ .../setContext/simple_context/subject.js | 2 + .../setContext/simple_context/test.ts | 17 ++++ .../suites/public-api/setContext/template.hbs | 11 +++ .../suites/public-api/setExtra/init.js | 7 ++ .../setExtra/multiple_extras/subject.js | 10 +++ .../setExtra/multiple_extras/test.ts | 13 ++++ .../non_serializable_extra/subject.js | 5 ++ .../setExtra/non_serializable_extra/test.ts | 13 ++++ .../setExtra/simple_extra/subject.js | 8 ++ .../public-api/setExtra/simple_extra/test.ts | 13 ++++ .../suites/public-api/setExtra/template.hbs | 11 +++ .../setExtras/consecutive_calls/subject.js | 11 +++ .../setExtras/consecutive_calls/test.ts | 13 ++++ .../suites/public-api/setExtras/init.js | 7 ++ .../setExtras/multiple_extras/subject.js | 12 +++ .../setExtras/multiple_extras/test.ts | 18 +++++ .../suites/public-api/setExtras/template.hbs | 11 +++ .../suites/public-api/setTag/init.js | 7 ++ .../suites/public-api/setTag/template.hbs | 11 +++ .../setTag/with_non_primitives/subject.js | 7 ++ .../setTag/with_non_primitives/test.ts | 13 ++++ .../setTag/with_primitives/subject.js | 8 ++ .../public-api/setTag/with_primitives/test.ts | 19 +++++ .../suites/public-api/setTags/init.js | 7 ++ .../suites/public-api/setTags/template.hbs | 11 +++ .../setTags/with_non_primitives/subject.js | 8 ++ .../setTags/with_non_primitives/test.ts | 13 ++++ .../setTags/with_primitives/subject.js | 10 +++ .../setTags/with_primitives/test.ts | 19 +++++ .../suites/public-api/setUser/init.js | 11 +++ .../suites/public-api/setUser/template.hbs | 11 +++ .../public-api/setUser/unset_user/subject.js | 13 ++++ .../public-api/setUser/unset_user/test.ts | 23 ++++++ .../public-api/setUser/update_user/subject.js | 12 +++ .../public-api/setUser/update_user/test.ts | 21 +++++ .../startTransaction/basic_usage/subject.js | 30 ++++++++ .../startTransaction/basic_usage/test.ts | 37 +++++++++ .../public-api/startTransaction/init.js | 10 +++ .../public-api/startTransaction/template.hbs | 11 +++ .../suites/public-api/withScope/init.js | 11 +++ .../withScope/nested_scopes/subject.js | 18 +++++ .../withScope/nested_scopes/test.ts | 30 ++++++++ .../suites/public-api/withScope/template.hbs | 11 +++ packages/integration-tests/utils/helpers.ts | 77 +++++++++++++++++-- 88 files changed, 1108 insertions(+), 18 deletions(-) delete mode 100644 packages/integration-tests/suites/demo/tmp/subject.js delete mode 100644 packages/integration-tests/suites/demo/tmp/test.ts create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/subject.js create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/test.ts rename packages/integration-tests/suites/{demo => public-api/addBreadcrumb}/init.js (100%) create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/subject.js create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/test.ts create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/subject.js create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/test.ts rename packages/integration-tests/suites/{demo => public-api/addBreadcrumb}/template.hbs (100%) create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/subject.js create mode 100644 packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/test.ts create mode 100644 packages/integration-tests/suites/public-api/captureException/empty_obj/subject.js create mode 100644 packages/integration-tests/suites/public-api/captureException/empty_obj/test.ts create mode 100644 packages/integration-tests/suites/public-api/captureException/init.js create mode 100644 packages/integration-tests/suites/public-api/captureException/simple_error/subject.js create mode 100644 packages/integration-tests/suites/public-api/captureException/simple_error/test.ts create mode 100644 packages/integration-tests/suites/public-api/captureException/template.hbs create mode 100644 packages/integration-tests/suites/public-api/captureException/undefined_arg/subject.js create mode 100644 packages/integration-tests/suites/public-api/captureException/undefined_arg/test.ts create mode 100644 packages/integration-tests/suites/public-api/captureException/with_context/init.js create mode 100644 packages/integration-tests/suites/public-api/captureException/with_context/subject.js create mode 100644 packages/integration-tests/suites/public-api/captureException/with_context/test.ts create mode 100644 packages/integration-tests/suites/public-api/captureMessage/init.js create mode 100644 packages/integration-tests/suites/public-api/captureMessage/simple_message/subject.js create mode 100644 packages/integration-tests/suites/public-api/captureMessage/simple_message/test.ts create mode 100644 packages/integration-tests/suites/public-api/captureMessage/template.hbs create mode 100644 packages/integration-tests/suites/public-api/captureMessage/with_context/init.js create mode 100644 packages/integration-tests/suites/public-api/captureMessage/with_context/subject.js create mode 100644 packages/integration-tests/suites/public-api/captureMessage/with_context/test.ts create mode 100644 packages/integration-tests/suites/public-api/captureMessage/with_level/init.js create mode 100644 packages/integration-tests/suites/public-api/captureMessage/with_level/subject.js create mode 100644 packages/integration-tests/suites/public-api/captureMessage/with_level/test.ts create mode 100644 packages/integration-tests/suites/public-api/configureScope/clear_scope/subject.js create mode 100644 packages/integration-tests/suites/public-api/configureScope/clear_scope/test.ts create mode 100644 packages/integration-tests/suites/public-api/configureScope/init.js create mode 100644 packages/integration-tests/suites/public-api/configureScope/set_properties/subject.js create mode 100644 packages/integration-tests/suites/public-api/configureScope/set_properties/test.ts create mode 100644 packages/integration-tests/suites/public-api/configureScope/template.hbs create mode 100644 packages/integration-tests/suites/public-api/setContext/init.js create mode 100644 packages/integration-tests/suites/public-api/setContext/multiple_contexts/subject.js create mode 100644 packages/integration-tests/suites/public-api/setContext/multiple_contexts/test.ts create mode 100644 packages/integration-tests/suites/public-api/setContext/non_serializable_context/subject.js create mode 100644 packages/integration-tests/suites/public-api/setContext/non_serializable_context/test.ts create mode 100644 packages/integration-tests/suites/public-api/setContext/simple_context/subject.js create mode 100644 packages/integration-tests/suites/public-api/setContext/simple_context/test.ts create mode 100644 packages/integration-tests/suites/public-api/setContext/template.hbs create mode 100644 packages/integration-tests/suites/public-api/setExtra/init.js create mode 100644 packages/integration-tests/suites/public-api/setExtra/multiple_extras/subject.js create mode 100644 packages/integration-tests/suites/public-api/setExtra/multiple_extras/test.ts create mode 100644 packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/subject.js create mode 100644 packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/test.ts create mode 100644 packages/integration-tests/suites/public-api/setExtra/simple_extra/subject.js create mode 100644 packages/integration-tests/suites/public-api/setExtra/simple_extra/test.ts create mode 100644 packages/integration-tests/suites/public-api/setExtra/template.hbs create mode 100644 packages/integration-tests/suites/public-api/setExtras/consecutive_calls/subject.js create mode 100644 packages/integration-tests/suites/public-api/setExtras/consecutive_calls/test.ts create mode 100644 packages/integration-tests/suites/public-api/setExtras/init.js create mode 100644 packages/integration-tests/suites/public-api/setExtras/multiple_extras/subject.js create mode 100644 packages/integration-tests/suites/public-api/setExtras/multiple_extras/test.ts create mode 100644 packages/integration-tests/suites/public-api/setExtras/template.hbs create mode 100644 packages/integration-tests/suites/public-api/setTag/init.js create mode 100644 packages/integration-tests/suites/public-api/setTag/template.hbs create mode 100644 packages/integration-tests/suites/public-api/setTag/with_non_primitives/subject.js create mode 100644 packages/integration-tests/suites/public-api/setTag/with_non_primitives/test.ts create mode 100644 packages/integration-tests/suites/public-api/setTag/with_primitives/subject.js create mode 100644 packages/integration-tests/suites/public-api/setTag/with_primitives/test.ts create mode 100644 packages/integration-tests/suites/public-api/setTags/init.js create mode 100644 packages/integration-tests/suites/public-api/setTags/template.hbs create mode 100644 packages/integration-tests/suites/public-api/setTags/with_non_primitives/subject.js create mode 100644 packages/integration-tests/suites/public-api/setTags/with_non_primitives/test.ts create mode 100644 packages/integration-tests/suites/public-api/setTags/with_primitives/subject.js create mode 100644 packages/integration-tests/suites/public-api/setTags/with_primitives/test.ts create mode 100644 packages/integration-tests/suites/public-api/setUser/init.js create mode 100644 packages/integration-tests/suites/public-api/setUser/template.hbs create mode 100644 packages/integration-tests/suites/public-api/setUser/unset_user/subject.js create mode 100644 packages/integration-tests/suites/public-api/setUser/unset_user/test.ts create mode 100644 packages/integration-tests/suites/public-api/setUser/update_user/subject.js create mode 100644 packages/integration-tests/suites/public-api/setUser/update_user/test.ts create mode 100644 packages/integration-tests/suites/public-api/startTransaction/basic_usage/subject.js create mode 100644 packages/integration-tests/suites/public-api/startTransaction/basic_usage/test.ts create mode 100644 packages/integration-tests/suites/public-api/startTransaction/init.js create mode 100644 packages/integration-tests/suites/public-api/startTransaction/template.hbs create mode 100644 packages/integration-tests/suites/public-api/withScope/init.js create mode 100644 packages/integration-tests/suites/public-api/withScope/nested_scopes/subject.js create mode 100644 packages/integration-tests/suites/public-api/withScope/nested_scopes/test.ts create mode 100644 packages/integration-tests/suites/public-api/withScope/template.hbs diff --git a/packages/integration-tests/suites/demo/tmp/subject.js b/packages/integration-tests/suites/demo/tmp/subject.js deleted file mode 100644 index d19e783e8a44..000000000000 --- a/packages/integration-tests/suites/demo/tmp/subject.js +++ /dev/null @@ -1 +0,0 @@ -Sentry.captureMessage(1); diff --git a/packages/integration-tests/suites/demo/tmp/test.ts b/packages/integration-tests/suites/demo/tmp/test.ts deleted file mode 100644 index 8542cee410e0..000000000000 --- a/packages/integration-tests/suites/demo/tmp/test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../utils/fixtures'; -import { getSentryRequest } from '../../../utils/helpers'; - -sentryTest('should fail', async ({ getLocalTestPath, page }) => { - const url = await getLocalTestPath({ testDir: __dirname }); - - const eventData = await getSentryRequest(page, url); - - expect(eventData.message).toBe('1'); -}); diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/subject.js b/packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/subject.js new file mode 100644 index 000000000000..abf90827f014 --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/subject.js @@ -0,0 +1,3 @@ +Sentry.addBreadcrumb({}); + +Sentry.captureMessage('test_empty_obj'); diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/test.ts b/packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/test.ts new file mode 100644 index 000000000000..e6e2b9a8f4dd --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/empty_obj/test.ts @@ -0,0 +1,20 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest( + 'should add an empty breadcrumb initialized with a timestamp, when an empty object is given', + async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.breadcrumbs).toHaveLength(1); + expect(eventData.breadcrumbs?.[0]).toMatchObject({ + timestamp: expect.any(Number), + }); + + expect(eventData.message).toBe('test_empty_obj'); + }, +); diff --git a/packages/integration-tests/suites/demo/init.js b/packages/integration-tests/suites/public-api/addBreadcrumb/init.js similarity index 100% rename from packages/integration-tests/suites/demo/init.js rename to packages/integration-tests/suites/public-api/addBreadcrumb/init.js diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/subject.js b/packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/subject.js new file mode 100644 index 000000000000..28eece8ee8df --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/subject.js @@ -0,0 +1,11 @@ +Sentry.addBreadcrumb({ + category: 'foo', + message: 'bar', + level: 'baz', +}); + +Sentry.addBreadcrumb({ + category: 'qux', +}); + +Sentry.captureMessage('test_multi_breadcrumbs'); diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/test.ts b/packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/test.ts new file mode 100644 index 000000000000..c7bca64aafd5 --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/multiple_breadcrumbs/test.ts @@ -0,0 +1,21 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should add multiple breadcrumbs', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.breadcrumbs).toHaveLength(2); + expect(eventData.breadcrumbs?.[0]).toMatchObject({ + category: 'foo', + message: 'bar', + level: 'baz', + }); + expect(eventData.breadcrumbs?.[1]).toMatchObject({ + category: 'qux', + }); + expect(eventData.message).toBe('test_multi_breadcrumbs'); +}); diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/subject.js b/packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/subject.js new file mode 100644 index 000000000000..46ee75ccebfe --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/subject.js @@ -0,0 +1,7 @@ +Sentry.addBreadcrumb({ + category: 'foo', + message: 'bar', + level: 'baz', +}); + +Sentry.captureMessage('test'); diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/test.ts b/packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/test.ts new file mode 100644 index 000000000000..98e36a254076 --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/simple_breadcrumb/test.ts @@ -0,0 +1,18 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should add a simple breadcrumb', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.breadcrumbs).toHaveLength(1); + expect(eventData.breadcrumbs?.[0]).toMatchObject({ + category: 'foo', + message: 'bar', + level: 'baz', + }); + expect(eventData.message).toBe('test'); +}); diff --git a/packages/integration-tests/suites/demo/template.hbs b/packages/integration-tests/suites/public-api/addBreadcrumb/template.hbs similarity index 100% rename from packages/integration-tests/suites/demo/template.hbs rename to packages/integration-tests/suites/public-api/addBreadcrumb/template.hbs diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/subject.js b/packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/subject.js new file mode 100644 index 000000000000..8d1d3605c2f1 --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/subject.js @@ -0,0 +1,3 @@ +Sentry.addBreadcrumb(); + +Sentry.captureMessage('test_undefined_arg'); diff --git a/packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/test.ts b/packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/test.ts new file mode 100644 index 000000000000..b41f527c58ed --- /dev/null +++ b/packages/integration-tests/suites/public-api/addBreadcrumb/undefined_arg/test.ts @@ -0,0 +1,20 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest( + 'should add an empty breadcrumb initialized with a timestamp, when no argument is given', + async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.breadcrumbs).toHaveLength(1); + expect(eventData.breadcrumbs?.[0]).toMatchObject({ + timestamp: expect.any(Number), + }); + + expect(eventData.message).toBe('test_undefined_arg'); + }, +); diff --git a/packages/integration-tests/suites/public-api/captureException/empty_obj/subject.js b/packages/integration-tests/suites/public-api/captureException/empty_obj/subject.js new file mode 100644 index 000000000000..bd85c8d4c6aa --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/empty_obj/subject.js @@ -0,0 +1 @@ +Sentry.captureException({}); diff --git a/packages/integration-tests/suites/public-api/captureException/empty_obj/test.ts b/packages/integration-tests/suites/public-api/captureException/empty_obj/test.ts new file mode 100644 index 000000000000..2606b2984d08 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/empty_obj/test.ts @@ -0,0 +1,20 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should capture an empty object', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + expect(eventData.exception?.values?.[0]).toMatchObject({ + type: 'Error', + value: 'Non-Error exception captured with keys: [object has no keys]', + mechanism: { + type: 'generic', + handled: true, + }, + }); +}); diff --git a/packages/integration-tests/suites/public-api/captureException/init.js b/packages/integration-tests/suites/public-api/captureException/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/captureException/simple_error/subject.js b/packages/integration-tests/suites/public-api/captureException/simple_error/subject.js new file mode 100644 index 000000000000..a10e80582708 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/simple_error/subject.js @@ -0,0 +1,5 @@ +try { + throw Error('test_simple_error'); +} catch (err) { + Sentry.captureException(err); +} diff --git a/packages/integration-tests/suites/public-api/captureException/simple_error/test.ts b/packages/integration-tests/suites/public-api/captureException/simple_error/test.ts new file mode 100644 index 000000000000..f52e951c20c6 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/simple_error/test.ts @@ -0,0 +1,23 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should capture a simple error with message', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + expect(eventData.exception?.values?.[0]).toMatchObject({ + type: 'Error', + value: 'test_simple_error', + mechanism: { + type: 'generic', + handled: true, + }, + stacktrace: { + frames: expect.any(Array), + }, + }); +}); diff --git a/packages/integration-tests/suites/public-api/captureException/template.hbs b/packages/integration-tests/suites/public-api/captureException/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/captureException/undefined_arg/subject.js b/packages/integration-tests/suites/public-api/captureException/undefined_arg/subject.js new file mode 100644 index 000000000000..fc2a11c7e345 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/undefined_arg/subject.js @@ -0,0 +1 @@ +Sentry.captureException(); diff --git a/packages/integration-tests/suites/public-api/captureException/undefined_arg/test.ts b/packages/integration-tests/suites/public-api/captureException/undefined_arg/test.ts new file mode 100644 index 000000000000..021af6f922f3 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/undefined_arg/test.ts @@ -0,0 +1,20 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should capture an undefined error when no arguments are provided', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + expect(eventData.exception?.values?.[0]).toMatchObject({ + type: 'Error', + value: 'undefined', + mechanism: { + type: 'generic', + handled: true, + }, + }); +}); diff --git a/packages/integration-tests/suites/public-api/captureException/with_context/init.js b/packages/integration-tests/suites/public-api/captureException/with_context/init.js new file mode 100644 index 000000000000..c96596448965 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/with_context/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + beforeSend: (event, hint) => { + event.hint = hint; + return event; + }, +}); diff --git a/packages/integration-tests/suites/public-api/captureException/with_context/subject.js b/packages/integration-tests/suites/public-api/captureException/with_context/subject.js new file mode 100644 index 000000000000..a712f5d1adf9 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/with_context/subject.js @@ -0,0 +1,5 @@ +try { + undefinedFn(); +} catch (err) { + Sentry.captureException(err, { foo: 'bar' }); +} diff --git a/packages/integration-tests/suites/public-api/captureException/with_context/test.ts b/packages/integration-tests/suites/public-api/captureException/with_context/test.ts new file mode 100644 index 000000000000..334ff4557491 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureException/with_context/test.ts @@ -0,0 +1,27 @@ +import { expect } from '@playwright/test'; +import { EventHint } from '@sentry/types'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should capture an error with provided hint context', async ({ getLocalTestPath, page, browserName }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.exception?.values).toHaveLength(1); + expect(eventData.exception?.values?.[0]).toMatchObject({ + type: 'ReferenceError', + value: browserName === 'webkit' ? `Can't find variable: undefinedFn` : 'undefinedFn is not defined', + mechanism: { + type: 'generic', + handled: true, + }, + stacktrace: { + frames: expect.any(Array), + }, + }); + expect((eventData as Event & { hint: EventHint }).hint.captureContext).toMatchObject({ + foo: 'bar', + }); +}); diff --git a/packages/integration-tests/suites/public-api/captureMessage/init.js b/packages/integration-tests/suites/public-api/captureMessage/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/captureMessage/simple_message/subject.js b/packages/integration-tests/suites/public-api/captureMessage/simple_message/subject.js new file mode 100644 index 000000000000..cf462c59a2fb --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/simple_message/subject.js @@ -0,0 +1 @@ +Sentry.captureMessage('foo'); diff --git a/packages/integration-tests/suites/public-api/captureMessage/simple_message/test.ts b/packages/integration-tests/suites/public-api/captureMessage/simple_message/test.ts new file mode 100644 index 000000000000..7b4b68f228d6 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/simple_message/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should capture a simple message string', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('foo'); + expect(eventData.level).toBe('info'); +}); diff --git a/packages/integration-tests/suites/public-api/captureMessage/template.hbs b/packages/integration-tests/suites/public-api/captureMessage/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/captureMessage/with_context/init.js b/packages/integration-tests/suites/public-api/captureMessage/with_context/init.js new file mode 100644 index 000000000000..c96596448965 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/with_context/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + beforeSend: (event, hint) => { + event.hint = hint; + return event; + }, +}); diff --git a/packages/integration-tests/suites/public-api/captureMessage/with_context/subject.js b/packages/integration-tests/suites/public-api/captureMessage/with_context/subject.js new file mode 100644 index 000000000000..60c958a41d1f --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/with_context/subject.js @@ -0,0 +1 @@ +Sentry.captureMessage('message_with_hint', { foo: 'bar', level: 'error' }); diff --git a/packages/integration-tests/suites/public-api/captureMessage/with_context/test.ts b/packages/integration-tests/suites/public-api/captureMessage/with_context/test.ts new file mode 100644 index 000000000000..f438d8400f8b --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/with_context/test.ts @@ -0,0 +1,17 @@ +import { expect } from '@playwright/test'; +import { EventHint } from '@sentry/types'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should capture a message with provided hint', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('message_with_hint'); + expect(eventData.level).toBe('error'); + expect((eventData as Event & { hint: EventHint }).hint.captureContext).toMatchObject({ + foo: 'bar', + level: 'error', + }); +}); diff --git a/packages/integration-tests/suites/public-api/captureMessage/with_level/init.js b/packages/integration-tests/suites/public-api/captureMessage/with_level/init.js new file mode 100644 index 000000000000..a88255b8428a --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/with_level/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.events = []; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + beforeSend: event => { + window.events.push(event); + }, +}); diff --git a/packages/integration-tests/suites/public-api/captureMessage/with_level/subject.js b/packages/integration-tests/suites/public-api/captureMessage/with_level/subject.js new file mode 100644 index 000000000000..3d7368c95fef --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/with_level/subject.js @@ -0,0 +1,7 @@ +Sentry.captureMessage('debug_message', 'debug'); +Sentry.captureMessage('info_message', 'info'); +Sentry.captureMessage('warning_message', 'warning'); +Sentry.captureMessage('error_message', 'error'); +Sentry.captureMessage('fatal_message', 'fatal'); +Sentry.captureMessage('critical_message', 'critical'); +Sentry.captureMessage('log_message', 'log'); diff --git a/packages/integration-tests/suites/public-api/captureMessage/with_level/test.ts b/packages/integration-tests/suites/public-api/captureMessage/with_level/test.ts new file mode 100644 index 000000000000..64686fe0ff03 --- /dev/null +++ b/packages/integration-tests/suites/public-api/captureMessage/with_level/test.ts @@ -0,0 +1,31 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryEvents } from '../../../../utils/helpers'; + +sentryTest('should capture with different severity levels', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const events = await getSentryEvents(page, url); + + expect(events[0].message).toBe('debug_message'); + expect(events[0].level).toBe('debug'); + + expect(events[1].message).toBe('info_message'); + expect(events[1].level).toBe('info'); + + expect(events[2].message).toBe('warning_message'); + expect(events[2].level).toBe('warning'); + + expect(events[3].message).toBe('error_message'); + expect(events[3].level).toBe('error'); + + expect(events[4].message).toBe('fatal_message'); + expect(events[4].level).toBe('fatal'); + + expect(events[5].message).toBe('critical_message'); + expect(events[5].level).toBe('critical'); + + expect(events[6].message).toBe('log_message'); + expect(events[6].level).toBe('log'); +}); diff --git a/packages/integration-tests/suites/public-api/configureScope/clear_scope/subject.js b/packages/integration-tests/suites/public-api/configureScope/clear_scope/subject.js new file mode 100644 index 000000000000..ae65f9976267 --- /dev/null +++ b/packages/integration-tests/suites/public-api/configureScope/clear_scope/subject.js @@ -0,0 +1,8 @@ +Sentry.configureScope(scope => { + scope.setTag('foo', 'bar'); + scope.setUser({ id: 'baz' }); + scope.setExtra('qux', 'quux'); + scope.clear(); +}); + +Sentry.captureMessage('cleared_scope'); diff --git a/packages/integration-tests/suites/public-api/configureScope/clear_scope/test.ts b/packages/integration-tests/suites/public-api/configureScope/clear_scope/test.ts new file mode 100644 index 000000000000..d8c8bc631553 --- /dev/null +++ b/packages/integration-tests/suites/public-api/configureScope/clear_scope/test.ts @@ -0,0 +1,15 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should clear previously set properties of a scope', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('cleared_scope'); + expect(eventData.user).toBeUndefined(); + expect(eventData.tags).toBeUndefined(); + expect(eventData.extra).toBeUndefined(); +}); diff --git a/packages/integration-tests/suites/public-api/configureScope/init.js b/packages/integration-tests/suites/public-api/configureScope/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/configureScope/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/configureScope/set_properties/subject.js b/packages/integration-tests/suites/public-api/configureScope/set_properties/subject.js new file mode 100644 index 000000000000..db5d34977b1e --- /dev/null +++ b/packages/integration-tests/suites/public-api/configureScope/set_properties/subject.js @@ -0,0 +1,7 @@ +Sentry.configureScope(scope => { + scope.setTag('foo', 'bar'); + scope.setUser({ id: 'baz' }); + scope.setExtra('qux', 'quux'); +}); + +Sentry.captureMessage('configured_scope'); diff --git a/packages/integration-tests/suites/public-api/configureScope/set_properties/test.ts b/packages/integration-tests/suites/public-api/configureScope/set_properties/test.ts new file mode 100644 index 000000000000..d4001c317d05 --- /dev/null +++ b/packages/integration-tests/suites/public-api/configureScope/set_properties/test.ts @@ -0,0 +1,15 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should set different properties of a scope', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('configured_scope'); + expect(eventData.user).toMatchObject({ id: 'baz' }); + expect(eventData.tags).toMatchObject({ foo: 'bar' }); + expect(eventData.extra).toMatchObject({ qux: 'quux' }); +}); diff --git a/packages/integration-tests/suites/public-api/configureScope/template.hbs b/packages/integration-tests/suites/public-api/configureScope/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/configureScope/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/setContext/init.js b/packages/integration-tests/suites/public-api/setContext/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/setContext/multiple_contexts/subject.js b/packages/integration-tests/suites/public-api/setContext/multiple_contexts/subject.js new file mode 100644 index 000000000000..6529de530f70 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/multiple_contexts/subject.js @@ -0,0 +1,18 @@ +Sentry.setContext('context_1', { + foo: 'bar', + baz: { + qux: 'quux', + }, +}); + +Sentry.setContext('context_2', { + 1: 'foo', + bar: false, +}); + +Sentry.setContext('context_3', null); +Sentry.setContext('context_4'); +Sentry.setContext('context_5', NaN); +Sentry.setContext('context_6', Math.PI); + +Sentry.captureMessage('multiple_contexts'); diff --git a/packages/integration-tests/suites/public-api/setContext/multiple_contexts/test.ts b/packages/integration-tests/suites/public-api/setContext/multiple_contexts/test.ts new file mode 100644 index 000000000000..ff5ec95ab89f --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/multiple_contexts/test.ts @@ -0,0 +1,22 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should record multiple extras of different types', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('multiple_contexts'); + expect(eventData.contexts).toMatchObject({ + context_1: { + foo: 'bar', + baz: { qux: 'quux' }, + }, + context_2: { 1: 'foo', bar: false }, + context_4: '[undefined]', + context_5: '[NaN]', + context_6: 3.141592653589793, + }); +}); diff --git a/packages/integration-tests/suites/public-api/setContext/non_serializable_context/subject.js b/packages/integration-tests/suites/public-api/setContext/non_serializable_context/subject.js new file mode 100644 index 000000000000..136790527917 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/non_serializable_context/subject.js @@ -0,0 +1,5 @@ +const el = document.querySelector('body'); + +Sentry.setContext('non_serializable', el); + +Sentry.captureMessage('non_serializable'); diff --git a/packages/integration-tests/suites/public-api/setContext/non_serializable_context/test.ts b/packages/integration-tests/suites/public-api/setContext/non_serializable_context/test.ts new file mode 100644 index 000000000000..fe67bdaff3e7 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/non_serializable_context/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should normalize non-serializable context', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.contexts?.non_serializable).toMatchObject({}); + expect(eventData.message).toBe('non_serializable'); +}); diff --git a/packages/integration-tests/suites/public-api/setContext/simple_context/subject.js b/packages/integration-tests/suites/public-api/setContext/simple_context/subject.js new file mode 100644 index 000000000000..c89035a61ff9 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/simple_context/subject.js @@ -0,0 +1,2 @@ +Sentry.setContext('foo', { bar: 'baz' }); +Sentry.captureMessage('simple_context_object'); diff --git a/packages/integration-tests/suites/public-api/setContext/simple_context/test.ts b/packages/integration-tests/suites/public-api/setContext/simple_context/test.ts new file mode 100644 index 000000000000..05f534888796 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/simple_context/test.ts @@ -0,0 +1,17 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should set a simple context', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('simple_context_object'); + expect(eventData.contexts).toMatchObject({ + foo: { + bar: 'baz', + }, + }); +}); diff --git a/packages/integration-tests/suites/public-api/setContext/template.hbs b/packages/integration-tests/suites/public-api/setContext/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setContext/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/setExtra/init.js b/packages/integration-tests/suites/public-api/setExtra/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/setExtra/multiple_extras/subject.js b/packages/integration-tests/suites/public-api/setExtra/multiple_extras/subject.js new file mode 100644 index 000000000000..2c3771360b03 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/multiple_extras/subject.js @@ -0,0 +1,10 @@ +Sentry.setExtra('extra_1', { + foo: 'bar', + baz: { + qux: 'quux', + }, +}); + +Sentry.setExtra('extra_2', false); + +Sentry.captureMessage('multiple_extras'); diff --git a/packages/integration-tests/suites/public-api/setExtra/multiple_extras/test.ts b/packages/integration-tests/suites/public-api/setExtra/multiple_extras/test.ts new file mode 100644 index 000000000000..13d8aa83d9c4 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/multiple_extras/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should record multiple extras of different types', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('multiple_extras'); + expect(eventData.extra).toMatchObject({ extra_1: { foo: 'bar', baz: { qux: 'quux' } }, extra_2: false }); +}); diff --git a/packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/subject.js b/packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/subject.js new file mode 100644 index 000000000000..722cd095abb3 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/subject.js @@ -0,0 +1,5 @@ +const el = document.querySelector('body'); + +Sentry.setExtra('non_serializable', el); + +Sentry.captureMessage('non_serializable'); diff --git a/packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/test.ts b/packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/test.ts new file mode 100644 index 000000000000..eaa9d342e4e8 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/non_serializable_extra/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should normalize non-serializable extra', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('non_serializable'); + expect(eventData.extra).toMatchObject({}); +}); diff --git a/packages/integration-tests/suites/public-api/setExtra/simple_extra/subject.js b/packages/integration-tests/suites/public-api/setExtra/simple_extra/subject.js new file mode 100644 index 000000000000..62d89873ab62 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/simple_extra/subject.js @@ -0,0 +1,8 @@ +Sentry.setExtra('simple_extra', { + foo: 'bar', + baz: { + qux: 'quux', + }, +}); + +Sentry.captureMessage('simple_extra'); diff --git a/packages/integration-tests/suites/public-api/setExtra/simple_extra/test.ts b/packages/integration-tests/suites/public-api/setExtra/simple_extra/test.ts new file mode 100644 index 000000000000..8dbac9e15995 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/simple_extra/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should set different properties of a scope', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('simple_extra'); + expect(eventData.extra).toMatchObject({ simple_extra: { foo: 'bar', baz: { qux: 'quux' } } }); +}); diff --git a/packages/integration-tests/suites/public-api/setExtra/template.hbs b/packages/integration-tests/suites/public-api/setExtra/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtra/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/setExtras/consecutive_calls/subject.js b/packages/integration-tests/suites/public-api/setExtras/consecutive_calls/subject.js new file mode 100644 index 000000000000..41b09872a029 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtras/consecutive_calls/subject.js @@ -0,0 +1,11 @@ +Sentry.setExtras({ extra: [] }); +Sentry.setExtras({ null: 0 }); +Sentry.setExtras({ + obj: { + foo: ['bar', 'baz', 1], + }, +}); +Sentry.setExtras({ [null]: Infinity }); +Sentry.setExtras({ [Infinity]: 2 }); + +Sentry.captureMessage('consecutive_calls'); diff --git a/packages/integration-tests/suites/public-api/setExtras/consecutive_calls/test.ts b/packages/integration-tests/suites/public-api/setExtras/consecutive_calls/test.ts new file mode 100644 index 000000000000..319afc32255b --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtras/consecutive_calls/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should set extras from multiple consecutive calls', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('consecutive_calls'); + expect(eventData.extra).toMatchObject({ extra: [], Infinity: 2, null: null, obj: { foo: ['bar', 'baz', 1] } }); +}); diff --git a/packages/integration-tests/suites/public-api/setExtras/init.js b/packages/integration-tests/suites/public-api/setExtras/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtras/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/setExtras/multiple_extras/subject.js b/packages/integration-tests/suites/public-api/setExtras/multiple_extras/subject.js new file mode 100644 index 000000000000..e9163209ea5f --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtras/multiple_extras/subject.js @@ -0,0 +1,12 @@ +Sentry.setExtras({ + extra_1: [1, ['foo'], 'bar'], + extra_2: 'baz', + extra_3: Math.PI, + extra_4: { + qux: { + quux: false, + }, + }, +}); + +Sentry.captureMessage('multiple_extras'); diff --git a/packages/integration-tests/suites/public-api/setExtras/multiple_extras/test.ts b/packages/integration-tests/suites/public-api/setExtras/multiple_extras/test.ts new file mode 100644 index 000000000000..07a43458e94b --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtras/multiple_extras/test.ts @@ -0,0 +1,18 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should record an extras object', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('multiple_extras'); + expect(eventData.extra).toMatchObject({ + extra_1: [1, ['foo'], 'bar'], + extra_2: 'baz', + extra_3: 3.141592653589793, + extra_4: { qux: { quux: false } }, + }); +}); diff --git a/packages/integration-tests/suites/public-api/setExtras/template.hbs b/packages/integration-tests/suites/public-api/setExtras/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setExtras/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/setTag/init.js b/packages/integration-tests/suites/public-api/setTag/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTag/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/setTag/template.hbs b/packages/integration-tests/suites/public-api/setTag/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTag/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/setTag/with_non_primitives/subject.js b/packages/integration-tests/suites/public-api/setTag/with_non_primitives/subject.js new file mode 100644 index 000000000000..b27b223abc36 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTag/with_non_primitives/subject.js @@ -0,0 +1,7 @@ +Sentry.setTag('tag_1', {}); +Sentry.setTag('tag_2', []); +Sentry.setTag('tag_3', ['a', new Map()]); +Sentry.setTag('tag_4'); +Sentry.setTag('tag_5', () => {}); + +Sentry.captureMessage('non_primitives'); diff --git a/packages/integration-tests/suites/public-api/setTag/with_non_primitives/test.ts b/packages/integration-tests/suites/public-api/setTag/with_non_primitives/test.ts new file mode 100644 index 000000000000..56843d8f6652 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTag/with_non_primitives/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should not accept non-primitive tags', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('non_primitives'); + expect(eventData.tags).toMatchObject({}); +}); diff --git a/packages/integration-tests/suites/public-api/setTag/with_primitives/subject.js b/packages/integration-tests/suites/public-api/setTag/with_primitives/subject.js new file mode 100644 index 000000000000..0df60c268caa --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTag/with_primitives/subject.js @@ -0,0 +1,8 @@ +Sentry.setTag('tag_1', 'foo'); +Sentry.setTag('tag_2', Math.PI); +Sentry.setTag('tag_3', false); +Sentry.setTag('tag_4', null); +Sentry.setTag('tag_5', undefined); +Sentry.setTag('tag_6', -1); + +Sentry.captureMessage('primitive_tags'); diff --git a/packages/integration-tests/suites/public-api/setTag/with_primitives/test.ts b/packages/integration-tests/suites/public-api/setTag/with_primitives/test.ts new file mode 100644 index 000000000000..b3c24a8cd2c9 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTag/with_primitives/test.ts @@ -0,0 +1,19 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should set primitive tags', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('primitive_tags'); + expect(eventData.tags).toMatchObject({ + tag_1: 'foo', + tag_2: 3.141592653589793, + tag_3: false, + tag_4: null, + tag_6: -1, + }); +}); diff --git a/packages/integration-tests/suites/public-api/setTags/init.js b/packages/integration-tests/suites/public-api/setTags/init.js new file mode 100644 index 000000000000..d8c94f36fdd0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTags/init.js @@ -0,0 +1,7 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', +}); diff --git a/packages/integration-tests/suites/public-api/setTags/template.hbs b/packages/integration-tests/suites/public-api/setTags/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTags/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/setTags/with_non_primitives/subject.js b/packages/integration-tests/suites/public-api/setTags/with_non_primitives/subject.js new file mode 100644 index 000000000000..2845b9f07d13 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTags/with_non_primitives/subject.js @@ -0,0 +1,8 @@ +Sentry.setTags({ + tag_1: {}, + tag_2: [], + tag_3: ['a', new Map()], + tag_4: () => {}, +}); + +Sentry.captureMessage('non_primitives'); diff --git a/packages/integration-tests/suites/public-api/setTags/with_non_primitives/test.ts b/packages/integration-tests/suites/public-api/setTags/with_non_primitives/test.ts new file mode 100644 index 000000000000..56843d8f6652 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTags/with_non_primitives/test.ts @@ -0,0 +1,13 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should not accept non-primitive tags', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('non_primitives'); + expect(eventData.tags).toMatchObject({}); +}); diff --git a/packages/integration-tests/suites/public-api/setTags/with_primitives/subject.js b/packages/integration-tests/suites/public-api/setTags/with_primitives/subject.js new file mode 100644 index 000000000000..4835af53de15 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTags/with_primitives/subject.js @@ -0,0 +1,10 @@ +Sentry.setTags({ + tag_1: 'foo', + tag_2: Math.PI, + tag_3: false, + tag_4: null, + tag_5: undefined, + tag_6: -1, +}); + +Sentry.captureMessage('primitive_tags'); diff --git a/packages/integration-tests/suites/public-api/setTags/with_primitives/test.ts b/packages/integration-tests/suites/public-api/setTags/with_primitives/test.ts new file mode 100644 index 000000000000..b3c24a8cd2c9 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setTags/with_primitives/test.ts @@ -0,0 +1,19 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryRequest } from '../../../../utils/helpers'; + +sentryTest('should set primitive tags', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryRequest(page, url); + + expect(eventData.message).toBe('primitive_tags'); + expect(eventData.tags).toMatchObject({ + tag_1: 'foo', + tag_2: 3.141592653589793, + tag_3: false, + tag_4: null, + tag_6: -1, + }); +}); diff --git a/packages/integration-tests/suites/public-api/setUser/init.js b/packages/integration-tests/suites/public-api/setUser/init.js new file mode 100644 index 000000000000..a88255b8428a --- /dev/null +++ b/packages/integration-tests/suites/public-api/setUser/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.events = []; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + beforeSend: event => { + window.events.push(event); + }, +}); diff --git a/packages/integration-tests/suites/public-api/setUser/template.hbs b/packages/integration-tests/suites/public-api/setUser/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setUser/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/setUser/unset_user/subject.js b/packages/integration-tests/suites/public-api/setUser/unset_user/subject.js new file mode 100644 index 000000000000..fc7092379818 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setUser/unset_user/subject.js @@ -0,0 +1,13 @@ +Sentry.captureMessage('no_user'); + +Sentry.setUser({ + id: 'foo', + ip_address: 'bar', + other_key: 'baz', +}); + +Sentry.captureMessage('user'); + +Sentry.setUser(null); + +Sentry.captureMessage('unset_user'); diff --git a/packages/integration-tests/suites/public-api/setUser/unset_user/test.ts b/packages/integration-tests/suites/public-api/setUser/unset_user/test.ts new file mode 100644 index 000000000000..30a6a8a6c27e --- /dev/null +++ b/packages/integration-tests/suites/public-api/setUser/unset_user/test.ts @@ -0,0 +1,23 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryEvents } from '../../../../utils/helpers'; + +sentryTest('should unset user', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryEvents(page, url); + + expect(eventData[0].message).toBe('no_user'); + expect(eventData[0].user).toBeUndefined(); + + expect(eventData[1].message).toBe('user'); + expect(eventData[1].user).toMatchObject({ + id: 'foo', + ip_address: 'bar', + other_key: 'baz', + }); + + expect(eventData[2].message).toBe('unset_user'); + expect(eventData[2].user).toBeUndefined(); +}); diff --git a/packages/integration-tests/suites/public-api/setUser/update_user/subject.js b/packages/integration-tests/suites/public-api/setUser/update_user/subject.js new file mode 100644 index 000000000000..75ff0208730d --- /dev/null +++ b/packages/integration-tests/suites/public-api/setUser/update_user/subject.js @@ -0,0 +1,12 @@ +Sentry.setUser({ + id: 'foo', + ip_address: 'bar', +}); + +Sentry.captureMessage('first_user'); + +Sentry.setUser({ + id: 'baz', +}); + +Sentry.captureMessage('second_user'); diff --git a/packages/integration-tests/suites/public-api/setUser/update_user/test.ts b/packages/integration-tests/suites/public-api/setUser/update_user/test.ts new file mode 100644 index 000000000000..c71ccc2f49b0 --- /dev/null +++ b/packages/integration-tests/suites/public-api/setUser/update_user/test.ts @@ -0,0 +1,21 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryEvents } from '../../../../utils/helpers'; + +sentryTest('should update user', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryEvents(page, url); + + expect(eventData[0].message).toBe('first_user'); + expect(eventData[0].user).toMatchObject({ + id: 'foo', + ip_address: 'bar', + }); + + expect(eventData[1].message).toBe('second_user'); + expect(eventData[1].user).toMatchObject({ + id: 'baz', + }); +}); diff --git a/packages/integration-tests/suites/public-api/startTransaction/basic_usage/subject.js b/packages/integration-tests/suites/public-api/startTransaction/basic_usage/subject.js new file mode 100644 index 000000000000..c75bd2718326 --- /dev/null +++ b/packages/integration-tests/suites/public-api/startTransaction/basic_usage/subject.js @@ -0,0 +1,30 @@ +const transaction = Sentry.startTransaction({ name: 'test_transaction_1' }); +const span_1 = transaction.startChild({ + op: 'span_1', + data: { + foo: 'bar', + baz: [1, 2, 3], + }, +}); +for (let i = 0; i < 2000; i++); + +// span_1 finishes +span_1.finish(); + +// span_2 doesn't finish +const span_2 = transaction.startChild({ op: 'span_2' }); +for (let i = 0; i < 4000; i++); + +const span_3 = transaction.startChild({ op: 'span_3' }); +for (let i = 0; i < 4000; i++); + +// span_4 is the child of span_3 but doesn't finish. +const span_4 = span_3.startChild({ op: 'span_4', data: { qux: 'quux' } }); + +// span_5 is another child of span_3 but finishes. +const span_5 = span_3.startChild({ op: 'span_5' }).finish(); + +// span_3 also finishes +span_3.finish(); + +transaction.finish(); diff --git a/packages/integration-tests/suites/public-api/startTransaction/basic_usage/test.ts b/packages/integration-tests/suites/public-api/startTransaction/basic_usage/test.ts new file mode 100644 index 000000000000..bd0ea4c8011b --- /dev/null +++ b/packages/integration-tests/suites/public-api/startTransaction/basic_usage/test.ts @@ -0,0 +1,37 @@ +import { expect } from '@playwright/test'; +import { Event } from '@sentry/types'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryTransactionRequest } from '../../../../utils/helpers'; + +sentryTest('should report a transaction in an envelope', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + const eventData = await getSentryTransactionRequest(page, url); + const transaction = eventData[2] as Event; + + expect(transaction.transaction).toBe('test_transaction_1'); + expect(transaction.spans).toBeDefined(); +}); + +sentryTest('should report finished spans as children of the root transaction', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + const eventData = await getSentryTransactionRequest(page, url); + const transaction = eventData[2] as Event; + + const rootSpanId = transaction?.contexts?.trace.spanId; + + expect(transaction.spans).toHaveLength(3); + + const span_1 = transaction.spans?.[0]; + expect(span_1?.op).toBe('span_1'); + expect(span_1?.parentSpanId).toEqual(rootSpanId); + expect(span_1?.data).toMatchObject({ foo: 'bar', baz: [1, 2, 3] }); + + const span_3 = transaction.spans?.[1]; + expect(span_3?.op).toBe('span_3'); + expect(span_3?.parentSpanId).toEqual(rootSpanId); + + const span_5 = transaction.spans?.[2]; + expect(span_5?.op).toBe('span_5'); + expect(span_5?.parentSpanId).toEqual(span_3?.spanId); +}); diff --git a/packages/integration-tests/suites/public-api/startTransaction/init.js b/packages/integration-tests/suites/public-api/startTransaction/init.js new file mode 100644 index 000000000000..b326cc489bde --- /dev/null +++ b/packages/integration-tests/suites/public-api/startTransaction/init.js @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/browser'; +// eslint-disable-next-line no-unused-vars +import * as _ from '@sentry/tracing'; + +window.Sentry = Sentry; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + tracesSampleRate: 1.0, +}); diff --git a/packages/integration-tests/suites/public-api/startTransaction/template.hbs b/packages/integration-tests/suites/public-api/startTransaction/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/startTransaction/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/suites/public-api/withScope/init.js b/packages/integration-tests/suites/public-api/withScope/init.js new file mode 100644 index 000000000000..a88255b8428a --- /dev/null +++ b/packages/integration-tests/suites/public-api/withScope/init.js @@ -0,0 +1,11 @@ +import * as Sentry from '@sentry/browser'; + +window.Sentry = Sentry; +window.events = []; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + beforeSend: event => { + window.events.push(event); + }, +}); diff --git a/packages/integration-tests/suites/public-api/withScope/nested_scopes/subject.js b/packages/integration-tests/suites/public-api/withScope/nested_scopes/subject.js new file mode 100644 index 000000000000..6425cf4d49a9 --- /dev/null +++ b/packages/integration-tests/suites/public-api/withScope/nested_scopes/subject.js @@ -0,0 +1,18 @@ +Sentry.setUser({ id: 'qux' }); +Sentry.captureMessage('root_before'); + +Sentry.withScope(scope => { + scope.setTag('foo', false); + Sentry.captureMessage('outer_before'); + + Sentry.withScope(scope => { + scope.setTag('bar', 10); + scope.setUser(null); + Sentry.captureMessage('inner'); + }); + + scope.setUser({ id: 'baz' }); + Sentry.captureMessage('outer_after'); +}); + +Sentry.captureMessage('root_after'); diff --git a/packages/integration-tests/suites/public-api/withScope/nested_scopes/test.ts b/packages/integration-tests/suites/public-api/withScope/nested_scopes/test.ts new file mode 100644 index 000000000000..5ce71ff0e285 --- /dev/null +++ b/packages/integration-tests/suites/public-api/withScope/nested_scopes/test.ts @@ -0,0 +1,30 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../utils/fixtures'; +import { getSentryEvents } from '../../../../utils/helpers'; + +sentryTest('should allow nested scoping', async ({ getLocalTestPath, page }) => { + const url = await getLocalTestPath({ testDir: __dirname }); + + const eventData = await getSentryEvents(page, url); + + expect(eventData[0].message).toBe('root_before'); + expect(eventData[0].user).toMatchObject({ id: 'qux' }); + expect(eventData[0].tags).toBeUndefined(); + + expect(eventData[1].message).toBe('outer_before'); + expect(eventData[1].user).toMatchObject({ id: 'qux' }); + expect(eventData[1].tags).toMatchObject({ foo: false }); + + expect(eventData[2].message).toBe('inner'); + expect(eventData[2].user).toBeUndefined(); + expect(eventData[2].tags).toMatchObject({ foo: false, bar: 10 }); + + expect(eventData[3].message).toBe('outer_after'); + expect(eventData[3].user).toMatchObject({ id: 'baz' }); + expect(eventData[3].tags).toMatchObject({ foo: false }); + + expect(eventData[4].message).toBe('root_after'); + expect(eventData[4].user).toMatchObject({ id: 'qux' }); + expect(eventData[4].tags).toBeUndefined(); +}); diff --git a/packages/integration-tests/suites/public-api/withScope/template.hbs b/packages/integration-tests/suites/public-api/withScope/template.hbs new file mode 100644 index 000000000000..a28a09b7b485 --- /dev/null +++ b/packages/integration-tests/suites/public-api/withScope/template.hbs @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts index cf612df77c35..81391c1f09ca 100644 --- a/packages/integration-tests/utils/helpers.ts +++ b/packages/integration-tests/utils/helpers.ts @@ -1,6 +1,11 @@ -import { Page } from '@playwright/test'; +import { Page, Request } from '@playwright/test'; import { Event } from '@sentry/types'; +const storeUrlRegex = /\.sentry\.io\/api\/\d+\/store\//; +const envelopeUrlRegex = /\.sentry\.io\/api\/\d+\/envelope\//; + +type SentryRequestType = 'event' | 'transaction'; + /** * Run script at the given path inside the test environment. * @@ -13,18 +18,72 @@ async function runScriptInSandbox(page: Page, path: string): Promise { } /** - * Wait and get Sentry's request sending the event at the given URL + * Wait and get Sentry's request sending the event. + * + * @param {Page} page + * @returns {*} {Promise} + */ +async function waitForSentryRequest(page: Page, requestType: SentryRequestType = 'event'): Promise { + return page.waitForRequest(requestType === 'event' ? storeUrlRegex : envelopeUrlRegex); +} + +/** + * Wait and get Sentry's request sending the event at the given URL, or the current page * * @param {Page} page * @param {string} url * @return {*} {Promise} */ -async function getSentryRequest(page: Page, url: string): Promise { - const request = (await Promise.all([page.goto(url), page.waitForRequest(/\.sentry\.io\/api\//)]))[1]; +async function getSentryRequest(page: Page, url?: string): Promise { + const request = (await Promise.all([page.goto(url || '#'), waitForSentryRequest(page)]))[1]; return JSON.parse((request && request.postData()) || ''); } +/** + * Wait and get multiple event requests at the given URL, or the current page + * + * @param {Page} page + * @param {number} count + * @param {string} url + * @return {*} {Promise} + */ +async function getMultipleSentryRequests(page: Page, count: number, url?: string): Promise { + const requests: Promise = new Promise((resolve, reject) => { + let reqCount = 0; + const requestData: Event[] = []; + + page.on('request', request => { + if (storeUrlRegex.test(request.url())) { + reqCount += 1; + try { + requestData.push(JSON.parse((request && request.postData()) || '')); + + if (reqCount >= count - 1) { + resolve(requestData); + } + } catch (err) { + reject(err); + } + } + }); + }); + + if (url) { + await page.goto(url); + } + + return requests; +} + +async function getSentryTransactionRequest(page: Page, url?: string): Promise>> { + const request = (await Promise.all([page.goto(url || '#'), waitForSentryRequest(page, 'transaction')]))[1]; + + // https://develop.sentry.dev/sdk/envelopes/ + const envelope = (request?.postData() as string) || ''; + + return envelope.split('\n').map(line => JSON.parse(line)); +} /** * Get Sentry events at the given URL, or the current page. * @@ -58,4 +117,12 @@ async function injectScriptAndGetEvents(page: Page, url: string, scriptPath: str return await getSentryEvents(page); } -export { runScriptInSandbox, getSentryRequest, getSentryEvents, injectScriptAndGetEvents }; +export { + runScriptInSandbox, + waitForSentryRequest, + getSentryRequest, + getMultipleSentryRequests, + getSentryTransactionRequest, + getSentryEvents, + injectScriptAndGetEvents, +};