import type { Page, Route } from "@playwright/test"; export const FOUR_TIER_QUOTES = [ { service_level: "standard", rate_option: "lowest", carrier: "Mothership", transit_days: "5-7", transit_description: "最低价格", raw_freight: 320, surcharges: 15, raw_total: 335, markup_percent: 0, markup_amount: 0, final_total: 335, breakdown: [ { item: "基础运费", amount: 320 }, { item: "附加费", amount: 15 }, { item: "加价", amount: 0 }, ], }, { service_level: "standard", rate_option: "fastest", carrier: "Mothership", transit_days: "3-4", transit_description: "最快送达", raw_freight: 365, surcharges: 0, raw_total: 365, markup_percent: 0, markup_amount: 0, final_total: 365, breakdown: [ { item: "基础运费", amount: 365 }, { item: "附加费", amount: 0 }, { item: "加价", amount: 0 }, ], }, { service_level: "guaranteed", rate_option: "lowest", carrier: "Mothership", transit_days: "4-5", transit_description: "保价最低", raw_freight: 380, surcharges: 0, raw_total: 380, markup_percent: 0, markup_amount: 0, final_total: 380, breakdown: [ { item: "基础运费", amount: 380 }, { item: "附加费", amount: 0 }, { item: "加价", amount: 0 }, ], }, { service_level: "guaranteed", rate_option: "fastest", carrier: "Mothership", transit_days: "2-3", transit_description: "保价最快", raw_freight: 410, surcharges: 0, raw_total: 410, markup_percent: 0, markup_amount: 0, final_total: 410, breakdown: [ { item: "基础运费", amount: 410 }, { item: "附加费", amount: 0 }, { item: "加价", amount: 0 }, ], }, ]; type MockMode = "cache" | "processing" | "stale" | "error"; export async function mockQuoteApi( page: Page, mode: MockMode, ): Promise { let pollCount = 0; await page.route("**/api/quotes", async (route: Route) => { if (route.request().method() === "POST") { if (mode === "error") { await route.fulfill({ status: 400, contentType: "application/json", body: JSON.stringify({ code: "VALIDATION_FAILED", message: "请求参数无效", data: null, }), }); return; } const status = mode === "processing" ? "processing" : "done"; await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ code: 0, message: "ok", data: { quote_id: "QTE_E2E_001", status, source_type: mode === "stale" ? "stale" : "cache", is_realtime: mode !== "stale", }, }), }); return; } await route.continue(); }); await page.route("**/api/quotes/*", async (route: Route) => { if (route.request().method() !== "GET") { await route.continue(); return; } if (mode === "processing") { pollCount += 1; if (pollCount < 2) { await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ code: 0, message: "ok", data: { quote_id: "QTE_E2E_001", request_id: "req-e2e", status: "processing", currency: "USD", }, }), }); return; } } if (mode === "error") { await route.fulfill({ status: 500, contentType: "application/json", body: JSON.stringify({ code: "INTERNAL_ERROR", message: "服务异常", data: null, }), }); return; } await route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify({ code: 0, message: "ok", data: { quote_id: "QTE_E2E_001", request_id: "req-e2e", status: "done", currency: "USD", source_type: mode === "stale" ? "stale" : "cache", is_realtime: mode !== "stale", confidence_score: mode === "stale" ? 0.6 : 1, valid_until: new Date(Date.now() + 180_000).toISOString(), quotes: FOUR_TIER_QUOTES, }, }), }); }); } export async function fillQuoteForm(page: Page): Promise { await page.locator('input[name="p_street"]').fill("1234 Warehouse Blvd"); await page.locator('input[name="p_city"]').fill("Los Angeles"); await page.locator('select[name="p_state"]').selectOption("CA"); await page.locator('input[name="p_zip"]').fill("90001"); await page .getByRole("button") .filter({ hasText: "Los Angeles" }) .first() .click(); await page.locator('input[name="d_street"]').fill("5678 Distribution Dr"); await page.locator('input[name="d_city"]').fill("Dallas"); await page.locator('select[name="d_state"]').selectOption("TX"); await page.locator('input[name="d_zip"]').fill("75201"); await page .getByRole("button") .filter({ hasText: "Dallas" }) .first() .click(); await page.locator('input[name="weight"]').fill("500"); await page.locator('input[name="pallet_count"]').fill("2"); }