diff --git a/packages/integration-tests/suites/sessions/init.js b/packages/integration-tests/suites/sessions/init.js
new file mode 100644
index 000000000000..af2df91a7ceb
--- /dev/null
+++ b/packages/integration-tests/suites/sessions/init.js
@@ -0,0 +1,8 @@
+import * as Sentry from '@sentry/browser';
+
+window.Sentry = Sentry;
+
+Sentry.init({
+ dsn: 'https://public@dsn.ingest.sentry.io/1337',
+ release: '0.1',
+});
diff --git a/packages/integration-tests/suites/sessions/start-session/template.hbs b/packages/integration-tests/suites/sessions/start-session/template.hbs
new file mode 100644
index 000000000000..49ff0beab214
--- /dev/null
+++ b/packages/integration-tests/suites/sessions/start-session/template.hbs
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+ Navigate
+
+
+
diff --git a/packages/integration-tests/suites/sessions/start-session/test.ts b/packages/integration-tests/suites/sessions/start-session/test.ts
new file mode 100644
index 000000000000..e4469bd369c1
--- /dev/null
+++ b/packages/integration-tests/suites/sessions/start-session/test.ts
@@ -0,0 +1,38 @@
+import { expect, Route } from '@playwright/test';
+import { SessionContext } from '@sentry/types';
+
+import { sentryTest } from '../../../utils/fixtures';
+import { getFirstSentryEnvelopeRequest } from '../../../utils/helpers';
+
+sentryTest('should start a new session on pageload.', async ({ getLocalTestPath, page }) => {
+ const url = await getLocalTestPath({ testDir: __dirname });
+ const session = await getFirstSentryEnvelopeRequest(page, url);
+
+ expect(session).toBeDefined();
+ expect(session.init).toBe(true);
+ expect(session.errors).toBe(0);
+ expect(session.status).toBe('ok');
+});
+
+sentryTest('should start a new session with navigation.', async ({ getLocalTestPath, page, browserName }) => {
+ // Navigations get CORS error on Firefox and WebKit as we're using `file://` protocol.
+ if (browserName !== 'chromium') {
+ sentryTest.skip();
+ }
+
+ const url = await getLocalTestPath({ testDir: __dirname });
+ await page.route('**/foo', (route: Route) => route.fulfill({ path: `${__dirname}/dist/index.html` }));
+
+ const initSession = await getFirstSentryEnvelopeRequest(page, url);
+
+ await page.click('#navigate');
+
+ const newSession = await getFirstSentryEnvelopeRequest(page, url);
+
+ expect(newSession).toBeDefined();
+ expect(newSession.init).toBe(true);
+ expect(newSession.errors).toBe(0);
+ expect(newSession.status).toBe('ok');
+ expect(newSession.sid).toBeDefined();
+ expect(initSession.sid).not.toBe(newSession.sid);
+});
diff --git a/packages/integration-tests/suites/sessions/update-session/subject.js b/packages/integration-tests/suites/sessions/update-session/subject.js
new file mode 100644
index 000000000000..04575f47e1bd
--- /dev/null
+++ b/packages/integration-tests/suites/sessions/update-session/subject.js
@@ -0,0 +1,7 @@
+document.getElementById('throw-error').addEventListener('click', () => {
+ throw new Error('test');
+});
+
+document.getElementById('capture-exception').addEventListener('click', () => {
+ Sentry.captureException('test');
+});
diff --git a/packages/integration-tests/suites/sessions/update-session/template.hbs b/packages/integration-tests/suites/sessions/update-session/template.hbs
new file mode 100644
index 000000000000..114ce1f75f83
--- /dev/null
+++ b/packages/integration-tests/suites/sessions/update-session/template.hbs
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/integration-tests/suites/sessions/update-session/test.ts b/packages/integration-tests/suites/sessions/update-session/test.ts
new file mode 100644
index 000000000000..9634e66c360e
--- /dev/null
+++ b/packages/integration-tests/suites/sessions/update-session/test.ts
@@ -0,0 +1,40 @@
+import { expect } from '@playwright/test';
+import { SessionContext } from '@sentry/types';
+
+import { sentryTest } from '../../../utils/fixtures';
+import { getFirstSentryEnvelopeRequest } from '../../../utils/helpers';
+
+sentryTest('should update session when an error is thrown.', async ({ getLocalTestPath, page }) => {
+ const url = await getLocalTestPath({ testDir: __dirname });
+ const pageloadSession = await getFirstSentryEnvelopeRequest(page, url);
+ const updatedSession = (
+ await Promise.all([page.click('#throw-error'), getFirstSentryEnvelopeRequest(page)])
+ )[1];
+
+ expect(pageloadSession).toBeDefined();
+ expect(pageloadSession.init).toBe(true);
+ expect(pageloadSession.errors).toBe(0);
+ expect(updatedSession).toBeDefined();
+ expect(updatedSession.init).toBe(false);
+ expect(updatedSession.errors).toBe(1);
+ expect(updatedSession.status).toBe('ok');
+ expect(pageloadSession.sid).toBe(updatedSession.sid);
+});
+
+sentryTest('should update session when an exception is captured.', async ({ getLocalTestPath, page }) => {
+ const url = await getLocalTestPath({ testDir: __dirname });
+
+ const pageloadSession = await getFirstSentryEnvelopeRequest(page, url);
+ const updatedSession = (
+ await Promise.all([page.click('#capture-exception'), getFirstSentryEnvelopeRequest(page)])
+ )[1];
+
+ expect(pageloadSession).toBeDefined();
+ expect(pageloadSession.init).toBe(true);
+ expect(pageloadSession.errors).toBe(0);
+ expect(updatedSession).toBeDefined();
+ expect(updatedSession.init).toBe(false);
+ expect(updatedSession.errors).toBe(1);
+ expect(updatedSession.status).toBe('ok');
+ expect(pageloadSession.sid).toBe(updatedSession.sid);
+});
diff --git a/packages/integration-tests/utils/helpers.ts b/packages/integration-tests/utils/helpers.ts
index 90365b11228d..84ee3f8b3ddc 100644
--- a/packages/integration-tests/utils/helpers.ts
+++ b/packages/integration-tests/utils/helpers.ts
@@ -43,7 +43,8 @@ async function getSentryRequest(page: Page, url?: string): Promise {
* @return {*} {Promise}
*/
async function getSentryTransactionRequest(page: Page, url?: string): Promise {
- return (await getMultipleSentryTransactionRequests(page, 1, url))[0];
+ // TODO: Remove this and update all usages in favour of `getFirstSentryEnvelopeRequest` and `getMultipleSentryEnvelopeRequests`
+ return (await getMultipleSentryEnvelopeRequests(page, 1, url))[0];
}
/**
@@ -135,15 +136,30 @@ async function getMultipleSentryRequests(page: Page, count: number, url?: string
}
/**
- * Wait and get multiple transaction requests at the given URL, or the current page
+ * Wait and get multiple envelope requests at the given URL, or the current page
*
+ * @template T
* @param {Page} page
* @param {number} count
* @param {string} [url]
- * @return {*} {Promise}
+ * @return {*} {Promise}
+ */
+async function getMultipleSentryEnvelopeRequests(page: Page, count: number, url?: string): Promise {
+ // TODO: This is not currently checking the type of envelope, just casting for now.
+ // We can update this to include optional type-guarding when we have types for Envelope.
+ return getMultipleRequests(page, count, envelopeUrlRegex, envelopeRequestParser, url) as Promise;
+}
+
+/**
+ * Wait and get the first envelope request at the given URL, or the current page
+ *
+ * @template T
+ * @param {Page} page
+ * @param {string} [url]
+ * @return {*} {Promise}
*/
-async function getMultipleSentryTransactionRequests(page: Page, count: number, url?: string): Promise {
- return getMultipleRequests(page, count, envelopeUrlRegex, envelopeRequestParser, url);
+async function getFirstSentryEnvelopeRequest(page: Page, url?: string): Promise {
+ return (await getMultipleSentryEnvelopeRequests(page, 1, url))[0];
}
/**
@@ -166,7 +182,8 @@ async function injectScriptAndGetEvents(page: Page, url: string, scriptPath: str
export {
runScriptInSandbox,
getMultipleSentryRequests,
- getMultipleSentryTransactionRequests,
+ getMultipleSentryEnvelopeRequests,
+ getFirstSentryEnvelopeRequest,
getSentryRequest,
getSentryTransactionRequest,
getSentryEvents,