添加LOTTERY_E2E环境变量来控制E2E测试相关功能, 包括绕过验证码、登录限制和钱包API URL验证, 同时更新composer.json以包含E2E专用的提供者和服务。
This commit is contained in:
129
e2e/tests/api/helpers/draw-settlement.ts
Normal file
129
e2e/tests/api/helpers/draw-settlement.ts
Normal file
@@ -0,0 +1,129 @@
|
||||
/**
|
||||
* 开奖 → 结算 → 派彩 确定性流水线(poll + tick,避免 test.skip)。
|
||||
*/
|
||||
|
||||
import { expect, type APIRequestContext } from '@playwright/test';
|
||||
import {
|
||||
buildAllResultItems,
|
||||
finishDrawCooldown,
|
||||
forceCloseDraw,
|
||||
resolveDrawId,
|
||||
tickDraws,
|
||||
waitForDrawStatus,
|
||||
} from '../_helper';
|
||||
|
||||
const CURRENCY = (process.env.LOTTERY_DEFAULT_CURRENCY ?? 'NPR').toUpperCase();
|
||||
|
||||
export interface DrawSettlementResult {
|
||||
drawNo: string;
|
||||
drawId: number;
|
||||
batchId: number;
|
||||
balanceBefore?: number;
|
||||
balanceAfter?: number;
|
||||
}
|
||||
|
||||
export async function runWalletDrawSettlement(params: {
|
||||
adminToken: string;
|
||||
playerToken: string;
|
||||
drawNo: string;
|
||||
betNumber?: string;
|
||||
betAmount?: number;
|
||||
balanceBefore?: number;
|
||||
expectWalletIncrease?: boolean;
|
||||
}): Promise<DrawSettlementResult> {
|
||||
const drawNo = params.drawNo;
|
||||
const betNumber = params.betNumber ?? '1234';
|
||||
const betAmount = params.betAmount ?? 10_000;
|
||||
|
||||
const player = await pwPlayerCtx(params.playerToken);
|
||||
let balanceBefore: number | undefined;
|
||||
if (params.expectWalletIncrease !== false) {
|
||||
balanceBefore =
|
||||
params.balanceBefore ??
|
||||
Number((await (await player.get('/api/v1/wallet/balance')).json()).data.balance);
|
||||
}
|
||||
|
||||
const place = await player.post('/api/v1/ticket/place', {
|
||||
data: {
|
||||
draw_id: drawNo,
|
||||
currency_code: CURRENCY,
|
||||
client_trace_id: `e2e-settle-${Date.now()}`,
|
||||
lines: [{ number: betNumber, play_code: 'straight', amount: betAmount }],
|
||||
},
|
||||
});
|
||||
expect(place.ok(), `place status=${place.status()}`).toBeTruthy();
|
||||
const placeBody = (await place.json()) as any;
|
||||
expect(placeBody.code).toBe(0);
|
||||
await player.dispose();
|
||||
|
||||
await forceCloseDraw(drawNo);
|
||||
await waitForDrawStatus(drawNo, ['closed', 'review', 'cooldown', 'settling', 'settled'], 15);
|
||||
|
||||
const admin = await pwAdminCtx(params.adminToken);
|
||||
const drawId = await resolveDrawId(admin, drawNo);
|
||||
|
||||
const store = await admin.post(`/api/v1/admin/draws/${drawId}/result-batches`, {
|
||||
data: { items: buildAllResultItems(betNumber) },
|
||||
});
|
||||
expect(store.ok(), `store batch status=${store.status()}`).toBeTruthy();
|
||||
const storeBody = (await store.json()) as any;
|
||||
expect(storeBody.code).toBe(0);
|
||||
const batchId: number = storeBody.data.batch.id;
|
||||
|
||||
const pub = await admin.post(`/api/v1/admin/draws/${drawId}/result-batches/${batchId}/publish`);
|
||||
expect(pub.ok(), `publish status=${pub.status()}`).toBeTruthy();
|
||||
const pubBody = (await pub.json()) as any;
|
||||
expect(pubBody.code).toBe(0);
|
||||
|
||||
await finishDrawCooldown(drawNo);
|
||||
await waitForDrawStatus(drawNo, ['settling', 'settled'], 25);
|
||||
|
||||
const insp = await waitForDrawStatus(drawNo, ['settled'], 25);
|
||||
if (String(insp.data?.status ?? insp.status) !== 'settled') {
|
||||
const settle = await admin.post(`/api/v1/admin/draws/${drawId}/settlement/run`);
|
||||
const settleBody = (await settle.json()) as any;
|
||||
if (settleBody.code !== 0) {
|
||||
await tickDraws();
|
||||
}
|
||||
await waitForDrawStatus(drawNo, ['settled'], 25);
|
||||
}
|
||||
|
||||
const list = await admin.get(`/api/v1/admin/settlement-batches?size=20`);
|
||||
const lb = (await list.json()) as any;
|
||||
const ourBatch = lb.data.items.find((b: any) => b.draw_id === drawId);
|
||||
if (ourBatch && ourBatch.status === 'pending_review') {
|
||||
await admin.post(`/api/v1/admin/settlement-batches/${ourBatch.id}/approve`, {
|
||||
data: { remark: 'e2e approve' },
|
||||
});
|
||||
await admin.post(`/api/v1/admin/settlement-batches/${ourBatch.id}/payout`);
|
||||
} else {
|
||||
await tickDraws();
|
||||
await waitForDrawStatus(drawNo, ['settled'], 15);
|
||||
}
|
||||
|
||||
await admin.dispose();
|
||||
|
||||
let balanceAfter: number | undefined;
|
||||
if (params.expectWalletIncrease !== false) {
|
||||
const player2 = await pwPlayerCtx(params.playerToken);
|
||||
const bal1 = (await (await player2.get('/api/v1/wallet/balance')).json()) as any;
|
||||
balanceAfter = Number(bal1.data.balance);
|
||||
await player2.dispose();
|
||||
}
|
||||
|
||||
return { drawNo, drawId, batchId, balanceBefore, balanceAfter };
|
||||
}
|
||||
|
||||
async function pwAdminCtx(token: string): Promise<APIRequestContext> {
|
||||
const { request: pwRequest } = await import('@playwright/test');
|
||||
return pwRequest.newContext({
|
||||
extraHTTPHeaders: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
}
|
||||
|
||||
async function pwPlayerCtx(token: string): Promise<APIRequestContext> {
|
||||
const { request: pwRequest } = await import('@playwright/test');
|
||||
return pwRequest.newContext({
|
||||
extraHTTPHeaders: { Authorization: `Bearer ${token}` },
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user