react-native-actions-sheet
react-native-actions-sheet copied to clipboard
Cannot test this library with testing-library/react-native
First off all thanks for this great library!
After I've switched to this library some of my tests are failing, specifically test cases which interact with ActionSheet. I need to render ActionSheet content in my tests, after some research I found this peace of code, these changes were added not so far in the commit what I guess to cause a problem. I'm not sure if it's possible to mock this value outside the library.
Hi @dkulakov, what functionality are you trying to test exactly? I would recommend not mocking this library and just asserting that the show and hide functions are called. If you really want to, you could also add a snapshot. Here is an example:
import React from 'react';
import { fireEvent, render } from 'utils/test-utils/custom-render';
import LoginRegisterInfoSheet from '../login-register-info-sheet';
import { hideActionSheet, SheetManagerSheets } from 'interfaces/sheet-manager';
describe('LoginRegisterInfoSheet', () => {
test('should render correctly', () => {
const tree = render({
ui: <LoginRegisterInfoSheet />,
});
expect(tree).toMatchSnapshot();
});
test('should call hideActionSheet() when pressed', () => {
const tree = render({
ui: <LoginRegisterInfoSheet />,
});
const closeActionSheetButton = tree.getByTestId('loginRegisterInfoSheetCloseButton');
fireEvent(closeActionSheetButton, 'press');
expect(hideActionSheet).toBeCalledWith({ id: SheetManagerSheets.loginRegisterInfo });
});
});
The custom render import aligns with docs: https://testing-library.com/docs/react-native-testing-library/setup
Hi @johnny-mcfadden-dailypay , thanks for your reply!
Exactly, I don't want to mock this library, but the problem is that the value dimensions.height will be always 0
in the test environment, so it means you can't test your custom content inside the ActionSheet
component.
@dkulakov if you trigger the sheet open and wait for it async, does it still have 0 dimensions in height? In the example above, the close action sheet button i'm getting:
const closeActionSheetButton = tree.getByTestId('loginRegisterInfoSheetCloseButton');
is within the action sheet, as "custom content" as you've referred to. But I could grab any content inside the action sheet by test id and interact with it.
@johnny-mcfadden-dailypay as I can see dimensions.height
changes inside onLayout event, but test environment renders components in nodejs environment which doesn't have any dimensions, that's why dimensions.height
always will be 0.
What version do you use? The bug appears after 0.8.3
Not seeing this issue. Even my snapshots have all the child obj nodes. I'm using the latest: 0.8.7
. Are you ensuring you open the action sheet first before trying to assert elements? (sorry maybe a silly question)
@johnny-mcfadden-dailypay I've created reproducible example. Can you check it?
It fails with the latest version, but if you install version 0.8.3
, test works well.
Thanks in advance!
@dkulakov in your example it doesn't look like you've called the action sheet open before trying to assert the combo change option was called, could you try that?
@johnny-mcfadden-dailypay here is I call the action sheet open
Hey guys, I have a related problem and I thought this would be the best place to ask. I have a problem of finding the elements inside the ActionSheet in my test. Heres my component code:
const MyComponent = () => {
const actionSheetRef = useRef<ActionSheetRef>(null);
useEffect(() => {
actionSheetRef.current?.show();
}, []);
return (
<ActionSheet
ref={actionSheetRef}
...
>
<View testID='viewTestId'>
...
</View>
</ActionSheet>
)
}
If I render MyComponent in the test, it is unable to find 'viewTestId' with 'getById()' inside the ActionSheet.
It seems that 'findByText()' works though, but it does give me a reference error:
ReferenceError: You are trying to import a file after the Jest environment has been torn down.
Heres the test:
describe('MyComponent', () => {
it('Renders', () => {
const component = render(
<MyComponent onBack={jest.fn()} />
);
expect(component.findByText('Muokkaa tietoja')).toBeTruthy();
})
});
The render() is a custom method:
const customRender = (ui : any) => {
return render(ui, { wrapper: renderWithProviders });
};
Any suggestions? Thank you
@Taloqq try to add waitFor
like in this example
your test should like like, but don't forget to add async
await waitFor(() => { component.findByText('Muokkaa tietoja'); });
@dkulakov It still gives me the same referenceerror. Im able to fix the reference error with jest.useFakeTimers('legacy')
but it still says A worker process has failed to exit gracefully and has been force exited.
Anyhow, is it possible to use getByTestId()
with this library?
@Taloqq I'm using version 0.8.3
and my tests work fine, but on the latest version it doesn't, so try to downgrade your version to 0.8.3
and check your tests again.
@dkulakov Hey I'm having a new issue. I have a pressable/button inside the sheet component, and when Im trying to press it, it fails with Cannot read properties of undefined (reading 'onPress')
Have you had this issue? It doesnt matter if I find it by text or testid. await waitFor(() => fireEvent.press(component.findByTestId('taloButton')));
With getByTestId, it is unable to find it.
Also if I just test expect(component.findByText('Talo')).toBeTruthy();
, it is successful.
@Taloqq Look how I do it in my example
@dkulakov
await waitFor(() => component.getByText('Talo'));
await act(async () => {
await fireEvent.press(component.getByText('Talo'));
});
Gives Unable to find an element with text: Talo
And If i replace getByText with findByText, it gives Timed out in waitFor.
@Taloqq Can you share your whole test case?
@dkulakov
describe('NewAddressView', () => {
it('Navigates to page 2 when address and location type is set', async () => {
const component = render(
<NewAddressView onBack={jest.fn()} />
);
fireEvent.press(component.getByTestId('locationConfirm'));
await waitFor(() => fireEvent.press(component.getByTestId('nextPageButton')));
await waitFor(() => component.getByText('Talo'));
await act(async () => {
await fireEvent.press(component.getByText('Talo'));
});
});
});
And heres how im calling it:
const askLocationType = async () => {
const locationTypeResponse = await SheetManager.show('LocationTypeSheet');
if (locationTypeResponse) {
...
}
};
@Taloqq
Is it also inside ActionSheet? If so, does it work?
await waitFor(() => fireEvent.press(component.getByTestId('nextPageButton')));
@dkulakov No, const askLocationType = async () => { }
is not inside the actionSheet. Its in my AddressPage1 component. The action sheet fires when 'nextPageButton' is pressed
@Taloqq
Try to remove waitFor
for fireEvent.press(component.getByTestId('nextPageButton'))
@dkulakov It has no effect :/
@Taloqq Can you reproduce this issue using my demo project?
jest.mock('react-native-actions-sheet', () => {
const { View } = require('react-native')
const ActionSheet = props => {
return <View testID="actionSheet">{props.children}</View>
}
return {
__esModule: true,
default: ActionSheet,
SheetManager: {
hideAll: jest.fn(),
hide: jest.fn(),
show: jest.fn(),
},
}
})
I mocked the library, can you try this?
@Kaung-Htet-Hein thanks, I tried, but it doesn't help.
import { registerSheet } from 'react-native-actions-sheet';
this method renders sheets in a portal, so if we mock this lib, then a content never appears in the test.
@Kaung-Htet-Hein well, I made it work in this way
jest.mock('react-native-actions-sheet', () => {
const funcs = jest.requireActual('react-native-actions-sheet');
return {
__esModule: true,
...funcs,
SheetManager: {
show: funcs.SheetManager.show,
hide: jest.fn(),
// hide: funcs.SheetManager.hide, // <-- It doesn't work if uncomment this line
},
default: ({ children }) => children,
};
});