I am trying to test a functional component. And the goal is to evaluate that the value change correctly.
I have only managed to carry out the test checking that it renders. But I can't find a way to pass the props to him
InputPassword
export default function InputPassword({ password, SetPassword }: any) {
return (
<input
type="password"
placeholder="password"
value={password ?? ''}
onChange={(event) => SetPassword(event.target.value)}
/>
);
}
Test:
test('Login InputPassword', () => {
render(<InputPassword />);
const username_input = screen.queryByPlaceholderText(/password/i);
});
Update final code
test('Login InputPassword', async () => {
const fakePass = '123';
const fakeCb = jest.fn();
render(<InputPassword password={fakePass} SetPassword={fakeCb} />);
const usernameInput = screen.queryByPlaceholderText(/password/i);
expect(usernameInput).toHaveValue(fakePass);
fireEvent.change(usernameInput, { target: { value: '000' } });
expect(fakeCb).toHaveBeenCalled();
});
Inside the render function you can pass props to the component just like you would pass props anywhere else.
test('Login InputPassword', () => {
render(<InputPassword password="123" />);
const username_input = screen.queryByPlaceholderText(/password/i);
});
Based on your comment:
test("Login InputPassword", async () => {
const fakePass = "123";
const fakeCb = jest.fn();
render(<InputPassword password={fakePass} setPassword={fakeCb} />);
const usernameInput = screen.queryByPlaceholderText(/password/i);
expect(usernameInput).toHaveValue(fakePass);
await userEvent.type(username_input, "changed");
expect(usernameInput).toHaveValue("changed");
expect(fakeCb).toHaveBeenCalledTimes(7);
});
On mount the input displays the password that is given to it via props. Then after the user provides a new password which calls the handler accordingly and the input's value is also updated.
Related
I need to assert that SearchInputActions.onSearchActivated(value) is called when something is written in an input. It is a callback which is in change handler handleChange. I've been trying to create to mocks - one for handleChange and one for search but it did not work either. I am using jest and enzyme for tests.
const SearchInput = () => {
const search = throttle(event => {
const value = event.target.value;
SearchInputActions.onSearchActivated(value);
});
const handleChange = event => {
event.persist();
search(event);
};
return (
<div>
<SomeChildComponent />
<input type="text" onChange={handleChange} />
</div>
)
}
Test:
it('should dispatch search action', async () => {
const tree = mount(<SearchInput />);
const spySearch = jest.spyOn(SearchInputActions, 'onSearchActivated');
SearchInputActions.onSearchActivated.mockImplementation(() => {})
tree.find('input').simulate('change', {target: value: 'test'}});
expect(spySearch).toBeCalled();
}
I figured it out: Because the callback function was throttled (lodash throttle) I needed to add jest.useFakeTimers(); Final code looks like this:
jest.useFakeTimers();
it('should dispatch search action', async () => {
const tree = mount(<SearchInput />);
const spySearch = jest.spyOn(SearchInputActions, 'onSearchActivated');
SearchInputActions.onSearchActivated.mockImplementation(() => {})
tree.find('input').simulate('change', {target: value: 'test'}});
expect(spySearch).not.toBeCalled();
jest.runAllTimers();
expect(spySearch).toBeCalled();
SearchInputActions.onSearchActivated.mockRestore();
}
I want to isolate the test to a targeted useState.
Lets say I have 3 useStates, of which some are in my component and some are in children components in this testcase.
Currently this logs for 3 different useStates. How to target the one I want. Lets say its called setMovies.
const createMockUseState = <T extends {}>() => {
type TSetState = Dispatch<SetStateAction<T>>;
const setState: TSetState = jest.fn((prop) => {
// if setMovies ???
console.log('jest - spy mock = ', prop);
});
type TmockUseState = (prop: T) => [T, TSetState];
const mockUseState: TmockUseState = (prop) => [prop, setState];
const spyUseState = jest.spyOn(React, 'useState') as jest.SpyInstance<[T, TSetState]>;
spyUseState.mockImplementation(mockUseState);
};
interface Props {
propertyToTest: boolean
};
describe('Search Movies', () => {
describe('Onload - do first search()', () => {
beforeAll(async () => {
createMockUseState<PROPS>();
wrapper = mount(
<ProviderMovies>
<SearchMovies />
</ProviderMovies>
);
await new Promise((resolve) => setImmediate(resolve));
await act(
() =>
new Promise<void>((resolve) => {
resolve();
})
);
});
});
});
as we know react hooks depends on each initialization position. And for example if you have 3 hooks inside your component and you want to mock the 2-nd, you should mock 1 and 2 with necessary data.
Something like this
//mock for test file
jest.mock(useState); // you should mock here useState from React
//mocks for each it block
const useMockHook = jest.fn(...);
jest.spyOn(React, 'useState').mockReturnValueOnce(useMockHook);
expect(useMockHook).toHaveBeenCalled();
// after that you can check whatever you need
I am new to Jestjs and enzyme framework and I am trying to write test cases for a particular react component and I am little stuck.
export class ProductDetailsForm extends Component{
handleMetaDataDefinition = e => {
const { value, name } = e.target;
if (name === "xmlVersion") {
this.checkSpecialCharacters(value);
}
this.setState(prevState => ({
...prevState,
[name]: value
}));
this.props.setProductDetailsFormValue({
...this.props.productDetailsForm,
[name]: value
});
};
checkSpecialCharacters = value => {
if (!value || value.match(/^[a-zA-Z0-9._-]+$/)) {
this.setState(() => ({ error: '' }));
} else {
this.setState(() => ({
error: `Special characters and operators such as !##$%^&*()+{}:;?|\\[]'"= are not allowed`
}));
}
}
render(){
return(
<div>
<MetaDataDefinition
readOnly={false}
metaData={this.state}
handleMetaDataDefinition={this.handleMetaDataDefinition}
validateVersion={this.validateVersion}
/>
</div>
);
}
}
I have started with the test case, but I am stuck and unable to proceed how to work on the function handleMetaDataDefinition for full coverage including the function checkSpecialCharacters. Below is the code that I started to write for ProductDetailsForm.test.js
let wrapper;
beforeEach(() => {
wrapper = shallow(
<ProductDetailForm />
);
});
test("should call handleMetaDataDefinition", ()=> {
wrapper.find('MetaDataDefinition').props('handleMetaDataDefinition');
});
I have used some part of my actual code and not the whole code, as I need help in this specific part only to write test case for handleMetaDataDefinition and checkSpecialCharacters methods.
There're two possible option how to write your tests.
You can trigger validation from your MetaDataDefinition component and pass there needed data.
test("should call handleMetaDataDefinition", ()=> {
const component = wrapper.find('MetaDataDefinition');
fillYourComponentSomehow();
triggerAnEventSomehow();
/*For example component.find('button').simulate('click');
wrapper.update();// We can wait for updating state differently(if needed i'll take a look to doc.)
expect(wrapper.state()).toBe(stateThatYouExpect);
});
Or you can test it as 'black box'
test("should call handleMetaDataDefinition", ()=> {
const component = wrapper.find('MetaDataDefinition');
component.props().handleMetaDataDefinition(objectForMethod)
wrapper.update();
expect(wrapper.state()).toBe(stateThatYouExpect);
});
If you have HOCs around your component you'll need to find this component by class name
wrapper.find('ProductDetailsForm')
UPDATE
You can test it like
let wrapper;
let setProductDetailsFormValue;
beforeEach(() => {
setProductDetailsFormValue = jest.fn();
wrapper = shallow(
<ProductDetailForm setProductDetailsFormValue={setProductDetailsFormValue} />
);
});
test("should call handleMetaDataDefinition", ()=> {
const testObject = { target: {name: 'xmlVersion', value: '!!!123asd!'}, }
const component = wrapper.find('MetaDataDefinition');
component.props().handleMetaDataDefinition(testObject)
wrapper.update();
expect(wrapper.state().error).toBe('Special characters and operators such as !##$%^&*()+{}:;?|\\[]'"= are not allowed');
expect(wrapper.state()[xmlVersion]).toBe('!!!123asd!');
expect(setProductDetailsFormValue).toBeCalledWith({
[xmlVersion]: '!!!123asd!',
...other fields})
});
I am developing a React application with jest and TypeMoq.
I can't test the negative path of a decision tree when the mocked call is a method on the object which needs to be undefined. Is there a method on TypeMoq that can help me verify that the provided method is not called?
type TopicComponentProps = {
topic: Topic
history?: History<any>
}
export const TopicComponent = ({topic, history} : TopicComponentProps) => {
const { Id, Name } = topic;
const filterTopic = () => {
if (history) { // <-- this is my problem
history.push(`/topic/overview/${Id}`);
}
}
return(
<Fragment>
<span
style={topicStyle}
onClick={() => filterTopic()}
className="topic">
{Name}
</span>
</Fragment>
)
}
The positive test case looks like this:
it('should trigger the navigation when clicked', () => {
const mockHistory = Mock.ofType<History<any>>();
const wrapper = mount(
<TopicComponent topic={testTopic} history={mockHistory.object} />
);
wrapper.simulate('click');
mockHistory.verify(x => x.push(It.isAnyString()), Times.once());
});
How do I setup the mock object, so i can test that no navigation happens when no history is provided?
it('should not trigger the navigation when history is undefined', () => {
let mockHistory = Mock.ofType<History<any>>();
???
const wrapper = mount(
<TopicComponent topic={testTopic} history={???} />
);
wrapper.simulate('click');
mockHistory.verify(x => x.push(It.isAnyString()), Times.never());
});
I have the following component:
render() {
return (
<textarea onChange={this.handlechange} value="initial value" />
)
}
handlechange = (e) => {
console.log(e.currentTarget.value);
}
and the corresponding test that's supposed to check if on change fired correctly or not:
const TEST_PROPS = {
OnChange: jest.fn()
}
it("Fires on change correctly", () => {
const textArea = enzyme.mount(<TextArea {...TEST_PROPS} />);
jest.resetAllMocks();
expect(textArea.find("textarea").simulate("change"));
expect(TEST_PROPS.OnChange).toHaveBeenCalledTimes(1);
expect(TEST_PROPS.OnChange).toHaveBeenLastCalledWith(//what should go here?//);
});
I want to pass in the value of the new target.value once the onchange is fired to the toHaveBeenLastCalledWith function. How can I do this?
simulate event accepts a event obj as a 2nd arg, which you can use it in your 2nd assertion.
const TEST_PROPS = {
OnChange: jest.fn()
}
it("Fires on change correctly", () => {
const textArea = enzyme.mount(<TextArea {...TEST_PROPS} />);
const event = { target: { value: "sometext" } };
jest.resetAllMocks();
expect(textArea.find("textarea").simulate("change", event));
expect(TEST_PROPS.OnChange).toHaveBeenCalledTimes(1);
expect(TEST_PROPS.OnChange).toHaveBeenLastCalledWith(event);
});