Mocking & monitoring Keyboard events with jest in react native
So this problem was way more complex that I could imagine to solve at start. Since what you want to test here is dismiss() and show() basically for a keyboard right?
Tests were executed with the following lib: @testing-library/react-native
So the events and listeners by documentation for 0.63 and 0.62 is https://reactnative.dev/docs/keyboard#docsNav
useEffect(() => {
Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
Keyboard.addListener("keyboardDidHide", _keyboardDidHide);
// cleanup function
return () => {
Keyboard.removeListener("keyboardDidShow", _keyboardDidShow);
Keyboard.removeListener("keyboardDidHide", _keyboardDidHide);
};
}, []);
const _keyboardDidShow = () => {
alert("Keyboard Shown");
};
const _keyboardDidHide = () => {
alert("Keyboard Hidden");
};
To get Jest to call the 2 functions _keyboardDidShow
and _keyboardDidHide
you will need to use Keyboard.emit('keyboardDidShow')
Example:
it('Test Keyboards keyboardDidShow is called', () => {
const { getByTestId } = render(<Container />);
act(() => {
Keyboard.emit('keyboardDidShow', {});
});
const box = getByTestId('TEST');
//Do here your expect clauses to check if something changed in your container
});
Not fully sure if this will ever help anyone. But that's how I solved this puzzle to figure out how to coverage the _keyboardDidShow and Hide
EDIT: For version 0.66 > now you need to do the following:
useEffect(() => {
const kds = Keyboard.addListener("keyboardDidShow", _keyboardDidShow);
const kdh = Keyboard.addListener("keyboardDidHide", _keyboardDidHide);
// cleanup function
return () => {
kdh.remove();
kds.remove();
};
}, []);
const _keyboardDidShow = () => {
alert("Keyboard Shown");
};
const _keyboardDidHide = () => {
alert("Keyboard Hidden");
};
Since they changed the way to make it subscription events from now on
And for the tests change the Keyboard.emit to:
Keyboard._emitter.emit('keyboardDidShow', {});
Keyboard._emitter.emit('keyboardDidHide', {});
And you should have everything you need to make it work in jest :)
I was facing a similar issue with component that subscribed to Keyboard
events
const MyComponent = () => {
useEffect(() => {
const listener = Keyboard.addListener('keyboardDidHide', () => {})
return () => {
listener.remove()
}
})
return <View>...</View>
}
I was able to test Keyboard.addListener
with following test and also test that listener.remove
is being called on component unmount
import renderer from 'react-test-renderer'
const mockListener = {
remove: jest.fn(),
}
const originalAddListener = Keyboard.addListener
const mockAddListener = jest.fn().mockReturnValue(mockListener)
describe('<MyComponent />', () => {
beforeAll(() => {
Keyboard.addListener = mockAddListener
})
beforeEach(() => {
mockAddListener.mockClear()
mockListener.remove.mockClear()
})
afterAll(() => {
Keyboard.addListener = originalAddListener
})
it('should subscribe to KeyboardDidClose event', () => {
renderer.create(<MyComponent />)
expect(Keyboard.addListener).toHaveBeenCalled()
})
it('should call listener.remove on unmount', () => {
const component = renderer.create(
< MyComponent />,
)
component.unmount()
expect(mockListener.remove).toHaveBeenCalled()
})
})