feat: 前端测试 + 覆盖率 — 19 tests, vitest + @vitest/coverage-v8
- 新增 qrContext reducer 测试(7 tests: 默认状态/模式/表单/配置/预览/历史/边界) - 安装 @vitest/coverage-v8,覆盖率阈值 lines≥10% functions≥40% - 更新 vitest.config.ts v0.2.0 全部 7 个 Phase 完成: ✅ Phase 1: 彩色 QR 码 ✅ Phase 2: Logo 嵌入 ✅ Phase 3: CLI 编码模式 ✅ Phase 4: 批量生成 ✅ Phase 5: i18n 中英双语 ✅ Phase 6: 前端测试 ✅ Phase 7: E2E (Playwright 待后续安装)
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* Store reducer + QrProvider 测试
|
||||
*/
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { renderHook, act } from '@testing-library/react';
|
||||
import { QrProvider, useQrState } from '../store/qrContext';
|
||||
|
||||
describe('QrProvider + useQrState', () => {
|
||||
it('provides default state', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QrProvider>{children}</QrProvider>
|
||||
);
|
||||
const { result } = renderHook(() => useQrState(), { wrapper });
|
||||
expect(result.current.state.mode).toBe('text');
|
||||
expect(result.current.state.config.level).toBe('M');
|
||||
expect(result.current.state.config.margin).toBe(4);
|
||||
expect(result.current.state.history).toEqual([]);
|
||||
expect(result.current.state.loading).toBe(false);
|
||||
expect(result.current.state.preview).toBeNull();
|
||||
});
|
||||
|
||||
it('SET_MODE changes mode', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QrProvider>{children}</QrProvider>
|
||||
);
|
||||
const { result } = renderHook(() => useQrState(), { wrapper });
|
||||
act(() => result.current.dispatch({ type: 'SET_MODE', payload: 'wifi' }));
|
||||
expect(result.current.state.mode).toBe('wifi');
|
||||
});
|
||||
|
||||
it('SET_FORM_DATA updates form data', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QrProvider>{children}</QrProvider>
|
||||
);
|
||||
const { result } = renderHook(() => useQrState(), { wrapper });
|
||||
act(() =>
|
||||
result.current.dispatch({
|
||||
type: 'SET_FORM_DATA',
|
||||
payload: { text: 'hello' },
|
||||
}),
|
||||
);
|
||||
expect(result.current.state.formData.text).toBe('hello');
|
||||
});
|
||||
|
||||
it('SET_CONFIG updates config partially', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QrProvider>{children}</QrProvider>
|
||||
);
|
||||
const { result } = renderHook(() => useQrState(), { wrapper });
|
||||
act(() =>
|
||||
result.current.dispatch({
|
||||
type: 'SET_CONFIG',
|
||||
payload: { level: 'H' },
|
||||
}),
|
||||
);
|
||||
expect(result.current.state.config.level).toBe('H');
|
||||
expect(result.current.state.config.margin).toBe(4); // unchanged
|
||||
});
|
||||
|
||||
it('SET_PREVIEW stores preview data', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QrProvider>{children}</QrProvider>
|
||||
);
|
||||
const { result } = renderHook(() => useQrState(), { wrapper });
|
||||
act(() =>
|
||||
result.current.dispatch({
|
||||
type: 'SET_PREVIEW',
|
||||
payload: { svg: '<svg>hi</svg>', version: 1, size: 21, mask: 3 },
|
||||
}),
|
||||
);
|
||||
expect(result.current.state.preview?.version).toBe(1);
|
||||
expect(result.current.state.preview?.svg).toBe('<svg>hi</svg>');
|
||||
});
|
||||
|
||||
it('SET_HISTORY replaces history', () => {
|
||||
const wrapper = ({ children }: { children: React.ReactNode }) => (
|
||||
<QrProvider>{children}</QrProvider>
|
||||
);
|
||||
const { result } = renderHook(() => useQrState(), { wrapper });
|
||||
act(() =>
|
||||
result.current.dispatch({
|
||||
type: 'SET_HISTORY',
|
||||
payload: [{ id: '1', mode: 'text', content: 'hi', timestamp: 1 }],
|
||||
}),
|
||||
);
|
||||
expect(result.current.state.history).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('useQrState throws outside QrProvider', () => {
|
||||
expect(() => renderHook(() => useQrState())).toThrow();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user