-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
on change for Material UI Select component not triggered #322
Comments
The same occurs with the Boostrap(reactstrap) Input Checkbox |
According to this issue (#275), you should use the onClick event, not the onChange Event, but on reactstrap its not supported right now :/ I hope react-testing-library can implement the onChange function to it like browsers has it. Edit: While inspecting this, I found out, that onClick isn't supported by react-testing-library as well. |
That's not true. If a "checkbox" component doesn't handle a click event then that component is inaccessible. This would be a bug in that component and should be fixed. As for the original post, do this:
Good luck! |
This by itself did not work. That being said, both of the following do work:
or
I personally prefer the second option. Something to note for future readers: If you are using a Material UI select, none of the above will work. You'll have to use the native version of the Select element. |
Hey @kentcdodds, Can you please brief us on how we can efficiently use react-testing-library with React Material-UI components ? I faced a similar issue of while testing the Material UI select(Not native select) onChange function. This is the codeSandBox link: https://codesandbox.io/s/q94q9z1849 In the codeSandBox code I have similar Select component which I am using. For your info, the dropdown which appears in Select component is a Paper component. Best regards!!! |
Hi @kentcdodds Any help on how can we make testing select possible for onchange event when native is not true? |
Sure, happy to have a look at it but your CodeSandbox is missing any unit tests at the moment |
Hey @weyert, please feel free to add unit test cases in the Codesandbox example. Thank you. |
I assume you already have some unit test cases you tried? The code sandbox you linked doesn't even have react-testing-library as a dependency. I would also suggest to look at https://stackoverflow.com/a/55576660 |
Hey @weyert , I have updated the codesandbox example and have wrote unit test for it. I would like to thank you for taking a look at this issue. Here is the link for updated codesandbox: https://codesandbox.io/s/q94q9z1849 Please feel free to edit it or suggest improvements on it. |
Try this: https://codesandbox.io/embed/94pm1qprmo Not sure, why it doesn't work in the browser but when you download it and test locally the unit test is successful. I hope it helps! |
Thanks @weyert @anandthanki1 |
Thank you @weyert |
The same issue occurs for Input components as well.
|
What if you actually type it with something like |
Maybe @oliviertassinari can help with this |
It would probably be good to have a few examples for testing MaterialUI components because we regularly get reports about difficulties with that library and I don't use it so I don't know why it's so uniquely difficult. |
The solution shared by @weyert looks great to me: https://codesandbox.io/s/94pm1qprmo, thanks! The non-native variation of the select component relies on click/keyboard interactions. You can't fire a DOM change event. The input element present is only here to support HTML POST forms. |
Similar to what is in codesandbox worked for me: const { getByText, getAllByRole, getByTestId, container } = render(
<Form />,
);
const selectNode = getByTestId('select-button-text');
const selectButton = getAllByRole('button')[0];
expect(selectButton).not.toBeNull();
expect(selectNode).not.toBeNull();
UserEvent.click(selectButton);
await waitForElement(() => getByText('Custom Text'), { container });
const itemClickable = getByText('Custom Text');
UserEvent.click(itemClickable);
getByTestId('custom1'); |
I had the problem that the text I want to select is elsewhere on the page, so I needed to target the 'dropdown' directly. Also I wanted it as a separate function, ideally not using the // myTestUtils.js
import {within, waitForElementToBeRemoved} from '@testing-library/react';
import UserEvent from '@testing-library/user-event';
export const selectMaterialUiSelectOption = async (element, optionText) =>
new Promise(resolve => {
// The the button that opens the dropdown, which is a sibling of the input
const selectButton = element.parentNode.querySelector('[role=button]');
// Open the select dropdown
UserEvent.click(selectButton);
// Get the dropdown element. We don't use getByRole() because it includes <select>s too.
const listbox = document.body.querySelector('ul[role=listbox]');
// Click the list item
const listItem = within(listbox).getByText(optionText);
UserEvent.click(listItem);
// Wait for the listbox to be removed, so it isn't visible in subsequent calls
waitForElementToBeRemoved(() => document.body.querySelector('ul[role=listbox]')).then(
resolve,
);
}); Edit: added async, since material-ui can take a tic to remove the listbox. |
Hey @davidgilbertson, Cool! This would be awesome for https://github.com/kentcdodds/react-testing-library-examples |
Okey doke I'll do a PR tonight. FYI I updated the above to use |
It does have a role implicitly. However, |
@davidgilbertson Solution is great.But the listbox is still present in jsdom even after value selected.When I am trying to open other dropdown in same testcase the previous listbox is showing instead of selected one. |
@sateesh-p, I had this issue as well. No fix, but I was able to just validate an @davidgilbertson, seriously thank you. This was a huge pain in the butt. |
@sateesh-p and @vikeen I came across the same problem, the trick was to wait for the element to be removed (as far as I could work out, it happens almost immediately). I've updated the code in my original comment above #322 (comment) So you need to call it like |
That's great @davidgilbertson .It's working as expected now.Thanks |
Thanks for sharing the snippet @davidgilbertson! I couldn't make it work with my code, but I modified it slightly and the following works for me: export const selectMaterialUiSelectOption = async (
container: HTMLElement,
selectElement: HTMLElement,
optionText: string,
) => {
userEvent.click(selectElement);
const listbox = await within(document.body).findByRole('listbox');
const listItem = await within(listbox).findByText(optionText);
userEvent.click(listItem);
await within(container).findByText(optionText);
}; |
Here's the solution which worked for me. You can mock the component in Jest and implement it as a native element for the duration of the test.
In
Go ahead and use your original |
For anyone coming across this issue like I did and is having trouble removing the list box from jsdom, Material UI uses ReactTransitionGroup under the hood for fading out the the options. You can disable the ReactTransitionGroup transitions by adding:
which solved the issue for me and removed the listbox immediately on clicking an item. |
Thx to have share all of this information it help a lot. |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
As a new user of this library I had a difficult time determining how to test outcomes of a drop-down selection. There is an example if you use the react-select library but very little information on the internet if you use a plain select tag. I found Kent's comment on an issue in the react-testing-library and thought it would be helpful to others to add it to the FAQs. testing-library/react-testing-library#322
My unit tests broke after updating MaterialUI to the latest version ( |
Add the `selectMaterialUiSelectOption` method to Jest Helpers because the select Material UI uses is react-select under the hood. As a result, it is not using select form element but div elements, making it hard to select a part from that input for testing. `selectMaterialUiSelectOption` finds text you want to use and makes the selection for you. --- Ref: testing-library/react-testing-library#322 (comment)
Add the `selectMaterialUiSelectOption` method to Jest Helpers because the select Material UI uses is react-select under the hood. As a result, it is not using select form element but div elements, making it hard to select a part from that input for testing. `selectMaterialUiSelectOption` finds text you want to use and makes the selection for you. --- Ref: testing-library/react-testing-library#322 (comment)
If anyone else comes across this awesome example here, but is using a multi-select, one note of caution -- multi-selects stay open when selecting options, so the You could easily modify this to accept multiple options (if you are looking to test clicking one to many items), and then at the end prior to the This will then properly await on the close of the listbox before proceeding. |
@davidgilbertson i am very new in testing and this issue just came out. can i ask you how should i implement this to my test. i did expect(selectMaterialUiSelectOption).tohavebeencalled(1) but it clearly is wrong way. it would be awesome if you help me out |
Using Material UI 5.10.3:
|
Thank you very much, I have done my problem with your solution |
Thank you @davidgilbertson, @bjunix and @zzgab! Had to change it to use 'fireEvent' instead of 'userEvent' to work for me (using material-ui/core 4.11.3): // myTestUtils.js
import { fireEvent, within } from '@testing-library/react';
const selectMaterialUiSelectOption = async (element, optionText) => {
// The the button that opens the dropdown, which is a sibling of the input
const selectButton = element.parentNode.querySelector('[role=button]');
// Open the select dropdown
fireEvent.mouseDown(selectButton);
// Get the dropdown element
const listbox = await within(document.body).findByRole('listbox');
// Click the list item
const listItem = await within(listbox).findByText(optionText);
fireEvent.click(listItem);
}; |
@matheusrizzo1 Tienes algún ejemplo que puedas compartir de como lo hiciste, porfa? |
react-testing-library
version: 4.1.3react
version: 16.4.1node
version: 11.10.1npm
(oryarn
) version: 6.7.0Relevant code or config:
What you did:
I am trying to fire the onChange method of the Material UI Select.
What happened:
onChange won't fire.
Also tried with
The text was updated successfully, but these errors were encountered: