From f2d032db9e712c39bd0ee033a2dabff00ca006f1 Mon Sep 17 00:00:00 2001 From: Luiz Baldi Date: Tue, 10 Nov 2020 10:15:51 -0300 Subject: [PATCH] test: write unit tests for existing components --- .eslintrc.js | 2 +- example/babel.config.js | 2 +- example/webpack.config.js | 2 +- package.json | 1 + src/AppBar/AppBar.spec.tsx | 29 ++++++++++++++++ src/AppBar/AppBar.tsx | 6 +++- src/Button/Button.spec.tsx | 68 ++++++++++++++++++++++++++++++++++++++ src/Button/Button.tsx | 9 +++-- src/Panel/Panel.spec.tsx | 29 ++++++++++++++++ src/Panel/Panel.tsx | 7 +++- src/Text/Text.spec.tsx | 20 +++++++++++ src/Text/Text.tsx | 2 +- 12 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 src/AppBar/AppBar.spec.tsx create mode 100644 src/Button/Button.spec.tsx create mode 100644 src/Panel/Panel.spec.tsx create mode 100644 src/Text/Text.spec.tsx diff --git a/.eslintrc.js b/.eslintrc.js index 1bda565..de785b9 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -2,7 +2,7 @@ module.exports = { extends: [ 'airbnb', 'plugin:prettier/recommended', - 'prettier/react' + 'prettier/react', 'plugin:jest/recommended' ], parser: '@typescript-eslint/parser', diff --git a/example/babel.config.js b/example/babel.config.js index 8168277..d1c579d 100644 --- a/example/babel.config.js +++ b/example/babel.config.js @@ -1,7 +1,7 @@ const path = require('path'); const pak = require('../package.json'); -module.exports = function (api) { +module.exports = function babelConfig(api) { api.cache(true); return { diff --git a/example/webpack.config.js b/example/webpack.config.js index 10b5069..2588c38 100644 --- a/example/webpack.config.js +++ b/example/webpack.config.js @@ -7,7 +7,7 @@ const root = path.resolve(__dirname, '..'); /* eslint-disable-next-line */ const node_modules = path.join(__dirname, 'node_modules'); -module.exports = async function (env, argv) { +module.exports = async function webpackConfig(env, argv) { const config = await createExpoWebpackConfigAsync(env, argv); config.module.rules.push({ diff --git a/package.json b/package.json index d10a004..37b0f19 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ ], "scripts": { "test": "jest", + "test:watch": "jest --watch", "typescript": "tsc --noEmit", "lint": "eslint \"**/*.{js,ts,tsx}\"", "prepare": "bob build", diff --git a/src/AppBar/AppBar.spec.tsx b/src/AppBar/AppBar.spec.tsx new file mode 100644 index 0000000..b7741d0 --- /dev/null +++ b/src/AppBar/AppBar.spec.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { render } from '@testing-library/react-native'; + +import { testId } from './AppBar'; +import { AppBar, Text } from '..'; + +describe('', () => { + it('should render children', () => { + const { getByTestId } = render( + + This is an AppBar + + ); + + expect(getByTestId(testId)).toHaveTextContent('This is an AppBar'); + }); + + it('should render custom styles', () => { + const style = { marginTop: 42 }; + + const { getByTestId } = render( + + This is an AppBar + + ); + + expect(getByTestId(testId)).toHaveStyle(style); + }); +}); diff --git a/src/AppBar/AppBar.tsx b/src/AppBar/AppBar.tsx index 46865a9..157c2b4 100644 --- a/src/AppBar/AppBar.tsx +++ b/src/AppBar/AppBar.tsx @@ -4,6 +4,8 @@ import { StyleSheet, View } from 'react-native'; import { original as theme } from '../common/themes'; import { border } from '../common/styles'; +export const testId = 'app-bar'; + type Props = { children: React.ReactNode; style?: Object; @@ -11,7 +13,9 @@ type Props = { const AppBar = ({ children, style = {} }: Props) => { return ( - {children} + + {children} + ); }; diff --git a/src/Button/Button.spec.tsx b/src/Button/Button.spec.tsx new file mode 100644 index 0000000..4dc1187 --- /dev/null +++ b/src/Button/Button.spec.tsx @@ -0,0 +1,68 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react-native'; + +import { blockSizes, ButtonSizes, testId } from './Button'; +import { Button, Text } from '..'; + +const noop = () => {}; + +describe(' + ); + + expect(getByText('Potato')).toBeTruthy(); + }); + + it('should fire press', () => { + const onButtonPress = jest.fn(); + + const { getByTestId } = render( + + ); + + fireEvent(getByTestId(testId), 'press'); + expect(onButtonPress).toHaveBeenCalled(); + }); + + it('should handle square sizes', () => { + const sizes: ButtonSizes[] = ['sm', 'md', 'lg']; + + sizes.forEach(size => { + const { getByTestId } = render( + + ); + + expect(getByTestId(testId)).toHaveStyle({ width: blockSizes[size] }); + }); + }); + + it('should render custom styles', () => { + const style = { backgroundColor: 'papayawhip' }; + + const { getByTestId } = render( + + ); + + expect(getByTestId(testId)).toHaveStyle(style); + }); + + it('should render a full width button', () => { + const { getByTestId } = render( + + ); + + expect(getByTestId(testId)).toHaveStyle({ width: '100%' }); + }); +}); diff --git a/src/Button/Button.tsx b/src/Button/Button.tsx index 2412f31..ef62b07 100644 --- a/src/Button/Button.tsx +++ b/src/Button/Button.tsx @@ -4,11 +4,15 @@ import { StyleSheet, TouchableHighlight, Text } from 'react-native'; import { original as theme } from '../common/themes'; import { border, box } from '../common/styles'; +export const testId = 'button'; + +export type ButtonSizes = 'sm' | 'md' | 'lg'; + type Props = { children: React.ReactNode; onPress: () => void; variant?: 'menu' | 'flat' | 'default'; - size?: 'sm' | 'md' | 'lg'; + size?: ButtonSizes; style?: Object; disabled?: boolean; fullWidth?: boolean; @@ -62,6 +66,7 @@ const Button = ({ onHideUnderlay={() => setIsPressed(false)} onShowUnderlay={() => setIsPressed(true)} underlayColor={theme.material} + testID={testId} > {children} @@ -86,7 +91,7 @@ const styles = StyleSheet.create({ flat: box.flat }); -const blockSizes = { +export const blockSizes = { sm: 27, md: 35, lg: 43 diff --git a/src/Panel/Panel.spec.tsx b/src/Panel/Panel.spec.tsx new file mode 100644 index 0000000..cb83e10 --- /dev/null +++ b/src/Panel/Panel.spec.tsx @@ -0,0 +1,29 @@ +import React from 'react'; +import { render } from '@testing-library/react-native'; + +import { testId } from './Panel'; +import { Panel, Text } from '..'; + +describe('', () => { + it('should render children', () => { + const { getByTestId } = render( + + Banana dance + + ); + + expect(getByTestId(testId)).toHaveTextContent('Banana dance'); + }); + + it('should render custom styles', () => { + const style = { backgroundColor: 'teal' }; + + const { getByTestId } = render( + + Panel + + ); + + expect(getByTestId(testId)).toHaveStyle(style); + }); +}); diff --git a/src/Panel/Panel.tsx b/src/Panel/Panel.tsx index 1336458..c840b5c 100644 --- a/src/Panel/Panel.tsx +++ b/src/Panel/Panel.tsx @@ -4,6 +4,8 @@ import { StyleSheet, View } from 'react-native'; import { original as theme } from '../common/themes'; import { border } from '../common/styles'; +export const testId = 'panel'; + type Props = { children: React.ReactNode; variant?: 'default' | 'well' | 'outside'; @@ -12,7 +14,10 @@ type Props = { const Panel = ({ children, variant = 'default', style = {} }: Props) => { return ( - + {children} ); diff --git a/src/Text/Text.spec.tsx b/src/Text/Text.spec.tsx new file mode 100644 index 0000000..8cb33b9 --- /dev/null +++ b/src/Text/Text.spec.tsx @@ -0,0 +1,20 @@ +import React from 'react'; +import { render } from '@testing-library/react-native'; + +import { Text } from '..'; + +describe('', () => { + it('should render children', () => { + const { getByText } = render(Potato); + + expect(getByText('Potato')).toBeTruthy(); + }); + + it('should render custom styles', () => { + const style = { color: 'papayawhip' }; + + const { getByText } = render(Potato); + + expect(getByText('Potato')).toHaveStyle(style); + }); +}); diff --git a/src/Text/Text.tsx b/src/Text/Text.tsx index 02e7fcc..5c19028 100644 --- a/src/Text/Text.tsx +++ b/src/Text/Text.tsx @@ -4,7 +4,7 @@ import { StyleSheet, Text as RNText } from 'react-native'; import { original as theme } from '../common/themes'; type Props = { - children: React.ReactNode; + children: string; style?: Object; };