import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
import { render, screen, cleanup } from "@testing-library/react";
import { ErrorBoundary } from "../ErrorBoundary";

function ThrowingChild(): never {
  throw new Error("synthetic render-time failure for GRO-2094");
}

function GoodChild() {
  return <div data-testid="good-child">ok</div>;
}

describe("ErrorBoundary (GRO-2094)", () => {
  let errorSpy: ReturnType<typeof vi.spyOn>;

  beforeEach(() => {
    // React 18+ logs caught render errors to console.error via React's own
    // instrumentation; suppress it so test output is clean but capture it
    // for an assertion below.
    errorSpy = vi.spyOn(console, "error").mockImplementation(() => {});
  });

  afterEach(() => {
    errorSpy.mockRestore();
    cleanup();
  });

  it("renders children when nothing throws", () => {
    render(
      <ErrorBoundary>
        <GoodChild />
      </ErrorBoundary>
    );
    expect(screen.getByTestId("good-child")).toBeInTheDocument();
    expect(screen.queryByTestId("error-boundary")).not.toBeInTheDocument();
  });

  it("renders the error visibly when a child throws during render", () => {
    render(
      <ErrorBoundary>
        <ThrowingChild />
      </ErrorBoundary>
    );

    const fallback = screen.getByTestId("error-boundary");
    expect(fallback).toBeInTheDocument();
    const message = screen.getByTestId("error-boundary-message");
    // The actual exception is shown — no more silent blank root.
    expect(message.textContent).toContain("synthetic render-time failure for GRO-2094");
    // The boundary also calls console.error so it shows up in the Playwright
    // console log even if the DOM-rendered fallback is somehow missed.
    expect(errorSpy).toHaveBeenCalled();
  });
});
