Ctrl K
ComunidadGuías…

tests/account-invoices.spec.ts

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

Archivo original ↗Preguntar a KiBot
import { expect } from "@playwright/test";

import { Plan, TeamUser } from "../apps/backend/src/database/models";
import { createInvoicesScenario } from "../apps/backend/src/database/seeds";
import { loggedTest } from "./logged-test";
import { ensureTeamOwner, screenshot } from "./util";

loggedTest.beforeEach(async ({ auth, team }) => {
  await ensureTeamOwner({ team: team.team, user: auth.user });
});

loggedTest("account invoices - billing history", async ({ page, team }) => {
  await createInvoicesScenario({ accountId: team.account.id });

  await page.goto(`/${team.account.slug}/settings/invoices`);

  await expect(page.getByRole("heading", { name: "Invoices" })).toBeVisible();

  // Most recent first, with what tells them apart: the month, the number the
  // customer's accounting quotes, whether it is settled, and the amount.
  const rows = page.getByRole("row");
  await expect(rows).toHaveCount(5);
  await expect(rows.first()).toContainText("August 2026");
  await expect(rows.first()).toContainText("ARGOS-0005");
  await expect(rows.first()).toContainText("Due");
  await expect(rows.first()).toContainText("€249.00");
  await expect(rows.nth(1)).toContainText("Paid");
  await expect(rows.nth(2)).toContainText("Void");
  // Stripe keeps a refunded invoice paid: the refund has to show regardless.
  await expect(rows.nth(3)).toContainText("Partially refunded");
  await expect(rows.nth(3)).toContainText("€50.00 refunded");
  await expect(rows.nth(4)).toContainText("Refunded");

  // Before the menu is touched: a trigger left focused would freeze its own
  // hover state into the baseline.
  await screenshot(page, "account-invoices");

  // Both ways to the document itself hang off the row's menu.
  await page
    .getByRole("button", { name: "Invoice ARGOS-0004 actions" })
    .click();
  await expect(
    page.getByRole("option", { name: "View invoice" }),
  ).toHaveAttribute("href", /\/invoices\/\d+\/view$/);
  await expect(
    page.getByRole("option", { name: "Download PDF" }),
  ).toHaveAttribute("href", /\/invoices\/\d+\/pdf$/);
});

loggedTest(
  "account invoices - reachable from the settings nav",
  async ({ page, team }) => {
    await createInvoicesScenario({ accountId: team.account.id });

    await page.goto(`/${team.account.slug}/settings`);
    await page.getByRole("link", { name: "Invoices" }).click();

    await expect(page.getByRole("heading", { name: "Invoices" })).toBeVisible();
    await expect(page).toHaveURL(
      new RegExp(`/${team.account.slug}/settings/invoices`),
    );
  },
);

loggedTest(
  "account invoices - no tab for a member, nor for a yearly contract",
  async ({ page, team, auth, plan }) => {
    await createInvoicesScenario({ accountId: team.account.id });

    // A yearly plan is a negotiated contract, invoiced by the sales side.
    await Plan.query().patch({ interval: "year" }).where("id", plan.id);
    await page.goto(`/${team.account.slug}/settings`);
    await expect(page.getByRole("link", { name: "Billing" })).toBeVisible();
    await expect(page.getByRole("link", { name: "Invoices" })).toHaveCount(0);

    await Plan.query().patch({ interval: "month" }).where("id", plan.id);
    await TeamUser.query()
      .patch({ userLevel: "member" })
      .where({ teamId: team.team.id, userId: auth.user.id });

    await page.goto(`/${team.account.slug}/settings`);
    await expect(page.getByRole("link", { name: "Invoices" })).toHaveCount(0);
  },
);