Ctrl K
ComunidadGuías…

src/components/dives/dives-page-frame.render.test.tsx

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

Archivo original ↗Preguntar a KiBot
import { describe, expect, it, vi } from "vitest";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";

import { DivesPageFrame } from "./dives-page-frame";
import { NO_DIVE_FILTERS } from "./dives-filters";

// The courses list's panel, pinned the same way: it is reachable, shutting it
// takes the filters with it rather than leaving a folded row narrowing the list
// unseen, and a list filtered to nothing says so in one line rather than as an
// empty logbook.

const frame = (props: Partial<Parameters<typeof DivesPageFrame>[0]> = {}) =>
  render(
    <DivesPageFrame
      isLoading={false}
      totalCount={0}
      itemsPerPage={10}
      cards={[<li key="d" />]}
      {...props}
    />,
  );

const toggle = () =>
  screen.getByRole("button", {
    name: /^(Filter and sort dives|Close filters)/,
  });

describe("DivesPageFrame", () => {
  it("offers Import beside Log new dive in its header", () => {
    frame();

    expect(screen.getByRole("link", { name: "Import" })).toHaveAttribute(
      "href",
      "/import",
    );
    expect(screen.getByRole("link", { name: "Log new dive" })).toHaveAttribute(
      "href",
      "/dives/new",
    );
  });

  it("keeps the filters shut until the button is pressed", async () => {
    frame();

    expect(screen.getByLabelText("Tag")).not.toBeVisible();
    expect(toggle()).toHaveAttribute("aria-expanded", "false");

    await userEvent.click(toggle());

    expect(screen.getByLabelText("Tag")).toBeVisible();
    expect(screen.getByLabelText("Dive type")).toBeVisible();
    expect(screen.getByLabelText("Sort")).toBeVisible();
    expect(toggle()).toHaveAttribute("aria-expanded", "true");
  });

  it("clears every filter and the sort as it shuts, and says so while there is something to clear", async () => {
    const onFiltersChange = vi.fn();
    frame({
      filters: { ...NO_DIVE_FILTERS, sort: "rating" },
      onFiltersChange,
    });

    await userEvent.click(toggle());
    expect(onFiltersChange).not.toHaveBeenCalled();
    expect(
      screen.getByRole("button", { name: "Close filters, clearing them" }),
    ).toBeInTheDocument();

    await userEvent.click(toggle());
    expect(onFiltersChange).toHaveBeenCalledWith(NO_DIVE_FILTERS);
  });

  it("says only that it closes when nothing is set", async () => {
    frame();

    await userEvent.click(toggle());

    expect(
      screen.getByRole("button", { name: "Close filters" }),
    ).toBeInTheDocument();
  });

  // The diver's tags are read off the back of this, so a visit that never opens
  // the panel never asks for them.
  it("says when the panel is opened, and not when it is shut again", async () => {
    const onFiltersOpened = vi.fn();
    frame({ onFiltersOpened });

    await userEvent.click(toggle());
    await userEvent.click(toggle());

    expect(onFiltersOpened).toHaveBeenCalledTimes(1);
  });

  it("offers the tags it is handed", async () => {
    frame({
      tags: [
        {
          uuid: "tag-night",
          name: "night",
          dive_count: 2,
          site_count: 0,
          created_at: "2026-01-01T00:00:00Z",
        },
      ],
    });

    await userEvent.click(toggle());

    expect(
      [...screen.getByLabelText<HTMLSelectElement>("Tag").options].map(
        (option) => option.text,
      ),
    ).toEqual(["Any tag", "night"]);
  });

  it("answers a filter that matched nothing in one line, keeping the count and the button", () => {
    frame({
      cards: [],
      filters: { ...NO_DIVE_FILTERS, type: "snorkel" },
      isCountNarrowed: true,
    });

    expect(
      screen.getByText("No dives match those filters."),
    ).toBeInTheDocument();
    expect(screen.getByText("0 dives found")).toBeInTheDocument();
    expect(toggle()).toBeInTheDocument();
    expect(
      screen.queryByRole("link", { name: /log your first dive/i }),
    ).not.toBeInTheDocument();
  });

  it("shows an empty logbook as one, with no button to filter nothing", () => {
    frame({ cards: [] });

    expect(screen.getByText("No dives logged yet")).toBeInTheDocument();
    expect(
      screen.queryByRole("button", { name: /^Filter and sort dives/ }),
    ).not.toBeInTheDocument();
    expect(screen.queryByLabelText("Tag")).not.toBeInTheDocument();
  });

  // Sorting orders every dive, so an empty list sorted by rating is still an
  // empty logbook.
  it("reads an empty list sorted by rating as an empty logbook", () => {
    frame({ cards: [], filters: { ...NO_DIVE_FILTERS, sort: "rating" } });

    expect(screen.getByText("No dives logged yet")).toBeInTheDocument();
  });
});