mirror of
https://github.com/kopia/htmlui.git
synced 2026-02-02 12:53:24 -08:00
218 lines
6.7 KiB
JavaScript
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"]);
|
|
});
|
|
});
|