Skip to content

Commit c6ac90e

Browse files
Marik Shnitmanethanshar
Marik Shnitman
andauthored
POC Export of testkits (#1925)
* POC Export of testkits * Added semicolon * Some more testing * Testing builds again * Babel build * Added testkit * Added testkit to npmignore unignore * Type fix wip * Removed .js file * Changed structure * Amit's Solution * Fixed types & main * Added drivers to export * Added Basic testkit for `Swtich` component * Fixed AccessibilityState * removed comment * Fixed packagejson testkit * Move Switch spec into __tests__ folder * Restructure and cleanup testkit components drivers Co-authored-by: Ethan Sharabi <[email protected]>
1 parent 8454ab2 commit c6ac90e

File tree

17 files changed

+207
-78
lines changed

17 files changed

+207
-78
lines changed

.npmignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,6 @@ index.ios.js
247247
*.ts
248248
*.tsx
249249
# include the .d.ts files
250-
!*.d.ts
250+
!*.d.ts
251+
252+
!testkit/*.ts

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
"@testing-library/react-hooks": "^7.0.2",
7373
"@testing-library/react-native": "^7.2.0",
7474
"@types/hoist-non-react-statics": "^3.3.1",
75+
"@types/jest": "^27.4.1",
7576
"@types/lodash": "^4.0.0",
7677
"@types/prop-types": "^15.5.3",
7778
"@types/react-native": "0.66.4",

src/.babelrc.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
[
66
"module-resolver",
77
{
8-
"root": ["./src"],
8+
"root": ["./src", "./testkit"],
99
"alias": {
1010
"commons": "./src/commons",
1111
"helpers": "./src/helpers",
Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1+
import _ from 'lodash';
12
import {fireEvent, RenderAPI} from '@testing-library/react-native';
23
import {ReactTestInstance} from 'react-test-renderer';
3-
import TextDriver from '../text/Text.driver';
4-
import ImageDriver from '../image/Image.driver';
5-
import _ from 'lodash';
4+
import {TextDriver} from '../text/Text.driver';
5+
import {ImageDriver} from '../image/Image.driver';
66

7-
8-
const ButtonDriverFactory = async ({wrapperComponent, testID}: {wrapperComponent: RenderAPI, testID: string}) => {
7+
export const ButtonDriver = async ({wrapperComponent, testID}: {wrapperComponent: RenderAPI; testID: string}) => {
98
const button: ReactTestInstance | null = await wrapperComponent.queryByTestId(testID);
109
const label = await TextDriver({wrapperComponent, testID: `${testID}.label`});
1110
const icon = await ImageDriver({wrapperComponent, testID: `${testID}.icon`});
@@ -17,7 +16,7 @@ const ButtonDriverFactory = async ({wrapperComponent, testID}: {wrapperComponent
1716
if (button) {
1817
fireEvent.press(button);
1918
} else {
20-
console.warn(`ButtonDriverFactory: cannot click because testID:${testID} were not found`);
19+
console.warn(`ButtonDriver: cannot click because testID:${testID} were not found`);
2120
}
2221
},
2322
// label
@@ -29,5 +28,3 @@ const ButtonDriverFactory = async ({wrapperComponent, testID}: {wrapperComponent
2928
isIconExists: () => icon.exists()
3029
};
3130
};
32-
33-
export default ButtonDriverFactory;

src/components/button/__tests__/index.driver.spec.js

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import React, {useState} from 'react';
22
import {render, waitFor} from '@testing-library/react-native';
3-
import Button from '../index';
43
import View from '../../view';
5-
import ButtonTestKit from '../Button.driver';
64
import Text from '../../text';
7-
import TextTestKit from '../../text/Text.driver';
5+
import Button from '../index';
6+
import {ButtonDriver} from '../Button.driver';
7+
import {TextDriver} from '../../text/Text.driver';
88

99
const BUTTON_ID = 'button_test_id';
1010
const CHILDREN_TEXT_ID = 'children_test_id';
@@ -14,22 +14,22 @@ const CHILDREN_TEXT = 'custom button text';
1414
describe.skip('Button', () => {
1515
it('should render a button', async () => {
1616
const wrapperComponent = renderWrapperScreenWithButton({});
17-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
17+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
1818
expect(buttonDriver.exists()).toBeTruthy();
1919
});
2020

2121
describe('custom button', () => {
2222
it('should render a custom button', async () => {
2323
const wrapperComponent = renderWrapperScreenWithCustomButton({});
24-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
24+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
2525
expect(buttonDriver.exists()).toBeTruthy();
2626
});
2727

2828
it('should render the children with correct text', async () => {
2929
const wrapperComponent = renderWrapperScreenWithCustomButton({});
30-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
30+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
3131
expect(buttonDriver.exists()).toBeTruthy();
32-
const childrenTextDriver = await TextTestKit({wrapperComponent, testID: CHILDREN_TEXT_ID});
32+
const childrenTextDriver = await TextDriver({wrapperComponent, testID: CHILDREN_TEXT_ID});
3333
expect(childrenTextDriver.getTextContent()).toEqual(CHILDREN_TEXT);
3434
});
3535
});
@@ -41,14 +41,14 @@ describe.skip('Button', () => {
4141

4242
it('should trigger onPress callback', async () => {
4343
const wrapperComponent = renderWrapperScreenWithButton({onPress: onPressCallback});
44-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
44+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
4545
buttonDriver.click();
4646
await waitFor(() => expect(onPressCallback).toHaveBeenCalledTimes(1));
4747
});
4848

4949
it('should not trigger onPress callback if button disabled', async () => {
5050
const wrapperComponent = renderWrapperScreenWithButton({onPress: onPressCallback, disabled: true});
51-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
51+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
5252
buttonDriver.click();
5353
await waitFor(() => expect(onPressCallback).toHaveBeenCalledTimes(0));
5454
});
@@ -58,35 +58,35 @@ describe.skip('Button', () => {
5858
const LABEL = 'mock label';
5959
it('should render a button with correct content', async () => {
6060
const wrapperComponent = renderWrapperScreenWithButton({label: LABEL});
61-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
61+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
6262
expect(buttonDriver.getLabelContent()).toEqual(LABEL);
6363
});
6464

6565
xit('should render a button with correct label content. ', async () => {
6666
// todo import @testing-library/jest-native(/extend-expect)
6767
const wrapperComponent = renderWrapperScreenWithButton({label: LABEL});
68-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
68+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
6969
expect(buttonDriver.getLabelRootElement()).toHaveTextContent(LABEL);
7070
});
7171

7272
it('should render a button without label. ', async () => {
7373
const wrapperComponent = renderWrapperScreenWithButton({});
74-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
74+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
7575
expect(buttonDriver.isLabelExists()).toBeFalsy();
7676
});
7777
});
7878

7979
describe('icon', () => {
8080
it('should render a button without an icon. ', async () => {
8181
const wrapperComponent = renderWrapperScreenWithButton({});
82-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
82+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
8383
expect(buttonDriver.isIconExists()).toBeFalsy();
8484
});
8585

8686
it('should render a button with icon. ', async () => {
8787
const ICON = 12;
8888
const wrapperComponent = renderWrapperScreenWithButton({iconSource: ICON});
89-
const buttonDriver = await ButtonTestKit({wrapperComponent, testID: BUTTON_ID});
89+
const buttonDriver = await ButtonDriver({wrapperComponent, testID: BUTTON_ID});
9090
expect(buttonDriver.isIconExists()).toBeTruthy();
9191
});
9292
});
@@ -95,10 +95,10 @@ describe.skip('Button', () => {
9595
//todo take it out of this file. to the demo screens maybe
9696
it('should change text values according to state changes from buttons pressing', async () => {
9797
const wrapperComponent = renderMoreComplicatedScreen();
98-
const text1Driver = await TextTestKit({wrapperComponent, testID: `text_1`});
99-
const text2Driver = await TextTestKit({wrapperComponent, testID: `text_2`});
100-
const button1Driver = await ButtonTestKit({wrapperComponent, testID: `${BUTTON_ID}1`});
101-
const button2Driver = await ButtonTestKit({wrapperComponent, testID: `${BUTTON_ID}2`});
98+
const text1Driver = await TextDriver({wrapperComponent, testID: `text_1`});
99+
const text2Driver = await TextDriver({wrapperComponent, testID: `text_2`});
100+
const button1Driver = await ButtonDriver({wrapperComponent, testID: `${BUTTON_ID}1`});
101+
const button2Driver = await ButtonDriver({wrapperComponent, testID: `${BUTTON_ID}2`});
102102
expect(text1Driver.getTextContent()).toBe('button 1 pressed 0 times');
103103
expect(text2Driver.getTextContent()).toBe('button 2 pressed 0 times');
104104
button1Driver.click();

src/components/image/Image.driver.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
import {RenderAPI} from '@testing-library/react-native';
22
import {ReactTestInstance} from 'react-test-renderer';
33

4-
5-
const ImageDriverFactory = async ({wrapperComponent, testID}: {wrapperComponent: RenderAPI, testID: string}) => {
6-
4+
export const ImageDriver = async ({wrapperComponent, testID}: {wrapperComponent: RenderAPI; testID: string}) => {
75
const text: ReactTestInstance | null = await wrapperComponent.queryByTestId(testID);
86
return {
97
//todo more research on this component
@@ -12,5 +10,3 @@ const ImageDriverFactory = async ({wrapperComponent, testID}: {wrapperComponent:
1210
// getImageContent: () => text.props.value
1311
};
1412
};
15-
16-
export default ImageDriverFactory;
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
import React from 'react';
2+
import {render} from '@testing-library/react-native';
3+
import Switch, {SwitchProps} from '../index';
4+
import {SwitchDriver} from '../switch.driver';
5+
import View from '../../view';
6+
7+
describe('Switch', () => {
8+
9+
const renderSwitch = (testID: string, props: Partial<SwitchProps>) => {
10+
const defaultProps: SwitchProps = {
11+
testID,
12+
value: false,
13+
onValueChange: jest.fn(),
14+
disabled: false
15+
};
16+
const component = render(<View><Switch {...defaultProps} {...props}/></View>);
17+
const driver = SwitchDriver({
18+
wrappedComponent: component,
19+
testID
20+
});
21+
22+
return {driver};
23+
};
24+
25+
26+
it('Should fire onChange event', () => {
27+
const testId = 'switch-comp';
28+
const onChange = jest.fn();
29+
const {driver} = renderSwitch(testId, {onValueChange: onChange});
30+
driver.press();
31+
expect(onChange).toHaveBeenCalled();
32+
});
33+
34+
it('Should fire onChange event with false value when toggling off', () => {
35+
const testId = 'switch-comp';
36+
const onChange = jest.fn();
37+
const {driver} = renderSwitch(testId, {onValueChange: onChange, value: true});
38+
driver.press();
39+
expect(onChange).toHaveBeenCalledWith(false);
40+
});
41+
it('Should fire onChange event with true value when toggling on', () => {
42+
const testId = 'switch-comp';
43+
const onChange = jest.fn();
44+
const {driver} = renderSwitch(testId, {onValueChange: onChange, value: false});
45+
driver.press();
46+
expect(onChange).toHaveBeenCalledWith(true);
47+
});
48+
49+
it('Should not fire onChange when disabled', () => {
50+
const testId = 'switch-comp';
51+
const onValueChange = jest.fn();
52+
const {driver} = renderSwitch(testId, {disabled: true, onValueChange});
53+
54+
driver.press();
55+
expect(onValueChange).not.toHaveBeenCalled();
56+
});
57+
58+
it('Accessibility value should be true when checked', () => {
59+
const testId = 'switch-comp';
60+
const {driver} = renderSwitch(testId, {value: true});
61+
62+
expect(driver.getAccessibilityValue()).toBe(true);
63+
});
64+
65+
it('Accessibility value should be false when not checked', () => {
66+
const testId = 'switch-comp';
67+
const {driver} = renderSwitch(testId, {value: false});
68+
69+
expect(driver.isChecked()).toBe(false);
70+
});
71+
72+
it('Accessibility value should be checked when checked', () => {
73+
const testId = 'switch-comp';
74+
const {driver} = renderSwitch(testId, {value: true});
75+
76+
expect(driver.isChecked()).toBe(true);
77+
});
78+
79+
it('Accessibility value should be false when not checked', () => {
80+
const testId = 'switch-comp';
81+
const {driver} = renderSwitch(testId, {value: false});
82+
83+
expect(driver.getAccessibilityValue()).toBe(false);
84+
});
85+
86+
it('Should be disabled', () => {
87+
const testId = 'switch-comp';
88+
const {driver} = renderSwitch(testId, {disabled: true});
89+
90+
expect(driver.isDisabled()).toBe(true);
91+
});
92+
93+
it('Should be disabled', () => {
94+
const testId = 'switch-comp';
95+
const {driver} = renderSwitch(testId, {disabled: false});
96+
97+
expect(driver.isDisabled()).toBe(false);
98+
});
99+
100+
it('Should pass correct color when on', () => {
101+
const testId = 'switch-comp';
102+
const {driver} = renderSwitch(testId, {value: true, onColor: 'red'});
103+
104+
expect(driver.getColor()).toBe('red');
105+
});
106+
107+
it('Should pass correct color when off', () => {
108+
const testId = 'switch-comp';
109+
const {driver} = renderSwitch(testId, {value: false, offColor: 'red'});
110+
111+
expect(driver.getColor()).toBe('red');
112+
});
113+
});

src/components/switch/index.tsx

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export type SwitchProps = {
5555
*/
5656
thumbStyle?: StyleProp<ViewStyle>;
5757
style?: StyleProp<ViewStyle>;
58-
testID?: string;
58+
testID?: string;
5959
}
6060

6161
/**
@@ -65,13 +65,13 @@ export type SwitchProps = {
6565
*/
6666
class Switch extends Component<SwitchProps> {
6767
static displayName = 'Switch';
68-
68+
6969
state = {
7070
thumbPosition: new Animated.Value(this.props.value ? 1 : 0)
7171
};
7272

7373
styles = createStyles(this.props);
74-
74+
7575
componentDidUpdate(prevProps: SwitchProps) {
7676
const {value} = this.props;
7777
if (prevProps.value !== value) {
@@ -82,11 +82,14 @@ class Switch extends Component<SwitchProps> {
8282
getAccessibilityProps() {
8383
const {disabled, value} = this.props;
8484

85-
85+
8686
return {
8787
accessible: true,
8888
accessibilityRole: 'switch',
89-
accessibilityStates: disabled ? ['disabled'] : value ? ['checked'] : ['unchecked'],
89+
accessibilityState: {
90+
disabled,
91+
checked: value ? 'checked' : 'unchecked'
92+
},
9093
accessibilityValue: {text: value ? '1' : '0'}
9194
};
9295
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import {RenderAPI, fireEvent} from '@testing-library/react-native';
2+
3+
export const SwitchDriver = ({wrappedComponent, testID}: {wrappedComponent: RenderAPI; testID: string}) => {
4+
const switchComp = wrappedComponent.getByTestId(testID);
5+
6+
return {
7+
exists: () => !!switchComp,
8+
getRootElement: () => switchComp,
9+
press: () => fireEvent(switchComp, 'press'),
10+
getAccessibilityValue: () => switchComp.props.accessibilityValue.text === '1',
11+
isDisabled: () => switchComp.props.accessibilityState.disabled === true,
12+
isChecked: () => switchComp.props.accessibilityState.checked === 'checked',
13+
getColor: () => switchComp.props.style.backgroundColor
14+
};
15+
};

src/components/text/Text.driver.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@ import {fireEvent, RenderAPI} from '@testing-library/react-native';
22
import {ReactTestInstance} from 'react-test-renderer';
33
import _ from 'lodash';
44

5-
const TextDriverFactory = async ({wrapperComponent, testID}: {wrapperComponent: RenderAPI, testID: string}) => {
6-
5+
export const TextDriver = async ({wrapperComponent, testID}: {wrapperComponent: RenderAPI; testID: string}) => {
76
const text: ReactTestInstance | null = await wrapperComponent.queryByTestId(testID);
87
return {
98
exists: () => !!text,
@@ -21,11 +20,8 @@ const TextDriverFactory = async ({wrapperComponent, testID}: {wrapperComponent:
2120
if (text) {
2221
fireEvent.press(text);
2322
} else {
24-
console.warn(`TextDriverFactory: cannot click because testID:${testID} were not found`);
23+
console.warn(`TextDriver: cannot click because testID:${testID} were not found`);
2524
}
2625
}
27-
2826
};
2927
};
30-
31-
export default TextDriverFactory;

0 commit comments

Comments
 (0)