import { render } from "@testing-library/react";
import { describe, expect, it } from "bun:test";
import type { ReactElement } from "react";
import { Field } from "@seed-design/react-field";
import { AttachmentInputRoot, AttachmentInputHiddenInput } from "./AttachmentInput";
function setUp(jsx: ReactElement) {
return render(jsx);
}
describe("AttachmentInput", () => {
describe("props merging", () => {
describe("AttachmentInputHiddenInput", () => {
it("should merge props from AttachmentInputRoot", () => {
const { getByTestId } = setUp(
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("name")).toBe("attachment");
expect(input.getAttribute("type")).toBe("file");
});
it("should merge props from Field context", () => {
const { getByTestId } = setUp(
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("name")).toBe("field-attachment");
expect(input.getAttribute("aria-required")).toBe("true");
expect(input.getAttribute("aria-invalid")).toBe("true");
expect(input).toBeDisabled();
});
it("should prioritize direct props over context props", () => {
const { getByTestId } = setUp(
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("name")).toBe("direct-name");
});
it("should get id from Field context", () => {
const { getByTestId } = setUp(
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("id")).toBeTruthy();
expect(input.getAttribute("id")).toContain("field:");
});
it("should have no id without Field context", () => {
const { getByTestId } = setUp(
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("id")).toBeNull();
});
it("should connect aria-describedby when Field has Description", () => {
const { getByTestId } = setUp(
Upload your files
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("aria-describedby")).toBeTruthy();
});
it("should connect aria-describedby when Field has ErrorMessage", () => {
const { getByTestId } = setUp(
File too large
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("aria-describedby")).toBeTruthy();
});
});
describe("Complex prop merging scenarios", () => {
it("should handle nested Field and AttachmentInput contexts", () => {
const { getByTestId } = setUp(
Attachment
Max 10MB
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("name")).toBe("attachment");
expect(input.getAttribute("aria-required")).toBe("true");
expect(input.getAttribute("aria-invalid")).toBe("true");
expect(input.getAttribute("aria-describedby")).toBeTruthy();
});
it("should let Field disabled override AttachmentInput enabled", () => {
const { getByTestId } = setUp(
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input).toBeDisabled();
});
it("should not put aria-readonly on the hidden input even when Field is read-only", () => {
// aria-readonly is invalid on per ARIA 1.2 — it's only valid on
// textbox/spinbutton/checkbox/switch/slider/etc. Field spreads aria-readonly to every
// child input, so AttachmentInputHiddenInput has to strip it.
const { getByTestId } = setUp(
,
);
const input = getByTestId("hidden-input") as HTMLInputElement;
expect(input.getAttribute("aria-readonly")).toBeNull();
// hidden input itself stays enabled so the form value is preserved when read-only
expect(input.disabled).toBe(false);
});
});
});
});