Comprehensive testing utilities including component type checking, event simulation, DOM utilities, and container management for React component testing.
/* Synchronous test wrapper */
let act: (unit => unit) => unit;
/* Asynchronous test wrapper */
let actAsync: (unit => Js.Promise.t('a)) => Js.Promise.t(unit);[@bs.module "react-dom/test-utils"]
external isElement: 'element => bool = "isElement";
[@bs.module "react-dom/test-utils"]
external isElementOfType: ('element, React.component('props)) => bool = "isElementOfType";
[@bs.module "react-dom/test-utils"]
external isDOMComponent: 'element => bool = "isDOMComponent";
[@bs.module "react-dom/test-utils"]
external isCompositeComponent: 'element => bool = "isCompositeComponent";
[@bs.module "react-dom/test-utils"]
external isCompositeComponentWithType: ('element, React.component('props)) => bool = "isCompositeComponentWithType";module Simulate = {
/* Basic events */
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external click: Dom.element => unit = "click";
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external clickWithEvent: (Dom.element, 'event) => unit = "click";
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external change: Dom.element => unit = "change";
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external changeWithEvent: (Dom.element, 'event) => unit = "change";
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external blur: Dom.element => unit = "blur";
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external focus: Dom.element => unit = "focus";
/* Form helpers */
let changeWithValue: (Dom.element, string) => unit;
let changeWithChecked: (Dom.element, bool) => unit;
/* Media events */
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external canPlay: Dom.element => unit = "canPlay";
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external timeUpdate: Dom.element => unit = "timeUpdate";
[@bs.module "react-dom/test-utils"] [@bs.scope "Simulate"]
external ended: Dom.element => unit = "ended";
};module DOM = {
[@bs.return nullable] [@bs.get]
external value: Dom.element => option(string) = "value";
let findBySelector: (Dom.element, string) => option(Dom.element);
let findByAllSelector: (Dom.element, string) => array(Dom.element);
let findBySelectorAndTextContent: (Dom.element, string, string) => option(Dom.element);
let findBySelectorAndPartialTextContent: (Dom.element, string, string) => option(Dom.element);
};let prepareContainer: (ref(option(Dom.element)), unit) => unit;
let cleanupContainer: (ref(option(Dom.element)), unit) => unit;
let getContainer: ref(option(Dom.element)) => Dom.element;/* Test a simple button component */
let testButton = () => {
let container = ref(None);
ReactTestUtils.prepareContainer(container, ());
let buttonElement = ReactDOM.render(
<button onClick={_ => Js.log("clicked")}>
{React.string("Click me")}
</button>,
ReactTestUtils.getContainer(container)
);
/* Test that it's a DOM component */
let isDOMElement = ReactTestUtils.isDOMComponent(buttonElement);
assert(isDOMElement);
/* Simulate click */
ReactTestUtils.Simulate.click(buttonElement);
ReactTestUtils.cleanupContainer(container, ());
};[@react.component]
let make = () => {
let (value, setValue) = React.useState(() => "");
let (submitted, setSubmitted) = React.useState(() => false);
let handleSubmit = (event) => {
ReactEvent.Form.preventDefault(event);
setSubmitted(_ => true);
};
<form onSubmit=handleSubmit data-testid="test-form">
<input
value
onChange={(e) => setValue(_ => ReactEvent.Form.target(e)##value)}
data-testid="test-input"
/>
<button type_="submit" data-testid="submit-button">
{React.string("Submit")}
</button>
{submitted ? <div data-testid="success"> {React.string("Submitted!")} </div> : React.null}
</form>
};
let testForm = () => {
let container = ref(None);
ReactTestUtils.prepareContainer(container, ());
ReactTestUtils.act(() => {
ReactDOM.render(<TestForm />, ReactTestUtils.getContainer(container));
});
let containerElement = ReactTestUtils.getContainer(container);
/* Find elements */
let inputElement = ReactTestUtils.DOM.findBySelector(containerElement, "[data-testid='test-input']");
let buttonElement = ReactTestUtils.DOM.findBySelector(containerElement, "[data-testid='submit-button']");
switch (inputElement, buttonElement) {
| (Some(input), Some(button)) => {
/* Test input change */
ReactTestUtils.act(() => {
ReactTestUtils.Simulate.changeWithValue(input, "test value");
});
/* Verify input value */
let inputValue = ReactTestUtils.DOM.value(input);
assert(inputValue === Some("test value"));
/* Test form submission */
ReactTestUtils.act(() => {
ReactTestUtils.Simulate.click(button);
});
/* Check for success message */
let successElement = ReactTestUtils.DOM.findBySelector(containerElement, "[data-testid='success']");
assert(Option.isSome(successElement));
}
| _ => assert(false)
};
ReactTestUtils.cleanupContainer(container, ());
};let testAsyncComponent = () => {
let container = ref(None);
ReactTestUtils.prepareContainer(container, ());
ReactTestUtils.actAsync(() => {
ReactDOM.render(<AsyncComponent />, ReactTestUtils.getContainer(container));
Promise.resolve();
})
|> Promise.then_(() => {
let containerElement = ReactTestUtils.getContainer(container);
let loadedContent = ReactTestUtils.DOM.findBySelectorAndTextContent(
containerElement,
".content",
"Loaded data"
);
assert(Option.isSome(loadedContent));
ReactTestUtils.cleanupContainer(container, ());
Promise.resolve();
});
};[@react.component]
let make = (~title: string) => {
<h1> {React.string(title)} </h1>
};
let testComponentTypes = () => {
let container = ref(None);
ReactTestUtils.prepareContainer(container, ());
let titleComponent = ReactDOM.render(
<TitleComponent title="Test Title" />,
ReactTestUtils.getContainer(container)
);
/* Test component type */
let isCorrectType = ReactTestUtils.isElementOfType(titleComponent, TitleComponent.make);
assert(isCorrectType);
let isComposite = ReactTestUtils.isCompositeComponent(titleComponent);
assert(isComposite);
ReactTestUtils.cleanupContainer(container, ());
};