Files
WanderQ-MiniAPP2.0/scripts/probe-secondary.mjs

130 lines
4.4 KiB
JavaScript

import fs from "node:fs/promises";
import path from "node:path";
import { chromium, devices } from "playwright";
const targetUrl =
"https://m.ctrip.com/tangram/OTQ1Mg==?ctm_ref=vactang_page_9452&isHideNavBar=YES&ctm_ref=vactang_page_159930";
const outDir = path.join(process.cwd(), "docs", "research", "secondary");
const shotDir = path.join(process.cwd(), "docs", "design-references", "secondary");
await fs.mkdir(outDir, { recursive: true });
await fs.mkdir(shotDir, { recursive: true });
const browser = await chromium.launch({ headless: true });
async function newPage() {
const context = await browser.newContext({
...devices["iPhone 13 Pro"],
viewport: { width: 390, height: 844 },
locale: "zh-CN",
timezoneId: "Asia/Shanghai",
extraHTTPHeaders: { "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8" },
});
const page = await context.newPage();
const events = [];
page.on("console", (msg) => {
if (msg.type() === "error") events.push({ type: "console-error", text: msg.text().slice(0, 300) });
});
page.on("pageerror", (err) => events.push({ type: "page-error", text: err.message.slice(0, 300) }));
await page.goto(targetUrl, { waitUntil: "domcontentloaded", timeout: 60000 });
await page.waitForTimeout(6000);
return { context, page, events };
}
async function snap(name, page, events, extra = {}) {
await page.screenshot({ path: path.join(shotDir, `${name}.png`), fullPage: false });
const data = await page.evaluate(() => ({
title: document.title,
url: location.href,
scrollY,
bodyText: document.body.innerText.slice(0, 2500),
buttons: [...document.querySelectorAll('button, a, [role="button"], .nav_bottom_item')].slice(0, 100).map((el) => ({
tag: el.tagName.toLowerCase(),
text: el.textContent?.trim().replace(/\s+/g, " ").slice(0, 160) ?? "",
className: String(el.className ?? "").slice(0, 160),
href: el instanceof HTMLAnchorElement ? el.href : "",
rect: (() => {
const r = el.getBoundingClientRect();
return { x: Math.round(r.x), y: Math.round(r.y), w: Math.round(r.width), h: Math.round(r.height) };
})(),
})),
}));
await fs.writeFile(path.join(outDir, `${name}.json`), JSON.stringify({ ...data, events, extra }, null, 2));
return data;
}
async function probe(name, action) {
const { context, page, events } = await newPage();
let error = null;
try {
await action(page);
await page.waitForTimeout(5000);
} catch (err) {
error = err instanceof Error ? err.message : String(err);
}
const data = await snap(name, page, events, { error });
await context.close();
return {
name,
error,
title: data.title,
url: data.url,
text: data.bodyText.slice(0, 200).replace(/\n/g, "|"),
};
}
const results = [];
results.push(
await probe("search-click", async (page) => {
await page.locator(".icon-wrap").filter({ hasText: "搜索" }).first().click({ timeout: 10000 });
}),
);
results.push(
await probe("support-click", async (page) => {
await page.locator(".icon-wrap").filter({ hasText: "客服" }).first().click({ timeout: 10000 });
}),
);
results.push(
await probe("product-first-click", async (page) => {
for (let y = 0; y < 2400; y += 600) {
await page.evaluate((scrollY) => scrollTo(0, scrollY), y);
await page.waitForTimeout(500);
}
const item = page.locator(".diy_product_flex_item.expose_dom").filter({ hasText: "¥" }).first();
await item.scrollIntoViewIfNeeded();
await page.waitForTimeout(500);
await item.click({ timeout: 10000 });
}),
);
results.push(
await probe("bottom-destination-click", async (page) => {
await page.locator(".nav_bottom_item").filter({ hasText: "目的地" }).first().click({ timeout: 10000 });
}),
);
results.push(
await probe("bottom-manager-click", async (page) => {
await page.locator(".nav_bottom_item").filter({ hasText: "客户经理" }).first().click({ timeout: 10000 });
}),
);
results.push(
await probe("bottom-message-click", async (page) => {
await page.locator(".nav_bottom_item").filter({ hasText: "消息" }).first().click({ timeout: 10000 });
}),
);
results.push(
await probe("bottom-order-click", async (page) => {
await page.locator(".nav_bottom_item").filter({ hasText: "订单" }).first().click({ timeout: 10000 });
}),
);
await fs.writeFile(path.join(outDir, "probe-summary.json"), JSON.stringify(results, null, 2));
console.log(JSON.stringify(results, null, 2));
await browser.close();