Skip to content

[Not for merge] Fixture for sourcemaps#96084

Draft
gaearon wants to merge 1 commit into
canaryfrom
gaearon-sourcemap-monster-fixture
Draft

[Not for merge] Fixture for sourcemaps#96084
gaearon wants to merge 1 commit into
canaryfrom
gaearon-sourcemap-monster-fixture

Conversation

@gaearon

@gaearon gaearon commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Not for merge.

I asked Claude to make this fixture to help me understand the impact of changes to sourcemapping logic in Next.js. It hardcodes checked-in faithful (hopefully) copies of the relevant React logic without actual Flight stuff, rendering, etc.

So we can capture dozens of inline snapshots that show how different pieces of Next.js see the stack. I've nudged Claude towards as much Next.js coverage as reasonable. If you scroll through this test, you'll see what I mean.

This reflects the current behavior so there might be some weird tests.


Since this would require updating whenever React updates upstream, even though (I believe) any divergence is caught by tests, this is still too annoying. So I don't actually aim to merge it but can use every once in a while as an aid.

@gaearon gaearon changed the title Cover the semantics of React's fake stack frames for revived errors [Not for merge] Fixture for sourcemaps Jul 22, 2026
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Stats from current PR

🔴 1 regression

Metric Canary PR Change Trend
Webpack Cold (First Request) 3.603s 3.909s 🔴 +306ms (+8%) ▄▃▆▁▂
📊 All Metrics
📖 Metrics Glossary

Dev Server Metrics:

  • Listen = TCP port starts accepting connections
  • First Request = HTTP server returns successful response
  • Cold = Fresh build (no cache)
  • Warm = With cached build artifacts

Build Metrics:

  • Fresh = Clean build (no .next directory)
  • Cached = With existing .next directory

Change Thresholds:

  • Time: Changes < 50ms AND < 10%, OR < 2% are insignificant
  • Size: Changes < 1KB AND < 1% are insignificant
  • All other changes are flagged to catch regressions

⚡ Dev Server

Metric Canary PR Change Trend
Cold (Listen) 812ms 813ms ▁▁▁▁▂
Cold (Ready in log) 780ms 782ms ▁▁▁▁▁
Cold (First Request) 1.307s 1.298s ▁▁▁▁▁
Warm (Listen) 810ms 812ms ▁▂▁▂▂
Warm (Ready in log) 769ms 782ms ▁▁▁▁▁
Warm (First Request) 1.282s 1.272s ▁▁▁▁▁
📦 Dev Server (Webpack) (Legacy)

📦 Dev Server (Webpack)

Metric Canary PR Change Trend
Cold (Listen) 863ms 813ms ████▁
Cold (Ready in log) 825ms 816ms ▃▄▅▁▁
Cold (First Request) 3.603s 3.909s 🔴 +306ms (+8%) ▄▃▆▁▂
Warm (Listen) 815ms 863ms ███▁█
Warm (Ready in log) 818ms 823ms ▂▅▁▁▂
Warm (First Request) 3.644s 3.726s ▃▄▄▁▂

⚡ Production Builds

Metric Canary PR Change Trend
Fresh Build 4.928s 5.065s ▁▁▁▁▁
Cached Build 5.015s 5.158s ▁▁▁▁▁
📦 Production Builds (Webpack) (Legacy)

📦 Production Builds (Webpack)

Metric Canary PR Change Trend
Fresh Build 27.933s 27.650s ▃▄▂▁▂
Cached Build 28.100s 27.945s ▁▃▁▁▂
node_modules Size 527 MB 527 MB █████
📦 Bundle Sizes

Bundle Sizes

⚡ Turbopack

Client

Main Bundles
Canary PR Change
00v6npozcc3c3.js gzip 155 B N/A -
0a-p0meqxynjz.js gzip 10.3 kB N/A -
0avtke4yefj4-.js gzip 13.1 kB N/A -
0cz1d0mv5g_q7.js gzip 39.4 kB 39.4 kB
0nvyq--brb2d1.js gzip 71.1 kB N/A -
0pt5of3ch6d2u.js gzip 13.6 kB N/A -
0xnsdo-6y9r3k.js gzip 5.72 kB N/A -
0yi7is8u4covm.js gzip 8.77 kB N/A -
1aqu9ze6v_-92.js gzip 157 B N/A -
1bhefyyiiy1a1.js gzip 160 B N/A -
1elt1qium-r2m.css gzip 115 B 115 B
1lh1fi2q329kp.js gzip 155 B N/A -
1lsl-hvtjoz38.js gzip 7.4 kB N/A -
1ltc02dslhmu0.js gzip 156 B N/A -
1prv-wg6jgtt2.js gzip 8.77 kB N/A -
1t47vod02e_4a.js gzip 8.75 kB N/A -
1tbq0-klq39t1.js gzip 156 B N/A -
1tf1phijqlx9j.js gzip 220 B 220 B
1tw002sq5bo4l.js gzip 10 kB N/A -
1wlerik1n7zbr.js gzip 8.7 kB N/A -
22vemgj_ppw9g.js gzip 157 B N/A -
28koph4jjzmen.js gzip 45.2 kB N/A -
2lviwqiqxm904.js gzip 3.52 kB N/A -
2pevdqjpbf3xk.js gzip 9.45 kB N/A -
2ppm-9338hg-g.js gzip 155 B N/A -
2qd2anu9eizlz.js gzip 8.75 kB N/A -
2sv39ae5_8vfj.js gzip 8.81 kB N/A -
2utx6n7w65xqa.js gzip 8.7 kB N/A -
2vo_g-1nu597x.js gzip 153 B N/A -
3_gkkw57bfro8.js gzip 168 B N/A -
3-ukivglqkfeq.js gzip 8.78 kB N/A -
325xisqrylugu.js gzip 450 B N/A -
3e9jui3nrs0cq.js gzip 161 B N/A -
3jc9ghvds1spf.js gzip 2.29 kB N/A -
3juwkvkgvywfe.js gzip 10.6 kB N/A -
3kbove7q58uqh.js gzip 13.2 kB N/A -
3qn7vntp30gaj.js gzip 1.47 kB N/A -
3tg5xymt-y3pf.js gzip 157 B N/A -
3y5l7macq6332.js gzip 156 B N/A -
45bnqre7r-j34.js gzip 65.6 kB N/A -
turbopack-0d..qkmb.js gzip 3.81 kB N/A -
turbopack-0m..pdb9.js gzip 3.78 kB N/A -
turbopack-1-..1ho9.js gzip 3.8 kB N/A -
turbopack-1d..316h.js gzip 3.82 kB N/A -
turbopack-1w..lyf1.js gzip 3.81 kB N/A -
turbopack-25..qyhv.js gzip 3.81 kB N/A -
turbopack-2c..lyeg.js gzip 3.81 kB N/A -
turbopack-2h..a-uq.js gzip 3.8 kB N/A -
turbopack-2j..bz11.js gzip 3.81 kB N/A -
turbopack-3-..gj1l.js gzip 3.81 kB N/A -
turbopack-36..evj4.js gzip 3.81 kB N/A -
turbopack-37.._yox.js gzip 3.8 kB N/A -
turbopack-3p..5n5c.js gzip 3.81 kB N/A -
turbopack-41..w-sa.js gzip 3.81 kB N/A -
030a1njeh5b77.js gzip N/A 10 kB -
0g4_k2uc6wv4q.js gzip N/A 157 B -
0gks75us8x8np.js gzip N/A 156 B -
0ot0qt5np20h7.js gzip N/A 8.78 kB -
1_0n9btq9p4ce.js gzip N/A 156 B -
1-qxxhh8-axib.js gzip N/A 45.2 kB -
12km8nr29deej.js gzip N/A 152 B -
12m9rr7_7cexd.js gzip N/A 8.7 kB -
186r3y_rfvr0b.js gzip N/A 8.78 kB -
19v97848yrjp7.js gzip N/A 8.81 kB -
1em_c2iwtphkh.js gzip N/A 155 B -
1j9dy_1o47w3f.js gzip N/A 157 B -
1k4eu86-nhh6g.js gzip N/A 156 B -
1nd_0rwgz2ozk.js gzip N/A 9.45 kB -
1oi9pltr_e10m.js gzip N/A 10.6 kB -
1rd9tzqgzsz2w.js gzip N/A 8.77 kB -
1rq1g_cwv642d.js gzip N/A 10.3 kB -
1sek4rdapnadp.js gzip N/A 157 B -
1uojw_uabeg93.js gzip N/A 450 B -
1w-7lusgyl81y.js gzip N/A 8.7 kB -
2-kdoq-jy_crq.js gzip N/A 7.41 kB -
21h56wdn9zddo.js gzip N/A 8.75 kB -
23m4n1cp16_my.js gzip N/A 158 B -
26urb3nj-ua41.js gzip N/A 71.1 kB -
2caur9q46_a46.js gzip N/A 160 B -
2d_gfdd2kvo3j.js gzip N/A 155 B -
2lg10omv7xu14.js gzip N/A 3.52 kB -
2ovff1533zvno.js gzip N/A 13.2 kB -
2s4z8jy0z7v93.js gzip N/A 1.46 kB -
2y6gb5bs4mnam.js gzip N/A 8.75 kB -
341h71ln1jpl3.js gzip N/A 2.29 kB -
34ttpt_n7605h.js gzip N/A 5.72 kB -
36ckfq9o-ys-a.js gzip N/A 13.1 kB -
3djafohg3a3jg.js gzip N/A 161 B -
3vdh6_u50pu5t.js gzip N/A 13.6 kB -
3vughx3b6vlec.js gzip N/A 65.6 kB -
3yr5uv4qtknye.js gzip N/A 169 B -
turbopack-04..uq8-.js gzip N/A 3.78 kB -
turbopack-0q..2a0a.js gzip N/A 3.81 kB -
turbopack-0w..pdzm.js gzip N/A 3.81 kB -
turbopack-1_..muub.js gzip N/A 3.8 kB -
turbopack-1d..c7mz.js gzip N/A 3.8 kB -
turbopack-1j..b3jd.js gzip N/A 3.81 kB -
turbopack-1s..sjan.js gzip N/A 3.81 kB -
turbopack-2b..8l3_.js gzip N/A 3.8 kB -
turbopack-2q..n442.js gzip N/A 3.81 kB -
turbopack-2t..t3xp.js gzip N/A 3.82 kB -
turbopack-2z..c636.js gzip N/A 3.8 kB -
turbopack-3_..zctb.js gzip N/A 3.8 kB -
turbopack-39.._x1-.js gzip N/A 3.81 kB -
turbopack-3e..733c.js gzip N/A 3.81 kB -
Total 448 kB 448 kB ⚠️ +37 B

Server

Middleware
Canary PR Change
middleware-b..fest.js gzip 780 B 778 B
Total 780 B 778 B ✅ -2 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 433 B 431 B
Total 433 B 431 B ✅ -2 B

📦 Webpack

Client

Main Bundles
Canary PR Change
3322-HASH.js gzip 63.7 kB N/A -
4191.HASH.js gzip 169 B N/A -
7920-HASH.js gzip 4.68 kB N/A -
9784-HASH.js gzip 5.63 kB N/A -
b1ad9f4c-HASH.js gzip 62.9 kB N/A -
framework-HASH.js gzip 59.7 kB 59.7 kB
main-app-HASH.js gzip 254 B 253 B
main-HASH.js gzip 40 kB 40 kB
webpack-HASH.js gzip 1.68 kB 1.68 kB
3577.HASH.js gzip N/A 168 B -
578-HASH.js gzip N/A 64.4 kB -
8590-HASH.js gzip N/A 5.61 kB -
9750-HASH.js gzip N/A 4.69 kB -
a8984546-HASH.js gzip N/A 62.9 kB -
Total 239 kB 239 kB ⚠️ +636 B
Polyfills
Canary PR Change
polyfills-HASH.js gzip 39.4 kB 39.4 kB
Total 39.4 kB 39.4 kB
Pages
Canary PR Change
_app-HASH.js gzip 194 B 193 B
_error-HASH.js gzip 181 B 182 B
css-HASH.js gzip 334 B 331 B
dynamic-HASH.js gzip 1.81 kB 1.81 kB
edge-ssr-HASH.js gzip 255 B 253 B
head-HASH.js gzip 349 B 351 B
hooks-HASH.js gzip 382 B 384 B
image-HASH.js gzip 581 B 582 B
index-HASH.js gzip 260 B 259 B
link-HASH.js gzip 2.48 kB 2.48 kB
routerDirect..HASH.js gzip 317 B 318 B
script-HASH.js gzip 384 B 386 B
withRouter-HASH.js gzip 316 B 315 B
1afbb74e6ecf..834.css gzip 106 B 106 B
Total 7.95 kB 7.95 kB ⚠️ +1 B

Server

Edge SSR
Canary PR Change
edge-ssr.js gzip 128 kB 128 kB
page.js gzip 287 kB 287 kB
Total 415 kB 414 kB ✅ -880 B
Middleware
Canary PR Change
middleware-b..fest.js gzip 618 B 617 B
middleware-r..fest.js gzip 156 B 156 B
middleware.js gzip 45.5 kB 45.3 kB
edge-runtime..pack.js gzip 842 B 842 B
Total 47.2 kB 46.9 kB ✅ -231 B
Build Details
Build Manifests
Canary PR Change
_buildManifest.js gzip 718 B 718 B
Total 718 B 718 B
Build Cache
Canary PR Change
0.pack gzip 4.84 MB 4.84 MB
index.pack gzip 120 kB 120 kB
index.pack.old gzip 119 kB 120 kB
Total 5.08 MB 5.08 MB ✅ -3.72 kB

🔄 Shared (bundler-independent)

Runtimes
Canary PR Change
app-page-exp...dev.js gzip 366 kB 366 kB
app-page-exp..prod.js gzip 202 kB 202 kB
app-page-tur...dev.js gzip 365 kB 365 kB
app-page-tur..prod.js gzip 202 kB 202 kB
app-page-tur...dev.js gzip 362 kB 362 kB
app-page-tur..prod.js gzip 200 kB 200 kB
app-page.run...dev.js gzip 362 kB 362 kB
app-page.run..prod.js gzip 200 kB 200 kB
app-route-ex...dev.js gzip 81.8 kB 81.8 kB
app-route-ex..prod.js gzip 55.6 kB 55.6 kB
app-route-tu...dev.js gzip 81.8 kB 81.8 kB
app-route-tu..prod.js gzip 55.6 kB 55.6 kB
app-route-tu...dev.js gzip 81.4 kB 81.4 kB
app-route-tu..prod.js gzip 55.4 kB 55.4 kB
app-route.ru...dev.js gzip 81.4 kB 81.4 kB
app-route.ru..prod.js gzip 55.4 kB 55.4 kB
dist_client_...dev.js gzip 324 B 324 B
dist_client_...dev.js gzip 326 B 326 B
dist_client_...dev.js gzip 318 B 318 B
dist_client_...dev.js gzip 317 B 317 B
pages-api-tu...dev.js gzip 45.4 kB 45.4 kB
pages-api-tu..prod.js gzip 34.1 kB 34.1 kB
pages-api.ru...dev.js gzip 45.4 kB 45.4 kB
pages-api.ru..prod.js gzip 34.1 kB 34.1 kB
pages-turbo....dev.js gzip 54.9 kB 54.9 kB
pages-turbo...prod.js gzip 39.7 kB 39.7 kB
pages.runtim...dev.js gzip 54.8 kB 54.8 kB
pages.runtim..prod.js gzip 39.7 kB 39.7 kB
server.runti..prod.js gzip 67.8 kB 67.8 kB
use-cache-pr...dev.js gzip 71.6 kB 71.6 kB
use-cache-pr...dev.js gzip 71.6 kB 71.6 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
use-cache-pr...dev.js gzip 69.9 kB 69.9 kB
Total 3.51 MB 3.51 MB
📎 Tarball URL
https://vercel-packages.vercel.app/next/commits/edbe4a9734f811cb77210c01a4c0d3c325c725e6/next

Commit: edbe4a9

@gaearon
gaearon force-pushed the gaearon-sourcemap-monster-fixture branch from 1977956 to 90bf403 Compare July 22, 2026 21:52
@github-actions

github-actions Bot commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Failing test suites

Commit: edbe4a9 | About building and testing Next.js

pnpm test test/unit/fake-stack-frames.test.ts (job)

  • fake stack frames > digests > suffixes digests with the error code and forwards them (DD)
  • fake stack frames > digests > collides digests of identical throws onto the first error (DD)
  • fake stack frames > digests and the Next.js error handlers > parses the structured stack trace for errors logged before thrown (DD)
  • fake stack frames > digests and the Next.js error handlers > parses the structured stack trace for errors that carry a digest (DD)
  • fake stack frames > digests and the Next.js error handlers > serializes the digest before formatServerError rewrites the message (DD)
  • fake stack frames > digests and the Next.js error handlers > rewrites createContext errors after the digest (DD)
  • fake stack frames > digests and the Next.js error handlers > rewrites client hook errors after the digest (DD)
  • fake stack frames > digests and the Next.js error handlers > recovers RSC errors by digest in the HTML error handler (DD)
  • fake stack frames > error shapes > applies a custom error name to the revived stack (DD)
  • fake stack frames > error shapes > replaces empty messages with the fallback message (DD)
  • fake stack frames > error shapes > revives thrown non-Error values with a machinery-only stack (DD)
  • fake stack frames > error shapes > describes thrown non-Error objects in the message (DD)
  • fake stack frames > error shapes > revives the cause with its own fake stack (DD)
  • fake stack frames > error shapes > round-trips the model value encodings through a cause (DD)
  • fake stack frames > error shapes > revives nested cause chains down to primitive causes (DD)
  • fake stack frames > error shapes > revives causes under the environment they carry (DD)
  • fake stack frames > error shapes > revives AggregateError errors with their own fake stacks (DD)
  • fake stack frames > frame shapes > keeps a leading space on the method name of async frames (DD)
  • fake stack frames > frame shapes > preserves constructor frame names (DD)
  • fake stack frames > frame shapes > revives native frames under at the fake script position (DD)
  • fake stack frames > frame shapes > preserves the frame count of deep stacks (DD)
  • fake stack frames > frame shapes > splits the eval origin of frames of eval'd scripts without a sourceURL (DD)
  • fake stack frames > frame shapes > revives module-evaluation frames (DD)
  • fake stack frames > frame shapes > resolves every frame of stacks that span multiple chunks (DD)
  • fake stack frames > frame shapes > revives message lines that look like stack frames as frames (DD)
  • fake stack frames > owner task chains > revives owner-stack rewritten errors with owner callsite frames (DD)
  • fake stack frames > paths and encodings > resolves every revival for chunk paths that percent-encoding does not change (DD)
  • fake stack frames > paths and encodings > does not resolve the second revival for chunk paths with a hash (DD)
  • fake stack frames > paths and encodings > resolves chunks required through a symlink (DD)
  • fake stack frames > paths and encodings > resolves every revival of webpack-internal frames (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > brackets (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > space (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > unicode (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > percent (DD)
  • fake stack frames > resolving source maps > splits the consumers on sparse mappings (DD)
  • fake stack frames > resolving source maps > resolves index source maps shaped like Turbopack emits them (DD)
  • fake stack frames > resolving source maps > resolves frames mapped by a later section of an index source map (DD)
  • fake stack frames > resolving source maps > resolves frames mapped by the first section of an index source map (DD)
  • fake stack frames > resolving source maps > keeps frames positioned before every index map section (DD)
  • fake stack frames > resolving source maps > keeps frames of chunks whose index source map has no sections (DD)
  • fake stack frames > resolving source maps > serves relative section sources that a debugger cannot resolve (DD)
  • fake stack frames > resolving source maps > does not resolve spec-conformant index source maps (DD)
  • fake stack frames > resolving source maps > does not resolve frames of scripts with an invalid source map (DD)
  • fake stack frames > resolving source maps > falls back to the plain file URL for scripts without a source map (DD)
  • fake stack frames > resolving source maps > resolves frames of eval'd scripts with inline source maps (DD)
  • fake stack frames > resolving source maps > resolves chunks whose files were deleted after loading (DD)
  • fake stack frames > resolving source maps > resolves errors from an edited chunk file with the stale source map (DD)
  • fake stack frames > resolving source maps > resolves query-busted ES module reloads with their own maps (DD)
  • fake stack frames > resolving source maps > resolves errors from a replaced eval with the stale source map (DD)
  • fake stack frames > resolving source maps > resolves terminal frames through the bundler source map fallback (DD)
  • fake stack frames > resolving source maps > ignore-lists frames whose original source is in node_modules (DD)
  • fake stack frames > reviving one error > revives an error with a source mapped fake stack frame (DD)
  • fake stack frames > reviving one error > reproduces the fake script layout byte-for-byte across revivals (DD)
  • fake stack frames > reviving one error > reuses fake stack frame scripts for identical frames (DD)
  • fake stack frames > reviving one error > creates one fake script per consumer under colliding URLs (DD)
  • fake stack frames > terminal output > cuts terminal output at the react bottom frame (DD)
  • fake stack frames > terminal output > ignore-lists native frames sandwiched between ignored frames (DD)
  • fake stack frames > terminal output > caches terminal source map lookups per file within one error (DD)
  • fake stack frames > terminal output > keeps ignore-listed frames in terminal output when asked to (DD)
  • fake stack frames > terminal output > prints terminal output without code frames when none is installed (DD)
  • fake stack frames > terminal output > rewrites webpack export helper names in terminal frames (DD)
  • fake stack frames > the dev overlay > resolves revived frames through the dev overlay machinery (DD)
  • fake stack frames > the dev overlay > resolves fake frame maps through the endpoint like a browser (DD)
  • fake stack frames > the dev overlay > maps browser console log frames for the terminal (DD)
  • fake stack frames > the dev overlay > serves source maps to the browser through the endpoint (DD)
  • fake stack frames > the dev overlay > cleans up browser-reported frames for the overlay (DD)
  • fake stack frames > which frames serialize > serializes no frames for code in node_modules (DD)
  • fake stack frames > which frames serialize > serializes no frames for chunks in directories named like node_modules (DD)
  • fake stack frames > which frames serialize > serializes no frames for chunks whose source map ignore-lists everything (DD)
  • fake stack frames > which frames serialize > keeps frames of chunks whose source map ignore-lists only other sources (DD)
  • fake stack frames > which frames serialize > drops new Promise frames (DD)
Expand output

● fake stack frames › reviving one error › revives an error with a source mapped fake stack frame

expect(received).toEqual(expected) // deep equality

- Expected  - 1
+ Received  + 1

  Object {
    "at": "hop 0",
-   "showsAboutURL": false,
+   "showsAboutURL": true,
  }

  224 |     const showsAboutURL = hop.terminal.includes('about://React/')
  225 |     const expected = rawTerminalURLs.has(place)
> 226 |     expect({ at: place, showsAboutURL }).toEqual({
      |                                          ^
  227 |       at: place,
  228 |       showsAboutURL: expected,
  229 |     })

  at toEqual (unit/fake-stack-frames.test.ts:226:42)
  at visitHop (unit/fake-stack-frames.test.ts:235:39)
      at Array.forEach (<anonymous>)
  at forEach (unit/fake-stack-frames.test.ts:235:15)
  at verifyInvariants (unit/fake-stack-frames.test.ts:144:3)
  at runScenario (unit/fake-stack-frames.test.ts:476:20)
  at Object.renderBothModes (unit/fake-stack-frames.test.ts:778:14)

● fake stack frames › reviving one error › reproduces the fake script layout byte-for-byte across revivals

expect(received).toEqual(expected) // deep equality

- Expected  - 1
+ Received  + 1

  Object {
    "at": "hop 0",
-   "showsAboutURL": false,
+   "showsAboutURL": true,
  }

  224 |     const showsAboutURL = hop.terminal.includes('about://React/')
  225 |     const expected = rawTerminalURLs.has(place)
> 226 |     expect({ at: place, showsAboutURL }).toEqual({
      |                                          ^
  227 |       at: place,
  228 |       showsAboutURL: expected,
  229 |     })

  at toEqual (unit/fake-stack-frames.test.ts:226:42)
  at visitHop (unit/fake-stack-frames.test.ts:235:39)
      at Array.forEach (<anonymous>)
  at forEach (unit/fake-stack-frames.test.ts:235:15)
  at verifyInvariants (unit/fake-stack-frames.test.ts:144:3)
  at Object.runScenario (unit/fake-stack-frames.test.ts:867:22)

● fake stack frames › reviving one error › reuses fake stack frame scripts for identical frames

expect(received).toEqual(expected) // deep equality

- Expected  - 1
+ Received  + 1

  Object {
    "at": "hop 0",
-   "showsAboutURL": false,
+   "showsAboutURL": true,
  }

  224 |     const showsAboutURL = hop.terminal.includes('about://React/')
  225 |     const expected = rawTerminalURLs.has(place)
> 226 |     expect({ at: place, showsAboutURL }).toEqual({
      |                                          ^
  227 |       at: place,
  228 |       showsAboutURL: expected,
  229 |     })

  at toEqual (unit/fake-stack-frames.test.ts:226:42)
  at visitHop (unit/fake-stack-frames.test.ts:235:39)
      at Array.forEach (<anonymous>)
  at forEach (unit/fake-stack-frames.test.ts:235:15)
  at verifyInvariants (unit/fake-stack-frames.test.ts:144:3)
  at Object.runScenario (unit/fake-stack-frames.test.ts:896:29)

● fake stack frames › reviving one error › creates one fake script per consumer under colliding URLs

expect(received).toEqual(expected) // deep equality

- Expected  - 1
+ Received  + 1

  Object {
    "at": "hop 0",
-   "showsAboutURL": false,
+   "showsAboutURL": true,
  }

  224 |     const showsAboutURL = hop.terminal.includes('about://React/')
  225 |     const expected = rawTerminalURLs.has(place)
> 226 |     expect({ at: place, showsAboutURL }).toEqual({
      |                                          ^
  227 |       at: place,
  228 |       showsAboutURL: expected,
  229 |     })

  at toEqual (unit/fake-stack-frames.test.ts:226:42)
  at visitHop (unit/fake-stack-frames.test.ts:235:39)
      at Array.forEach (<anonymous>)
  at forEach (unit/fake-stack-frames.test.ts:235:15)
  at verifyInvariants (unit/fake-stack-frames.test.ts:144:3)
  at Object.runScenario (unit/fake-stack-frames.test.ts:975:29)

● fake stack frames › which frames serialize › serializes no frames for code in node_modules

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `fake stack frames which frames serialize serializes no frames for code in node_modules 1`

- Snapshot  - 18
+ Received  + 12

  "== hop 0 (Server) ==
  error.stack (the raw string):
    Error: boom:chunk.js
-       at <anonymous> (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at <anonymous> (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at throwAndCatch (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at throwAndCatch (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at node-modules-frames (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at node-modules-frames (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at  main (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at  main (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at Object.resolveErrorDev (<tmp>/consumer-0/node_modules/flight-client/react-flight-semantics.js:<pos>)
+       at Object.resolveErrorDev (<tmp>\consumer-0\node_modules\flight-client\react-flight-semantics.js:<pos>)
-       at Immediate.<anonymous> (<tmp>/consumer-0/node_modules/flight-client/index.js:<pos>)
+       at Immediate.<anonymous> (<tmp>\consumer-0\node_modules\flight-client\index.js:31:17)
        at process.processImmediate (node:internal/timers:<pos>)
        at process.callbackTrampoline (node:internal/async_hooks:<pos>)
  terminal (the dev server prints through the patched inspect):
    Error: boom:chunk.js
-       at <anonymous> (test/unit/fake-stack-frames/scenario.js:<pos>)
+       at <anonymous> (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at throwAndCatch (test/unit/fake-stack-frames/scenario.js:<pos>)
+       at throwAndCatch (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at node-modules-frames (test/unit/fake-stack-frames/scenario.js:<pos>)
+       at node-modules-frames (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at  main (test/unit/fake-stack-frames/scenario.js:<pos>) {
+       at  main (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>) {
      environmentName: 'Server',
      digest: '<hash>'
    }
- top frame (as an attached debugger resolves it): <anonymous> at file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>
+ top frame (as an attached debugger resolves it): <anonymous> at C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>
      script: no source map
- == fake scripts ==
- file://<tmp>/node_modules/some-pkg/chunk.js
-   map: chunk.js.map
- file://<tmp>/consumer-0/node_modules/flight-client/index.js
-   map: -
- file://<tmp>/consumer-0/node_modules/flight-client/react-flight-semantics.js
-   map: -"
+ == fake scripts =="

  1062 |     it('serializes no frames for code in node_modules', () => {
  1063 |       expect(renderScenario(runScenario('node-modules-frames')))
> 1064 |         .toMatchInlineSnapshot(`
       |          ^
  1065 |        "== hop 0 (Server) ==
  1066 |        error.stack (the raw string):
  1067 |          Error: boom:chunk.js

  at Object.toMatchInlineSnapshot (unit/fake-stack-frames.test.ts:1064:10)

● fake stack frames › which frames serialize › serializes no frames for chunks in directories named like node_modules

expect(received).toMatchInlineSnapshot(snapshot)

Snapshot name: `fake stack frames which frames serialize serializes no frames for chunks in directories named like node_modules 1`

- Snapshot  - 33
+ Received  + 23

  "======== cjs ========
  == hop 0 (Server) ==
  error.stack (the raw string):
    Error: boom:chunk.js
-       at <anonymous> (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at <anonymous> (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at throwAndCatch (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at throwAndCatch (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at node-modules-substring-in-project-path (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at node-modules-substring-in-project-path (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at  main (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at  main (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at Object.resolveErrorDev (<tmp>/consumer-0/node_modules/flight-client/react-flight-semantics.js:<pos>)
+       at Object.resolveErrorDev (<tmp>\consumer-0\node_modules\flight-client\react-flight-semantics.js:<pos>)
-       at Immediate.<anonymous> (<tmp>/consumer-0/node_modules/flight-client/index.js:<pos>)
+       at Immediate.<anonymous> (<tmp>\consumer-0\node_modules\flight-client\index.js:31:17)
        at process.processImmediate (node:internal/timers:<pos>)
        at process.callbackTrampoline (node:internal/async_hooks:<pos>)
  terminal (the dev server prints through the patched inspect):
    Error: boom:chunk.js
-       at <anonymous> (test/unit/fake-stack-frames/scenario.js:<pos>)
+       at <anonymous> (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at throwAndCatch (test/unit/fake-stack-frames/scenario.js:<pos>)
+       at throwAndCatch (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at node-modules-substring-in-project-path (test/unit/fake-stack-frames/scenario.js:<pos>)
+       at node-modules-substring-in-project-path (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at  main (test/unit/fake-stack-frames/scenario.js:<pos>) {
+       at  main (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>) {
      environmentName: 'Server',
      digest: '<hash>'
    }
- top frame (as an attached debugger resolves it): <anonymous> at file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>
+ top frame (as an attached debugger resolves it): <anonymous> at C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>
      script: no source map
  == fake scripts ==
- file://<tmp>/my_node_modules_backup/chunk.js
-   map: chunk.js.map
- file://<tmp>/consumer-0/node_modules/flight-client/index.js
-   map: -
- file://<tmp>/consumer-0/node_modules/flight-client/react-flight-semantics.js
-   map: -
  ======== esm ========
  == hop 0 (Server) ==
  error.stack (the raw string):
    Error: boom:chunk.js
-       at <anonymous> (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at <anonymous> (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at throwAndCatch (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at throwAndCatch (C:%5Ca%5Cnext.js%5Cnext.js%5Ctest%5Cunit%5Cfake-stack-frames%5Cscenario.js:<pos>)
-       at node-modules-substring-in-project-path (file://<repo>/test/unit/fake-stack-frames/scenario.js:<pos>)
+       at node-modules-substring-in-project-path (C:%5Ca%5Cnex

... truncated ...

pnpm test test/unit/fake-stack-frames.test.ts (job)

  • fake stack frames > digests > suffixes digests with the error code and forwards them (DD)
  • fake stack frames > digests > collides digests of identical throws onto the first error (DD)
  • fake stack frames > digests and the Next.js error handlers > parses the structured stack trace for errors logged before thrown (DD)
  • fake stack frames > digests and the Next.js error handlers > parses the structured stack trace for errors that carry a digest (DD)
  • fake stack frames > digests and the Next.js error handlers > serializes the digest before formatServerError rewrites the message (DD)
  • fake stack frames > digests and the Next.js error handlers > rewrites createContext errors after the digest (DD)
  • fake stack frames > digests and the Next.js error handlers > rewrites client hook errors after the digest (DD)
  • fake stack frames > digests and the Next.js error handlers > recovers RSC errors by digest in the HTML error handler (DD)
  • fake stack frames > error shapes > applies a custom error name to the revived stack (DD)
  • fake stack frames > error shapes > replaces empty messages with the fallback message (DD)
  • fake stack frames > error shapes > revives thrown non-Error values with a machinery-only stack (DD)
  • fake stack frames > error shapes > describes thrown non-Error objects in the message (DD)
  • fake stack frames > error shapes > revives the cause with its own fake stack (DD)
  • fake stack frames > error shapes > round-trips the model value encodings through a cause (DD)
  • fake stack frames > error shapes > revives nested cause chains down to primitive causes (DD)
  • fake stack frames > error shapes > revives causes under the environment they carry (DD)
  • fake stack frames > error shapes > revives AggregateError errors with their own fake stacks (DD)
  • fake stack frames > frame shapes > keeps a leading space on the method name of async frames (DD)
  • fake stack frames > frame shapes > preserves constructor frame names (DD)
  • fake stack frames > frame shapes > revives native frames under at the fake script position (DD)
  • fake stack frames > frame shapes > preserves the frame count of deep stacks (DD)
  • fake stack frames > frame shapes > splits the eval origin of frames of eval'd scripts without a sourceURL (DD)
  • fake stack frames > frame shapes > revives module-evaluation frames (DD)
  • fake stack frames > frame shapes > resolves every frame of stacks that span multiple chunks (DD)
  • fake stack frames > frame shapes > revives message lines that look like stack frames as frames (DD)
  • fake stack frames > owner task chains > revives owner-stack rewritten errors with owner callsite frames (DD)
  • fake stack frames > paths and encodings > resolves every revival for chunk paths that percent-encoding does not change (DD)
  • fake stack frames > paths and encodings > does not resolve the second revival for chunk paths with a hash (DD)
  • fake stack frames > paths and encodings > resolves chunks required through a symlink (DD)
  • fake stack frames > paths and encodings > resolves every revival of webpack-internal frames (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > brackets (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > space (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > unicode (DD)
  • fake stack frames > paths and encodings > does not resolve the second CJS revival for chunk paths that percent-encoding changes > percent (DD)
  • fake stack frames > resolving source maps > splits the consumers on sparse mappings (DD)
  • fake stack frames > resolving source maps > resolves index source maps shaped like Turbopack emits them (DD)
  • fake stack frames > resolving source maps > resolves frames mapped by a later section of an inde

... truncated to fit in one GitHub comment ...

@gaearon
gaearon force-pushed the gaearon-sourcemap-monster-fixture branch from 90bf403 to b8cbac4 Compare July 22, 2026 21:56
@gaearon
gaearon force-pushed the gaearon-sourcemap-monster-fixture branch from b8cbac4 to edbe4a9 Compare July 22, 2026 22:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant