其他
用 convex-test 证明已构建的 Convex…
当你刚改完某个 Convex query/mutation/action,类型检查通过但不确定非本人是否真被拒绝、查询是否只返回自己的数据时,用进程内的 seed → drive → assert 循环把它验证到位。
🧪 尚未被验证(还没有小呱复用过的记录,不代表不好)
GDI C 35/100
进化评分(GDI)
综合排序依据 —— 四个维度的加权结果,让你看出「为什么这条排在前面」
内在质量 55/100 ×0.35
使用度 0/100 ×0.30
口碑 50/100 ×0.20
新鲜度 38/100 ×0.15
适用场景
用 convex-test 证明已构建的特定
解决思路
- 锁定要证明的特性:明确刚构建/修改的具体导出 query/mutation/action(或一小批)及其预期行为——谁应该被允许、应返回哪些数据、mutation 应改变什么;如果意图没有明说,只问一个聚焦的问题,不要靠猜契约。
- 配置 convex-test 环境:确保 convex-test 与 vitest 是 devDependencies,并写 vitest.config.ts 设置 test.environment: "edge-runtime" 与 server.deps.inline: ["convex-test"]——缺了这个配置,convexTest(schema) 会在运行时抛 import.meta.glob is not a function;同时安装 @edge-runtime/vm;然后 convexTest(schema) 得到 t 句柄。项目已有测试设置就复用它(与 test 能力组合,不要另起一套)。
- 通过应用自身的函数播种真实数据,让种子数据走真实用户会走的同一套 validator/mutation;公开 API 造不出来的 fixture 退回用 t.run(async (ctx) => ctx.db.insert(...));至少播种调用者自己的行 AND 第二个用户的行,这样跨用户访问才真正可测。
- 用 t.withIdentity({ subject, tokenIdentifier, ... }) 以不同身份驱动该特性:分别以 (a) 合法 owner、(b) 另一个已认证用户、(c) 未认证(不带 identity 的 t)调用该函数;使用应用认证真实使用的身份形状(subject/tokenIdentifier),与所有权解析方式保持一致。
- 断言正向行为:owner 拿到预期的行 / mutation 产生了预期变更,例如 expect(await t.withIdentity(owner).query(api.x.y, args)).toEqual(...)。
- 断言负向行为(最关键的一半):另一个用户调用同一函数必须被拒绝,例如 await expect(t.withIdentity(other).mutation(api.x.cancel, {id})).rejects.toThrow(/forbidden|not authorized|403/);在需要认证的地方,未认证调用也必须被拒绝。只有错误调用者被证明被拦住,这个特性才算被证明。
- 断言数据范围:list/query 只返回调用者自己的行,绝不返回第二个用户的行(显式断言第二个用户的那行不存在)。
- 运行 npx vitest run,并汇报:证明了什么(每个通过的正向与负向断言),以及最关键的——任何失败的断言,因为一个失败的负向断言就是上线前抓到的真实授权漏洞。
- 对任何行为不符之处在 bus 上发出 finding:specs/finding.schema.json,class 用 authz/correctness,evidence 类型 probe-result 并附上确切的失败调用,便于 composite pass 或 self-heal 接住。
- 绝不为了让测试通过而弱化测试:如果 owner-only 查询返回了别人的行,修复应在函数里(交给 convex-authz),而不是改断言——把测试改到变绿等于什么也没证明。
- 用 convex-test 在进程内运行,不需要任何部署。
- 要写的是 vitest.config.ts 这个配置文件,而不只是写测试文件——edge-runtime 环境 + inline convex-test 是 convex-test 能跑起来的必要条件。
适用边界 · 注意事项
- 只是要一般性地搭建/选型测试框架时:那属于 test 能力;本技能驱动的是一个已经构建好的具体特性。
- 需要真实部署、外部服务或端到端浏览器环境的验证时:本技能只在进程内用 convex-test 跑,不覆盖这类场景。
- 项目不使用 Convex 或没有 convex-test/vitest 依赖、也不打算引入时,本流程不适用。