feat: add ImageFind application and release pipelines
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import assert from "node:assert/strict";
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
const require = createRequire(new URL("../frontend/package.json", import.meta.url));
|
||||
const { chromium } = require("playwright");
|
||||
const baseUrl = process.env.PROTOTYPE_URL || "http://127.0.0.1:4178";
|
||||
const output = path.resolve(process.env.PLAYER_AUDIT_DIR || ".artifacts/player-round-1");
|
||||
const cases = [
|
||||
{ name: "mobile-390", width: 390, height: 844 },
|
||||
{ name: "desktop-1440", width: 1440, height: 900 }
|
||||
];
|
||||
|
||||
fs.mkdirSync(output, { recursive: true });
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const report = [];
|
||||
|
||||
for (const profile of cases) {
|
||||
const context = await browser.newContext({ viewport: profile, locale: "zh-CN" });
|
||||
const page = await context.newPage();
|
||||
const errors = [];
|
||||
page.on("pageerror", error => errors.push(`pageerror: ${error.message}`));
|
||||
page.on("console", message => message.type() === "error" && errors.push(`console: ${message.text()}`));
|
||||
|
||||
await page.goto(`${baseUrl}/#/player/v1`, { waitUntil: "networkidle" });
|
||||
const geometry = await page.evaluate(() => {
|
||||
const stage = document.querySelector(".player-stage-v2").getBoundingClientRect();
|
||||
const back = document.querySelector('.player-topbar button[aria-label="返回"]').getBoundingClientRect();
|
||||
const fullscreen = document.querySelector('.player-controls-row button[aria-label="全屏"]').getBoundingClientRect();
|
||||
const visibleControls = [...document.querySelectorAll(".player-stage-v2 button")].filter(button => {
|
||||
const box = button.getBoundingClientRect();
|
||||
const style = getComputedStyle(button);
|
||||
return style.display !== "none" && style.visibility !== "hidden" && box.width > 0 && box.height > 0;
|
||||
});
|
||||
return {
|
||||
viewportWidth: innerWidth,
|
||||
documentWidth: document.documentElement.scrollWidth,
|
||||
stage: { x: stage.x, width: stage.width, height: stage.height, right: stage.right },
|
||||
ratio: stage.width / stage.height,
|
||||
backVisible: back.left >= 0 && back.right <= innerWidth,
|
||||
fullscreenVisible: fullscreen.left >= 0 && fullscreen.right <= innerWidth,
|
||||
tapHighlight: getComputedStyle(document.querySelector(".main-play")).webkitTapHighlightColor,
|
||||
controlsBelow44: visibleControls.filter(button => {
|
||||
const box = button.getBoundingClientRect();
|
||||
return box.width < 44 || box.height < 44;
|
||||
}).length
|
||||
};
|
||||
});
|
||||
|
||||
assert.equal(geometry.documentWidth, geometry.viewportWidth, `${profile.name} 存在横向溢出`);
|
||||
assert.ok(Math.abs(geometry.ratio - 16 / 9) < 0.02, `${profile.name} 播放舞台不是 16:9`);
|
||||
assert.equal(geometry.backVisible, true, `${profile.name} 返回按钮被裁切`);
|
||||
assert.equal(geometry.fullscreenVisible, true, `${profile.name} 全屏按钮被裁切`);
|
||||
if (profile.width <= 720) assert.equal(geometry.controlsBelow44, 0, `${profile.name} 存在小于 44px 的播放器按钮`);
|
||||
if (profile.width <= 720) assert.ok(geometry.tapHighlight === "rgba(0, 0, 0, 0)" || geometry.tapHighlight === "transparent", `${profile.name} 仍存在系统蓝色点击高亮`);
|
||||
assert.equal(await page.locator(".rate-control").textContent(), "1×");
|
||||
await page.screenshot({ path: path.join(output, `${profile.name}-player.png`), fullPage: true });
|
||||
|
||||
await page.locator(".player-tap-surface").click({ position: { x: 10, y: 100 } });
|
||||
await page.locator(".player-stage-v2.controls-hidden").waitFor({ state: "visible" });
|
||||
await page.waitForTimeout(150);
|
||||
await page.getByRole("button", { name: "显示播放控件" }).click({ position: { x: 10, y: 100 } });
|
||||
await page.locator(".player-stage-v2.controls-visible").waitFor({ state: "visible" });
|
||||
|
||||
const beforeSkip = Number(await page.locator('.timeline input[type="range"]').inputValue());
|
||||
await page.getByRole("button", { name: "快进 10 秒" }).click();
|
||||
const afterSkip = Number(await page.locator('.timeline input[type="range"]').inputValue());
|
||||
assert.ok(afterSkip > beforeSkip, `${profile.name} 快进没有更新进度`);
|
||||
|
||||
await page.locator(".rate-control").click();
|
||||
assert.equal(await page.locator(".rate-control").textContent(), "1.25×");
|
||||
await page.getByRole("button", { name: "时间点", exact: true }).click();
|
||||
await page.locator('.player-drawer[aria-label="视频时间点"]').waitFor({ state: "visible" });
|
||||
await page.waitForTimeout(250);
|
||||
await page.screenshot({ path: path.join(output, `${profile.name}-markers.png`), fullPage: true });
|
||||
await page.keyboard.press("Escape");
|
||||
await page.locator(".player-drawer").waitFor({ state: "detached" });
|
||||
|
||||
await page.getByRole("button", { name: "合集目录" }).click();
|
||||
await page.locator('.player-drawer[aria-label="合集目录"]').waitFor({ state: "visible" });
|
||||
await page.locator(".player-panel-scrim").click({ position: { x: 4, y: 4 } });
|
||||
await page.locator(".player-drawer").waitFor({ state: "detached" });
|
||||
|
||||
await page.locator(".player-title-row").getByRole("button", { name: "喜欢" }).click();
|
||||
assert.equal(await page.locator(".player-title-row").getByRole("button", { name: "喜欢" }).getAttribute("aria-pressed"), "true");
|
||||
|
||||
if (profile.width <= 720) {
|
||||
await page.locator(".main-play").click();
|
||||
await page.waitForTimeout(3750);
|
||||
await page.locator(".player-stage-v2.controls-hidden").waitFor({ state: "visible" });
|
||||
await page.locator(".player-tap-surface").click({ position: { x: 10, y: 100 } });
|
||||
await page.locator(".main-play").click();
|
||||
await page.waitForTimeout(3750);
|
||||
assert.equal(await page.locator(".player-stage-v2").getAttribute("class").then(value => value.includes("controls-visible")), true, "暂停后控件不应自动隐藏");
|
||||
}
|
||||
|
||||
report.push({ ...profile, geometry, errors: [...new Set(errors)] });
|
||||
await context.close();
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
fs.writeFileSync(path.join(output, "report.json"), JSON.stringify(report, null, 2));
|
||||
console.log(JSON.stringify(report, null, 2));
|
||||
assert.equal(report.flatMap(item => item.errors).length, 0, "播放器运行时出现控制台错误");
|
||||
Reference in New Issue
Block a user