// 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() 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() 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; });