Files
ARR-2.0-0918/tests/javascript/arr_download_progress.cjs
T

147 lines
8.3 KiB
JavaScript

// Actual progress rendering against synthetic task snapshots; no Oracle requests.
const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const path = require('node:path');
const vm = require('node:vm');
const {harness,response,scopedKey} = require('./helpers/arr_ui_harness.cjs');
const localeContext=vm.createContext({window:{},document:{readyState:'loading',addEventListener(){}}});
vm.runInContext(fs.readFileSync(path.resolve(__dirname,'../../arr_web/static/i18n.js'),'utf8'),localeContext);
const catalog=localeContext.window.ARRI18n.CATALOG;
const date='2026-09-16';
const task={request_id:'d'.repeat(32),report_date:date,status:'downloading',job_id:null,can_retry:false};
const progress=(phase,completed,total,percent)=>({phase,completed,total,percent,updated_at:'2026-10-08T05:00:00Z'});
function setup(respond=()=>{throw new Error('rendering must not send a request');}) {
const h=harness(respond);
h.i18n.t=(key,values={})=>(catalog[key]?.[0]||key).replace(/\{(\w+)\}/g,(_,name)=>String(values[name]??''));
return h;
}
async function render(h,snapshot) {
await h.acceptARRDownloadTask(snapshot,{sync:false});
}
test('unknown reservation totals remain indeterminate and never invent zero totals or percentages',async()=>{
const h=setup();
for(const phase of ['queued','searching','fetching']) {
await render(h,{...task,status:phase==='queued'?'queued':'downloading',acquisition_progress:progress(phase,0,null,null)});
assert.equal(h.element('#arr-acquisition-progress').hidden,false);
assert.equal(h.element('#arr-acquisition-track').getAttribute('aria-valuenow'),null);
assert.equal(h.element('#arr-acquisition-track').classList.contains('is-indeterminate'),true);
assert.equal(h.element('#arr-acquisition-percent').hidden,true);
assert.doesNotMatch(h.element('#arr-acquisition-detail').textContent,/0\s*\/\s*0|%/);
}
assert.equal(h.calls.length,0);
});
test('a real 58 of 85 snapshot renders server progress and accessible counts',async()=>{
const h=setup();
await render(h,{...task,acquisition_progress:progress('fetching',58,85,68)});
assert.equal(h.element('#arr-acquisition-status').textContent,'取数中');
assert.equal(h.element('#arr-acquisition-detail').textContent,'已获取 58 / 85 笔');
assert.equal(h.element('#arr-acquisition-percent').textContent,'68%');
assert.equal(h.element('#arr-acquisition-track').getAttribute('aria-valuenow'),'68');
assert.match(h.element('#arr-acquisition-track').getAttribute('aria-valuetext'),/58 \/ 85.*68%/);
assert.equal(h.element('#arr-acquisition-track').classList.contains('is-indeterminate'),false);
assert.equal(h.element('#arr-acquisition-bar').style.width,'68%');
});
test('all records still show 99 percent while completeness is being verified',async()=>{
const h=setup();
for(const percent of [99,100]) {
await render(h,{...task,acquisition_progress:progress('verifying',85,85,percent)});
assert.equal(h.element('#arr-acquisition-status').textContent,'取数中');
assert.equal(h.element('#arr-acquisition-percent').textContent,'99%');
assert.match(h.element('#arr-acquisition-detail').textContent,/85 \/ 85.*正在校验完整性/);
assert.equal(h.element('#arr-acquisition-track').getAttribute('aria-valuenow'),'99');
}
});
test('a verified empty result is a real completed zero total',async()=>{
const h=setup();
await render(h,{...task,status:'succeeded',acquisition_progress:progress('completed',0,0,100)});
assert.equal(h.element('#arr-acquisition-status').textContent,'已完成');
assert.equal(h.element('#arr-acquisition-detail').textContent,'已获取 0 / 0 笔');
assert.equal(h.element('#arr-acquisition-percent').textContent,'100%');
});
test('completed retrieval remains distinct from pending field and price review',async()=>{
for(const status of ['needs_data_review','needs_review','processing','succeeded']) {
const h=setup(url=>{
assert.equal(url,`/api/arr-downloads/${task.request_id}/data-review`);
return response(200,{request_id:task.request_id,report_date:date,status:'editing',items:[],pending_count:0,total_count:0});
});
await render(h,{...task,status,job_id:status==='needs_data_review'?null:'fixture-job',acquisition_progress:progress('completed',85,85,100)});
assert.equal(h.element('#arr-acquisition-status').textContent,'已完成');
assert.equal(h.element('#arr-acquisition-percent').textContent,'100%');
assert.equal(h.element('#arr-acquisition-detail').textContent,'已获取 85 / 85 笔');
if(status==='needs_data_review') assert.equal(h.element('#arr-download-data-review').hidden,false);
if(status==='needs_review') assert.equal(h.element('#arr-download-review').hidden,false);
assert.doesNotMatch(h.element('#arr-acquisition-detail').textContent,/生成|报表已完成/);
}
});
test('failed and interrupted retrieval never appear as 100 percent complete',async()=>{
const h=setup();
for(const phase of ['failed','interrupted']) {
await render(h,{...task,status:phase,acquisition_progress:progress(phase,85,85,100)});
assert.equal(h.element('#arr-acquisition-status').textContent,phase==='failed'?'取数失败':'取数中断');
assert.equal(h.element('#arr-acquisition-progress').classList.contains('is-completed'),false);
assert.equal(h.element('#arr-acquisition-progress').classList.contains('is-error'),true);
assert.equal(h.element('#arr-acquisition-percent').textContent,'99%');
assert.equal(h.element('#arr-acquisition-track').classList.contains('is-indeterminate'),false);
}
});
test('legacy metadata absence shows truthful status without fabricated counts',async()=>{
const h=setup();
await render(h,task);
assert.equal(h.element('#arr-acquisition-status').textContent,'取数中');
assert.equal(h.element('#arr-acquisition-track').classList.contains('is-indeterminate'),true);
assert.equal(h.element('#arr-acquisition-detail').textContent,'正在获取预订数据…');
await render(h,{...task,status:'needs_review',job_id:'fixture-job'});
assert.equal(h.element('#arr-acquisition-status').textContent,'已完成');
assert.equal(h.element('#arr-acquisition-percent').hidden,true);
assert.equal(h.element('#arr-acquisition-track').hidden,true);
assert.equal(h.element('#arr-acquisition-detail').textContent,'该任务未记录取数笔数。');
for(const status of ['failed','interrupted']) {
await render(h,{...task,status});
assert.equal(h.element('#arr-acquisition-percent').hidden,true);
assert.equal(h.element('#arr-acquisition-track').hidden,true);
assert.notEqual(h.element('#arr-acquisition-status').textContent,'已完成');
}
});
test('progress hides for another selected date and returns for the original running task',async()=>{
const h=setup();
await render(h,{...task,acquisition_progress:progress('fetching',58,85,68)});
h.element('#arr-download-date').value='2026-09-17';
h.handleARRDownloadDateChange();
assert.equal(h.element('#arr-acquisition-progress').hidden,true);
assert.equal(h.state.arrDownloadTask.report_date,date);
assert.match(h.element('#arr-download-status').textContent,/2026-09-16/);
h.element('#arr-download-date').value=date;
h.handleARRDownloadDateChange();
assert.equal(h.element('#arr-acquisition-progress').hidden,false);
assert.equal(h.element('#arr-acquisition-percent').textContent,'68%');
assert.equal(h.calls.length,0);
});
test('context changes hide the former task progress and empty selection has none',async()=>{
const h=setup(()=>response(200,{context_id:'new-context',ready:true,default_date:date,pending_reviews:[],latest_task:null}));
h.state.arrDownloadContextId='old-context';
h.state.arrDownloadStorageKey=scopedKey('old-context');
await render(h,{...task,acquisition_progress:progress('fetching',58,85,68)});
await h.initARRDownload();
assert.equal(h.state.arrDownloadTask,null);
assert.equal(h.element('#arr-acquisition-progress').hidden,true);
});
test('acquisition labels, counts and completeness guidance are available in all three languages',()=>{
for(const [key,values] of Object.entries(catalog).filter(([key])=>key.startsWith('arr_acquisition.'))) {
assert.equal(values.length,3,key);
assert.equal(values.every(value=>typeof value==='string'&&value.length>0),true,key);
assert.match(values[2],/[\u0e00-\u0e7f]/,key);
}
assert.match(catalog['arr_acquisition.verifying_counts'][0],/校验完整性/);
});