summaryrefslogtreecommitdiff
path: root/qa/driver
diff options
context:
space:
mode:
authorSomhairle H. Marisol <[email protected]>2026-09-22 02:29:30 +0800
committerSomhairle H. Marisol <[email protected]>2026-09-22 02:29:30 +0800
commit8c01adf05f1428bf2ada49574b25529c064da884 (patch)
tree6342850684ff70bae877855d91074f7af3e4a030 /qa/driver
parent7da3c3d938e4b64a43963d602ab4a0a8c89f6f9e (diff)
downloadfund-lab-8c01adf05f1428bf2ada49574b25529c064da884.tar.gz
Add stocks probe panel with live stock quote flow (3d-18)
Diffstat (limited to 'qa/driver')
-rw-r--r--qa/driver/browser-test.js70
1 files changed, 70 insertions, 0 deletions
diff --git a/qa/driver/browser-test.js b/qa/driver/browser-test.js
index dddc562..424872a 100644
--- a/qa/driver/browser-test.js
+++ b/qa/driver/browser-test.js
@@ -35,6 +35,7 @@ let lastRebalanceExecutionsResponse = null;
let lastNavDatesResponse = null;
let lastNavSeriesResponse = null;
let lastBondQuoteResponse = null;
+let lastStockQuoteResponse = null;
function check(name, ok, detail) {
results.push({ name, ok, detail: detail || "" });
@@ -189,6 +190,11 @@ async function summaryLabelExists(page, label, name) {
lastBondQuoteResponse = await r.json();
} catch {}
}
+ if (r.url().includes("/market/stock-quote") && r.request().method() === "GET" && r.status() < 400) {
+ try {
+ lastStockQuoteResponse = await r.json();
+ } catch {}
+ }
if (r.status() >= 400 && !/\/api\/instruments\//.test(r.url()) && !/\/api\/market\//.test(r.url()) && !/\/orders/.test(r.url()) && !/\/redemptions/.test(r.url()) && !/\/capital/.test(r.url())) {
consoleErrors.push("resource " + r.status() + ": " + r.url());
}
@@ -241,6 +247,7 @@ async function summaryLabelExists(page, label, name) {
await plansScenario(page);
await rebalanceScenario(page);
await bondsScenario(page);
+ await stocksScenario(page);
} finally {
check("G1 无浏览器控制台/页面错误", consoleErrors.length === 0, consoleErrors.slice(0, 3).join(" | "));
await browser.close();
@@ -694,6 +701,69 @@ async function bondsScenario(page) {
await page.screenshot({ path: SHOTS + "/21-bonds.png" });
}
+async function stocksScenario(page) {
+ // S 系列: 股票行情探针面板走真实 API(QA 环境由桩采集器提供,非前端 mock)。
+ await page.waitForSelector(".stocks-panel", { timeout: 10000 });
+
+ lastStockQuoteResponse = null;
+ await page.fill(".stock-code-input", "600519");
+ await page.click(".stock-quote-action");
+ await page.waitForSelector(".stock-quote-result", { timeout: 10000 });
+
+ const resultText = ((await page.textContent(".stock-quote-result")) || "").trim();
+ const quote = lastStockQuoteResponse || {};
+
+ check(
+ "S1 真实可用股票返回名称与价格字符串",
+ quote.code === "600519" &&
+ typeof quote.name === "string" &&
+ quote.name.includes("贵州茅台") &&
+ typeof quote.price === "string" &&
+ quote.price.length > 0 &&
+ resultText.includes("贵州茅台") &&
+ resultText.includes(quote.price),
+ `quote=${JSON.stringify(quote).slice(0, 160)} result=${resultText.slice(0, 160)}`
+ );
+
+ await page.fill(".stock-code-input", "999999");
+ await page.click(".stock-quote-action");
+ await page.waitForFunction(
+ () => {
+ const element = document.querySelector(".stock-quote-unavailable");
+ return element && !element.hidden && element.textContent.includes("股票行情不可用");
+ },
+ { timeout: 10000 }
+ );
+
+ const unavailableText = ((await page.textContent(".stock-quote-unavailable")) || "").trim();
+ const resultGone = (await page.locator(".stock-quote-result").count()) === 0;
+ const token = process.env.QA_TOKEN || "qa-token";
+
+ const failure = await page.evaluate(async (token) => {
+ const response = await fetch("/api/market/stock-quote?code=999999", {
+ headers: { Authorization: `Bearer ${token}` },
+ });
+ let body = null;
+ try {
+ body = await response.json();
+ } catch {}
+ return { status: response.status, body };
+ }, token);
+
+ check(
+ "S2 无有效报价时显示不可用提示且不显示 0 占位",
+ unavailableText.includes("股票行情不可用") &&
+ resultGone &&
+ !unavailableText.includes("0.00") &&
+ failure.status === 503 &&
+ failure.body &&
+ failure.body.error === "MARKET_DATA_UNAVAILABLE",
+ `message=${unavailableText.slice(0, 200)} status=${failure.status}`
+ );
+
+ await page.screenshot({ path: SHOTS + "/22-stocks.png" });
+}
+
async function postInvestmentPlanViaApi(page, fundId, token) {
return page.evaluate(
async ({ fundId, token }) => {