Skip to content

Commit 62fe80c

Browse files
esmcelroyCopilot
andcommitted
test: increase coverage from 22% to 56% with 43 new unit tests
- imageUtils.ts: 4% → 100% (28 tests for all canvas operations) - useDarkMode.ts: 0% → 93% (8 tests for theme hook) - App.tsx: 0% → 24% (7 tests for rendering and interactions) - Raised coverage thresholds to 50% lines/statements, 60% branches - Total: 80 unit tests + 17 E2E tests = 97 tests Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent cb87884 commit 62fe80c

4 files changed

Lines changed: 641 additions & 7 deletions

File tree

src/__tests__/App.test.tsx

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2+
import { render, screen } from '@testing-library/react';
3+
4+
// Mock dependencies before importing App
5+
vi.mock('../lib/imageUtils', () => ({
6+
getImageDimensions: vi.fn().mockResolvedValue({ width: 100, height: 100 }),
7+
findMaxAspectRatio: vi.fn().mockReturnValue(1),
8+
padImageToAspectRatio: vi.fn().mockResolvedValue('data:image/png;base64,mock'),
9+
}));
10+
11+
vi.mock('../lib/heicUtils', () => ({
12+
processFilesForHeic: vi.fn().mockResolvedValue({ converted: [], errors: [] }),
13+
}));
14+
15+
vi.mock('jszip', () => {
16+
return {
17+
default: vi.fn().mockImplementation(() => ({
18+
file: vi.fn(),
19+
generateAsync: vi.fn().mockResolvedValue(new Blob()),
20+
})),
21+
};
22+
});
23+
24+
import App from '../App';
25+
26+
describe('App', () => {
27+
const originalMatchMedia = window.matchMedia;
28+
29+
beforeEach(() => {
30+
localStorage.clear();
31+
document.documentElement.classList.remove('dark');
32+
window.matchMedia = vi.fn(() => ({
33+
matches: false,
34+
media: '(prefers-color-scheme: dark)',
35+
onchange: null,
36+
addEventListener: vi.fn(),
37+
removeEventListener: vi.fn(),
38+
addListener: vi.fn(),
39+
removeListener: vi.fn(),
40+
dispatchEvent: vi.fn(),
41+
})) as any;
42+
});
43+
44+
afterEach(() => {
45+
window.matchMedia = originalMatchMedia;
46+
});
47+
48+
it('renders with header "Squarify"', () => {
49+
render(<App />);
50+
expect(screen.getByText('Squarify')).toBeInTheDocument();
51+
});
52+
53+
it('renders the subtitle', () => {
54+
render(<App />);
55+
expect(screen.getByText('Pad photos to a uniform aspect ratio')).toBeInTheDocument();
56+
});
57+
58+
it('renders upload zone', () => {
59+
render(<App />);
60+
expect(screen.getByText(/drop photos here|click to browse/i)).toBeInTheDocument();
61+
});
62+
63+
it('renders settings panel with Process button', () => {
64+
render(<App />);
65+
expect(screen.getByText('Process Images')).toBeInTheDocument();
66+
});
67+
68+
it('renders theme toggle buttons', () => {
69+
render(<App />);
70+
expect(screen.getByTitle('Light')).toBeInTheDocument();
71+
expect(screen.getByTitle('Dark')).toBeInTheDocument();
72+
expect(screen.getByTitle('System')).toBeInTheDocument();
73+
});
74+
75+
it('process button is disabled when no photos', () => {
76+
render(<App />);
77+
const processButton = screen.getByText('Process Images').closest('button');
78+
expect(processButton).toBeDisabled();
79+
});
80+
81+
it('does not show clear all button when no photos', () => {
82+
render(<App />);
83+
expect(screen.queryByText('Clear all')).not.toBeInTheDocument();
84+
});
85+
});

0 commit comments

Comments
 (0)