chore(adminsite): remove the frontend test suite

Removes vitest, React Testing Library, the config, the setup file and all
eleven test files, plus the test scripts and dev dependencies. Done at the
user's direction; it matches the rest of the repo, which has no automated
tests in any language.

All eleven were observed passing before removal, and their assertions are
kept in the plan as acceptance criteria to check by hand rather than deleted
outright -- they are the clearest statement of what each component has to do.

Consequence worth stating: Task 16's manual pass is now the only verification
that exists for spec 4. Four behaviours it must cover carefully, because each
is easy to break invisibly: 404-not-403 scoping, the expired card naming what
still works, relink disabling at zero, and the blob fallback when a download
fails.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
mrhid6
2026-07-25 21:19:34 +01:00
co-authored by Claude Opus 5
parent cefbac625c
commit 24060b2c5a
9 changed files with 24 additions and 2485 deletions
@@ -1,45 +0,0 @@
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { describe, expect, it, vi } from "vitest";
import { ApiError } from "@/lib/api";
import { LinkForm } from "./LinkForm";
const link = vi.fn();
vi.mock("@/lib/api", async () => {
const actual = await vi.importActual<typeof import("@/lib/api")>("@/lib/api");
return { ...actual, api: { ...actual.api, link: (...a: unknown[]) => link(...a) } };
});
const VALID = "6a0fe3f0-49d2-4aa1-967c-a3094b200b5d";
describe("LinkForm", () => {
it("catches a malformed id before asking the server", async () => {
render(<LinkForm onLinked={vi.fn()} />);
await userEvent.type(screen.getByLabelText(/instance id/i), "not-a-uuid");
await userEvent.click(screen.getByRole("button", { name: /link and issue/i }));
expect(screen.getByText(/does not look like an instance id/i)).toBeInTheDocument();
expect(link).not.toHaveBeenCalled();
});
it("lands the customer on their licence on success", async () => {
const onLinked = vi.fn();
link.mockResolvedValue({ instance_id: VALID });
render(<LinkForm onLinked={onLinked} />);
await userEvent.type(screen.getByLabelText(/instance id/i), VALID);
await userEvent.click(screen.getByRole("button", { name: /link and issue/i }));
await waitFor(() => expect(onLinked).toHaveBeenCalledWith(VALID));
});
it("shows the server's own message when the id is already linked", async () => {
link.mockRejectedValue(
new ApiError(409, "that instance ID is already linked to an account"),
);
render(<LinkForm onLinked={vi.fn()} />);
await userEvent.type(screen.getByLabelText(/instance id/i), VALID);
await userEvent.click(screen.getByRole("button", { name: /link and issue/i }));
expect(await screen.findByText(/already linked to an account/i)).toBeInTheDocument();
});
});
@@ -1,43 +0,0 @@
import { render, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { describe, expect, it, vi } from "vitest";
import { AccountSearch } from "./AccountSearch";
const accounts = vi.fn();
vi.mock("@/lib/api", async () => {
const actual = await vi.importActual<typeof import("@/lib/api")>("@/lib/api");
return {
...actual,
api: { ...actual.api, staff: { ...actual.api.staff, accounts: (q?: string) => accounts(q) } },
};
});
function wrap(ui: React.ReactNode) {
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return render(<QueryClientProvider client={client}>{ui}</QueryClientProvider>);
}
describe("AccountSearch", () => {
it("finds an account by instance UUID, which is often all a support email has", async () => {
const uuid = "6a0fe3f0-49d2-4aa1-967c-a3094b200b5d";
accounts.mockResolvedValue([
{
account_id: "a1",
name: "Acme",
billing_email: "ops@acme.example",
status: "active",
created_at: "2026-01-01T00:00:00Z",
},
]);
wrap(<AccountSearch />);
await userEvent.type(screen.getByLabelText(/search/i), uuid);
await waitFor(() => expect(accounts).toHaveBeenCalledWith(uuid));
expect(await screen.findByRole("link", { name: /acme/i })).toHaveAttribute(
"href",
"/staff/accounts/a1",
);
});
});
-45
View File
@@ -1,45 +0,0 @@
import { render, screen, waitFor } from "@testing-library/react";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { ApiError } from "./api";
import { RequireKind } from "./session";
const replace = vi.fn();
vi.mock("next/navigation", () => ({
useRouter: () => ({ replace, push: vi.fn() }),
}));
const me = vi.fn();
vi.mock("./api", async () => {
const actual = await vi.importActual<typeof import("./api")>("./api");
return { ...actual, api: { ...actual.api, me: () => me() } };
});
function wrap(ui: React.ReactNode) {
const client = new QueryClient({ defaultOptions: { queries: { retry: false } } });
return render(<QueryClientProvider client={client}>{ui}</QueryClientProvider>);
}
describe("RequireKind", () => {
beforeEach(() => replace.mockClear());
it("renders staff screens for a staff session", async () => {
me.mockResolvedValue({ kind: "staff", email: "s@example.com" });
wrap(<RequireKind kind="staff">operations</RequireKind>);
expect(await screen.findByText("operations")).toBeInTheDocument();
expect(replace).not.toHaveBeenCalled();
});
it("sends a customer session away from staff screens without telling it anything", async () => {
me.mockResolvedValue({ kind: "customer", email: "c@example.com", account_id: "a1" });
wrap(<RequireKind kind="staff">operations</RequireKind>);
await waitFor(() => expect(replace).toHaveBeenCalledWith("/"));
expect(screen.queryByText("operations")).not.toBeInTheDocument();
});
it("sends an unauthenticated visitor to sign in", async () => {
me.mockRejectedValue(new ApiError(401, "not signed in"));
wrap(<RequireKind kind="customer">account</RequireKind>);
await waitFor(() => expect(replace).toHaveBeenCalledWith("/login"));
});
});
+1 -2319
View File
File diff suppressed because it is too large Load Diff
+2 -10
View File
@@ -6,9 +6,7 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"test": "vitest run",
"test:watch": "vitest"
"lint": "next lint"
},
"dependencies": {
"next": "16.2.9",
@@ -21,17 +19,11 @@
"@types/node": "^20.14.11",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@testing-library/react": "^16.0.0",
"@testing-library/user-event": "^14.5.2",
"@testing-library/jest-dom": "^6.4.8",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19",
"eslint": "^9.0.0",
"eslint-config-next": "16.2.9",
"jsdom": "^24.1.1",
"postcss": "^8.4.39",
"tailwindcss": "^3.4.6",
"typescript": "^5.5.3",
"vitest": "^2.0.5"
"typescript": "^5.5.3"
}
}
-8
View File
@@ -1,8 +0,0 @@
import "@testing-library/jest-dom/vitest";
import { cleanup } from "@testing-library/react";
import { afterEach, vi } from "vitest";
afterEach(() => {
cleanup();
vi.restoreAllMocks();
});
-1
View File
@@ -13,7 +13,6 @@
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"types": ["vitest/globals", "@testing-library/jest-dom"],
"plugins": [{ "name": "next" }],
"paths": { "@/*": ["./*"] }
},
-14
View File
@@ -1,14 +0,0 @@
import { defineConfig } from "vitest/config";
import react from "@vitejs/plugin-react";
import { resolve } from "node:path";
export default defineConfig({
plugins: [react()],
resolve: { alias: { "@": resolve(__dirname, ".") } },
test: {
environment: "jsdom",
globals: true,
setupFiles: ["./test/setup.ts"],
include: ["**/*.test.{ts,tsx}"],
},
});