Skip to content

Commit 2d26ee8

Browse files
committed
implement
1 parent 528474a commit 2d26ee8

4 files changed

Lines changed: 56 additions & 95 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { test } from '@playwright/test';
2+
import { waitForTransaction } from '@sentry-internal/test-utils';
3+
import { APP_NAME } from '../constants';
4+
5+
test.describe('low-quality transaction filter', () => {
6+
test('does not send a server transaction for /__manifest? requests', async ({ page }) => {
7+
// Positive anchor: the navigation transaction we know the framework emits
8+
const navigationPromise = waitForTransaction(APP_NAME, async transactionEvent => {
9+
return (
10+
transactionEvent.transaction === '/performance/ssr' && transactionEvent.contexts?.trace?.op === 'navigation'
11+
);
12+
});
13+
14+
// Negative: throw if a server txn for /__manifest? sneaks through
15+
waitForTransaction(APP_NAME, async evt => {
16+
if (evt.transaction?.match(/GET \/__manifest\?/)) {
17+
throw new Error('Filtered manifest server transaction should not be sent');
18+
}
19+
return false;
20+
});
21+
22+
await page.goto('/performance'); // pageload
23+
await page.waitForTimeout(1000);
24+
await page.getByRole('link', { name: 'SSR Page' }).click(); // navigation → fetches /__manifest?
25+
26+
await navigationPromise;
27+
await page.waitForTimeout(1000); // give late server txns a chance to flush
28+
});
29+
});

packages/react-router/src/server/sdk.ts

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,15 @@ import { reactRouterServerIntegration } from './integration/reactRouterServer';
1010
* @param options The options for the SDK.
1111
*/
1212
export function getDefaultReactRouterServerIntegrations(options: NodeOptions): Integration[] {
13-
return [
14-
...getNodeDefaultIntegrations(options),
15-
reactRouterServerIntegration(),
16-
];
13+
return [...getNodeDefaultIntegrations(options), reactRouterServerIntegration()];
1714
}
1815

19-
const LOW_QUALITY_TRANSACTIONS_REGEXES = [/GET \/node_modules\//, /GET \/favicon\.ico/, /GET \/@id\//, /GET \/__manifest\?/];
16+
const LOW_QUALITY_TRANSACTIONS_REGEXES = [
17+
/GET \/node_modules\//,
18+
/GET \/favicon\.ico/,
19+
/GET \/@id\//,
20+
/GET \/__manifest\?/,
21+
];
2022

2123
/**
2224
* Initializes the server side of the React Router SDK
@@ -27,10 +29,7 @@ export function init(options: NodeOptions): NodeClient | undefined {
2729
defaultIntegrations: getDefaultReactRouterServerIntegrations(options),
2830
};
2931

30-
opts.ignoreSpans = [
31-
...(opts.ignoreSpans || []),
32-
...LOW_QUALITY_TRANSACTIONS_REGEXES,
33-
];
32+
opts.ignoreSpans = [...(opts.ignoreSpans || []), ...LOW_QUALITY_TRANSACTIONS_REGEXES];
3433

3534
DEBUG_BUILD && debug.log('Initializing SDK...');
3635

packages/react-router/test/server/lowQualityTransactionsFilterIntegration.test.ts

Lines changed: 0 additions & 67 deletions
This file was deleted.

packages/react-router/test/server/sdk.test.ts

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { NodeClient } from '@sentry/node';
33
import * as SentryNode from '@sentry/node';
44
import { SDK_VERSION } from '@sentry/node';
55
import { afterEach, describe, expect, it, vi } from 'vitest';
6-
import * as LowQualityModule from '../../src/server/integration/lowQualityTransactionsFilterIntegration';
76
import { init as reactRouterInit } from '../../src/server/sdk';
87

98
const nodeInit = vi.spyOn(SentryNode, 'init');
@@ -48,28 +47,29 @@ describe('React Router server SDK', () => {
4847
expect(client).not.toBeUndefined();
4948
});
5049

51-
it('adds the low quality transactions filter integration by default', () => {
52-
const filterSpy = vi.spyOn(LowQualityModule, 'lowQualityTransactionsFilterIntegration');
53-
54-
reactRouterInit({
55-
dsn: 'https://public@dsn.ingest.sentry.io/1337',
56-
});
57-
58-
expect(filterSpy).toHaveBeenCalled();
59-
60-
expect(nodeInit).toHaveBeenCalledTimes(1);
61-
const initOptions = nodeInit.mock.calls[0]?.[0];
50+
it('configures ignoreSpans to drop low-quality transactions', () => {
51+
reactRouterInit({});
6252

63-
expect(initOptions).toBeDefined();
53+
expect(nodeInit).toHaveBeenCalledWith(
54+
expect.objectContaining({
55+
ignoreSpans: expect.arrayContaining([
56+
/GET \/node_modules\//,
57+
/GET \/favicon\.ico/,
58+
/GET \/@id\//,
59+
/GET \/__manifest\?/,
60+
]),
61+
}),
62+
);
63+
});
6464

65-
const defaultIntegrations = initOptions?.defaultIntegrations as Integration[];
66-
expect(Array.isArray(defaultIntegrations)).toBe(true);
65+
it('preserves user-provided ignoreSpans entries', () => {
66+
reactRouterInit({ ignoreSpans: [/keep-me/] });
6767

68-
const filterIntegration = defaultIntegrations.find(
69-
integration => integration.name === 'LowQualityTransactionsFilter',
68+
expect(nodeInit).toHaveBeenCalledWith(
69+
expect.objectContaining({
70+
ignoreSpans: expect.arrayContaining([/keep-me/]),
71+
}),
7072
);
71-
72-
expect(filterIntegration).toBeDefined();
7373
});
7474

7575
it('adds reactRouterServer integration by default', () => {

0 commit comments

Comments
 (0)