import * as React from "react"; import { describe, it, expect, vi } from "vitest"; import { RepeaterField } from "../../src/components/RepeaterField"; import { render } from "../utils/render.tsx"; describe("RepeaterField", () => { describe("datetime sub-field", () => { it("displays a stored ISO datetime in the datetime-local input", async () => { // Mirrors the top-level datetime widget contract: full ISO 8601 // values must round-trip through ``, // which only accepts `YYYY-MM-DDTHH:mm`. const screen = await render( , ); const input = screen.getByLabelText("Recall date"); await expect.element(input).toHaveValue("2026-02-26T09:30"); }); it("emits a full ISO 8601 value with Z and milliseconds on change", async () => { const onChange = vi.fn(); const screen = await render( , ); const input = screen.getByLabelText("Recall date"); await input.fill("2026-02-26T09:30"); expect(onChange).toHaveBeenLastCalledWith([ expect.objectContaining({ recall_date: "2026-02-26T09:30:00.000Z" }), ]); }); }); }); /** * Image sub-field support (issue #1424): rows render the media picker * (ImageFieldRenderer) instead of falling through to a plain text input. */ describe("RepeaterField sub-field types", () => { it("renders the media picker for image sub-fields", async () => { const screen = await render( , ); // Image sub-field → picker button, not a text input. await expect.element(screen.getByRole("button", { name: /Select image/ })).toBeVisible(); // Scalar sub-fields keep their plain inputs. await expect.element(screen.getByRole("textbox", { name: "Caption" })).toBeVisible(); }); it("shows the existing image preview for media values", async () => { const screen = await render( , ); // MediaValue with a storageKey renders the local-media preview image. await expect .element(screen.container.querySelector('img[src="/_emdash/api/media/file/01ABC.png"]')) .toBeInTheDocument(); }); it("initializes image sub-fields as null when adding an item", async () => { const onChange = vi.fn(); const screen = await render( , ); await screen.getByRole("button", { name: /Add First Item/ }).click(); expect(onChange).toHaveBeenCalledWith([{ image: null, caption: "" }]); }); it("renders a searchable combobox for select sub-fields", async () => { const screen = await render( , ); // Select sub-field → searchable typeahead input (role "combobox"), // not a plain native select, and it reflects the stored value. const input = screen.getByRole("combobox"); await expect.element(input).toBeVisible(); await expect.element(input).toHaveValue("CT"); }); });