Skip to content

Commit

Permalink
breaking: Migrate codebase to typescript (#101)
Browse files Browse the repository at this point in the history
Co-authored-by: Maciej Jastrzębski <[email protected]>
  • Loading branch information
Ne3l and mdjastrzebski authored Sep 30, 2022
1 parent d38fc80 commit 0896cd2
Show file tree
Hide file tree
Showing 26 changed files with 223 additions and 135 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ jobs:
- name: ▶️ Run linter
run: yarn lint

- name: ▶️ Run typecheck
run: yarn typecheck

- name: ▶️ Run tests with coverage
run: yarn test:coverage

Expand Down
5 changes: 3 additions & 2 deletions extend-expect.d.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ImageStyle, TextStyle, ViewStyle } from 'react-native';
import type { ReactTestInstance } from 'react-test-renderer';

declare global {
Expand All @@ -7,10 +8,10 @@ declare global {
toBeDisabled(): R;
toContainElement(element: ReactTestInstance | null): R;
toBeEmptyElement(): R;
toHaveProp(attr: string, value?: any): R;
toHaveProp(attr: string, value?: unknown): R;
toHaveTextContent(text: string | RegExp, options?: { normalizeWhitespace: boolean }): R;
toBeEnabled(): R;
toHaveStyle(style: object[] | object): R;
toHaveStyle(style: StyleProp<ViewStyle | TextStyle | ImageStyle>): R;

/** @deprecated This function has been renamed to `toBeEmptyElement`. */
toBeEmpty(): R;
Expand Down
6 changes: 2 additions & 4 deletions jest.config.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
const ignores = ['/node_modules/', '/__tests__/helpers/', '__mocks__'];

module.exports = {
preset: '@testing-library/react-native',
testMatch: ['**/__tests__/**/*.+(js|jsx|ts|tsx)'],
testPathIgnorePatterns: [...ignores],
setupFilesAfterEnv: ['<rootDir>/setup-tests.js'],
setupFilesAfterEnv: ['<rootDir>/setup-tests.ts'],
snapshotSerializers: ['@relmify/jest-serializer-strip-ansi/always'],
collectCoverageFrom: ['src/**/*.+(js|jsx|ts|tsx)'],
testPathIgnorePatterns: ['/node_modules/', '/__tests__/helpers/', '/dist/', '__mocks__'],
};
21 changes: 15 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
"readme:toc": "doctoc README.md --maxlevel 3 --title '## Table of Contents'",
"test": "jest --colors",
"lint": "eslint .",
"prepublishOnly": "rm -rf dist; babel src --out-dir dist --ignore 'src/__tests__/*'",
"prepublishOnly": "rm -rf dist && tsc -p tsconfig.prod.json",
"semantic-release": "semantic-release",
"test:coverage": "jest --coverage --colors",
"test:watch": "jest --watch --coverage"
"test:watch": "jest --watch --coverage",
"typecheck": "tsc -noEmit"
},
"files": [
"dist",
Expand All @@ -32,7 +33,7 @@
"chalk": "^4.1.2",
"jest-diff": "^29.0.1",
"jest-matcher-utils": "^29.0.1",
"pretty-format": "^29.0.1",
"pretty-format": "^29.0.3",
"redent": "^3.0.0"
},
"devDependencies": {
Expand All @@ -42,18 +43,23 @@
"@callstack/eslint-config": "^13.0.1",
"@relmify/jest-serializer-strip-ansi": "^1.0.2",
"@testing-library/react-native": "^11.0.0",
"@types/jest": "^29.0.1",
"@types/react": "^18.0.19",
"@types/react-native": "^0.69.8",
"@types/react-test-renderer": "^18.0.0",
"commitizen": "^4.2.5",
"cz-conventional-changelog": "^3.3.0",
"eslint": "^8.21.0",
"husky": "^8.0.1",
"jest": "^29.0.1",
"metro-react-native-babel-preset": "^0.70.3",
"metro-react-native-babel-preset": "^0.72.0",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"react": "18.0.0",
"react-native": "^0.69.4",
"react-test-renderer": "18.0.0",
"semantic-release": "^19.0.3"
"semantic-release": "^19.0.3",
"typescript": "^4.8.3"
},
"peerDependencies": {
"react": ">=16.0.0",
Expand All @@ -79,11 +85,14 @@
"react-native-a11y/has-valid-accessibility-descriptors": "off",
"react-native-a11y/has-accessibility-hint": "off",
"react-native-a11y/has-valid-accessibility-ignores-invert-colors": "off",
"react-native-a11y/has-valid-accessibility-value": "off"
"react-native-a11y/has-valid-accessibility-value": "off",
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/no-explicit-any": "error"
}
},
"eslintIgnore": [
"node_modules/",
"dist/",
"lib/"
],
"release": {
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ describe('.toBeDisabled', () => {
Object.entries(ALLOWED_COMPONENTS).forEach(([name, Component]) => {
test(`handle disabled prop for element ${name}`, () => {
const { queryByTestId } = render(
//@ts-expect-error JSX element type 'Component' does not have any construct or call signatures.ts(2604)
<Component disabled testID={name}>
<TextInput />
</Component>,
Expand All @@ -38,6 +39,7 @@ describe('.toBeDisabled', () => {
Object.entries(ALLOWED_COMPONENTS).forEach(([name, Component]) => {
test(`handle disabled in accessibilityState for element ${name}`, () => {
const { queryByTestId } = render(
//@ts-expect-error JSX element type 'Component' does not have any construct or call signatures.ts(2604)
<Component accessibilityState={{ disabled: true }} testID={name}>
<TextInput />
</Component>,
Expand All @@ -53,6 +55,7 @@ describe('.toBeEnabled', () => {
Object.entries(ALLOWED_COMPONENTS).forEach(([name, Component]) => {
test(`handle disabled prop for element ${name} when undefined`, () => {
const { queryByTestId } = render(
//@ts-expect-error JSX element type 'Component' does not have any construct or call signatures.ts(2604)
<Component testID={name}>
<TextInput />
</Component>,
Expand All @@ -66,6 +69,7 @@ describe('.toBeEnabled', () => {
Object.entries(ALLOWED_COMPONENTS).forEach(([name, Component]) => {
test(`handle disabled in accessibilityState for element ${name} when false`, () => {
const { queryByTestId } = render(
//@ts-expect-error JSX element type 'Component' does not have any construct or call signatures.ts(2604)
<Component accessibilityState={{ disabled: false }} testID={name}>
<TextInput />
</Component>,
Expand Down Expand Up @@ -103,14 +107,14 @@ describe('for .toBeEnabled/Disabled Button', () => {
});

test('Errors when matcher misses', () => {
const { queryByTestId, queryByTitle } = render(
const { queryByTestId, queryByText } = render(
<View testID="view">
<Button testID="enabled" title="enabled" />
<Button disabled testID="disabled" title="disabled" />
</View>,
);

expect(() => expect(queryByTestId('enabled')).toBeDisabled()).toThrow();
expect(() => expect(queryByTitle('disabled')).toBeEnabled()).toThrow();
expect(() => expect(queryByText('disabled')).toBeEnabled()).toThrow();
});
});
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,21 @@ test('.toContainElement negative test cases', () => {
expect(() => expect(nonExistantElement).toContainElement(grandparent)).toThrow();
expect(() => expect(grandparent).toContainElement(nonExistantElement)).toThrow();
expect(() => expect(nonExistantElement).toContainElement(nonExistantElement)).toThrow();

// @ts-expect-error intentionally passing incorrect type
expect(() => expect(nonExistantElement).toContainElement(fakeElement)).toThrow();
expect(() => expect(fakeElement).toContainElement(nonExistantElement)).toThrow();
expect(() => expect(fakeElement).not.toContainElement(nonExistantElement)).toThrow();
expect(() => expect(fakeElement).toContainElement(grandparent)).toThrow();

// @ts-expect-error intentionally passing incorrect type
expect(() => expect(grandparent).toContainElement(fakeElement)).toThrow();

// @ts-expect-error intentionally passing incorrect type
expect(() => expect(fakeElement).toContainElement(fakeElement)).toThrow();
expect(() => expect(grandparent).not.toContainElement(child)).toThrow();
expect(() => expect(grandparent).not.toContainElement(textElement)).toThrow();

// @ts-expect-error intentionally passing incorrect type
expect(() => expect(grandparent).not.toContainElement(undefined)).toThrow();
});
10 changes: 5 additions & 5 deletions src/__tests__/to-have-prop.js → src/__tests__/to-have-prop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,20 @@ import { render } from '@testing-library/react-native';

test('.toHaveProp', () => {
const { queryByTestId } = render(
<View accessibilityLabel={null} testID="view">
<Text allowFontScaling={false} testID="text" editable={false}>
<View style={null} testID="view">
<Text allowFontScaling={false} testID="text" ellipsizeMode="head">
text
</Text>
<Button disabled testID="button" title="ok" />
</View>,
);

expect(queryByTestId('button')).toHaveProp('accessibilityState', { disabled: true });
expect(queryByTestId('text')).toHaveProp('editable', false);
expect(queryByTestId('text')).toHaveProp('ellipsizeMode', 'head');
expect(queryByTestId('text')).toHaveProp('allowFontScaling', false);

expect(queryByTestId('button')).not.toHaveProp('accessibilityStates');
expect(queryByTestId('button')).not.toHaveProp('editable', false);
expect(queryByTestId('button')).not.toHaveProp('ellipsizeMode', undefined);
expect(queryByTestId('button')).not.toHaveProp('allowFontScaling', false);
expect(queryByTestId('text')).not.toHaveProp('style');

Expand All @@ -30,5 +30,5 @@ test('.toHaveProp', () => {
expect(queryByTestId('text')).toHaveProp('allowFontScaling', 'wrongValue'),
).toThrow();

expect(queryByTestId('view')).toHaveProp('accessibilityLabel', null);
expect(queryByTestId('view')).toHaveProp('style', null);
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { render } from '@testing-library/react-native';

describe('.toHaveStyle', () => {
test('handles positive test cases', () => {
const styles = StyleSheet.create({ container: { color: 'white' } });
const styles = StyleSheet.create({ container: { borderBottomColor: 'white' } });
const { getByTestId } = render(
<View
testID="container"
Expand All @@ -29,7 +29,7 @@ describe('.toHaveStyle', () => {
expect(container).toHaveStyle([{ backgroundColor: 'blue' }, { height: '100%' }]);
expect(container).toHaveStyle({ backgroundColor: 'blue' });
expect(container).toHaveStyle({ height: '100%' });
expect(container).toHaveStyle({ color: 'white' });
expect(container).toHaveStyle({ borderBottomColor: 'white' });
expect(container).toHaveStyle({ width: '50%' });
expect(container).toHaveStyle([[{ width: '50%' }]]);
expect(container).toHaveStyle({ transform: [{ scale: 2 }, { rotate: '45deg' }] });
Expand All @@ -41,7 +41,7 @@ describe('.toHaveStyle', () => {
testID="container"
style={{
backgroundColor: 'blue',
color: 'black',
borderBottomColor: 'black',
height: '100%',
transform: [{ scale: 2 }, { rotate: '45deg' }],
}}
Expand All @@ -54,8 +54,8 @@ describe('.toHaveStyle', () => {
expect(() =>
expect(container).toHaveStyle({ backgroundColor: 'blue', transform: [{ scale: 1 }] }),
).toThrowErrorMatchingSnapshot();
expect(() => expect(container).toHaveStyle({ fontWeight: 'bold' })).toThrow();
expect(() => expect(container).not.toHaveStyle({ color: 'black' })).toThrow();
expect(container).not.toHaveStyle({ fontWeight: 'bold' });
expect(container).not.toHaveStyle({ color: 'black' });
expect(container).not.toHaveStyle({ transform: [{ rotate: '45deg' }, { scale: 2 }] });
expect(container).not.toHaveStyle({ transform: [{ rotate: '45deg' }] });
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ describe('.toHaveTextContent', () => {
const { queryByTestId } = render(<Text testID="count-value">2</Text>);

expect(queryByTestId('count-value')).toHaveTextContent('2');
expect(queryByTestId('count-value')).toHaveTextContent(2);
expect(queryByTestId('count-value')).toHaveTextContent(/2/);
expect(queryByTestId('count-value')).not.toHaveTextContent('21');
});
Expand Down Expand Up @@ -73,7 +72,7 @@ describe('.toHaveTextContent', () => {
});

test('can handle multiple levels with no explicit children prop', () => {
const NoChildren = ({ text }) => <Text>{text}</Text>;
const NoChildren = ({ text }: { text: string }) => <Text>{text}</Text>;
const answer = 'Answer';
const { container } = render(
<View>
Expand Down
36 changes: 0 additions & 36 deletions src/__tests__/utils.js

This file was deleted.

39 changes: 39 additions & 0 deletions src/__tests__/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { checkReactElement, isEmpty } from '../utils';

describe('checkReactElement', () => {
test('it does not throw an error for valid native primitives', () => {
expect(() => {
// @ts-expect-error Argument of type '{ type: "text"; }' is not assignable to parameter of type 'ReactTestInstance'. Type '{ type: "text"; }' is missing the following properties from type 'ReactTestInstance': instance, props, parent, children, and 6 more.ts(2345)
checkReactElement({ type: 'Text' }, () => {}, null);
}).not.toThrow();
});

test('ReactTestInstance does not throw', () => {
expect(() => {
// @ts-expect-error Argument of type '{ _fiber: {}; }' is not assignable to parameter of type 'ReactTestInstance'. Object literal may only specify known properties, and '_fiber' does not exist in type 'ReactTestInstance'.ts(2345)
checkReactElement({ _fiber: {} }, () => {}, null);
}).not.toThrow();
});

test('it does throw an error for invalid native primitives', () => {
expect(() => {
// @ts-expect-error Argument of type '{ type: "button"; }' is not assignable to parameter of type 'ReactTestInstance'. Type '{ type: "button"; }' is missing the following properties from type 'ReactTestInstance': instance, props, parent, children, and 6 more.ts(2345)
checkReactElement({ type: 'Button' }, () => {}, null);
}).toThrow();
});
});

test('isEmpty', () => {
expect(isEmpty(null)).toEqual(true);
expect(isEmpty(undefined)).toEqual(true);
expect(isEmpty('')).toEqual(true);
expect(isEmpty(' ')).toEqual(false);
expect(isEmpty([])).toEqual(true);
expect(isEmpty([[]])).toEqual(false);
expect(isEmpty({})).toEqual(true);
expect(isEmpty({ x: 0 })).toEqual(false);
expect(isEmpty(0)).toEqual(true);
expect(isEmpty(1)).toEqual(false);
expect(isEmpty(NaN)).toEqual(true);
expect(isEmpty([''])).toEqual(false);
});
3 changes: 0 additions & 3 deletions src/extend-expect.js

This file was deleted.

14 changes: 7 additions & 7 deletions src/index.js → src/extend-expect.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { toBeDisabled, toBeEnabled } from './to-be-disabled';
import { toBeEmptyElement, toBeEmpty } from './to-be-empty-element';
import { toHaveProp } from './to-have-prop';
import { toHaveTextContent } from './to-have-text-content';
import { toContainElement } from './to-contain-element';
import { toHaveProp } from './to-have-prop';
import { toHaveStyle } from './to-have-style';
import { toHaveTextContent } from './to-have-text-content';

export {
expect.extend({
toBeDisabled,
toContainElement,
toBeEnabled,
toBeEmptyElement,
toBeEmpty, // Deprecated
toContainElement,
toHaveProp,
toHaveTextContent,
toBeEnabled,
toHaveStyle,
};
toHaveTextContent,
});
Loading

0 comments on commit 0896cd2

Please sign in to comment.