@@ -909,7 +909,7 @@ describe("createMemoryRouter", () => {
909
909
} ) ;
910
910
} ) ;
911
911
912
- it ( "reloads data using useRevalidate " , async ( ) => {
912
+ it ( "reloads data using useRevalidator " , async ( ) => {
913
913
let count = 1 ;
914
914
let router = createMemoryRouter (
915
915
createRoutesFromElements (
@@ -1747,37 +1747,11 @@ describe("createMemoryRouter", () => {
1747
1747
) ;
1748
1748
let { container } = render ( < RouterProvider router = { router } /> ) ;
1749
1749
1750
- expect ( getHtml ( container ) ) . toMatchInlineSnapshot ( `
1751
- "<div>
1752
- <h2>
1753
- Unexpected Application Error!
1754
- </h2>
1755
- <h3
1756
- style="font-style: italic;"
1757
- >
1758
- 404 Not Found
1759
- </h3>
1760
- <p>
1761
- 💿 Hey developer 👋
1762
- </p>
1763
- <p>
1764
- You can provide a way better UX than this when your app throws errors by providing your own
1765
- <code
1766
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
1767
- >
1768
- ErrorBoundary
1769
- </code>
1770
- or
1771
-
1772
- <code
1773
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
1774
- >
1775
- errorElement
1776
- </code>
1777
- prop on your route.
1778
- </p>
1779
- </div>"
1780
- ` ) ;
1750
+ let html = getHtml ( container ) ;
1751
+ expect ( html ) . toMatch ( "Unexpected Application Error!" ) ;
1752
+ expect ( html ) . toMatch ( "404 Not Found" ) ;
1753
+ expect ( html ) . toMatch ( "💿 Hey developer 👋" ) ;
1754
+ expect ( html ) . not . toMatch ( / s t a c k / i) ;
1781
1755
} ) ;
1782
1756
1783
1757
it ( "renders navigation errors with a default if no errorElements are provided" , async ( ) => {
@@ -1861,42 +1835,11 @@ describe("createMemoryRouter", () => {
1861
1835
error . stack = "FAKE STACK TRACE" ;
1862
1836
barDefer . reject ( error ) ;
1863
1837
await waitFor ( ( ) => screen . getByText ( "Kaboom!" ) ) ;
1864
- expect ( getHtml ( container ) ) . toMatchInlineSnapshot ( `
1865
- "<div>
1866
- <h2>
1867
- Unexpected Application Error!
1868
- </h2>
1869
- <h3
1870
- style="font-style: italic;"
1871
- >
1872
- Kaboom!
1873
- </h3>
1874
- <pre
1875
- style="padding: 0.5rem; background-color: rgba(200, 200, 200, 0.5);"
1876
- >
1877
- FAKE STACK TRACE
1878
- </pre>
1879
- <p>
1880
- 💿 Hey developer 👋
1881
- </p>
1882
- <p>
1883
- You can provide a way better UX than this when your app throws errors by providing your own
1884
- <code
1885
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
1886
- >
1887
- ErrorBoundary
1888
- </code>
1889
- or
1890
-
1891
- <code
1892
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
1893
- >
1894
- errorElement
1895
- </code>
1896
- prop on your route.
1897
- </p>
1898
- </div>"
1899
- ` ) ;
1838
+ let html = getHtml ( container ) ;
1839
+ expect ( html ) . toMatch ( "Unexpected Application Error!" ) ;
1840
+ expect ( html ) . toMatch ( "Kaboom!" ) ;
1841
+ expect ( html ) . toMatch ( "FAKE STACK TRACE" ) ;
1842
+ expect ( html ) . toMatch ( "💿 Hey developer 👋" ) ;
1900
1843
} ) ;
1901
1844
1902
1845
// This test ensures that when manual routes are used, we add hasErrorBoundary
@@ -2095,42 +2038,11 @@ describe("createMemoryRouter", () => {
2095
2038
throw error ;
2096
2039
}
2097
2040
2098
- expect ( getHtml ( container ) ) . toMatchInlineSnapshot ( `
2099
- "<div>
2100
- <h2>
2101
- Unexpected Application Error!
2102
- </h2>
2103
- <h3
2104
- style="font-style: italic;"
2105
- >
2106
- Kaboom!
2107
- </h3>
2108
- <pre
2109
- style="padding: 0.5rem; background-color: rgba(200, 200, 200, 0.5);"
2110
- >
2111
- FAKE STACK TRACE
2112
- </pre>
2113
- <p>
2114
- 💿 Hey developer 👋
2115
- </p>
2116
- <p>
2117
- You can provide a way better UX than this when your app throws errors by providing your own
2118
- <code
2119
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
2120
- >
2121
- ErrorBoundary
2122
- </code>
2123
- or
2124
-
2125
- <code
2126
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
2127
- >
2128
- errorElement
2129
- </code>
2130
- prop on your route.
2131
- </p>
2132
- </div>"
2133
- ` ) ;
2041
+ let html = getHtml ( container ) ;
2042
+ expect ( html ) . toMatch ( "Unexpected Application Error!" ) ;
2043
+ expect ( html ) . toMatch ( "Kaboom!" ) ;
2044
+ expect ( html ) . toMatch ( "FAKE STACK TRACE" ) ;
2045
+ expect ( html ) . toMatch ( "💿 Hey developer 👋" ) ;
2134
2046
} ) ;
2135
2047
2136
2048
it ( "does not handle render errors for non-data routers" , async ( ) => {
@@ -2280,44 +2192,11 @@ describe("createMemoryRouter", () => {
2280
2192
2281
2193
router . navigate ( "/child" ) ;
2282
2194
await waitFor ( ( ) => screen . getByText ( "Kaboom!" ) ) ;
2283
- expect ( getHtml ( container ) ) . toMatchInlineSnapshot ( `
2284
- "<div>
2285
- <div>
2286
- <h2>
2287
- Unexpected Application Error!
2288
- </h2>
2289
- <h3
2290
- style="font-style: italic;"
2291
- >
2292
- Kaboom!
2293
- </h3>
2294
- <pre
2295
- style="padding: 0.5rem; background-color: rgba(200, 200, 200, 0.5);"
2296
- >
2297
- FAKE STACK TRACE
2298
- </pre>
2299
- <p>
2300
- 💿 Hey developer 👋
2301
- </p>
2302
- <p>
2303
- You can provide a way better UX than this when your app throws errors by providing your own
2304
- <code
2305
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
2306
- >
2307
- ErrorBoundary
2308
- </code>
2309
- or
2310
-
2311
- <code
2312
- style="padding: 2px 4px; background-color: rgba(200, 200, 200, 0.5);"
2313
- >
2314
- errorElement
2315
- </code>
2316
- prop on your route.
2317
- </p>
2318
- </div>
2319
- </div>"
2320
- ` ) ;
2195
+ let html = getHtml ( container ) ;
2196
+ expect ( html ) . toMatch ( "Unexpected Application Error!" ) ;
2197
+ expect ( html ) . toMatch ( "Kaboom!" ) ;
2198
+ expect ( html ) . toMatch ( "FAKE STACK TRACE" ) ;
2199
+ expect ( html ) . toMatch ( "💿 Hey developer 👋" ) ;
2321
2200
2322
2201
router . navigate ( - 1 ) ;
2323
2202
await waitFor ( ( ) => {
@@ -2508,6 +2387,120 @@ describe("createMemoryRouter", () => {
2508
2387
) ;
2509
2388
errorSpy . mockRestore ( ) ;
2510
2389
} ) ;
2390
+
2391
+ it ( "allows a successful useRevalidator to resolve the error boundary (loader + child boundary)" , async ( ) => {
2392
+ let shouldFail = true ;
2393
+ let router = createMemoryRouter (
2394
+ createRoutesFromElements (
2395
+ < Route
2396
+ path = "/"
2397
+ Component = { ( ) => (
2398
+ < >
2399
+ < MemoryNavigate to = "child" > /child</ MemoryNavigate >
2400
+ < Outlet />
2401
+ </ >
2402
+ ) }
2403
+ >
2404
+ < Route
2405
+ path = "child"
2406
+ loader = { ( ) => {
2407
+ if ( shouldFail ) {
2408
+ shouldFail = false ;
2409
+ throw new Error ( "Broken" ) ;
2410
+ } else {
2411
+ return "Fixed" ;
2412
+ }
2413
+ } }
2414
+ Component = { ( ) => < p > { ( "Child:" + useLoaderData ( ) ) as string } </ p > }
2415
+ ErrorBoundary = { ( ) => {
2416
+ let { revalidate } = useRevalidator ( ) ;
2417
+ return (
2418
+ < >
2419
+ < p > { "Error:" + ( useRouteError ( ) as Error ) . message } </ p >
2420
+ < button onClick = { ( ) => revalidate ( ) } > Try again</ button >
2421
+ </ >
2422
+ ) ;
2423
+ } }
2424
+ />
2425
+ </ Route >
2426
+ )
2427
+ ) ;
2428
+
2429
+ let { container } = render (
2430
+ < div >
2431
+ < RouterProvider router = { router } />
2432
+ </ div >
2433
+ ) ;
2434
+
2435
+ fireEvent . click ( screen . getByText ( "/child" ) ) ;
2436
+ await waitFor ( ( ) => screen . getByText ( "Error:Broken" ) ) ;
2437
+ expect ( getHtml ( container ) ) . toMatch ( "Error:Broken" ) ;
2438
+ expect ( router . state . errors ) . not . toBe ( null ) ;
2439
+
2440
+ fireEvent . click ( screen . getByText ( "Try again" ) ) ;
2441
+ await waitFor ( ( ) => {
2442
+ expect ( queryByText ( container , "Child:Fixed" ) ) . toBeInTheDocument ( ) ;
2443
+ } ) ;
2444
+ expect ( getHtml ( container ) ) . toMatch ( "Child:Fixed" ) ;
2445
+ expect ( router . state . errors ) . toBe ( null ) ;
2446
+ } ) ;
2447
+
2448
+ it ( "allows a successful useRevalidator to resolve the error boundary (loader + parent boundary)" , async ( ) => {
2449
+ let shouldFail = true ;
2450
+ let router = createMemoryRouter (
2451
+ createRoutesFromElements (
2452
+ < Route
2453
+ path = "/"
2454
+ Component = { ( ) => (
2455
+ < >
2456
+ < MemoryNavigate to = "child" > /child</ MemoryNavigate >
2457
+ < Outlet />
2458
+ </ >
2459
+ ) }
2460
+ ErrorBoundary = { ( ) => {
2461
+ let { revalidate } = useRevalidator ( ) ;
2462
+ return (
2463
+ < >
2464
+ < p > { "Error:" + ( useRouteError ( ) as Error ) . message } </ p >
2465
+ < button onClick = { ( ) => revalidate ( ) } > Try again</ button >
2466
+ </ >
2467
+ ) ;
2468
+ } }
2469
+ >
2470
+ < Route
2471
+ path = "child"
2472
+ loader = { ( ) => {
2473
+ if ( shouldFail ) {
2474
+ shouldFail = false ;
2475
+ throw new Error ( "Broken" ) ;
2476
+ } else {
2477
+ return "Fixed" ;
2478
+ }
2479
+ } }
2480
+ Component = { ( ) => < p > { ( "Child:" + useLoaderData ( ) ) as string } </ p > }
2481
+ />
2482
+ </ Route >
2483
+ )
2484
+ ) ;
2485
+
2486
+ let { container } = render (
2487
+ < div >
2488
+ < RouterProvider router = { router } />
2489
+ </ div >
2490
+ ) ;
2491
+
2492
+ fireEvent . click ( screen . getByText ( "/child" ) ) ;
2493
+ await waitFor ( ( ) => screen . getByText ( "Error:Broken" ) ) ;
2494
+ expect ( getHtml ( container ) ) . toMatch ( "Error:Broken" ) ;
2495
+ expect ( router . state . errors ) . not . toBe ( null ) ;
2496
+
2497
+ fireEvent . click ( screen . getByText ( "Try again" ) ) ;
2498
+ await waitFor ( ( ) => {
2499
+ expect ( queryByText ( container , "Child:Fixed" ) ) . toBeInTheDocument ( ) ;
2500
+ } ) ;
2501
+ expect ( getHtml ( container ) ) . toMatch ( "Child:Fixed" ) ;
2502
+ expect ( router . state . errors ) . toBe ( null ) ;
2503
+ } ) ;
2511
2504
} ) ;
2512
2505
2513
2506
describe ( "defer" , ( ) => {
0 commit comments