How can I mock useMediaQuery in React units tests? - reactjs

I'm using jest and #testing-library for my units tests in react (typescript).
I have a custom datatable component that uses useMediaQuery to display or not some elements on mobile.
const isDesktop = useMediaQuery({
query: '(min-width: 768px)',
});
With this boolean, in my case, I choosed to hide the row selection on mobile with a simple ternary.
In my test, I want to check if the selection checkbox is in the document, but of course it's not.
By removing the mobile condition, the test passes with success, because we render the selection checkbox no matter the screen size.
I conclude that my test environment is like a small screen, so the mobile condition returns true everytime and I cannot test my checkboxes.
(When I say mobile condition, it's of course based on the isDesktop).
Is there a way to mock jest and say before each test "i want that the test screen size is 1500pw width" or something like that ?
I tried something that I saw on an other topic but it does not work for me :
window.matchMedia = jest.fn().mockImplementation((query) => ({
matches: query === `(min-width: ${utils.breakpoints.md}px)`,
media: '',
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
}));

Related

React Testing library testing error `NaN` is an invalid value for the `left` css style property

I am using internal library component that uses React popper. Component is a dropdown that should open when i click on a marked element, as any other dropdown menu should.
I am trying to test with React testing library flow where user opens dropdown and does some interaction. But when i make my test open that dropdown it throws this error (warning):
Warning: `NaN` is an invalid value for the `left` css style property.
at div
at Popover__MenuArrow (/my-project/node_modules/styled-components/src/models/Keyframes.js:20:51)
at WithTheme(Component) (/my-project/node_modules/styled-components/src/models/ServerStyleSheet.js:66:13)
at div
at Popover__DropdownContainer (/my-project/node_modules/styled-components/src/models/Keyframes.js:20:51)
at WithTheme(Component) (/my-project/node_modules/styled-components/src/models/ServerStyleSheet.js:66:13)
...
This is not a blocking error, it is a warning, and test actually passes, but it is annoying to see it all the time when i run my tests.
My question is, how can I make this warning text not show when i run my tests?
This is the test code:
it('Should open dropdown menu', () => {
const { getByTestId } = render(<DropdownMenu />);
// Click on dropdown and open it
const dropdownButton = getByTestId('my-dropdown-menu');
fireEvent.click(dropdownButton);
// Assert if dropdown list is visible
const dropdownList = getByTestId('my-dropdown-list');
expect(dropdownList).toBeTruthy();
});
After some browsing around, I found this interesting approach on GitHub to not allow this warning to show.
The idea is to mock popper.js and set placements value. You need to put this code above your test it or describe code block.
jest.mock('popper.js', () => {
const PopperJS = jest.requireActual('popper.js');
return class {
static placements = PopperJS.placements;
constructor() {
return {
destroy: () => {},
scheduleUpdate: () => {},
};
}
};
});
This does not fix the problem, it just masks it and prevents that warning to show in the terminal at all. It will not influence on a test and your test will be able to simulate click on a element in that dropdown menu.
CAUSE:
It seems that the problem lies in the fact that test is being run in a headless browser and there is no point of reference for Popper.js to position itself when the dropdown is opened.
With the above code, we give Popper default placement values him to run in headless environment.

How can i write a test using React Testing Library to check if hover changes the components style?

I am testing my application, and encountered a problem. When trying to test whether a row in my Dropdown component applies an effect on hover, I noticed I was not able to check elements for their background color, which I find odd.
Trying to use the jest-dom matcher "toHaveStyle()", the following is an example where I cannot for the life of me get it to work.
dropdown.test.tsx
test('Should contain clickable elements that change style when hovered', () => {
const dropElement1 = screen.getByLabelText('testLabel1');
expect(dropElement1).toHaveStyle('background: white');
});
Error
I have also tried this by using 'background-color', by using the hex value (another interesting bug is that PrettyDom converts hex to RGB), or by adding ; to the declaration in toHaveStyle().
I am certain that the element is indeed white, and I can't understand what is going wrong. If my approach is bad practice and you have a better idea of how to check this, or you have a solution to my problem, please, let me know!
Your testing case can't find the dropElement1 styles because it's a drop-down menu and not opened since you just render the Dropdonw component.
You need to simulate a mouse hover or clicking action on the DropDown menu and then expect to have styles property for it.
import React from "react";
import { render, screen, fireEvent, waitFor } from "#testing-library/react";
import { Dropdown } from "./Dropdown";
test('Should contain clickable elements that change style when hovered', async () => {
render(<Dropdown />);
fireEvent.mouseEnter(screen.getByText('drop-down-btn'));
await waitFor(() => screen.getByTestId('dropdown-menu'))
expect(screen.getByLabelText('testLabel1')).toHaveStyle('background: white');
});
Note: as you have not posted the Dropdown component, I put some sample names for getting your toggles and drop-down menu. also, you can read about the mouse events on the react-testing-library. you can also use mouseOver but it depends on your drop-down menu implementation.

QuerySelectorAll in React Testing Library?

Question:
I have multiple dropdowns and I am checking to see if any of them are open. How can i do this in React testing library? (I'm going through bunch of tabIndexes and checking through them)
Issue:
container.querySelectorAll isn't possible in react testing library.
Code:
it('should not expand dropdown for multiple view', () => {
const { container } = render(
getMockedComponent()
)
expect(container).toBeVisible()
container
.querySelector('div[tabindex]').forEach(eachAccordian => {
expect(eachAccordian).toHaveAttribute('aria-expanded', 'false')
})
})
How can i check all the nodes using React testing library?
You can do this by using querySelectorAll instead of querySelector.
container
.querySelectorAll('div[tabindex]').forEach(eachAccordian => {
expect(eachAccordian).toHaveAttribute('aria-expanded', 'false')
})
You might want to use the React Testing Library queries instead of querySelector. queryAllBy should probably get you what you need, where you can select anything with a certain data-test-id or role, and check their attributes from there!
It seems "getByRole" solves many querySelector requirements.
Roles: https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/ARIA_Techniques#roles

How to work with multiple components in intro js for react

I'm using introjs-react package for my project but I'm facing a problem of interacting with multiple components..... As it is not able to select element which is not being rendered at first but at second step I'm rendering component on the screen (by history.push) but still it is not selecting it and showing element is null.
<Steps
enabled={enableSteps}
steps={steps}
initialStep={initialStep}
options={{
showStepNumbers: false,
showBullets: false,
exitOnOverlayClick: false,
doneLabel: "Finish",
nextLabel: "Next",
hideNext: true,
showProgress: true
}}
onChange={(index) => changeSteps(index)}
onStart={index => startSteps(index)}
onExit={(index) => exitSteps(index)}
/>
this is the steps component
const changeSteps = (index) => {
if (index === 2) {
history.push('/notifications');
}
}
here I am just trying to go to another page notifications which is not being rendered at first.....due to which selector is not working and is not selecting elements in notification page
I spent a lot of my time on this but it appears that there is no proper solution for this.....Although u can solve it by creating a reference to Steps component and then u can change elements through
refName.current.introJS.steps[stepIndex].element= document.querySelector(element)
it must be done after you render the other component on which you want to display instructions.....!

How to test enzyme, react-virtualized, material-ui?

I have to test a very unusual case, in my test I should click to some component which is wrapped by from material-ui and it is inside the List from react-vertualized.
I have dived to it -
wrapper
.find(TreeView)
.dive()
.find(AutoSizer)
.renderProp('children', {})
.find(VirtualizedTree)
.dive()
.renderProp('rowRenderer', { index: 0, props: {...} });
And if I debug it I see this result -
<WithStyles(TreeNode) data-test="projected-tree" components={{...}} onSelectToggle={[Function]} onExpandToggle={[Function]} width={...} style={...} node={{...}} level={0} isOdd={true} />
The component which I want to click is inside the TreeNode, but when I try to dive I receive the error related to my custom theme which I use in my project, this happening because has lost the connection to the custom theme.
I think this happening because it has been rendered through the rowRenderer property of List.
Maybe somebody has any ideas on how to pass the custom theme inside the List.rowRenderer?
you need to mock the width and height to make AutoSizer return a width to children can showup
you can use this function mockOffsetSize
// AutoSizer uses offsetWidth and offsetHeight.
// Jest runs in JSDom which doesn't support measurements APIs.
function mockOffsetSize(width, height) {
Object.defineProperty(HTMLElement.prototype, 'offsetHeight', {
configurable: true,
value: height,
});
Object.defineProperty(HTMLElement.prototype, 'offsetWidth', {
configurable: true,
value: width,
});
}
ref: https://github.com/bvaughn/react-virtualized/blob/master/source/AutoSizer/AutoSizer.jest.js#L68

Resources