How to test using jest office-ui-fabric-react CallOut component? - reactjs

I've been trying to test Callout component in my react project.
For simplification, following is React render component:
<div className="UserInfoDiv">
<div ref={this.menuButtonElement}>
<ActionButton id="toggleCallout"
onClick={changeIsCallOutVisibleProptoTrue}
text="Show Callout" />
</div>
<Callout
className="calloutClass1"
target={this.menuButtonElement.current}
hidden={!this.props.isCalloutVisible}>
<div id="callOutContainer">
<span>Need to test items here.<span>
<button className="clickForSomeAction">Simulate Click on this</button>
</div>
</Callout>
</div>
This works absolutely fine in UI. For testing in jest, I tried following:
userMenu = mount(<UserInfoDivComponent {...props} />);
UserInfoDiv.find("button#toggleCallout").simulate('click');
expect(changeIsCallOutVisibleProptoTrue.mock.calls.length).toBe(1);
userMenu.setProps({isCalloutVisible: true });
// Following only gives html(included UserInfoDiv,toggleCallout) `without html from callout`:
console.log(userMenu.html());
I need help on, How to test following scenarios?
Callout is Visible?
Find .clickForSomeAction button inside Callout.calloutClass1 and simulate click
There are similar component (ex: DropDown, Contextual Menu) from office-fabric-ui which renders HTML in document and not in current component HTML.

Finally, I did testing of Callout using ReactTestUtils as given in examples:
let component:any;
const container = document.createElement('div');
document.body.appendChild(container);
let threwException = false;
try {
component = ReactTestUtils.renderIntoDocument(<UserInfoDivComponent {...itemProps} />);
} catch (e) {
threwException = true;
}
expect(threwException).toEqual(false);
const UserInfoDiv= ReactTestUtils.findRenderedDOMComponentWithClass(component, "UserInfoDiv");
const clickForSomeAction = ReactTestUtils.findRenderedDOMComponentWithClass(component, "clickForSomeAction");
ReactTestUtils.Simulate.click(clickForSomeAction);
it works as expected, which few glitches as we can not query ReactTestUtils directly by querySelectors.
Edit 1
we can query using XML selectors.

Related

React Jest Testing : How to test image is left aligned according to input parameter

I have to create react component having image and text box, so My task is to test
Image or Text box is Left or right aligned , as needed
Image or Text box is Top or bottom aligned, as needed
By passing input variant as textLeft or textRight
Example Component
Any Help?
If they both had the same aria-label or another selector you could use the getAllBy query which would give you an array of items in order they find them so then you could check the children by using within to query inside those.
Something like this would work.
const Component = () => {
return (
<>
<div aria-label="card">
<img alt="image example" />
</div>
<div aria-label="card">
<h1>This is heading</h1>
</div>
</>
)
}
import { render, screen, within } from '#testing-library/react'
test('React Testing Library works!', () => {
render(<Component />)
const cards = screen.getAllByLabelText('card')
expect(cards).toHaveLength(2)
expect(within(cards[0]).getByAltText('image example'))
expect(within(cards[1]).queryByAltText('image example')).not.toBeInTheDocument()
expect(within(cards[1]).getByText('This is heading'))
expect(within(cards[0]).queryByText('This is heading')).not.toBeInTheDocument()
})

react-testing-library testing Ant Design modal

I have a React component with Ant Design Modal inside it and I am trying to test that modal gets opened when a button it clicked:
The component:
const ModalComponent = () => {
const [visible, setVisible] = useState(false);
return (
<>
<Button type="primary" onClick={() => setVisible(true)}>
Open Modal
</Button>
<Modal
title="Modal title"
centered
visible={visible}
onOk={() => setVisible(false)}
onCancel={() => setVisible(false)}
>
<p>some contents...</p>
<p>some contents...</p>
<p>some contents...</p>
</Modal>
</>
);
};
Test file:
test('modal opening', async () => {
const { queryByText } = render(<ModalComponent />);
fireEvent.click(queryByText('Open Modal'));
await waitFor(() => expect(queryByText('Modal title')).toBeInTheDocument());
});
The problem is that the modal DOM is never rendered in the test when I try to debug, so the test fails. It could be happening because the modal content is created outside of the component DOM tree right inside the body tag?
There is no test failure that you have given from our side.
A little information from my side on Antd modal component.
Antd Modal during testing renders outside the container. This is because Antd uses the rc-dialog component and that component uses react portal to show modal which is always render outside the root div. In the same way, during testing modal will not render in the container but outside of it.
The test that you have given will pass(modal is present) because the queryByText will search the element in document.body not inside the container.
test('modal opening', async () => {
const { baseElement, queryByText } = render(<ModalComponent />);
fireEvent.click(queryByText('Open Modal'));
expect(baseElement).toMatchSnapshot(); // added snapshot
await waitFor(() => expect(queryByText('Modal title')).toBeInTheDocument());
});
baseElement will show all the elements that are present in the document.body.
I had this exact same use case, with a very similar component.
For some reason, if I triggered the event inside act, then the state of the component wouldn't be updated and the modal would never come up (even if a console.log in the event handler does show up in the console).
The solution was to do userEvent.click outside the act

Passing JSX into dangerouslySetInnerHtml - React

Background
I am working on a React application. I need to place some HTTML inside a div. But I need to pass a tooltip package inside the HTML I pass. I want to eventually only have the tooltip trigger on certain words. For now, I just want the package to show up when I wrap the entire html element string
Code
I basically want to do this
import Tippy from '#tippy.js/react';
const App = () => {
const myHtmlString = '<p>Hi</p>`;
const text = <Tippy content={myHtmlString} />;
return (
<div dangerouslySetInnerHtml={{ __html: text }} />
)
}
Problem
This renders [object Object]
I would like to render the text surrounded by the tooltip instead.

Testing grommet Layer component

I'm using grommet with react to render my application's UI. I have a Layer component shown when user click a button. Everything works fine but I don't know how to test Layer's children.
I'm using enzyme, mocha and chai as test suite.
This is code the code of my component:
<Layer align="right" closer>
<Header size="large" justify="between" align="center">
<Button icon={<CloseIcon />} plain={true} onClick={ props.hide }/>
</Header>
<Section key={index} pad={{ horizontal: 'large', vertical: 'small' }}>
{ props.list }
</Section>
</Layer>
and this is my test:
const wrapper = shallow(<MyComponent />);
const layer = wrapper.find(Layer);
//this works
expect(layer).to.have.length.of(1);
const section = layer.find(Section);
//and this fails
expect(section).to.have.length.of(1);
Looking at the rendered component in the application, I found that grommet render his Layer component in this way:
<Layer><span style={{ display: 'none'}}></span></Layer>
Anyone can help me?
Thank you
If you look at the source code for the layer component, you will see that it returns the span that you posted in the render method. It's not until the component has mounted that the layer's contents will be rendered by calling the addLayer method in the Layer class.
I believe that you should use enzyme's mount function in order to test that the Layer is properly rendering its content since you will want the componentDidMount method to be called.
I finally managed to resolve this issue by mocking grommet Layer component:
jest.mock("grommet/components/Layer", () => (props) => props.children);

React.js unit test click event with Enzyme and Sinon

I'm trying to attach a spy to a click event on my react component. I am using Enzyme with Mocha and Chai but I'm having trouble getting the following test to pass:
it('Handles a Click Event', () => {
let rootId = Bigtree['rootId'];
const spy = sinon.spy();
const render = shallow(<EnvH tree={smalltree.objects}
node={smalltree.objects[rootId]} root={rootId}/>);
render.find('.toggler').simulate('click');
expect(spy.called).to.be.true;
});
Here is the component I am testing:
class EnvH extends React.Component {
return (
<div className='top' key={Math.random()}>
<div className={'tableRow row'} id={node.id} style={rowStyle} key={Math.random()}>
<div style={nodeStyle} className={'root EnvHColumn ' + classNames(classObject)} key={Math.random()}>
//Here is the actual Click Item in question
<span className={'toggler'} onClick={this.toggleCollapseState.bind(this)}>{node.type} - {node.name}</span>
</div>
<ColumnContent columnType={'description'} nodeInfo={node.description} />
<ColumnContent columnType={'createdOn'} nodeInfo={node.createdAt} />
<ColumnContent columnType={'updatedOn'} nodeInfo={node.updatedAt} />
</div>
<div className={'Children'} style={childrenStyle} key={Math.random()}>
{childNodes}
</div>
</div>
);
Here is the function that gets called when the span gets clicked:
toggleCollapseState() {
this.setState({collapsed: !this.state.collapsed});
};
Thank you in advance for any help on this one. I should also mention that the test is not passing stating that it is expecting true but found false.
Your test is not passing because the spy function is not given to the span.toggler element, so it's never called by it.
To make the test pass you should instead write
sinon.spy(EnvH.prototype, 'toggleCollapseState')
and then
expect(EnvH.prototype.toggleCollapseState.calledOnce).to.be.true

Resources