# All files / src/components/error ErrorFallback.tsx

0% Statements 0/101
0% Branches 0/1
0% Functions 0/1
0% Lines 0/101

Press n or j to go to the next uncovered block, b, p or k for the previous block.

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102

     import { useState } from "react";
    import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
    import { AIErrorHelper } from "@/components/error/AIErrorHelper";
    import { Button } from "@/components/ui/button";
    import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
    import { AlertTriangleIcon, RefreshCwIcon, ChevronDownIcon, ChevronUpIcon, CopyIcon, CheckIcon } from "lucide-react";

    interface ErrorFallbackProps {
      error: Error;
    }

    export function ErrorFallback({ error }: ErrorFallbackProps) {
      // Only throw in development environment (not in tests)
      if (typeof process !== 'undefined' && process.env.NODE_ENV === 'development') {
        throw error;
      }

      const [isStackOpen, setIsStackOpen] = useState(false);
      const [copied, setCopied] = useState(false);

      const errorDetails = `Error: ${error.message}\n\nStack Trace:\n${error.stack || 'No stack trace available'}`;

      const handleCopy = () => {
        navigator.clipboard.writeText(errorDetails);
        setCopied(true);
        setTimeout(() => setCopied(false), 2000);
      };

      return (
        <div className="min-h-screen bg-background flex items-center justify-center p-4" data-testid="error-fallback">
          <div className="w-full max-w-3xl">
            <Alert variant="destructive" className="mb-6" data-testid="error-alert">
              <AlertTriangleIcon aria-hidden="true" />
              <AlertTitle>This spark has encountered a runtime error</AlertTitle>
              <AlertDescription className="mt-3 space-y-4">
                <div className="flex items-center justify-between gap-2">
                  <code
                    className="text-sm bg-destructive/20 px-2 py-1 rounded flex-1 break-all"
                    data-testid="error-message"
                  >
                    {error.message}
                  </code>
                  <Button
                    size="sm"
                    variant="outline"
                    onClick={handleCopy}
                    className="shrink-0"
                    data-testid="copy-error-btn"
                    aria-label="Copy error details"
                  >
                    {copied ? (
                      <>
                        <CheckIcon className="h-3.5 w-3.5" />
                        Copied
                      </>
                    ) : (
                      <>
                        <CopyIcon className="h-3.5 w-3.5" />
                        Copy
                      </>
                    )}
                  </Button>
                </div>

                <Collapsible open={isStackOpen} onOpenChange={setIsStackOpen}>
                  <CollapsibleTrigger className="w-full justify-between">
                    {isStackOpen ? (
                      <>
                        Hide Stack Trace <ChevronUpIcon className="h-4 w-4 ml-2" />
                      </>
                    ) : (
                      <>
                        Show Stack Trace <ChevronDownIcon className="h-4 w-4 ml-2" />
                      </>
                    )}
                  </CollapsibleTrigger>
                  <CollapsibleContent>
                    <div className="mt-4">
                      <pre className="text-xs bg-destructive/10 p-3 rounded overflow-auto max-h-60">
                        {error.stack || 'No stack trace available'}
                      </pre>
                    </div>
                  </CollapsibleContent>
                </Collapsible>
              </AlertDescription>
            </Alert>

            <AIErrorHelper error={error} />

            <Button
              onClick={() => window.location.reload()}
              className="w-full mt-6"
              variant="outline"
            >
              <RefreshCwIcon className="h-4 w-4 mr-2" />
              Try Reloading
            </Button>
          </div>
        </div>
      );
    }