test(qa): chat tab selector handles unread badge suffix
build-and-publish / test (push) Has been cancelled
build-and-publish / image (push) Has been cancelled

The new topbar badge on the Chat tab (chatThreadCount > 0) broke the
old /^\\s*Chat\\s*$/ regex. Switched to a Playwright filter chain:
.tab filtered by hasText 'Chat' AND hasNotText 'Assistant' (which also
contains 'Chat' substring elsewhere in DOM). All 4 QA suites green:

- 36/36 dogfood (chat_sidebar threads=8 previews=8 times=8)
- 12/12 buyer-script (Approvals action disabled? true)
- 8/8 idle-poll (0 reqs at 30s on every scene)
- 14/14 mobile (390px clean)
This commit is contained in:
2026-06-14 18:44:57 +04:00
parent be20b189a3
commit dd83530d6a
2 changed files with 17 additions and 1 deletions
+2 -1
View File
@@ -262,7 +262,8 @@ record("llm_unconfigured_falls_back_gracefully", unmatchedReply.length > 0 && !/
// 17. CHAT polish: open Chat tab; if any thread exists, sidebar shows relative // 17. CHAT polish: open Chat tab; if any thread exists, sidebar shows relative
// timestamps and last-message previews; unread aggregate banner shows when // timestamps and last-message previews; unread aggregate banner shows when
// other personas have written since last open. // other personas have written since last open.
await p.locator(".tab", { hasText: /^\s*Chat\s*$/ }).click(); const chatTab = p.locator(".tab").filter({ hasText: "Chat" }).filter({ hasNotText: "Assistant" }).first();
await chatTab.click({ timeout: 15000 });
await p.waitForTimeout(2500); await p.waitForTimeout(2500);
const initialThreadCount = await p.locator(".chat-thread-row").count(); const initialThreadCount = await p.locator(".chat-thread-row").count();
if (initialThreadCount === 0) { if (initialThreadCount === 0) {
+15
View File
@@ -0,0 +1,15 @@
import { chromium } from "playwright";
const args = ["--host-resolver-rules=MAP canvas.flow-master.ai 65.21.71.186", "--ignore-certificate-errors"];
const b = await chromium.launch({ headless: true, args });
const p = await (await b.newContext({ viewport: { width: 1440, height: 900 } })).newPage();
await p.goto("https://canvas.flow-master.ai/", { waitUntil: "networkidle" });
await p.waitForTimeout(800);
await p.locator(".persona-chip", { hasText: /Mariana/ }).click();
await p.locator(".dev-login-btn").click();
await p.waitForSelector(".hero-actions", { timeout: 15000 });
await p.waitForFunction(() => document.querySelectorAll(".hub-chip").length >= 8, undefined, { timeout: 15000 }).catch(() => {});
await p.locator(".hub-chip", { hasText: /Procurement Hub/ }).click();
await p.waitForTimeout(2000);
const tabs = await p.locator(".tab").evaluateAll((els) => els.map((e) => JSON.stringify(e.textContent)));
console.log("tabs:", tabs);
await b.close();