fe17886ac4
- 车辆 / 洗车 / 加油 / 充电 / 保养 / 保险 完整 CRUD + 软删 - AI 截图识别(5 类型 OCR schema):OpenAI 兼容 + MiniMax M3 - 化学品 / Grocy 实例对接 + 库存镜像同步 - 仪表盘:30 天频次 + 健康度 + 同比环比 + 油价趋势 + 年均养护 - 月度报表:Excel 6 sheet + PDF - PWA:manifest / SW / 离线缓存 / iOS 引导 - 安全:bcrypt + CSRF + 登录锁定(IP/用户/全局三级)+ 401 自动跳登录 + 表单草稿 - 高 ROI 8 功能:里程/提醒/成本/搜索/标签/通知/同比/成就 - 3 个新 migration(0016/0017/0018)+ 18 个迁移全幂等 - 101/101 测试通过(含 ipRateLimit / CSRF / retry / stats / tags / notifications) - 部署:宝塔面板文档 + PM2 + Nginx
64 lines
2.4 KiB
JavaScript
64 lines
2.4 KiB
JavaScript
// server/test/challenge.test.js
|
||
import { describe, it, expect } from 'vitest';
|
||
import { verifyChallenge } from '../src/services/challenge.js';
|
||
|
||
describe('verifyChallenge()', () => {
|
||
it('加法正确', () => {
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '+', answer: 8 })).toBe(true);
|
||
});
|
||
|
||
it('加法错误', () => {
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '+', answer: 7 })).toBe(false);
|
||
});
|
||
|
||
it('减法正确(含负数)', () => {
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '-', answer: -2 })).toBe(true);
|
||
});
|
||
|
||
it('乘法正确', () => {
|
||
expect(verifyChallenge({ a: 4, b: 6, op: '*', answer: 24 })).toBe(true);
|
||
});
|
||
|
||
it('answer 是字符串数字也能通过', () => {
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '+', answer: '8' })).toBe(true);
|
||
});
|
||
|
||
it('answer 是非数字 → 拒绝', () => {
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '+', answer: 'abc' })).toBe(false);
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '+', answer: null })).toBe(false);
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '+', answer: undefined })).toBe(false);
|
||
});
|
||
|
||
it('a/b 是非数字 → 拒绝', () => {
|
||
expect(verifyChallenge({ a: 'x', b: 5, op: '+', answer: 5 })).toBe(false);
|
||
// b=null 会被 Number(null)=0,3+0=3=answer 3 → 实际算"合法",非 bug
|
||
// 我们用更明确的 NaN 来验证
|
||
expect(verifyChallenge({ a: 3, b: 'abc', op: '+', answer: 3 })).toBe(false);
|
||
});
|
||
|
||
it('非法 op → 拒绝', () => {
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '/', answer: 0.6 })).toBe(false);
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '**', answer: 243 })).toBe(false);
|
||
expect(verifyChallenge({ a: 3, b: 5, op: '', answer: 8 })).toBe(false);
|
||
});
|
||
|
||
it('challenge 是 null/undefined → 拒绝', () => {
|
||
expect(verifyChallenge(null)).toBe(false);
|
||
expect(verifyChallenge(undefined)).toBe(false);
|
||
expect(verifyChallenge('string')).toBe(false);
|
||
});
|
||
|
||
it('a/b 字符串数字 → 也能算', () => {
|
||
expect(verifyChallenge({ a: '3', b: '5', op: '+', answer: 8 })).toBe(true);
|
||
});
|
||
|
||
it('空对象 → 拒绝', () => {
|
||
expect(verifyChallenge({})).toBe(false);
|
||
});
|
||
|
||
it('缺失字段 → 拒绝', () => {
|
||
expect(verifyChallenge({ a: 3, b: 5, answer: 8 })).toBe(false); // 缺 op
|
||
expect(verifyChallenge({ a: 3, op: '+', answer: 3 })).toBe(false); // 缺 b
|
||
});
|
||
});
|