chore: initialize WanderQ MiniAPP 2.0 repository
This commit is contained in:
129
scripts/probe-secondary.mjs
Normal file
129
scripts/probe-secondary.mjs
Normal file
@@ -0,0 +1,129 @@
|
||||
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();
|
||||
Reference in New Issue
Block a user