feat(web): vocab list/terms sort+filter, external_uri in rows, rename guard, url input (#50)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -74,3 +74,59 @@ test("add term without EN label shows required alert and does not POST", async (
|
||||
expect(screen.getByRole("alert")).toBeInTheDocument();
|
||||
expect(posted).toBe(false);
|
||||
});
|
||||
|
||||
test("vocabularies render sorted by key", async () => {
|
||||
server.use(
|
||||
http.get("/api/admin/vocabularies", () =>
|
||||
HttpResponse.json([
|
||||
{ id: "v-zeta", key: "zeta" },
|
||||
{ id: "v-alpha", key: "alpha" },
|
||||
]),
|
||||
),
|
||||
);
|
||||
renderApp(tree(), { route: "/vocabularies" });
|
||||
expect(await screen.findByText("alpha")).toBeInTheDocument();
|
||||
const links = screen.getAllByRole("link");
|
||||
const keys = links.map((link) => link.textContent);
|
||||
expect(keys.indexOf("alpha")).toBeLessThan(keys.indexOf("zeta"));
|
||||
});
|
||||
|
||||
test("filter narrows the vocabulary list", async () => {
|
||||
renderApp(tree(), { route: "/vocabularies" });
|
||||
expect(await screen.findByText("material")).toBeInTheDocument();
|
||||
expect(screen.getByText("technique")).toBeInTheDocument();
|
||||
await userEvent.type(screen.getByRole("textbox", { name: /filter/i }), "mat");
|
||||
expect(screen.getByText("material")).toBeInTheDocument();
|
||||
expect(screen.queryByText("technique")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
test("renaming a vocabulary to an empty key does not call the rename endpoint", async () => {
|
||||
let renamed = false;
|
||||
server.use(
|
||||
http.patch("/api/admin/vocabularies/:id", () => {
|
||||
renamed = true;
|
||||
return new HttpResponse(null, { status: 204 });
|
||||
}),
|
||||
);
|
||||
renderApp(tree(), { route: "/vocabularies" });
|
||||
expect(await screen.findByText("material")).toBeInTheDocument();
|
||||
await userEvent.click(screen.getAllByRole("button", { name: /rename/i })[0]);
|
||||
const keyInputs = screen.getAllByRole("textbox", { name: /key/i });
|
||||
const input = keyInputs[keyInputs.length - 1];
|
||||
await userEvent.clear(input);
|
||||
await userEvent.click(screen.getByRole("button", { name: /save/i }));
|
||||
expect(renamed).toBe(false);
|
||||
});
|
||||
|
||||
test("term read row shows its external_uri as a link", async () => {
|
||||
server.use(
|
||||
http.get("/api/admin/vocabularies/:id/terms", () =>
|
||||
HttpResponse.json([
|
||||
{ id: "t-bronze", external_uri: "https://example.org/bronze", labels: [{ lang: "en", label: "Bronze" }] },
|
||||
]),
|
||||
),
|
||||
);
|
||||
renderApp(tree(), { route: "/vocabularies/v-material" });
|
||||
expect(await screen.findByText("Bronze")).toBeInTheDocument();
|
||||
expect(screen.getByRole("link", { name: /example\.org/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user