frontend/e2e/media-processing-settings.test.ts
Rama master · réplica de lectura del repositorio original.
import assert from 'node:assert/strict';
import { mkdir } from 'node:fs/promises';
import path from 'node:path';
import { after, before, describe, it } from 'node:test';
import type { Browser, Page } from 'playwright-core';
import { launch, layout, settle, visit, VIEWPORTS } from './harness.ts';
/** 这台机器的媒体处理偏好:页面写进来的值留在这一份里,重新载入读回的就是它。 */
function mediaProcessing() {
const state = { disabled: false, timeline: 'coarse', previewAcceleration: 'auto', playbackAcceleration: 'auto' };
const writes: unknown[] = [];
const route = async (page: Page) => {
await page.route('**/api/media-processing', async route => {
if (route.request().method() === 'POST') {
const body = route.request().postDataJSON();
writes.push(body);
if ('metadata_only' in body) {
state.disabled = body.metadata_only;
if (state.disabled) state.timeline = 'off';
}
if ('preview_acceleration' in body) state.previewAcceleration = body.preview_acceleration;
if ('playback_acceleration' in body) state.playbackAcceleration = body.playback_acceleration;
}
await route.fulfill({ json: { metadata_only: state.disabled,
preview_acceleration: state.previewAcceleration, playback_acceleration: state.playbackAcceleration } });
});
await page.route('**/api/thumbnail-jobs', route => route.fulfill({ json: { mode: state.timeline, status: 'idle' } }));
};
return { state, writes, route };
}
describe('视频预览设置', () => {
let browser: Browser;
before(async () => { browser = await launch() });
after(async () => { await browser?.close() });
for (const viewport of VIEWPORTS) {
it(`${viewport.name}:总开关持久化并控制时间轴设置,重新开启后时间轴由用户选择`, async () => {
const { state, writes, route } = mediaProcessing();
const opened = await visit(browser, '/settings/library', viewport, route);
const { page } = opened;
try {
const toggle = page.getByRole('switch', { name: '生成视频预览', exact: true });
const interval = page.locator('#videoThumbnailSetting button');
await toggle.waitFor();
await settle(page);
assert.equal(await toggle.isChecked(), true);
assert.equal(await interval.isDisabled(), false);
await page.locator('label').filter({ has: toggle }).click();
await page.getByText('已关闭视频预览生成', { exact: true }).waitFor();
assert.equal(await toggle.isChecked(), false);
assert.equal(await interval.isDisabled(), true);
await page.reload();
await toggle.waitFor();
await settle(page);
assert.equal(await toggle.isChecked(), false);
assert.equal(await interval.isDisabled(), true);
assert.match(await interval.innerText(), /关闭/);
await toggle.focus();
await page.keyboard.press('Space');
await page.getByText('已开启视频预览生成', { exact: true }).waitFor();
assert.equal(await interval.isDisabled(), false);
assert.match(await interval.innerText(), /关闭/);
assert.deepEqual(writes, [{ metadata_only: true }, { metadata_only: false }]);
const preview = page.locator('#previewAccelerationSetting button');
await preview.click();
await page.getByRole('option', { name: '软件解码', exact: true }).click();
await page.getByText('已保存抽帧解码方式', { exact: true }).waitFor();
assert.equal(state.previewAcceleration, 'software');
assert.equal(state.playbackAcceleration, 'auto');
assert.deepEqual(writes.slice(-1), [{ preview_acceleration: 'software' }]);
// 播放转码在「应用与维护 → 视频播放」,这一页签里只有抽帧解码方式。
assert.equal(await page.locator('.ui-board-group-active #playbackAccelerationSetting').count(), 0);
await page.reload();
await preview.waitFor();
await settle(page);
assert.match(await preview.innerText(), /软件解码/);
const measured = await layout(page);
assert.ok(measured.scrollWidth <= measured.viewportWidth, JSON.stringify(measured));
assert.deepEqual(measured.offenders, []);
const artifacts = path.resolve('..', 'build', 'agent-verification', 'media-processing');
await mkdir(artifacts, { recursive: true });
await page.screenshot({ path: path.join(artifacts, `${viewport.name}.png`), fullPage: true });
assert.deepEqual(opened.problems, []);
} finally { await opened.close() }
});
it(`${viewport.name}:「应用与维护 → 视频播放」里改转码方式,只写这一项,重新载入读回`, async () => {
const { state, writes, route } = mediaProcessing();
const opened = await visit(browser, '/settings/maintenance', viewport, route);
const { page } = opened;
try {
const section = page.getByRole('region', { name: '视频播放', exact: true });
const trigger = section.locator('#playbackAccelerationSetting button');
await trigger.waitFor({ state: 'visible' });
await page.waitForFunction(() => document.querySelector('#playbackAccelerationSetting button')?.hasAttribute('disabled') === false);
await settle(page);
assert.match(await trigger.innerText(), /自动/);
/* 这张卡排在首屏以下。先滚到位、等两帧让滚动事件派发完:下拉打开之后再收到触发框所在页面的
滚动,React Aria 会把它合上。 */
await trigger.scrollIntoViewIfNeeded();
await page.evaluate(() => new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(resolve))));
await trigger.click();
await page.getByRole('option', { name: '软件编解码', exact: true }).click();
await page.getByText('已保存转码方式', { exact: true }).waitFor();
assert.equal(state.playbackAcceleration, 'software');
assert.equal(state.previewAcceleration, 'auto');
assert.deepEqual(writes, [{ playback_acceleration: 'software' }]);
// 「视频播放」排在「开机自启」之后、「存储空间」之前(没有这两张卡的环境只比相对次序)。
const order = await page.locator('.ui-board-group-active').evaluate((group) =>
[...group.querySelectorAll('section[aria-label], form[aria-label]')].map((node) => node.getAttribute('aria-label')));
const at = order.indexOf('视频播放');
assert.ok(at >= 0 && order.slice(0, at).every((name) => ['检查更新', '自动修复', '自动更新', '开机自启'].includes(name ?? '')), JSON.stringify(order));
await page.reload();
await trigger.waitFor({ state: 'visible' });
await page.waitForFunction(() => /软件编解码/.test(document.querySelector('#playbackAccelerationSetting button')?.textContent || ''));
const measured = await layout(page);
assert.ok(measured.scrollWidth <= measured.viewportWidth, JSON.stringify(measured));
assert.deepEqual(measured.offenders, []);
assert.deepEqual(opened.problems, []);
} finally { await opened.close() }
});
}
});