diff --git a/packages/e2e-tests/run.ts b/packages/e2e-tests/run.ts index 01b6e44c1575..7a069907d65d 100644 --- a/packages/e2e-tests/run.ts +++ b/packages/e2e-tests/run.ts @@ -14,7 +14,7 @@ const PUBLISH_PACKAGES_DOCKER_IMAGE_NAME = 'publish-packages'; const publishScriptNodeVersion = process.env.E2E_TEST_PUBLISH_SCRIPT_NODE_VERSION; const DEFAULT_BUILD_TIMEOUT_SECONDS = 60 * 5; -const DEFAULT_TEST_TIMEOUT_SECONDS = 60; +const DEFAULT_TEST_TIMEOUT_SECONDS = 60 * 2; if (!process.env.E2E_TEST_AUTH_TOKEN) { console.log( diff --git a/packages/e2e-tests/test-applications/standard-frontend-react/tests/behaviour-test.spec.ts b/packages/e2e-tests/test-applications/standard-frontend-react/tests/behaviour-test.spec.ts index dd85a686c2e3..53eef7287d9c 100644 --- a/packages/e2e-tests/test-applications/standard-frontend-react/tests/behaviour-test.spec.ts +++ b/packages/e2e-tests/test-applications/standard-frontend-react/tests/behaviour-test.spec.ts @@ -4,8 +4,7 @@ import axios, { AxiosError } from 'axios'; const SENTRY_TEST_ORG_SLUG = 'sentry-sdks'; const SENTRY_TEST_PROJECT = 'sentry-javascript-e2e-tests'; -const EVENT_POLLING_TIMEOUT = 45000; -const EVENT_POLLING_RETRY_INTERVAL = 1000; +const EVENT_POLLING_TIMEOUT = 30_000; const authToken = process.env.E2E_TEST_AUTH_TOKEN; @@ -18,30 +17,150 @@ test('Sends an exception to Sentry', async ({ page }) => { const exceptionIdHandle = await page.waitForFunction(() => window.capturedExceptionId); const exceptionEventId = await exceptionIdHandle.jsonValue(); - let lastErrorResponse: AxiosError | undefined; + await expect + .poll( + async () => { + try { + const response = await axios.get( + `https://sentry.io/api/0/projects/${SENTRY_TEST_ORG_SLUG}/${SENTRY_TEST_PROJECT}/events/${exceptionEventId}/`, + { headers: { Authorization: `Bearer ${authToken}` } }, + ); + return response.status; + } catch (e) { + if (e instanceof AxiosError && e.response) { + if (e.response.status !== 404) { + throw e; + } else { + return e.response.status; + } + } else { + throw e; + } + } + }, + { + timeout: EVENT_POLLING_TIMEOUT, + }, + ) + .toBe(200); +}); + +test('Sends a pageload transaction to Sentry', async ({ page }) => { + await page.goto('/'); - const timeout = setTimeout(() => { - if (lastErrorResponse?.response?.status) { - throw new Error( - `Timeout reached while polling event. Last received status code: ${lastErrorResponse.response.status}`, - ); + const recordedTransactionsHandle = await page.waitForFunction(() => { + if (window.recordedTransactions && window.recordedTransactions?.length >= 1) { + return window.recordedTransactions; } else { - throw new Error('Timeout reached while polling event.'); + return undefined; } - }, EVENT_POLLING_TIMEOUT); - - while (true) { - try { - const response = await axios.get( - `https://sentry.io/api/0/projects/${SENTRY_TEST_ORG_SLUG}/${SENTRY_TEST_PROJECT}/events/${exceptionEventId}/`, - { headers: { Authorization: `Bearer ${authToken}` } }, - ); - clearTimeout(timeout); - expect(response?.status).toBe(200); - break; - } catch (e) { - lastErrorResponse = e; - await new Promise(resolve => setTimeout(resolve, EVENT_POLLING_RETRY_INTERVAL)); + }); + const recordedTransactionEventIds = await recordedTransactionsHandle.jsonValue(); + + if (recordedTransactionEventIds === undefined) { + throw new Error("Application didn't record any transaction event IDs."); + } + + let hadPageLoadTransaction = false; + + await Promise.all( + recordedTransactionEventIds.map(async transactionEventId => { + await expect + .poll( + async () => { + try { + const response = await axios.get( + `https://sentry.io/api/0/projects/${SENTRY_TEST_ORG_SLUG}/${SENTRY_TEST_PROJECT}/events/${transactionEventId}/`, + { headers: { Authorization: `Bearer ${authToken}` } }, + ); + + if (response.data.contexts.trace.op === 'pageload') { + hadPageLoadTransaction = true; + } + + return response.status; + } catch (e) { + if (e instanceof AxiosError && e.response) { + if (e.response.status !== 404) { + throw e; + } else { + return e.response.status; + } + } else { + throw e; + } + } + }, + { + timeout: EVENT_POLLING_TIMEOUT, + }, + ) + .toBe(200); + }), + ); + + expect(hadPageLoadTransaction).toBe(true); +}); + +test('Sends a navigation transaction to Sentry', async ({ page }) => { + await page.goto('/'); + + // Give pageload transaction time to finish + page.waitForTimeout(4000); + + const linkElement = page.locator('id=navigation'); + await linkElement.click(); + + const recordedTransactionsHandle = await page.waitForFunction(() => { + if (window.recordedTransactions && window.recordedTransactions?.length >= 2) { + return window.recordedTransactions; + } else { + return undefined; } + }); + const recordedTransactionEventIds = await recordedTransactionsHandle.jsonValue(); + + if (recordedTransactionEventIds === undefined) { + throw new Error("Application didn't record any transaction event IDs."); } + + let hadPageNavigationTransaction = false; + + await Promise.all( + recordedTransactionEventIds.map(async transactionEventId => { + await expect + .poll( + async () => { + try { + const response = await axios.get( + `https://sentry.io/api/0/projects/${SENTRY_TEST_ORG_SLUG}/${SENTRY_TEST_PROJECT}/events/${transactionEventId}/`, + { headers: { Authorization: `Bearer ${authToken}` } }, + ); + + if (response.data.contexts.trace.op === 'navigation') { + hadPageNavigationTransaction = true; + } + + return response.status; + } catch (e) { + if (e instanceof AxiosError && e.response) { + if (e.response.status !== 404) { + throw e; + } else { + return e.response.status; + } + } else { + throw e; + } + } + }, + { + timeout: EVENT_POLLING_TIMEOUT, + }, + ) + .toBe(200); + }), + ); + + expect(hadPageNavigationTransaction).toBe(true); }); diff --git a/packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json b/packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json index 1d693b2b06ac..c8df41dcf4b5 100644 --- a/packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json +++ b/packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json @@ -16,5 +16,5 @@ "noEmit": true, "jsx": "react" }, - "include": ["src"] + "include": ["src", "tests"] }