Created basic tests

This commit is contained in:
Zhiyuan Zheng 2020-12-28 00:59:57 +01:00
parent 0ee30de03e
commit 66385fd0f4
No known key found for this signature in database
GPG Key ID: 078A93AB607D85E0
15 changed files with 3803 additions and 125 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ web-build/
.DS_Store
.env
coverage/

View File

@ -0,0 +1,96 @@
import React from 'react'
import {
toBeDisabled,
toHaveStyle,
toHaveTextContent
} from '@testing-library/jest-native'
import { cleanup, fireEvent, render } from '@testing-library/react-native/pure'
import Button from '@components/Button'
expect.extend({ toBeDisabled, toHaveStyle, toHaveTextContent })
describe('Testing component button', () => {
afterEach(cleanup)
describe('static button', () => {
it('with text only', () => {
const onPress = jest.fn()
const { getByTestId, toJSON } = render(
<Button type='text' content='Test Button' onPress={onPress} />
)
fireEvent.press(getByTestId('base'))
expect(onPress).toHaveBeenCalled()
expect(onPress).toHaveBeenCalledTimes(1)
expect(getByTestId('text')).toHaveTextContent('Test Button')
expect(toJSON()).toMatchSnapshot()
})
it('with icon only', () => {
const onPress = jest.fn()
const { getByTestId, toJSON } = render(
<Button type='icon' content='x' onPress={onPress} />
)
fireEvent.press(getByTestId('base'))
expect(onPress).toHaveBeenCalled()
expect(onPress).toHaveBeenCalledTimes(1)
expect(toJSON()).toMatchSnapshot()
})
it('loading state', () => {
const { getByTestId, toJSON } = render(
<Button type='text' content='test' onPress={jest.fn()} loading />
)
expect(getByTestId('base')).toBeDisabled()
expect(toJSON()).toMatchSnapshot()
})
it('disabled state', () => {
const { getByTestId, toJSON } = render(
<Button type='text' content='test' onPress={jest.fn()} disabled />
)
expect(getByTestId('base')).toBeDisabled()
expect(toJSON()).toMatchSnapshot()
})
it('apply custom styling', () => {
const { getByTestId, toJSON } = render(
<Button
type='text'
content='test'
onPress={jest.fn()}
style={{ backgroundColor: 'black' }}
/>
)
expect(getByTestId('base')).toHaveStyle({ backgroundColor: 'black' })
expect(toJSON()).toMatchSnapshot()
})
})
describe('dynamic button', () => {
it('from default to loading', () => {
const onPress = jest.fn()
const { getByTestId, rerender } = render(
<Button type='text' content='test' onPress={onPress} />
)
rerender(<Button type='text' content='test' onPress={onPress} loading />)
expect(getByTestId('base')).toBeDisabled()
})
it('from default to disabled', () => {
const onPress = jest.fn()
const { getByTestId, rerender } = render(
<Button type='text' content='test' onPress={onPress} />
)
rerender(<Button type='text' content='test' onPress={onPress} disabled />)
expect(getByTestId('base')).toBeDisabled()
})
})
})

View File

@ -0,0 +1,15 @@
import React from 'react'
import { cleanup, render } from '@testing-library/react-native/pure'
import MenuHeader from '@components/Menu/Header'
describe('Testing component menu header', () => {
afterEach(cleanup)
it('with text only', () => {
const { getByText, toJSON } = render(<MenuHeader heading='test' />)
getByText('test')
expect(toJSON()).toMatchSnapshot()
})
})

View File

@ -0,0 +1,50 @@
import React from 'react'
import { toBeDisabled } from '@testing-library/jest-native'
import { cleanup, fireEvent, render } from '@testing-library/react-native'
import MenuRow from '@components/Menu/Row'
expect.extend({ toBeDisabled })
describe('Testing component menu row', () => {
afterEach(cleanup)
it('with title only', () => {
const { getByText, toJSON } = render(<MenuRow title='test title' />)
getByText('test title')
expect(toJSON()).toMatchSnapshot()
})
it('with title and content', () => {
const { getByText, toJSON } = render(
<MenuRow title='test title' content='test content' />
)
getByText('test title')
getByText('test content')
expect(toJSON()).toMatchSnapshot()
})
it('on press event', () => {
const onPress = jest.fn()
const { getByTestId, toJSON } = render(
<MenuRow title='test' onPress={onPress} />
)
fireEvent.press(getByTestId('base'))
expect(onPress).toHaveBeenCalled()
expect(onPress).toHaveBeenCalledTimes(1)
expect(toJSON()).toMatchSnapshot()
})
it('loading state', () => {
const onPress = jest.fn()
const { getByTestId, toJSON } = render(
<MenuRow title='test' loading onPress={onPress} />
)
fireEvent.press(getByTestId('base'))
expect(onPress).toHaveBeenCalledTimes(0)
expect(getByTestId('base')).toBeDisabled()
expect(toJSON()).toMatchSnapshot()
})
})

View File

@ -0,0 +1,29 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Testing component menu header with text only 1`] = `
<View
style={
Object {
"paddingBottom": 8,
"paddingLeft": 16,
"paddingRight": 16,
}
}
>
<Text
style={
Array [
Object {
"fontSize": 14,
"fontWeight": "600",
},
Object {
"color": "rgb(135, 135, 135)",
},
]
}
>
test
</Text>
</View>
`;

View File

@ -0,0 +1,273 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Testing component menu row loading state 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"height": 50,
}
}
testID="base"
>
<View
style={
Object {
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
"paddingRight": 16,
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexBasis": "70%",
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Array [
Object {
"flex": 1,
"fontSize": 16,
},
Object {
"color": "rgb(18, 18, 18)",
},
]
}
>
test
</Text>
</View>
</View>
</View>
`;
exports[`Testing component menu row on press event 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"height": 50,
}
}
testID="base"
>
<View
style={
Object {
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
"paddingRight": 16,
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexBasis": "70%",
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Array [
Object {
"flex": 1,
"fontSize": 16,
},
Object {
"color": "rgb(18, 18, 18)",
},
]
}
>
test
</Text>
</View>
</View>
</View>
`;
exports[`Testing component menu row with title and content 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"height": 50,
}
}
testID="base"
>
<View
style={
Object {
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
"paddingRight": 16,
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexBasis": "70%",
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Array [
Object {
"flex": 1,
"fontSize": 16,
},
Object {
"color": "rgb(18, 18, 18)",
},
]
}
>
test title
</Text>
</View>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexBasis": "30%",
"flexDirection": "row",
"justifyContent": "flex-end",
}
}
>
<Text
numberOfLines={1}
style={
Array [
Object {
"fontSize": 16,
},
Object {
"color": "rgb(135, 135, 135)",
"opacity": 1,
},
]
}
>
test content
</Text>
</View>
</View>
</View>
`;
exports[`Testing component menu row with title only 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Object {
"height": 50,
}
}
testID="base"
>
<View
style={
Object {
"flex": 1,
"flexDirection": "row",
"paddingLeft": 16,
"paddingRight": 16,
}
}
>
<View
style={
Object {
"alignItems": "center",
"flex": 1,
"flexBasis": "70%",
"flexDirection": "row",
}
}
>
<Text
numberOfLines={1}
style={
Array [
Object {
"flex": 1,
"fontSize": 16,
},
Object {
"color": "rgb(18, 18, 18)",
},
]
}
>
test title
</Text>
</View>
</View>
</View>
`;

View File

@ -0,0 +1,393 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Testing component button static button apply custom styling 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"alignItems": "center",
"borderRadius": 100,
"flexDirection": "row",
"justifyContent": "center",
},
Object {
"backgroundColor": "rgb(250, 250, 250)",
"borderColor": "rgb(18, 18, 18)",
"borderWidth": 1,
"paddingHorizontal": 16,
"paddingVertical": 8,
},
Object {
"backgroundColor": "black",
},
]
}
testID="base"
>
<Text
style={
Object {
"color": "rgb(18, 18, 18)",
"fontSize": 16,
"fontWeight": undefined,
"opacity": 1,
}
}
testID="text"
>
test
</Text>
</View>
`;
exports[`Testing component button static button disabled state 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"alignItems": "center",
"borderRadius": 100,
"flexDirection": "row",
"justifyContent": "center",
},
Object {
"backgroundColor": "rgb(250, 250, 250)",
"borderColor": "rgb(135, 135, 135)",
"borderWidth": 1,
"paddingHorizontal": 16,
"paddingVertical": 8,
},
undefined,
]
}
testID="base"
>
<Text
style={
Object {
"color": "rgb(135, 135, 135)",
"fontSize": 16,
"fontWeight": undefined,
"opacity": 1,
}
}
testID="text"
>
test
</Text>
</View>
`;
exports[`Testing component button static button loading state 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"alignItems": "center",
"borderRadius": 100,
"flexDirection": "row",
"justifyContent": "center",
},
Object {
"backgroundColor": "rgb(250, 250, 250)",
"borderColor": "rgb(135, 135, 135)",
"borderWidth": 1,
"paddingHorizontal": 16,
"paddingVertical": 8,
},
undefined,
]
}
testID="base"
>
<Text
style={
Object {
"color": "rgb(18, 18, 18)",
"fontSize": 16,
"fontWeight": undefined,
"opacity": 0,
}
}
testID="text"
>
test
</Text>
<View
style={
Object {
"position": "absolute",
}
}
>
<View
style={
Object {
"alignItems": "center",
"height": 16,
"justifyContent": "center",
"opacity": 1,
"transform": Array [
Object {
"rotate": "0deg",
},
],
"width": 16,
}
}
>
<View
style={
Object {
"backgroundColor": "rgb(135, 135, 135)",
"borderRadius": 2,
"height": 4,
"position": "absolute",
"transform": Array [
Object {
"rotate": "73.27536734311887deg",
},
Object {
"translateY": -6,
},
Object {
"scale": 0.7,
},
],
"width": 4,
}
}
/>
<View
style={
Object {
"backgroundColor": "rgb(135, 135, 135)",
"borderRadius": 2,
"height": 4,
"position": "absolute",
"transform": Array [
Object {
"rotate": "46.49829517703514deg",
},
Object {
"translateY": -6,
},
Object {
"scale": 0.8008696779414123,
},
],
"width": 4,
}
}
/>
<View
style={
Object {
"backgroundColor": "rgb(135, 135, 135)",
"borderRadius": 2,
"height": 4,
"position": "absolute",
"transform": Array [
Object {
"rotate": "25.743213498935145deg",
},
Object {
"translateY": -6,
},
Object {
"scale": 0.8875624559768125,
},
],
"width": 4,
}
}
/>
<View
style={
Object {
"backgroundColor": "rgb(135, 135, 135)",
"borderRadius": 2,
"height": 4,
"position": "absolute",
"transform": Array [
Object {
"rotate": "11.201058030774364deg",
},
Object {
"translateY": -6,
},
Object {
"scale": 0.9510040862404615,
},
],
"width": 4,
}
}
/>
<View
style={
Object {
"backgroundColor": "rgb(135, 135, 135)",
"borderRadius": 2,
"height": 4,
"position": "absolute",
"transform": Array [
Object {
"rotate": "2.731234791722257deg",
},
Object {
"translateY": -6,
},
Object {
"scale": 0.9881665278710133,
},
],
"width": 4,
}
}
/>
<View
style={
Object {
"backgroundColor": "rgb(135, 135, 135)",
"borderRadius": 2,
"height": 4,
"position": "absolute",
"transform": Array [
Object {
"rotate": "0deg",
},
Object {
"translateY": -6,
},
Object {
"scale": 1,
},
],
"width": 4,
}
}
/>
</View>
</View>
</View>
`;
exports[`Testing component button static button with icon only 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"alignItems": "center",
"borderRadius": 100,
"flexDirection": "row",
"justifyContent": "center",
},
Object {
"backgroundColor": "rgb(250, 250, 250)",
"borderColor": "rgb(18, 18, 18)",
"borderWidth": 1,
"paddingHorizontal": 16,
"paddingVertical": 8,
},
undefined,
]
}
testID="base"
>
<Text />
</View>
`;
exports[`Testing component button static button with text only 1`] = `
<View
accessible={true}
focusable={true}
onBlur={[Function]}
onClick={[Function]}
onFocus={[Function]}
onResponderGrant={[Function]}
onResponderMove={[Function]}
onResponderRelease={[Function]}
onResponderTerminate={[Function]}
onResponderTerminationRequest={[Function]}
onStartShouldSetResponder={[Function]}
style={
Array [
Object {
"alignItems": "center",
"borderRadius": 100,
"flexDirection": "row",
"justifyContent": "center",
},
Object {
"backgroundColor": "rgb(250, 250, 250)",
"borderColor": "rgb(18, 18, 18)",
"borderWidth": 1,
"paddingHorizontal": 16,
"paddingVertical": 8,
},
undefined,
]
}
testID="base"
>
<Text
style={
Object {
"color": "rgb(18, 18, 18)",
"fontSize": 16,
"fontWeight": undefined,
"opacity": 1,
}
}
testID="text"
>
Test Button
</Text>
</View>
`;

6
jest/react-native.js vendored Normal file
View File

@ -0,0 +1,6 @@
jest.mock('react-native/Libraries/LayoutAnimation/LayoutAnimation', () => ({
...require.requireActual(
'react-native/Libraries/LayoutAnimation/LayoutAnimation'
),
configureNext: jest.fn()
}))

14
jest/react-navigation.js vendored Normal file
View File

@ -0,0 +1,14 @@
import 'react-native-gesture-handler/jestSetup'
jest.mock('react-native-reanimated', () => {
const Reanimated = require('react-native-reanimated/mock')
// The mock for `call` immediately calls the callback which is incorrect
// So we override it with a no-op
Reanimated.default.call = () => {}
return Reanimated
})
// Silence the warning: Animated: `useNativeDriver` is not supported because the native animated module is missing
jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper')

View File

@ -5,7 +5,8 @@
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject"
"eject": "expo eject",
"test": "jest"
},
"dependencies": {
"@expo/vector-icons": "^12.0.0",
@ -66,9 +67,15 @@
"devDependencies": {
"@babel/core": "~7.9.0",
"@babel/plugin-proposal-optional-chaining": "^7.12.1",
"@babel/preset-typescript": "^7.12.7",
"@expo/config": "^3.3.15",
"@jest/types": "^26.6.2",
"@testing-library/jest-native": "^3.4.3",
"@testing-library/react-hooks": "^3.7.0",
"@testing-library/react-native": "^7.1.0",
"@types/crypto-js": "^4.0.1",
"@types/gl-react-expo": "^3.16.2",
"@types/jest": "^26.0.19",
"@types/lodash": "^4.14.164",
"@types/node": "^14.14.7",
"@types/react": "~16.9.35",
@ -76,10 +83,33 @@
"@types/react-native": "~0.63.2",
"@types/react-navigation": "^3.4.0",
"@types/react-redux": "^7.1.12",
"@types/react-test-renderer": "^17.0.0",
"@welldone-software/why-did-you-render": "^6.0.3",
"babel-plugin-module-resolver": "^4.1.0",
"chalk": "^4.1.0",
"jest": "^26.6.3",
"jest-expo": "^40.0.1",
"react-test-renderer": "^16.13.1",
"typescript": "~4.0.0"
},
"jest": {
"preset": "jest-expo",
"collectCoverage": true,
"collectCoverageFrom": [
"src /**/*.{ts,tsx}",
"!**/coverage /**",
"!**/node_modules /**",
"!**/app.config.ts",
"!**/babel.config.js",
"!**/jest.setup.ts"
],
"setupFiles": [
"<rootDir>/jest/react-native.js",
"<rootDir>/jest/react-navigation.js"
],
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|react-clone-referenced-element|@react-native-community|expo(nent)?|@expo(nent)?/.*|react-navigation|@react-navigation/.*|@unimodules/.*|unimodules|sentry-expo|native-base|@sentry/.*)"
]
},
"private": true
}

View File

@ -83,6 +83,7 @@ const Button: React.FC<Props> = ({
size={StyleConstants.Font.Size[size] * (size === 'M' ? 1 : 1.5)}
color={colorContent}
style={{ opacity: loading ? 0 : 1 }}
testID='icon'
/>
{loading && loadingSpinkit}
</>
@ -101,6 +102,7 @@ const Button: React.FC<Props> = ({
opacity: loading ? 0 : 1
}}
children={content}
testID='text'
/>
{loading && loadingSpinkit}
</>
@ -136,8 +138,6 @@ const Button: React.FC<Props> = ({
return (
<Pressable
{...(!disabled && !loading && { onPress })}
children={children}
style={[
styles.button,
{
@ -150,6 +150,10 @@ const Button: React.FC<Props> = ({
},
customStyle
]}
testID='base'
onPress={onPress}
children={children}
disabled={disabled || loading}
/>
)
}

View File

@ -20,18 +20,17 @@ export interface Props {
onPress?: () => void
}
const Core: React.FC<Props> = ({
const MenuRow: React.FC<Props> = ({
iconFront,
iconFrontColor,
iconFrontColor = 'primary',
title,
content,
iconBack,
iconBackColor,
loading = false
iconBackColor = 'secondary',
loading = false,
onPress
}) => {
const { theme } = useTheme()
iconFrontColor = iconFrontColor || 'primary'
iconBackColor = iconBackColor || 'secondary'
const loadingSpinkit = useMemo(
() => (
@ -45,64 +44,63 @@ const Core: React.FC<Props> = ({
[theme]
)
return (
<View style={styles.core}>
<View style={styles.front}>
{iconFront && (
<Feather
name={iconFront}
size={StyleConstants.Font.Size.M + 2}
color={theme[iconFrontColor]}
style={styles.iconFront}
/>
)}
<Text style={[styles.text, { color: theme.primary }]} numberOfLines={1}>
{title}
</Text>
</View>
{(content || iconBack) && (
<View style={styles.back}>
{content && content.length ? (
<>
<Text
style={[
styles.content,
{
color: theme.secondary,
opacity: !iconBack && loading ? 0 : 1
}
]}
numberOfLines={1}
>
{content}
</Text>
{loading && !iconBack && loadingSpinkit}
</>
) : null}
{iconBack && (
<>
<Feather
name={iconBack}
size={StyleConstants.Font.Size.M + 2}
color={theme[iconBackColor]}
style={[styles.iconBack, { opacity: loading ? 0 : 1 }]}
/>
{loading && loadingSpinkit}
</>
)}
</View>
)}
</View>
)
}
const MenuRow: React.FC<Props> = ({ ...props }) => {
return (
<Pressable
style={styles.base}
{...(!props.loading && props.onPress && { onPress: props.onPress })}
onPress={onPress}
disabled={loading}
testID='base'
>
<Core {...props} />
<View style={styles.core}>
<View style={styles.front}>
{iconFront && (
<Feather
name={iconFront}
size={StyleConstants.Font.Size.M + 2}
color={theme[iconFrontColor]}
style={styles.iconFront}
/>
)}
<Text
style={[styles.text, { color: theme.primary }]}
numberOfLines={1}
>
{title}
</Text>
</View>
{(content || iconBack) && (
<View style={styles.back}>
{content && content.length ? (
<>
<Text
style={[
styles.content,
{
color: theme.secondary,
opacity: !iconBack && loading ? 0 : 1
}
]}
numberOfLines={1}
>
{content}
</Text>
{loading && !iconBack && loadingSpinkit}
</>
) : null}
{iconBack && (
<>
<Feather
name={iconBack}
size={StyleConstants.Font.Size.M + 2}
color={theme[iconBackColor]}
style={[styles.iconBack, { opacity: loading ? 0 : 1 }]}
/>
{loading && loadingSpinkit}
</>
)}
</View>
)}
</View>
</Pressable>
)
}

View File

@ -104,7 +104,7 @@ const renderNode = ({
export interface Props {
content: string
size: 'M' | 'L'
size?: 'M' | 'L'
emojis?: Mastodon.Emoji[]
mentions?: Mastodon.Mention[]
showFullLink?: boolean
@ -114,7 +114,7 @@ export interface Props {
const ParseContent: React.FC<Props> = ({
content,
size,
size = 'M',
emojis,
mentions,
showFullLink = false,

View File

@ -54,7 +54,7 @@ const TimelineDefault: React.FC<Props> = ({
[]
)
return (
<Pressable style={styles.statusView} onPress={onPress}>
<Pressable style={styles.statusView} onPress={onPress} disabled={true}>
{item.reblog ? (
<TimelineActioned action='reblog' account={item.account} />
) : pinnedLength && index < pinnedLength ? (

2883
yarn.lock

File diff suppressed because it is too large Load Diff