'use strict'; const assert=require('node:assert/strict'); const core=require('./icampus-study-helper.user.js'); const {harness,ID,detail}=require('./study-helper.test.cjs'); let passed=0; async function test(name,fn){await fn();passed++;console.log(`PASS ${name}`);} function mount(h){const nodes=new Map();const panel={querySelector(s){if(!nodes.has(s))nodes.set(s,{textContent:'',value:'all',checked:true});return nodes.get(s);}}; h.context.document.body={append(){}};h.context.document.createElement=()=>({style:{},attachShadow:()=>panel});h.api.mount();return nodes;} (async()=>{ await test('a platform pass below 100 never counts as a completed course',()=>{ const d=detail();d.course.status='COMPLETED';d.course.examScorePercent=60;d.resources.forEach(r=>r.completed=true); assert.equal(core.courseDone(d.course),false);assert.equal(core.videoPlan(d).kind,'quiz'); d.course.examScorePercent=100;assert.equal(core.courseDone(d.course),true); }); await test('a course below 100 starts its quiz before playing or switching video',async()=>{ const h=harness();let starts=0;const c=h.api.details.get(ID).course;c.examPassed=false;c.examScorePercent=0; const button={textContent:'开始测验',disabled:false,getClientRects:()=>[{}],click(){starts++;}}; h.selectors.set('.course-quiz',{querySelector:()=>null,querySelectorAll:s=>s==='button'?[button]:[]}); h.api.begin();await h.api.tickCourse(ID);assert.equal(starts,1);assert.equal(h.video.playCount,0);assert.equal(h.buttons[1].clicks,0);assert.equal(h.video.paused,true); }); await test('a low passing score with a missing retake entry stays armed and does not advance',async()=>{ const h=harness();const c=h.api.details.get(ID).course;c.examScorePercent=80; const result={getClientRects:()=>[{}],querySelector:s=>s==='.quiz-result__status.is-pass'?{}:s==='.quiz-result__score strong'?{textContent:'80%'}:null}; h.selectors.set('.course-quiz',{querySelector:s=>s==='.quiz-result'?result:null,querySelectorAll:()=>[]}); h.api.begin();await h.api.tickCourse(ID);assert.equal(h.api.state.armed,true);assert.equal(h.api.state.running,false); assert.match(h.api.state.status,/100%/);assert.equal(h.video.playCount,0);assert.equal(h.buttons[1].clicks,0); }); await test('temporary waits retain the started button state and retry automatically',async()=>{ const h=harness();const ui=mount(h);ui.get('[data-start]').onclick();h.api.park('网络等待'); assert.equal(h.api.state.armed,true);assert.equal(ui.get('[data-start]').disabled,true);assert.match(ui.get('[data-start]').textContent,/已启动/); h.advance(15001);await h.api.tick();h.advance(1000);await h.api.tick();assert.equal(h.video.playCount,1); }); await test('ordinary refresh restores the enabled intent without another start click',()=>{ const h=harness();const ui=mount(h);ui.get('[data-start]').onclick();h.api.park('等待页面响应'); const restarted=harness({sessionEntries:[...h.session]});mount(restarted); assert.equal(restarted.api.state.armed,true);assert.equal(restarted.api.state.running,true); }); await test('manual cancellation is the only action that clears the stored enabled intent',async()=>{ const h=harness();const ui=mount(h);ui.get('[data-start]').onclick();h.api.park('暂时等待'); ui.get('[data-stop]').onclick();assert.equal(h.api.state.armed,false);assert.equal(h.session.has('icampus.study.v1.enabled'),false); h.advance(60000);await h.api.tick();assert.equal(h.video.playCount,0); const restarted=harness({sessionEntries:[...h.session]});mount(restarted);assert.equal(restarted.api.state.armed,false); }); await test('manual video pause waits for a real resume without cancelling the intent',async()=>{ const h=harness();h.api.begin();h.api.track(h.video);h.video.paused=true;h.api.monitor(); assert.equal(h.api.state.armed,true);h.advance(30000);await h.api.tick();assert.equal(h.video.playCount,0); h.video.paused=false;await h.api.tick();assert.equal(h.api.state.running,true); }); console.log(`${passed} persistent-run tests passed.`); })().catch(e=>{console.error(e);process.exitCode=1;});