Files
htmlui/tests/forms/StringList.test.jsx
2025-06-07 08:03:18 -07:00

218 lines
6.7 KiB
JavaScript

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(<MockFormComponent fieldName="testField" />);
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(<MockFormComponent fieldName="testField" initialState={initialState} />);
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(<MockFormComponent ref={ref} fieldName="testField" />);
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(<MockFormComponent ref={ref} fieldName="testField" initialState={initialState} />);
const textarea = getByRole("textbox");
act(() => {
fireEvent.change(textarea, { target: { value: "" } });
});
expect(ref.current.state.testField).toBeUndefined();
});
it("has correct textarea attributes", () => {
const { getByRole } = render(<MockFormComponent fieldName="testField" />);
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(<MockFormComponent fieldName="testField" props={props} />);
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(
<MockFormComponent ref={ref} fieldName="testField" initialState={{ testField: ["initial"] }} />,
);
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(<MockFormComponent fieldName="nested.field" initialState={initialState} />);
const textarea = getByRole("textbox");
expect(textarea.value).toBe("nested\nvalue");
});
it("maintains proper Form.Group structure", () => {
const { container } = render(<MockFormComponent fieldName="testField" />);
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(<MockFormComponent ref={ref} fieldName="testField" />);
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"]);
});
});