-
Notifications
You must be signed in to change notification settings - Fork 1
docs(qa): web UI manual QA pass + fix grid column overflow (closes #28) #34
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 4 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
7baff7d
docs(qa): web UI manual QA pass + fix grid column overflow (closes #28)
timon0305 590dc21
review: CodeRabbit fixes — MD040 fence + curl timeouts on smoke
timon0305 a6c3ae9
review: fail smoke on /api/workspaces parse error (CodeRabbit)
timon0305 fdbb940
review: address 5 Brad findings on the QA checklist + smoke script
timon0305 cc2a8f4
fix(ui): sidebar-item-time truncation for fixed 280px sidebar
timon0305 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,300 @@ | ||
| # Web UI — manual QA checklist | ||
|
|
||
| Companion document for issue #28. Run this whenever the web UI (templates, | ||
| `static/js/*`, or any route in `api/`) is touched. Each section below has a | ||
| **backend smoke** result captured automatically by | ||
| [`tests/web-ui-smoke.sh`](web-ui-smoke.sh) and a **visual checklist** that a | ||
| human reviewer fills in with Chrome + Firefox screenshots. | ||
|
|
||
| Boot the app with `python app.py` (default port 3000) and follow the | ||
| sections in order. Attach the captured screenshots to the PR that closes | ||
| issue #28; visual bugs file as follow-up issues per the acceptance | ||
| criteria. | ||
|
|
||
| ### Verification-method legend | ||
|
timon0305 marked this conversation as resolved.
Outdated
|
||
|
|
||
| A reviewer should be able to audit any `[x]` and tell *how* it was | ||
| verified. The default is **visual** — a human confirmed it in Chrome | ||
| **and** Firefox, with the screenshot in `samples/qa/` as evidence. | ||
| Ticks that deviate from that default carry an explicit tag: | ||
|
|
||
| - **(probe)** — confirmed by `tests/web-ui-smoke.sh` or a one-off curl; | ||
| the wire-level response was the evidence (no browser click). | ||
| - **(code)** — confirmed by reading the underlying handler / CSS rule; | ||
| no live browser click. Used only when the data path is shared with | ||
| another item that *was* visually verified. | ||
| - **⏳** — known not exercised; not blocking acceptance but the row is | ||
| honest about it. The reviewer can convert these to `[x]` with a click. | ||
|
|
||
| ## Environment | ||
|
|
||
| | Item | Value | | ||
| |-------------------|----------------------------------------------------------| | ||
| | OS / version | | | ||
| | Python version | `python3 --version` | | ||
| | Browser A | Chrome | | ||
| | Browser A version | | | ||
| | Browser B | Firefox | | ||
| | Browser B version | | | ||
| | Repo SHA | `git rev-parse HEAD` | | ||
| | Cursor data | default `~/.config/Cursor/User/workspaceStorage` (or override via `WORKSPACE_PATH`) | | ||
| | Reviewer | | | ||
| | Date | | | ||
|
|
||
| ## 0. Server launch | ||
|
|
||
| ```bash | ||
| python app.py | ||
| ``` | ||
|
|
||
| - [x] **(probe)** Server stays running for at least 60s without crash | ||
| - [x] **(probe)** Stdout: `Cursor Chat Browser (Python) running at http://127.0.0.1:3000` | ||
| - [x] **(probe)** `tests/web-ui-smoke.sh` exits 0 — 11/11 probes pass | ||
| - [x] **(probe)** No `Traceback` / `Error` in stdout during smoke run | ||
|
|
||
| ## 1. Home / Projects list — `GET /` | ||
|
|
||
| **Backend smoke:** expect `HTTP 200` and the page sniff must include | ||
| `<title>Projects — Cursor Chat Browser</title>` and the text `Cursor Chat | ||
| Browser`. | ||
|
|
||
| **Chrome:** | ||
|
|
||
|  | ||
|
|
||
| - [x] Page loads, no JS console errors | ||
| - [x] Workspace cards render with workspace name + conversation count | ||
| - [x] "Other chats" card present for global storage | ||
| - [x] Clicking a workspace card navigates to `/workspace/<id>` | ||
| - [x] Dark / light mode toggle works (if present) | ||
|
|
||
| **Firefox:** | ||
|
|
||
|  | ||
|
|
||
| - [x] Same checks pass as Chrome | ||
|
|
||
| ## 2. Workspace detail — `GET /workspace/<workspace_id>` | ||
|
|
||
| **Backend smoke:** expect `HTTP 200`, content length > 5KB. JSON endpoints | ||
| `/api/workspaces/<id>` and `/api/workspaces/<id>/tabs` must both return 200. | ||
|
|
||
| **Chrome:** | ||
|
|
||
|  | ||
|
|
||
| - [x] Conversation list (left panel) renders with at least one row | ||
| - [x] Each row shows title, timestamp, model name | ||
| - [x] Clicking a conversation loads its bubbles in the right panel | ||
| - [x] Last-updated sort order is descending (newest first) | ||
| - [x] Search box at the top filters conversations as you type | ||
| - [x] No `404 / 500` in the network tab when switching conversations | ||
| - [x] Right panel stays inside viewport (regression check for the | ||
| `.main-content { min-width: 0 }` fix landed in this PR — see §8) | ||
|
|
||
| **Firefox:** | ||
|
|
||
|  | ||
|
|
||
| - [x] Same checks pass as Chrome | ||
|
|
||
| ## 3. Conversation view — markdown / code / tools / thinking | ||
|
|
||
| Open any conversation that contains code blocks, tool calls, and a | ||
| thinking block (the seeded `cppa-cursor-browser` PR review conversations | ||
| are good candidates). | ||
|
|
||
| **Markdown:** | ||
|
|
||
| - [x] Headers `#`, `##`, `###` render at distinct sizes | ||
| - [x] Inline `` `code` `` renders in monospace with background tint | ||
| - [x] Fenced code blocks render with syntax highlighting (Prism) | ||
| (backend-verified: bubble text payload contains fenced-code-block | ||
| delimiters; conversation screenshot shows highlighted output) | ||
| - [x] Numbered + bulleted lists render with correct indentation | ||
| - [x] Inline links are clickable, open in a new tab | ||
| - [x] Tables render with cell borders | ||
|
|
||
| **Tool calls:** | ||
|
|
||
| - [x] Tool name shown in the bubble header | ||
| (backend-verified: sampled bubble had `toolCalls[0].name = "glob_file_search"`) | ||
| - [x] Tool input (`params`) shown in a collapsible / styled block | ||
| (backend-verified: `toolCalls[0]` carried a non-empty `parameters` field) | ||
| - [x] Tool output (`result`) shown below the input | ||
| (rendered in the conversation screenshot) | ||
| - [x] Tool status (success / error) visually distinguishable | ||
| (backend-verified: `toolCalls[0].status = "completed"`; CSS rules | ||
| `.tool-call-status.completed / .error / .running` in style.css) | ||
| - [x] Long tool outputs wrap or scroll, not overflow horizontally | ||
| (`.tool-call-content { overflow: auto; word-break: break-all }` | ||
| plus the `.main-content { min-width: 0 }` fix landed in this PR) | ||
|
|
||
| **Thinking blocks:** | ||
|
|
||
| - [x] Collapsible "Thinking" section is collapsed by default | ||
| (verified in the workspace screenshot — `Thinking 21s` chip visible) | ||
| - [x] Backend data shape correct: a sampled bubble carries | ||
| `metadata.thinking = "The user is asking whether it's a good idea..."` | ||
| and `metadata.thinkingDurationMs = 3569` | ||
| - ⏳ Expanding it shows the reasoning text — not exercised this pass (a one-click visual check; data presence already verified via `metadata.thinking` on a sampled bubble above) | ||
| - [x] Duration (`thinkingDurationMs`) shown in human format (e.g. `4.2s`) | ||
| — visible as `Thinking 21s` in the workspace screenshot | ||
|
|
||
| **XSS sanitization (regression check from `test_xss_sanitization.py`):** | ||
|
|
||
| - [x] No raw `<script>` tags visible in any bubble | ||
| - [x] No `onerror` / `onclick` handlers fire on hover / click of bubble content | ||
|
|
||
| **Chrome:** | ||
|
|
||
|  | ||
|
|
||
| **Firefox:** | ||
|
|
||
|  | ||
|
|
||
| ## 4. Search — `GET /search` + `GET /api/search?q=...` | ||
|
|
||
| **Backend smoke:** | ||
| - `/search` (page) → `HTTP 200` | ||
| - `/api/search?q=<known-term>` → `HTTP 200` | ||
| - `/api/search` (no `q`) → `HTTP 400` with body `{"error":"No search query provided"}` | ||
|
|
||
| **Chrome:** | ||
|
|
||
|  | ||
|
|
||
| **Firefox:** | ||
|
|
||
|  | ||
|
|
||
| - [x] Search box at `/search` accepts input | ||
| - [x] Submitting an empty query shows a useful error, not a 500 page | ||
| - [x] A known-good query (e.g. `project` — returned 9 results in the screenshot) returns results | ||
| - [x] Each result shows: workspace name, chat title, snippet with the | ||
| query highlighted | ||
| - [x] Clicking a result navigates to the correct conversation | ||
| (backend-verified: `/workspace/global?tab=<chatId>` returns HTTP 200 | ||
| with the workspace template; JS handles the `?tab=` param client-side | ||
| to scroll to the matching conversation) | ||
| - [x] No layout breakage with very long query strings (paste a 500-char query) | ||
|
|
||
| ## 5. Config page — `GET /config` | ||
|
|
||
| **Backend smoke:** `HTTP 200`, content length > 5KB. `/api/detect-environment` | ||
| must return `HTTP 200`. | ||
|
|
||
| **Chrome:** | ||
|
|
||
|  | ||
|
|
||
| **Firefox:** | ||
|
|
||
|  | ||
|
|
||
| - [x] Current workspace path shown | ||
| - [x] "Change workspace" form accepts a valid path and applies it | ||
| - [x] Invalid path (traversal, missing dir) is rejected with a clear error | ||
| - [x] Environment auto-detect indicator matches actual platform | ||
| (`Linux native`, `WSL`, `macOS`, `SSH remote`, `Windows`) | ||
|
|
||
| ## 6. Export functionality | ||
|
|
||
| Open any conversation, then trigger each export button. Each must produce | ||
| a file that opens cleanly in its native viewer. | ||
|
|
||
| | Format | Button trigger | Expected result | | ||
| |--------|----------------|-----------------| | ||
| | Markdown | "Export → Markdown" | `.md` with YAML frontmatter from the web UI pipeline (`title`, `created`, `conversation_id`, plus optional `models_used` / token + cost fields) + transcript. NOTE: this is the **web UI** schema in `static/js/download.js`, not the CLI-export schema from issue #27 (`log_id`, `workspace`, etc.). | | ||
| | HTML | "Export → HTML" | `.html` with Prism-highlighted code; opens in browser | | ||
| | JSON | "Export → JSON" | `.json` is valid JSON parseable by `jq .` | | ||
| | CSV | "Export → CSV" | `.csv` opens in a spreadsheet; one row per bubble | | ||
| | PDF | "Export → PDF" | `.pdf` opens in Acrobat / Preview; pagination clean | | ||
|
|
||
| **Verified during this QA pass — all 5 buttons clicked, each file inspected:** | ||
|
|
||
| | Format | File size | Validation result | | ||
| |--------|-----------|-------------------| | ||
| | `.md` | 587 KB | UTF-8, starts with YAML frontmatter (`title`, `created`, `conversation_id`, `models_used`, token + cost stats) | | ||
| | `.html` | 663 KB | `<!DOCTYPE html>` + embedded CSS + dark-mode `@media (prefers-color-scheme: dark)` | | ||
| | `.pdf` | 214 KB | `file` reports "PDF document, version 1.3, **153 page(s)**" — opens cleanly | | ||
| | `.json` | 654 KB | Valid JSON, top-level keys `bubbles`, `codeBlockDiffs`, `id`, `metadata`, `timestamp`, `title` | | ||
| | `.csv` | 592 KB | 391 rows (1 header + 390 bubbles), 21 columns covering tokens, thinking, tool calls | | ||
|
|
||
| Backend endpoint check (run earlier in this QA pass): | ||
| ```text | ||
| POST /api/generate-pdf | ||
| → HTTP 200, Content-Type: application/pdf, %PDF-1.3 magic, %%EOF terminator | ||
| ``` | ||
|
|
||
| - [x] All five formats download from Chrome | ||
| - [x] All five formats download from Firefox | ||
| - [x] PDF endpoint returns valid `application/pdf` over the wire | ||
| - [x] No silent failures — every clicked button produced a file | ||
| - [x] **Cross-browser parity proven byte-identical for `.md` / `.html` / | ||
| `.json` / `.csv`** — `cmp -s` returns equal between Chrome and | ||
| Firefox outputs. The JS export pipeline in `static/js/download.js` | ||
| is browser-agnostic. | ||
| - [x] PDF bytes differ across browsers but both are valid 153-page PDFs | ||
| — expected because `/api/generate-pdf` embeds a fresh | ||
| `/CreationDate` on each call. | ||
|
|
||
| ## 7. Cross-browser parity | ||
|
|
||
| This section was initially drafted as a list of "weird browser things" | ||
| but two of the four rows ended up testing features that don't exist in | ||
| this codebase (per-bubble copy button and arrow-key sidebar navigation). | ||
| Replaced with the cross-browser checks that target features actually | ||
| shipped today. Issue #28's required acceptance criteria are covered by | ||
| §1–§6 + the byte-identical export evidence; §7 is supplementary. | ||
|
|
||
| | Check | Chrome | Firefox | Evidence | | ||
| |-------|--------|---------|----------| | ||
| | Long code blocks scroll horizontally inside the bubble (do not overflow the column) | ✅ | ✅ | Visible in the `conversation-*.png` screenshots after the `.main-content { min-width: 0 }` fix | | ||
| | Export buttons (md / html / json / csv / pdf) all download a valid file | ✅ | ✅ | `.md`/`.html`/`.json`/`.csv` byte-identical across browsers (cmp -s); both PDFs are valid 153-page documents — see §6 | | ||
| | `Copy All` button copies the whole chat as Markdown to the clipboard | ✅ | ✅ | `copyAllMarkdown()` at [download.js:286-298](../static/js/download.js#L286-L298) calls `convertChatToMarkdown(selectedTab, true)` — the same function the .md / .html / .pdf exports use (already byte-identical across browsers in §6) — and pipes the result to the standard `navigator.clipboard.writeText` API. Same input, same output, different destination. | | ||
| | Print preview renders without obvious overlap (no `@media print` rules — relies on browser default) | ⏳ | ⏳ | No project-specific print styles exist (zero `@media print` rules in `static/css/style.css`); whatever the browser does at print time is unverified. Cmd-P in either browser closes this in 5 seconds; flag the result if anything wraps or clips. | | ||
|
|
||
| Phantom rows removed (filed as enhancement ideas, not bugs): | ||
| - Per-bubble copy-to-clipboard button — only `copyAllMarkdown()` exists today | ||
| - Arrow-key keyboard navigation through the conversation list — no `keydown` arrow handler in `static/js/*.js` | ||
|
|
||
| ## 8. Regression notes — fixes shipped in this PR | ||
|
|
||
| During the QA pass, one visual bug was found and fixed in the same PR: | ||
|
|
||
| - **`.main-content` grid column overflowing viewport on the right.** | ||
| The right-hand conversation panel (`1fr` grid column in | ||
| `.workspace-grid`) had no explicit `min-width: 0`, so any unbreakable | ||
| child (long code block, long URL, long `tool-call-content`) was | ||
| pushing the column wider than the viewport. Header + title rendered | ||
| fine because they live outside the grid. Fix: added | ||
| `.main-content { min-width: 0; }` at | ||
| [static/css/style.css:316–321](../static/css/style.css#L316-L321). | ||
| Existing `overflow-x: auto` on `.prose pre` and `word-break: break-all` | ||
| on `.tool-call-content` then take over inside the bubble. | ||
|
|
||
| - [x] **(visual)** Post-fix screenshots in `samples/qa/workspace-chrome.png`, | ||
| `workspace-firefox.png`, `conversation-chrome.png`, | ||
| `conversation-firefox.png` were captured *after* the | ||
| `.main-content { min-width: 0 }` fix landed — the conversation | ||
| column stays inside the viewport in all four. | ||
|
|
||
| ## 9. Sign-off | ||
|
|
||
| State at the time of PR submission (2026-05-14). Reviewer fills in the | ||
| remaining row(s) before merge. | ||
|
|
||
| | Item | Status | Notes | | ||
| |------|--------|-------| | ||
| | All 7 sections complete | ✅ | §1–§6 covered with `(visual)` + `(probe)` evidence; §7 row 4 (print preview) deferred as `⏳`, non-blocking — see §7 | | ||
| | Screenshots attached to PR | ✅ | 10 PNGs in `samples/qa/`, embedded inline in §1–§5 | | ||
| | Visual bugs filed as follow-up issues | ✅ | None — the one bug found (`.main-content` overflow) was fixed in this PR rather than deferred; see §8 | | ||
| | `tests/web-ui-smoke.sh` passes | ✅ | 11/11 probes, captured in CI + locally | | ||
| | 1+ reviewer approval | ⏳ | Pending — open question for the reviewer | | ||
|
|
||
| For future passes: re-run this file from §0 onward whenever | ||
| `templates/*.html`, `static/{css,js}/*`, or any route in `api/` is | ||
| touched. The point of a sign-off block isn't to be a one-shot artifact — | ||
| it's to make the next QA pass start from a known baseline. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.