Tests refactor
This commit is contained in:
parent
245520fb50
commit
99134d8556
165 changed files with 911 additions and 531 deletions
689
packages/web/tests/app/(dashboard)/refills/page.test.tsx
Normal file
689
packages/web/tests/app/(dashboard)/refills/page.test.tsx
Normal file
|
|
@ -0,0 +1,689 @@
|
|||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
import type React from 'react';
|
||||
|
||||
const { mockUseApi } = vi.hoisted(() => ({ mockUseApi: vi.fn() }));
|
||||
|
||||
const {
|
||||
mockGetRefillAlerts,
|
||||
mockListRefillLists,
|
||||
mockCreateRefillList,
|
||||
mockUpdateRefillList,
|
||||
mockUpdateRefillListItem,
|
||||
mockAddToCabinet,
|
||||
} = vi.hoisted(() => ({
|
||||
mockGetRefillAlerts: vi.fn(),
|
||||
mockListRefillLists: vi.fn(),
|
||||
mockCreateRefillList: vi.fn(),
|
||||
mockUpdateRefillList: vi.fn(),
|
||||
mockUpdateRefillListItem: vi.fn(),
|
||||
mockAddToCabinet: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('@/lib/useApi', () => ({ useApi: mockUseApi }));
|
||||
vi.mock('@/services/refills', () => ({
|
||||
getRefillAlerts: mockGetRefillAlerts,
|
||||
listRefillLists: mockListRefillLists,
|
||||
createRefillList: mockCreateRefillList,
|
||||
updateRefillList: mockUpdateRefillList,
|
||||
updateRefillListItem: mockUpdateRefillListItem,
|
||||
addToCabinet: mockAddToCabinet,
|
||||
}));
|
||||
vi.mock('next/link', () => ({
|
||||
default: (props: { href?: string; children: React.ReactNode }) => props.children,
|
||||
}));
|
||||
|
||||
import RefillsPage from '../../../../src/app/(dashboard)/refills/page';
|
||||
|
||||
const emptyAlerts = { data: [], pagination: { cursor: null, hasMore: false } };
|
||||
const emptyLists = { data: [], pagination: { cursor: null, hasMore: false } };
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
mockGetRefillAlerts.mockResolvedValue(emptyAlerts);
|
||||
mockListRefillLists.mockResolvedValue(emptyLists);
|
||||
});
|
||||
|
||||
describe('RefillsPage', () => {
|
||||
it('shows loading skeleton when session loading', () => {
|
||||
mockUseApi.mockReturnValue({ householdId: null, isLoading: true });
|
||||
render(<RefillsPage />);
|
||||
expect(screen.getByText('Refills')).toBeInTheDocument();
|
||||
expect(screen.queryByText('New Refill List')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows household prompt when no householdId', () => {
|
||||
mockUseApi.mockReturnValue({ householdId: null, isLoading: false });
|
||||
render(<RefillsPage />);
|
||||
expect(screen.getByText(/create or join a household/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders Refills heading when householdId exists', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
render(<RefillsPage />);
|
||||
expect(screen.getByText('Refills')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows empty state for alerts', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
render(<RefillsPage />);
|
||||
await waitFor(() => expect(screen.getByText(/No medicines running low/)).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('shows empty state for refill lists', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
render(<RefillsPage />);
|
||||
await waitFor(() => expect(screen.getByText(/No refill lists yet/)).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('shows error when alerts fail', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockGetRefillAlerts.mockRejectedValue(new Error('Alert error'));
|
||||
render(<RefillsPage />);
|
||||
await waitFor(() => expect(screen.getByText('Alert error')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('shows New List button and toggles form', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('New List'));
|
||||
await userEvent.click(screen.getByText('New List'));
|
||||
expect(screen.getByPlaceholderText('List name')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('creates a new refill list', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockCreateRefillList.mockResolvedValue({
|
||||
_id: 'rl-1',
|
||||
name: 'Test List',
|
||||
status: 'active',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('New List'));
|
||||
await userEvent.click(screen.getByText('New List'));
|
||||
|
||||
await waitFor(() => screen.getByPlaceholderText('List name'));
|
||||
fireEvent.change(screen.getByPlaceholderText('List name'), { target: { value: 'Test List' } });
|
||||
fireEvent.submit(screen.getByPlaceholderText('List name').closest('form')!);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockCreateRefillList).toHaveBeenCalledWith(
|
||||
'hh1',
|
||||
expect.objectContaining({ name: 'Test List' }),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('shows refill list and can select it', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [
|
||||
{
|
||||
_id: 'item-1',
|
||||
medicineId: 'med-1',
|
||||
medicineName: 'Aspirin',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
checked: false,
|
||||
addedToCabinet: false,
|
||||
},
|
||||
],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
},
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Aspirin')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('updates a refill list status', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockUpdateRefillList.mockResolvedValue({});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText('Start shopping'));
|
||||
await userEvent.click(screen.getByText('Start shopping'));
|
||||
|
||||
expect(mockUpdateRefillList).toHaveBeenCalledWith('hh1', 'rl-1', { status: 'shopping' });
|
||||
});
|
||||
|
||||
it('shows error when create list fails', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockCreateRefillList.mockRejectedValue(new Error('Create failed'));
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('New List'));
|
||||
await userEvent.click(screen.getByText('New List'));
|
||||
|
||||
await waitFor(() => screen.getByPlaceholderText('List name'));
|
||||
fireEvent.change(screen.getByPlaceholderText('List name'), { target: { value: 'Test' } });
|
||||
fireEvent.submit(screen.getByPlaceholderText('List name').closest('form')!);
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Create failed')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('adds checked items to cabinet', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [
|
||||
{
|
||||
_id: 'item-1',
|
||||
medicineId: 'med-1',
|
||||
medicineName: 'Aspirin',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
checked: true,
|
||||
addedToCabinet: false,
|
||||
},
|
||||
],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockAddToCabinet.mockResolvedValue({ addedCount: 1 });
|
||||
vi.spyOn(window, 'confirm').mockReturnValue(true);
|
||||
vi.spyOn(window, 'alert').mockImplementation(() => {});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText(/Add .* to Cabinet/));
|
||||
await userEvent.click(screen.getByText(/Add .* to Cabinet/));
|
||||
|
||||
expect(mockAddToCabinet).toHaveBeenCalledWith('hh1', 'rl-1');
|
||||
});
|
||||
|
||||
it('generates a refill list from alerts', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockGetRefillAlerts.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
medicineId: 'm1',
|
||||
medicineName: 'Aspirin',
|
||||
medicineStrength: 500,
|
||||
medicineStrengthUnit: 'mg',
|
||||
currentStock: 5,
|
||||
dailyConsumption: 1.5,
|
||||
daysUntilEmpty: 3,
|
||||
},
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockCreateRefillList.mockResolvedValue({
|
||||
_id: 'rl-gen',
|
||||
name: 'Auto Refills',
|
||||
status: 'active',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Aspirin'));
|
||||
await userEvent.click(screen.getByText('Generate Refill List'));
|
||||
|
||||
await waitFor(() => screen.getByPlaceholderText('List name, e.g. Weekly refills'));
|
||||
fireEvent.change(screen.getByPlaceholderText('List name, e.g. Weekly refills'), {
|
||||
target: { value: 'Auto Refills' },
|
||||
});
|
||||
fireEvent.submit(
|
||||
screen.getByPlaceholderText('List name, e.g. Weekly refills').closest('form')!,
|
||||
);
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockCreateRefillList).toHaveBeenCalledWith(
|
||||
'hh1',
|
||||
expect.objectContaining({ name: 'Auto Refills', fromAlerts: true }),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
it('cancels create list form', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('New List'));
|
||||
await userEvent.click(screen.getByText('New List'));
|
||||
|
||||
await waitFor(() => screen.getByPlaceholderText('List name'));
|
||||
await userEvent.click(
|
||||
screen.getAllByRole('button', { name: 'Cancel' })[
|
||||
screen.getAllByRole('button', { name: 'Cancel' }).length - 1
|
||||
]!,
|
||||
);
|
||||
|
||||
expect(screen.queryByPlaceholderText('List name')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('closes the refill list detail panel', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
},
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByTitle('Close'));
|
||||
await userEvent.click(screen.getByTitle('Close'));
|
||||
|
||||
// After close, detail panel should not be visible (no Close button)
|
||||
expect(screen.queryByTitle('Close')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('archives a refill list', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockUpdateRefillList.mockResolvedValue({});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText('Archive'));
|
||||
await userEvent.click(screen.getByText('Archive'));
|
||||
|
||||
expect(mockUpdateRefillList).toHaveBeenCalledWith('hh1', 'rl-1', { status: 'archived' });
|
||||
});
|
||||
|
||||
it('shows error when generate list fails', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockGetRefillAlerts.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
medicineId: 'm1',
|
||||
medicineName: 'Aspirin',
|
||||
medicineStrength: 500,
|
||||
medicineStrengthUnit: 'mg',
|
||||
currentStock: 5,
|
||||
dailyConsumption: 1.5,
|
||||
daysUntilEmpty: 3,
|
||||
},
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockCreateRefillList.mockRejectedValue(new Error('Generate failed'));
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Aspirin'));
|
||||
await userEvent.click(screen.getByText('Generate Refill List'));
|
||||
|
||||
await waitFor(() => screen.getByPlaceholderText('List name, e.g. Weekly refills'));
|
||||
fireEvent.change(screen.getByPlaceholderText('List name, e.g. Weekly refills'), {
|
||||
target: { value: 'Auto Refills' },
|
||||
});
|
||||
fireEvent.submit(
|
||||
screen.getByPlaceholderText('List name, e.g. Weekly refills').closest('form')!,
|
||||
);
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Generate failed')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('dismisses refill list panel error', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRefillLists.mockRejectedValue(new Error('List error'));
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('List error'));
|
||||
await userEvent.click(screen.getByText('Dismiss'));
|
||||
expect(screen.queryByText('List error')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('toggles item checked state', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [
|
||||
{
|
||||
_id: 'item-1',
|
||||
medicineId: 'med-1',
|
||||
medicineName: 'Aspirin',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
checked: false,
|
||||
addedToCabinet: false,
|
||||
},
|
||||
],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockUpdateRefillListItem.mockResolvedValue({
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [
|
||||
{
|
||||
_id: 'item-1',
|
||||
medicineId: 'med-1',
|
||||
medicineName: 'Aspirin',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
checked: true,
|
||||
addedToCabinet: false,
|
||||
},
|
||||
],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText('Aspirin'));
|
||||
await userEvent.click(screen.getByRole('checkbox'));
|
||||
|
||||
expect(mockUpdateRefillListItem).toHaveBeenCalledWith('hh1', 'rl-1', 'item-1', {
|
||||
checked: true,
|
||||
});
|
||||
});
|
||||
|
||||
it('marks a shopping list as complete', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'shopping',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockUpdateRefillList.mockResolvedValue({});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText('Mark complete'));
|
||||
await userEvent.click(screen.getByText('Mark complete'));
|
||||
|
||||
expect(mockUpdateRefillList).toHaveBeenCalledWith('hh1', 'rl-1', { status: 'completed' });
|
||||
});
|
||||
|
||||
it('filters refill lists by status', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
_id: 'rl-1',
|
||||
name: 'Active List',
|
||||
status: 'active',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
},
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Active List'));
|
||||
fireEvent.change(screen.getByDisplayValue('All statuses'), { target: { value: 'active' } });
|
||||
|
||||
await waitFor(() => expect(mockListRefillLists).toHaveBeenCalledTimes(2));
|
||||
});
|
||||
|
||||
it('shows actual price input after checking item and allows price entry', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [
|
||||
{
|
||||
_id: 'item-1',
|
||||
medicineId: 'med-1',
|
||||
medicineName: 'Aspirin',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
checked: true,
|
||||
addedToCabinet: false,
|
||||
},
|
||||
],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByPlaceholderText('Actual price'));
|
||||
fireEvent.change(screen.getByPlaceholderText('Actual price'), { target: { value: '5.99' } });
|
||||
|
||||
expect(screen.getByPlaceholderText('Actual price')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('dismisses panel-level error', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [
|
||||
{
|
||||
_id: 'item-1',
|
||||
medicineId: 'med-1',
|
||||
medicineName: 'Aspirin',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
checked: true,
|
||||
addedToCabinet: false,
|
||||
},
|
||||
],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockAddToCabinet.mockRejectedValue(new Error('Cabinet error'));
|
||||
vi.spyOn(window, 'confirm').mockReturnValue(true);
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText(/Add .* to Cabinet/));
|
||||
await userEvent.click(screen.getByText(/Add .* to Cabinet/));
|
||||
|
||||
await waitFor(() => screen.getByText('Cabinet error'));
|
||||
// Dismiss via inline button in the panel
|
||||
const dismissBtns = screen.getAllByText('Dismiss');
|
||||
await userEvent.click(dismissBtns[dismissBtns.length - 1]!);
|
||||
|
||||
expect(screen.queryByText('Cabinet error')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows fallback error when non-Error thrown on update item', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [
|
||||
{
|
||||
_id: 'item-1',
|
||||
medicineId: 'med-1',
|
||||
medicineName: 'Aspirin',
|
||||
quantity: 30,
|
||||
unit: 'tablet',
|
||||
checked: false,
|
||||
addedToCabinet: false,
|
||||
},
|
||||
],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockUpdateRefillListItem.mockRejectedValue('update failed');
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText('Aspirin'));
|
||||
await userEvent.click(screen.getAllByRole('checkbox')[0]!);
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Failed to update item')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('shows fallback error when non-Error thrown on update status', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
const refillList = {
|
||||
_id: 'rl-1',
|
||||
name: 'Weekly List',
|
||||
status: 'active',
|
||||
items: [],
|
||||
householdId: 'hh1',
|
||||
createdBy: 'u1',
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
mockListRefillLists.mockResolvedValue({
|
||||
data: [refillList],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
mockUpdateRefillList.mockRejectedValue('status failed');
|
||||
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => screen.getByText('Weekly List'));
|
||||
await userEvent.click(screen.getByText('Weekly List'));
|
||||
|
||||
await waitFor(() => screen.getByText('Start shopping'));
|
||||
await userEvent.click(screen.getByText('Start shopping'));
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Failed to update status')).toBeInTheDocument());
|
||||
});
|
||||
|
||||
it('shows refill alert when present', async () => {
|
||||
mockUseApi.mockReturnValue({ householdId: 'hh1', isLoading: false });
|
||||
mockGetRefillAlerts.mockResolvedValue({
|
||||
data: [
|
||||
{
|
||||
medicineId: 'm1',
|
||||
medicineName: 'Aspirin',
|
||||
medicineStrength: 500,
|
||||
medicineStrengthUnit: 'mg',
|
||||
currentStock: 5,
|
||||
dailyConsumption: 1.5,
|
||||
daysUntilEmpty: 3,
|
||||
},
|
||||
],
|
||||
pagination: { cursor: null, hasMore: false },
|
||||
});
|
||||
render(<RefillsPage />);
|
||||
|
||||
await waitFor(() => expect(screen.getByText('Aspirin')).toBeInTheDocument());
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue