Skip to content

fix: correct the request type tabs in the snapshot#7994

Merged
sid-bruno merged 3 commits into
usebruno:mainfrom
sid-bruno:fix/snapshot-ws-messages
May 13, 2026
Merged

fix: correct the request type tabs in the snapshot#7994
sid-bruno merged 3 commits into
usebruno:mainfrom
sid-bruno:fix/snapshot-ws-messages

Conversation

@sid-bruno
Copy link
Copy Markdown
Collaborator

@sid-bruno sid-bruno commented May 13, 2026

Description

JIRA

Corrects how the snapshot refers to the different request types

Contribution Checklist:

  • I've used AI significantly to create this pull request
  • The pull request only addresses one issue or adds one feature.
  • The pull request does not introduce any breaking changes
  • I have added screenshots or gifs to help explain the change if applicable.
  • I have read the contribution guidelines.
  • Create an issue and link to the pull request.

Note: Keeping the PR small and focused helps make it easier to review and merge. If you have multiple changes you want to make, please consider submitting them as separate pull requests.

Publishing to New Package Managers

Please see here for more information.

Summary by CodeRabbit

  • Bug Fixes

    • Request tabs now preserve and restore the concrete request type and pathname so the correct pane (body/query/params/headers) is selected after restart.
    • New tabs opened from collection items reflect the item's request type when available.
    • Default pane selection improved for gRPC/WebSocket (body) and GraphQL (query) when no saved pane is present.
  • Tests

    • Added unit and end-to-end tests covering restoration for gRPC, WebSocket, GraphQL, and generic requests.
    • Improved test utilities for reliably selecting pane tabs.

Review Change Stack

Copilot AI review requested due to automatic review settings May 13, 2026 08:45
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 13, 2026

Walkthrough

Adds type-aware defaulting for request-pane tabs, persists type and pathname when opening tabs, updates deserialization to compute appropriate pane defaults (gRPC/ws → body, graphql → query), and adds unit + E2E tests plus a more robust test helper for selecting pane tabs.

Changes

Request pane snapshot and tab restoration

Layer / File(s) Summary
Type-aware request pane defaults and deserialization
packages/bruno-app/src/utils/snapshot/index.js
getDefaultRequestPaneTabForType maps request types to default panes (gRPC/WS → body, GraphQL → query, else → params). deserializeTab reads a restored snapshotTab.request.tab when present; otherwise it computes requestPaneTab from the resolved item type and recalculates when restoring pathname-scoped tabs.
Tab creation with metadata propagation
packages/bruno-app/src/providers/ReduxStore/middlewares/tasks/middleware.js, packages/bruno-app/src/components/OpenAPISyncTab/hooks/useOpenAPISync.js
When opening request tabs, dispatched addTab payloads now include type and pathname derived from the collection item (fallback to 'request' where appropriate), so snapshots contain the concrete item metadata.
Unit test coverage for tab deserialization
packages/bruno-app/src/utils/snapshot/index.spec.js
Adds Jest tests asserting requestPaneTab defaults to 'body' for gRPC/ws and to 'query' for GraphQL when snapshot values are missing, and that generic request snapshot entries resolve to concrete item types via pathname.
End-to-end snapshot persistence and restore tests
tests/snapshots/request-pane-interactivity.spec.ts
Adds helpers (readSnapshot, findSnapshotRequestTab) and Playwright tests for gRPC, WebSocket, and GraphQL that persist a request, select a pane, relaunch the app, and assert saved type and request.tab plus correct UI restoration.
Test helper: robust pane tab selection
tests/utils/page/actions.ts
Replaces selectPaneTab with a retrying, multi-strategy selector using escapeRegExp, direct clicks, overflow menu lookup, and .tippy-box fallback to improve test reliability.

Sequence Diagram(s)

(No sequence diagrams generated: the core change is localized defaulting/deserialization and test additions; interactions are straightforward and captured in the layers.)

Possibly related PRs

  • usebruno/bruno#6502: Both PRs modify tests/utils/page/actions.ts’s request-pane tab selection logic (overflow/tippy dropdown locators).
  • usebruno/bruno#7948: Adjusts request-restore flow and tab metadata syncing related to snapshot deserialization.
  • usebruno/bruno#7794: Overlaps on snapshot deserializeTab and addTab payload handling for tab type/pathname.

Suggested reviewers

  • naman-bruno
  • lohit-bruno
  • bijin-bruno

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Request tabs remember their type and pane,
GRPC, WebSocket, GraphQL too—
Snapshots restore what they came to maintain, 📸
No more mixed tabs breaking the view.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: correct the request type tabs in the snapshot' directly and specifically describes the main change: correcting how request type tabs are handled in snapshot deserialization across multiple request types (gRPC, WebSocket, GraphQL).
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
tests/snapshots/request-pane-interactivity.spec.ts (1)

166-167: ⚡ Quick win

Replace fixed sleeps with condition-based snapshot waits.

Line 166 and Line 222 use page.waitForTimeout(2000). This is brittle under slow/fast environments; wait on the snapshot condition instead, then close the app.

♻️ Suggested change
-      await page.waitForTimeout(2000);
+      await expect.poll(() => {
+        const snapshot = readSnapshot(userDataPath);
+        const tab = findSnapshotRequestTab(snapshot, 'ReqGrpcSnapshot');
+        return tab?.request?.tab;
+      }).toBe('body');
       await closeElectronApp(app);
-      await page.waitForTimeout(2000);
+      await expect.poll(() => {
+        const snapshot = readSnapshot(userDataPath);
+        const tab = findSnapshotRequestTab(snapshot, 'ReqWsSnapshot');
+        return tab?.request?.tab;
+      }).toBe('body');
       await closeElectronApp(app);

As per coding guidelines: "Replace magic timeouts with event-driven waits in E2E tests."

Also applies to: 222-223

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/snapshots/request-pane-interactivity.spec.ts` around lines 166 - 167,
Replace the fixed 2s sleeps in request-pane-interactivity.spec.ts (the
page.waitForTimeout(2000) calls) with condition-based waits that observe the
snapshot-ready condition before calling closeElectronApp(app); for example,
await a stable UI element or snapshot marker using
page.locator('<snapshot-or-result-selector>').waitFor({ state: 'visible' }) or
await page.waitForFunction(() => !!window.__SNAPSHOT_READY__), then proceed to
await closeElectronApp(app) — update both occurrences that use
page.waitForTimeout to use these event-driven waits referencing
page.waitForFunction or page.locator(...).waitFor instead of
page.waitForTimeout.
packages/bruno-app/src/utils/snapshot/index.js (1)

352-362: ⚡ Quick win

Use one shared default-tab resolver to prevent mapping drift.

This local mapping duplicates request-pane default logic already used in tab creation. Reusing a single helper for both write/restore paths will avoid future mismatches.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/bruno-app/src/utils/snapshot/index.js` around lines 352 - 362, The
local function getDefaultRequestPaneTabForType duplicates the request-pane
default-tab logic used elsewhere; replace it by importing and calling the single
shared default-tab resolver used by tab creation (remove
getDefaultRequestPaneTabForType and any local mapping), update callers to use
that shared helper, and ensure the import name matches the existing resolver in
the request-pane/tab creation module so both write/restore paths use the same
logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/bruno-app/src/utils/snapshot/index.js`:
- Around line 352-362: The local function getDefaultRequestPaneTabForType
duplicates the request-pane default-tab logic used elsewhere; replace it by
importing and calling the single shared default-tab resolver used by tab
creation (remove getDefaultRequestPaneTabForType and any local mapping), update
callers to use that shared helper, and ensure the import name matches the
existing resolver in the request-pane/tab creation module so both write/restore
paths use the same logic.

In `@tests/snapshots/request-pane-interactivity.spec.ts`:
- Around line 166-167: Replace the fixed 2s sleeps in
request-pane-interactivity.spec.ts (the page.waitForTimeout(2000) calls) with
condition-based waits that observe the snapshot-ready condition before calling
closeElectronApp(app); for example, await a stable UI element or snapshot marker
using page.locator('<snapshot-or-result-selector>').waitFor({ state: 'visible'
}) or await page.waitForFunction(() => !!window.__SNAPSHOT_READY__), then
proceed to await closeElectronApp(app) — update both occurrences that use
page.waitForTimeout to use these event-driven waits referencing
page.waitForFunction or page.locator(...).waitFor instead of
page.waitForTimeout.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: dcff364d-d844-4fbe-a703-2892d35008b1

📥 Commits

Reviewing files that changed from the base of the PR and between dd922c7 and b59a6d7.

📒 Files selected for processing (4)
  • packages/bruno-app/src/providers/ReduxStore/middlewares/tasks/middleware.js
  • packages/bruno-app/src/utils/snapshot/index.js
  • packages/bruno-app/src/utils/snapshot/index.spec.js
  • tests/snapshots/request-pane-interactivity.spec.ts

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates snapshot/tab restoration to correctly persist and restore request-pane tab defaults for gRPC and WebSocket requests (including ensuring concrete request types are stored in the snapshot), and adds regression tests to cover the behavior.

Changes:

  • Added Playwright snapshot tests to assert snapshot persistence/restoration for gRPC and WebSocket request tabs.
  • Updated snapshot deserialization to apply request-type-specific default request pane tabs and to resolve generic snapshot request types via pathname lookup.
  • Updated the task middleware’s addTab payload to include type and pathname when opening a newly-created request.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

File Description
tests/snapshots/request-pane-interactivity.spec.ts Adds e2e coverage ensuring gRPC/WS snapshot stores concrete type + correct request tab key and restores without 404.
packages/bruno-app/src/utils/snapshot/index.spec.js Adds unit tests for request-pane defaulting and resolving generic snapshot request type via pathname.
packages/bruno-app/src/utils/snapshot/index.js Implements request-pane default selection by request type and resolves generic request snapshot type using collection items.
packages/bruno-app/src/providers/ReduxStore/middlewares/tasks/middleware.js Ensures newly opened request tabs include type and pathname so snapshots can serialize request metadata correctly.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread packages/bruno-app/src/utils/snapshot/index.js
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/snapshots/request-pane-interactivity.spec.ts`:
- Line 251: The test title "graphql snapshot stores concrete type and query tab
key" is inconsistent with the assertions which check the Headers pane; update
the test name string passed to the test(...) call (the title literal) to reflect
"headers tab key" (e.g., "graphql snapshot stores concrete type and headers tab
key") so the test name matches the selection step and assertion in the test
function.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 187efee0-37e1-446b-99c3-3fb1a68b2025

📥 Commits

Reviewing files that changed from the base of the PR and between b59a6d7 and 3893d9d.

📒 Files selected for processing (4)
  • packages/bruno-app/src/components/OpenAPISyncTab/hooks/useOpenAPISync.js
  • packages/bruno-app/src/utils/snapshot/index.spec.js
  • tests/snapshots/request-pane-interactivity.spec.ts
  • tests/utils/page/actions.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bruno-app/src/utils/snapshot/index.spec.js

Comment thread tests/snapshots/request-pane-interactivity.spec.ts
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
tests/utils/page/actions.ts (1)

819-819: ⚡ Quick win

Strengthen tab-name matching to avoid false positives with similar label pairs.

All three branches use substring matching: getByRole('tab', { name: tabName }) (line 819), getByRole('menuitem', { name: new RegExp(..., 'i') }) without anchors (lines 842–844), and .filter({ hasText: tabName }) (line 856). For labels like 'Body' vs 'Body Auth' or 'Query' vs 'Query Params', the first substring match could be incorrect.

Add { exact: true } to the role queries, anchor the RegExp with ^...$, and scope the menuitem lookup under .tippy-box to eliminate substring false matches.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/utils/page/actions.ts` at line 819, The tab lookups use loose substring
matching causing false positives; update the locator calls: change the
pane.locator('.tabs').getByRole('tab', { name: tabName }) call (visibleTab) to
pass exact: true; scope the menuitem search to the tippy popup (use
pane.locator('.tippy-box').getByRole('menuitem', { name: new
RegExp(`^${escapeRegExp(tabName)}$`, 'i'), exact: true })) and anchor the RegExp
with ^...$ (ensure tabName is escaped when building the RegExp); and replace
.filter({ hasText: tabName }) with a stricter match (either use getByRole with
exact: true or filter using an anchored/escaped RegExp) so only exact label
matches like "Body" vs "Body Auth" are returned.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/utils/page/actions.ts`:
- Around line 836-868: The overflow dropdown can remain open when a subsequent
path (dropdownItem or fallbackDropdownItem) fails, causing flakes; in the catch
blocks inside the function handling overflowButton.click and the two dropdown
click/expect blocks (references: overflowButton.click, dropdownItem,
fallbackDropdownItem, visibleTab) dismiss the popover before returning false —
e.g. call a neutral dismiss action such as page.keyboard.press('Escape') or
click a neutral area (page.click on a non-interactive selector) and await it,
then return false so the next poll iteration starts with the menu closed.
- Line 824: The test uses Playwright's matcher toContainClass on visibleTab (see
await expect(visibleTab).toContainClass('active', { timeout: 500 });) which
requires `@playwright/test` >= v1.52.0; update the package.json dependency for
`@playwright/test` from ^1.51.1 to ^1.52.0 (or later) so the runtime resolver will
install a version that includes toContainClass, then run install and CI tests to
verify the assertions (also update any other occurrences referenced in the
review).

---

Nitpick comments:
In `@tests/utils/page/actions.ts`:
- Line 819: The tab lookups use loose substring matching causing false
positives; update the locator calls: change the
pane.locator('.tabs').getByRole('tab', { name: tabName }) call (visibleTab) to
pass exact: true; scope the menuitem search to the tippy popup (use
pane.locator('.tippy-box').getByRole('menuitem', { name: new
RegExp(`^${escapeRegExp(tabName)}$`, 'i'), exact: true })) and anchor the RegExp
with ^...$ (ensure tabName is escaped when building the RegExp); and replace
.filter({ hasText: tabName }) with a stricter match (either use getByRole with
exact: true or filter using an anchored/escaped RegExp) so only exact label
matches like "Body" vs "Body Auth" are returned.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 80d7c052-bb5a-4e1f-b461-c90402dd3951

📥 Commits

Reviewing files that changed from the base of the PR and between 3893d9d and 609f395.

📒 Files selected for processing (1)
  • tests/utils/page/actions.ts

Comment thread tests/utils/page/actions.ts
Comment thread tests/utils/page/actions.ts
@sid-bruno sid-bruno merged commit 2c9dc9d into usebruno:main May 13, 2026
14 of 16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants