diff --git a/.eslintrc.js b/.eslintrc.js index 5eaf5de..1c28822 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -5,5 +5,5 @@ module.exports = { semi: 'off', '@typescript-eslint/semi': ['error', 'never'], }, - ignorePatterns: ['coverage/*'], + ignorePatterns: ['coverage/*', 'jest/*'], } diff --git a/jest.config.js b/jest.config.js index 7907fa3..ba14c31 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,6 +5,7 @@ module.exports = { '/jest/fileMock.js', }, collectCoverageFrom: ['src/**/*.ts*', 'src/**/*.js*'], + coveragePathIgnorePatterns: ['styles.ts'], fakeTimers: { enableGlobally: true, }, diff --git a/jest/fileMock.js b/jest/fileMock.js index e69de29..0e56c5b 100644 --- a/jest/fileMock.js +++ b/jest/fileMock.js @@ -0,0 +1 @@ +module.exports = 'test-file-stub' diff --git a/package.json b/package.json index e4b2c51..a568d75 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "DiabetorRnGui", + "name": "diabetor-gui", "version": "0.0.1", "private": true, "scripts": { diff --git a/src/__tests__/App.test.tsx b/src/__tests__/App.test.tsx index db6fbea..b2fb13c 100644 --- a/src/__tests__/App.test.tsx +++ b/src/__tests__/App.test.tsx @@ -11,14 +11,14 @@ import {it, expect} from '@jest/globals' // Note: test renderer must be required after react-native. //import renderer from 'react-test-renderer'; -import {fireEvent, render} from '@testing-library/react-native' +import {fireEvent, render, screen} from '@testing-library/react-native' it('renders correctly', () => { const SampleApp = () => - let root = render() - let punctualElement = root.getByTestId('punctual') - let basalElement = root.getByTestId('basal') + render() + let punctualElement = screen.getByTestId('punctual') + let basalElement = screen.getByTestId('basal') expect(punctualElement).toBeDefined() expect(basalElement).toBeDefined() @@ -27,9 +27,17 @@ it('renders correctly', () => { it('navigates well to punctual adaptation screen', () => { const SampleApp = () => - let root = render() - let punctualElement = root.getByTestId('punctual') + render() + let punctualElement = screen.getByTestId('punctual') fireEvent(punctualElement, 'onPress') - expect(root.getByTestId('glycemiaInput')).toBeDefined() + expect(screen.getByTestId('glycemiaInput')).toBeDefined() +}) + +it('navigates well to basal screen', () => { + const SampleApp = () => + + render() + let basalElement = screen.getByTestId('basal') + fireEvent(basalElement, 'onPress') }) diff --git a/src/components/__tests__/DbButtonComponent.test.tsx b/src/components/__tests__/DbButtonComponent.test.tsx index a5c08e1..33349db 100644 --- a/src/components/__tests__/DbButtonComponent.test.tsx +++ b/src/components/__tests__/DbButtonComponent.test.tsx @@ -9,14 +9,13 @@ import {DbButton} from '../DbButtonComponent' import {it, expect} from '@jest/globals' // Note: test renderer must be required after react-native. -import {fireEvent, render} from '@testing-library/react-native' +import {fireEvent, render, screen} from '@testing-library/react-native' it('renders correctly', async () => { const Sample = () => - let root = render() - let punctualButton = root.getByTestId('coucou') + render() + let punctualButton = screen.getByTestId('coucou') expect(punctualButton).toBeDefined() fireEvent(punctualButton, 'onPress') - //await sleep(10) }) diff --git a/src/screens/BasalAdaptationScreen.tsx b/src/screens/BasalAdaptationScreen.tsx index 668faee..296dd0e 100644 --- a/src/screens/BasalAdaptationScreen.tsx +++ b/src/screens/BasalAdaptationScreen.tsx @@ -1,64 +1,82 @@ -import React, {useState} from 'react' -import {Text, View} from 'react-native' +import React from 'react' +import {SafeAreaView, Text, View} from 'react-native' import {DbNumericTextInput} from '../components/DbNumericTextInputComponent' +import {screenStyles} from './styles' +//import {ScreenComponentType} from '@react-navigation/core/src/types' -// interface NightGlycemiaInterval { -// glycemiaBefore: number -// glycemiaAfter: number -// } - -export function BasalAdaptationScreen() { - const [glycemiasBefore, setGlycemiaBefore] = useState([]) - - const [glycemiasAfter, setGlycemiaAfter] = useState([]) +interface BasalState { + glycemiasBefore: number[] + glycemiasAfter: number[] +} - const manageGlycemiaBefore = (i: number, glycemiaStr: string) => { - setGlycemiaBefore((existing: number[]) => { - existing[i] = parseFloat(glycemiaStr) - return existing - }) +export class BasalAdaptationScreen extends React.Component<{}, BasalState> { + constructor(props: {}) { + super(props) + this.state = { + glycemiasBefore: [], + glycemiasAfter: [], + } } - const manageGlycemiaAfter = (i: number, glycemiaStr: string) => { - setGlycemiaAfter((existing: number[]) => { - existing[i] = parseFloat(glycemiaStr) - return existing - }) - } + render() { + const manageGlycemiaBefore = (i: number, glycemiaStr: string) => { + let newBefore = Array.from(this.state.glycemiasBefore) + newBefore[i] = parseFloat(glycemiaStr) - const glycemiaIntervalInputs = [] - for (let i = 0; i < 3; i++) { - glycemiaIntervalInputs.push( - - - Interval {i + 1}:{' '} - - { - manageGlycemiaBefore(i, newtText) - }} - /> - { - manageGlycemiaAfter(i, newtText) - }} - /> - , - ) - } + this.setState({ + glycemiasBefore: newBefore, + }) + } + + const manageGlycemiaAfter = (i: number, glycemiaStr: string) => { + let newAfter = Array.from(this.state.glycemiasAfter) + newAfter[i] = parseFloat(glycemiaStr) - return ( - - Basal adaptation + this.setState({ + glycemiasAfter: newAfter, + }) + } - {glycemiaIntervalInputs} + const glycemiaIntervalInputs = [] + for (let i = 0; i < 3; i++) { + glycemiaIntervalInputs.push( + + Interval {i + 1}: + { + manageGlycemiaBefore(i, newtText) + }} + /> + { + manageGlycemiaAfter(i, newtText) + }} + /> + , + ) + } - - {glycemiasBefore.join(', ')} - {glycemiasAfter.join(', ')} - - - ) + return ( + + + {glycemiaIntervalInputs} + + + {this.state.glycemiasBefore.join(', ')} + + + {this.state.glycemiasAfter.join(', ')} + + + + + ) + } } + +// interface NightGlycemiaInterval { +// glycemiaBefore: number +// glycemiaAfter: number +// } diff --git a/src/screens/HomeScreen.tsx b/src/screens/HomeScreen.tsx index 30ba9ab..6732f40 100644 --- a/src/screens/HomeScreen.tsx +++ b/src/screens/HomeScreen.tsx @@ -1,12 +1,13 @@ import React from 'react' import {SafeAreaView, ScrollView, View} from 'react-native' import {DbButton} from '../components/DbButtonComponent' +import {screenStyles} from './styles' -export function HomeScreen({navigation}: any) { +export function HomeScreen({navigation}: any): JSX.Element { return ( - + - + { + constructor(props: {}) { + super(props) - const backgroundStyle = { - backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, + this.state = { + glycemiaLevel: undefined, + acetoneLevel: undefined, + punctualAdaptationResult: null, + visibleAcetone: false, + errorMessage: '', + } + } + + formatResult = ( + punctualAdaptationResult: PuntualAdaptationResult, + ): string => { + return ` + glycemia adaptation: ${punctualAdaptationResult.glycemiaAdaptation} + acetone adaptation: ${punctualAdaptationResult.acetoneAdaptation} + ` } - const [glycemia, setGlycemia] = useState(undefined) - const [acetoneLevel, setAcetoneLevel] = useState( - undefined, - ) - const [punctualAdaptationResult, setPunctualAdaptationResult] = - useState(null) - const [visibleAcetone, setVisibleAcetone] = useState(false) - const [errorMessage, setErrorMessage] = useState('') + setGlycemiaLevel = (glycemiaLevel: number | undefined): void => { + this.setState({ + glycemiaLevel: glycemiaLevel, + }) + } - const manageNumberInput = ( + setAcetoneLevel = (acetoneLevel: number | undefined): void => { + this.setState({ + acetoneLevel: acetoneLevel, + }) + } + + manageNumberInput = ( strValue: string, - setValueFunction: (num: number | undefined) => void, - ) => { + setValueFunction: (value: number | undefined) => void, + ): void => { if (!strValue) { setValueFunction(undefined) return } - let numberValue: number = Number(strValue) //parseFloat(glycemiaStr) + let numberValue: number = Number(strValue) if (isNaN(numberValue) || !isFinite(numberValue)) { - setErrorMessage('Invalid number') + this.setErrorMessage('Invalid number') } else { setValueFunction(numberValue) - manageValidation() - setErrorMessage('') + this.manageValidation() + this.setErrorMessage('') } } - const manageValidation = () => { - if (glycemia === undefined) { - setPunctualAdaptationResult(null) + setPunctualAdaptationResult = ( + punctualAdaptationResult: PuntualAdaptationResult | null, + ): void => { + this.setState({ + punctualAdaptationResult: punctualAdaptationResult, + }) + } + + setVisibleAcetone = (visible: boolean) => { + this.setState({visibleAcetone: visible}) + } + + setErrorMessage = (errorMessage: string) => { + this.setState({ + errorMessage: errorMessage, + }) + } + + manageValidation = (): void => { + if (this.state.glycemiaLevel === undefined) { + this.setPunctualAdaptationResult(null) return } let quickInsulin = new QuickInsulin() try { let lPunctualAdaptationResult = quickInsulin.computePunctualAdaptation( - glycemia, - acetoneLevel, + this.state.glycemiaLevel, + this.state.acetoneLevel, ) - setPunctualAdaptationResult(lPunctualAdaptationResult) + this.setPunctualAdaptationResult(lPunctualAdaptationResult) } catch (e) { if (e instanceof AcetoneNeededError) { try { Vibration.vibrate() } catch (ve) {} - setVisibleAcetone(true) + this.setVisibleAcetone(true) } else { - setAcetoneLevel(0) - setVisibleAcetone(false) - setPunctualAdaptationResult(null) + this.setAcetoneLevel(undefined) + this.setVisibleAcetone(false) + this.setPunctualAdaptationResult(null) } } } - return ( - - - - -
- - Glycemia level: + render(): JSX.Element { + const isDarkMode = Appearance.getColorScheme() === 'dark' + + const backgroundStyle = { + backgroundColor: isDarkMode ? Colors.darker : Colors.lighter, + } + + return ( + + + + + Glycemia level: + + this.manageNumberInput(newText, this.setGlycemiaLevel) + } + testID="glycemiaInput" + defaultValue={ + this.state.glycemiaLevel == null + ? '' + : this.state.glycemiaLevel.toString() + } + /> + + + {this.state.visibleAcetone && ( + + Acetone level: - manageNumberInput(newText, setGlycemia) + this.manageNumberInput(newText, this.setAcetoneLevel) + } + testID="acetoneInput" + defaultValue={ + this.state.acetoneLevel == null + ? '' + : this.state.acetoneLevel.toString() } - testID="glycemiaInput" - defaultValue={glycemia == null ? '' : glycemia.toString()} /> - - {visibleAcetone && ( - - Acetone level: - - manageNumberInput(newText, setAcetoneLevel) - } - testID="acetoneInput" - defaultValue={ - acetoneLevel == null ? '' : acetoneLevel.toString() - } - /> - - )} -
-
+ )} + + -
-
- - Insulin adaptation: - - {punctualAdaptationResult - ? (punctualAdaptationResult?.totalAdaptation < 0 ? '' : '+') + - punctualAdaptationResult?.totalAdaptation - : ''} + + + {this.state.punctualAdaptationResult && ( + + + {this.state.punctualAdaptationResult?.totalAdaptation?.toString()} -
- {errorMessage && ( -
- - {errorMessage} - -
)} - {punctualAdaptationResult != null && ( -
+ {this.state.punctualAdaptationResult != null && ( + - {formatResult(punctualAdaptationResult)} + {this.formatResult(this.state.punctualAdaptationResult)} -
+
+ )} + + {this.state.errorMessage && ( + + {this.state.errorMessage} + )} -
-
-
- ) + +
+ ) + } } diff --git a/src/screens/__tests__/PunctualGlycemiaScreen.test.tsx b/src/screens/__tests__/PunctualGlycemiaScreen.test.tsx index 450c1e4..2099c76 100644 --- a/src/screens/__tests__/PunctualGlycemiaScreen.test.tsx +++ b/src/screens/__tests__/PunctualGlycemiaScreen.test.tsx @@ -42,34 +42,34 @@ it('displays results when acetone not needed and entered glycemia is valid', () it('displays acetone input when needed', () => { let SampleScreen = () => - let root = render() + render() - let glycemiaInput = root.getByTestId('glycemiaInput') - let validateButton = root.getByTestId('validateButton') + let glycemiaInput = screen.getByTestId('glycemiaInput') + let validateButton = screen.getByTestId('validateButton') expect(glycemiaInput).toBeDefined() fireEvent.changeText(glycemiaInput, '2.6') fireEvent(validateButton, 'onPress') - let acetoneInput = root.getByTestId('acetoneInput') + let acetoneInput = screen.getByTestId('acetoneInput') expect(acetoneInput).toBeDefined() }) it('displays results when glycemia + acetone inputs are needed', () => { let SampleScreen = () => - let root = render() + render() - let glycemiaInput = root.getByTestId('glycemiaInput') - let validateButton = root.getByTestId('validateButton') + let glycemiaInput = screen.getByTestId('glycemiaInput') + let validateButton = screen.getByTestId('validateButton') expect(glycemiaInput).toBeDefined() fireEvent.changeText(glycemiaInput, '2.6') fireEvent(validateButton, 'onPress') - let acetoneInput = root.getByTestId('acetoneInput') + let acetoneInput = screen.getByTestId('acetoneInput') expect(acetoneInput).toBeDefined() fireEvent.changeText(acetoneInput, '1') @@ -86,17 +86,17 @@ it('displays results when glycemia + acetone inputs are needed', () => { it('displays error message when entered glycemia is not valid', () => { let SampleScreen = () => - let root = render() + render() - let glycemiaInput = root.getByTestId('glycemiaInput') - let validateButton = root.getByTestId('validateButton') + let glycemiaInput = screen.getByTestId('glycemiaInput') + let validateButton = screen.getByTestId('validateButton') expect(glycemiaInput).toBeDefined() fireEvent.changeText(glycemiaInput, 'abc') fireEvent(validateButton, 'onPress') - let errorMessage = root.getByTestId('errorMessage') + let errorMessage = screen.getByTestId('errorMessage') expect(errorMessage.props.children).toEqual('Invalid number') }) @@ -104,10 +104,10 @@ it('displays error message when entered glycemia is not valid', () => { it('does not update anything when entered glycemia is empty', () => { let SampleScreen = () => - let root = render() + render() - let glycemiaInput = root.getByTestId('glycemiaInput') - let validateButton = root.getByTestId('validateButton') + let glycemiaInput = screen.getByTestId('glycemiaInput') + let validateButton = screen.getByTestId('validateButton') expect(glycemiaInput).toBeDefined() diff --git a/src/screens/styles.ts b/src/screens/styles.ts new file mode 100644 index 0000000..a36fdd4 --- /dev/null +++ b/src/screens/styles.ts @@ -0,0 +1,27 @@ +import {StyleSheet} from 'react-native' + +export const screenStyles = StyleSheet.create({ + intervalContainer: { + flexDirection: 'row', + }, + intervalLabel: { + color: 'white', + verticalAlign: 'middle', + }, + intervalSummary: { + color: 'white', + }, + screenBackground: { + backgroundColor: 'black', + height: '100%', + }, + buttonListContainer: { + margin: 8, + alignItems: 'center', + height: '100%', + }, + punctualAdaptationResult: { + padding: 10, + fontSize: 42, + }, +})