fix: resume video playback and advance linked exams with attempt controls

This commit is contained in:
薇星幻海
2026-10-18 02:12:06 +08:00
parent 2e044655bb
commit 1b497286dc
20 changed files with 1629 additions and 155 deletions
+51
View File
@@ -165,6 +165,51 @@ async function main() {
console.log('PASS exam defaults/score/full answer evidence, partial learning updates and persistent switch/details state');
await tab('video').click();
assert(await host.getByTestId('video-mode-note').textContent().then(text => text.includes('平台确认视频完成后') && text.includes('已开放的关联考试') && text.includes('人工保护仍生效')));
const callsBeforeModeHints = await page.evaluate(() => JSON.stringify(qaCalls));
for (const mode of ['video', 'videoQuiz']) {
await page.evaluate(mode => qaPanel.setState({ learning: { mode } }), mode);
assert(await host.getByTestId('video-mode-note').textContent().then(text => text.includes('不会进入独立或关联考试') && text.includes('任务总览选择“视频+考试”')));
}
await page.evaluate(() => qaPanel.setState({ learning: { mode: 'exam' } }));
assert(await host.getByTestId('video-mode-note').textContent().then(text => text.includes('本模式未启用视频')));
await page.evaluate(() => qaPanel.setState({ learning: { mode: 'all', skipSingleAttemptQuiz: false } }));
assert(await host.getByTestId('video-mode-note').textContent().then(text => text.includes('单次机会保护已关闭')));
await page.evaluate(() => qaPanel.setState({ learning: { skipSingleAttemptQuiz: true } }));
assert.equal(await page.evaluate(() => JSON.stringify(qaCalls)), callsBeforeModeHints, '模式说明更新只展示状态,不启动任务或改设置');
const playbackSwitches = [
['autoContinuePlayback', '自动继续上次播放'],
['skipSingleAttemptQuiz', '仅 1 次答题机会时交给我处理'],
['resumePlaybackOnReturn', '切回页面时自动恢复播放']
];
for (const [key, label] of playbackSwitches) {
const control = host.getByTestId('setting-' + key);
assert.equal(await control.getAttribute('role'), 'switch');
assert.equal(await control.getAttribute('aria-label'), label);
assert(await control.isChecked(), label + '默认开启');
await control.uncheck();
assert.deepEqual(await page.evaluate(() => qaCalls.settings.at(-1)), [key, false]);
}
const callsAfterPlaybackOff = await page.evaluate(() => JSON.stringify(qaCalls));
await tab('overview').click();
await page.evaluate(() => qaPanel.setState({ learning: { etaSeconds: 358 } }));
await tab('video').click();
for (const [key] of playbackSwitches) assert(!await host.getByTestId('setting-' + key).isChecked(), '切栏及部分更新保留视频开关状态');
assert.equal(await page.evaluate(() => JSON.stringify(qaCalls)), callsAfterPlaybackOff, '切栏不能启动续播或自动答题');
await page.evaluate(() => qaPanel.setState({ learning: { autoContinuePlayback: true, skipSingleAttemptQuiz: true, resumePlaybackOnReturn: true } }));
for (const [key] of playbackSwitches) assert(await host.getByTestId('setting-' + key).isChecked(), '显示外部恢复的视频开关状态');
assert.equal(await page.evaluate(() => JSON.stringify(qaCalls)), callsAfterPlaybackOff, '读取保存状态不触发设置或任务回调');
assert(await host.getByTestId('playback-return-hint').textContent().then(text => text.includes('手动暂停优先') && text.includes('不会自动播放')));
await page.evaluate(() => qaPanel.setState({ learning: { video: { title: '1-1安全生产方针和目标', status: 'backgroundPaused', currentTime: 45, duration: 633, learnedTime: 27, actualRate: 1.5, refreshCount: 1 } } }));
assert(await host.locator('.worker-status').textContent().then(text => text.includes('后台暂停,等待返回')));
await page.evaluate(() => qaPanel.setState({ learning: { video: { title: '1-1安全生产方针和目标', status: 'playing', currentTime: 45, duration: 633, learnedTime: 27, actualRate: 1.5, refreshCount: 1 } } }));
await screenshot('02b-desktop-playback-switches.png');
for (const [key] of playbackSwitches) {
await host.getByTestId('setting-' + key).uncheck();
await host.getByTestId('setting-' + key).check();
assert.deepEqual(await page.evaluate(() => qaCalls.settings.at(-1)), [key, true]);
}
console.log('PASS playback switches default on, boolean callbacks, persisted rendered state and manual-pause guidance');
await host.getByTestId('setting-rate').selectOption('2');
assert.deepEqual(await page.evaluate(() => qaCalls.settings.at(-1)), ['rate', 2]);
await host.getByTestId('task-videoPause').click();
@@ -213,6 +258,12 @@ async function main() {
const moved = await host.boundingBox(); assert(Math.abs(moved.x - box.x - 35) <= 2);
await page.setViewportSize({ width: 390, height: 844 }); await visible();
assert.equal(await host.locator('.navigation').evaluate(element => getComputedStyle(element).flexDirection), 'row');
await tab('video').click();
for (const [key] of playbackSwitches) {
const control = host.getByTestId('setting-' + key);
await control.scrollIntoViewIfNeeded(); assert(await control.isVisible()); assert(await control.isChecked());
}
await screenshot('03b-mobile-playback-switches.png');
await tab('exam').click(); await incompleteSwitch.scrollIntoViewIfNeeded();
assert(await incompleteSwitch.isVisible()); assert(await incompleteSwitch.isChecked());
await screenshot('03a-mobile-incomplete-switch-on.png');