Skip to content

Commit bfdb026

Browse files
authored
feat: jest integration (#102)
## 📜 Description Will fix #101 ## 💡 Motivation and Context Right now it's not possible to write jest tests for components, that are using this library. To overcome the limitation I added `mock` and wrote several test cases as examples. ## 📢 Changelog ### CI - run `example` tests; ### Docs - added section about testing; ### Jest - added mocks; - added example of tests; ## 🤔 How Has This Been Tested? Tested locally and on CI that tests are working fine. ## 📝 Checklist - [x] CI successfully passed
1 parent 0ecccfc commit bfdb026

17 files changed

+2382
-61
lines changed

Diff for: .github/workflows/verify-js.yml

+10-3
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,13 @@ jobs:
4848
node-version: 16.x
4949
cache: yarn
5050
- name: Install dependencies
51-
run: yarn install --frozen-lockfile
52-
- name: Run tests
53-
run: yarn test
51+
run: |
52+
yarn install --frozen-lockfile
53+
cd example
54+
yarn install --frozen-lockfile
55+
- name: Run lib tests
56+
run: yarn test src
57+
- name: Run example app tests (verify mocks)
58+
run: |
59+
cd example
60+
yarn test

Diff for: docs/docs/recipes/jest-testing-guide.md

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
sidebar_position: 3
3+
---
4+
5+
# Jest testing guide
6+
7+
## Setting up a mock
8+
9+
This library includes a built in mock for Jest. To use it, add the following code to the [jest setup](https://jestjs.io/docs/configuration#setupfiles-array) file:
10+
11+
```js
12+
jest.mock('react-native-keyboard-controller', () =>
13+
require('react-native-keyboard-controller/jest')
14+
);
15+
```
16+
17+
## Test case example
18+
19+
Once you've set up mock - you can write your first test 😊. A sample of test case is shown below. For more test cases please see [this](https://github.com/kirillzyusko/react-native-keyboard-controller/tree/main/example/__tests__) link.
20+
21+
```tsx
22+
import '@testing-library/jest-native/extend-expect';
23+
import React from 'react';
24+
import { Animated } from 'react-native';
25+
import { render } from '@testing-library/react-native';
26+
27+
import { useKeyboardAnimation } from 'react-native-keyboard-controller';
28+
29+
function TestComponent() {
30+
const { height } = useKeyboardAnimation();
31+
32+
return (
33+
<Animated.View
34+
testID="view"
35+
style={{ transform: [{ translateY: height }] }}
36+
/>
37+
);
38+
}
39+
40+
describe('basic keyboard interaction', () => {
41+
it('should have different styles depends on position', () => {
42+
const { getByTestId, update } = render(<TestComponent />);
43+
44+
expect(getByTestId('view')).toHaveStyle({ transform: [{ translateY: 0 }] });
45+
46+
(useKeyboardAnimation as jest.Mock).mockReturnValue({
47+
height: new Animated.Value(150),
48+
progress: new Animated.Value(0.5),
49+
});
50+
update(<TestComponent />);
51+
52+
expect(getByTestId('view')).toHaveStyle({
53+
transform: [{ translateY: 150 }],
54+
});
55+
56+
(useKeyboardAnimation as jest.Mock).mockReturnValue({
57+
height: new Animated.Value(300),
58+
progress: new Animated.Value(1),
59+
});
60+
update(<TestComponent />);
61+
62+
expect(getByTestId('view')).toHaveStyle({
63+
transform: [{ translateY: 300 }],
64+
});
65+
});
66+
});
67+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
---
2+
sidebar_position: 3
3+
---
4+
5+
# Jest testing guide
6+
7+
## Setting up a mock
8+
9+
This library includes a built in mock for Jest. To use it, add the following code to the [jest setup](https://jestjs.io/docs/configuration#setupfiles-array) file:
10+
11+
```js
12+
jest.mock('react-native-keyboard-controller', () =>
13+
require('react-native-keyboard-controller/jest')
14+
);
15+
```
16+
17+
## Test case example
18+
19+
Once you've set up mock - you can write your first test 😊. A sample of test case is shown below. For more test cases please see [this](https://github.com/kirillzyusko/react-native-keyboard-controller/tree/main/example/__tests__) link.
20+
21+
```tsx
22+
import '@testing-library/jest-native/extend-expect';
23+
import React from 'react';
24+
import { Animated } from 'react-native';
25+
import { render } from '@testing-library/react-native';
26+
27+
import { useKeyboardAnimation } from 'react-native-keyboard-controller';
28+
29+
function TestComponent() {
30+
const { height } = useKeyboardAnimation();
31+
32+
return (
33+
<Animated.View
34+
testID="view"
35+
style={{ transform: [{ translateY: height }] }}
36+
/>
37+
);
38+
}
39+
40+
describe('basic keyboard interaction', () => {
41+
it('should have different styles depends on position', () => {
42+
const { getByTestId, update } = render(<TestComponent />);
43+
44+
expect(getByTestId('view')).toHaveStyle({ transform: [{ translateY: 0 }] });
45+
46+
(useKeyboardAnimation as jest.Mock).mockReturnValue({
47+
height: new Animated.Value(150),
48+
progress: new Animated.Value(0.5),
49+
});
50+
update(<TestComponent />);
51+
52+
expect(getByTestId('view')).toHaveStyle({
53+
transform: [{ translateY: 150 }],
54+
});
55+
56+
(useKeyboardAnimation as jest.Mock).mockReturnValue({
57+
height: new Animated.Value(300),
58+
progress: new Animated.Value(1),
59+
});
60+
update(<TestComponent />);
61+
62+
expect(getByTestId('view')).toHaveStyle({
63+
transform: [{ translateY: 300 }],
64+
});
65+
});
66+
});
67+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`components rendering should render \`KeyboardControllerView\` 1`] = `
4+
<KeyboardControllerView
5+
statusBarTranslucent={true}
6+
/>
7+
`;
8+
9+
exports[`components rendering should render \`KeyboardProvider\` 1`] = `
10+
<KeyboardProvider
11+
statusBarTranslucent={true}
12+
>
13+
<View
14+
style={
15+
Object {
16+
"backgroundColor": "black",
17+
"height": 20,
18+
"width": 20,
19+
}
20+
}
21+
/>
22+
</KeyboardProvider>
23+
`;

Diff for: example/__tests__/basic-interaction.spec.tsx

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import '@testing-library/jest-native/extend-expect';
2+
import React from 'react';
3+
import { Animated } from 'react-native';
4+
import { render } from '@testing-library/react-native';
5+
6+
import { useKeyboardAnimation } from 'react-native-keyboard-controller';
7+
8+
function TestComponent() {
9+
const { height } = useKeyboardAnimation();
10+
11+
return (
12+
<Animated.View
13+
testID="view"
14+
style={{ transform: [{ translateY: height }] }}
15+
/>
16+
);
17+
}
18+
19+
describe('basic keyboard interaction', () => {
20+
it('should have different styles depends on position', () => {
21+
const { getByTestId, update } = render(<TestComponent />);
22+
23+
expect(getByTestId('view')).toHaveStyle({ transform: [{ translateY: 0 }] });
24+
25+
(useKeyboardAnimation as jest.Mock).mockReturnValue({
26+
height: new Animated.Value(150),
27+
progress: new Animated.Value(0.5),
28+
});
29+
update(<TestComponent />);
30+
31+
expect(getByTestId('view')).toHaveStyle({
32+
transform: [{ translateY: 150 }],
33+
});
34+
35+
(useKeyboardAnimation as jest.Mock).mockReturnValue({
36+
height: new Animated.Value(300),
37+
progress: new Animated.Value(1),
38+
});
39+
update(<TestComponent />);
40+
41+
expect(getByTestId('view')).toHaveStyle({
42+
transform: [{ translateY: 300 }],
43+
});
44+
});
45+
});

Diff for: example/__tests__/components-rendering.spec.tsx

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import React from 'react';
2+
import { View } from 'react-native';
3+
import {
4+
KeyboardControllerView,
5+
KeyboardProvider,
6+
} from 'react-native-keyboard-controller';
7+
import { render } from '@testing-library/react-native';
8+
9+
function KeyboardControllerViewTest() {
10+
return <KeyboardControllerView statusBarTranslucent />;
11+
}
12+
13+
function KeyboardProviderTest() {
14+
return (
15+
<KeyboardProvider statusBarTranslucent>
16+
<View style={{ width: 20, height: 20, backgroundColor: 'black' }} />
17+
</KeyboardProvider>
18+
);
19+
}
20+
21+
describe('components rendering', () => {
22+
it('should render `KeyboardControllerView`', () => {
23+
expect(render(<KeyboardControllerViewTest />)).toMatchSnapshot();
24+
});
25+
26+
it('should render `KeyboardProvider`', () => {
27+
expect(render(<KeyboardProviderTest />)).toMatchSnapshot();
28+
});
29+
});

Diff for: example/__tests__/keyboard-handler.spec.tsx

+88
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
jest.unmock('react-native-reanimated');
2+
jest.useFakeTimers();
3+
4+
global.ReanimatedDataMock = {
5+
now: () => 0,
6+
};
7+
8+
import '@testing-library/jest-native/extend-expect';
9+
import React from 'react';
10+
import Reanimated, {
11+
useAnimatedStyle,
12+
useSharedValue,
13+
} from 'react-native-reanimated';
14+
import { render } from '@testing-library/react-native';
15+
16+
import {
17+
KeyboardHandler,
18+
NativeEvent,
19+
useKeyboardHandler,
20+
} from 'react-native-keyboard-controller';
21+
22+
function TestComponent() {
23+
const height = useSharedValue(0);
24+
useKeyboardHandler(
25+
{
26+
onStart: (e) => {
27+
'worklet';
28+
height.value = e.height;
29+
},
30+
onMove: (e) => {
31+
'worklet';
32+
height.value = e.height;
33+
},
34+
onEnd: (e) => {
35+
'worklet';
36+
height.value = e.height;
37+
},
38+
},
39+
[]
40+
);
41+
const style = useAnimatedStyle(
42+
() => ({
43+
width: 20,
44+
height: 20,
45+
backgroundColor: 'red',
46+
transform: [{ translateY: height.value }],
47+
}),
48+
[]
49+
);
50+
51+
return <Reanimated.View testID="view" style={style} />;
52+
}
53+
54+
describe('keyboard handler specification', () => {
55+
it('should execute all handlers and change corresponding style properties', () => {
56+
let handlers: KeyboardHandler = {};
57+
(useKeyboardHandler as jest.Mock).mockImplementation(
58+
(handler) => (handlers = handler)
59+
);
60+
const onStart = (e: NativeEvent) => handlers.onStart?.(e);
61+
const onMove = (e: NativeEvent) => handlers.onMove?.(e);
62+
const onEnd = (e: NativeEvent) => handlers.onEnd?.(e);
63+
const { getByTestId } = render(<TestComponent />);
64+
65+
expect(getByTestId('view')).toHaveStyle({ transform: [{ translateY: 0 }] });
66+
67+
onStart({ height: 100, progress: 1 });
68+
jest.advanceTimersByTime(100);
69+
70+
expect(getByTestId('view')).toHaveAnimatedStyle({
71+
transform: [{ translateY: 100 }],
72+
});
73+
74+
onMove({ height: 20, progress: 0.2 });
75+
jest.advanceTimersByTime(100);
76+
77+
expect(getByTestId('view')).toHaveAnimatedStyle({
78+
transform: [{ translateY: 20 }],
79+
});
80+
81+
onEnd({ height: 100, progress: 1 });
82+
jest.advanceTimersByTime(100);
83+
84+
expect(getByTestId('view')).toHaveAnimatedStyle({
85+
transform: [{ translateY: 100 }],
86+
});
87+
});
88+
});

Diff for: example/__tests__/reanimated.spec.tsx

+49
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import '@testing-library/jest-native/extend-expect';
2+
import React from 'react';
3+
import Reanimated, { useAnimatedStyle } from 'react-native-reanimated';
4+
import { render } from '@testing-library/react-native';
5+
6+
import { useReanimatedKeyboardAnimation } from 'react-native-keyboard-controller';
7+
8+
function TestComponent() {
9+
const { height } = useReanimatedKeyboardAnimation();
10+
const style = useAnimatedStyle(
11+
() => ({
12+
width: 20,
13+
height: 20,
14+
backgroundColor: 'red',
15+
transform: [{ translateY: height.value }],
16+
}),
17+
[]
18+
);
19+
20+
return <Reanimated.View testID="view" style={style} />;
21+
}
22+
23+
describe('basic keyboard interaction', () => {
24+
it('should have different styles depends on position', () => {
25+
const { getByTestId, update } = render(<TestComponent />);
26+
27+
expect(getByTestId('view')).toHaveStyle({ transform: [{ translateY: 0 }] });
28+
29+
(useReanimatedKeyboardAnimation as jest.Mock).mockReturnValue({
30+
height: { value: 150 },
31+
progress: { progress: 0.5 },
32+
});
33+
update(<TestComponent />);
34+
35+
expect(getByTestId('view')).toHaveStyle({
36+
transform: [{ translateY: 150 }],
37+
});
38+
39+
(useReanimatedKeyboardAnimation as jest.Mock).mockReturnValue({
40+
height: { value: 300 },
41+
progress: { progress: 1 },
42+
});
43+
update(<TestComponent />);
44+
45+
expect(getByTestId('view')).toHaveStyle({
46+
transform: [{ translateY: 300 }],
47+
});
48+
});
49+
});

0 commit comments

Comments
 (0)