99 lines
5.7 KiB
JavaScript
99 lines
5.7 KiB
JavaScript
// Explicit opt-in against an owned synthetic direct-data portal only.
|
|
// Credentials/artifacts stay in the supplied private instance; no hotel requests.
|
|
const fs = require('node:fs');
|
|
const path = require('node:path');
|
|
const assert = require('node:assert/strict');
|
|
const {chromium} = require(process.env.ARR_TEST_PLAYWRIGHT_MODULE || 'playwright');
|
|
const root = path.resolve(process.env.ARR_REPLAY_TEST_ROOT || '');
|
|
assert(process.env.ARR_REPLAY_TEST_ROOT, 'explicit private instance required');
|
|
const instance = JSON.parse(fs.readFileSync(path.join(root, 'instance.json')));
|
|
assert.equal(instance.version, 'arr-local-direct-data/v1');
|
|
assert.equal(instance.root, root);
|
|
assert.equal(instance.oracle_connected, false);
|
|
const credentials = JSON.parse(fs.readFileSync(path.join(root, 'login.json')));
|
|
const source = {...instance, source_sha256:instance.fixture_sha256};
|
|
const mode = 'local-direct-data-simulation';
|
|
const base = 'http://127.0.0.1:8875';
|
|
|
|
(async () => {
|
|
const browser = await chromium.launch({headless:true,
|
|
...(process.env.ARR_TEST_CHROMIUM ? {executablePath:process.env.ARR_TEST_CHROMIUM} : {})});
|
|
try {
|
|
const context = await browser.newContext({viewport:{width:1440,height:1000}});
|
|
const page = await context.newPage();
|
|
const errors = [];
|
|
page.on('pageerror', error => errors.push(error.message));
|
|
await page.goto(base);
|
|
await page.locator('#username').fill(credentials.username);
|
|
await page.locator('#password').fill(credentials.password);
|
|
await page.locator('#login-submit').click();
|
|
await page.waitForURL(base + '/');
|
|
await page.waitForFunction(() => !document.querySelector('#arr-download-button').disabled);
|
|
assert.equal(await page.locator('#arr-download-date').inputValue(), source.report_date);
|
|
assert((await page.locator('.local-replay-banner').textContent()).includes('未连接 Oracle'));
|
|
const health = (await (await context.request.get(base+'/api/health')).json()).data;
|
|
assert.equal(health.processing_ready, true, 'manual upload remains available');
|
|
const config = (await (await context.request.get(base+'/api/arr-downloads')).json()).data;
|
|
assert.equal(config.environment, mode);
|
|
assert.equal(config.oracle_connected, false);
|
|
let task = config.latest_task;
|
|
let submitted = false;
|
|
if (!task) {
|
|
const post = page.waitForResponse(r => r.url() === base+'/api/arr-downloads' && r.request().method() === 'POST');
|
|
await page.locator('#arr-download-button').click();
|
|
const response = await post;
|
|
assert.equal(response.status(), 202);
|
|
task = (await response.json()).data;
|
|
submitted = true;
|
|
}
|
|
const deadline = Date.now()+90000;
|
|
while (Date.now()<deadline) {
|
|
task = (await (await context.request.get(base+'/api/arr-downloads/'+task.request_id)).json()).data;
|
|
if (!['queued','downloading','processing'].includes(task.status)) break;
|
|
await new Promise(r => setTimeout(r, 200));
|
|
}
|
|
assert.equal(task.status, 'succeeded');
|
|
const daily = await context.request.get(base+'/api/download/daily?job_id='+task.job_id);
|
|
assert.equal(daily.status(), 200);
|
|
const dailyBytes = await daily.body();
|
|
assert.equal(dailyBytes.subarray(0,2).toString(), 'PK');
|
|
fs.writeFileSync(path.join(root, 'verified-daily.xlsx'), dailyBytes, {mode:0o600});
|
|
let monthly;
|
|
const monthlyDeadline = Date.now()+90000;
|
|
while (Date.now()<monthlyDeadline) {
|
|
const response = await context.request.get(base+'/api/monthly-runs?month='+source.report_date.slice(0,7));
|
|
assert.equal(response.status(), 200);
|
|
const rows = (await response.json()).data;
|
|
if (rows.length) { monthly = rows[0]; break; }
|
|
await new Promise(r => setTimeout(r, 300));
|
|
}
|
|
assert(monthly, 'monthly outbox must publish');
|
|
const monthlyId = monthly.report_id ?? monthly.id;
|
|
assert(monthlyId, 'monthly result must have an identity');
|
|
const monthlyResponse = await context.request.get(base+'/api/download/monthly?report_id='+monthlyId);
|
|
assert.equal(monthlyResponse.status(), 200);
|
|
const monthlyBytes = await monthlyResponse.body();
|
|
assert.equal(monthlyBytes.subarray(0,2).toString(), 'PK');
|
|
fs.writeFileSync(path.join(root, 'verified-monthly.xlsx'), monthlyBytes, {mode:0o600});
|
|
await page.reload();
|
|
await page.waitForFunction(() => document.querySelector('#arr-download-feedback').classList.contains('is-success'));
|
|
await page.waitForFunction(() => getComputedStyle(document.querySelector("#panel-daily")).opacity === "1");
|
|
assert((await page.locator("#jobs-body").textContent()).includes("接口获取"));
|
|
await page.screenshot({path:path.join(root,'browser-desktop.png'),fullPage:true});
|
|
fs.chmodSync(path.join(root,'browser-desktop.png'),0o600);
|
|
await page.setViewportSize({width:390,height:844});
|
|
assert(await page.evaluate(() => document.documentElement.scrollWidth <= innerWidth));
|
|
await page.screenshot({path:path.join(root,'browser-mobile.png'),fullPage:true});
|
|
fs.chmodSync(path.join(root,'browser-mobile.png'),0o600);
|
|
assert.deepEqual(errors, []);
|
|
const result = {environment:mode, report_date:source.report_date,
|
|
source_records:source.source_records, source_sha256:source.source_sha256,
|
|
submitted, task_status:task.status, request_id:task.request_id, job_id:task.job_id,
|
|
daily_download:true, monthly_download:true, reload_preserved_success:true,
|
|
mobile_overflow:false, page_errors:0, oracle_connected:false};
|
|
fs.writeFileSync(path.join(root,'browser-verification.json'),JSON.stringify(result,null,2),{mode:0o600});
|
|
console.log(JSON.stringify(result));
|
|
await context.close();
|
|
} finally { await browser.close(); }
|
|
})().catch(error => { console.error(error.name, error.message); process.exitCode=1; });
|