添加LOTTERY_E2E环境变量来控制E2E测试相关功能, 包括绕过验证码、登录限制和钱包API URL验证, 同时更新composer.json以包含E2E专用的提供者和服务。
This commit is contained in:
85
e2e/tests/api/15.reconcile-job.spec.ts
Normal file
85
e2e/tests/api/15.reconcile-job.spec.ts
Normal file
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* E2E:主站超时 pending_reconcile → 后台 reconcile-jobs 扫描检出。
|
||||
*/
|
||||
|
||||
import { test, expect } from '@playwright/test';
|
||||
import {
|
||||
adminLoginViaBypass,
|
||||
adminCtxOf,
|
||||
configureWalletMock,
|
||||
playerCtxOf,
|
||||
playerLoginViaBypass,
|
||||
resetE2EPlayer,
|
||||
resetWalletMock,
|
||||
setMockWalletMode,
|
||||
} from './_helper';
|
||||
|
||||
const CURRENCY = (process.env.LOTTERY_DEFAULT_CURRENCY ?? 'NPR').toUpperCase();
|
||||
const MOCK_BASE = `http://127.0.0.1:${process.env.E2E_MOCK_WALLET_PORT ?? '5555'}`;
|
||||
|
||||
function isoDateOffset(days: number): string {
|
||||
const d = new Date();
|
||||
d.setDate(d.getDate() + days);
|
||||
return d.toISOString().slice(0, 10);
|
||||
}
|
||||
|
||||
test.beforeEach(async () => {
|
||||
await resetWalletMock();
|
||||
await setMockWalletMode('success');
|
||||
});
|
||||
|
||||
test('transfer-out 504 pending_reconcile → reconcile-jobs 扫描到差异项', async () => {
|
||||
test.setTimeout(120_000);
|
||||
|
||||
await resetE2EPlayer();
|
||||
await configureWalletMock(MOCK_BASE);
|
||||
await setMockWalletMode('504');
|
||||
|
||||
const session = await playerLoginViaBypass();
|
||||
const playerId = session.player.id;
|
||||
const idemKey = `e2e-reconcile-${Date.now()}`;
|
||||
|
||||
const player = await playerCtxOf(session.access_token);
|
||||
const tout = await player.post('/api/v1/wallet/transfer-out', {
|
||||
data: {
|
||||
amount: 10_000,
|
||||
currency: CURRENCY,
|
||||
idempotent_key: idemKey,
|
||||
},
|
||||
});
|
||||
const toutBody = (await tout.json()) as any;
|
||||
expect(Number(toutBody.code)).toBe(1002);
|
||||
await player.dispose();
|
||||
|
||||
const adminSession = await adminLoginViaBypass();
|
||||
const admin = await adminCtxOf(adminSession.accessToken);
|
||||
|
||||
const scan = await admin.post('/api/v1/admin/reconcile-jobs', {
|
||||
data: {
|
||||
reconcile_type: 'wallet_transfer',
|
||||
date_from: isoDateOffset(-1),
|
||||
date_to: isoDateOffset(0),
|
||||
player_id: playerId,
|
||||
},
|
||||
});
|
||||
expect(scan.ok(), `reconcile-jobs create status=${scan.status()}`).toBeTruthy();
|
||||
const scanBody = (await scan.json()) as any;
|
||||
expect(scanBody.code).toBe(0);
|
||||
expect(Number(scanBody.data.item_count)).toBeGreaterThanOrEqual(1);
|
||||
|
||||
const jobId = scanBody.data.id;
|
||||
const items = await admin.get(`/api/v1/admin/reconcile-jobs/${jobId}/items?size=20`);
|
||||
expect(items.ok()).toBeTruthy();
|
||||
const itemsBody = (await items.json()) as any;
|
||||
expect(itemsBody.code).toBe(0);
|
||||
expect(itemsBody.data.items.length).toBeGreaterThanOrEqual(1);
|
||||
|
||||
const hit = itemsBody.data.items.find(
|
||||
(it: any) =>
|
||||
String(it.side_a_ref ?? '').startsWith('TO_') ||
|
||||
String(it.side_b_ref ?? '').startsWith('TO_'),
|
||||
);
|
||||
expect(hit, '扫描结果应包含 pending_reconcile 转账单引用').toBeTruthy();
|
||||
|
||||
await admin.dispose();
|
||||
});
|
||||
Reference in New Issue
Block a user