Blort browser audit

111 / 111 passing browser cases · 12 reproduced regression reports · Chromium · 2026-10-02T12:09:02.957Z

Real Next.js UI and HTTP proxy with a session-isolated local API fixture. Live backend, billing providers, OAuth, parsers, and multiplayer signaling are outside this run.

Open Playwright report with traces and request logs

Bug recordings and repairs

Login loses the requested query string

Passing regression coverage

Reproduction, root cause, and repair

Open /boards?folder=42&sort=updated while signed out. Both recordings show the same login form; the change is in the return URL stored by the route guard.

Behavior Before fix After fix
Return destination passed to login /boards /boards?folder=42&sort=updated
Query parameters retained None folder=42 and sort=updated
Visible login form Unchanged Unchanged

The recordings capture the webpage viewport, so they do not show the browser's address bar. The automated assertion reads the login URL's redirect parameter: it failed with /boards before the fix and passes with the complete original destination afterward. This particular regression checks the redirect into login; it does not sign in or demonstrate a folder being opened afterward.

  • Regression: anonymous protected navigation preserves the complete destination in e2e/auth.spec.ts.
  • Reproduce: With no session, open /boards?folder=42&sort=updated.
  • Before: Login receives redirect=/boards; folder and sort state disappear.
  • Cause: The Next route guard stores only pathname in the login continuation.
  • Fix: src/proxy.ts includes both the pathname and query string.
  • Expected: The login continuation is /boards?folder=42&sort=updated.
  • Recording: artifacts/e2e/bugs/auth-query-loss/before/video.webm. That directory also contains the pre-fix screenshot and Playwright trace.
  • After: The matching passing browser recording is copied to artifacts/e2e/bugs/auth-query-loss/after/ by the evidence report.

The browser exercises the real Next route guard. This failure is independent of backend authentication correctness.

Download before/after MP4

Before fix: anonymous protected navigation preserves the complete destination
Download recording
After fix: anonymous protected navigation preserves the complete destination
Download recording

Login accepts a redirect to an untrusted origin

Passing regression coverage

Reproduction, root cause, and repair
  • Regression: login refuses a backslash redirect to another origin in e2e/auth.spec.ts.
  • Reproduce: Open login with redirect=/\evil.example/steal, then log in successfully.
  • Before: The browser navigates to http://evil.example/steal. The recording displays a locally intercepted destination; no external service receives the test traffic.
  • Cause: A prefix check accepts a slash followed by a backslash as local. Browser URL parsing normalizes the backslash into a slash and interprets the result as a hostname.
  • Fix: getSafeLocalRedirect in src/lib/utils/auth-redirect.ts uses URL parsing, checks the resolved origin, and returns a normalized local path. Login, verification, and the auth server layout all consume that helper.
  • Expected: Untrusted destinations fall back to the normal in-app landing flow.
  • Recording: artifacts/e2e/bugs/auth-open-redirect/before/video.webm. The directory also contains the pre-fix screenshot and Playwright trace.
  • After: artifacts/e2e/bugs/auth-open-redirect/after/.

Absolute and protocol-relative variants are also covered. This is browser-level redirect proof, with synthetic credentials and an isolated API.

Download before/after MP4

Before fix: login refuses a backslash redirect to another origin
Download recording
After fix: login refuses a backslash redirect to another origin
Download recording

Signed-in visitors lose their login continuation

Passing regression coverage

Reproduction, root cause, and repair
  • Regression: signed-in login navigation follows its local destination in e2e/auth.spec.ts.
  • Reproduce: With a verified session, open /login?redirect=%2Fchange-email%3Ffrom%3Dexisting-session.
  • Before: The auth layout redirects through / to /boards, discarding the intended page and its query.
  • Cause: The server layout honors MCP authorization continuations but ignores the ordinary redirect parameter for already authenticated visitors.
  • Fix: src/app/(auth)/layout.tsx follows the validated local redirect after checking the MCP continuation.
  • Expected: The existing session goes directly to /change-email?from=existing-session without another login request.
  • Recording: artifacts/e2e/bugs/auth-signed-in-continuation/before/video.webm. The directory also contains the pre-fix screenshot and Playwright trace.
  • After: artifacts/e2e/bugs/auth-signed-in-continuation/after/.

This regression exercises the server-rendered auth layout, independently of client login.

Download before/after MP4

Before fix: signed-in login navigation follows its local destination
Download recording
After fix: signed-in login navigation follows its local destination
Download recording

Successful email verification loses the original destination

Passing regression coverage

Reproduction, root cause, and repair
  • Regression: successful verification refreshes the session before following the original destination in e2e/auth.spec.ts.
  • Reproduce: With an unverified session, open /verify-code?redirect=%2Fchange-email%3Fverified%3D1 and submit a valid six-digit code.
  • Before: Verification succeeds and refreshes the session, then navigates through /?new-user=true to pricing instead of the requested destination.
  • Cause: The success handler preserves the ordinary continuation during preceding auth navigation but never uses it after verification.
  • Fix: src/components/auth/verify-code-page.tsx follows the validated local destination after the existing session refresh and MCP continuation check.
  • Expected: The browser reaches /change-email?verified=1, with /auth/refresh observed after /auth/verify.
  • Recording: artifacts/e2e/bugs/auth-verification-continuation/before/video.webm. The directory also contains the pre-fix screenshot and Playwright trace.
  • After: artifacts/e2e/bugs/auth-verification-continuation/after/.

The API supplies verification results; the real client owns refresh ordering and navigation.

Download before/after MP4

Before fix: successful verification refreshes the session before following the original destination
Download recording
After fix: successful verification refreshes the session before following the original destination
Download recording

Backspace gets stuck in an empty verification digit

Passing regression coverage

Reproduction, root cause, and repair
  • Regression: Backspace from a cleared middle code slot clears the preceding digit in e2e/auth.spec.ts.
  • Reproduce: Enter 123456, focus digit 3, and press Backspace twice.
  • Before: The first press clears digit 3; the second leaves digit 2 as 2 and focus remains in the empty third slot.
  • Cause: The internal code retains a space placeholder for a middle hole. The handler treats that space as a nonempty digit and repeatedly clears the same slot.
  • Fix: src/components/auth/otp-input.tsx checks the trimmed digit and moves left when it is empty. It also avoids writing a negative array index at the first slot.
  • Expected: The second press clears digit 2 and focuses it while later digits remain unchanged and incomplete verification stays disabled.
  • Recording: artifacts/e2e/bugs/auth-otp-backspace/before/video.webm. The directory also contains the pre-fix screenshot and Playwright trace.
  • After: artifacts/e2e/bugs/auth-otp-backspace/after/.

The browser uses actual keyboard events against the rendered controlled inputs.

Download before/after MP4

Before fix: Backspace from a cleared middle code slot clears the preceding digit
Download recording
After fix: Backspace from a cleared middle code slot clears the preceding digit
Download recording

Favourite button remains flipped when its request fails

Passing regression coverage

Reproduction, root cause, and repair

Severity: medium. A temporary API failure leaves the board card displaying the opposite of the persisted favourite state. The next click sends the inverse operation, so the user's retry never achieves the intended result.

Reproduce: open the board library, click an unliked card's star while POST /board/1/like returns 500, wait for the error toast, then click the star again. Before the fix, the recorded requests are POST followed by DELETE. Expected: POST followed by POST, followed by the board appearing under Liked. Starting from a liked board reproduces the reverse sequence: DELETE followed by POST instead of DELETE followed by DELETE.

Root cause: BoardCardComponent initialized local isLiked from props, changed it inside mutationFn, and only handled success. Failed requests never restored the state; later refreshed props also could not replace the stale local value.

Fix: keep only a temporary optimistic override, pass the target favourite state explicitly into the mutation, clear the override on error, and clear it after the successful list refresh. Disable the star during the request to prevent competing clicks. aria-pressed now exposes the visible favourite state to assistive technology.

The regression cases are failed like restores saved state so retry performs the same operation and failed unlike restores saved state so retry performs the same operation in e2e/boards.spec.ts. Both failed before the fix on the intended request sequence assertion. The baseline also reported a separate fixture teardown error for an unimplemented survey endpoint; that error does not explain the failed request sequence.

Before videos, screenshots, trace, and failure context:

  • artifacts/e2e/bugs/favourite-rollback/before/like/
  • artifacts/e2e/bugs/favourite-rollback/before/unlike/

After videos are retained from the passing regression run under artifacts/e2e/bugs/favourite-rollback/after/.

Download before/after MP4

Before fix: failed like restores saved state so retry performs the same operation
Download recording
Before fix: failed unlike restores saved state so retry performs the same operation
Download recording
After fix: failed like restores saved state so retry performs the same operation
Download recording
After fix: failed unlike restores saved state so retry performs the same operation
Download recording

Persisted board preferences display the default after reload

Passing regression coverage

Reproduction, root cause, and repair

Severity: medium. Every persisted board preference can display the opposite of its saved setting after a full page reload, including Dark Mode. The visual switch and its accessible checked state disagree with the current browser preference.

Reproduce: open /settings?tab=board, turn Mini map on, and reload. Before the fix, its switch returns visually to off even though localStorage still contains miniMap=true. The same failure occurs when changing Background Dots, Connection Animations, Proximity Connect, or Dark Mode away from their defaults.

Root cause: the Zustand store's initializer reads localStorage and the theme cookie in the browser but returns hard-coded defaults during SSR. Installed Zustand uses getInitialState() as React's hydration snapshot. The server and browser initial snapshots therefore disagree. React reports a hydration attribute mismatch and does not repair the switch's checked DOM attributes when it considers the current client value unchanged.

Fix: initialize the store with identical defaults on the server and browser, then apply persisted browser values to its current state using the existing store API. Zustand retains the stable initial snapshot for hydration and publishes the persisted current snapshot immediately afterward. Existing getters, setters, localStorage keys, and the theme cookie remain compatible.

Regression cases in e2e/navigation.spec.ts:

  • Mini map preference persists across a reload
  • Background Dots preference persists across a reload
  • Connection Animations preference persists across a reload
  • Proximity Connect preference persists across a reload
  • dark mode changes the rendered theme and persists across reload

All five failed on the intended persisted switch assertion before the fix. Before recordings, screenshots, trace and failure contexts are in artifacts/e2e/bugs/settings-hydration/before/{mini-map,background-dots,connection-animations,proximity-connect,dark-mode}/. After recordings are retained under artifacts/e2e/bugs/settings-hydration/after/ once verified.

Download before/after MP4

Before fix: Background Dots preference persists across a reload
Download recording
Before fix: Connection Animations preference persists across a reload
Download recording
Before fix: dark mode changes the rendered theme and persists across reload
Download recording
Before fix: Mini map preference persists across a reload
Download recording
Before fix: Proximity Connect preference persists across a reload
Download recording
After fix: Mini map preference persists across a reload
Download recording
After fix: Background Dots preference persists across a reload
Download recording
After fix: Connection Animations preference persists across a reload
Download recording
After fix: Proximity Connect preference persists across a reload
Download recording
After fix: dark mode changes the rendered theme and persists across reload
Download recording

Whitespace-only prompts enabled an ineffective Send button

Passing regression coverage

Reproduction, root cause, and repair

Reproduction: Enter spaces in the assistant composer. The Send button was enabled, although submission silently rejected the empty trimmed prompt.

Root cause: The button checked raw input while the submit handler checked trimmed input.

Fix: The disabled condition now checks input.trim(), consistently preserving image-only submissions.

Regression: e2e/canvas.spec.ts — whitespace-only prompts cannot be sent. The Chromium browser test failed before the repair for this intended reason.

Evidence: before video, before screenshot, before trace. After video is collected by the verification run.

Scope: these tests execute the real Next.js application against an isolated HTTP backend. For the viewer case they prove the frontend attempted a forbidden mutation; they do not claim the production backend accepted it.

Download before/after MP4

Before fix: whitespace-only prompts cannot be sent
Download recording
After fix: whitespace-only prompts cannot be sent
Download recording

Viewer boards accepted file drops through the editor

Passing regression coverage

Reproduction, root cause, and repair

Reproduction: Open shared board3 as a viewer, then drop a TXT file. The browser initiated POST /source/text with boardId3 despite disabled creation controls.

Root cause: The canvas file-drop hook had no permission gate; disabling toolbar controls did not cover drag-and-drop.

Fix: Flow disables the drop boundary for viewers and previews. The hook also checks current read-only state before creation and after asynchronous text-file reads.

Regression: e2e/sources.spec.ts — viewer cannot import files by dropping them onto a read-only board. The Chromium browser test failed before the repair for this intended reason.

Evidence: before video, before screenshot, before trace. After video is collected by the verification run.

Scope: these tests execute the real Next.js application against an isolated HTTP backend. For the viewer case they prove the frontend attempted a forbidden mutation; they do not claim the production backend accepted it.

Download before/after MP4

Before fix: viewer cannot import files by dropping them onto a read-only board
Download recording
After fix: viewer cannot import files by dropping them onto a read-only board
Download recording

Preview boards created content from file drops

Passing regression coverage

Reproduction, root cause, and repair

Reproduction: Open /board/1?preview=1, then drop a TXT file. A text node appeared and a source creation request was sent.

Root cause: Preview hid editing controls but left file-drop listeners active.

Fix: Preview now disables the canvas drop boundary and uses read-only editor state.

Regression: e2e/sources.spec.ts — preview boards cannot import files through drag and drop. The Chromium browser test failed before the repair for this intended reason.

Evidence: before video, before screenshot, before trace. After video is collected by the verification run.

Scope: these tests execute the real Next.js application against an isolated HTTP backend. For the viewer case they prove the frontend attempted a forbidden mutation; they do not claim the production backend accepted it.

Download before/after MP4

Before fix: preview boards cannot import files through drag and drop
Download recording
After fix: preview boards cannot import files through drag and drop
Download recording

Preview text remained editable

Passing regression coverage

Reproduction, root cause, and repair

Reproduction: Open a board containing text with ?preview=1. The rendered Tiptap editor had contenteditable=true despite preview mode.

Root cause: FlowPage treated copied boards and viewer permissions as read-only but omitted preview mode.

Fix: Preview enters the same read-only state as copies, disabling text editors and the chat composer.

Regression: e2e/sources.spec.ts — preview text content is readable but cannot be edited. The Chromium browser test failed before the repair for this intended reason.

Evidence: before video, before screenshot, before trace. After video is collected by the verification run.

Scope: these tests execute the real Next.js application against an isolated HTTP backend. For the viewer case they prove the frontend attempted a forbidden mutation; they do not claim the production backend accepted it.

Download before/after MP4

Before fix: preview text content is readable but cannot be edited
Download recording
After fix: preview text content is readable but cannot be edited
Download recording

Late account data overwrites a user's profile description draft

Passing regression coverage

Reproduction, root cause, and repair

Severity: medium. A slow account request can erase the profile description that a user has already typed, including a draft they intended to retry after a failed save.

Reproduce: open Settings with the initial account request slower than the social-profile requests, type a niche description as soon as the field appears, reject its first save, and allow the account request to finish. Before the fix, the existing account initialization effect replaces the user's draft with the saved account description. The recording captured the text disappearing immediately after a failed save.

Root cause: ProfileTab exposes its description field when the independent social-profile loader finishes. Its didInitNiche guard is set only when account data arrives, so a user edit during that earlier window does not prevent the account effect's setDescription from overwriting the draft.

Fix: mark the existing initialization guard as complete when the user edits the description. Late account data still initializes an untouched field, while an explicit user edit takes precedence.

The regression in e2e/navigation.spec.ts is failed profile niche save preserves edits while account loads and can be retried. It holds the first account response until the user has typed and received a rejected save, then releases the response and requires the draft to remain available for retry and persist after reload.

The original naturally occurring failure was failed profile niche save preserves edits and can be retried; it failed on the immediate draft-preservation assertion (expected Independent travel creators, received an empty string), independently of transport-fixture teardown. The saved trace shows social requests resolving before the initial account request and the user editing in between.

The deterministic delayed-account case was also run against the original production code and failed on the same draft assertion: expected Independent travel creators, received Previously saved niche. That separate reproduction is archived under artifacts/e2e/bugs/profile-draft-race/before/deterministic/.

Before recording, trace, screenshot, and failure context: artifacts/e2e/bugs/profile-draft-race/before/. After recording is saved under artifacts/e2e/bugs/profile-draft-race/after/ after the deterministic regression passes.

Download before/after MP4

Before fix: failed profile niche save preserves edits while account loads and can be retried
Download recording
Before fix: failed profile niche save preserves edits and can be retried
Download recording
After fix: failed profile niche save preserves edits while account loads and can be retried
Download recording

Every tested flow


SourceBehaviorOutcomeDurationRecording
auth.spec.ts:13anonymous protected navigation preserves the complete destinationpassed5.3sVideo 1
auth.spec.ts:24signed-out users can reach /loginpassed5.3sVideo 1
auth.spec.ts:24signed-out users can reach /signuppassed5.1sVideo 1
auth.spec.ts:24signed-out users can reach /forgot-passwordpassed5.1sVideo 1
auth.spec.ts:31login validates after blur and becomes usable after correctionpassed7.6sVideo 1
auth.spec.ts:56password visibility preserves the value without submittingpassed7.7sVideo 1
auth.spec.ts:69auth navigation carries the entered email and continuationpassed8.2sVideo 1
auth.spec.ts:88invalid credentials show feedback and allow a successful retrypassed9.6sVideo 1
auth.spec.ts:105verified login submits credentials and follows a local URL including its querypassed9.4sVideo 1
auth.spec.ts:118unverified login enters verification with the continuation intactpassed9.0sVideo 1
auth.spec.ts:130signed-in login navigation follows its local destinationpassed8.0sVideo 1
auth.spec.ts:143login refuses a absolute redirect to another originpassed7.7sVideo 1
auth.spec.ts:143login refuses a protocol-relative redirect to another originpassed7.7sVideo 1
auth.spec.ts:143login refuses a backslash redirect to another originpassed10.7sVideo 1
auth.spec.ts:155signup requires a nonblank name and a valid passwordpassed6.5sVideo 1
auth.spec.ts:169duplicate signup stays on the form with useful feedbackpassed6.3sVideo 1
auth.spec.ts:183signup sends credentials and campaign attribution then enters verificationpassed11.3sVideo 1
auth.spec.ts:204password recovery sends email and enforces cooldown across reloadpassed11.2sVideo 1
auth.spec.ts:225recovery honors the remaining server cooldownpassed10.3sVideo 1
auth.spec.ts:238a missing reset token cannot change a passwordpassed6.7sVideo 1
auth.spec.ts:249reset consumes the secret URL parameter but keeps it for submissionpassed9.3sVideo 1
auth.spec.ts:272an expired reset offers another link with the account emailpassed5.9sVideo 1
auth.spec.ts:290signed-out verification returns to login with continuationpassed7.6sVideo 1
auth.spec.ts:298/verify-email stale links enter the code flow and discard the dead tokenpassed8.2sVideo 1
auth.spec.ts:298/verify stale links enter the code flow and discard the dead tokenpassed7.2sVideo 1
auth.spec.ts:312an existing valid code is accepted without an error or duplicate deliverypassed5.3sVideo 1
auth.spec.ts:333a dead verification session returns to loginpassed7.0sVideo 1
auth.spec.ts:349verification rejects non-digits and incomplete codes, including a deleted middle digitpassed6.0sVideo 1
auth.spec.ts:372pasting a code distributes digits and arrow keys move focuspassed10.8sVideo 1
auth.spec.ts:394Backspace from a cleared middle code slot clears the preceding digitpassed6.2sVideo 1
auth.spec.ts:413incorrect verification clears digits and allows another attemptpassed5.5sVideo 1
auth.spec.ts:440successful verification refreshes the session before following the original destinationpassed5.2sVideo 1
auth.spec.ts:459resend becomes available after cooldown and starts a new cooldownpassed4.6sVideo 1
auth.spec.ts:486verification logout clears the session and preserves continuationpassed8.4sVideo 1
boards.spec.ts:51library renders hydrated owner and shared boards without previewspassed5.5sVideo 1
boards.spec.ts:59search filters boards and clearing restores the whole librarypassed12.0sVideo 1
boards.spec.ts:69an empty search recovers when the query is replacedpassed11.4sVideo 1
boards.spec.ts:81liked filter and search intersect instead of leaking unliked boardspassed9.5sVideo 1
boards.spec.ts:93library loads boards beyond the first page without duplicatespassed7.5sVideo 1
boards.spec.ts:107create board navigates to the new board and survives returning to librarypassed18.1sVideo 1
boards.spec.ts:119rejected creation keeps library usable for a successful retrypassed13.8sVideo 1
boards.spec.ts:130rename submits with Enter and persists after reloadpassed18.2sVideo 1
boards.spec.ts:144rename rejects a whitespace-only name and Escape preserves the originalpassed10.4sVideo 1
boards.spec.ts:164a rejected rename preserves the draft and permits retrypassed10.9sVideo 1
boards.spec.ts:181delete requires confirmation and cancelled deletion keeps the boardpassed7.6sVideo 1
boards.spec.ts:196confirmed deletion removes only the selected board and persistspassed15.3sVideo 1
boards.spec.ts:209failed delete keeps board and confirmation open for retrypassed13.3sVideo 1
boards.spec.ts:223duplicate creates a separate board while leaving source unchangedpassed17.8sVideo 1
boards.spec.ts:243editor shared boards expose unshare without owner rename or deletepassed17.5sVideo 1
boards.spec.ts:243viewer shared boards expose unshare without owner rename or deletepassed16.0sVideo 1
boards.spec.ts:261liking from a card stays in library and persists in liked filterpassed16.5sVideo 1
boards.spec.ts:276failed like restores saved state so retry performs the same operationpassed9.1sVideo 1
boards.spec.ts:276failed unlike restores saved state so retry performs the same operationpassed11.4sVideo 1
boards.spec.ts:305templates tab has independent empty state and returns to the librarypassed9.7sVideo 1
boards.spec.ts:318mobile library search and owner actions stay reachablepassed9.8sVideo 1
canvas.spec.ts:33loads existing rich text and uses the board name as the document titlepassed16.1sVideo 1
canvas.spec.ts:45creates one text node, saves typing, and restores it after reloadpassed27.9sVideo 1
canvas.spec.ts:76failed text creation removes the optimistic ghost and can be retriedpassed27.5sVideo 1
canvas.spec.ts:103creates sticky notes with the persisted sticky discriminatorpassed27.0sVideo 1
canvas.spec.ts:129Backspace inside a rich text editor does not delete the canvas nodepassed14.5sVideo 1
canvas.spec.ts:148delete, undo, and redo preserve backend state across reloadpassed27.0sVideo 1
canvas.spec.ts:170failed deletion restores the selected source instead of losing itpassed25.2sVideo 1
canvas.spec.ts:190node search matches note content and Escape returns to the canvaspassed18.2sVideo 1
canvas.spec.ts:208unmatched node search shows an empty result and can be correctedpassed14.9sVideo 1
canvas.spec.ts:225renaming a board persists and Escape cancels a second editpassed24.6sVideo 1
canvas.spec.ts:264dragging a text node saves its position across reloadpassed28.5sVideo 1
canvas.spec.ts:285creating a group preserves its name and dimensions after reloadpassed23.9sVideo 1
canvas.spec.ts:313sharing rejects an invalid email and successful Enter submission sends one invitationpassed17.1sVideo 1
canvas.spec.ts:337rejected invitations retain the email for correction and retrypassed15.3sVideo 1
canvas.spec.ts:371creates one assistant node and restores it after reloadpassed24.2sVideo 1
canvas.spec.ts:391failed assistant creation removes its optimistic placeholderpassed17.5sVideo 1
canvas.spec.ts:409unsent chat drafts survive reload without creating a conversationpassed24.8sVideo 1
canvas.spec.ts:424whitespace-only prompts cannot be sentpassed17.9sVideo 1
canvas.spec.ts:437Shift+Enter inserts a line break while Delete edits the prompt safelypassed13.3sVideo 1
canvas.spec.ts:457sending a prompt renders the streamed assistant response and unlocks inputpassed31.0sVideo 1
navigation.spec.ts:8Mini map preference persists across a reloadpassed16.8sVideo 1
navigation.spec.ts:8Background Dots preference persists across a reloadpassed16.2sVideo 1
navigation.spec.ts:8Connection Animations preference persists across a reloadpassed12.8sVideo 1
navigation.spec.ts:8Proximity Connect preference persists across a reloadpassed18.5sVideo 1
navigation.spec.ts:22dark mode changes the rendered theme and persists across reloadpassed20.1sVideo 1
navigation.spec.ts:35direct settings tab navigation loads the matching content and allows switchingpassed14.7sVideo 1
navigation.spec.ts:51profile niche saves trimmed text and persists after reloadpassed34.9sVideo 1
navigation.spec.ts:65failed profile niche save preserves edits while account loads and can be retriedpassed37.4sVideo 1
navigation.spec.ts:108notification preferences persist and disabling alerts disables dependent controlspassed49.4sVideo 1
navigation.spec.ts:148failed notification update rolls back the visible preference and supports retrypassed35.9sVideo 1
navigation.spec.ts:182API key creation masks the key, reveals it on demand, and revokes itpassed36.9sVideo 1
navigation.spec.ts:205API key regeneration replaces the persisted keypassed28.9sVideo 1
navigation.spec.ts:236Saved navigation reaches an actionable empty collectionpassed27.5sVideo 1
navigation.spec.ts:250unsaving a source removes the saved card and persists after reloadpassed24.1sVideo 1
navigation.spec.ts:276failed unsave restores the source card and supports a successful retrypassed26.8sVideo 1
navigation.spec.ts:343pricing tabs display plans for their billing period and hide private offerspassed10.1sVideo 1
navigation.spec.ts:360existing board owner can return from pricing to the board librarypassed13.6sVideo 1
navigation.spec.ts:368pricing ignores invalid or private checkout-plan -1passed13.0sVideo 1
navigation.spec.ts:368pricing ignores invalid or private checkout-plan 99passed13.4sVideo 1
navigation.spec.ts:368pricing ignores invalid or private checkout-plan not-a-planpassed9.7sVideo 1
sources.spec.ts:40blank website submission stays disabled and makes no source requestpassed18.8sVideo 1
sources.spec.ts:59rejects an invalid website URL: not a websitepassed19.0sVideo 1
sources.spec.ts:59rejects an invalid website URL: javascript:alert(1)passed17.9sVideo 1
sources.spec.ts:59rejects an invalid website URL: ftp://example.com/privatepassed17.4sVideo 1
sources.spec.ts:77valid website content creates a persisted sourcepassed43.3sVideo 1
sources.spec.ts:102detects YouTube links before import and preserves the submitted URLpassed18.6sVideo 1
sources.spec.ts:127canceling an import clears its draft before reopeningpassed20.5sVideo 1
sources.spec.ts:145rejects executable files without submitting an uploadpassed19.7sVideo 1
sources.spec.ts:164uploads a CSV file with its original bytes and restores the source after reloadpassed31.3sVideo 1
sources.spec.ts:200dropping a text file imports editable content and persists itpassed32.6sVideo 1
sources.spec.ts:228oversized dropped text files are rejected before any source creationpassed23.9sVideo 1
sources.spec.ts:252viewer can read content but toolbar and keyboard cannot mutate itpassed37.1sVideo 1
sources.spec.ts:278viewer cannot import files by dropping them onto a read-only boardpassed52.5sVideo 1
sources.spec.ts:307preview boards cannot import files through drag and droppassed46.8sVideo 1
sources.spec.ts:332preview text content is readable but cannot be editedpassed45.1sVideo 1
sources.spec.ts:362missing board shows an actionable access error instead of an endless spinnerpassed20.1sVideo 1