Context
- I am mounting my component inside a Storybook
- I am attempting to interact with this component using Storybook interactions
- Storybook uses Testing-Library under the hood
I have the following component
import React from "react";
import PropTypes from "prop-types";
import cn from "classnames";
import FormControl from "@mui/material/FormControl";
import RadioGroup from "@mui/material/RadioGroup";
import FormLabel from "@mui/material/FormLabel";
import FormHelperText from "@mui/material/FormHelperText";
import FormControlLabel from "@mui/material/FormControlLabel";
import Radio from "@mui/material/Radio";
const MyRadioGroup = (props) => {
const { value, input, label, meta, children, options, classes, ...custom } =
props;
const _value = value || input?.value;
const _defaultValue = input?.defaultValue || meta?.initial;
return (
<FormControl
sx={{ width: "100%" }}
className={cn("radiogroup", classes.formControl)}
key={`key-${input.name}`}
error={Boolean(meta.touched && meta.error)}
>
<FormLabel className={classes.inputLabel} htmlFor={`id-${input.name}`}>
{label}
</FormLabel>
<RadioGroup
{...input}
{...custom}
data-testid={`radio-group-${input.name}`}
className={cn(classes.select, {
[classes.error]: Boolean(meta.touched && meta.error),
})}
variant="standard"
value={_value}
defaultValue={_defaultValue}
>
{children ||
options?.map((option) => {
const label =
typeof option === "string"
? option
: option.label || option.value;
const value = typeof option === "string" ? option : option.value;
return (
<FormControlLabel
data-testid={`radio-option-${value}`}
key={value}
value={value}
control={<Radio />}
label={label}
/>
);
})}
</RadioGroup>
{meta.touched && meta.error && (
<FormHelperText sx={{ margin: 0 }}>
{meta.touched && meta.error}
</FormHelperText>
)}
</FormControl>
);
};
MyRadioGroup.propTypes = {
classes: PropTypes.shape({
formControl: PropTypes.string,
inputLabel: PropTypes.string,
select: PropTypes.string,
error: PropTypes.string,
}),
defaultValue: PropTypes.any,
value: PropTypes.any,
label: PropTypes.string,
input: PropTypes.object,
children: PropTypes.node,
options: PropTypes.arrayOf(
PropTypes.oneOfType([
PropTypes.string,
PropTypes.shape({
label: PropTypes.string,
value: PropTypes.any,
}),
])
),
meta: PropTypes.shape({
initial: PropTypes.any,
touched: PropTypes.bool,
invalid: PropTypes.bool,
error: PropTypes.any,
}),
};
MyRadioGroup.defaultProps = {
classes: {
formControl: "",
inputLabel: "",
select: "",
},
};
export default MyRadioGroup;
And the following story:
export const Automated: Story = {
args: {
row: true,
label: "This is an Automated RadioGroup",
options: [
"option1",
{ value: "option2" },
{ value: "option3", label: "The Third One" },
],
},
play: async ({ canvasElement, step }) => {
const { selectRadioButton } = Interact({ canvasElement, step });
await selectRadioButton(".radiogroup", "option1");
},
};
The problem is somewhere in the following function (I think).
I've tried selecting all sorts of components, firing all sorts of events, but I can't get the UI to show me a 'selected' RadioGroup in my Storybook
const selectRadioButton = async (selector: string, value: string) =>
step(`selectRadioButton "${selector}": "${value}")`, async () => {
const container = root?.querySelector(selector);
const inContainer = within(container as HTMLElement);
const radioGroup = inContainer.getByRole("radiogroup");
const radios = inContainer.getAllByRole("radio");
// I've tried selecting the RadioGroup many different ways using
// normal querySelectors, getByRole, getByTestId
// I've also tried selecting the Radio option many different ways
const inputWithValue = await container?.querySelector( `input[type=radio][value="${value}"]` );
const closestSpan = inputWithValue?.closest("span");
const nextSibling = closestSpan?.nextSibling as HTMLElement;
const closestLabel = inputWithValue?.closest("label");
// I've tried triggering all sorts of events
// userEvent.click(...)
// userEvent.selectOptions(...) (throws a warning that it can't find an option with the selected value, even though I can see it in error output)
// fireEvent.click(...)
// fireEvent.click(..., { target: { value: value } })
// fireEvent.click(..., { target: { checked: true } })
// fireEvent(..., new MouseEvent('click', { bubbles: true }));
// fireEvent.mouseDown(...)
// fireEvent.mouseUp(...)
});
I think the closest I've gotten is that the MUI Ripple effect will trigger but I can't get the RadioButton to actually be checked or the onChange event to fire