@@ -417,4 +417,194 @@ 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
+ debugger;
453
+ let msg;
454
+ if (isRouteErrorResponse(error)) {
455
+ console.error(" Error: " + error.status + " " + error.statusText);
456
+ } else if (error instanceof Error) {
457
+ console.error(" Error: " + error.message);
458
+ console.error(" Stack: " + error.stack);
459
+ } else {
460
+ console.error("Dunno what this is");
461
+ }
462
+ }
463
+ ` ,
464
+ ...routeFiles ,
465
+ } ,
466
+ } ,
467
+ ServerMode . Production
468
+ ) ;
469
+ } ) ;
470
+
471
+ test ( "renders document without errors" , async ( ) => {
472
+ let response = await fixture . requestDocument ( "/" ) ;
473
+ let html = await response . text ( ) ;
474
+ expect ( html ) . toMatch ( "Index Route" ) ;
475
+ expect ( html ) . toMatch ( "LOADER" ) ;
476
+ expect ( html ) . not . toMatch ( "MESSAGE:" ) ;
477
+ expect ( html ) . not . toMatch ( / s t a c k / i) ;
478
+ } ) ;
479
+
480
+ test ( "sanitizes loader errors in document requests" , async ( ) => {
481
+ let response = await fixture . requestDocument ( "/?loader" ) ;
482
+ let html = await response . text ( ) ;
483
+ expect ( html ) . toMatch ( "Index Error" ) ;
484
+ expect ( html ) . not . toMatch ( "LOADER" ) ;
485
+ expect ( html ) . toMatch ( "MESSAGE:Unexpected Server Error" ) ;
486
+ expect ( html ) . toMatch (
487
+ '{"routes/index":{"message":"Unexpected Server Error","__type":"Error"}}'
488
+ ) ;
489
+ expect ( html ) . not . toMatch ( / s t a c k / i) ;
490
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
491
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual ( " Request: GET test://test/?loader" ) ;
492
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Loader Error" ) ;
493
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
494
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
495
+ } ) ;
496
+
497
+ test ( "sanitizes render errors in document requests" , async ( ) => {
498
+ let response = await fixture . requestDocument ( "/?render" ) ;
499
+ let html = await response . text ( ) ;
500
+ expect ( html ) . toMatch ( "Index Error" ) ;
501
+ expect ( html ) . toMatch ( "MESSAGE:Unexpected Server Error" ) ;
502
+ expect ( html ) . toMatch (
503
+ '{"routes/index":{"message":"Unexpected Server Error","__type":"Error"}}'
504
+ ) ;
505
+ expect ( html ) . not . toMatch ( / s t a c k / i) ;
506
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
507
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual ( " Request: GET test://test/?render" ) ;
508
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Render Error" ) ;
509
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
510
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
511
+ } ) ;
512
+
513
+ test ( "renders deferred document without errors" , async ( ) => {
514
+ let response = await fixture . requestDocument ( "/defer" ) ;
515
+ let html = await response . text ( ) ;
516
+ expect ( html ) . toMatch ( "Defer Route" ) ;
517
+ expect ( html ) . toMatch ( "RESOLVED" ) ;
518
+ expect ( html ) . not . toMatch ( "MESSAGE:" ) ;
519
+ // Defer errors are not not part of the JSON blob but rather rejected
520
+ // against a pending promise and therefore are inlined JS.
521
+ expect ( html ) . not . toMatch ( "x.stack=e.stack;" ) ;
522
+ } ) ;
523
+
524
+ test ( "sanitizes defer errors in document requests" , async ( ) => {
525
+ let response = await fixture . requestDocument ( "/defer?loader" ) ;
526
+ let html = await response . text ( ) ;
527
+ expect ( html ) . toMatch ( "Defer Error" ) ;
528
+ expect ( html ) . not . toMatch ( "RESOLVED" ) ;
529
+ expect ( html ) . toMatch ( '{"message":"Unexpected Server Error"}' ) ;
530
+ // Defer errors are not not part of the JSON blob but rather rejected
531
+ // against a pending promise and therefore are inlined JS.
532
+ expect ( html ) . toMatch ( "x.stack=undefined;" ) ;
533
+ // defer errors are not logged to the server console since the request
534
+ // has "succeeded"
535
+ expect ( errorLogs . length ) . toBe ( 0 ) ;
536
+ } ) ;
537
+
538
+ test ( "returns data without errors" , async ( ) => {
539
+ let response = await fixture . requestData ( "/" , "routes/index" ) ;
540
+ let text = await response . text ( ) ;
541
+ expect ( text ) . toMatch ( "LOADER" ) ;
542
+ expect ( text ) . not . toMatch ( "MESSAGE:" ) ;
543
+ expect ( text ) . not . toMatch ( / s t a c k / i) ;
544
+ } ) ;
545
+
546
+ test ( "sanitizes loader errors in data requests" , async ( ) => {
547
+ let response = await fixture . requestData ( "/?loader" , "routes/index" ) ;
548
+ let text = await response . text ( ) ;
549
+ expect ( text ) . toBe ( '{"message":"Unexpected Server Error"}' ) ;
550
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
551
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual (
552
+ " Request: GET test://test/?loader=&_data=routes%2Findex"
553
+ ) ;
554
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Loader Error" ) ;
555
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
556
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
557
+ } ) ;
558
+
559
+ test ( "returns deferred data without errors" , async ( ) => {
560
+ let response = await fixture . requestData ( "/defer" , "routes/defer" ) ;
561
+ let text = await response . text ( ) ;
562
+ expect ( text ) . toMatch ( "RESOLVED" ) ;
563
+ expect ( text ) . not . toMatch ( "REJECTED" ) ;
564
+ expect ( text ) . not . toMatch ( / s t a c k / i) ;
565
+ } ) ;
566
+
567
+ test ( "sanitizes loader errors in deferred data requests" , async ( ) => {
568
+ let response = await fixture . requestData ( "/defer?loader" , "routes/defer" ) ;
569
+ let text = await response . text ( ) ;
570
+ expect ( text ) . toBe (
571
+ '{"lazy":"__deferred_promise:lazy"}\n\n' +
572
+ 'error:{"lazy":{"message":"Unexpected Server Error"}}\n\n'
573
+ ) ;
574
+ // defer errors are not logged to the server console since the request
575
+ // has "succeeded"
576
+ expect ( errorLogs . length ) . toBe ( 0 ) ;
577
+ } ) ;
578
+
579
+ test ( "sanitizes loader errors in resource requests" , async ( ) => {
580
+ let response = await fixture . requestData (
581
+ "/resource?loader" ,
582
+ "routes/resource"
583
+ ) ;
584
+ let text = await response . text ( ) ;
585
+ expect ( text ) . toBe ( '{"message":"Unexpected Server Error"}' ) ;
586
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
587
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual (
588
+ " Request: GET test://test/resource?loader=&_data=routes%2Fresource"
589
+ ) ;
590
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual ( " Error: Loader Error" ) ;
591
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
592
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
593
+ } ) ;
594
+
595
+ test ( "sanitizes mismatched route errors in data requests" , async ( ) => {
596
+ let response = await fixture . requestData ( "/" , "not-a-route" ) ;
597
+ let text = await response . text ( ) ;
598
+ expect ( text ) . toBe ( '{"message":"Unexpected Server Error"}' ) ;
599
+ expect ( errorLogs [ 0 ] [ 0 ] ) . toEqual ( "App Specific Error Logging:" ) ;
600
+ expect ( errorLogs [ 1 ] [ 0 ] ) . toEqual (
601
+ " Request: GET test://test/?_data=not-a-route"
602
+ ) ;
603
+ expect ( errorLogs [ 2 ] [ 0 ] ) . toEqual (
604
+ ' Error: Route "not-a-route" does not match URL "/"'
605
+ ) ;
606
+ expect ( errorLogs [ 3 ] [ 0 ] ) . toMatch ( " at " ) ;
607
+ expect ( errorLogs . length ) . toBe ( 4 ) ;
608
+ } ) ;
609
+ } ) ;
420
610
} ) ;
0 commit comments