Testing Formik using enzyme and jest in react - reactjs

My Formik page:
const IssueForm =({values,errors,touched,isSubmitting})=>{
const [modified,setModified] = useState(false);
const handleModified = () => setModified(true);
const handleSubmit = () => setModified(false);
return(
<div><br></br><br></br><br></br><br></br>
<h1>Add Issue</h1><br></br>
<Form>
<div>
<label>Description: </label>
<Field width="100px" type="text" name="issueDescription" placeholder="issuedescription" onInput={handleModified}/>
{touched.issueDescription && errors.issueDescription&&<span style={{color:'red'}}>{errors.issueDescription}</span>}
</div><div><br></br>
<button type ="submit" disabled={isSubmitting} onClick={handleSubmit}>Submit</button>
</Form>
</div>
)
};
I have mentioned one field .like this I have so many fields.
when I used normal form I generated test cases successfully as below.
describe('Test UserForm using Shallow rendering', () => {
let wrapper;
beforeEach(() => {
wrapper = shallow(<UserForm/>);
});
it('has 1 text input elements', () => {
expect(wrapper.find('input').length).toEqual(1);
})
it('should allow to type in issuedescription input field', () => {
wrapper.find('input#issueDescription').simulate('change', {
target: {value: 'Sachin'}
});
wrapper.update();
expect(wrapper.find('input#issueDescription').prop('value')).toEqual('Sachin');
})
});
when I changed my normal from to formik I executed the same test cases in formik I am getting error.
for first case :
expect(received).toEqual(expected) // deep equality
Expected: 1
Received: 0
for second case:
Method “simulate” is meant to be run on 1 node. 0 found instead.
I need to run this two cases for formik page .Iam new to react .can anyone help??

Related

react testing library and jest with search input to update value on props

Demo
The search has several props to handle debouncing and api calls being made. Therefor, the state of the search will be the following:
Empty: shows a search-icon with no text in the input
Recently typed text: shows a spinner(replacing the search-icon) to indicate a lookup is happening
debounced typed text: after xSeconds, a clear-x-icon(replacing the spinner) shows with the typed out text.
The Problem
I can't figure out how to get the unit test to update the passed value in the props after the input has been updated by the mock function.
The Component Code
function SearchBox({
isSearching,
searchValue,
handleSearch,
clearSearch
}) {
const classes = useSearchStyles();
return (
<div className={classes.searchContainer}>
{isSearching ? (
<div className={classes.spinnerContainer}>
<Spinner />
</div>
) : searchValue ? (
<Button icon className={classes.clearIcon} onClick={clearSearch}>
<ClearIcon />
</Button>
) : (
<SearchIcon className={classes.searchIcon} />
)}
<Input
className={classes.searchInput}
type="text"
placeholder="Search"
maxLength={500}
value={searchValue}
onChange={(e: ChangeEvent<HTMLInputElement>) => handleSearch(e.target.value)}
/>
</div>
);
}
The Test Code
import React from 'react';
import { render, screen, waitFor } from '#testing-library/react';
import userEvent from '#testing-library/user-event';
import SearchBox from './SearchBox';
// ===========================================================================
// =============================== Setup Tests ===============================
// ===========================================================================
const searchValue = 'test';
const mockHandleSearchFn = jest.fn();
const mockClearSearchFn = jest.fn();
function TestContainer() {
return (
<SearchBox
isSearching={false}
searchValue=""
handleSearch={mockHandleSearchFn}
clearSearch={mockClearSearchFn}
/>
);
}
// ===========================================================================
// =============================== Start Tests ===============================
// ===========================================================================
describe('SearchBox', () => {
describe('should match snapshot when', () => {
it('input is empty', () => {
const testComponent = render(<TestContainer />);
expect(testComponent.container).toMatchSnapshot();
});
it('then, enters text in input and handleSearch is invoked', async () => {
const userViewer = userEvent.setup();
render(<TestContainer />);
const searchInput = await waitFor(() => screen.getByPlaceholderText(/Search/i));
await userViewer.type(searchInput, searchValue);
expect(mockHandleSearchFn).toHaveBeenCalledTimes(1);
expect(searchInput).toHaveAttribute('value', searchValue); // <------------------------ failing here
});
Tests Execution Output Example
When you type into an <input /> field, it doesn't set the value attribute. You can see this by typing into a plain input and inspecting the element.
The proper way to access the input value is via toHaveValue:
expect(searchInput).toHaveValue(searchValue);

Test useRef's currents' properties using jest-enzyme

I am trying to test a hidden file inputs click using Jest-enzyme, for the following component.
const UploadField = ({handleFileUpload}) => {
const hiddenFileInputRef = React.useRef(null);
const handleChange = (event) => {
handleFileUpload(event.target.files[0]);
};
const handleClick = () => {
hiddenFileInputRef.current.click();
};
return (
<>
<input
type="file"
ref={hiddenFileInputRef}
onChange={handleChange}
style={{display: 'none'}}
/>
<div
onClick={handleClick}
className="upload-button-container">
upload file
</div>
</>
);
};
i tried the following test :
it('should call handle click of hidden fileinput on click of div', () => {
const useRefSpy = jest
.spyOn(React, 'useRef')
.mockReturnValueOnce({current: {click: jest.fn()}});
let divWrapper = wrapper.find(
'.upload-button-container'
);
divWrapper.simulate('click');
expect(useRefSpy).toBeCalledTimes(1);
});
It gives an error "TypeError: Cannot read property 'click' of null" . what am i doing wrong here?
Try to check if you were able find the right div by logging wrapperDiv.html() or debugging
I think you might have to pass the event like in this post. Simulating a Div Click on Enzyme and React

How to fire and test a real paste event (not simulated by calling the prop) in Jest and Enzyme

I'm trying to unit test a very simple feature in a React app where I'm blocking the user from pasting into a textarea by adding an event.preventDefault() in the event handler, like so:
function handlePaste(event) {
event.preventDefault();
}
// ... pass it down as props
<TextareaComponent onPaste={handlePaste} />
The problem I'm having is that every method I've found of dispatching events in Jest or Enzyme just "simulates" the event by getting the function passed to the onPaste prop and calling it directly with a mock event object. That's not what I'm interested in testing.
Ideally I want to do something like this, testing that the actual value of the input hasn't changed after pasting:
const wrapper = mount(<ParentComponent inputValue="Prefilled text" />);
const input = wrapper.find(TextareaComponent);
expect(input.value).toEqual("Prefilled text")
input.doAPaste("Pasted text")
expect(input.value).not.toEqual("Pasted text")
expect(input.value).toEqual("Prefilled text")
But haven't been able to find a method that works. Any help would be appreciated!
Since you're just testing against a synthetic event (and not some sort of secondary action -- like a pop up that warns the user that pasting is disabled), then the easiest and correct solution is to simulate a paste event, pass it a mocked preventDefault function, and then assert that the mocked function was called.
Attempting to make assertions against a real paste event is pointless as this a React/Javascript implementation (for example, making assertions that a callback function is called when an onPaste/onChange event is triggered). Instead, you'll want to test against what happens as a result of calling the callback function (in this example, making assertions that event.preventDefault was called -- if it wasn't called, then we know the callback function was never executed!).
Working example (click the Tests tab to run the assertions):
To keep it simple, I'm just asserting that the input is initially empty and then only updates the value if an onChange event was triggered. This can very easily be adapted to have some sort of passed in prop influence the default input's value.
App.js
import React, { useCallback, useState } from "react";
const App = () => {
const [value, setValue] = useState("");
const handleChange = useCallback(
({ target: { value } }) => setValue(value),
[]
);
const handlePaste = useCallback((e) => {
e.preventDefault();
}, []);
const resetValue = useCallback(() => {
setValue("");
}, []);
const handleSubmit = useCallback(
(e) => {
e.preventDefault();
console.log(`Submitted value: ${value}`);
setValue("");
},
[value]
);
return (
<form onSubmit={handleSubmit}>
<label htmlFor="foo">
<input
id="foo"
type="text"
data-testid="test-input"
value={value}
onPaste={handlePaste}
onChange={handleChange}
/>
</label>
<br />
<button data-testid="reset-button" type="button" onClick={resetValue}>
Reset
</button>
<button type="submit">Submit</button>
</form>
);
};
export default App;
App.test.js
import React from "react";
import { configure, mount } from "enzyme";
import Adapter from "enzyme-adapter-react-16";
import App from "./App";
configure({ adapter: new Adapter() });
const value = "Hello";
describe("App", () => {
let wrapper;
let inputNode;
beforeEach(() => {
wrapper = mount(<App />);
// finding the input node by a 'data-testid'; this is not required, but easier
// when working with multiple form elements and can be easily removed
// when the app is compiled for production
inputNode = () => wrapper.find("[data-testid='test-input']");
});
it("initially displays an empty input", () => {
expect(inputNode()).toHaveLength(1);
expect(inputNode().props().value).toEqual("");
});
it("updates the input's value", () => {
inputNode().simulate("change", { target: { value } });
expect(inputNode().props().value).toEqual(value);
});
it("prevents the input's value from updating from a paste event", () => {
const mockPreventDefault = jest.fn();
const prefilledText = "Goodbye";
// updating input with prefilled text
inputNode().simulate("change", { target: { value: prefilledText } });
// simulating a paste event with a mocked preventDefault
// the target.value isn't required, but included for illustration purposes
inputNode().simulate("paste", {
preventDefault: mockPreventDefault,
target: { value }
});
// asserting that "event.preventDefault" was called
expect(mockPreventDefault).toHaveBeenCalled();
// asserting that the input's value wasn't changed
expect(inputNode().props().value).toEqual(prefilledText);
});
it("resets the input's value", () => {
inputNode().simulate("change", { target: { value } });
wrapper.find("[data-testid='reset-button']").simulate("click");
expect(inputNode().props().value).toEqual("");
});
it("submits the input's value", () => {
inputNode().simulate("change", { target: { value } });
wrapper.find("form").simulate("submit");
expect(inputNode().props().value).toEqual("");
});
});

React mock submit form function using Jest and Enzyme

I'm trying to create a "simple" test to check if the onSubmit function of the form has been added / not removed from the component.
Form component:
<form onSubmit={SubmitForm} data-test="submit-new-product-form" >
<TextField type="text" ref={enteredNameRef} className="text-field" label="Name" value={enteredName} onChange={event => { handleChange('enteredName', setEnteredName, event.target.value) } } data-test="input-entered-name" /></form>
Test example:
test('should call submitNewProduct function upon form submission', () => {
let submitNewProduct = jest.fn(); //This is the mock I'm trying to put to check if it was called
let wrapper = shallow(<AddNewProduct />);
let form = wrapper.find("[data-test='submit-new-product-form']");
//This is where things don't make sense to me. Above I have the form component and I need to assign the
//submitNewProduct mock function to its onSubmit prop. But I don't know how.
form.simulate('submit', { preventDefault: () => console.log('preventDefault') });
expect(submitNewProduct).toHaveBeenCalled();
});
Any ideas please?

How to we simulate a file upload in jest

I'm writing a test using jest to test my reactJS components. I need to simulate a file upload in jest to test my reactjs component. Does anyone know how? Here's my code
<div className="add-graphic-card-cta">
<input
ref={inputRef}
className='add-graphic-card-file'
type="file"
accept=".jpg,.jpeg,.png,image/jpeg,image/png"
onChange={this._handleChooseGraphicChange.bind(this)}
onDrop={(e) => {
e.preventDefault();
return false;
}}
/>
<Button
className="add-graphic-card-button"
label={this.props.intl.formatMessage({ id: 'ccl-graphic-verb-add' })}
variant="cta"
onClick={this.onFileUpload.bind(this, inputRef)} />
</div>
Here's the test
it('upload a file', () => {
const fn = jest.fn();
const header = shallowWithIntl(<LibraryManagerAddGraphicCard onClick={fn} />).dive();
header.find('.add-graphic-card-button').simulate('click', {
preventDefault: jest.fn(),
stopPropagation: jest.fn()
});
I have not actually tried this one out, but I suppose you can simulate the onChange event to mock the file upload event:
header.find('.add-graphic-card-file').simulate('change', {
target: {
files: ['file.jpg'],
},
});
This should cause the _handleChooseGraphicChange method to be triggered.

Resources