From b49aeb3968fd4511537fb2424004996feee11bea Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Tue, 21 Dec 2021 11:02:50 +0000 Subject: [PATCH 1/4] Add integration tests for `startTransaction` --- .../startTransaction/basic_usage/subject.js | 30 +++++++++++++++ .../startTransaction/basic_usage/test.ts | 37 +++++++++++++++++++ .../public-api/startTransaction/init.js | 10 +++++ .../public-api/startTransaction/template.hbs | 11 ++++++ 4 files changed, 88 insertions(+) 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 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 @@ + + + + + + + + + + + From e5cb0d288faa6649803a7f29c0f491b7bc3d97b8 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Tue, 21 Dec 2021 11:05:24 +0000 Subject: [PATCH 2/4] Add `getSentryTransactionRequest` helper. --- packages/integration-tests/utils/helpers.ts | 40 ++++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts index cf612df77c35..a165bd3a74cd 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,36 @@ 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()) || ''); } +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 +81,11 @@ async function injectScriptAndGetEvents(page: Page, url: string, scriptPath: str return await getSentryEvents(page); } -export { runScriptInSandbox, getSentryRequest, getSentryEvents, injectScriptAndGetEvents }; +export { + runScriptInSandbox, + waitForSentryRequest, + getSentryRequest, + getSentryTransactionRequest, + getSentryEvents, + injectScriptAndGetEvents, +}; From 19a6cd50c92dfbde84dadb1f8133296947b6617a Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Wed, 22 Dec 2021 21:44:39 +0000 Subject: [PATCH 3/4] Properly type `getSentryTransactionRequest`s return value. --- .../suites/public-api/startTransaction/basic_usage/test.ts | 7 ++----- packages/integration-tests/utils/helpers.ts | 5 +++-- 2 files changed, 5 insertions(+), 7 deletions(-) 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 index bd0ea4c8011b..1dc2eff3febc 100644 --- a/packages/integration-tests/suites/public-api/startTransaction/basic_usage/test.ts +++ b/packages/integration-tests/suites/public-api/startTransaction/basic_usage/test.ts @@ -1,13 +1,11 @@ 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; + const transaction = await getSentryTransactionRequest(page, url); expect(transaction.transaction).toBe('test_transaction_1'); expect(transaction.spans).toBeDefined(); @@ -15,8 +13,7 @@ sentryTest('should report a transaction in an envelope', async ({ getLocalTestPa 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 transaction = await getSentryTransactionRequest(page, url); const rootSpanId = transaction?.contexts?.trace.spanId; diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts index 4f406afa4c00..ae9fefa3613e 100644 --- a/packages/integration-tests/utils/helpers.ts +++ b/packages/integration-tests/utils/helpers.ts @@ -40,13 +40,14 @@ async function getSentryRequest(page: Page, url?: string): Promise { return JSON.parse((request && request.postData()) || ''); } -async function getSentryTransactionRequest(page: Page, url?: string): Promise>> { +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)); + // Third row of the envelop is the event payload. + return envelope.split('\n').map(line => JSON.parse(line))[2]; } /** * Get Sentry events at the given URL, or the current page. From ed328f0d4b367e11acf7edba68ffd50b5c552702 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Wed, 22 Dec 2021 22:57:38 +0000 Subject: [PATCH 4/4] Reject `getSentryTransactionRequest` on errors. --- packages/integration-tests/utils/helpers.ts | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts index ae9fefa3613e..c30621f67135 100644 --- a/packages/integration-tests/utils/helpers.ts +++ b/packages/integration-tests/utils/helpers.ts @@ -43,11 +43,15 @@ async function getSentryRequest(page: Page, url?: string): Promise { 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) || ''; - - // Third row of the envelop is the event payload. - return envelope.split('\n').map(line => JSON.parse(line))[2]; + try { + // https://develop.sentry.dev/sdk/envelopes/ + const envelope = request?.postData() || ''; + + // Third row of the envelop is the event payload. + return envelope.split('\n').map(line => JSON.parse(line))[2]; + } catch (err) { + return Promise.reject(err); + } } /** * Get Sentry events at the given URL, or the current page.