Ctrl K
ComunidadGuías…

lib/content-toaster.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
// @vitest-environment jsdom

import { act, createElement } from "react";
import { createRoot, type Root } from "react-dom/client";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { toast } from "sonner";
import { ContentToaster } from "@/components/content-toaster";

let pane: HTMLDivElement;
let main: HTMLElement;
let root: Root;

beforeEach(() => {
  toast.dismiss();
  window.localStorage.clear();
  vi.stubGlobal("IS_REACT_ACT_ENVIRONMENT", true);
  vi.stubGlobal("matchMedia", () => ({ matches: false, addEventListener() {}, removeEventListener() {} }));
  vi.stubGlobal("requestAnimationFrame", (callback: FrameRequestCallback) => window.setTimeout(() => callback(Date.now()), 1));
  vi.stubGlobal("cancelAnimationFrame", (id: number) => window.clearTimeout(id));
  vi.spyOn(document, "hidden", "get").mockReturnValue(false);
  vi.useFakeTimers();
  pane = document.createElement("div");
  main = document.createElement("main");
  pane.appendChild(main);
  document.body.appendChild(pane);
  root = createRoot(main);
});

afterEach(() => {
  act(() => root.unmount());
  pane.remove();
  vi.restoreAllMocks();
  vi.unstubAllGlobals();
  vi.useRealTimers();
});

function render() {
  act(() => root.render(createElement(ContentToaster)));
}

function fire(fn: () => void) {
  act(fn);
  act(() => { vi.advanceTimersByTime(20); });
}

const title = () => pane.querySelector("[data-title]")?.textContent;
const notification = () => pane.querySelector("[data-sonner-toast]");

describe("the content toaster", () => {
  it("anchors a single toast surface to the pane outside the scrolling main", () => {
    render();
    fire(() => toast.success("Copied"));
    const surface = pane.querySelector(".content-toaster");
    expect(surface?.getAttribute("data-x-position")).toBe("center");
    expect(surface?.getAttribute("data-y-position")).toBe("bottom");
    expect(pane.querySelectorAll("[data-sonner-toaster]")).toHaveLength(1);
    expect(main.querySelector("[data-sonner-toaster]")).toBeNull();
    expect(title()).toBe("Copied");
    expect(pane.querySelector('[aria-live="polite"]')).not.toBeNull();
  });

  it.each(["info", "success", "warning", "error"] as const)("keeps %s feedback typed for its colored badge", (kind) => {
    render();
    fire(() => toast[kind](`${kind} feedback`));
    expect(notification()?.getAttribute("data-type")).toBe(kind);
    expect(title()).toBe(`${kind} feedback`);
  });

  it("keeps bare copy confirmations visible", () => {
    render();
    fire(() => toast("Copied"));
    expect(title()).toBe("Copied");
    expect(notification()?.getAttribute("data-type")).toBeNull();
  });

  it("updates the same toast id without duplicating the message", () => {
    render();
    fire(() => toast.info("Dictating…", { id: "dictation-in-flight" }));
    fire(() => toast.success("Done", { id: "dictation-in-flight" }));
    expect(title()).toBe("Done");
    expect(pane.querySelectorAll("[data-sonner-toast]")).toHaveLength(1);
    expect(pane.textContent).not.toContain("Dictating…");
  });

  it("automatically expires messages and removes them from Sonner's active store", () => {
    render();
    fire(() => toast.success("Saved", { id: "expires" }));
    act(() => { vi.advanceTimersByTime(4_000); });
    act(() => { vi.advanceTimersByTime(250); });
    expect(notification()).toBeNull();
    expect(toast.getToasts().some((entry) => entry.id === "expires")).toBe(false);
  });

  it("honors explicit dismissal", () => {
    render();
    fire(() => toast.info("In flight", { id: "dismissed" }));
    fire(() => toast.dismiss("dismissed"));
    act(() => { vi.advanceTimersByTime(500); });
    act(() => { vi.advanceTimersByTime(250); });
    expect(notification()).toBeNull();
  });

  it("purges legacy error history without restoring or saving errors", () => {
    window.localStorage.setItem("minddy:status-errors", '{"format":"minddy-local-v1","ciphertext":"old"}');
    const save = vi.spyOn(Storage.prototype, "setItem");
    const fetch = vi.fn();
    vi.stubGlobal("fetch", fetch);
    render();
    fire(() => toast.error("Failure"));
    expect(window.localStorage.getItem("minddy:status-errors")).toBeNull();
    expect(save).not.toHaveBeenCalled();
    expect(fetch).not.toHaveBeenCalled();
    expect(pane.querySelectorAll("button")).toHaveLength(1); // Only Sonner's dismiss control.
  });
});