Skip to content

Commit 5bf058a

Browse files
committed
test(nextjs): Add NextJS server-side E2E tests.
1 parent 461afdf commit 5bf058a

File tree

9 files changed

+103
-15
lines changed

9 files changed

+103
-15
lines changed

packages/e2e-tests/test-applications/create-next-app/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
"build": "next build",
88
"start": "next start",
99
"lint": "next lint",
10-
"test": "TEST_MODE=build playwright test",
10+
"test": "test:prod && test:dev",
11+
"test:prod": "TEST_MODE=prod playwright test",
1112
"test:dev": "TEST_MODE=dev playwright test"
1213
},
1314
"dependencies": {
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import * as Sentry from '@sentry/nextjs';
2+
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
3+
import type { NextApiRequest, NextApiResponse } from 'next';
4+
5+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
6+
const exceptionId = Sentry.captureException(new Error('This is an error'));
7+
8+
await Sentry.flush(2000);
9+
10+
res.status(200).json({ exceptionId });
11+
}

packages/e2e-tests/test-applications/create-next-app/pages/api/hello.ts

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2+
import type { NextApiRequest, NextApiResponse } from 'next';
3+
import * as Sentry from '@sentry/nextjs';
4+
5+
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
6+
await Sentry.flush(2000);
7+
8+
res.status(200).json({
9+
transactionIds: global.transactionIds,
10+
});
11+
}

packages/e2e-tests/test-applications/create-next-app/playwright.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ const config: PlaywrightTestConfig = {
6161

6262
/* Run your local dev server before starting the tests */
6363
webServer: {
64-
command: process.env.TEST_MODE === 'build' ? 'yarn start' : 'yarn dev',
64+
command: process.env.TEST_MODE === 'prod' ? 'yarn start' : 'yarn dev',
6565
port: 3000,
6666
},
6767
};

packages/e2e-tests/test-applications/create-next-app/sentry.server.config.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44

55
import * as Sentry from '@sentry/nextjs';
66

7+
declare global {
8+
namespace globalThis {
9+
var transactionIds: [string | undefined];
10+
var exceptionId: string | undefined;
11+
}
12+
}
13+
714
Sentry.init({
815
dsn: process.env.NEXT_PUBLIC_E2E_TEST_DSN,
916
// Adjust this value in production, or use tracesSampler for greater control
@@ -13,3 +20,16 @@ Sentry.init({
1320
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
1421
// that it will also get attached to your source maps
1522
});
23+
24+
Sentry.addGlobalEventProcessor(event => {
25+
global.transactionIds = global.transactionIds || [];
26+
27+
if (event.type === 'transaction') {
28+
const eventId = event.event_id;
29+
if (eventId) {
30+
global.transactionIds.push(eventId);
31+
}
32+
}
33+
34+
return event;
35+
});

packages/e2e-tests/test-applications/create-next-app/test-recipe.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"buildCommand": "yarn install --pure-lockfile && npx playwright install && yarn build",
55
"tests": [
66
{
7-
"testName": "Playwright tests - Build Mode",
8-
"testCommand": "yarn test"
7+
"testName": "Playwright tests - Prod Mode",
8+
"testCommand": "yarn test:prod"
99
},
1010
{
1111
"testName": "Playwright tests - Dev Mode",

packages/e2e-tests/test-applications/create-next-app/tests/client/behaviour.test.ts renamed to packages/e2e-tests/test-applications/create-next-app/tests/behaviour-client.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ const sentryTestOrgSlug = process.env.E2E_TEST_SENTRY_ORG_SLUG;
66
const sentryTestProject = process.env.E2E_TEST_SENTRY_TEST_PROJECT;
77
const EVENT_POLLING_TIMEOUT = 30_000;
88

9-
test('Sends an exception to Sentry', async ({ page, baseURL }) => {
9+
test('Sends a client-side exception to Sentry', async ({ page }) => {
1010
await page.goto('/');
1111

1212
const exceptionButton = page.locator('id=exception-button');
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
import { test, expect } from '@playwright/test';
2+
import axios from 'axios';
3+
4+
const authToken = process.env.E2E_TEST_AUTH_TOKEN;
5+
const sentryTestOrgSlug = process.env.E2E_TEST_SENTRY_ORG_SLUG;
6+
const sentryTestProject = process.env.E2E_TEST_SENTRY_TEST_PROJECT;
7+
const EVENT_POLLING_TIMEOUT = 30_000;
8+
9+
test('Sends a server-side exception to Sentry', async ({ baseURL }) => {
10+
const { data } = await axios.get(`${baseURL}api/error`);
11+
const { exceptionId } = data;
12+
13+
console.log(`Polling for error eventId: ${exceptionId}`);
14+
15+
expect
16+
.poll(
17+
async () => {
18+
const response = await axios.get(
19+
`https://sentry.io/api/0/projects/${sentryTestOrgSlug}/${sentryTestProject}/events/${exceptionId}/`,
20+
{ headers: { Authorization: `Bearer ${authToken}` } },
21+
);
22+
return response.status;
23+
},
24+
{ timeout: EVENT_POLLING_TIMEOUT },
25+
)
26+
.toBe(200);
27+
});
28+
29+
test('Sends server-side transactions to Sentry', async ({ baseURL }) => {
30+
const { data } = await axios.get(`${baseURL}api/success`);
31+
const { transactionIds } = data;
32+
33+
console.log(`Polling for transaction eventIds: ${JSON.stringify(transactionIds)}`);
34+
35+
await Promise.all(
36+
transactionIds.map(async (transactionId: string | undefined) => {
37+
if (!transactionId) {
38+
return;
39+
}
40+
41+
await expect
42+
.poll(
43+
async () => {
44+
const response = await axios.get(
45+
`https://sentry.io/api/0/projects/${sentryTestOrgSlug}/${sentryTestProject}/events/${transactionId}/`,
46+
{ headers: { Authorization: `Bearer ${authToken}` } },
47+
);
48+
return response.status;
49+
},
50+
{ timeout: EVENT_POLLING_TIMEOUT },
51+
)
52+
.toBe(200);
53+
}),
54+
);
55+
});

0 commit comments

Comments
 (0)