Skip to content

Commit 1adae56

Browse files
authored
Merge branch 'develop' into upgrade-vite-vitest
2 parents 40bbc53 + 8c4ae52 commit 1adae56

File tree

197 files changed

+2702
-660
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

197 files changed

+2702
-660
lines changed

dev-packages/browser-integration-tests/suites/integrations/captureConsole-attachStackTrace/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ sentryTest(
1919
const errorEvent = events.find(event => event.message === 'console error');
2020
const traceEvent = events.find(event => event.message === 'console trace');
2121
const errorWithErrorEvent = events.find(
22-
event => event.exception && event.exception.values?.[0].value === 'console error with error object',
22+
event => event.exception?.values?.[0].value === 'console error with error object',
2323
);
2424
const traceWithErrorEvent = events.find(
25-
event => event.exception && event.exception.values?.[0].value === 'console trace with error object',
25+
event => event.exception?.values?.[0].value === 'console trace with error object',
2626
);
2727

2828
expect(logEvent).toEqual(

dev-packages/browser-integration-tests/suites/integrations/captureConsole/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,10 @@ sentryTest('it captures console messages correctly', async ({ getLocalTestUrl, p
1717
const errorEvent = events.find(event => event.message === 'console error');
1818
const traceEvent = events.find(event => event.message === 'console trace');
1919
const errorWithErrorEvent = events.find(
20-
event => event.exception && event.exception.values?.[0].value === 'console error with error object',
20+
event => event.exception?.values?.[0].value === 'console error with error object',
2121
);
2222
const traceWithErrorEvent = events.find(
23-
event => event.exception && event.exception.values?.[0].value === 'console trace with error object',
23+
event => event.exception?.values?.[0].value === 'console trace with error object',
2424
);
2525

2626
expect(logEvent).toEqual(

dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/withScope/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({
2222
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
2323
await page.goto(url);
2424

25-
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true);
26-
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false);
25+
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true);
26+
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false);
2727

2828
await page.evaluate(() => {
2929
const Sentry = (window as any).Sentry;

dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/withScope/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({
2222
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
2323
await page.goto(url);
2424

25-
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true);
26-
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false);
25+
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true);
26+
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false);
2727

2828
await page.evaluate(() => {
2929
const Sentry = (window as any).Sentry;

dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/withScope/test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ sentryTest('Flag evaluations in forked scopes are stored separately.', async ({
2222
const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true });
2323
await page.goto(url);
2424

25-
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === true);
26-
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags && event.tags.isForked === false);
25+
const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true);
26+
const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false);
2727

2828
await page.evaluate(() => {
2929
const Sentry = (window as any).Sentry;

dev-packages/browser-integration-tests/suites/old-sdk-interop/acs/getCurrentScope/subject.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const sentryCarrier = window?.__SENTRY__;
44
* Simulate an old pre v8 SDK obtaining the hub from the global sentry carrier
55
* and checking for the hub version.
66
*/
7-
const res = sentryCarrier.acs && sentryCarrier.acs.getCurrentScope();
7+
const res = sentryCarrier.acs?.getCurrentScope();
88

99
// Write back result into the document
1010
document.getElementById('currentScope').innerText = res && 'scope';

dev-packages/browser-integration-tests/suites/old-sdk-interop/hub/isOlderThan/subject.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ const sentryCarrier = window?.__SENTRY__;
44
* Simulate an old pre v8 SDK obtaining the hub from the global sentry carrier
55
* and checking for the hub version.
66
*/
7-
const res = sentryCarrier.hub && sentryCarrier.hub.isOlderThan(7);
7+
const res = sentryCarrier.hub?.isOlderThan(7);
88

99
// Write back result into the document
1010
document.getElementById('olderThan').innerText = res;

dev-packages/browser-integration-tests/suites/replay/captureReplayOffline/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getReplayEvent, shouldSkipReplayTest, waitForReplayRequest } from '../.
55

66
sentryTest('should capture replays offline', async ({ getLocalTestUrl, page }) => {
77
// makeBrowserOfflineTransport is not included in any CDN bundles
8-
if (shouldSkipReplayTest() || (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle'))) {
8+
if (shouldSkipReplayTest() || process.env.PW_BUNDLE?.startsWith('bundle')) {
99
sentryTest.skip();
1010
}
1111

dev-packages/browser-integration-tests/suites/replay/replayIntegrationShim/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sentryTest(
77
async ({ getLocalTestUrl, page, forceFlushReplay }) => {
88
const bundle = process.env.PW_BUNDLE;
99

10-
if (!bundle || !bundle.startsWith('bundle_') || bundle.includes('replay')) {
10+
if (!bundle?.startsWith('bundle_') || bundle.includes('replay')) {
1111
sentryTest.skip();
1212
}
1313

dev-packages/browser-integration-tests/suites/replay/replayShim/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ sentryTest(
77
async ({ getLocalTestUrl, page, forceFlushReplay }) => {
88
const bundle = process.env.PW_BUNDLE;
99

10-
if (!bundle || !bundle.startsWith('bundle_') || bundle.includes('replay')) {
10+
if (!bundle?.startsWith('bundle_') || bundle.includes('replay')) {
1111
sentryTest.skip();
1212
}
1313

dev-packages/browser-integration-tests/suites/tracing/dsc-txn-name-update/test.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,8 +182,5 @@ async function captureErrorAndGetEnvelopeTraceHeader(page: Page): Promise<Partia
182182

183183
const [, errorEnvelopeTraceHeader] = (await errorEventPromise)[0];
184184

185-
// @ts-expect-error - EventEnvelopeHeaders type in (types/envelope.ts) suggests that trace_id is optional,
186-
// which the DynamicSamplingContext type does not permit.
187-
// TODO(v9): We should adjust the EventEnvelopeHeaders type because the trace header always needs to have a trace_id
188185
return errorEnvelopeTraceHeader;
189186
}

dev-packages/browser-integration-tests/suites/transport/offline/queued/test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ function delay(ms: number) {
1010

1111
sentryTest('should queue and retry events when they fail to send', async ({ getLocalTestUrl, page }) => {
1212
// makeBrowserOfflineTransport is not included in any CDN bundles
13-
if (process.env.PW_BUNDLE && process.env.PW_BUNDLE.startsWith('bundle')) {
13+
if (process.env.PW_BUNDLE?.startsWith('bundle')) {
1414
sentryTest.skip();
1515
}
1616

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# production
12+
/build
13+
14+
# misc
15+
.DS_Store
16+
.env.local
17+
.env.development.local
18+
.env.test.local
19+
.env.production.local
20+
21+
npm-debug.log*
22+
yarn-debug.log*
23+
yarn-error.log*
24+
25+
/test-results/
26+
/playwright-report/
27+
/playwright/.cache/
28+
29+
!*.d.ts
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
@sentry:registry=http://127.0.0.1:4873
2+
@sentry-internal:registry=http://127.0.0.1:4873
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"name": "react-create-browser-router-test",
3+
"version": "0.1.0",
4+
"private": true,
5+
"dependencies": {
6+
"@sentry/react": "latest || *",
7+
"@types/node": "^18.19.1",
8+
"@types/react": "18.0.0",
9+
"@types/react-dom": "18.0.0",
10+
"react": "18.2.0",
11+
"react-dom": "18.2.0",
12+
"react-router-dom": "^6.4.1",
13+
"react-scripts": "5.0.1",
14+
"typescript": "~5.0.0"
15+
},
16+
"scripts": {
17+
"build": "react-scripts build",
18+
"start": "serve -s build",
19+
"test": "playwright test",
20+
"clean": "npx rimraf node_modules pnpm-lock.yaml",
21+
"test:build": "pnpm install && pnpm build",
22+
"test:build-canary": "pnpm install && pnpm add react@canary react-dom@canary && pnpm build",
23+
"test:assert": "pnpm test"
24+
},
25+
"eslintConfig": {
26+
"extends": ["react-app", "react-app/jest"]
27+
},
28+
"browserslist": {
29+
"production": [">0.2%", "not dead", "not op_mini all"],
30+
"development": ["last 1 chrome version", "last 1 firefox version", "last 1 safari version"]
31+
},
32+
"devDependencies": {
33+
"@playwright/test": "^1.44.1",
34+
"@sentry-internal/test-utils": "link:../../../test-utils",
35+
"serve": "14.0.1"
36+
},
37+
"volta": {
38+
"extends": "../../package.json"
39+
}
40+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { getPlaywrightConfig } from '@sentry-internal/test-utils';
2+
3+
const config = getPlaywrightConfig({
4+
startCommand: `pnpm start`,
5+
});
6+
7+
export default config;
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="utf-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1" />
6+
<meta name="theme-color" content="#000000" />
7+
<meta name="description" content="Web site created using create-react-app" />
8+
<title>React App</title>
9+
</head>
10+
<body>
11+
<noscript>You need to enable JavaScript to run this app.</noscript>
12+
<div id="root"></div>
13+
<!--
14+
This HTML file is a template.
15+
If you open it directly in the browser, you will see an empty page.
16+
17+
You can add webfonts, meta tags, or analytics to this file.
18+
The build step will place the bundled scripts into the <body> tag.
19+
20+
To begin the development, run `npm start` or `yarn start`.
21+
To create a production bundle, use `npm run build` or `yarn build`.
22+
-->
23+
</body>
24+
</html>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
interface Window {
2+
recordedTransactions?: string[];
3+
capturedExceptionId?: string;
4+
sentryReplayId?: string;
5+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import * as Sentry from '@sentry/react';
2+
import React from 'react';
3+
import ReactDOM from 'react-dom/client';
4+
import {
5+
RouterProvider,
6+
createBrowserRouter,
7+
createRoutesFromChildren,
8+
matchRoutes,
9+
useLocation,
10+
useNavigationType,
11+
} from 'react-router-dom';
12+
import Index from './pages/Index';
13+
import User from './pages/User';
14+
15+
const replay = Sentry.replayIntegration();
16+
17+
Sentry.init({
18+
// environment: 'qa', // dynamic sampling bias to keep transactions
19+
dsn: process.env.REACT_APP_E2E_TEST_DSN,
20+
integrations: [
21+
Sentry.reactRouterV6BrowserTracingIntegration({
22+
useEffect: React.useEffect,
23+
useLocation,
24+
useNavigationType,
25+
createRoutesFromChildren,
26+
matchRoutes,
27+
}),
28+
replay,
29+
],
30+
// We recommend adjusting this value in production, or using tracesSampler
31+
// for finer control
32+
tracesSampleRate: 1.0,
33+
release: 'e2e-test',
34+
35+
tunnel: 'http://localhost:3031',
36+
37+
// Always capture replays, so we can test this properly
38+
replaysSessionSampleRate: 1.0,
39+
replaysOnErrorSampleRate: 0.0,
40+
41+
debug: !!process.env.DEBUG,
42+
});
43+
44+
const sentryCreateBrowserRouter = Sentry.wrapCreateBrowserRouterV6(createBrowserRouter);
45+
46+
const router = sentryCreateBrowserRouter(
47+
[
48+
{
49+
path: '/',
50+
element: <Index />,
51+
},
52+
{
53+
path: '/user/:id',
54+
element: <User />,
55+
},
56+
],
57+
{
58+
// We're testing whether this option is avoided in the integration
59+
// We expect this to be ignored
60+
initialEntries: ['/user/1'],
61+
},
62+
);
63+
64+
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
65+
66+
root.render(<RouterProvider router={router} />);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// biome-ignore lint/nursery/noUnusedImports: Need React import for JSX
2+
import * as React from 'react';
3+
import { Link } from 'react-router-dom';
4+
5+
const Index = () => {
6+
return (
7+
<>
8+
<input
9+
type="button"
10+
value="Capture Exception"
11+
id="exception-button"
12+
onClick={() => {
13+
throw new Error('I am an error!');
14+
}}
15+
/>
16+
<Link to="/user/5" id="navigation">
17+
navigate
18+
</Link>
19+
</>
20+
);
21+
};
22+
23+
export default Index;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// biome-ignore lint/nursery/noUnusedImports: Need React import for JSX
2+
import * as React from 'react';
3+
4+
const User = () => {
5+
return <p>I am a blank page :)</p>;
6+
};
7+
8+
export default User;
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/// <reference types="react-scripts" />
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
import { startEventProxyServer } from '@sentry-internal/test-utils';
2+
3+
startEventProxyServer({
4+
port: 3031,
5+
proxyServerName: 'react-create-browser-router',
6+
});
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import { expect, test } from '@playwright/test';
2+
import { waitForError } from '@sentry-internal/test-utils';
3+
4+
test('Captures exception correctly', async ({ page }) => {
5+
const errorEventPromise = waitForError('react-create-browser-router', event => {
6+
return !event.type && event.exception?.values?.[0]?.value === 'I am an error!';
7+
});
8+
9+
await page.goto('/');
10+
11+
const exceptionButton = page.locator('id=exception-button');
12+
await exceptionButton.click();
13+
14+
const errorEvent = await errorEventPromise;
15+
16+
expect(errorEvent.exception?.values).toHaveLength(1);
17+
expect(errorEvent.exception?.values?.[0]?.value).toBe('I am an error!');
18+
19+
expect(errorEvent.request).toEqual({
20+
headers: expect.any(Object),
21+
url: 'http://localhost:3030/',
22+
});
23+
24+
expect(errorEvent.transaction).toEqual('/');
25+
26+
expect(errorEvent.contexts?.trace).toEqual({
27+
trace_id: expect.stringMatching(/[a-f0-9]{32}/),
28+
span_id: expect.stringMatching(/[a-f0-9]{16}/),
29+
});
30+
});

0 commit comments

Comments
 (0)