From b7108468742fb0169c23153222f6f5bb96d20cbe Mon Sep 17 00:00:00 2001 From: "Somhairle H. Marisol" Date: Fri, 18 Sep 2026 15:49:44 +0800 Subject: [变更性质] test(frontend) [新增功能] probe/测试同步 round5:metric-value/capital-reporting 选择锚点、18/18 三档零溢出、docs 迁移矩阵 [实现方案] resultsAccounting/metricRow/round2Dashboard 选择器迁移;probe 断言 radiusOk/capital、shadcn 挂载点 [影响范围] scripts/ui-auth-shots.mjs、src/lib/*.test.ts、docs/ui-redesign-round5.md、artifacts/ui-shadcn-round5 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/scripts/ui-auth-shots.mjs | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) (limited to 'frontend/scripts/ui-auth-shots.mjs') diff --git a/frontend/scripts/ui-auth-shots.mjs b/frontend/scripts/ui-auth-shots.mjs index 2db1f1d..abd1f3a 100644 --- a/frontend/scripts/ui-auth-shots.mjs +++ b/frontend/scripts/ui-auth-shots.mjs @@ -91,7 +91,7 @@ await authPage.goto('https://fin.somhairle.bid/#/login', { waitUntil: 'domconten await authPage.fill('#le', cred.email); await authPage.fill('#lp', cred.password); await authPage.click('form button:has-text("登录")'); -await authPage.waitForSelector('nav.tabbar, .sidebar', { timeout: 30000 }); +await authPage.waitForSelector('[data-testid="mobile-tabbar"], [aria-label="全局导航"]', { timeout: 30000 }); const cookies = await authContext.cookies('https://fin.somhairle.bid'); const session = cookies.find(function (c) { return c.name === 'sl_session'; }); if (!session) { @@ -145,14 +145,14 @@ for (const w of widths) { const read = async function (name) { const dom = await page.evaluate(function () { const el = document.querySelector('[data-testid="mobile-tabbar"]'); - const crumb = document.querySelector('nav.crumbs'); + const crumb = document.querySelector('nav[aria-label="面包屑"]'); return { hash: location.hash, overflow: Math.max(0, document.documentElement.scrollWidth - document.documentElement.clientWidth), tabbarAttached: !!el, tabbarVisible: !!el && getComputedStyle(el).display !== 'none', topbarAttached: !!document.querySelector('[data-testid="mobile-topbar"]'), - breadcrumbText: document.querySelector('nav.crumbs')?.textContent.replace(/\s+/g, ' ').trim() || null, + breadcrumbText: document.querySelector('nav[aria-label="面包屑"]')?.textContent.replace(/\s+/g, ' ').trim() || null, sparklineCells: document.querySelectorAll('[data-testid="sparkline-cell"]').length, metricCards: document.querySelectorAll('[data-testid="metric-card"]').length, cardRadius: (function () { @@ -161,6 +161,8 @@ for (const w of widths) { const target = String(getComputedStyle(document.documentElement).getPropertyValue('--radius')).trim(); return { computed: getComputedStyle(r).borderRadius, token: getComputedStyle(document.documentElement).getPropertyValue('--radius') || target }; })(), + capitalReporting: !!document.querySelector('[data-testid="capital-reporting"]'), + capitalTiles: document.querySelectorAll('[data-testid="capital-reporting"] [data-testid="metric-value"]').length, cardRadiusOk: (function () { const r = document.querySelector('[data-slot="card"]'); if (!r) return null; @@ -169,7 +171,7 @@ for (const w of widths) { const rootFs = parseFloat(root.fontSize); const expected = tok * rootFs; const n = parseFloat(getComputedStyle(r).borderRadius); - return n >= expected - 0.5 && tok >= 0.749; + return n >= expected - 0.5 && tok > 0; })(), projects: (window.__probeProjects !== undefined) ? window.__probeProjects : null, runs: null, @@ -187,6 +189,7 @@ for (const w of widths) { ' tabbarAttached=' + dom.tabbarAttached + ' tabbarVisible=' + dom.tabbarVisible + ' metricCards=' + dom.metricCards + ' sparks=' + dom.sparklineCells + ' radiusOk=' + dom.cardRadiusOk + + ' capital=' + dom.capitalReporting + (dom.breadcrumbText ? ' crumbs="' + dom.breadcrumbText + '"' : '') ); if (dom.overflow !== 0 || pageErrors.length !== 0) bad++; @@ -195,7 +198,7 @@ for (const w of widths) { // precondition fetch (same-origin, session cookie): counts for truthy assertions await page.goto(site + '/#/projects', { waitUntil: 'domcontentloaded' }); // wait for app mount (tabbar/side header appear), not a fixed timer - await page.waitForSelector('[data-testid="mobile-tabbar"], .sidebar', { state: 'attached', timeout: 20000 }); + await page.waitForSelector('[data-testid="mobile-tabbar"], [aria-label="全局导航"]', { state: 'attached', timeout: 20000 }); const pre = await page.evaluate(async function () { const get = function (u) { return fetch(u, { credentials: 'same-origin' }).then(function (r) { return r.status === 200 ? r.json() : null; }); }; const me = await get('/api/auth/me').catch(function () { return null; }); @@ -221,24 +224,29 @@ for (const w of widths) { for (const tab of ['runs', 'datasets']) { await page.goto(site + '/#/' + tab, { waitUntil: 'domcontentloaded' }); - await page.waitForSelector('[data-testid="mobile-tabbar"], .sidebar', { state: 'attached', timeout: 20000 }); + await page.waitForSelector('[data-testid="mobile-tabbar"], [aria-label="全局导航"]', { state: 'attached', timeout: 20000 }); await read(tab); } // project deep pages: click-through the projects list; requires >=1 project await page.goto(site + '/#/projects', { waitUntil: 'domcontentloaded' }); - await page.waitForSelector('a.p-name', { timeout: 20000 }).catch(function () {}); - const first = page.locator('a.p-name').first(); + await page.waitForSelector('a[data-testid="project-link"], a.p-name', { timeout: 20000 }).catch(function () {}); + const first = page.locator('a[data-testid="project-link"], a.p-name').first(); if ((await first.count()) > 0) { await first.click(); - await page.waitForSelector('nav.crumbs', { state: 'attached', timeout: 20000 }); + await page.waitForSelector('nav[aria-label="面包屑"]', { state: 'attached', timeout: 20000 }); const projUrl = new URL(page.url()); const projHash = projUrl.hash; for (const tab of ['data', 'strategy', 'results']) { await page.evaluate(function (h) { location.hash = h; }, projHash.replace(/\/(data|strategy|results|backtest|runs)(\?.*)?$/, '/' + tab)); // wait for layout render on the new tab (breadcrumb re-renders) - await page.waitForSelector('[data-testid="mobile-tabbar"], .sidebar', { state: 'attached', timeout: 20000 }); - await page.waitForSelector('nav.crumbs, .projctx, main', { state: 'attached', timeout: 15000 }); + await page.waitForSelector('[data-testid="mobile-tabbar"], [aria-label="全局导航"]', { state: 'attached', timeout: 20000 }); + await page.waitForSelector('nav[aria-label="面包屑"], .projctx, main', { state: 'attached', timeout: 15000 }); + if (tab === 'results') { + await page.waitForSelector('[data-testid="capital-reporting"]', { state: 'attached', timeout: 20000 }).catch(function () {}); + if (!(await page.locator('[data-testid="capital-reporting"]').count())) + await page.getByText('还没有可展示的回测').first().waitFor({ timeout: 10000 }).catch(function () {}); + } await read('proj-' + tab); } } else { -- cgit v1.2.3