通过表格原生渲染统一生成手机布局标签,删除全页监听与后补扫描。动态等级列使用单一标题并保留颜色。 补齐首次插入、深链刷新、动态表头与首页延迟响应几何回归。全量214项通过,最终专项16项通过;不声明全站所有场景零位移。
This commit is contained in:
1 parent
30cbfd3a9c
commit
1c0c0f16bc
6 files changed
+241
-58
No files matched your search
@@ -1,7 +1,12 @@
|
||||
/** OpenVue/Deni 迁移的实际导航、移动表格与弹窗行为,不断言包名或源码形状。 */
|
||||
import assert from "node:assert/strict";
|
||||
import { test } from "node:test";
|
||||
import { eventually, login, scenario } from "./helpers/console-browser.mjs";
|
||||
import {
|
||||
backendOrigin,
|
||||
eventually,
|
||||
login,
|
||||
scenario,
|
||||
} from "./helpers/console-browser.mjs";
|
||||
|
||||
const navigation = (page) =>
|
||||
page.getByRole("navigation", { name: "会员中心导航", exact: true });
|
||||
@@ -170,6 +175,22 @@ test(
|
||||
scenario(t, {}, async (page) => {
|
||||
await page.setViewportSize({ width: 375, height: 812 });
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
await page.addInitScript(() => {
|
||||
// 读取浏览器收到的首批单元格,不等待后续帧补写属性,也不改动产品 DOM。
|
||||
window.initialTableCells = null;
|
||||
const observer = new MutationObserver(() => {
|
||||
const cells = document.querySelectorAll(
|
||||
".p-datatable-tbody > tr:not(.p-datatable-empty-message) > td",
|
||||
);
|
||||
if (!cells.length) return;
|
||||
window.initialTableCells = [...cells].map((cell) => ({
|
||||
label: cell.getAttribute("data-label"),
|
||||
visible: getComputedStyle(cell).display !== "none",
|
||||
}));
|
||||
observer.disconnect();
|
||||
});
|
||||
observer.observe(document, { childList: true, subtree: true });
|
||||
});
|
||||
await login(page, "/security/ssh-keys");
|
||||
const name = page.getByText("audit-01", { exact: true });
|
||||
await name.waitFor();
|
||||
@@ -182,6 +203,25 @@ test(
|
||||
});
|
||||
assert.equal(label.value, "名称");
|
||||
assert.equal(label.displayed.includes("名称"), true);
|
||||
const initial = await page.evaluate(() => window.initialTableCells);
|
||||
assert.ok(initial?.length > 0);
|
||||
assert.equal(
|
||||
initial.every((cell) => cell.label !== null),
|
||||
true,
|
||||
"Mobile cells must carry layout labels when inserted, without another frame",
|
||||
);
|
||||
assert.ok(
|
||||
initial.some((cell) => cell.label === "名称" && cell.visible),
|
||||
"The primary field must be visible in the initial card geometry",
|
||||
);
|
||||
await page.reload();
|
||||
await name.waitFor();
|
||||
const refreshed = await page.evaluate(() => window.initialTableCells);
|
||||
assert.deepEqual(
|
||||
refreshed,
|
||||
initial,
|
||||
"A deep-link refresh must insert the same complete mobile card geometry",
|
||||
);
|
||||
await page
|
||||
.getByRole("button", { name: "编辑", exact: true })
|
||||
.first()
|
||||
@@ -202,8 +242,94 @@ test(
|
||||
assert.equal(fits, true);
|
||||
return {
|
||||
tableFieldLabels: true,
|
||||
initialTableGeometryReady: true,
|
||||
refreshKeepsInitialTableGeometry: true,
|
||||
editableDialogFits: true,
|
||||
pageHasNoHorizontalOverflow: true,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
test(
|
||||
"dynamic columns share a single colored title and mobile field label",
|
||||
{ timeout: 30000 },
|
||||
(t) =>
|
||||
scenario(t, {}, async (page) => {
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await page.emulateMedia({ reducedMotion: "reduce" });
|
||||
await page.route(`${backendOrigin}/console/v1/**`, async (route) => {
|
||||
const path = new URL(route.request().url()).pathname;
|
||||
if (path.endsWith("/account")) {
|
||||
const response = await route.fetch();
|
||||
const json = await response.json();
|
||||
json.data.account.customfield = {
|
||||
idcsmart_client_level: { id: 1, name: "本地会员" },
|
||||
};
|
||||
return route.fulfill({ response, json });
|
||||
}
|
||||
if (path.endsWith("/country"))
|
||||
return route.fulfill({
|
||||
json: { status: 200, msg: "", data: { list: [] } },
|
||||
});
|
||||
if (!path.endsWith("/client_level")) return route.fallback();
|
||||
return route.fulfill({
|
||||
json: {
|
||||
status: 200,
|
||||
msg: "",
|
||||
data: {
|
||||
level_id: 1,
|
||||
levels: [
|
||||
{
|
||||
id: 1,
|
||||
name: "本地会员",
|
||||
background_color: "#0284c7",
|
||||
discount_list: [
|
||||
{ product_name: "本地云产品", discount_percent: 95 },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
await login(page, "/account");
|
||||
await page.getByRole("button", { name: "本地会员", exact: true }).click();
|
||||
const dialog = page.getByRole("dialog", {
|
||||
name: "等级策略",
|
||||
exact: true,
|
||||
});
|
||||
// 手机字段名来自 ::before,参与无障碍名称;按实际折扣文字定位单元格再核对标签。
|
||||
const discount = dialog.locator("td").filter({ hasText: /^95%$/ });
|
||||
await discount.waitFor();
|
||||
assert.equal(await discount.getAttribute("data-label"), "本地会员");
|
||||
// 手机表头隐藏,切回桌面核对用户实际看到的自定义标题,而非隐藏元素的无障碍名称。
|
||||
await page.setViewportSize({ width: 1440, height: 900 });
|
||||
const header = dialog.getByRole("columnheader", {
|
||||
name: "本地会员",
|
||||
exact: true,
|
||||
});
|
||||
await header.waitFor();
|
||||
assert.equal(
|
||||
await header.count(),
|
||||
1,
|
||||
"Dynamic columns must display a single title",
|
||||
);
|
||||
assert.equal(
|
||||
await header.evaluate((element) => getComputedStyle(element).color),
|
||||
"rgb(2, 132, 199)",
|
||||
"The server-provided level color must remain visible",
|
||||
);
|
||||
assert.equal(
|
||||
await dialog
|
||||
.locator("td")
|
||||
.filter({ hasText: /^本地云产品$/ })
|
||||
.getAttribute("data-label"),
|
||||
"商品",
|
||||
);
|
||||
return {
|
||||
dynamicHeaderLabel: true,
|
||||
singleTitle: true,
|
||||
levelColorPreserved: true,
|
||||
};
|
||||
}),
|
||||
);
|
||||
Reference in new issue
Block a user