diff --git a/web/package-lock.json b/web/package-lock.json index 8bfb5cd..2a4180e 100644 --- a/web/package-lock.json +++ b/web/package-lock.json @@ -8,7 +8,6 @@ "name": "web", "version": "0.1.0", "dependencies": { - "@types/react-router-dom": "^5.3.3", "react": "^19.2.4", "react-dom": "^19.2.4", "react-router-dom": "^7.13.1" @@ -835,12 +834,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/history": { - "version": "4.7.11", - "resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz", - "integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==", - "license": "MIT" - }, "node_modules/@types/node": { "version": "25.5.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.2.tgz", @@ -855,6 +848,7 @@ "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==", + "dev": true, "license": "MIT", "dependencies": { "csstype": "^3.2.2" @@ -870,27 +864,6 @@ "@types/react": "^19.2.0" } }, - "node_modules/@types/react-router": { - "version": "5.1.20", - "resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz", - "integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==", - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*" - } - }, - "node_modules/@types/react-router-dom": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz", - "integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==", - "license": "MIT", - "dependencies": { - "@types/history": "^4.7.11", - "@types/react": "*", - "@types/react-router": "*" - } - }, "node_modules/@vitejs/plugin-react": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.1.tgz", @@ -1162,6 +1135,7 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, "license": "MIT" }, "node_modules/data-urls": { diff --git a/web/src/pages/TimeOff.test.tsx b/web/src/pages/TimeOff.test.tsx index a8ef385..c37e4b9 100644 --- a/web/src/pages/TimeOff.test.tsx +++ b/web/src/pages/TimeOff.test.tsx @@ -1,11 +1,12 @@ import React from 'react'; import { render, screen, fireEvent, waitFor } from '@testing-library/react'; +import { vi, type Mock } from 'vitest'; import { MemoryRouter } from 'react-router-dom'; import TimeOff from './TimeOff'; import { api, TimeOffRequest, ApiError } from '../api'; import { AuthProvider } from '../auth'; -jest.mock('../api', () => { +vi.mock('../api', () => { class MockApiError extends Error { status: number; data: any; @@ -17,24 +18,24 @@ jest.mock('../api', () => { } return { api: { - listTimeOff: jest.fn(), - createTimeOff: jest.fn(), - updateTimeOff: jest.fn(), - deleteTimeOff: jest.fn(), - reviewTimeOff: jest.fn(), - getRemovedShifts: jest.fn(), - listVolunteers: jest.fn(), + listTimeOff: vi.fn(), + createTimeOff: vi.fn(), + updateTimeOff: vi.fn(), + deleteTimeOff: vi.fn(), + reviewTimeOff: vi.fn(), + getRemovedShifts: vi.fn(), + listVolunteers: vi.fn(), }, ApiError: MockApiError, }; }); -const mockListTimeOff = api.listTimeOff as jest.Mock; -const mockCreateTimeOff = api.createTimeOff as jest.Mock; -const mockDeleteTimeOff = api.deleteTimeOff as jest.Mock; -const mockReviewTimeOff = api.reviewTimeOff as jest.Mock; -const mockGetRemovedShifts = api.getRemovedShifts as jest.Mock; -const mockListVolunteers = api.listVolunteers as jest.Mock; +const mockListTimeOff = api.listTimeOff as Mock; +const mockCreateTimeOff = api.createTimeOff as Mock; +const mockDeleteTimeOff = api.deleteTimeOff as Mock; +const mockReviewTimeOff = api.reviewTimeOff as Mock; +const mockGetRemovedShifts = api.getRemovedShifts as Mock; +const mockListVolunteers = api.listVolunteers as Mock; function buildFakeJWT(payload: object): string { const header = btoa(JSON.stringify({ alg: 'HS256', typ: 'JWT' })); @@ -90,7 +91,7 @@ function renderAsAdmin() { } beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); localStorage.clear(); mockListVolunteers.mockResolvedValue([]); }); @@ -147,10 +148,10 @@ describe('TimeOff page', () => { it('shows conflict warning on 409 and allows confirmation', async () => { mockListTimeOff.mockResolvedValue([]); - const { ApiError: MockApiError } = jest.requireMock('../api'); + const { ApiError: MockApiError } = await vi.importMock('../api'); mockCreateTimeOff .mockRejectedValueOnce( - new MockApiError('conflict', 409, { + new (MockApiError as any)('conflict', 409, { message: 'Time off conflicts with assigned shifts.', conflicts: [ { instance_id: 100, name: 'Morning Walk', date: '2026-06-01', start_time: '08:00', end_time: '12:00' },