import { describe, it, expect } from "vitest";
import { renderToStaticMarkup } from "react-dom/server";
import { GENERATED_NAME_ATTR } from "../constants";
import { renderGenerativeUI } from "../renderGenerativeUI";
import { interactiveVocabulary } from "./interactive";
const render = (node: unknown) =>
renderToStaticMarkup(<>{renderGenerativeUI(node, interactiveVocabulary)}>);
describe("interactiveVocabulary", () => {
it("Button renders a button with style/block hooks and the label", () => {
expect(
render({
$type: "Button",
label: "Go",
buttonStyle: "primary",
block: true,
}),
).toBe(
'',
);
});
it("Button omits data-aui-block when block is false or omitted", () => {
expect(render({ $type: "Button", label: "Go", block: false })).toBe(
'',
);
});
it('Button renders type="button" by default and type="submit" with the submit prop', () => {
expect(render({ $type: "Button", label: "Go" })).toContain('type="button"');
const html = render({ $type: "Button", label: "Go", submit: true });
expect(html).toContain('type="submit"');
expect(html).toContain("data-aui-submit");
});
it("Button omits data-aui-submit when submit is false or omitted", () => {
expect(
render({ $type: "Button", label: "Go", submit: false }),
).not.toContain("data-aui-submit");
});
it("Select renders an aria-label when label is provided", () => {
const html = render({
$type: "Select",
label: "Choose",
options: [{ label: "A", value: "a" }],
});
expect(html).toContain('aria-label="Choose"');
});
it("Select keys options by index so duplicate values do not collide", () => {
const html = render({
$type: "Select",
options: [
{ label: "A", value: "x" },
{ label: "B", value: "x" },
],
});
expect(html).toContain('');
expect(html).toContain('');
});
it("Select renders a name attribute when provided", () => {
const html = render({
$type: "Select",
name: "role",
options: [{ label: "A", value: "a" }],
});
expect(html).toContain('name="role"');
});
it("Button stashes $action on a data-aui-action attribute", () => {
const html = render({
$type: "Button",
label: "Buy",
$action: { type: "purchase", itemId: "sku-1" },
});
expect(html).toContain('data-aui-action="');
expect(html).toContain(""type":"purchase"");
expect(html).toContain(""itemId":"sku-1"");
});
it("Button without $action omits the data-aui-action attribute", () => {
expect(render({ $type: "Button", label: "Go" })).toBe(
'',
);
});
it("Select renders options with values and a placeholder", () => {
const html = render({
$type: "Select",
placeholder: "Pick one",
options: [
{ label: "A", value: "a" },
{ label: "B", value: "b" },
],
});
expect(html).toContain('data-aui="select"');
expect(html).toContain(
'value="" disabled="" selected="">Pick one',
);
expect(html).toContain('');
expect(html).toContain('');
});
it("Select ignores malformed options instead of throwing", () => {
expect(render({ $type: "Select" })).toBe(
'',
);
expect(render({ $type: "Select", options: "not-an-array" })).toBe(
'',
);
expect(
render({
$type: "Select",
options: [
null,
{ label: "Missing value" },
{ value: "Missing label" },
{ label: "A", value: "a" },
],
}),
).toBe('');
});
it("Input renders a single-line input by default", () => {
expect(render({ $type: "Input", placeholder: "type here" })).toBe(
'',
);
});
it("Input renders a name attribute when provided", () => {
expect(render({ $type: "Input", name: "email" })).toContain('name="email"');
});
it("Input multiline renders a textarea with the multiline hook", () => {
const html = render({ $type: "Input", multiline: true });
expect(html).toContain("data-aui-multiline");
expect(html).toContain("