Tests refactor
This commit is contained in:
parent
245520fb50
commit
99134d8556
165 changed files with 911 additions and 531 deletions
|
|
@ -0,0 +1,305 @@
|
|||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, waitFor } from '@testing-library/react';
|
||||
|
||||
const { mockUseApi } = vi.hoisted(() => ({
|
||||
mockUseApi: vi.fn(),
|
||||
}));
|
||||
|
||||
const { mockListRegimens } = vi.hoisted(() => ({
|
||||
mockListRegimens: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/useApi', () => ({ useApi: mockUseApi }));
|
||||
|
||||
vi.mock('@/services/regimens', () => ({
|
||||
listRegimens: mockListRegimens,
|
||||
}));
|
||||
|
||||
vi.mock('next/link', () => ({
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
default: (props: any) => <a href={props.href}>{props.children}</a>,
|
||||
}));
|
||||
|
||||
import SchedulePage from '../../../../../src/app/(dashboard)/medicines/schedule/page';
|
||||
|
||||
beforeEach(() => vi.clearAllMocks());
|
||||
|
||||
const makeRegimen = (overrides = {}) => ({
|
||||
_id: 'reg1',
|
||||
householdId: 'hh1',
|
||||
name: 'Daily Vitamins',
|
||||
isActive: true,
|
||||
startDate: '2026-01-01',
|
||||
medications: [
|
||||
{
|
||||
medicineId: 'm1',
|
||||
medicineName: 'Vitamin D',
|
||||
medicineStrength: '1000',
|
||||
medicineStrengthUnit: 'IU',
|
||||
dosage: 1,
|
||||
dosageUnit: 'tablet',
|
||||
frequency: 'daily',
|
||||
timeOfDay: 'morning',
|
||||
},
|
||||
],
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
updatedAt: '2026-01-01T00:00:00.000Z',
|
||||
...overrides,
|
||||
});
|
||||
|
||||
describe('SchedulePage', () => {
|
||||
it('shows loading skeleton when session is loading', () => {
|
||||
mockUseApi.mockReturnValue({ householdId: null, isLoading: true });
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
expect(screen.getByText('Schedule & Log')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows no household message', () => {
|
||||
mockUseApi.mockReturnValue({ householdId: null, isLoading: false });
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
expect(screen.getByText(/create or join a household/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows empty state when no regimens', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('No active regimens found.')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows set up link in empty state', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Set up a regimen')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('renders medication in morning slot', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [makeRegimen()],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Vitamin D')).toBeInTheDocument();
|
||||
expect(screen.getByText('Morning')).toBeInTheDocument();
|
||||
expect(screen.getByText('1000 IU')).toBeInTheDocument();
|
||||
expect(screen.getByText('Daily Vitamins')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows frequency label', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [makeRegimen()],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/Once daily/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows custom frequency', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [
|
||||
makeRegimen({
|
||||
medications: [
|
||||
{
|
||||
medicineId: 'm1',
|
||||
medicineName: 'Custom Med',
|
||||
medicineStrength: '50',
|
||||
medicineStrengthUnit: 'mg',
|
||||
dosage: 1,
|
||||
dosageUnit: 'tablet',
|
||||
frequency: 'custom',
|
||||
customFrequencyPerDay: 4,
|
||||
timeOfDay: 'morning',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/4x daily/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows instructions when present', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [
|
||||
makeRegimen({
|
||||
medications: [
|
||||
{
|
||||
medicineId: 'm1',
|
||||
medicineName: 'Med A',
|
||||
medicineStrength: '10',
|
||||
medicineStrengthUnit: 'mg',
|
||||
dosage: 1,
|
||||
dosageUnit: 'pill',
|
||||
frequency: 'daily',
|
||||
timeOfDay: 'evening',
|
||||
instructions: 'Take with food',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Take with food')).toBeInTheDocument();
|
||||
expect(screen.getByText('Evening')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows dose count', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [makeRegimen()],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('1 dose')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows error when fetch fails', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockRejectedValue(new Error('Network error'));
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Network error')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('shows fallback error for non-Error failures', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockRejectedValue('unexpected');
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Failed to load regimens')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('groups into "any" slot when timeOfDay is missing', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [
|
||||
makeRegimen({
|
||||
medications: [
|
||||
{
|
||||
medicineId: 'm2',
|
||||
medicineName: 'Aspirin',
|
||||
medicineStrength: '100',
|
||||
medicineStrengthUnit: 'mg',
|
||||
dosage: 1,
|
||||
dosageUnit: 'tablet',
|
||||
frequency: 'as_needed',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Aspirin')).toBeInTheDocument();
|
||||
expect(screen.getByText('Any time')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('paginates through regimens', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens
|
||||
.mockResolvedValueOnce({
|
||||
data: [makeRegimen()],
|
||||
pagination: { cursor: 'next', hasMore: true },
|
||||
})
|
||||
.mockResolvedValueOnce({
|
||||
data: [
|
||||
makeRegimen({
|
||||
_id: 'reg2',
|
||||
name: 'Second Regimen',
|
||||
medications: [
|
||||
{
|
||||
medicineId: 'm2',
|
||||
medicineName: 'Iron',
|
||||
medicineStrength: '65',
|
||||
medicineStrengthUnit: 'mg',
|
||||
dosage: 1,
|
||||
dosageUnit: 'tablet',
|
||||
frequency: 'daily',
|
||||
timeOfDay: 'afternoon',
|
||||
},
|
||||
],
|
||||
}),
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText('Vitamin D')).toBeInTheDocument();
|
||||
expect(screen.getByText('Iron')).toBeInTheDocument();
|
||||
});
|
||||
expect(mockListRegimens).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
it('shows regimen and dose summary', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRegimens.mockResolvedValue({
|
||||
data: [makeRegimen()],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<SchedulePage />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/1 active regimen/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/1 dose per day/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue