Feat/frontend tests (#62)
* test(frontend): add vitest test infrastructure - Add vitest, testing-library, jsdom dependencies - Configure vitest with jsdom environment - Add test setup with mocks for fetch, localStorage, matchMedia - Set 75% coverage threshold * Add frontend tests (#61) * Initial plan * Add frontend tests - utilities, hooks, and components (21% coverage) Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Add more component tests (Auth, AboutModal, ExportModal) and useRefill hook tests - 30% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Add useMedicationForm utility function tests - 30% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Add AppHeader tests and more schedule.ts tests - 32% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Changes before error encountered Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Fix page tests and add more tests - 326 tests passing, 34% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Add tests for ProfileModal, UserFilterModal, MedDetailModal - 361 tests, 36% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Add SharedSchedule tests - 366 tests, 39% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Expand page tests - 383 tests, 39% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Add MobileEditModal tests - 409 tests, 40% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Expand Dashboard and Schedule page tests - 427 tests, 40% coverage Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> * Fix code review issues - remove invalid remindEnabled property Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com> --------- Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com> Co-authored-by: DanielVolz <3275994+DanielVolz@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,203 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import { render, screen, fireEvent } from '@testing-library/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { SchedulePage } from '../../pages/SchedulePage';
|
||||
|
||||
// Mock the context
|
||||
vi.mock('../../context', () => ({
|
||||
useAppContext: () => ({
|
||||
meds: [],
|
||||
settings: {
|
||||
lowStockThreshold: 30,
|
||||
criticalStockThreshold: 7,
|
||||
expiryWarningDays: 30,
|
||||
lowStockDays: 7,
|
||||
normalStockDays: 30,
|
||||
highStockDays: 90
|
||||
},
|
||||
scheduleDays: 30,
|
||||
setScheduleDays: vi.fn(),
|
||||
showPastDays: false,
|
||||
setShowPastDays: vi.fn(),
|
||||
pastDays: [],
|
||||
futureDays: [],
|
||||
takenDoses: new Set(),
|
||||
markDoseTaken: vi.fn(),
|
||||
undoDoseTaken: vi.fn(),
|
||||
coverageByMed: {},
|
||||
depletionByMed: {},
|
||||
manuallyExpandedDays: new Set(),
|
||||
toggleDayCollapse: vi.fn(),
|
||||
openUserFilter: vi.fn()
|
||||
})
|
||||
}));
|
||||
|
||||
vi.mock('../../components/Auth', () => ({
|
||||
useAuth: () => ({
|
||||
user: { id: 1, username: 'testuser' }
|
||||
})
|
||||
}));
|
||||
|
||||
describe('SchedulePage', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('renders schedule page', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
// Should render the schedule section
|
||||
const section = document.querySelector('section.grid');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders schedule title', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(screen.getByText(/dashboard\.schedules\.title/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders day range selector', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
// Should have schedule days select dropdown
|
||||
const select = document.querySelector('.schedule-days-select');
|
||||
expect(select).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders timeline section', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
// Should have timeline div
|
||||
const timeline = document.querySelector('.timeline');
|
||||
expect(timeline).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('shows empty state when no medications', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
// With no meds, should show the schedule card but with empty timeline
|
||||
const card = document.querySelector('.card.schedule-full');
|
||||
expect(card).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders card head', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const cardHead = document.querySelector('.card-head');
|
||||
expect(cardHead).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders schedule days options', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const select = document.querySelector('.schedule-days-select');
|
||||
const options = select?.querySelectorAll('option');
|
||||
expect(options?.length).toBe(3);
|
||||
});
|
||||
|
||||
it('has 30, 90, 180 day options', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
expect(screen.getByText(/dashboard\.schedules\.1month/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/dashboard\.schedules\.3months/i)).toBeInTheDocument();
|
||||
expect(screen.getByText(/dashboard\.schedules\.6months/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('can change schedule days', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const select = document.querySelector('.schedule-days-select') as HTMLSelectElement;
|
||||
expect(select).toBeInTheDocument();
|
||||
|
||||
fireEvent.change(select, { target: { value: '90' } });
|
||||
});
|
||||
});
|
||||
|
||||
describe('SchedulePage structure', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
localStorage.clear();
|
||||
});
|
||||
|
||||
it('has heading element', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const heading = document.querySelector('h2');
|
||||
expect(heading).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders article element', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const article = document.querySelector('article');
|
||||
expect(article).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders section element', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const section = document.querySelector('section');
|
||||
expect(section).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders card with correct class', () => {
|
||||
render(
|
||||
<MemoryRouter>
|
||||
<SchedulePage />
|
||||
</MemoryRouter>
|
||||
);
|
||||
|
||||
const card = document.querySelector('.card.schedule-full');
|
||||
expect(card).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user