80 lines
2.8 KiB
TypeScript
80 lines
2.8 KiB
TypeScript
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
import { db } from '../../../db/client.js';
|
|
import { getBootstrap } from '../../../services/app/bootstrap-service.js';
|
|
|
|
function selectRows(rows: unknown[]) {
|
|
return {
|
|
from: vi.fn().mockReturnValue({
|
|
where: vi.fn().mockReturnValue({
|
|
orderBy: vi.fn().mockResolvedValue(rows),
|
|
limit: vi.fn().mockResolvedValue(rows),
|
|
then: (resolve: (value: unknown) => unknown) => Promise.resolve(rows).then(resolve),
|
|
}),
|
|
orderBy: vi.fn().mockResolvedValue(rows),
|
|
}),
|
|
};
|
|
}
|
|
|
|
function mockSelectQueue(queue: unknown[][]) {
|
|
let index = 0;
|
|
vi.mocked(db.select).mockImplementation((() => {
|
|
const rows = index < queue.length ? queue[index]! : [];
|
|
index += 1;
|
|
return selectRows(rows);
|
|
}) as never);
|
|
}
|
|
|
|
function mockUpdate() {
|
|
return { set: vi.fn().mockReturnValue({ where: vi.fn().mockResolvedValue(undefined) }) } as never;
|
|
}
|
|
|
|
describe('bootstrap-service', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
});
|
|
|
|
it('includes wallet, inventory, shop catalog, ad benefits, and subscription in bootstrap', async () => {
|
|
mockSelectQueue([
|
|
[{ id: 'user-1', nickname: '多奇', avatarUrl: null, tier: 'free', xpTotal: 100 }],
|
|
// getProgressSummary
|
|
[{ id: 'user-1', tier: 'free', xpTotal: 100, activeTrackId: null, dailyAttemptsLeft: 5, dailyAttemptsDate: new Date(), checkInDays: 1, lastCheckInDate: new Date(), streakProtectedUntil: null, heartsRemaining: 5 }],
|
|
[{ tier: 'free', heartsRemaining: 5, heartsLastRestore: null }],
|
|
[{ streakDays: 1, streakLastDate: new Date() }],
|
|
[],
|
|
[{ id: 'user-1', tier: 'free', xpTotal: 100, activeTrackId: null, dailyAttemptsLeft: 5, dailyAttemptsDate: new Date(), checkInDays: 1, lastCheckInDate: new Date(), streakProtectedUntil: null, heartsRemaining: 5 }],
|
|
[{ used: 1, restored: 0 }],
|
|
// getThemeTracks
|
|
[],
|
|
// getClientSubscription
|
|
[],
|
|
// getCoinBalance
|
|
[{ coinsBalance: 260 }],
|
|
// getClientInventory
|
|
[{ itemId: 'hint_feather', quantity: 2, activeUntil: null, metadata: null }],
|
|
]);
|
|
vi.mocked(db.update).mockReturnValue(mockUpdate());
|
|
|
|
const result = await getBootstrap('user-1');
|
|
|
|
expect(result.user).toEqual({
|
|
id: 'user-1',
|
|
nickname: '多奇',
|
|
avatarUrl: null,
|
|
tier: 'free',
|
|
level: 2,
|
|
});
|
|
expect(result.wallet).toEqual({ coinsBalance: 260 });
|
|
expect(result.inventory.items).toEqual([
|
|
{ itemId: 'hint_feather', quantity: 2, activeUntil: null, metadata: null },
|
|
]);
|
|
expect(result.shop.products.map((product) => product.id)).toContain('hint-feather');
|
|
expect(result.shopBenefits).toBe(result.shop.benefits);
|
|
expect(result.subscription).toEqual({
|
|
status: 'none',
|
|
tier: 'free',
|
|
expiresAt: null,
|
|
autoRenew: false,
|
|
});
|
|
});
|
|
});
|