补齐金币商店测试覆盖
This commit is contained in:
parent
6bf9db9820
commit
7aa53657fc
@ -78,7 +78,7 @@
|
|||||||
| G3-4 | 实现商店商品和购买接口 | [x] | 商品价格符合设计:提示羽毛 80、爱心补给 150、双倍 XP 250、连胜护盾 400、装扮 800-3000 |
|
| G3-4 | 实现商店商品和购买接口 | [x] | 商品价格符合设计:提示羽毛 80、爱心补给 150、双倍 XP 250、连胜护盾 400、装扮 800-3000 |
|
||||||
| G3-5 | 实现道具使用接口 | [x] | 爱心补给恢复满心,双倍 XP 药水 15 分钟生效,提示羽毛返回可排除选项,连胜护盾可保护断签 |
|
| G3-5 | 实现道具使用接口 | [x] | 爱心补给恢复满心,双倍 XP 药水 15 分钟生效,提示羽毛返回可排除选项,连胜护盾可保护断签 |
|
||||||
| G3-6 | 更新 bootstrap/shop DTO | [x] | 客户端能拿到金币、库存、可购买商品、广告商品、订阅权益 |
|
| G3-6 | 更新 bootstrap/shop DTO | [x] | 客户端能拿到金币、库存、可购买商品、广告商品、订阅权益 |
|
||||||
| G3-7 | 添加金币/商店测试 | [ ] | 覆盖余额不足、重复购买、使用道具、药水时效、库存扣减和流水记录 |
|
| G3-7 | 添加金币/商店测试 | [x] | 覆盖余额不足、重复购买、使用道具、药水时效、库存扣减和流水记录 |
|
||||||
|
|
||||||
验证记录(2026-05-13):G3-1 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/learning/challenge-service.test.ts` 仍在启动阶段被 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
验证记录(2026-05-13):G3-1 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/learning/challenge-service.test.ts` 仍在启动阶段被 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
||||||
验证记录(2026-05-13):G3-2 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/gamification/chest-service.test.ts src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/gamification-rules.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
验证记录(2026-05-13):G3-2 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/gamification/chest-service.test.ts src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/gamification-rules.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
||||||
@ -86,6 +86,7 @@
|
|||||||
验证记录(2026-05-13):G3-4 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/shop/shop-service.test.ts src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/gamification/inventory-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
验证记录(2026-05-13):G3-4 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/shop/shop-service.test.ts src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/gamification/inventory-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
||||||
验证记录(2026-05-13):G3-5 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/gamification/item-use-service.test.ts src/__tests__/services/gamification/inventory-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
验证记录(2026-05-13):G3-5 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/gamification/item-use-service.test.ts src/__tests__/services/gamification/inventory-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
||||||
验证记录(2026-05-13):G3-6 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/app/bootstrap-service.test.ts src/__tests__/services/gamification/inventory-service.test.ts src/__tests__/services/shop/shop-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
验证记录(2026-05-13):G3-6 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/app/bootstrap-service.test.ts src/__tests__/services/gamification/inventory-service.test.ts src/__tests__/services/shop/shop-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
||||||
|
验证记录(2026-05-13):G3-7 已通过 `./node_modules/.bin/tsc --noEmit`、`./node_modules/.bin/eslint .` 和 `git diff --check`;定向运行 `./node_modules/.bin/vitest run src/__tests__/services/gamification/coin-service.test.ts src/__tests__/services/shop/shop-service.test.ts src/__tests__/services/gamification/inventory-service.test.ts src/__tests__/services/gamification/item-use-service.test.ts` 仍在启动阶段被同一个 `@rolldown/binding-darwin-x64` 原生 binding 未签名问题阻塞。
|
||||||
|
|
||||||
## Phase G4:广告恢复与订阅权益对齐
|
## Phase G4:广告恢复与订阅权益对齐
|
||||||
|
|
||||||
|
|||||||
@ -89,10 +89,13 @@ describe('item-use-service', () => {
|
|||||||
clientRequestId: 'use-xp-1',
|
clientRequestId: 'use-xp-1',
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const activeUntilMs = Date.parse(result.effect.activeUntil ?? '');
|
||||||
|
const expectedMs = Date.now() + 15 * 60 * 1000;
|
||||||
expect(result.itemId).toBe('double_xp_potion');
|
expect(result.itemId).toBe('double_xp_potion');
|
||||||
expect(result.quantityRemaining).toBe(0);
|
expect(result.quantityRemaining).toBe(0);
|
||||||
expect(result.effect.type).toBe('double_xp');
|
expect(result.effect.type).toBe('double_xp');
|
||||||
expect(result.effect.activeUntil).toEqual(expect.any(String));
|
expect(result.effect.activeUntil).toEqual(expect.any(String));
|
||||||
|
expect(Math.abs(activeUntilMs - expectedMs)).toBeLessThan(2_000);
|
||||||
expect(updateSet).toHaveBeenCalledWith(expect.objectContaining({
|
expect(updateSet).toHaveBeenCalledWith(expect.objectContaining({
|
||||||
activeUntil: expect.any(Date),
|
activeUntil: expect.any(Date),
|
||||||
metadata: {
|
metadata: {
|
||||||
|
|||||||
@ -106,6 +106,29 @@ describe('shop-service', () => {
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('does not spend coins or grant inventory twice for duplicate purchases', async () => {
|
||||||
|
mockSelectQueue([
|
||||||
|
[{ id: 'coin-tx-1' }], // spendCoins: existing spend transaction
|
||||||
|
[{ coinsBalance: 220 }],
|
||||||
|
[{ id: 'item-tx-1' }], // grantInventoryItem: existing item grant
|
||||||
|
[{ itemId: 'hint_feather', quantity: 1, activeUntil: null, metadata: null }],
|
||||||
|
]);
|
||||||
|
|
||||||
|
const result = await purchaseShopProduct('user-1', 'hint-feather', 'request-1');
|
||||||
|
|
||||||
|
expect(result.product.id).toBe('hint-feather');
|
||||||
|
expect(result.coinsSpent).toBe(0);
|
||||||
|
expect(result.coinsBalance).toBe(220);
|
||||||
|
expect(result.item).toEqual({
|
||||||
|
itemId: 'hint_feather',
|
||||||
|
quantity: 1,
|
||||||
|
activeUntil: null,
|
||||||
|
metadata: null,
|
||||||
|
});
|
||||||
|
expect(db.insert).not.toHaveBeenCalled();
|
||||||
|
expect(db.update).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
it('throws when the user does not have enough coins', async () => {
|
it('throws when the user does not have enough coins', async () => {
|
||||||
mockSelectQueue([
|
mockSelectQueue([
|
||||||
[], // no existing spend
|
[], // no existing spend
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user