#testing-library/React : Clicking outside of component not working - reactjs

I'm using react testing library to test my component built with FluentUI.
Here is link:
https://codesandbox.io/s/keen-borg-2tqmj?file=/src/App.spec.js
The code is basically a pasted snippet of the example code of Dialog component from FluentUI docs site. The behavior that I'm testing is:
User opens the dialog
User clicks outside of the dialog
onDimiss prop of the component should be fired.
It works when I'm playing with it manually however it seems that I failed to simulate a click outside of the component with testing library.
I tried using userEvent.click(document.body) as mentioned in this post but got no luck
Does anyone has any idea how to make test work?

It is not working because the Dialog component is not listening for the onClick event on the body, so what you need to do in this case is to find the actual element that is being clicked, observing the dom you'll find that the overlay is a div with some overlay classes on it.
<div
class="ms-Modal is-open ms-Dialog root-94"
role="document"
>
<div
aria-hidden="true"
class="ms-Overlay ms-Overlay--dark root-99"
/>
The problem now is to find a way to select it. Unfortunately, you cannot select elements in RTL by their className, so you need to use another selector; in this case, we can get the parent element by the role and then access the first child.
const onDismiss = jest.fn();
const { getByRole } = render(<App onDismiss={onDismiss} />);
UserEvent.click(screen.getByText("Open Dialog"));
const document = getByRole("document");
UserEvent.click(document.firstChild);
expect(onDismiss).toHaveBeenCalled();
https://codesandbox.io/s/hungry-joliot-tjcph?file=/src/App.spec.js

Related

How to call or use a .js file using onclick Reactjs functional component

I have .js file called Edit which is used for edit purpose. I have another .js file called Add. I have a dialog box in edit.js which will open when I click a button. But I don't want to use a button instead I want to get that a dialog box when I click anywhere on box. I tried using onclick in div tag but I didn't get any response.
this is the output
so if you observe we got a edit button there if click it I am getting form/dialog box for editing the content. but I want that form or dialog box to open when I click anywhere on the yellow box.
<div id='color' className='div2' key={item.id} style={{width: 340,
# border: '5px solid white',textIndent:-30,paddingRight:32,paddingLeft:40,whiteSpace:'pre',paddingTop:15, backgroundColor:item.currentColor}} onClick={()=>{editpage(item.id)}} >
this is what I used for calling function for getting form in another .js file. It is part of a mapping function.` there is a onclick event I used that whenever I click on the box or content which is all under div tag I need to go to that function and there go to edit and then form but it didn't work
the function to which it goes is this:
const editpage=(id)=>{ <Edit id={id}></Edit> }
I want to send a id as a parameter which is passed to Edit.js.
I used <Edit/> because it is a another js file which I am importing in Add.js file.
I am not able to get the output can you please me with this.
how I can use this when I click on color box should open a form which is indeed in another file.
This is successfully calling a function on the click event:
onClick={()=>{editpage(item.id)}}
But what does that function do? Absolutely nothing:
const editpage=(id)=>{ <Edit id={id}></Edit> }
The function doesn't return anything (not that returning from a click handler does anything either of course), doesn't perform any operations, nothing. It's just a single JSX expression.
Take a different approach entirely. Add your component to the markup, but wrap it in a condition based on state. For example, consider this state value:
const [openEditPage, setOpenEditPage] = useState();
The purpose of this state value is to keep track of which item.id should currently have its "edit" component visible. (Default to undefined so none are visible by default.)
Use this value when rendering the components:
<div id='color' className='div2' key={item.id} style={/*...*/} onClick={()=>{editpage(item.id)}}>
{openEditPage === item.id ? <Edit id={item.id}></Edit> : null}
</div>
So in this case the <Edit> component will only be rendered if openEditPage === item.id. Which is what the editpage() function can do:
const editpage = id => setOpenEditPage(id);
Clicking on the <div> would invoke the editpage function, which updates the state value, which triggers a re-render, and in the new render the <Edit> component is shown because the condition would be true.

How can I test a popover from chakra-ui

I need to test a popover from chakra-ui in a React App.
I tried with this. But It does not find the popover. If I try by text, then I cannot assert if it is visible.
it('show a popover when hover terms and conditions', () => {
render(<SummaryForm />);
const link = screen.getByText(/terms and conditions/i);
const popover = screen.getByRole('dialog');
expect(popover.parentNode).not.toBeVisible();
userEvent.click(link);
expect(popover.parentNode).toBeVisible();
});
Try using the hidden option of the API:
const popover = screen.getByRole('dialog', {hidden: true})
ChakraUI renders a wrapper div around the section that has the dialog role. You can see this by using screen.debug() if you are using the testing-library. Notice the wrapper controls the visibility of said section, which starts as hidden, with styling elements and aria tags.
Using the hidden option allows you to look amognst the elements that aren't visible in the accessibility tree.
Since you want to test the popover, you should know there are some issues with modifying and checking the visibility of the popover when using jest-dom.
The chakra Modal applies a transform style to toggle its visibility. toBeVisible only checks a limited set of style attributes - transform is not one of them - so you might have to check for those instead, for example:
For invisibility:
expect(screen.getByRole('dialog')).toHaveStyle('transform: translateX(0px) translateY(0.18967%) translateZ(0);')
try toBeInTheDocument() or toMatchSnapshot()

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.

ReactJS & Material UI - ClickawayListener is not working properly in the Shadow DOM

I'm trying to build Micro Front End applications using ReactJS and Material UI framework. As a part of it, I was trying to embed a react application into the main React App using ShadowDOM.
I got the application running and working except when opening a popover, dialogs, modal, or date picker the ClickAwayListener is not functioning as expected meaning not closing.
Please suggest a way to fix this or show me a workaround to get the application running.
Code Sandbox
Found a workaround:
First, create a click listener on your shadow root to trigger a CustomEvent called closeModal.
const shadowRoot = document.getElementById('root').attachShadow({open: true});
let mountPoint = document.createElement('div');
mountPoint.id = "portal";
mountPoint.addEventListener('click', (e) => {
let event = new CustomEvent('closeModal',{bubbles: true, cancelable: false});
shadowRoot.dispatchEvent(event);
});
ReactDOM.render(themeProvider, mountPoint);
Then, when the popover or modal or date picker or dialog opens, create another event listener
document.getElementById('root').shadowRoot.addEventListener('closeModal', this.handleClose);
Once the modal is closed by the handleClose function, remove the event listener
document.getElementById('root').shadowRoot.removeEventListener('closeModal', this.handleClose);
Thats it.
I don't see where ClickAwayListener is being used in your CodeSandbox link, but I would guess that this issue is because you didn't wrap the inner element in an element that can accept a ref. Try wrapping the child element in a <div> and see where that gets you. :)

How to behaviour test a Component which uses React Bootstrap with Jest

In pseudo code:
MyComponent: React.createClass
doThis: () ->
//do something
render: () ->
<div>
<button className='something' onClick={clickHandler()}>click this button</button>
<ReactBootstrap.Pagination onSelect=(this.doThis) items=3 />
</div>
//tests
component = TestUtils.renderIntoDocument <MyComponent>
//test1
el = TestUtils.findRenderedDOMComponentWithClass component, 'something'
TestUtils.Simulate.click el
//test2
el = TestUtils.srcyRenderedDOMComponentsWithTag component, 'li'
TestUtils.Simulate.click el[0]
In test1 the click is fired. In test2 doThis() is not called
In both cases I definitely have a dom node and am firing the click on it. onSelect is the correct prop to use to pass to ReactBoostrap.Pagination. It works fine in the browser.
The Pagination class in Bootstrap uses onClick and seems to attach it to the li element it renders so I think I am targeting the correct element. (Edit: looking at Bootstrap-react's test for the Pagination component that targets the a tag which is rendered inside the li https://github.com/react-bootstrap/react-bootstrap/blob/master/test/PaginationSpec.js. However; I tried that too so I don't think that is my problem).
It seems to be to do with trying to target a dom node rendered by a child component. But I have no idea how to proceed. (Edit: or perhaps it is specific to react-bootstrap? Maybe I need to not mock some dependency...?)
The answer, for me, was to not mock 'classnames' - which is a dependency of react-bootstrap:
jest.dontMock 'classnames'
The answer was given by: http://racingtadpole.com/blog/test-react-with-jest/ so thanks to racingtadpole.

Resources