Skip to content

fix(file-mode): crash issue while searching in file mode#8532

Merged
bijin-bruno merged 6 commits into
usebruno:mainfrom
shubh-bruno:fix/file-change
Jul 9, 2026
Merged

fix(file-mode): crash issue while searching in file mode#8532
bijin-bruno merged 6 commits into
usebruno:mainfrom
shubh-bruno:fix/file-change

Conversation

@shubh-bruno

@shubh-bruno shubh-bruno commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Description

JIRA - (Unable to Save a .bru File in File Mode for a Transient Request)
JIRA - (Ctrl/Cmd+F in code editor crashes app)

Fixes: #8437

Problem

When you create a transient request, switch to File Mode, edit the raw content, and save, the edits were silently dropped and the request was saved from stale data. Related close/keybinding paths were inconsistent, and the file-mode editor had a search crash.

Root cause

File-mode edits are stored only in item.draft.raw, but the transient save path serialized the structured request (transformRequestToSaveToFilesystem), which never reads raw.

Solution

  • Transient save preserves raw edits - when the raw was actually edited in file mode (draft.raw !== item.raw), parse it back to structured form via renderer:convert-to-json before saving. Code-mode saves keep the original structured path (guarded by the !== check so code-mode edits aren't clobbered).
  • Unified close/save routing - Save & Close and the save shortcut now route to saveFile(raw) in file mode (matching the Save button) vs saveRequest otherwise, so ✕ / middle-click / Cmd-W / Cmd-S all behave the same.
  • File-mode editor honors Preferences keybindings - added the mousetrap class and removed the hardcoded Cmd-S, so the user's configured save binding works inside the editor.
  • Fixed in-editor search crash - Cmd-F used a broken querySelector(...).focus() that threw null.focus(); replaced with a CodeMirrorSearch ref.

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

  • New Features
    • Improved in-editor search: Cmd/Ctrl+F now reliably opens the search UI and immediately focuses the search input.
    • Enhanced transient request saving for file-mode workflows, including “Save” and “Save and Close” with the correct save destination.
  • Bug Fixes
    • Fixed file-mode transient saves by converting edited raw content to JSON when required, validating the prepared payload, and ensuring drafts are fully handled.
  • Tests
    • Added/extended Playwright coverage for transient file-mode saving and search across formats, plus updated test utilities and data-testid attributes for the search UI.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Updates CodeEditor search handling to focus the search bar through a ref, routes file-mode and JS saves through saveFile, converts transient raw content before saving, and adds file-mode Playwright helpers plus save/search coverage.

Changes

File-mode save and editor search

Layer / File(s) Summary
CodeEditor search focus
packages/bruno-app/src/components/FileEditor/CodeEditor/index.js, packages/bruno-app/src/components/CodeMirrorSearch/index.js
Adds a search-bar ref, updates Cmd/Ctrl-F to show and focus the search input through that ref, adds the mousetrap class to the CodeMirror input, and adds test identifiers to the search UI.
Request saving and transient conversion
packages/bruno-app/src/components/RequestTabs/RequestTab/index.js, packages/bruno-app/src/components/SaveTransientRequest/index.js
Dispatches saveFile instead of saveRequest for file-mode or js items in the Save shortcut and Save and Close flow, converts draft raw content to JSON before saving, strips draft and raw fields from the saved item, and adds createCollection metadata plus modal test identifiers.
File-mode test helpers
tests/utils/page/file-mode.ts, tests/utils/page/locators.ts, tests/utils/page/index.ts
Adds file-mode locators, deterministic search content, file-mode editor and modal helpers, and re-exports them through the page utility modules.
Transient file-mode Playwright coverage
tests/transient-requests/transient-file-mode-save.spec.ts
Adds a parameterized Playwright suite for file-mode save flows, a code-mode regression, and file-mode search highlighting across bru and yml formats.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

  • usebruno/bruno#6980: Overlaps with the same search-bar focus flow in CodeEditor and CodeMirrorSearch.
  • usebruno/bruno#8258: Introduces the file-mode save path and saveFile infrastructure that this PR uses.
  • usebruno/bruno#7141: Touches keyboard shortcut handling in Playwright coverage and save shortcut behavior.

Suggested reviewers: helloanoop, lohit-bruno, naman-bruno, bijin-bruno, sid-bruno

Poem

Cmd-F now finds its little way,
and file-mode saves can stay and play.
Draft raw becomes JSON with care,
while tests march through bru and yml pair.
Search glows, saves land, no crash today ✨

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The search refactor replaces the null focus path in CodeEditor and adds coverage for file-mode search, addressing #8437.
Out of Scope Changes check ✅ Passed The save-flow and test-helper changes support the stated file-mode fixes, so no clear unrelated scope is introduced.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the primary fix for the file-mode search crash.
✨ 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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/bruno-app/src/components/FileEditor/CodeEditor/index.js (1)

184-184: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Ref callback returns a value — use a statement body for React 19 compatibility.

The expression-body arrow (node) => (this.searchBarRef.current = node) returns node. React 19 discourages returning values from ref callbacks (returning a function is treated as a cleanup function). The other ref callback in this file (line 190) already uses curly braces correctly.

♻️ Proposed fix
-          ref={(node) => (this.searchBarRef.current = node)}
+          ref={(node) => {
+            this.searchBarRef.current = node;
+          }}
🤖 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/components/FileEditor/CodeEditor/index.js` at line
184, The ref callback assigned to searchBarRef in CodeEditor should not use an
expression body that returns the node value, because React 19 treats ref
callback return values as cleanup functions. Update the ref callback in the
CodeEditor component to use a block body with an assignment statement, matching
the safer pattern already used by the other ref callback in this file.
tests/transient-requests/transient-file-mode-save.spec.ts (1)

11-79: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚖️ Poor tradeoff

Centralize selectors and move assertions out of helpers per path instructions.

The spec defines helpers (switchToFileMode, setUrlInFileModeRaw, saveTransientViaModal, expectFileModeRawContainsUrl, searchInFileMode, closeFileModeSearch) with inline raw CSS selectors like .file-mode .CodeMirror, .bruno-modal-card, #request-name, .bruno-search-bar, and .cm-search-current. Several helpers also contain expect() assertions. Per path instructions, selectors should be centralized in page modules under tests/utils/page/* and assertions should live in the spec, not in helpers.

As per path instructions, "Centralize locators and actions in page modules under tests/utils/page/*; never inline raw selectors in a spec" and "Assertions must live in the spec (expect(...)), while page-module helpers should only synchronize."

🤖 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/transient-requests/transient-file-mode-save.spec.ts` around lines 11 -
79, This spec mixes raw selectors and assertions into local helpers, which
should instead be centralized and kept action-only. Move the locator logic from
switchToFileMode, setUrlInFileModeRaw, saveTransientViaModal,
expectFileModeRawContainsUrl, searchInFileMode, and closeFileModeSearch into
page modules under tests/utils/page/* using shared locators for file mode, the
save modal, and search bar. Remove expect() calls from those helpers so they
only perform synchronization/actions, and keep all assertions in the spec body
after calling the page-module helpers.

Source: Path instructions

🤖 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/components/FileEditor/CodeEditor/index.js`:
- Line 184: The ref callback assigned to searchBarRef in CodeEditor should not
use an expression body that returns the node value, because React 19 treats ref
callback return values as cleanup functions. Update the ref callback in the
CodeEditor component to use a block body with an assignment statement, matching
the safer pattern already used by the other ref callback in this file.

In `@tests/transient-requests/transient-file-mode-save.spec.ts`:
- Around line 11-79: This spec mixes raw selectors and assertions into local
helpers, which should instead be centralized and kept action-only. Move the
locator logic from switchToFileMode, setUrlInFileModeRaw, saveTransientViaModal,
expectFileModeRawContainsUrl, searchInFileMode, and closeFileModeSearch into
page modules under tests/utils/page/* using shared locators for file mode, the
save modal, and search bar. Remove expect() calls from those helpers so they
only perform synchronization/actions, and keep all assertions in the spec body
after calling the page-module helpers.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 182246ad-d025-4538-9cbe-d53c1e234769

📥 Commits

Reviewing files that changed from the base of the PR and between da707ea and 22fb7cb.

📒 Files selected for processing (4)
  • packages/bruno-app/src/components/FileEditor/CodeEditor/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/components/SaveTransientRequest/index.js
  • tests/transient-requests/transient-file-mode-save.spec.ts

Comment thread packages/bruno-app/src/components/FileEditor/CodeEditor/index.js Outdated
Comment thread tests/transient-requests/transient-file-mode-save.spec.ts Outdated
Comment thread tests/transient-requests/transient-file-mode-save.spec.ts Outdated
Comment thread tests/transient-requests/transient-file-mode-save.spec.ts Outdated
Comment thread tests/transient-requests/transient-file-mode-save.spec.ts Outdated
Comment thread tests/transient-requests/transient-file-mode-save.spec.ts Outdated
Comment thread tests/transient-requests/transient-file-mode-save.spec.ts Outdated
Comment thread tests/transient-requests/transient-file-mode-save.spec.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/utils/page/file-mode.ts (1)

8-11: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Move assertions out of action helpers

switchToFileMode, saveTransientViaModal, searchInFileMode, and closeFileModeSearch contain expect() assertions. Per the Playwright testing guide, actions should only synchronize/wait — assertions belong in the spec. Replace expect().toBeVisible() with waitFor() for synchronization, and move behavioral assertions (search highlights, result counts) to the spec.

As per path instructions, the referenced documentation states: "Add assertions in the spec (expect) while actions should only synchronize/wait (no assertions inside actions)."

♻️ Proposed refactor for file-mode.ts action helpers
 export const switchToFileMode = async (page: Page) => {
   await page.getByTestId('view-mode-file').click();
-  await expect(fileModeEditor(page)).toBeVisible();
+  await fileModeEditor(page).waitFor();
 };
 export const saveTransientViaModal = async (page: Page, requestName: string) => {
   const saveModal = page.locator('.bruno-modal-card').filter({ hasText: 'Save Request' });
-  await expect(saveModal).toBeVisible({ timeout: 5000 });
+  await saveModal.waitFor({ timeout: 5000 });
   const requestNameInput = saveModal.locator('`#request-name`');
   await requestNameInput.clear();
   await requestNameInput.fill(requestName);
   await saveModal.getByRole('button', { name: 'Save' }).click();
 };
+export const searchHighlight = (page: Page) =>
+  fileModeEditor(page).locator('.cm-search-current').first();
+export const searchResultCount = (page: Page) =>
+  page.locator('.bruno-search-bar .searchbar-result-count');
+
 export const searchInFileMode = async (page: Page, term: string) => {
   await fileModeEditor(page).click();
   await page.keyboard.press(findShortcut);
   const searchBar = page.locator('.bruno-search-bar');
-  await expect(searchBar).toBeVisible();
+  await searchBar.waitFor();
   await searchBar.locator('input').fill(term);
-  await expect(fileModeEditor(page).locator('.cm-search-current').first()).toBeVisible();
-  await expect(searchBar.locator('.searchbar-result-count')).not.toHaveText('0 results');
 };
 export const closeFileModeSearch = async (page: Page) => {
   await page.locator('.bruno-search-bar input').press('Escape');
-  await expect(page.locator('.bruno-search-bar')).toBeHidden();
+  await page.locator('.bruno-search-bar').waitFor({ state: 'hidden' });
 };

Then in the spec, add the behavioral assertions after calling searchInFileMode:

await test.step('Search "meta" -> matches are highlighted', async () => {
  await searchInFileMode(page, 'meta');
  await expect(searchHighlight(page)).toBeVisible();
  await expect(searchResultCount(page)).not.toHaveText('0 results');
});

Remember to re-export searchHighlight and searchResultCount from tests/utils/page/index.ts.

Also applies to: 22-29, 61-69, 71-74

🤖 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/file-mode.ts` around lines 8 - 11, `switchToFileMode`,
`saveTransientViaModal`, `searchInFileMode`, and `closeFileModeSearch` currently
mix actions with `expect()` assertions; move those behavioral checks into the
spec and keep helpers limited to synchronization. Replace the visibility
assertion in `switchToFileMode` with a `waitFor()`-based wait on
`fileModeEditor(page)`, and apply the same pattern to the other helpers where
they assert UI state. Update the relevant spec to assert search highlights and
result counts after calling `searchInFileMode`, and re-export `searchHighlight`
and `searchResultCount` from the page index so the spec can use them.

Source: Path instructions

🤖 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 `@tests/utils/page/file-mode.ts`:
- Around line 8-11: `switchToFileMode`, `saveTransientViaModal`,
`searchInFileMode`, and `closeFileModeSearch` currently mix actions with
`expect()` assertions; move those behavioral checks into the spec and keep
helpers limited to synchronization. Replace the visibility assertion in
`switchToFileMode` with a `waitFor()`-based wait on `fileModeEditor(page)`, and
apply the same pattern to the other helpers where they assert UI state. Update
the relevant spec to assert search highlights and result counts after calling
`searchInFileMode`, and re-export `searchHighlight` and `searchResultCount` from
the page index so the spec can use them.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 590b4af8-4374-45f2-baa2-416f463312f9

📥 Commits

Reviewing files that changed from the base of the PR and between 22fb7cb and a00ee92.

📒 Files selected for processing (4)
  • packages/bruno-app/src/components/FileEditor/CodeEditor/index.js
  • tests/transient-requests/transient-file-mode-save.spec.ts
  • tests/utils/page/file-mode.ts
  • tests/utils/page/index.ts
✅ Files skipped from review due to trivial changes (1)
  • tests/utils/page/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/bruno-app/src/components/FileEditor/CodeEditor/index.js

sid-bruno
sid-bruno previously approved these changes Jul 8, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/utils/page/file-mode.ts (1)

6-9: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer semantic selectors over raw CSS class matching where feasible.

editor, editorContent, and currentSearchMatch use raw CSS selectors (.file-mode .CodeMirror, .cm-search-current) rather than getByTestId/getByRole. Consider adding a data-testid on the file-mode editor wrapper for consistency with the other locators in this file.

As per path instructions: "Use semantic selectors in page modules (getByTestId, getByRole, getByLabel) rather than raw CSS selectors."

🤖 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/file-mode.ts` around lines 6 - 9, The file-mode locator
helpers are using raw CSS selectors instead of the preferred semantic test
selectors. Update buildFileModeLocators to use getByTestId/getByRole/getByLabel
where possible, and add a data-testid on the file-mode editor wrapper if needed
so editor, editorContent, and currentSearchMatch can be targeted consistently
without class-based selectors.

Source: Path instructions

🤖 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 `@tests/utils/page/file-mode.ts`:
- Around line 6-9: The file-mode locator helpers are using raw CSS selectors
instead of the preferred semantic test selectors. Update buildFileModeLocators
to use getByTestId/getByRole/getByLabel where possible, and add a data-testid on
the file-mode editor wrapper if needed so editor, editorContent, and
currentSearchMatch can be targeted consistently without class-based selectors.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c8c070a2-2870-42c9-853b-918047b4aa5d

📥 Commits

Reviewing files that changed from the base of the PR and between a00ee92 and 938a6df.

📒 Files selected for processing (6)
  • packages/bruno-app/src/components/CodeMirrorSearch/index.js
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • packages/bruno-app/src/components/SaveTransientRequest/index.js
  • tests/transient-requests/transient-file-mode-save.spec.ts
  • tests/utils/page/file-mode.ts
  • tests/utils/page/locators.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/bruno-app/src/components/CodeMirrorSearch/index.js
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • tests/transient-requests/transient-file-mode-save.spec.ts

Comment thread packages/bruno-app/src/components/RequestTabs/RequestTab/index.js Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
tests/utils/page/file-mode.ts (1)

7-9: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the existing Code Editor label for the top-level locator

editor() can target the wrapper’s aria-label="Code Editor" instead of .file-mode .CodeMirror. editorContent() and currentSearchMatch() still rely on CodeMirror internals, so add a semantic hook there if these assertions need to stay.

🤖 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/file-mode.ts` around lines 7 - 9, The top-level editor
locator in the file-mode page object should use the existing “Code Editor” aria
label instead of the CodeMirror class selector. Update the `editor()` helper in
`file-mode.ts` to target the accessible wrapper, and keep `editorContent()` and
`currentSearchMatch()` on CodeMirror internals only if needed by adding a stable
semantic hook for those assertions.

Source: Path instructions

🤖 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 `@tests/utils/page/file-mode.ts`:
- Around line 7-9: The top-level editor locator in the file-mode page object
should use the existing “Code Editor” aria label instead of the CodeMirror class
selector. Update the `editor()` helper in `file-mode.ts` to target the
accessible wrapper, and keep `editorContent()` and `currentSearchMatch()` on
CodeMirror internals only if needed by adding a stable semantic hook for those
assertions.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 16b18fb4-89e0-4d6c-ba3c-74ab6ea4763c

📥 Commits

Reviewing files that changed from the base of the PR and between bfe2b7a and 9a362af.

📒 Files selected for processing (2)
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js
  • tests/utils/page/file-mode.ts
💤 Files with no reviewable changes (1)
  • packages/bruno-app/src/components/RequestTabs/RequestTab/index.js

@bijin-bruno
bijin-bruno merged commit ce7dde1 into usebruno:main Jul 9, 2026
12 of 18 checks passed
ravindra-bruno pushed a commit to ravindra-bruno/bruno that referenced this pull request Jul 9, 2026
* fix(file-mode): crash issue while searching in file mode

* fix: moved test utils & updated locators

* fix: resolved comments

* fix: resolved comments

* fix: resolve comments & update locators

---------

Co-authored-by: shubh-bruno <shubh-bruno@shubh-bruno.local>
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.

Ctrl+F causes crash: Cannot read properties of null (reading 'focus') in editor

3 participants