Skip to content

Commit 52637c3

Browse files
committed
feat(suite-native): introduce component tests with redux
1 parent 4faec83 commit 52637c3

File tree

14 files changed

+145
-31
lines changed

14 files changed

+145
-31
lines changed

jest.config.native.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@ module.exports = {
2424
'\\.(js|jsx|ts|tsx)$': ['babel-jest', babelConfig],
2525
},
2626
transformIgnorePatterns: [
27-
'node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg)',
27+
'node_modules/(?!((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|@sentry/react-native|native-base|react-native-svg|@shopify/react-native-skia)',
2828
],
2929
setupFiles: [
3030
'<rootDir>/../../node_modules/@shopify/react-native-skia/jestSetup.js',
3131
'<rootDir>/../../node_modules/react-native-gesture-handler/jestSetup.js',
3232
'<rootDir>/../../suite-native/test-utils/src/atomsMock.js',
3333
'<rootDir>/../../suite-native/test-utils/src/expoMock.js',
34+
'<rootDir>/../../suite-native/firmware/src/jestSetup.js',
35+
'<rootDir>/../../suite-native/connection-status/src/jestSetup.js',
36+
'<rootDir>/../../suite-native/react-native-graph/src/jestSetup.js',
3437
],
3538
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { renderWithStore, waitFor } from '@suite-native/test-utils';
2+
3+
import { AppTabNavigator } from '../AppTabNavigator';
4+
5+
describe('AppTabNavigator', () => {
6+
it('should render 3 buttons', async () => {
7+
const { getByText } = renderWithStore(<AppTabNavigator />);
8+
await waitFor(() => expect(getByText('Home')).toBeDefined());
9+
10+
expect(getByText('Home')).toBeDefined();
11+
expect(getByText('My assets')).toBeDefined();
12+
expect(getByText('Settings')).toBeDefined();
13+
});
14+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import mockRNCNetInfo from '@react-native-community/netinfo/jest/netinfo-mock.js';
2+
3+
jest.mock('@react-native-community/netinfo', () => mockRNCNetInfo);
+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
jest.mock('@suite-native/firmware', () => ({
2+
...jest.requireActual('./nativeFirmwareSlice'),
3+
...jest.requireActual('./hooks/useIsFirmwareUpdateFeatureEnabled'),
4+
UpdateProgressIndicatorDemo: () => null,
5+
FirmwareUpdateInProgressScreen: () => null,
6+
}));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
jest.mock('@suite-native/react-native-graph', () => ({}));

suite-native/state/src/store.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ import { blockchainMiddleware } from '@suite-native/blockchain';
1212
import { extraDependencies } from './extraDependencies';
1313
import { prepareRootReducers } from './reducers';
1414

15+
type RootReducerShape = Awaited<ReturnType<typeof prepareRootReducers>>;
16+
export type PreloadedState = Partial<RootReducerShape> | undefined;
17+
1518
const ENABLE_REDUX_LOGGER = false;
1619

1720
const middlewares: Middleware[] = [
@@ -33,7 +36,7 @@ if (__DEV__) {
3336
}
3437
}
3538

36-
export const initStore = async () =>
39+
export const initStore = async (preloadedState?: PreloadedState) =>
3740
configureStore({
3841
reducer: await prepareRootReducers(),
3942
middleware: getDefaultMiddleware =>
@@ -45,4 +48,5 @@ export const initStore = async () =>
4548
immutableCheck: false,
4649
}).concat(middlewares),
4750
enhancers: defaultEnhancers => defaultEnhancers.concat(enhancers),
51+
preloadedState,
4852
});

suite-native/test-utils/package.json

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,12 @@
1010
"type-check": "yarn g:tsc --build"
1111
},
1212
"dependencies": {
13+
"@react-navigation/native": "6.1.18",
14+
"@reduxjs/toolkit": "1.9.5",
1315
"@testing-library/react-native": "13.0.0",
1416
"@trezor/styles": "workspace:*",
1517
"@trezor/theme": "workspace:*",
16-
"react": "18.2.0"
18+
"react": "18.2.0",
19+
"react-redux": "8.0.7"
1720
}
1821
}

suite-native/test-utils/redux.d.ts

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { AsyncThunkAction } from '@reduxjs/toolkit';
2+
3+
declare module 'redux' {
4+
export interface Dispatch<A extends Action = AnyAction> {
5+
<TThunk extends AsyncThunkAction<any, any, any>>(thunk: TThunk): ReturnType<TThunk>;
6+
7+
<ReturnType = any, State = any, ExtraThunkArg = any>(
8+
thunkAction: ThunkAction<ReturnType, State, ExtraThunkArg, A>,
9+
): ReturnType;
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,22 @@
11
import { ReactNode } from 'react';
22

3+
import { NavigationContainer } from '@react-navigation/native';
4+
35
import { createRenderer, StylesProvider } from '@trezor/styles';
46
import { prepareNativeTheme } from '@trezor/theme';
57
import { IntlProvider } from '@suite-native/intl';
68

79
type ProviderProps = {
810
children: ReactNode;
911
};
12+
1013
const renderer = createRenderer();
1114
const theme = prepareNativeTheme({ colorVariant: 'standard' });
1215

13-
export const Provider = ({ children }: ProviderProps) => (
16+
export const BasicProvider = ({ children }: ProviderProps) => (
1417
<IntlProvider>
1518
<StylesProvider theme={theme} renderer={renderer}>
16-
{children}
19+
<NavigationContainer>{children}</NavigationContainer>
1720
</StylesProvider>
1821
</IntlProvider>
1922
);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import { ReactNode, useEffect, useState } from 'react';
2+
import { Provider } from 'react-redux';
3+
4+
import { EnhancedStore } from '@reduxjs/toolkit';
5+
6+
import { initStore, PreloadedState } from '@suite-native/state';
7+
8+
import { BasicProvider } from './BasicProvider';
9+
10+
type ReduxProviderProps = {
11+
children: ReactNode;
12+
preloadedState: PreloadedState;
13+
};
14+
15+
/*
16+
This is file is a copy of `StoreProvider.tsx` from `suite-native/state` but with ability to pass `preloadedState` as a prop
17+
and without the `Persistor` and `Sentry` logic.
18+
*/
19+
export const StoreProviderForTests = ({ children, preloadedState }: ReduxProviderProps) => {
20+
const [store, setStore] = useState<EnhancedStore | null>(null);
21+
22+
useEffect(() => {
23+
const initStoreAsync = async () => {
24+
const freshStore = await initStore(preloadedState);
25+
setStore(freshStore);
26+
};
27+
28+
initStoreAsync();
29+
}, [preloadedState]);
30+
31+
if (store === null) return null;
32+
33+
return (
34+
<Provider store={store}>
35+
<BasicProvider>{children}</BasicProvider>
36+
</Provider>
37+
);
38+
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ReactElement } from 'react';
2+
3+
import { render, RenderOptions } from '@testing-library/react-native';
4+
5+
import { PreloadedState } from '@suite-native/state';
6+
7+
type ProviderProps = {
8+
preloadedState?: PreloadedState;
9+
} & RenderOptions;
10+
11+
export const createRender =
12+
(Provider: NonNullable<RenderOptions['wrapper']>) =>
13+
<T,>(
14+
element: ReactElement<T>,
15+
{ wrapper: WrapperComponent, preloadedState, ...options }: ProviderProps = {},
16+
) => {
17+
const wrapperWithProvider = ({ children }: { children: ReactElement }) => (
18+
<Provider preloadedState={preloadedState}>
19+
{WrapperComponent ? <WrapperComponent>{children}</WrapperComponent> : children}
20+
</Provider>
21+
);
22+
23+
return render(element, {
24+
wrapper: wrapperWithProvider,
25+
...options,
26+
});
27+
};

suite-native/test-utils/src/expoMock.js

+2
Original file line numberDiff line numberDiff line change
@@ -401,3 +401,5 @@ jest.mock('expo-constants', () => {
401401

402402
return Constants;
403403
});
404+
405+
jest.mock('redux-devtools-expo-dev-plugin', () => () => next => next);

suite-native/test-utils/src/index.tsx

+8-26
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,8 @@
1-
import { ReactElement } from 'react';
1+
import { createRender } from './createRender';
2+
import { BasicProvider } from './BasicProvider';
3+
import { StoreProviderForTests } from './StoreProviderForTests';
24

3-
import { render as origRender } from '@testing-library/react-native';
4-
5-
import { Provider } from './Provider';
6-
7-
type Parameters<TParams> = TParams extends (...args: infer TParamsInferred) => any
8-
? TParamsInferred
9-
: never;
10-
11-
export const render = (
12-
element: ReactElement,
13-
{ wrapper: WrapperComponent, ...options }: Parameters<typeof origRender>[1] = {},
14-
): ReturnType<typeof origRender> => {
15-
const wrapperWithProvider = WrapperComponent
16-
? ({ children }: { children: ReactElement }) => (
17-
<Provider>
18-
<WrapperComponent>{children}</WrapperComponent>
19-
</Provider>
20-
)
21-
: Provider;
22-
23-
return origRender(element, {
24-
wrapper: wrapperWithProvider,
25-
...options,
26-
});
27-
};
5+
export type { PreloadedState } from '@suite-native/state';
286

297
export {
308
act,
@@ -35,3 +13,7 @@ export {
3513
waitFor,
3614
waitForElementToBeRemoved,
3715
} from '@testing-library/react-native';
16+
17+
export const render = createRender(BasicProvider);
18+
19+
export const renderWithStore = createRender(StoreProviderForTests);

yarn.lock

+17
Original file line numberDiff line numberDiff line change
@@ -10950,6 +10950,20 @@ __metadata:
1095010950
languageName: unknown
1095110951
linkType: soft
1095210952

10953+
"@suite-native/module-trading@workspace:suite-native/module-trading":
10954+
version: 0.0.0-use.local
10955+
resolution: "@suite-native/module-trading@workspace:suite-native/module-trading"
10956+
dependencies:
10957+
"@react-navigation/native-stack": "npm:6.11.0"
10958+
"@reduxjs/toolkit": "npm:1.9.5"
10959+
"@suite-native/navigation": "workspace:*"
10960+
"@trezor/styles": "workspace:*"
10961+
react: "npm:18.2.0"
10962+
react-native: "npm:0.76.1"
10963+
react-native-reanimated: "npm:^3.16.7"
10964+
languageName: unknown
10965+
linkType: soft
10966+
1095310967
"@suite-native/navigation@workspace:*, @suite-native/navigation@workspace:suite-native/navigation":
1095410968
version: 0.0.0-use.local
1095510969
resolution: "@suite-native/navigation@workspace:suite-native/navigation"
@@ -11175,10 +11189,13 @@ __metadata:
1117511189
version: 0.0.0-use.local
1117611190
resolution: "@suite-native/test-utils@workspace:suite-native/test-utils"
1117711191
dependencies:
11192+
"@react-navigation/native": "npm:6.1.18"
11193+
"@reduxjs/toolkit": "npm:1.9.5"
1117811194
"@testing-library/react-native": "npm:13.0.0"
1117911195
"@trezor/styles": "workspace:*"
1118011196
"@trezor/theme": "workspace:*"
1118111197
react: "npm:18.2.0"
11198+
react-redux: "npm:8.0.7"
1118211199
languageName: unknown
1118311200
linkType: soft
1118411201

0 commit comments

Comments
 (0)