How to simulate a click on a Font Awesome Icon using Jest? - reactjs

I'm testing through Jest and am trying to test the click on a Font Awesome Icon. I've tried different ways to find the 'node', but I get the error that "Method “simulate” is meant to be run on 1 node. 0 found instead." Any insight would be helpful.
The error I get when I try different inputs to component.find() is: Method “simulate” is meant to be run on 1 node. 0 found instead.
StringEditor
const clearInput = () => {
onRemove()
}
render (
...
<FontAwesomeIcon icon={['fal', 'times-circle']} className="clear-button"
onClick={clearInput} /> : null`
)
onRemove is a callback function.
it('should call clearInput thus onRemove', () =>{
const onRemove= jest.fn()
const component = mount(<StringEditor {...defaultProps} onRemove={onRemove} />)
component.find('<dont know what to put>').simulate('click')
expect(saveValueFn).toBeCalled()
})

Try this:
it('should call clearInput thus onRemove', () =>{
const onRemove= jest.fn()
const component = mount(<StringEditor {...defaultProps} onRemove={onRemove} />)
component.find({ className: "clear-button" }).simulate('click');
expect(clearInput).toHaveBeenCalled();
})

You can use the Object Property Selector: https://airbnb.io/enzyme/docs/api/selector.html#4-object-property-selector
Or a React Component Constructor: https://airbnb.io/enzyme/docs/api/selector.html#2-a-react-component-constructor

Related

Test ResizeObserver and contentRect.height in TypeScript React Enzyme test

I created a simple Hook that uses ResizeObserver to run setState when an Mui Box element is resized before/after a certain point. The purpose was to apply different styles based on whether the flex component was wrapped or not.
It works in the browser, but now the problem that I have is that I have no idea how to write tests for it. I tried with Jest, Enzyme, but I cannot find a way to really run a test against it. I would like to mount the component with one width and verify that it has the proper class, then trigger the resize event and verify that the class changed. I will need to mock the ref and the height. I am searched the web for hours for a solution but haven't found anything that works.
Here is the component:
function Component {
const [isWrapped, setIsWrapped] = useState(false);
const myRef = useRef() as React.MutableRefObject<HTMLInputElement>;
React.useEffect() {
const resizeObserver = new ResizeObserver((entries) => {
if (entries[0].contentRect.height > 100) {
setIsWrapped(true);
} else {
setIsWrapped(false);
}
});
resizeObserver.observe(myRef.current);
}
return (
<Box {...{ ref: myRef }} display="flex" id="my-element" className={isWrapped ? classes.wrappedClass : classes.inlineClass}>{"someText"}</Box>
)
}
At the top of my test file I have
global.ResizeObserver = jest.fn().mockImplementation(() => ({
observe: jest.fn(),
unobserve: jest.fn(),
disconnect: jest.fn(),
}))
what I want my test to be like:
it("Test wrap/unwrap conditional styling", () => {
// mount with height 80px
let wrapper = mount(
<ReduxProvider store={store}>
<Component />
</ReduxProvider>
);
expect(toJson(wrapper)).toMatchSnapshot();
const myElement = wrapper.find("#my-element");
expect(myElement).toHaveCLass("wrappedClass");
// trigger resize with height 110
expect(myElement).toHaveCLass("inlineClass");
}

How to find a component inside another component in jest?

I want to find a component inside another component in Jest. After finding the component The length should be 1 but I am getting 0 length.
Test cases code is as follows -
beforeEach(() => {
wrapper = enzyme.mount(
<Rest
onApplyClick={mockOnApplyClick}
translateFn={mockTranslateFn}
someData={mockSomeData}
/>
);
});
and then we have test case -
it('Test case', () => {
let Button= wrapper.find(Button);
Button.simulate('click');
expect(wrapper.find(StyledPopover).prop('open')).toBe(true);
act(() => {
let newWrapper = wrapper
.find(<NewComponent {...props} myData={mockMyData[1]} />)
expect(newWrapper.length).toBe(1);
console.log(newWrapper.length, "newWrapper.length")
});
});
I am getting 0 length in console.log(newWrapper.length) But if we are passing let newWrapper = wrapper.find(NewComponent) Then I am getting length 1. So how to resolve this issue as I want to pass props to NewComponent so that I can find some other elements inside NewComponent.

Cant test copy from 'copy-to-clipboard' with sinon

I'm trying to test my component with Sinon.
It seems I can't simulate the click function which is in the TableMenu component.
TableMenu.jsx
import copy from 'copy-to-clipboard';
const TableMenu = ({onClick, onHide, rowId}) => (
<MenuPopover
onClick={onClick}
onHide={onHide}>
<MenuPopover.Item id={1} onClick={() => copy(rowId)} label='Copy'/>
</MenuPopover>
);
TableMenu.test.js
import copy from 'copy-to-clipboard';
jest.mock('copy-to-clipboard', () => sinon.spy());
it('check method onCopy called', () => {
const wrapper = shallow(<TableMenu {...props}/>);
wrapper.find(MenuPopover.Item).last().props().onClick()
expect(copy.calledOnce).to.eql(true);
});
I'm getting the below error:
Error: Not implemented: window.prompt
at module.exports (C:\adm\node_modules\jsdom\lib\jsdom\browser\not-implemented.js:9:17)
at Window.prompt (C:\adm\node_modules\jsdom\lib\jsdom\browser\Window.js:458:7)
at copy (C:\adm\node_modules\copy-to-clipboard\index.js:58:14)
at Object.onClick (C:\adm\src\TableMenu/TableMenu.jsx:19:43)
...
...
TypeError: reselectPrevious is not a function
at copy (node_modules\copy-to-clipboard\index.js:72:5)
at Object.onClick (src\TableMenu/TableMenu.jsx:19:43)
at Context.<anonymous> (src\TableMenu/TableMenu.test.js:62:62)
at process.topLevelDomainCallback (domain.js:121:23)
I guess this is being discussed in the github repo and the potential solution could be #106 (comment)
Or, just simply mock an implementation for window.prompt. e.g.
jest.spyOn(window, 'prompt').mockImplementation();

OnClick Enzyme - test Error: Method “simulate” is meant to be run on 1 node. 0 found instead

I have the following situation for React JS. I asked a similar question before and Tried to apply the same method to this:
className={'custom-grid-buttons tran-button enrollment-button'}
onClick={() => {this.props.openBatchUpdateLOAModal()}}
>
Batch Update
</button>
<button
className={'custom-grid-buttons tran-button enrollment-button'}
onClick={() => {this.props.getSelectedLOAs().then(() => {
this.props.selectedLOAs && this.props.selectedLOAs.length > 0 ? this.props.openDownloadLOAModal() : alert('Please select at least one LOA.')})}}
>
Download By Custodian
</button>
Getting the following error: Method “simulate” is meant to be run on 1 node. 0 found instead. I posted most of the test file here but I believe the main error is coming from this line :
wrapper.find(".custom-grid-buttons tran-button enrollment-button").simulate("click");
Pros are all set :
// jest mock functions (mocks this.props.func)
const setFromStatusList = jest.fn();
const openBatchUpdateLOAModal = jest.fn();
const getSelectedLOAs = jest.fn();
const getDynamicRender = jest.fn();
const openDownloadLOAModal = jest.fn();
const onClick = jest.fn();
// defining this.props
const baseProps = {
location: {
pathname:[],
},
services :{
Counterparty :{
URL : "TEST URL",
subscription_key: "test key",
},
},
setFromStatusList,
openBatchUpdateLOAModal,
getSelectedLOAs,
backgroundapp:{},
getDynamicRender,
openDownloadLOAModal,
onClick,
selectedLOAS:[],
}
beforeEach(() => wrapper = shallow(<BrowserRouter><LOA {...baseProps} /></BrowserRouter>));
it("should call openBatchUpdateLOAModal click", () => {
// Reset info from possible previous calls of these mock functions:
baseProps.openBatchUpdateLOAModal.mockClear();
baseProps.getSelectedLOAs.mockClear();
wrapper.setProps({
selectedLOAS: null
});
// Find the button and call the onClick handler
wrapper.find(".custom-grid-buttons tran-button enrollment-button").simulate("click");
// Test to make sure prop functions were called via simulating the button click
expect(baseProps.openBatchUpdateLOAModal).toHaveBeenCalled();
expect(baseProps.getSelectedLOAs).toHaveBeenCalled();
Likely just missing the . in front of the other class names:
wrapper.find(".custom-grid-buttons .tran-button .enrollment-button").simulate("click");
Though this can likely be simplified to just:
wrapper.find(".enrollment-button").simulate("click");
Unless you have multiple enrollment buttons on your page.

How to test React components inside react-responsive tags

Inside a <MyComponent> component I am using react-responsive <MediaQuery> components to distinguish between rendering mobile and desktop content.
export class MyComponent extends React.Component {
//...
render() {
<MediaQuery query="(max-width: 600)">
<div className="inside-mobile">mobile view</div>
</MediaQuery>
}
}
I want to test the HTML inside <MyComponent>'s render() using enzyme, but can't seem to dive into the child elements of <MediaQuery>:
it('should dive into <MediaQuery>', () => {
const wrapper = mount(<Provider store={mockedStore}><MyComponent/></Provider>)
const actual = wrapper.getDOMNode().querySelectorAll(".inside-mobile")
expect(actual).to.have.length(1)
}
A console.log(wrapper.debug())shows that nothing inside <MediaQuery> is being rendered, though.
I'm guessing in a test (with no actual browser) window.width is not set which leads to the <MediaQuery> component not rendering anything.
What I want to do:
I want to be able to test <MyComponent>'s content using enzyme with react-responsive (or something similar such as react-media) to deal with mobile vs desktop viewports.
Things I've tried:
circumventing this by using enzyme's shallow with dive() instead of mount, to no avail.
using react-media's <Media> instead of react-responsive's <MediaQuery>, which seems to set window.matchMedia() to true by default. However, that's not working either.
console.log(wrapper.debug()) shows:
<MyComponent content={{...}}>
<Media query="(min-width: 600px)" defaultMatches={true} />
</MyComponent>
I found a working solution, using react-media instead of react-responsive, by mocking window.matchMedia so that matches is set to true during the test:
Create specific media components for different viewports:
const Mobile = ({ children, content }) => <Media query="(max-width: 600px)" children={children}>{matches => matches ? content : "" }</Media>;
const Desktop = ...
Use specific media component:
<MyComponent>
<Mobile content={
<div className="mobile">I'm mobile</div>
}/>
<Desktop content={...}/>
</MyComponent>
Test content per viewport:
const createMockMediaMatcher = matches => () => ({
matches,
addListener: () => {},
removeListener: () => {}
});
describe('MyComponent', () => {
beforeEach(() => {
window.matchMedia = createMockMediaMatcher(true);
});
it('should display the correct text on mobile', () => {
const wrapper = shallow(<MyComponent/>);
const mobileView = wrapper.find(Mobile).shallow().dive();
const actual = mobileView.find(".mobile").text();
expect(actual).to.equal("I'm mobile");
});
});

Resources