fix: replace libasound2 with libasound2t64 for Ubuntu 24.04, add README screenshots#3
Merged
Conversation
Three root causes fixed:
1. Ubuntu: E2E step never started Xvfb, so Electron couldn't open a
window. All beforeAll() calls timed out, leaving app undefined and
crashing afterAll(() => app.close()). Fixed by running the Linux
step under xvfb-run --auto-servernum.
2. rest.spec.ts: passed NEXUS_DEV_TOOLS instead of HITRO_DEV_TOOLS to
electron.launch(), so DevTools opened and firstWindow() returned the
wrong window. Every test in the suite was interacting with DevTools.
Also added waitForSelector('send-button') in beforeAll and navigated
to the correct tabs before interacting with assertions.
3. app.spec.ts: ten categories of broken selectors:
- [data-testid="tab-bar"] > div counted the scroll wrapper (always 1)
instead of individual tabs — replaced with [data-tab-id]
- .gradient-text only exists in EmptyState (hidden when a tab is
open) — replaced with data-testid="app-brand" on TitleBar brand span
- .rounded-full.bg-pk-accent never existed on the dirty indicator
(it uses var(--pk-warning)) — added data-testid="dirty-indicator"
- button[hasText='Import'] matched both sidebar trigger and modal
submit simultaneously — added data-testid="open-import-modal"
- button[hasText='send'] matched SQS mode tab AND main Send button
(Playwright hasText is case-insensitive) — scoped to sqs-config
- text=Proto File doesn't exist in GrpcConfig — fixed to placeholder
- button[hasText='Body/Headers/Assertions'].first() clicked
RequestBuilder tabs, not ResponsePanel tabs — scoped with
data-testid="response-panel" added to ResponsePanel wrapper
- text=Concurrency doesn't exist; label reads "Concurrent users"
- text=○ None used a Unicode circle not present in the DOM
- All afterAll(() => app.close()) calls hardened to app?.close()
so a failed beforeAll no longer cascades into unrelated errors
- workers: 1 in playwright.config.ts prevents concurrent Electron processes from sharing the same SQLite user-data directory, which caused SQLite locking failures in Suites 8-18. - Assertion row selectors used select.first()/select.nth(1) assuming two dropdowns, but AssertionEditor has one select (operator) and two inputs (field, expected). Replaced with data-testid selectors.
Each call to launch() now creates a fresh mkdtemp directory and passes --user-data-dir to Electron. This gives every test suite its own clean SQLite database, eliminating the shared-state corruption that caused suites 8-18 and rest.spec.ts to fail when run after earlier suites had written to the shared ~/.config/Hitro/hitro.db.
- text=Concurrent -> text=Concurrent users (desc para also has 'concurrent')
- text=Duration -> text=Duration (seconds)
- text=Collections -> text=/^Collections$/i (strict: 'No collections yet' also matched)
- button[hasText='cURL'] -> button[hasText='cURL Command'] (ImportModal label changed;
also avoids conflict with RequestBuilder's Copy-as-cURL button)
- button[hasText='OpenAPI'] -> button[hasText='OpenAPI 3.0']
- button[hasText='HAR'] -> button[hasText='HAR File']
- button[hasText='.env'] -> button[hasText='.env File']
- button[hasText='{}'] -> button[title^='Global Variables'] (button renders SVG, no text)
- button[hasText='▶'] -> button[title='Run all'] (play button is SVG, not ▶ char)
- text=Sending… -> .first() (both ResponsePanel and send-button show 'Sending…')
- localhost:19999 -> localhost:1 (port 19999 appears to be in use on macOS CI runners)
…ix unreachable host URL Import modal shows a success state but does NOT auto-close. Collection names appear in both the sidebar AND the modal's textarea (which still holds the imported JSON). text=CollectionName matched both -> strict mode violation. - All post-import expect/click/waitFor calls for collection names scoped to [data-testid="sidebar"] to avoid matching the open modal's textarea. - .env import: add Escape after Import to close the modal before clicking the Env button (fixed overlay blocking error). - Mock server 'Manage -> opens': text=Mock Servers matched 3 elements (sidebar label, panel h2, 'No mock servers yet') -> use h2[hasText='Mock Servers']. - Unreachable host URL: localhost:1 can be bound on macOS CI runners; use .invalid TLD (guaranteed NXDOMAIN by RFC 2606) for both app.spec.ts and rest.spec.ts. - rest.spec.ts beforeEach: wait for send-button to be enabled so a slow httpbin response from test 1 can't leave test 2's click blocked.
…outs
- Assertion 404 test: response-status.waitFor() resolved instantly because
the previous 200 response was still showing. Changed to toContainText('404')
which waits for the NEW response. Applied same fix to the 200 test.
- .env import: page.keyboard.press('Escape') crashes Electron on Linux when
the import IPC call is still in-flight. Replaced with waitForTimeout(1.5s)
+ page.locator('button[hasText=✕]').first().click() to close gracefully.
- All import collection/OpenAPI/HAR/runner toBeVisible timeouts bumped from
8s to 15s to account for slow CI runners.
…runners - Sidebar suite: close import modal via ✕ button instead of Escape key (Escape is unreliable on Linux/Electron and can leave modal open, causing all subsequent sidebar tests to fail) - Mock server: add timeout: 5_000 to '+ Add Endpoint' toBeVisible check so the button has time to appear after '+ New Server' click - Env indicator: increase activation timeout from 3_000 to 8_000ms to accommodate slow CI runners - Dirty indicator: waitFor Save button visible before clicking to ensure the button is ready before the click fires
Full design for the Hitro UI/UX overhaul covering: - Vibrant Studio aesthetic with protocol-aware chromatic accents - Energetic motion system (compositor-only animations) - Hover-to-expand icon rail sidebar (pure CSS) - Hardened input/error contract for all components - Three-phase layered implementation approach - Release pipeline hardening (Windows/macOS/Linux) - CI reliability overhaul (mock server fixture, 60s timeouts)
- Replace dark/light :root blocks with --vs-* design tokens (protocol colours, depth layers, borders, text, accent, semantic) - Add --pk-* backward-compat aliases pointing to --vs-* so all existing components continue to work without changes - Add .low-spec CSS gate: kills looping animations and backdrop-filter - Add animation tokens (--vs-spring, --vs-ease-out, --vs-dur-*) inside prefers-reduced-motion: no-preference media query - Extend tailwind.config.js with vs.* protocol colour utilities - Install @tanstack/react-virtual (needed for Task 3)
…aming adapters
- src/main/index.ts: promote BrowserWindow to module-level mainWindow; add
process.on('uncaughtException') and process.on('unhandledRejection') handlers
that forward error messages to the renderer via the main:error IPC event;
clear mainWindow reference in window-all-closed handler
- websocket.ts: add 30s terminate timeout on connection setup
- mqtt.ts: increase connect timeout from 15s to 30s
- kafka.ts: wrap producer.connect() and consumer.connect() in Promise.race with
30s timeout
- sqs.ts: wrap both client.send() calls in Promise.race with 30s timeout
- sse.ts: reduce overall AbortController timeout from 60s to 30s
- socketio.ts: add timeout:30_000 to io() options; increase connect timeout from
15s to 30s
…barPanel) Split Sidebar.tsx into three files: SidebarRail (48px permanent icon strip with data-testid="sidebar-rail"), SidebarPanel (220px hover-expanded panel with all existing sidebar logic), and a thin Sidebar shell that composes them inside a vs-sidebar-wrapper div. Added CSS hover-expand animation to index.css.
…, Windows rebuild fix, smoke-test job
… IPC allowlist, tab animation, SSE timeout, VirtualList integration
…tatus badge, Ctrl shortcuts, copy error button
- Add vs-sidebar-rail CSS class with ::after right-edge glow on wrapper hover (opacity 0.4) - Add group/rail Tailwind group to rail div so chevron affordance fades in on hover - Add bottom chevron SVG (opacity-0 → opacity-100 on group-hover/rail) as expand hint - Add pinned state (localStorage key hitro-sidebar-pinned) with togglePin logic - Add pin button between logo and new-tab button; icon switches between pin/unpin SVG - Add sidebar-pinned CSS class that forces translateX(0) !important on the panel
The sidebar panel is now hidden (translateX(-100%)) until the user hovers over the SidebarRail. All tests that click elements inside the panel now call openSidebarPanel() first to expand it before interacting. Affected suites: 9 (Sidebar), 10 (Import modal), 11 (Mock server), 13 (Collection import), 14 (Import validation), 15 (OpenAPI/HAR), 16 (Env import), 18 (Collection runner).
…0ms for CI - Add .first() to all sidebar text locators that resolve 2 elements in strict mode (leaf button/span plus parent div both containing the collection name text) - Increase openSidebarPanel waitForTimeout from 300ms to 500ms for CI runner speed - Add waitForTimeout(300) before toHaveValue assertions on rest-url after sidebar clicks
Root causes and fixes: 1. MockServerPanel "Add Endpoint" label mismatch — button said "+ Add", test expected "+ Add Endpoint"; renamed button to match. 2. Sidebar pointer-events circular dependency — the 48 px rail wrapper only covers the rail, so moving the mouse from rail into panel content loses the CSS :hover that keeps pointer-events:auto, causing Playwright click retries to time out. Fix: openSidebarPanel() now pins the sidebar (sidebar-pin testid added to SidebarRail) so .sidebar-pinned keeps pointer-events:auto !important for all subsequent interactions. 3. MockServerPanel close-button ambiguity — after an endpoint is added, its EndpointEditor ✕ button precedes the panel close button in DOM order. Added data-testid="mock-panel-close" and updated the test to use it instead of button[hasText='✕'].first(). 4. Collection re-import created duplicates — _importPostman always generates a fresh UUID, so saveCollection() added an existing-name check: deletes any matching collection before inserting the new one. 5. Save did not clear dirty indicator for uncollected requests — handleSave() opened the "Save to Collection" modal and returned early, never calling saveRequest(). Now saveRequest() is called first (clears isDirty), then the modal opens if no collectionId is set. 6. HITRO_HEADLESS=1 — BrowserWindow created with show:false in headless mode to suppress window flashing in CI; all three spec files updated to pass the env var.
Two root causes remained after previous fix: 1. openSidebarPanel() used page.hover() + pin-button click, then waited only 100ms — shorter than the panel's 250ms CSS transition. Playwright's stability check detected the mid-animation element movement and kept retrying all 30 s. Replace with page.addStyleTag() that sets transform/pointer-events/transition all to !important, applying instantly with no animation race. 2. show:false on BrowserWindow (HITRO_HEADLESS=1) breaks Chromium's CSS rendering pipeline in hidden windows — getComputedStyle().borderBottomColor returns wrong values, failing the Kafka tab colour assertion in ui.spec.ts. Revert the show:false change; window flashing in CI is cosmetic and does not affect test correctness.
…dicator
1. clickSidebarText helper — Playwright's standard .click() fails for elements
inside the sidebar panel because the main workspace (position:static) paints
over the panel (position:absolute) in some CI rendering paths, causing
Playwright's element-covered check to retry until 30 s timeout. The new
helper fires both a native dispatchEvent AND the React fiber's pendingProps
.onClick directly, bypassing all hit-test checks. A 500 ms setTimeout inside
page.evaluate allows React to flush the state update before the assertion.
2. VirtualList height — TanStack Virtual requires an explicit height on the
scroll container to determine the virtual viewport. The collection request
list used maxHeight:200 (a cap, not a size), so getTotalSize() was 0 and
getVirtualItems() returned [] — request items never rendered after toggle.
Fixed to height: Math.min(items.length * 32, 200).
3. Env indicator assertion — DotIcon is an SVG circle (no text content), so the
button text after activation is "Environment E2E Test Env", not
"● E2E Test Env". Regex updated to /Environment.*E2E Test Env/.
4. Re-import strict mode — button[hasText='Collection'] matched both the
collection toggle and the import modal button after the collection was
expanded. Changed to filter({ hasText: /^Collection$/ }) for exact match.
…ME screenshots Ubuntu 24.04 (now the default for ubuntu-latest) renamed libasound2 to libasound2t64, causing the Linux build job to fail with exit code 100 and blocking the downstream release job. Also adds a 12-screenshot "In Action" section to README with live captures of every major feature (REST, GraphQL, gRPC, WebSocket, Kafka, MQTT, collections, environments, assertions), plus the Playwright spec and script used to generate them.
aks-reviewes
approved these changes
Jun 25, 2026
aks-reviewes
left a comment
Collaborator
There was a problem hiding this comment.
Auto-approved by aks-builds secondary account - PR opened by the sole codeowner.
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
ubuntu-latest) renamedlibasound2→libasound2t64. The Linux build job was failing with exit code 100 at the Install system dependencies step, blocking the downstream smoke-test and release jobs entirely. Windows and macOS builds were unaffected.docs/screenshots/.tests/e2e/screenshots.spec.ts— reusable Playwright spec to regenerate screenshots after UI changes.Test plan
libasound2t64fix)