diff --git a/packages/app/components/__tests__/Children.test.js b/packages/app/components/__tests__/Children.test.js new file mode 100644 index 000000000..488aa861d --- /dev/null +++ b/packages/app/components/__tests__/Children.test.js @@ -0,0 +1,186 @@ +import { + useChildList, + useCalendar, + useClassmates, + useNews, + useNotifications, + useSchedule, +} from '@skolplattformen/api-hooks' +import { render } from '../../utils/testHelpers' +import React from 'react' +import { Children } from '../children.component.js' + +jest.mock('@skolplattformen/api-hooks') + +const setup = () => { + return render() +} + +beforeEach(() => { + useCalendar.mockReturnValueOnce({ data: [], status: 'loaded' }) + useNotifications.mockReturnValueOnce({ data: [], status: 'loaded' }) + useNews.mockReturnValueOnce({ data: [], status: 'loaded' }) + useClassmates.mockReturnValueOnce({ data: [], status: 'loaded' }) + useSchedule.mockReturnValueOnce({ data: [], status: 'loaded' }) +}) + +test('renders loading state', () => { + useChildList.mockImplementationOnce(() => ({ + data: [], + status: 'loading', + })) + + const screen = setup() + + expect(screen.getByText(/laddar/i)).toBeTruthy() +}) + +test('renders empty state message', () => { + useChildList.mockImplementationOnce(() => ({ + data: [], + status: 'loaded', + })) + + const screen = setup() + + expect( + screen.getByText( + 'Det finns inga barn registrerade för ditt personnummer i Stockholms Stad' + ) + ).toBeTruthy() +}) + +test('renders child in preschool', () => { + useChildList.mockImplementationOnce(() => ({ + data: [ + { + name: 'Test Testsson', + status: 'F', + }, + ], + status: 'loaded', + })) + + const screen = setup() + + expect(screen.getByText('Test Testsson')).toBeTruthy() + expect(screen.getByText('Förskoleklass')).toBeTruthy() +}) + +test('renders child in elementary school', () => { + useChildList.mockImplementationOnce(() => ({ + data: [ + { + name: 'Test Testsson', + status: 'GR', + }, + ], + status: 'loaded', + })) + + const screen = setup() + + expect(screen.getByText('Test Testsson')).toBeTruthy() + expect(screen.getByText('Grundskolan')).toBeTruthy() +}) + +test('renders child in high school', () => { + useChildList.mockImplementationOnce(() => ({ + data: [ + { + name: 'Test Testsson', + status: 'G', + }, + ], + status: 'loaded', + })) + + const screen = setup() + + expect(screen.getByText('Test Testsson')).toBeTruthy() + expect(screen.getByText('Gymnasiet')).toBeTruthy() +}) + +test('renders multiple children', () => { + useChildList.mockImplementationOnce(() => ({ + data: [ + { + name: 'Storasyster Testsson', + status: 'G', + }, + { + name: 'Lillebror Testsson', + status: 'GR', + }, + ], + status: 'loaded', + })) + + const screen = setup() + + expect(screen.getByText('Storasyster Testsson')).toBeTruthy() + expect(screen.getByText('Gymnasiet')).toBeTruthy() + + expect(screen.getByText('Lillebror Testsson')).toBeTruthy() + expect(screen.getByText('Grundskolan')).toBeTruthy() +}) + +test('displays class name if child has class mates', () => { + useClassmates.mockReset() + useClassmates.mockReturnValueOnce({ + data: [ + { + className: '8C', + }, + ], + status: 'loaded', + }) + useChildList.mockImplementationOnce(() => ({ + data: [ + { + name: 'Test Testsson', + status: 'G', + }, + ], + status: 'loaded', + })) + + const screen = setup() + + expect(screen.getByText('Test Testsson')).toBeTruthy() + expect(screen.getByText('8C')).toBeTruthy() + expect(screen.queryByText('Gymnasiet')).toBeFalsy() +}) + +test('removes any parenthesis from name', () => { + useChildList.mockImplementationOnce(() => ({ + data: [ + { + name: 'Test Testsson(något annat)', + status: 'G', + }, + ], + status: 'loaded', + })) + + const screen = setup() + + expect(screen.getByText('Test Testsson')).toBeTruthy() +}) + +test('handles multiple statuses for a child', () => { + useChildList.mockImplementationOnce(() => ({ + data: [ + { + name: 'Test Testsson(något annat)', + status: 'G;GR;F', + }, + ], + status: 'loaded', + })) + + const screen = setup() + + expect(screen.getByText('Test Testsson')).toBeTruthy() + expect(screen.getByText('Gymnasiet, Grundskolan, Förskoleklass')).toBeTruthy() +}) diff --git a/packages/app/components/__tests__/Notification.test.js b/packages/app/components/__tests__/Notification.test.js index e3d3c4fc1..69a804dd8 100644 --- a/packages/app/components/__tests__/Notification.test.js +++ b/packages/app/components/__tests__/Notification.test.js @@ -1,8 +1,6 @@ import React from 'react' -import { render } from '@testing-library/react-native' +import { render } from '../../utils/testHelpers' import { Notification } from '../notification.component.js' -import { ApplicationProvider } from '@ui-kitten/components' -import * as eva from '@eva-design/eva' import MockDate from 'mockdate' const defaultItem = { @@ -17,11 +15,7 @@ const setup = (customProps = {}) => { ...customProps, } - return render( - - - - ) + return render() } beforeEach(() => { diff --git a/packages/app/components/childListItem.component.js b/packages/app/components/childListItem.component.js index a15e0742e..b3418546b 100644 --- a/packages/app/components/childListItem.component.js +++ b/packages/app/components/childListItem.component.js @@ -134,7 +134,7 @@ export const ChildListItem = ({ navigation, child, color }) => { return ( { const styles = StyleSheet.create({ card: { - flex: 1, - margin: 10, + marginBottom: 20, }, itemFooter: { flexDirection: 'row', diff --git a/packages/app/components/children.component.js b/packages/app/components/children.component.js index d627d1ce6..c9865aacc 100644 --- a/packages/app/components/children.component.js +++ b/packages/app/components/children.component.js @@ -3,17 +3,21 @@ import { Divider, Icon, Layout, + List, Spinner, Text, TopNavigation, TopNavigationAction, } from '@ui-kitten/components' import React from 'react' -import { Image, SafeAreaView, StyleSheet, View } from 'react-native' +import { Dimensions, Image, SafeAreaView, StyleSheet, View } from 'react-native' import { ChildListItem } from './childListItem.component' + +const { width } = Dimensions.get('window') const colors = ['primary', 'success', 'info', 'warning', 'danger'] const BackIcon = (props) => + export const Children = ({ navigation }) => { const { data: childList, status } = useChildList() const navigateBack = () => { @@ -32,27 +36,46 @@ export const Children = ({ navigation }) => { accessoryLeft={BackAction} /> - + {status === 'loaded' ? ( - - {childList.map((child, i) => ( - - ))} + + + Inga barn + + Det finns inga barn registrerade för ditt personnummer i + Stockholms Stad + + + + } + renderItem={({ item: child, index }) => { + return ( + + ) + }} + /> ) : ( - + - + Laddar... @@ -64,6 +87,9 @@ export const Children = ({ navigation }) => { } const styles = StyleSheet.create({ + fullFlex: { + flex: 1, + }, topContainer: { flex: 1, backgroundColor: '#fff', @@ -73,8 +99,42 @@ const styles = StyleSheet.create({ justifyContent: 'center', alignItems: 'center', }, - childList: { + loadingImage: { + height: (width / 16) * 9, + width: width, + }, + loadingMessage: { + alignItems: 'center', + flexDirection: 'row', + marginTop: 8, + }, + loadingText: { + marginLeft: 20, + }, + childListWrap: { flex: 1, justifyContent: 'flex-start', }, + childList: { + flex: 1, + padding: 20, + }, + emptyState: { + backgroundColor: '#fff', + flex: 1, + justifyContent: 'center', + alignItems: 'center', + paddingHorizontal: 20, + }, + emptyStateDescription: { + lineHeight: 21, + marginTop: 8, + textAlign: 'center', + }, + emptyStateImage: { + // 80% size and 16:9 aspect ratio + height: ((width * 0.8) / 16) * 9, + marginTop: 20, + width: width * 0.8, + }, }) diff --git a/packages/app/package.json b/packages/app/package.json index 919981a0e..eda663918 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -7,7 +7,7 @@ "ios": "react-native-fix-image && react-native run-ios", "pod": "npx pod-install", "start": "react-native start", - "test": "jest --passWithNoTests", + "test": "jest", "lint": "eslint ." }, "dependencies": { @@ -68,7 +68,7 @@ "jest": { "preset": "react-native", "setupFilesAfterEnv": [ - "react-native-gesture-handler/jestSetup", + "/setupTests.js", "@testing-library/jest-native/extend-expect" ], "transformIgnorePatterns": [ diff --git a/packages/app/setupTests.js b/packages/app/setupTests.js new file mode 100644 index 000000000..f16555f23 --- /dev/null +++ b/packages/app/setupTests.js @@ -0,0 +1,4 @@ +import 'react-native-gesture-handler/jestSetup' + +// Silence useNativeDriver error +jest.mock('react-native/Libraries/Animated/src/NativeAnimatedHelper') diff --git a/packages/app/utils/testHelpers.js b/packages/app/utils/testHelpers.js new file mode 100644 index 000000000..b60d38b45 --- /dev/null +++ b/packages/app/utils/testHelpers.js @@ -0,0 +1,16 @@ +import * as eva from '@eva-design/eva' +import { render as rtlRender } from '@testing-library/react-native' +import { ApplicationProvider, IconRegistry } from '@ui-kitten/components' +import { EvaIconsPack } from '@ui-kitten/eva-icons' +import React from 'react' + +export const render = (children) => { + return rtlRender( + <> + + + {children} + + + ) +}