import { describe, expect, test } from "vitest"; import { screen, waitFor } from "@testing-library/react"; import { userEvent } from "@testing-library/user-event"; import { calls, deferred, fail, route } from "../fetch.ts"; import { makeSession, wire } from "../fixtures.ts"; import { currentPath, renderPage } from "../render.tsx"; describe("UserRegister", () => { function setup(search = "?token=inv-1") { const user = userEvent.setup(); renderPage(`/register${search}`); return user; } test("no token: an invalid invite, no request", async () => { setup(""); expect(await screen.findByRole("alert")).toHaveTextContent( "Invalid invite", ); expect(calls("GET /api/invites/:t")).toHaveLength(0); }); test("an unknown token is invalid", async () => { const invite = deferred(); route("GET /api/invites/:t", () => invite.promise); setup(); expect(await screen.findByText("Checking invite…")).toBeInTheDocument(); invite.resolve(fail("nope", 404)); expect(await screen.findByRole("alert")).toHaveTextContent("already used"); }); test("registers with a valid invite", async () => { route("GET /api/invites/:t", () => ({})); const session = makeSession({ username: "new_one" }); route("POST /api/users", () => wire(session)); const user = setup(); await user.type(await screen.findByPlaceholderText("Username"), "new_one"); await user.type(screen.getByPlaceholderText("Email address"), "n@o.pe"); await user.type( screen.getByPlaceholderText("Password (min. 8 characters)"), "longenough{Enter}", ); await waitFor(() => expect(currentPath()).toBe("/")); expect(calls("POST /api/users")[0].body).toEqual({ username: "new_one", password: "longenough", inviteToken: "inv-1", email: "n@o.pe", }); expect(calls("GET /api/invites/:t")[0].params.t).toBe("inv-1"); }); test("validates the username and password length", async () => { route("GET /api/invites/:t", () => ({})); const user = setup(); await user.type( await screen.findByPlaceholderText("Username"), "bad name!", ); await user.type(screen.getByPlaceholderText("Email address"), "n@o.pe"); await user.type( screen.getByPlaceholderText("Password (min. 8 characters)"), "short{Enter}", ); expect(await screen.findByText(/letters, numbers, or underscores/)) .toBeInTheDocument(); expect(screen.getByText("At least 8 characters")).toBeInTheDocument(); expect(calls("POST /api/users")).toHaveLength(0); }); test("shows a server refusal (username taken)", async () => { route("GET /api/invites/:t", () => ({})); route( "POST /api/users", () => fail("Username already taken", 409), ); const user = setup(); await user.type(await screen.findByPlaceholderText("Username"), "taken"); await user.type(screen.getByPlaceholderText("Email address"), "n@o.pe"); await user.type( screen.getByPlaceholderText("Password (min. 8 characters)"), "longenough{Enter}", ); expect(await screen.findByRole("alert")).toHaveTextContent( "Username already taken", ); }); });