样式修改

This commit is contained in:
谢宇宁
2026-10-16 14:10:10 +07:00
parent d2ddb1c321
commit 4afd5f9143
42 changed files with 89 additions and 1765 deletions
+5 -56
View File
@@ -12,7 +12,7 @@ import { createStyleFixture } from "./style-fixtures";
// Bundle the actual React provider, dialogs, header/footer and encrypted media
// hooks. The ephemeral server and browser request policy isolate all writes,
// destinations and analytics; no original business JS or template runtime runs.
// and destinations; no original business JS or template runtime runs.
const root = resolve(dirname(fileURLToPath(import.meta.url)), "..");
const temporary = await mkdtemp(join(tmpdir(), "huakui-native-site-")),
bundle = join(temporary, "site.js");
@@ -23,7 +23,6 @@ await build({
contents: `
import {createRoot} from 'react-dom/client';
import {SiteProvider,useSite} from '@/components/providers/SiteProvider';
import {TrackerProvider} from '@/components/analytics/TrackerProvider';
import {SiteHeader} from '@/components/layout/SiteHeader';
import {SiteFooter} from '@/components/layout/SiteFooter';
import {SiteShell} from '@/components/layout/SiteShell';
@@ -32,7 +31,7 @@ import {AppDownloadLink} from '@/components/catalog/Interactions';
import {setAuthSession} from '@/lib/api';
window.__setAuthSession=setAuthSession;
const app=createRoot(document.getElementById('root'));function UserProbe(){const site=useSite();return <div style={{position:'absolute',top:150,left:10}}><output id='display-avatar' data-value={site.user?.avatar||''} data-name={site.user?.nickName||''} data-balance={site.user?.recharge||0} data-registered={String(!!site.user?.isRegister)}/></div>}
function render(data){app.render(data.requestPath==='/navigation/'?<SiteShell view='nav' data={data}><SiteNavigationPage data={data}/></SiteShell>:<SiteProvider data={data}><TrackerProvider data={data}><SiteHeader data={data}/><UserProbe/><main style={{minHeight:900,paddingTop:100}}><h1>真实 React 共享组件隔离检查</h1><AppDownloadLink className="hk-app-cta__download" href={data.installGuide.fallbackURL}>点击下载</AppDownloadLink><button id="outside">页面按钮</button></main><SiteFooter data={data}/></TrackerProvider></SiteProvider>);}window.__rerender=render;render(window.__fixture);
function render(data){app.render(data.requestPath==='/navigation/'?<SiteShell view='nav' data={data}><SiteNavigationPage data={data}/></SiteShell>:<SiteProvider data={data}><SiteHeader data={data}/><UserProbe/><main style={{minHeight:900,paddingTop:100}}><h1>真实 React 共享组件隔离检查</h1><AppDownloadLink className="hk-app-cta__download" href={data.installGuide.fallbackURL}>点击下载</AppDownloadLink><button id="outside">页面按钮</button></main><SiteFooter data={data}/></SiteProvider>);}window.__rerender=render;render(window.__fixture);
`,
},
bundle: true,
@@ -72,13 +71,6 @@ const server = createServer(async (request, response) => {
response.end(await readFile(bundle));
return;
}
if (path === "/static/common/web-sdk-v1.2.0.js") {
response.setHeader("Content-Type", "application/javascript");
response.end(
"/* SDK mocked by the browser fixture before React mounts. */",
);
return;
}
if (path.startsWith("/static/")) {
const file = resolve(root, "public", "." + path);
if (!file.startsWith(join(root, "public") + "/")) {
@@ -151,7 +143,6 @@ const server = createServer(async (request, response) => {
requestPath: path,
pageKey: "home",
pageName: "首页",
trackerAppId: "isolated",
isLoggedIn: user,
isRegistered: false,
userName: "隔离游客",
@@ -203,9 +194,7 @@ const image = Buffer.from(
key = Buffer.from("2019ysapp7527");
for (let i = 0; i < Math.min(100, image.length); i++)
image[i] ^= key[i % key.length];
type EventRecord = { method: string; payload: Record<string, unknown> };
const events: EventRecord[] = [],
errors: string[] = [],
const errors: string[] = [],
missing: string[] = [],
unexpected: string[] = [],
destinations: string[] = [];
@@ -214,14 +203,8 @@ let releaseImage: (() => void) | undefined,
delayImage = false,
imageRequested = 0;
const configure = async (context: BrowserContext, ageAccepted = false) => {
await context.exposeBinding(
"__recordEvent",
(_source, event: EventRecord) => {
events.push(event);
},
);
await context.addInitScript({
content: `window.__ageClosed=0;document.addEventListener('eighteen:closed',function(){window.__ageClosed++});window.WebSDK={init:function(){return Promise.resolve()},getCommonFields:function(){return Promise.resolve({device_id:'isolated-device',device:'OTHER',sid:'isolated-sid'})},flush:function(){},track:new Proxy({},{get:function(_,method){return function(payload){return window.__recordEvent({method:String(method),payload:payload})}}})};try{${ageAccepted ? "localStorage.setItem('hg_age_ok','1');" : ""}if(!localStorage.getItem('__fixture_history_seeded')){localStorage.setItem('hgdj_search_history',JSON.stringify(['历史词']));localStorage.setItem('__fixture_history_seeded','1');}}catch{}`,
content: `window.__ageClosed=0;document.addEventListener('eighteen:closed',function(){window.__ageClosed++});try{${ageAccepted ? "localStorage.setItem('hg_age_ok','1');" : ""}if(!localStorage.getItem('__fixture_history_seeded')){localStorage.setItem('hgdj_search_history',JSON.stringify(['历史词']));localStorage.setItem('__fixture_history_seeded','1');}}catch{}`,
});
await context.route("**/*", async (route) => {
const request = route.request(),
@@ -302,7 +285,6 @@ const configure = async (context: BrowserContext, ageAccepted = false) => {
};
const ready = async (page: Page) => {
await page.waitForSelector(".hk-site-header");
await page.waitForFunction(() => !!window.__trackerCommonFields);
};
const footerQR = async (page: Page, value: string, previous = "") => {
await page.waitForFunction(({ value, previous }) => {
@@ -413,17 +395,8 @@ try {
await stack.keyboard.press("Escape");
await stack.waitForSelector("[data-dialog-ad]", { state: "detached" });
await expectOverflow(stack, "");
await stack.waitForTimeout(50);
assert.equal(
events.filter(
(event) =>
event.method === "adImpression" && event.payload.ad_id === "stack-1",
).length,
1,
);
await stacked.close();
imageRequested = 0;
events.length = 0;
// Age gate cannot be bypassed by Escape. Ads wait for actual XOR decode + image
// load, resume their queue on another page, and stay dismissed in this session.
const context = await browser.newContext({
@@ -459,7 +432,6 @@ try {
await page.waitForTimeout(150);
assert.equal(imageRequested, 1);
assert.equal(await page.locator("[data-dialog-ad]").isVisible(), false);
assert.equal(events.filter((e) => e.method === "adImpression").length, 0);
assert.equal(
await page.evaluate(() => localStorage.getItem("hg_age_ok")),
"1",
@@ -515,16 +487,6 @@ try {
await page.evaluate(() => sessionStorage.getItem("dialogAdDismissed")),
"2|1|2",
);
assert.equal(
events.filter((e) => e.method === "adImpression" && e.payload.ad_id === "1")
.length,
1,
);
assert.equal(
events.filter((e) => e.method === "adClick" && e.payload.ad_id === "1")
.length,
1,
);
await page.goto(origin + "/?ads=1&bad=1");
await ready(page);
await page.locator("[data-dialog-ad].hk-is-open").waitFor();
@@ -532,12 +494,6 @@ try {
await page.locator("[data-dialog-ad-id]").getAttribute("data-dialog-ad-id"),
"2",
);
assert.equal(
events.some(
(e) => e.method === "adImpression" && e.payload.ad_id === "bad",
),
false,
);
await page.keyboard.press("Escape");
// Actual HeaderSearch hooks, keyboard navigation and history; no account entry remains.
await page.goto(origin + "/?user=1");
@@ -1053,15 +1009,8 @@ try {
assert.ok(destinations.includes("/mock/android.apk"));
assert.ok(destinations.includes("/mock/fallback"));
assert.ok(destinations.includes("/mock/launch"));
assert.ok(
events.some(
(event) =>
event.method === "navigation" &&
event.payload.navigation_key === "header_download",
),
);
console.log(
"Native React site smoke passed: age gate/focus lock, encrypted advertisement readiness/failure/queue/cross-page session, footer QR pixels/size/URL/official fallback/empty configuration/restoration, HeaderSearch/history/keyboard/encoded URLs, configured desktop hover/focus/toggle/Escape/outside-click and mobile expandable navigation/canonical/external/download links, no login/user-menu/account entries, PC download and configured/fallback iOS/Android tabs/actions/deep links, drawer/footer/main entries, scroll/focus restoration and analytics. All APIs and outbound destinations isolated.",
"Native React site smoke passed: age gate/focus lock, encrypted advertisement readiness/failure/queue/cross-page session, footer QR pixels/size/URL/official fallback/empty configuration/restoration, HeaderSearch/history/keyboard/encoded URLs, configured desktop hover/focus/toggle/Escape/outside-click and mobile expandable navigation/canonical/external/download links, no login/user-menu/account entries, PC download and configured/fallback iOS/Android tabs/actions/deep links, drawer/footer/main entries, scroll/focus restoration. All APIs and outbound destinations isolated.",
);
} finally {
releaseImage?.();