90 lines
3.1 KiB
TypeScript
90 lines
3.1 KiB
TypeScript
import { fireEvent, render, screen, within } from "@testing-library/react";
|
|
import userEvent from "@testing-library/user-event";
|
|
import { beforeEach, describe, expect, it } from "vitest";
|
|
|
|
import { Workbench } from "../../src/components/Workbench";
|
|
|
|
describe("Helper Tools workbench", () => {
|
|
beforeEach(() => {
|
|
history.replaceState(null, "", "/");
|
|
});
|
|
|
|
it("exposes all workspaces and performs strict text encoding", () => {
|
|
render(<Workbench />);
|
|
|
|
expect(
|
|
screen.getByRole("heading", {
|
|
name: "Useful values, without a round trip",
|
|
}),
|
|
).toBeVisible();
|
|
expect(
|
|
within(
|
|
screen.getByRole("tablist", { name: "Helper workspaces" }),
|
|
).getAllByRole("tab"),
|
|
).toHaveLength(8);
|
|
const encodeCard = screen
|
|
.getByRole("heading", { name: "Encode text" })
|
|
.closest("section");
|
|
expect(encodeCard).not.toBeNull();
|
|
expect(
|
|
within(encodeCard!).getAllByText("SGVsbG8sIGxvY2FsIHRvb2xib3gh"),
|
|
).toHaveLength(2);
|
|
});
|
|
|
|
it("supports direct hashes and canonicalizes an IPv6 CIDR", () => {
|
|
history.replaceState(null, "", "/#network");
|
|
render(<Workbench />);
|
|
|
|
expect(screen.getByRole("heading", { name: "Network" })).toBeVisible();
|
|
const canonical = screen.getByText("Canonical").parentElement;
|
|
expect(canonical).not.toBeNull();
|
|
expect(within(canonical!).getByText("2001:db8::/64")).toBeVisible();
|
|
expect(screen.getByText("Yes")).toBeVisible();
|
|
});
|
|
|
|
it("moves between workspace tabs with the keyboard", async () => {
|
|
const user = userEvent.setup();
|
|
render(<Workbench />);
|
|
const encoding = screen.getByRole("tab", { name: /^Encoding/u });
|
|
encoding.focus();
|
|
await user.keyboard("{ArrowRight}");
|
|
|
|
expect(
|
|
screen.getByRole("tab", { name: /^Text & Unicode/u }),
|
|
).toHaveAttribute("aria-selected", "true");
|
|
expect(location.hash).toBe("#text");
|
|
});
|
|
|
|
it("keeps unsafe JSON inert and reports the rejected key", async () => {
|
|
const user = userEvent.setup();
|
|
render(<Workbench />);
|
|
await user.click(screen.getByRole("tab", { name: /^Structured/u }));
|
|
const input = screen.getByLabelText("JSON input");
|
|
fireEvent.change(input, {
|
|
target: { value: '{"__proto__":{"polluted":true}}' },
|
|
});
|
|
|
|
expect(screen.getByRole("alert")).toHaveTextContent(/dangerous.*key/iu);
|
|
expect(({} as { polluted?: boolean }).polluted).toBeUndefined();
|
|
});
|
|
|
|
it("repeats seeded random output and labels it as non-secure", async () => {
|
|
const user = userEvent.setup();
|
|
render(<Workbench />);
|
|
await user.click(screen.getByRole("tab", { name: /^Random/u }));
|
|
const generate = screen.getByRole("button", {
|
|
name: "Generate seeded bytes",
|
|
});
|
|
await user.click(generate);
|
|
const first = screen.getByText("Seeded hexadecimal (not secure)")
|
|
.parentElement?.nextElementSibling?.textContent;
|
|
await user.click(generate);
|
|
const second = screen.getByText("Seeded hexadecimal (not secure)")
|
|
.parentElement?.nextElementSibling?.textContent;
|
|
|
|
expect(first).toMatch(/^[0-9a-f]{32}$/u);
|
|
expect(second).toBe(first);
|
|
expect(screen.getByText(/must never be used for tokens/u)).toBeVisible();
|
|
});
|
|
});
|