Add basic working unit tests
This commit is contained in:
parent
cc97c760bb
commit
6e75614d10
6
App.tsx
6
App.tsx
|
@ -8,7 +8,7 @@ import {useColorScheme} from 'react-native';
|
||||||
import {
|
import {
|
||||||
DarkTheme as PaperDarkTheme,
|
DarkTheme as PaperDarkTheme,
|
||||||
DefaultTheme as PaperDefaultTheme,
|
DefaultTheme as PaperDefaultTheme,
|
||||||
Provider,
|
Provider as PaperProvider,
|
||||||
} from 'react-native-paper';
|
} from 'react-native-paper';
|
||||||
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
||||||
import {Color} from './color';
|
import {Color} from './color';
|
||||||
|
@ -75,7 +75,7 @@ const App = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Color.Provider value={{color, setColor}}>
|
<Color.Provider value={{color, setColor}}>
|
||||||
<Provider
|
<PaperProvider
|
||||||
theme={theme}
|
theme={theme}
|
||||||
settings={{icon: props => <MaterialIcon {...props} />}}>
|
settings={{icon: props => <MaterialIcon {...props} />}}>
|
||||||
<NavigationContainer theme={theme}>
|
<NavigationContainer theme={theme}>
|
||||||
|
@ -87,7 +87,7 @@ const App = () => {
|
||||||
)}
|
)}
|
||||||
</MassiveSnack>
|
</MassiveSnack>
|
||||||
</NavigationContainer>
|
</NavigationContainer>
|
||||||
</Provider>
|
</PaperProvider>
|
||||||
</Color.Provider>
|
</Color.Provider>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
10
SetList.tsx
10
SetList.tsx
|
@ -12,7 +12,6 @@ import Page from './Page';
|
||||||
import Set from './set';
|
import Set from './set';
|
||||||
import {defaultSet, getSets, getToday} from './set.service';
|
import {defaultSet, getSets, getToday} from './set.service';
|
||||||
import SetItem from './SetItem';
|
import SetItem from './SetItem';
|
||||||
import {useSettings} from './use-settings';
|
|
||||||
|
|
||||||
const limit = 15;
|
const limit = 15;
|
||||||
|
|
||||||
|
@ -22,27 +21,22 @@ export default function SetList() {
|
||||||
const [offset, setOffset] = useState(0);
|
const [offset, setOffset] = useState(0);
|
||||||
const [term, setTerm] = useState('');
|
const [term, setTerm] = useState('');
|
||||||
const [end, setEnd] = useState(false);
|
const [end, setEnd] = useState(false);
|
||||||
const {settings} = useSettings();
|
|
||||||
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
const navigation = useNavigation<NavigationProp<HomePageParams>>();
|
||||||
|
|
||||||
const refresh = useCallback(
|
const refresh = useCallback(async (value: string) => {
|
||||||
async (value: string) => {
|
|
||||||
const todaysSet = await getToday();
|
const todaysSet = await getToday();
|
||||||
if (todaysSet) setSet({...todaysSet});
|
if (todaysSet) setSet({...todaysSet});
|
||||||
const newSets = await getSets({
|
const newSets = await getSets({
|
||||||
term: `%${value}%`,
|
term: `%${value}%`,
|
||||||
limit,
|
limit,
|
||||||
offset: 0,
|
offset: 0,
|
||||||
format: settings.date || '%Y-%m-%d %H:%M',
|
|
||||||
});
|
});
|
||||||
console.log(`${SetList.name}.refresh:`, {first: newSets[0]});
|
console.log(`${SetList.name}.refresh:`, {first: newSets[0]});
|
||||||
if (newSets.length === 0) return setSets([]);
|
if (newSets.length === 0) return setSets([]);
|
||||||
setSets(newSets);
|
setSets(newSets);
|
||||||
setOffset(0);
|
setOffset(0);
|
||||||
setEnd(false);
|
setEnd(false);
|
||||||
},
|
}, []);
|
||||||
[settings.date],
|
|
||||||
);
|
|
||||||
|
|
||||||
useFocusEffect(
|
useFocusEffect(
|
||||||
useCallback(() => {
|
useCallback(() => {
|
||||||
|
|
|
@ -47,7 +47,7 @@ export default function StartPlan() {
|
||||||
setCounts(newCounts);
|
setCounts(newCounts);
|
||||||
console.log(`${StartPlan.name}.focus:`, {newCounts});
|
console.log(`${StartPlan.name}.focus:`, {newCounts});
|
||||||
});
|
});
|
||||||
}, [params]),
|
}, [workouts]),
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
|
@ -101,7 +101,7 @@ export default function StartPlan() {
|
||||||
setUnit(newBest.unit);
|
setUnit(newBest.unit);
|
||||||
setBest(newBest);
|
setBest(newBest);
|
||||||
},
|
},
|
||||||
[name, workouts],
|
[name, counts],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -10,10 +10,10 @@ import {WorkoutsPageParams} from './WorkoutsPage';
|
||||||
|
|
||||||
export default function WorkoutItem({
|
export default function WorkoutItem({
|
||||||
item,
|
item,
|
||||||
onRemoved,
|
onRemove,
|
||||||
}: {
|
}: {
|
||||||
item: Set;
|
item: Set;
|
||||||
onRemoved: () => void;
|
onRemove: () => void;
|
||||||
}) {
|
}) {
|
||||||
const [showMenu, setShowMenu] = useState(false);
|
const [showMenu, setShowMenu] = useState(false);
|
||||||
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
const [anchor, setAnchor] = useState({x: 0, y: 0});
|
||||||
|
@ -24,8 +24,8 @@ export default function WorkoutItem({
|
||||||
const remove = useCallback(async () => {
|
const remove = useCallback(async () => {
|
||||||
await deleteSetsBy(item.name);
|
await deleteSetsBy(item.name);
|
||||||
setShowMenu(false);
|
setShowMenu(false);
|
||||||
onRemoved();
|
onRemove();
|
||||||
}, [setShowMenu, onRemoved, item.name]);
|
}, [setShowMenu, onRemove, item.name]);
|
||||||
|
|
||||||
const longPress = useCallback(
|
const longPress = useCallback(
|
||||||
(e: GestureResponderEvent) => {
|
(e: GestureResponderEvent) => {
|
||||||
|
|
|
@ -43,11 +43,7 @@ export default function WorkoutList() {
|
||||||
|
|
||||||
const renderItem = useCallback(
|
const renderItem = useCallback(
|
||||||
({item}: {item: Set}) => (
|
({item}: {item: Set}) => (
|
||||||
<WorkoutItem
|
<WorkoutItem item={item} key={item.name} onRemove={() => refresh(term)} />
|
||||||
item={item}
|
|
||||||
key={item.name}
|
|
||||||
onRemoved={() => refresh(term)}
|
|
||||||
/>
|
|
||||||
),
|
),
|
||||||
[refresh, term],
|
[refresh, term],
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
/**
|
|
||||||
* @format
|
|
||||||
*/
|
|
||||||
|
|
||||||
import 'react-native';
|
|
||||||
import React from 'react';
|
|
||||||
import App from '../App';
|
|
||||||
|
|
||||||
// Note: test renderer must be required after react-native.
|
|
||||||
import renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
it('renders correctly', () => {
|
|
||||||
renderer.create(<App />);
|
|
||||||
});
|
|
15
__tests__/BestList-test.tsx
Normal file
15
__tests__/BestList-test.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import {render, screen} from '@testing-library/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import 'react-native';
|
||||||
|
import BestList from '../BestList';
|
||||||
|
import {MockProviders} from '../mock-providers';
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
render(
|
||||||
|
<MockProviders>
|
||||||
|
<BestList />
|
||||||
|
</MockProviders>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Best')).toBeDefined();
|
||||||
|
expect(screen.getByPlaceholderText('Search')).toBeDefined();
|
||||||
|
});
|
26
__tests__/PlanItem-test.tsx
Normal file
26
__tests__/PlanItem-test.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import {render, screen} from '@testing-library/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import 'react-native';
|
||||||
|
import {MockProviders} from '../mock-providers';
|
||||||
|
import {Plan} from '../plan';
|
||||||
|
import PlanItem from '../PlanItem';
|
||||||
|
|
||||||
|
const plan: Plan = {
|
||||||
|
days: 'Monday,Tuesday,Wednesday',
|
||||||
|
workouts: 'Bench press,Bicep curls,Overhead press',
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const onRemove = jest.fn();
|
||||||
|
render(
|
||||||
|
<MockProviders>
|
||||||
|
<PlanItem item={plan} onRemove={onRemove} />
|
||||||
|
</MockProviders>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText(/Monday/i)).toBeDefined();
|
||||||
|
expect(screen.getByText(/Tuesday/i)).toBeDefined();
|
||||||
|
expect(screen.getByText(/Wednesday/i)).toBeDefined();
|
||||||
|
expect(screen.getByText(/Bench press/i)).toBeDefined();
|
||||||
|
expect(screen.getByText(/Bicep curls/i)).toBeDefined();
|
||||||
|
expect(screen.getByText(/Overhead press/i)).toBeDefined();
|
||||||
|
});
|
15
__tests__/PlanList-test.tsx
Normal file
15
__tests__/PlanList-test.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import {render, screen} from '@testing-library/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import 'react-native';
|
||||||
|
import {MockProviders} from '../mock-providers';
|
||||||
|
import PlanList from '../PlanList';
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
render(
|
||||||
|
<MockProviders>
|
||||||
|
<PlanList />
|
||||||
|
</MockProviders>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Plans')).toBeDefined();
|
||||||
|
expect(screen.getByPlaceholderText('Search')).toBeDefined();
|
||||||
|
});
|
26
__tests__/SetItem-test.tsx
Normal file
26
__tests__/SetItem-test.tsx
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import {render, screen} from '@testing-library/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import 'react-native';
|
||||||
|
import {MockProviders} from '../mock-providers';
|
||||||
|
import Set from '../set';
|
||||||
|
import SetItem from '../SetItem';
|
||||||
|
|
||||||
|
const set: Set = {
|
||||||
|
name: 'Bench press',
|
||||||
|
reps: 6,
|
||||||
|
weight: 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const onRemove = jest.fn();
|
||||||
|
render(
|
||||||
|
<MockProviders>
|
||||||
|
<SetItem item={set} onRemove={onRemove} />
|
||||||
|
</MockProviders>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText(set.name)).toBeDefined();
|
||||||
|
const reps = RegExp(set.reps.toString());
|
||||||
|
expect(screen.getByText(reps)).toBeDefined();
|
||||||
|
const weight = RegExp(set.weight.toString());
|
||||||
|
expect(screen.getByText(weight)).toBeDefined();
|
||||||
|
});
|
15
__tests__/SetList-test.tsx
Normal file
15
__tests__/SetList-test.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import {render, screen} from '@testing-library/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import 'react-native';
|
||||||
|
import {MockProviders} from '../mock-providers';
|
||||||
|
import SetList from '../SetList';
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
render(
|
||||||
|
<MockProviders>
|
||||||
|
<SetList />
|
||||||
|
</MockProviders>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Home')).toBeDefined();
|
||||||
|
expect(screen.getByPlaceholderText('Search')).toBeDefined();
|
||||||
|
});
|
27
__tests__/WorkoutItem-test.tsx
Normal file
27
__tests__/WorkoutItem-test.tsx
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import {render, screen} from '@testing-library/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import 'react-native';
|
||||||
|
import {MockProviders} from '../mock-providers';
|
||||||
|
import Set from '../set';
|
||||||
|
import WorkoutItem from '../WorkoutItem';
|
||||||
|
|
||||||
|
const set: Set = {
|
||||||
|
name: 'Bench press',
|
||||||
|
reps: 6,
|
||||||
|
weight: 20,
|
||||||
|
seconds: 40,
|
||||||
|
minutes: 3,
|
||||||
|
sets: 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
const onRemove = jest.fn();
|
||||||
|
render(
|
||||||
|
<MockProviders>
|
||||||
|
<WorkoutItem item={set} onRemove={onRemove} />
|
||||||
|
</MockProviders>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText(set.name)).toBeDefined();
|
||||||
|
const sets = RegExp(set.sets?.toString() || '');
|
||||||
|
expect(screen.getByText(sets)).toBeDefined();
|
||||||
|
});
|
15
__tests__/WorkoutList-test.tsx
Normal file
15
__tests__/WorkoutList-test.tsx
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import {render, screen} from '@testing-library/react-native';
|
||||||
|
import React from 'react';
|
||||||
|
import 'react-native';
|
||||||
|
import {MockProviders} from '../mock-providers';
|
||||||
|
import WorkoutList from '../WorkoutList';
|
||||||
|
|
||||||
|
it('renders correctly', () => {
|
||||||
|
render(
|
||||||
|
<MockProviders>
|
||||||
|
<WorkoutList />
|
||||||
|
</MockProviders>,
|
||||||
|
);
|
||||||
|
expect(screen.getByText('Workouts')).toBeDefined();
|
||||||
|
expect(screen.getByPlaceholderText('Search')).toBeDefined();
|
||||||
|
});
|
|
@ -1,6 +1,9 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
set -ex
|
set -ex
|
||||||
|
yarn tsc
|
||||||
|
yarn lint
|
||||||
|
yarn test
|
||||||
git push origin HEAD > /dev/null &
|
git push origin HEAD > /dev/null &
|
||||||
cd android || exit 1
|
cd android || exit 1
|
||||||
build=app/build.gradle
|
build=app/build.gradle
|
||||||
|
|
|
@ -7,5 +7,8 @@ module.exports = {
|
||||||
transformIgnorePatterns: [
|
transformIgnorePatterns: [
|
||||||
'node_modules/(?!(jest-)?@?react-native|@react-native-community|@react-navigation)',
|
'node_modules/(?!(jest-)?@?react-native|@react-native-community|@react-navigation)',
|
||||||
],
|
],
|
||||||
setupFiles: ['./jestSetup.ts'],
|
setupFiles: [
|
||||||
|
'./node_modules/react-native-gesture-handler/jestSetup',
|
||||||
|
'./jestSetup.ts',
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|
34
jestSetup.ts
34
jestSetup.ts
|
@ -1,21 +1,29 @@
|
||||||
|
import 'react-native-gesture-handler/jestSetup';
|
||||||
import {NativeModules as RNNativeModules} from 'react-native';
|
import {NativeModules as RNNativeModules} from 'react-native';
|
||||||
|
|
||||||
RNNativeModules.UIManager = RNNativeModules.UIManager || {};
|
//RNNativeModules.UIManager = RNNativeModules.UIManager || {};
|
||||||
RNNativeModules.UIManager.RCTView = RNNativeModules.UIManager.RCTView || {};
|
//RNNativeModules.UIManager.RCTView = RNNativeModules.UIManager.RCTView || {};
|
||||||
RNNativeModules.RNGestureHandlerModule =
|
//RNNativeModules.RNGestureHandlerModule =
|
||||||
RNNativeModules.RNGestureHandlerModule || {
|
// RNNativeModules.RNGestureHandlerModule || {
|
||||||
State: {BEGAN: 'BEGAN', FAILED: 'FAILED', ACTIVE: 'ACTIVE', END: 'END'},
|
// State: {BEGAN: 'BEGAN', FAILED: 'FAILED', ACTIVE: 'ACTIVE', END: 'END'},
|
||||||
attachGestureHandler: jest.fn(),
|
// attachGestureHandler: jest.fn(),
|
||||||
createGestureHandler: jest.fn(),
|
// createGestureHandler: jest.fn(),
|
||||||
dropGestureHandler: jest.fn(),
|
// dropGestureHandler: jest.fn(),
|
||||||
updateGestureHandler: jest.fn(),
|
// updateGestureHandler: jest.fn(),
|
||||||
};
|
// };
|
||||||
RNNativeModules.PlatformConstants = RNNativeModules.PlatformConstants || {
|
//RNNativeModules.PlatformConstants = RNNativeModules.PlatformConstants || {
|
||||||
forceTouchAvailable: false,
|
// forceTouchAvailable: false,
|
||||||
};
|
//};
|
||||||
RNNativeModules.RNViewShot = RNNativeModules.RNViewShot || {
|
RNNativeModules.RNViewShot = RNNativeModules.RNViewShot || {
|
||||||
captureScreen: jest.fn(),
|
captureScreen: jest.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
jest.mock('react-native-file-access', () => jest.fn());
|
jest.mock('react-native-file-access', () => jest.fn());
|
||||||
jest.mock('react-native-share', () => jest.fn());
|
jest.mock('react-native-share', () => jest.fn());
|
||||||
|
jest.mock('react-native/Libraries/Animated/NativeAnimatedHelper');
|
||||||
|
jest.useFakeTimers();
|
||||||
|
jest.mock('react-native-reanimated', () => {
|
||||||
|
const Reanimated = require('react-native-reanimated/mock');
|
||||||
|
Reanimated.default.call = () => {};
|
||||||
|
return Reanimated;
|
||||||
|
});
|
||||||
|
|
29
mock-providers.tsx
Normal file
29
mock-providers.tsx
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
import {NavigationContainer} from '@react-navigation/native';
|
||||||
|
import React from 'react';
|
||||||
|
import {Provider as PaperProvider} from 'react-native-paper';
|
||||||
|
import {Color} from './color';
|
||||||
|
import {lightColors} from './colors';
|
||||||
|
import MassiveSnack from './MassiveSnack';
|
||||||
|
import {defaultSettings, SettingsContext} from './use-settings';
|
||||||
|
import MaterialIcon from 'react-native-vector-icons/MaterialIcons';
|
||||||
|
|
||||||
|
const color = lightColors[0].hex;
|
||||||
|
export const setColor = jest.fn();
|
||||||
|
const settings = defaultSettings;
|
||||||
|
export const setSettings = jest.fn();
|
||||||
|
|
||||||
|
export const MockProviders = ({
|
||||||
|
children,
|
||||||
|
}: {
|
||||||
|
children: JSX.Element | JSX.Element[];
|
||||||
|
}) => (
|
||||||
|
<Color.Provider value={{color, setColor}}>
|
||||||
|
<PaperProvider settings={{icon: props => <MaterialIcon {...props} />}}>
|
||||||
|
<SettingsContext.Provider value={{settings, setSettings}}>
|
||||||
|
<MassiveSnack>
|
||||||
|
<NavigationContainer>{children}</NavigationContainer>
|
||||||
|
</MassiveSnack>
|
||||||
|
</SettingsContext.Provider>
|
||||||
|
</PaperProvider>
|
||||||
|
</Color.Provider>
|
||||||
|
);
|
|
@ -1,11 +1,7 @@
|
||||||
import React, {useContext} from 'react';
|
import React, {useContext} from 'react';
|
||||||
import Settings from './settings';
|
import Settings from './settings';
|
||||||
|
|
||||||
export const SettingsContext = React.createContext<{
|
export const defaultSettings: Settings = {
|
||||||
settings: Settings;
|
|
||||||
setSettings: (value: Settings) => void;
|
|
||||||
}>({
|
|
||||||
settings: {
|
|
||||||
alarm: 0,
|
alarm: 0,
|
||||||
color: '',
|
color: '',
|
||||||
date: '',
|
date: '',
|
||||||
|
@ -18,7 +14,14 @@ export const SettingsContext = React.createContext<{
|
||||||
steps: 0,
|
steps: 0,
|
||||||
theme: 'system',
|
theme: 'system',
|
||||||
vibrate: 1,
|
vibrate: 1,
|
||||||
},
|
noSound: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SettingsContext = React.createContext<{
|
||||||
|
settings: Settings;
|
||||||
|
setSettings: (value: Settings) => void;
|
||||||
|
}>({
|
||||||
|
settings: defaultSettings,
|
||||||
setSettings: () => null,
|
setSettings: () => null,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user