import { createHash } from 'node:crypto';
import { mkdir, readFile, writeFile } from 'node:fs/promises';
import { resolve } from 'node:path';
import { chromium } from '@playwright/test';
const baseUrl = process.env.REF_NATION_BETTING_URL ?? 'https://dev-sam-ref.hided.net/sam/';
const staticBaseUrl = process.env.REF_NATION_BETTING_STATIC_BASE_URL;
const username = process.env.REF_NATION_BETTING_USER ?? 'refuser1';
const passwordFile = process.env.REF_NATION_BETTING_PASSWORD_FILE;
const artifactRoot = resolve(process.env.REF_NATION_BETTING_ARTIFACT_DIR ?? 'test-results/reference-nation-betting');
if (!staticBaseUrl && !passwordFile) {
throw new Error('REF_NATION_BETTING_PASSWORD_FILE is required.');
}
const password = passwordFile ? (await readFile(passwordFile, 'utf8')).trim() : '';
const bettingList = {
result: true,
bettingList: {
7: {
id: 7,
type: 'bettingNation',
name: '천통국 예상',
finished: false,
selectCnt: 2,
isExclusive: false,
reqInheritancePoint: true,
openYearMonth: 2316,
closeYearMonth: 2340,
winner: null,
totalAmount: 800,
},
},
year: 193,
month: 1,
};
const bettingDetail = {
result: true,
bettingInfo: {
id: 7,
type: 'bettingNation',
name: '천통국 예상',
finished: false,
selectCnt: 2,
isExclusive: false,
reqInheritancePoint: true,
openYearMonth: 2316,
closeYearMonth: 2340,
candidates: [
{ title: '촉', info: '국력: 1200
장수 수: 8
도시 수: 5', isHtml: true },
{ title: '위', info: '국력: 1100
장수 수: 7
도시 수: 4', isHtml: true },
{ title: '오', info: '국력: 900
장수 수: 6
도시 수: 3', isHtml: true },
{ title: '연', info: '국력: 700
장수 수: 5
도시 수: 2', isHtml: true },
{ title: '양', info: '국력: 650
장수 수: 4
도시 수: 2', isHtml: true },
{ title: '형', info: '국력: 600
장수 수: 3
도시 수: 1', isHtml: true },
],
winner: null,
},
bettingDetail: [
['[-1]', 500],
['[0,1]', 200],
['[1,2]', 100],
],
myBetting: [['[0,1]', 50]],
remainPoint: 1200,
year: 193,
month: 1,
};
const login = async (context, page) => {
await page.goto(baseUrl, { waitUntil: 'networkidle', timeout: 60_000 });
const globalSalt = await page.locator('#global_salt').inputValue();
// The reference entrance polls install status and can keep the PHP session
// occupied. Leave it before the login request so the session lock is free.
await page.goto('about:blank');
await context.clearCookies();
const passwordHash = createHash('sha512')
.update(globalSalt + password + globalSalt)
.digest('hex');
const response = await context.request.post(new URL('api.php?path=Login/LoginByID', baseUrl).toString(), {
data: { username, password: passwordHash },
timeout: 60_000,
});
const result = await response.json();
if (!response.ok() || result.result !== true) {
throw new Error('Reference login failed.');
}
};
const installBettingFixture = async (page) => {
await page.route('**/api.php*', async (route) => {
const path = new URL(route.request().url()).searchParams.get('path');
if (path === 'Betting/GetBettingList') {
await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(bettingList) });
return;
}
if (path === 'Betting/GetBettingDetail') {
await route.fulfill({
status: 200,
contentType: 'application/json',
body: JSON.stringify(bettingDetail),
});
return;
}
await route.continue();
});
};
const mountStaticReference = async (page) => {
const hweUrl = new URL('hwe/', staticBaseUrl);
const assetUrl = new URL('dist_js/hwe_dynamic/vue/', staticBaseUrl);
await page.setContent(
`