Skip to content

Commit 8617447

Browse files
committed
Add some tests
1 parent 4586551 commit 8617447

File tree

4 files changed

+226
-49
lines changed

4 files changed

+226
-49
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { QueryClientProvider } from "@tanstack/react-query";
2+
import { render, screen } from '@testing-library/react';
3+
import { SlotDetails } from 'components/WorkoutRoutines/Detail/SlotDetails';
4+
import { Slot } from 'components/WorkoutRoutines/models/Slot';
5+
import { SlotConfig } from "components/WorkoutRoutines/models/SlotConfig";
6+
import React from 'react';
7+
import { testQueryClient } from "tests/queryClient";
8+
9+
describe('SlotDetails Component', () => {
10+
11+
const slotConfig = new SlotConfig(1, 2, 3, 4, 5, 6, 7, 8, 'test', 'normal',);
12+
const testSlot = new Slot(1, 2, 3, '', [slotConfig]);
13+
14+
test('renders only sets, weight, and reps fields in simpleMode', () => {
15+
render(
16+
<QueryClientProvider client={testQueryClient}>
17+
<SlotDetails slot={testSlot} routineId={1} simpleMode={true} />
18+
</QueryClientProvider>
19+
);
20+
21+
expect(screen.getByTestId('sets-field')).toBeInTheDocument();
22+
expect(screen.getByTestId('sets-field')).toBeInTheDocument();
23+
expect(screen.getByTestId('weight-field')).toBeInTheDocument();
24+
expect(screen.getByTestId('reps-field')).toBeInTheDocument();
25+
26+
// Assert that other config fields are NOT rendered
27+
expect(screen.queryByTestId('max-weight-field')).not.toBeInTheDocument();
28+
expect(screen.queryByTestId('max-reps-field')).not.toBeInTheDocument();
29+
expect(screen.queryByTestId('rir-field')).not.toBeInTheDocument();
30+
expect(screen.queryByTestId('rest-field')).not.toBeInTheDocument();
31+
expect(screen.queryByTestId('max-rest-field')).not.toBeInTheDocument();
32+
});
33+
34+
test('renders all config fields when not in simpleMode', () => {
35+
render(
36+
<QueryClientProvider client={testQueryClient}>
37+
<SlotDetails slot={testSlot} routineId={1} simpleMode={false} />
38+
</QueryClientProvider>
39+
);
40+
41+
// Assert that all config fields are rendered
42+
expect(screen.getByTestId('sets-field')).toBeInTheDocument();
43+
expect(screen.getByTestId('weight-field')).toBeInTheDocument();
44+
expect(screen.getByTestId('max-weight-field')).toBeInTheDocument();
45+
expect(screen.getByTestId('reps-field')).toBeInTheDocument();
46+
expect(screen.getByTestId('max-reps-field')).toBeInTheDocument();
47+
expect(screen.getByTestId('rir-field')).toBeInTheDocument();
48+
expect(screen.getByTestId('rest-field')).toBeInTheDocument();
49+
expect(screen.getByTestId('max-rest-field')).toBeInTheDocument();
50+
});
51+
});

src/components/WorkoutRoutines/Detail/SlotDetails.tsx

Lines changed: 27 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -43,66 +43,44 @@ export const SlotDetails = (props: { slot: Slot, routineId: number, simpleMode:
4343

4444
<Grid container spacing={2}>
4545
{props.simpleMode ? (
46-
// Show only weight, reps, and sets in simple mode
4746
<>
48-
<Grid item xs={12} sm={4} key={`sets-config-${slotConfig.id}`}>
47+
<Grid item xs={12} sm={3} key={`sets-config-${slotConfig.id}`}>
4948
{getConfigComponent('sets', slotConfig.nrOfSetsConfigs, props.routineId, slotConfig.id)}
5049
</Grid>
51-
<Grid item xs={12} sm={4} key={`weight-config-${slotConfig.id}`}>
50+
<Grid item xs={12} sm={3} key={`weight-config-${slotConfig.id}`}>
5251
{getConfigComponent('weight', slotConfig.weightConfigs, props.routineId, slotConfig.id)}
5352
</Grid>
54-
<Grid item xs={12} sm={4} key={`reps-config-${slotConfig.id}`}>
53+
<Grid item xs={12} sm={3} key={`reps-config-${slotConfig.id}`}>
5554
{getConfigComponent('reps', slotConfig.repsConfigs, props.routineId, slotConfig.id)}
5655
</Grid>
57-
5856
</>
5957
) : (
6058
// Show all config details in advanced mode, also in a grid
6159
<>
62-
<h1>TODO!</h1>
63-
{slotConfig.weightConfigs.map((config) => (
64-
<Grid item xs={12} sm={4} key={`weight-${config.id}`}>
65-
<ConfigDetailsField config={config} type="weight" routineId={props.routineId} />
66-
</Grid>
67-
))}
68-
{slotConfig.maxWeightConfigs.map((config) => (
69-
<Grid item xs={12} sm={4} key={`max-weight-${config.id}`}>
70-
<ConfigDetailsField config={config} type="max-weight"
71-
routineId={props.routineId} />
72-
</Grid>
73-
))}
74-
{slotConfig.repsConfigs.map((config) => (
75-
<Grid item xs={12} sm={4} key={`reps-${config.id}`}>
76-
<ConfigDetailsField config={config} type="reps" routineId={props.routineId} />
77-
</Grid>
78-
))}
79-
{slotConfig.maxRepsConfigs.map((config) => (
80-
<Grid item xs={12} sm={4} key={`max-reps-${config.id}`}>
81-
<ConfigDetailsField config={config} type="max-reps"
82-
routineId={props.routineId} />
83-
</Grid>
84-
))}
85-
{slotConfig.nrOfSetsConfigs.map((config) => (
86-
<Grid item xs={12} sm={4} key={`sets-${config.id}`}>
87-
<ConfigDetailsField config={config} type="sets" routineId={props.routineId} />
88-
</Grid>
89-
))}
90-
{slotConfig.restTimeConfigs.map((config) => (
91-
<Grid item xs={12} sm={4} key={`rest-${config.id}`}>
92-
<ConfigDetailsField config={config} type="rest" routineId={props.routineId} />
93-
</Grid>
94-
))}
95-
{slotConfig.maxRestTimeConfigs.map((config) => (
96-
<Grid item xs={12} sm={4} key={`max-rest-${config.id}`}>
97-
<ConfigDetailsField config={config} type="max-rest"
98-
routineId={props.routineId} />
99-
</Grid>
100-
))}
101-
{slotConfig.rirConfigs.map((config) => (
102-
<Grid item xs={12} sm={4} key={`rir-${config.id}`}>
103-
<ConfigDetailsField config={config} type="rir" routineId={props.routineId} />
104-
</Grid>
105-
))}
60+
<Grid item xs={12} sm={2} key={`sets-config-${slotConfig.id}`}>
61+
{getConfigComponent('sets', slotConfig.nrOfSetsConfigs, props.routineId, slotConfig.id)}
62+
</Grid>
63+
<Grid item xs={12} sm={2} key={`weight-config-${slotConfig.id}`}>
64+
{getConfigComponent('weight', slotConfig.weightConfigs, props.routineId, slotConfig.id)}
65+
</Grid>
66+
<Grid item xs={12} sm={1} key={`max-weight-config-${slotConfig.id}`}>
67+
{getConfigComponent('max-weight', slotConfig.maxWeightConfigs, props.routineId, slotConfig.id)}
68+
</Grid>
69+
<Grid item xs={12} sm={2} key={`reps-config-${slotConfig.id}`}>
70+
{getConfigComponent('reps', slotConfig.repsConfigs, props.routineId, slotConfig.id)}
71+
</Grid>
72+
<Grid item xs={12} sm={1} key={`max-reps-config-${slotConfig.id}`}>
73+
{getConfigComponent('max-reps', slotConfig.maxRepsConfigs, props.routineId, slotConfig.id)}
74+
</Grid>
75+
<Grid item xs={12} sm={2} key={`rir-config-${slotConfig.id}`}>
76+
{getConfigComponent('rir', slotConfig.rirConfigs, props.routineId, slotConfig.id)}
77+
</Grid>
78+
<Grid item xs={12} sm={1} key={`rest-config-${slotConfig.id}`}>
79+
{getConfigComponent('rest', slotConfig.restTimeConfigs, props.routineId, slotConfig.id)}
80+
</Grid>
81+
<Grid item xs={12} sm={1} key={`max-rest-config-${slotConfig.id}`}>
82+
{getConfigComponent('max-rest', slotConfig.maxRestTimeConfigs, props.routineId, slotConfig.id)}
83+
</Grid>
10684
</>
10785
)}
10886
</Grid>
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
import { QueryClientProvider } from "@tanstack/react-query";
2+
import { render, screen } from '@testing-library/react';
3+
import userEvent from "@testing-library/user-event";
4+
import { BaseConfig } from 'components/WorkoutRoutines/models/BaseConfig';
5+
6+
import { ConfigDetailsField } from 'components/WorkoutRoutines/widgets/forms/BaseConfigForm';
7+
import React from 'react';
8+
import { testQueryClient } from "tests/queryClient";
9+
10+
11+
jest.mock('utils/consts', () => {
12+
return {
13+
DEBOUNCE_ROUTINE_FORMS: '5'
14+
};
15+
});
16+
17+
18+
jest.mock('components/WorkoutRoutines/queries', () => ({
19+
useEditWeightConfigQuery: jest.fn(() => ({ mutate: editMutation })),
20+
useAddWeightConfigQuery: jest.fn(() => ({ mutate: addMutation })),
21+
useDeleteWeightConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
22+
useEditMaxWeightConfigQuery: jest.fn(() => ({ mutate: editMutation })),
23+
useAddMaxWeightConfigQuery: jest.fn(() => ({ mutate: addMutation })),
24+
useDeleteMaxWeightConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
25+
useEditRepsConfigQuery: jest.fn(() => ({ mutate: editMutation })),
26+
useAddRepsConfigQuery: jest.fn(() => ({ mutate: addMutation })),
27+
useDeleteRepsConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
28+
useEditMaxRepsConfigQuery: jest.fn(() => ({ mutate: editMutation })),
29+
useAddMaxRepsConfigQuery: jest.fn(() => ({ mutate: addMutation })),
30+
useDeleteMaxRepsConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
31+
useEditNrOfSetsConfigQuery: jest.fn(() => ({ mutate: editMutation })),
32+
useAddNrOfSetsConfigQuery: jest.fn(() => ({ mutate: addMutation })),
33+
useDeleteNrOfSetsConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
34+
useEditRestConfigQuery: jest.fn(() => ({ mutate: editMutation })),
35+
useAddRestConfigQuery: jest.fn(() => ({ mutate: addMutation })),
36+
useDeleteRestConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
37+
useEditMaxRestConfigQuery: jest.fn(() => ({ mutate: editMutation })),
38+
useAddMaxRestConfigQuery: jest.fn(() => ({ mutate: addMutation })),
39+
useDeleteMaxRestConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
40+
useEditRiRConfigQuery: jest.fn(() => ({ mutate: editMutation })),
41+
useAddRiRConfigQuery: jest.fn(() => ({ mutate: addMutation })),
42+
useDeleteRiRConfigQuery: jest.fn(() => ({ mutate: deleteMutation })),
43+
}));
44+
45+
46+
const editMutation = jest.fn();
47+
const addMutation = jest.fn();
48+
const deleteMutation = jest.fn();
49+
50+
const DEBOUNCE_WAIT = 10;
51+
52+
describe('ConfigDetailsField Component', () => {
53+
const routineId = 1;
54+
const slotId = 2;
55+
56+
beforeEach(() => {
57+
jest.clearAllMocks();
58+
});
59+
60+
afterEach(() => {
61+
jest.restoreAllMocks();
62+
});
63+
64+
const testConfigTypes = ['weight', 'max-weight', 'reps', 'max-reps', 'sets', 'rest', 'max-rest', 'rir'] as const;
65+
66+
testConfigTypes.forEach((type) => {
67+
describe(`for type ${type}`, () => {
68+
test('calls editQuery.mutate with correct data when entry exists', async () => {
69+
70+
const mockConfig = new BaseConfig(123, 10, 1, null, 5, '+', null, true, false);
71+
const user = userEvent.setup();
72+
73+
render(
74+
<QueryClientProvider client={testQueryClient}>
75+
<ConfigDetailsField config={mockConfig} routineId={routineId} slotId={slotId} type={type} />
76+
</QueryClientProvider>
77+
);
78+
79+
await user.type(screen.getByTestId(`${type}-field`), '2');
80+
81+
82+
await new Promise((resolve) => setTimeout(resolve, DEBOUNCE_WAIT));
83+
84+
expect(addMutation).toHaveBeenCalledTimes(0);
85+
expect(editMutation).toHaveBeenCalledTimes(1);
86+
expect(editMutation).toHaveBeenCalledWith({
87+
id: mockConfig.id,
88+
slot_config: slotId,
89+
value: 52,
90+
iteration: 1,
91+
operation: null,
92+
replace: true,
93+
need_log_to_apply: false,
94+
});
95+
expect(deleteMutation).toHaveBeenCalledTimes(0);
96+
});
97+
98+
test('calls addQuery.mutate with correct data when creating a new entry', async () => {
99+
const user = userEvent.setup();
100+
101+
render(
102+
<QueryClientProvider client={testQueryClient}>
103+
<ConfigDetailsField routineId={routineId} slotId={slotId} type={type} />
104+
</QueryClientProvider>
105+
);
106+
107+
await user.type(screen.getByTestId(`${type}-field`), '8');
108+
await new Promise((resolve) => setTimeout(resolve, DEBOUNCE_WAIT));
109+
110+
expect(addMutation).toHaveBeenCalledTimes(1);
111+
expect(addMutation).toHaveBeenCalledWith({
112+
slot: slotId,
113+
slot_config: 2,
114+
value: 8,
115+
iteration: 1,
116+
operation: null,
117+
replace: true,
118+
need_log_to_apply: false,
119+
});
120+
expect(editMutation).toHaveBeenCalledTimes(0);
121+
expect(deleteMutation).toHaveBeenCalledTimes(0);
122+
});
123+
124+
test('calls deleteQuery.mutate when value is deleted', async () => {
125+
const user = userEvent.setup();
126+
127+
const mockConfig = new BaseConfig(123, 10, 1, null, 5, '+', null, true, false);
128+
render(
129+
<QueryClientProvider client={testQueryClient}>
130+
<ConfigDetailsField config={mockConfig} routineId={routineId} slotId={slotId} type={type} />
131+
</QueryClientProvider>
132+
);
133+
134+
await user.clear(screen.getByTestId(`${type}-field`));
135+
await new Promise((resolve) => setTimeout(resolve, DEBOUNCE_WAIT));
136+
137+
expect(addMutation).toHaveBeenCalledTimes(0);
138+
expect(editMutation).toHaveBeenCalledTimes(0);
139+
expect(deleteMutation).toHaveBeenCalledTimes(1);
140+
expect(deleteMutation).toHaveBeenCalledWith(mockConfig.id);
141+
});
142+
});
143+
});
144+
});

src/components/WorkoutRoutines/widgets/forms/BaseConfigForm.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,12 @@ export const ConfigDetailsField = (props: {
127127

128128
return (<>
129129
<TextField
130+
inputProps={{
131+
"data-testid": `${props.type}-field`,
132+
}}
130133
label={props.type}
131134
value={value}
135+
fullWidth
132136
onChange={e => onChange(e.target.value)}
133137
InputProps={{
134138
endAdornment: (editQueryHook.isLoading || addQueryHook.isLoading) && <CircularProgress size={20} />

0 commit comments

Comments
 (0)