Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
fda52cb
Add error boundary to Rum-Nextjs
BeltranBulbarellaDD Mar 17, 2026
48f6769
Add e2e tests
BeltranBulbarellaDD Mar 17, 2026
3cf211b
Disallow side effect from React, CI fixes
BeltranBulbarellaDD Mar 17, 2026
e0d3dee
fix rum-react version
BeltranBulbarellaDD Mar 17, 2026
cd405c3
Remove import
BeltranBulbarellaDD Mar 17, 2026
f4aedea
Add error boundary to Rum-Nextjs
BeltranBulbarellaDD Mar 17, 2026
676d170
build
BeltranBulbarellaDD Mar 17, 2026
bb905f7
add skill
BeltranBulbarellaDD Mar 18, 2026
c7e7ca7
Fix tests
BeltranBulbarellaDD Mar 18, 2026
6d7f023
format
BeltranBulbarellaDD Mar 18, 2026
818eab3
Remove internal file, add firefox timeout, update nextjs dependencies.
BeltranBulbarellaDD Mar 19, 2026
58eb95b
Remove unused file
BeltranBulbarellaDD Mar 19, 2026
3cb098b
Skip Firefox test on pages router error, add internal types for error…
BeltranBulbarellaDD Mar 20, 2026
9254f01
Prevent duplicate error name
BeltranBulbarellaDD Mar 20, 2026
aaf0066
Merge branch 'main' into beltran.bulbarella/nextjs_pages__router_error
BeltranBulbarellaDD Mar 23, 2026
7807ff3
Simplify Nextjs plugin test initialization
BeltranBulbarellaDD Mar 23, 2026
e81b850
Merge branch 'main' into beltran.bulbarella/nextjs_pages__router_error
BeltranBulbarellaDD Mar 23, 2026
5572aa3
Remove internal.d.ts, add topological pack
BeltranBulbarellaDD Mar 23, 2026
7a91c27
Test
BeltranBulbarellaDD Mar 23, 2026
b4185ae
Merge branch 'main' into beltran.bulbarella/nextjs_pages__router_error
BeltranBulbarellaDD Mar 24, 2026
6aa5690
Fix conflict
BeltranBulbarellaDD Mar 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions eslint-local-rules/disallowSideEffects.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const pathsWithSideEffect = new Set([
const packagesWithoutSideEffect = new Set([
'@datadog/browser-core',
'@datadog/browser-rum-core',
'@datadog/browser-rum-react/internal',
'react',
'react-router-dom',
'vue',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"build:apps": "node scripts/build/build-test-apps.ts",
"build:docs:json": "typedoc --logLevel Verbose --json ./generated-docs.json",
"build:docs:html": "typedoc --out ./generated-docs",
"pack": "yarn workspaces foreach --all --parallel --include '@datadog/*' exec yarn pack",
"pack": "yarn workspaces foreach --all --parallel --topological --include '@datadog/*' exec yarn pack",
"format": "prettier --check .",
"lint": "NODE_OPTIONS='--max-old-space-size=4096' eslint .",
"typecheck": "tsc -b --noEmit true",
Expand Down
6 changes: 4 additions & 2 deletions packages/rum-nextjs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
},
"dependencies": {
"@datadog/browser-core": "6.31.0",
"@datadog/browser-rum-core": "6.31.0"
"@datadog/browser-rum-core": "6.31.0",
"@datadog/browser-rum-react": "6.31.0"
},
"peerDependencies": {
"next": ">=13.0.0",
Expand All @@ -36,6 +37,7 @@
"devDependencies": {
"@types/react": "19.2.11",
"next": "15.5.10",
"react": "19.2.4"
"react": "19.2.4",
"react-dom": "19.2.4"
}
}
42 changes: 42 additions & 0 deletions packages/rum-nextjs/src/domain/error/errorBoundary.spec.tsx
Comment thread
BeltranBulbarellaDD marked this conversation as resolved.
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react'

import { disableJasmineUncaughtExceptionTracking, ignoreConsoleLogs } from '@datadog/browser-core/test'
import { appendComponent } from '../../../../rum-react/test/appendComponent'
import { initReactOldBrowsersSupport } from '../../../../rum-react/test/reactOldBrowsersSupport'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test imports appendComponent and initReactOldBrowsersSupport via relative paths across package boundaries (../../../../rum-react/test/...). Is there a plan to extract these into a shared test utility, or is this the accepted pattern? It works, just looks fragile if packages ever move around.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. Maybe we can expose them as shared utility, that would be better.

import { initializeNextjsPlugin } from '../../../test/initializeNextjsPlugin'
import { ErrorBoundary } from './errorBoundary'

// Component behavior (renders children, fallback, resetError) is tested via createErrorBoundary
// in packages/rum-react/src/domain/error/errorBoundary.spec.tsx

describe('NextjsErrorBoundary', () => {
it('reports the error through addNextjsError', () => {
ignoreConsoleLogs('error', 'Error: error')
disableJasmineUncaughtExceptionTracking()
initReactOldBrowsersSupport()

const addErrorSpy = jasmine.createSpy()
initializeNextjsPlugin({ addError: addErrorSpy })
const originalError = new Error('error')
const ComponentSpy = jasmine.createSpy().and.throwError(originalError)
;(ComponentSpy as any).displayName = 'ComponentSpy'

appendComponent(
<ErrorBoundary fallback={() => null}>
<ComponentSpy />
</ErrorBoundary>
)

expect(addErrorSpy).toHaveBeenCalledOnceWith(
jasmine.objectContaining({
error: originalError,
handlingStack: jasmine.any(String),
startClocks: jasmine.any(Object),
context: jasmine.objectContaining({
framework: 'nextjs',
}),
componentStack: jasmine.stringContaining('ComponentSpy'),
})
)
})
})
22 changes: 22 additions & 0 deletions packages/rum-nextjs/src/domain/error/errorBoundary.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client'
import { createErrorBoundary } from '@datadog/browser-rum-react/internal'
export type { ErrorBoundaryFallback, ErrorBoundaryProps } from '@datadog/browser-rum-react/internal'
import { addNextjsError } from './addNextjsError'

/**
* ErrorBoundary component to report React errors to Datadog using the Next.js error context.
*
* For more advanced error handling, you can use the {@link addNextjsError} function.
*
* @category Error
* @example
* ```ts
* import { ErrorBoundary } from '@datadog/browser-rum-nextjs'
*
* <ErrorBoundary fallback={() => null}>
* <Component />
* </ErrorBoundary>
* ```
*/
// eslint-disable-next-line local-rules/disallow-side-effects
export const ErrorBoundary = createErrorBoundary(addNextjsError)
2 changes: 2 additions & 0 deletions packages/rum-nextjs/src/entries/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ export type { NextjsPlugin } from '../domain/nextjsPlugin'
export { DatadogAppRouter } from '../domain/nextJSRouter/datadogAppRouter'
export { DatadogPagesRouter } from '../domain/nextJSRouter/datadogPagesRouter'
export { addNextjsError } from '../domain/error/addNextjsError'
export { ErrorBoundary } from '../domain/error/errorBoundary'
Comment thread
BeltranBulbarellaDD marked this conversation as resolved.
export type { ErrorBoundaryFallback, ErrorBoundaryProps } from '../domain/error/errorBoundary'
21 changes: 8 additions & 13 deletions test/apps/angular-app/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -296,42 +296,37 @@ __metadata:

"@datadog/browser-core@file:../../../packages/core/package.tgz::locator=angular-app%40workspace%3A.":
version: 6.31.0
resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=d110af&locator=angular-app%40workspace%3A."
checksum: 10c0/1e3797a56310fde499578396bd2594c4e0ac891610e7d57ddac2164a8c29a97177b3eac938f6a8480192bb31b5d798acaf2ea26de1778047d43c010ff0124dc0
resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=6201e3&locator=angular-app%40workspace%3A."
checksum: 10c0/a019713374971a2dd35c63318cecd76e38d08348a24ca5b88abb8fca8501d17589e187bd4e68c7358f3523dd3fd08d110b307647854a620b0f3371f2c7db14ca
languageName: node
linkType: hard

"@datadog/browser-rum-angular@file:../../../packages/rum-angular/package.tgz::locator=angular-app%40workspace%3A.":
version: 0.0.0
resolution: "@datadog/browser-rum-angular@file:../../../packages/rum-angular/package.tgz#../../../packages/rum-angular/package.tgz::hash=1db391&locator=angular-app%40workspace%3A."
resolution: "@datadog/browser-rum-angular@file:../../../packages/rum-angular/package.tgz#../../../packages/rum-angular/package.tgz::hash=004229&locator=angular-app%40workspace%3A."
dependencies:
"@datadog/browser-core": "npm:6.31.0"
"@datadog/browser-rum-core": "npm:6.31.0"
peerDependencies:
"@angular/core": ">=15 <=21"
"@angular/router": ">=15 <=21"
rxjs: ">=7"
peerDependenciesMeta:
"@angular/core":
optional: true
"@angular/router":
optional: true
checksum: 10c0/837488f8f27aee3c58e0be4f91039b2de9c3bc00e655f6f65bd5992c1101443ae48fbeedc68c95ef4281535c3a4de8c3e3073974b2938ebb493cf23e3a91f5a6
checksum: 10c0/ec9054d51805f45cb4618bcbc6fa00049ba5d1597048aa3c354aea14a15a06275ee0ba06b3de7d77fbd0d2f009f74159a88e10f2f6b9e629eeed0a5ca30a27ae
languageName: node
linkType: hard

"@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz::locator=angular-app%40workspace%3A.":
version: 6.31.0
resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=638808&locator=angular-app%40workspace%3A."
resolution: "@datadog/browser-rum-core@file:../../../packages/rum-core/package.tgz#../../../packages/rum-core/package.tgz::hash=0334b6&locator=angular-app%40workspace%3A."
dependencies:
"@datadog/browser-core": "npm:6.31.0"
checksum: 10c0/f57c5d9fdbc7243f373afba6912bb75a90f3b65ab036750a858aa7776ed30b8921e456eff32a02e7dc021c192cd7bc220ea7b124459eacb7685c5c5ba0cca1c5
checksum: 10c0/3ece55e0ca0bc0691fd91c557433c806e2871b56e3a0008c01b6e369809c9130fa384952b22ee6464d49d182d3e4e5bd66f51b6b629d4024d6e482f7e64d13c8
languageName: node
linkType: hard

"@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=angular-app%40workspace%3A.":
version: 6.31.0
resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=920d70&locator=angular-app%40workspace%3A."
resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=033900&locator=angular-app%40workspace%3A."
dependencies:
"@datadog/browser-core": "npm:6.31.0"
"@datadog/browser-rum-core": "npm:6.31.0"
Expand All @@ -340,7 +335,7 @@ __metadata:
peerDependenciesMeta:
"@datadog/browser-logs":
optional: true
checksum: 10c0/135a2cdf999ea9505e08031ae7069f4d6a236a88e6203ef7105c784a77ae23a23fbabc648d793305dcb4b960cbe4a535fab2d688748efb5824137597f4de84b5
checksum: 10c0/ac0080efb7f664a5664162a64e618b885d2c4d2d06426db0ad076c855dd02cbc84f1ba6fc30913db8db74d50a511d0a0a62ba1ad7bb9e8de5c3ef0c03e3f9c56
languageName: node
linkType: hard

Expand Down
35 changes: 35 additions & 0 deletions test/apps/nextjs/pages/pages-router/error-test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { ErrorBoundary } from '@datadog/browser-rum-nextjs'
import type { ErrorBoundaryFallback } from '@datadog/browser-rum-nextjs'
import { useState } from 'react'
import Link from 'next/link'

function ErrorThrower() {
const [shouldThrow, setShouldThrow] = useState(false)
if (shouldThrow) throw new Error('Pages Router error from NextjsErrorBoundary')
return (
<button data-testid="trigger-error" onClick={() => setShouldThrow(true)}>
Trigger Error
</button>
)
}

const ErrorFallback: ErrorBoundaryFallback = ({ error, resetError }) => (
<div data-testid="error-boundary">
<p>{error.message}</p>
<button data-testid="reset-error" onClick={resetError}>
Reset
</button>
</div>
)

export default function ErrorTestPage() {
return (
<div>
<Link href="/pages-router">← Back to Home</Link>
<h1>Error Test</h1>
<ErrorBoundary fallback={ErrorFallback}>
<ErrorThrower />
</ErrorBoundary>
</div>
)
}
3 changes: 3 additions & 0 deletions test/apps/nextjs/pages/pages-router/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ export default function HomePage() {
<li>
<Link href="/pages-router/guides/123">Go to Guides 123</Link>
</li>
<li>
<Link href="/pages-router/error-test">Go to Error Test</Link>
</li>
</ul>
</div>
)
Expand Down
12 changes: 9 additions & 3 deletions test/apps/nextjs/pages/pages-router/user/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ export default function UserPage() {
<Link href="/pages-router">← Back to Home</Link>
<h1>User {id}</h1>
<p>This is a dynamic route testing view name normalization.</p>
<Link href="/pages-router/user/999?admin=true">Go to User 999</Link>
<Link href={`/pages-router/user/${id}?admin=false`}>Change query params</Link>
<Link href={`/pages-router/user/${id}#section`}>Go to Section</Link>
<div>
<Link href="/pages-router/user/999?admin=true">Go to User 999</Link>
</div>
<div>
<Link href={`/pages-router/user/${id}?admin=false`}>Change query params</Link>
</div>
<div>
<Link href={`/pages-router/user/${id}#section`}>Go to Section</Link>
</div>
</div>
)
}
27 changes: 14 additions & 13 deletions test/apps/nextjs/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ __metadata:

"@datadog/browser-core@file:../../../packages/core/package.tgz::locator=nextjs%40workspace%3A.":
version: 6.31.0
resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=d35e3a&locator=nextjs%40workspace%3A."
checksum: 10c0/e35c0d98c72fa3ed46dcbd42615c156fcb13f4622681906145aac91630c291adc7a166861568e61a09f6301baed1adaf5c95b675b9407c72fbe936129f305253
resolution: "@datadog/browser-core@file:../../../packages/core/package.tgz#../../../packages/core/package.tgz::hash=6201e3&locator=nextjs%40workspace%3A."
checksum: 10c0/a019713374971a2dd35c63318cecd76e38d08348a24ca5b88abb8fca8501d17589e187bd4e68c7358f3523dd3fd08d110b307647854a620b0f3371f2c7db14ca
languageName: node
linkType: hard

Expand All @@ -23,10 +23,11 @@ __metadata:

"@datadog/browser-rum-nextjs@file:../../../packages/rum-nextjs/package.tgz::locator=nextjs%40workspace%3A.":
version: 0.0.0
resolution: "@datadog/browser-rum-nextjs@file:../../../packages/rum-nextjs/package.tgz#../../../packages/rum-nextjs/package.tgz::hash=0643d8&locator=nextjs%40workspace%3A."
resolution: "@datadog/browser-rum-nextjs@file:../../../packages/rum-nextjs/package.tgz#../../../packages/rum-nextjs/package.tgz::hash=33a720&locator=nextjs%40workspace%3A."
dependencies:
"@datadog/browser-core": "npm:6.31.0"
"@datadog/browser-rum-core": "npm:6.31.0"
"@datadog/browser-rum-react": "npm:6.31.0"
peerDependencies:
next: ">=13.0.0"
react: ">=18.0.0"
Expand All @@ -35,13 +36,13 @@ __metadata:
optional: true
react:
optional: true
checksum: 10c0/8f1ae5ce76730608a77b924f6c25cc9b325f314621fa1d03ed29a9a6d6a084dcfa61e9a36bb1f2005ff5939b5137dbe11ff5b27af09d41b3a5dcdbc0e0ef4ace
checksum: 10c0/5bd3c94fa2fa71d0c19626b8a8cdfa933da6bd0626a99abbd5d0bb07374c9bca9554eba05c427baf35fe0e0fbf4f891dd741822908a4cebe30ca4ea502ae9355
languageName: node
linkType: hard

"@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz::locator=nextjs%40workspace%3A.":
version: 6.31.0
resolution: "@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz#../../../packages/rum-react/package.tgz::hash=2dd471&locator=nextjs%40workspace%3A."
resolution: "@datadog/browser-rum-react@file:../../../packages/rum-react/package.tgz#../../../packages/rum-react/package.tgz::hash=ff7bfc&locator=nextjs%40workspace%3A."
dependencies:
"@datadog/browser-core": "npm:6.31.0"
"@datadog/browser-rum-core": "npm:6.31.0"
Expand All @@ -66,7 +67,7 @@ __metadata:

"@datadog/browser-rum@file:../../../packages/rum/package.tgz::locator=nextjs%40workspace%3A.":
version: 6.31.0
resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=439f60&locator=nextjs%40workspace%3A."
resolution: "@datadog/browser-rum@file:../../../packages/rum/package.tgz#../../../packages/rum/package.tgz::hash=033900&locator=nextjs%40workspace%3A."
dependencies:
"@datadog/browser-core": "npm:6.31.0"
"@datadog/browser-rum-core": "npm:6.31.0"
Expand All @@ -75,7 +76,7 @@ __metadata:
peerDependenciesMeta:
"@datadog/browser-logs":
optional: true
checksum: 10c0/be73607a3c5602407ad824b7e149c633c9bfebf3e6fd543b56598a4067afcbbf28e6324be430b6e846aef8bee0c588e4bd258ae3671a1419a3fdaa31efa5e3f1
checksum: 10c0/ac0080efb7f664a5664162a64e618b885d2c4d2d06426db0ad076c855dd02cbc84f1ba6fc30913db8db74d50a511d0a0a62ba1ad7bb9e8de5c3ef0c03e3f9c56
languageName: node
linkType: hard

Expand Down Expand Up @@ -415,18 +416,18 @@ __metadata:
linkType: hard

"baseline-browser-mapping@npm:^2.8.3":
version: 2.10.7
resolution: "baseline-browser-mapping@npm:2.10.7"
version: 2.10.8
resolution: "baseline-browser-mapping@npm:2.10.8"
bin:
baseline-browser-mapping: dist/cli.cjs
checksum: 10c0/fe2988088ede5a2dc7936f0a718d4b500b2a28a7ee3e11e2a3844a9444dd217a95a070c00508d8130da73c4fe576d677b21844bc078f6cd7867fb0e1be60caf0
checksum: 10c0/a77882e8ac37a900a9a0757b9bf4e50f407829ed17ee7630273ab5da0ae10d9c64ed4c5a1e03afb3490e39713440092417ded4bb856eeb9bd44856eacbd97497
languageName: node
linkType: hard

"caniuse-lite@npm:^1.0.30001579":
version: 1.0.30001778
resolution: "caniuse-lite@npm:1.0.30001778"
checksum: 10c0/830042e0a6af0796d3da4d9575f60966b92308c5504577993b618dd196c835d023dbd725fa8b47c33b74c487d75ce01ee3ebd6e7a078714989513110e8ff80e5
version: 1.0.30001780
resolution: "caniuse-lite@npm:1.0.30001780"
checksum: 10c0/8a88f39758a228852d6f3ac92362ecb7694b1b2b022f194d8dfe59123ad40a5de6202bf2dff0fe316bb3d5ca9caf316c22056e0da693459c3be2771cde4f4bf9
languageName: node
linkType: hard

Expand Down
Loading
Loading