import { render, act } from "@testing-library/react"; import React from "react"; import PropTypes from "prop-types"; import { StringList } from "../../src/forms/StringList"; import { fireEvent } from "@testing-library/react"; import { listToMultilineString, multilineStringToList } from "../../src/forms/StringList"; // Mock component to simulate the form component that would use StringList class MockFormComponent extends React.Component { static propTypes = { fieldName: PropTypes.string.isRequired, initialState: PropTypes.object, props: PropTypes.object, }; constructor(props) { super(props); this.state = props.initialState || {}; this.handleChange = this.handleChange.bind(this); } handleChange(event, valueGetter = (x) => x.value) { const name = event.target.name; const value = valueGetter(event.target); this.setState({ [name]: value }); } render() { return StringList(this, this.props.fieldName, this.props.props); } } describe("listToMultilineString", () => { it("converts array to multiline string", () => { expect(listToMultilineString(["first", "second", "third"])).toBe("first\nsecond\nthird"); }); it("handles empty array", () => { expect(listToMultilineString([])).toBe(""); }); it("handles single item array", () => { expect(listToMultilineString(["single"])).toBe("single"); }); it("handles undefined input", () => { expect(listToMultilineString(undefined)).toBe(""); }); it("handles null input", () => { expect(listToMultilineString(null)).toBe(""); }); it("handles array with empty strings", () => { expect(listToMultilineString(["first", "", "third"])).toBe("first\n\nthird"); }); }); describe("multilineStringToList", () => { it("converts multiline string to array", () => { const target = { value: "first\nsecond\nthird" }; expect(multilineStringToList(target)).toEqual(["first", "second", "third"]); }); it("returns undefined for empty string", () => { const target = { value: "" }; expect(multilineStringToList(target)).toBeUndefined(); }); it("handles single line string", () => { const target = { value: "single line" }; expect(multilineStringToList(target)).toEqual(["single line"]); }); it("handles strings with empty lines", () => { const target = { value: "first\n\nthird" }; expect(multilineStringToList(target)).toEqual(["first", "", "third"]); }); it("handles strings with carriage returns", () => { const target = { value: "first\r\nsecond" }; expect(multilineStringToList(target)).toEqual(["first\r", "second"]); }); it("handles trailing newline", () => { const target = { value: "first\nsecond\n" }; expect(multilineStringToList(target)).toEqual(["first", "second", ""]); }); }); describe("StringList component", () => { it("renders empty textarea when no value is set", () => { const { getByRole } = render(); const textarea = getByRole("textbox"); expect(textarea.value).toBe(""); expect(textarea.name).toBe("testField"); }); it("displays existing string list values", () => { const initialState = { testField: ["item 1", "item 2", "item 3"], }; const { getByRole } = render(); const textarea = getByRole("textbox"); expect(textarea.value).toBe("item 1\nitem 2\nitem 3"); }); it("handles onChange event and updates state", () => { let ref = React.createRef(); const { getByRole } = render(); const textarea = getByRole("textbox"); act(() => { fireEvent.change(textarea, { target: { value: "new item 1\nnew item 2" } }); }); expect(ref.current.state.testField).toEqual(["new item 1", "new item 2"]); }); it("clears state when input is empty", () => { let ref = React.createRef(); const initialState = { testField: ["existing", "items"], }; const { getByRole } = render(); const textarea = getByRole("textbox"); act(() => { fireEvent.change(textarea, { target: { value: "" } }); }); expect(ref.current.state.testField).toBeUndefined(); }); it("has correct textarea attributes", () => { const { getByRole } = render(); const textarea = getByRole("textbox"); expect(textarea.tagName).toBe("TEXTAREA"); expect(textarea.rows).toBe(5); expect(textarea.classList.contains("form-control-sm")).toBe(true); }); it("passes additional props to Form.Control", () => { const props = { placeholder: "Enter items", disabled: true, "data-testid": "string-list-input", className: "custom-class", }; const { getByTestId } = render(); const textarea = getByTestId("string-list-input"); expect(textarea.placeholder).toBe("Enter items"); expect(textarea.disabled).toBe(true); expect(textarea.classList.contains("custom-class")).toBe(true); }); it("handles component state updates", () => { let ref = React.createRef(); const { getByRole } = render( , ); let textarea = getByRole("textbox"); expect(textarea.value).toBe("initial"); // Update the component state act(() => { ref.current.setState({ testField: ["updated", "list"] }); }); textarea = getByRole("textbox"); expect(textarea.value).toBe("updated\nlist"); }); it("handles nested field names via stateProperty", () => { const initialState = { nested: { field: ["nested", "value"], }, }; const { getByRole } = render(); const textarea = getByRole("textbox"); expect(textarea.value).toBe("nested\nvalue"); }); it("maintains proper Form.Group structure", () => { const { container } = render(); const formGroup = container.querySelector(".col"); expect(formGroup).toBeTruthy(); expect(formGroup.querySelector("textarea.form-control")).toBeTruthy(); }); it("preserves whitespace in list items", () => { let ref = React.createRef(); const { getByRole } = render(); const textarea = getByRole("textbox"); act(() => { fireEvent.change(textarea, { target: { value: " item with spaces \n\ttabbed item\n normal item" } }); }); expect(ref.current.state.testField).toEqual([" item with spaces ", "\ttabbed item", " normal item"]); }); });