mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-26 01:44:53 +10:00
6a01207b6b
Adds ~1000 tests to bring the previously-untested packages and apps under coverage: - packages/utils — string, color, date, file, level, locale, sanitize, field, html, network-icons, rate-limit, url, url-security, monorepo, resume/patch, resume/docx/link-utils, style helpers (~97% on the testable utility files) - packages/ui — 28 component test files plus the use-controlled-state, use-mobile, use-confirm, use-prompt hooks (95% statements) - packages/pdf — shared template helpers (filtering, columns, picture, metrics, section-links, page-size, rich-text-html, section-title) - packages/schema — resumeDataSchema, page, templates, default - packages/fonts — expanded coverage on font helpers - packages/ai — resume sanitize and extraction template - packages/api — resume-access-policy - apps/web — error-message, locale, theme, pwa, dialogs/store, and the resume/move-item / section-actions / make-section-item helpers Adds jsdom polyfills (ResizeObserver, IntersectionObserver, scrollIntoView, matchMedia) and an explicit React Testing Library cleanup hook to vitest.setup.ts so portal- and overlay-based components work without per-test setup.
76 lines
2.1 KiB
TypeScript
76 lines
2.1 KiB
TypeScript
import { act, renderHook } from "@testing-library/react";
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
import { useIsMobile } from "./use-mobile";
|
|
|
|
type ChangeListener = (e: { matches: boolean }) => void;
|
|
|
|
describe("useIsMobile", () => {
|
|
let listeners: ChangeListener[];
|
|
let matches: boolean;
|
|
let originalMatchMedia: typeof window.matchMedia;
|
|
|
|
beforeEach(() => {
|
|
listeners = [];
|
|
matches = false;
|
|
originalMatchMedia = window.matchMedia;
|
|
window.matchMedia = vi.fn().mockImplementation((query: string) => ({
|
|
matches,
|
|
media: query,
|
|
onchange: null,
|
|
addEventListener: vi.fn((_event: string, listener: ChangeListener) => {
|
|
listeners.push(listener);
|
|
}),
|
|
removeEventListener: vi.fn((_event: string, listener: ChangeListener) => {
|
|
const idx = listeners.indexOf(listener);
|
|
if (idx >= 0) listeners.splice(idx, 1);
|
|
}),
|
|
addListener: vi.fn(),
|
|
removeListener: vi.fn(),
|
|
dispatchEvent: vi.fn(),
|
|
}));
|
|
});
|
|
|
|
afterEach(() => {
|
|
window.matchMedia = originalMatchMedia;
|
|
});
|
|
|
|
it("returns false when matchMedia.matches is false", () => {
|
|
matches = false;
|
|
const { result } = renderHook(() => useIsMobile());
|
|
expect(result.current).toBe(false);
|
|
});
|
|
|
|
it("returns true when matchMedia.matches is true", () => {
|
|
matches = true;
|
|
const { result } = renderHook(() => useIsMobile());
|
|
expect(result.current).toBe(true);
|
|
});
|
|
|
|
it("uses the documented mobile breakpoint of 768px", () => {
|
|
renderHook(() => useIsMobile());
|
|
expect(window.matchMedia).toHaveBeenCalledWith("(max-width: 767px)");
|
|
});
|
|
|
|
it("updates when the media query changes", () => {
|
|
const { result } = renderHook(() => useIsMobile());
|
|
expect(result.current).toBe(false);
|
|
|
|
act(() => {
|
|
for (const listener of listeners) listener({ matches: true });
|
|
});
|
|
expect(result.current).toBe(true);
|
|
|
|
act(() => {
|
|
for (const listener of listeners) listener({ matches: false });
|
|
});
|
|
expect(result.current).toBe(false);
|
|
});
|
|
|
|
it("removes the change listener on unmount", () => {
|
|
const { unmount } = renderHook(() => useIsMobile());
|
|
expect(listeners).toHaveLength(1);
|
|
unmount();
|
|
expect(listeners).toHaveLength(0);
|
|
});
|
|
});
|