@@ -417,4 +417,193 @@ test.describe("Error Sanitization", () => {
417
417
expect ( errorLogs [ 0 ] [ 0 ] . stack ) . toMatch ( " at " ) ;
418
418
} ) ;
419
419
} ) ;
420
+
421
+ test . describe ( "serverMode=production (user-provided handleError)" , ( ) => {
422
+ test . beforeAll ( async ( ) => {
423
+ fixture = await createFixture (
424
+ {
425
+ files : {
426
+ "app/entry.server.tsx" : js `
427
+ import type { EntryContext } from "@remix-run/node";
428
+ import { RemixServer, isRouteErrorResponse } from "@remix-run/react";
429
+ import { renderToString } from "react-dom/server";
430
+
431
+ export default function handleRequest(
432
+ request: Request,
433
+ responseStatusCode: number,
434
+ responseHeaders: Headers,
435
+ remixContext: EntryContext
436
+ ) {
437
+ let markup = renderToString(
438
+ <RemixServer context={remixContext} url={request.url} />
439
+ );
440
+
441
+ responseHeaders.set("Content-Type", "text/html");
442
+
443
+ return new Response("<!DOCTYPE html>" + markup, {
444
+ status: responseStatusCode,
445
+ headers: responseHeaders,
446
+ });
447
+ }
448
+
449
+ export function handleError(error: unknown, { request }: { request: Request }) {
450
+ console.error("App Specific Error Logging:");
451
+ console.error(" Request: " + request.method + " " + request.url);
452
+ let msg;
453
+ if (isRouteErrorResponse(error)) {
454
+ console.error(" Error: " + error.status + " " + error.statusText);
455
+ } else if (error instanceof Error) {
456
+ console.error(" Error: " + error.message);
457
+ console.error(" Stack: " + error.stack);
458
+ } else {
459
+ console.error("Dunno what this is");
460
+ }
461
+ }
462
+ ` ,
463
+ ...routeFiles ,
464
+ } ,
465
+ } ,
466
+ ServerMode . Production
467
+ ) ;
468
+ } ) ;
469
+
470
+ test ( "renders document without errors" , async ( ) => {
471
+ let response = await fixture . requestDocument ( "/" ) ;
472
+ let html = await response . text ( ) ;
473
+ expect ( html ) . toMatch ( "Index Route" ) ;
474
+ expect ( html ) . toMatch ( "LOADER" ) ;
475
+ expect ( html ) . not . toMatch ( "MESSAGE:" ) ;
476
+ expect ( html ) . not . toMatch ( / s t a c k / i) ;
477
+ } ) ;
478
+
479
+ test ( "sanitizes loader errors in document requests" , async ( ) => {
480
+ let response = await fixture . requestDocument ( "/?loader" ) ;
481
+ let html = await response . text ( ) ;
482
+ expect ( html ) . toMatch ( "Index Error" ) ;
483
+ expect ( html ) . not . toMatch ( "LOADER" ) ;
484
+ expect ( html ) . toMatch ( "MESSAGE:Unexpected Server Error" ) ;
485
+ expect ( html ) . toMatch (
486
+ '{"routes/index":{"message":"Unexpected Server Error","__type":"Error"}}'
487
+ ) ;
488
+ expect ( html ) . not . toMatch ( / s t a c k / i) ;
489
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
490
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual ( " Request: GET test://test/?loader" ) ;
491
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Loader Error" ) ;
492
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
493
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
494
+ } ) ;
495
+
496
+ test ( "sanitizes render errors in document requests" , async ( ) => {
497
+ let response = await fixture . requestDocument ( "/?render" ) ;
498
+ let html = await response . text ( ) ;
499
+ expect ( html ) . toMatch ( "Index Error" ) ;
500
+ expect ( html ) . toMatch ( "MESSAGE:Unexpected Server Error" ) ;
501
+ expect ( html ) . toMatch (
502
+ '{"routes/index":{"message":"Unexpected Server Error","__type":"Error"}}'
503
+ ) ;
504
+ expect ( html ) . not . toMatch ( / s t a c k / i) ;
505
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
506
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual ( " Request: GET test://test/?render" ) ;
507
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Render Error" ) ;
508
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
509
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
510
+ } ) ;
511
+
512
+ test ( "renders deferred document without errors" , async ( ) => {
513
+ let response = await fixture . requestDocument ( "/defer" ) ;
514
+ let html = await response . text ( ) ;
515
+ expect ( html ) . toMatch ( "Defer Route" ) ;
516
+ expect ( html ) . toMatch ( "RESOLVED" ) ;
517
+ expect ( html ) . not . toMatch ( "MESSAGE:" ) ;
518
+ // Defer errors are not not part of the JSON blob but rather rejected
519
+ // against a pending promise and therefore are inlined JS.
520
+ expect ( html ) . not . toMatch ( "x.stack=e.stack;" ) ;
521
+ } ) ;
522
+
523
+ test ( "sanitizes defer errors in document requests" , async ( ) => {
524
+ let response = await fixture . requestDocument ( "/defer?loader" ) ;
525
+ let html = await response . text ( ) ;
526
+ expect ( html ) . toMatch ( "Defer Error" ) ;
527
+ expect ( html ) . not . toMatch ( "RESOLVED" ) ;
528
+ expect ( html ) . toMatch ( '{"message":"Unexpected Server Error"}' ) ;
529
+ // Defer errors are not not part of the JSON blob but rather rejected
530
+ // against a pending promise and therefore are inlined JS.
531
+ expect ( html ) . toMatch ( "x.stack=undefined;" ) ;
532
+ // defer errors are not logged to the server console since the request
533
+ // has "succeeded"
534
+ expect ( errorLogs . length ) . toBe ( 0 ) ;
535
+ } ) ;
536
+
537
+ test ( "returns data without errors" , async ( ) => {
538
+ let response = await fixture . requestData ( "/" , "routes/index" ) ;
539
+ let text = await response . text ( ) ;
540
+ expect ( text ) . toMatch ( "LOADER" ) ;
541
+ expect ( text ) . not . toMatch ( "MESSAGE:" ) ;
542
+ expect ( text ) . not . toMatch ( / s t a c k / i) ;
543
+ } ) ;
544
+
545
+ test ( "sanitizes loader errors in data requests" , async ( ) => {
546
+ let response = await fixture . requestData ( "/?loader" , "routes/index" ) ;
547
+ let text = await response . text ( ) ;
548
+ expect ( text ) . toBe ( '{"message":"Unexpected Server Error"}' ) ;
549
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
550
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual (
551
+ " Request: GET test://test/?loader=&_data=routes%2Findex"
552
+ ) ;
553
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Loader Error" ) ;
554
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
555
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
556
+ } ) ;
557
+
558
+ test ( "returns deferred data without errors" , async ( ) => {
559
+ let response = await fixture . requestData ( "/defer" , "routes/defer" ) ;
560
+ let text = await response . text ( ) ;
561
+ expect ( text ) . toMatch ( "RESOLVED" ) ;
562
+ expect ( text ) . not . toMatch ( "REJECTED" ) ;
563
+ expect ( text ) . not . toMatch ( / s t a c k / i) ;
564
+ } ) ;
565
+
566
+ test ( "sanitizes loader errors in deferred data requests" , async ( ) => {
567
+ let response = await fixture . requestData ( "/defer?loader" , "routes/defer" ) ;
568
+ let text = await response . text ( ) ;
569
+ expect ( text ) . toBe (
570
+ '{"lazy":"__deferred_promise:lazy"}\n\n' +
571
+ 'error:{"lazy":{"message":"Unexpected Server Error"}}\n\n'
572
+ ) ;
573
+ // defer errors are not logged to the server console since the request
574
+ // has "succeeded"
575
+ expect ( errorLogs . length ) . toBe ( 0 ) ;
576
+ } ) ;
577
+
578
+ test ( "sanitizes loader errors in resource requests" , async ( ) => {
579
+ let response = await fixture . requestData (
580
+ "/resource?loader" ,
581
+ "routes/resource"
582
+ ) ;
583
+ let text = await response . text ( ) ;
584
+ expect ( text ) . toBe ( '{"message":"Unexpected Server Error"}' ) ;
585
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
586
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual (
587
+ " Request: GET test://test/resource?loader=&_data=routes%2Fresource"
588
+ ) ;
589
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Loader Error" ) ;
590
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
591
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
592
+ } ) ;
593
+
594
+ test ( "sanitizes mismatched route errors in data requests" , async ( ) => {
595
+ let response = await fixture . requestData ( "/" , "not-a-route" ) ;
596
+ let text = await response . text ( ) ;
597
+ expect ( text ) . toBe ( '{"message":"Unexpected Server Error"}' ) ;
598
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
599
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual (
600
+ " Request: GET test://test/?_data=not-a-route"
601
+ ) ;
602
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual (
603
+ ' Error: Route "not-a-route" does not match URL "/"'
604
+ ) ;
605
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
606
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
607
+ } ) ;
608
+ } ) ;
420
609
} ) ;
0 commit comments