Ctrl K
ComunidadGuías…

src/components/dives/dive-drafts-card.render.test.tsx

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

Archivo original ↗Preguntar a KiBot
import { beforeEach, describe, expect, it, vi } from "vitest";
import { render, screen, waitFor, within } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { DiveDraftsCard } from "./dive-drafts-card";
import type { DiveDraft, DiveDraftValuesRead } from "@/lib/api/dive-drafts";

vi.mock("@/lib/api/dive-drafts", () => ({
  diveDraftsAPI: { getDrafts: vi.fn(), deleteDraft: vi.fn() },
}));
vi.mock("@/lib/api/dive-sites", () => ({
  diveSitesAPI: { lookupDiveSitesByUuid: vi.fn() },
}));
const toast = vi.fn();
vi.mock("@/components/ui/use-toast", () => ({ useToast: () => ({ toast }) }));

const { diveDraftsAPI } = await import("@/lib/api/dive-drafts");
const { diveSitesAPI } = await import("@/lib/api/dive-sites");

const draft = (
  uuid: string,
  values: Partial<DiveDraftValuesRead> = {},
): DiveDraft => ({
  uuid,
  created_at: "2026-10-20T08:00:00Z",
  updated_at: "2026-10-21T08:00:00Z",
  gear_set_uuid: null,
  values: {
    start_time: null,
    dive_site_uuids: null,
    ...values,
  } as DiveDraftValuesRead,
});

const page = (data: DiveDraft[]) => ({
  data,
  total_count: data.length,
  has_more: false,
  page: 1,
  items_per_page: 100,
});

beforeEach(() => {
  vi.clearAllMocks();
  vi.mocked(diveSitesAPI.lookupDiveSitesByUuid).mockResolvedValue([
    {
      uuid: "site-1",
      name: "Blue Hole",
      owner: "account",
      saved: true,
      attribution: null,
    },
  ]);
  vi.mocked(diveDraftsAPI.deleteDraft).mockResolvedValue({
    message: "Dive draft deleted",
  });
});

describe("DiveDraftsCard", () => {
  it("draws nothing when the account has no drafts", async () => {
    vi.mocked(diveDraftsAPI.getDrafts).mockResolvedValue(page([]));
    const { container } = render(<DiveDraftsCard enabled />);

    await waitFor(() => expect(diveDraftsAPI.getDrafts).toHaveBeenCalled());
    expect(container).toBeEmptyDOMElement();
    expect(diveSitesAPI.lookupDiveSitesByUuid).not.toHaveBeenCalled();
  });

  it("lists each draft with its start, its site and Continue", async () => {
    vi.mocked(diveDraftsAPI.getDrafts).mockResolvedValue(
      page([
        draft("draft-1", {
          start_time: "2026-07-01T09:30:00+02:00",
          dive_site_uuids: ["site-1", "site-2"],
        }),
        draft("draft-2"),
      ]),
    );
    render(<DiveDraftsCard enabled />);

    const rows = await screen.findAllByRole("listitem");
    expect(rows).toHaveLength(2);
    expect(rows[0]).toHaveTextContent(/July 1, 2026 at 09:30/);
    await waitFor(() => expect(rows[0]).toHaveTextContent(/Blue Hole/));
    expect(rows[1]).toHaveTextContent("Untitled draft");
    expect(rows[1]).toHaveTextContent(/Changed/);
    expect(
      within(rows[0]).getByRole("link", { name: /Continue/ }),
    ).toHaveAttribute("href", "/dives/new?draft=draft-1");
    // One lookup, over the primary sites only.
    expect(diveSitesAPI.lookupDiveSitesByUuid).toHaveBeenCalledTimes(1);
    expect(diveSitesAPI.lookupDiveSitesByUuid).toHaveBeenCalledWith(["site-1"]);
  });

  it("discards a draft after a confirmation, and goes with the last one", async () => {
    vi.mocked(diveDraftsAPI.getDrafts).mockResolvedValue(
      page([draft("draft-1")]),
    );
    const onVanished = vi.fn();
    const { container } = render(
      <DiveDraftsCard enabled onVanished={onVanished} />,
    );

    await userEvent.click(
      await screen.findByRole("button", { name: /Discard/ }),
    );
    expect(diveDraftsAPI.deleteDraft).not.toHaveBeenCalled();
    await userEvent.click(
      within(screen.getByRole("dialog")).getByRole("button", {
        name: "Discard",
      }),
    );

    await waitFor(() =>
      expect(diveDraftsAPI.deleteDraft).toHaveBeenCalledWith("draft-1"),
    );
    await waitFor(() => expect(container).toBeEmptyDOMElement());
    expect(onVanished).toHaveBeenCalled();
  });

  it("drops a draft that was already gone when discarded", async () => {
    vi.mocked(diveDraftsAPI.getDrafts).mockResolvedValue(
      page([draft("draft-1"), draft("draft-2")]),
    );
    vi.mocked(diveDraftsAPI.deleteDraft).mockRejectedValue({
      response: { status: 404 },
    });
    render(<DiveDraftsCard enabled />);

    await userEvent.click(
      (await screen.findAllByRole("button", { name: /Discard/ }))[0],
    );
    await userEvent.click(
      within(screen.getByRole("dialog")).getByRole("button", {
        name: "Discard",
      }),
    );

    await waitFor(() =>
      expect(screen.getAllByRole("listitem")).toHaveLength(1),
    );
    expect(toast).not.toHaveBeenCalled();
  });
});