/** 官网回归使用真实 CMS 信封和图片字节边界,不替换内部模型或手工触发图片事件。 */ import assert from "node:assert/strict"; import test from "node:test"; import { appOrigin, backendOrigin, eventually, loginAccount, loginPassword, scenario, } from "./helpers/console-browser.mjs"; // 与线上 CMS 的字段形状一致:旧入口仍由 CMS 覆盖,不能只测试默认文案。 function cmsContent() { return { header: { navigation: [ { label: "产品服务", href: "#products", is_show: true }, { label: "客户自定义方案", href: "https://customer.example.invalid/plan", is_show: true, }, ], }, hero: { title: "为客户保留的自定义标题", buttonLabel: "浏览产品服务", buttonHref: "/login?redirect=%2Fproducts", }, products: { items: [ { title: "客户自定义云方案", buttonLabel: "查看云服务器", href: "/login?redirect=%2Fcloud-servers", features: [], is_show: true, }, { title: "物理服务器", buttonLabel: "查看物理服务器", href: "/login?redirect=%2Fdedicated-servers", features: [], is_show: true, }, { title: "机柜托管", buttonLabel: "了解机柜托管", href: "/login?redirect=%2Fcolocations", features: [], is_show: true, }, ], }, footer: { phone: "", email: "", address: "", linkGroups: [ { title: "产品服务", links: [ { label: "云服务器", href: "/login?redirect=%2Fcloud-servers" }, { label: "机柜托管", href: "/login?redirect=%2Fcolocations" }, ], }, ], }, }; } async function officialBoundary(page, content = {}) { const imageErrors = []; await page .context() .route(`${appOrigin}/official-test-images/**`, (route) => { if (route.request().url().endsWith("valid-avatar.svg")) { return route.fulfill({ contentType: "image/svg+xml", body: '', }); } // HTTP 成功但图片不可解码,真实触发 img error;不放宽共享 console 错误门禁。 imageErrors.push(new URL(route.request().url()).pathname); return route.fulfill({ contentType: "image/png", body: "invalid PNG bytes", }); }); await page.context().route(`${backendOrigin}/console/v1/**`, (route) => { const path = new URL(route.request().url()).pathname.replace( /^\/console\/v1/, "", ); const reply = (data) => route.fulfill({ json: { status: 200, msg: "", data } }); if (path === "/official_site_cms/content") return reply({ content }); if (path === "/product/group/first") { return reply({ list: [ { id: 1, name: "云服务器" }, { id: 2, name: "物理服务器" }, ], }); } if (path === "/product/group/second") { return reply({ list: [{ id: 11, parent_id: 1, name: "公开云线路" }] }); } if (path === "/product") return reply({ list: [], count: 0 }); if (path === "/ticket/config") return reply({ ticket_notice_open: 0 }); if (["/ticket/type", "/ticket/department"].includes(path)) return reply({ list: [] }); return route.fallback(); }); return { imageErrors }; } for (const [label, destination, content] of [ ["浏览产品服务", "/products", {}], ["浏览产品服务", "/products", cmsContent()], ["查看云服务器", "/products/cloud-server", cmsContent()], ["查看物理服务器", "/products/dedicated-server", cmsContent()], ]) { test( `official purchase CTA opens ${destination} anonymously with ${Object.keys(content).length ? "CMS" : "default"} content`, { timeout: 30000 }, (t) => scenario(t, {}, async (page) => { await officialBoundary(page, content); await page.goto(`${appOrigin}/official-site`); if (content.hero) { await page .getByRole("heading", { name: content.hero.title, exact: true }) .waitFor(); assert.equal( await page .getByRole("link", { name: "客户自定义方案", exact: true }) .getAttribute("href"), "https://customer.example.invalid/plan", ); assert.equal( await page .getByRole("heading", { name: "客户自定义云方案", exact: true }) .count(), 1, ); } await page.getByRole("link", { name: label, exact: true }).click(); await eventually( () => new URL(page.url()).pathname, (path) => path === destination, "Public purchase CTA must reach its product route without a login gate", ); await page.locator(".public-order-layout").waitFor(); assert.equal(await page.locator("#account").count(), 0); return { anonymousDestination: destination, customContentPreserved: !!content.hero, }; }), ); } test( "official cabinet consultation reaches an implemented support flow", { timeout: 30000 }, (t) => scenario(t, { loginMode: "password-only" }, async (page) => { const content = cmsContent(); content.contact = { is_show: false }; content.sectionOrder = ["products", "infrastructure", "reviews"]; await officialBoundary(page, content); await page.goto(`${appOrigin}/official-site`); await page .getByRole("heading", { name: "为客户保留的自定义标题", exact: true }) .waitFor(); assert.equal( await page.locator("#contact").count(), 0, "CMS contact visibility must not be overridden", ); await page .getByText("机柜托管及定制方案请登录后提交工单咨询", { exact: true }) .waitFor(); await page .getByRole("link", { name: "了解机柜托管", exact: true }) .click(); await page.getByRole("button", { name: "登录", exact: true }).waitFor(); assert.equal( new URL(page.url()).searchParams.get("redirect"), "/tickets/create", ); await page.locator("#account").fill(loginAccount); await page.locator("#password").fill(loginPassword); await page.getByRole("button", { name: "登录", exact: true }).click(); await page.waitForURL((url) => url.pathname === "/tickets/create"); await page.locator(".ticket-create").waitFor(); return { consultationAvailable: true, supportRouteOpened: "/tickets/create", }; }), ); test( "official configurable images fall back after real image decoding failures", { timeout: 30000 }, (t) => scenario(t, {}, async (page) => { const content = cmsContent(); content.brand = { name: "破碎工坊网络", logoUrl: "/official-test-images/logo.png", }; content.footer.qrImage = "/official-test-images/qr.png"; content.footer.qrCaption = "扫码咨询"; content.reviews = { is_show: true, items: [ { author: "Sophon", company: "", quote: "保留原有客户评价", avatar: "/official-test-images/avatar.png", is_show: true, }, { author: "Ramdisk", company: "", quote: "保留可用客户头像", avatar: "/official-test-images/valid-avatar.svg", is_show: true, }, ], }; const boundary = await officialBoundary(page, content); await page.goto(`${appOrigin}/official-site`); await page.getByText("保留原有客户评价", { exact: true }).waitFor(); await eventually( () => [...new Set(boundary.imageErrors)].sort(), (paths) => paths.length === 3, "The browser must request each configured bad image", ); await eventually( () => page.locator(".official-brand-mark").count(), (count) => count === 2, "Both failed brand images must use the existing brand mark", ); assert.equal( await page.locator(".official-review-avatar").textContent(), "S", ); await page .getByText("二维码暂时无法显示,请使用工单咨询", { exact: true }) .waitFor(); assert.equal( await page.locator(".official-site img").count(), 1, "Only the successfully decoded original customer avatar should remain", ); assert.equal( await page .getByRole("img", { name: "Ramdisk", exact: true }) .evaluate((image) => image.complete && image.naturalWidth > 0), true, ); assert.equal(await page.getByText("Sophon", { exact: true }).count(), 1); await page.setViewportSize({ width: 390, height: 844 }); assert.equal( await page.evaluate( () => document.documentElement.scrollWidth <= window.innerWidth, ), true, "Image fallbacks and consultation text must fit the mobile viewport", ); return { brandFallbacks: 2, customerIdentityPreserved: true, qrReplacedByConsultationText: true, imageFailure: "HTTP 200 with invalid PNG bytes", }; }), );