Conversation
WalkthroughRefactors modal styling to use theme tokens and adds modal.closeButton token; converts multiple Preferences panels to debounced autosave (removing manual Save); updates collection removal modal UI and related styled components; adjusts tests and test helpers to use new testids and autosave waits. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant PrefUI as Preferences UI
participant Debouncer as Debounce Timer
participant Validator as Schema Validator
participant Store as Redux/API
User->>PrefUI: change input
activate PrefUI
PrefUI->>Debouncer: schedule debouncedSave (500ms)
deactivate PrefUI
Note over Debouncer: repeated input resets timer
Debouncer->>Validator: validate(values)
activate Validator
alt valid
Validator-->>Debouncer: valid
Debouncer->>Store: dispatch save action
activate Store
Store-->>Debouncer: success / error
deactivate Store
else invalid
Validator-->>Debouncer: invalid (skip save)
Debouncer->>PrefUI: surface validation state
end
deactivate Validator
Note over PrefUI,Debouncer: useEffect cleanup cancels pending debouncedSave on unmount
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/bruno-app/src/components/Preferences/ProxySettings/index.js (1)
18-18: Remove debugconsole.logstatement.This appears to be a leftover debug statement that should be removed before merge.
Proposed fix
const dispatch = useDispatch(); - console.log(preferences);
🧹 Nitpick comments (11)
packages/bruno-app/src/components/Preferences/StyledWrapper.js (1)
40-45: Fixed viewport sizing may cause issues on smaller screens.The
70vhmin/max height and50vwmax-width could clip content or cause poor UX on smaller displays. Consider using responsive breakpoints or more flexible constraints.packages/bruno-app/src/components/Modal/StyledWrapper.js (2)
104-114: Redundantborder-radiusdeclarations.Line 109 sets
border-radius: 0px;but line 113 immediately overrides it with${(props) => props.theme.border.radius.sm}. Remove the first declaration.Proposed fix
.textbox { line-height: 1.42857143; border: 1px solid #ccc; padding: 0.45rem; box-shadow: none; - border-radius: 0px; outline: none; box-shadow: none; transition: border-color ease-in-out 0.1s; border-radius: ${(props) => props.theme.border.radius.sm};
104-121: Duplicatebox-shadow: none;declarations.Lines 108 and 111 both declare
box-shadow: none;. Remove the duplicate.packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js (1)
4-8: Use theme token forborder-radiusconsistency.Other StyledWrapper files in this PR use
${(props) => props.theme.border.radius.sm}or.basefor border-radius. Hardcoding4pxhere breaks consistency.Proposed fix
.collection-info-card { background-color: ${(props) => props.theme.modal.title.bg}; - border-radius: 4px; + border-radius: ${(props) => props.theme.border.radius.sm}; padding: 12px; }packages/bruno-app/src/components/Preferences/Display/Font/index.js (1)
41-46: Debounced function recreated on everyhandleSavechange — consideruseMemoor stable ref.Since
handleSavedepends onpreferences, each save triggers a newhandleSave→ newdebouncedSave. This cancels the previous debounce and may cause unexpected behavior during rapid changes. Consider usinguseMemowith an empty dependency array and referencinghandleSavevia a ref, or useuseRefto store a stable debounced function.Alternative pattern using ref
+ const handleSaveRef = useRef(handleSave); + useEffect(() => { + handleSaveRef.current = handleSave; + }, [handleSave]); + + const debouncedSave = useMemo( + () => debounce((font, fontSize) => { + handleSaveRef.current(font, fontSize); + }, 500), + [] + ); - const debouncedSave = useCallback( - debounce((font, fontSize) => { - handleSave(font, fontSize); - }, 500), - [handleSave] - );packages/bruno-app/src/components/Preferences/ProxySettings/index.js (2)
91-92: Empty catch block silently swallows validation errors.Consider logging the error or providing user feedback when validation fails, similar to the pattern in General/index.js.
Proposed fix
.catch((error) => { + console.error('Proxy validation error:', error.message); });
78-100:proxySchemain dependency array causes unnecessary re-renders.
proxySchemais defined inside the component and creates a new reference on each render. Move it outside the component or memoize it to stabilize the dependency.packages/bruno-app/src/components/Preferences/General/index.js (2)
136-137: Empty catch block silently swallows validation errors.Same issue as ProxySettings — consider logging the error for debugging purposes.
Proposed fix
.catch((error) => { + console.error('Preferences validation error:', error.message); });
130-140: Same debounce recreation pattern — consider extracting to a custom hook.All preference components (Font, ProxySettings, General, Beta) use the same debounced auto-save pattern. Consider extracting this into a reusable hook like
useDebouncedSaveto reduce duplication and centralize the fix for the dependency recreation issue.packages/bruno-app/src/components/Preferences/Beta/index.js (2)
70-80:betaSchemain dependency array is recreated each render.
generateValidationSchema()is called on line 45 every render, producing a new schema reference. This causesdebouncedSaveto be recreated constantly. Memoize the schema:Proposed fix
- const betaSchema = generateValidationSchema(); + const betaSchema = useMemo(() => generateValidationSchema(), []);And add
useMemoto the imports on line 1.
76-77: Empty catch block silently swallows validation errors.Consistent with other preference components — consider logging for debugging.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
packages/bruno-app/src/components/Modal/StyledWrapper.jspackages/bruno-app/src/components/Preferences/Beta/index.jspackages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/components/Preferences/General/index.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.jspackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.jspackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/components/Preferences/Beta/index.jspackages/bruno-app/src/components/Modal/StyledWrapper.jspackages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/Preferences/General/index.js
🧠 Learnings (5)
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{jsx,tsx} : Styled Components are used as wrappers to define both self and children components style; Tailwind classes are used specifically for layout based styles
Applied to files:
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.jspackages/bruno-app/src/components/Modal/StyledWrapper.jspackages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/components/Preferences/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{jsx,tsx} : Styled Component CSS might also change layout but Tailwind classes shouldn't define colors
Applied to files:
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.jspackages/bruno-app/src/components/Modal/StyledWrapper.jspackages/bruno-app/src/components/Preferences/StyledWrapper.js
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.{jsx,tsx} : Use styled component's theme prop to manage CSS colors and not CSS variables when in the context of a styled component or any React component using the styled component
Applied to files:
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.jspackages/bruno-app/src/components/Modal/StyledWrapper.jspackages/bruno-app/src/components/Preferences/StyledWrapper.js
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.jspackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.jspackages/bruno-app/src/components/Preferences/ProxySettings/index.jspackages/bruno-app/src/components/Preferences/Beta/index.jspackages/bruno-app/src/components/Modal/StyledWrapper.jspackages/bruno-app/src/components/Preferences/Display/Font/index.jspackages/bruno-app/src/components/Preferences/StyledWrapper.jspackages/bruno-app/src/components/Preferences/General/index.js
📚 Learning: 2025-12-02T20:48:05.670Z
Learnt from: NikHillAgar
Repo: usebruno/bruno PR: 6279
File: packages/bruno-app/src/components/RequestPane/PromptVariables/PromptVariablesModal/index.js:79-86
Timestamp: 2025-12-02T20:48:05.670Z
Learning: In React 19+, ref callbacks support returning cleanup functions. When a ref callback returns a function, React will call it when the element unmounts or the ref changes, similar to useEffect cleanup. This is documented at https://react.dev/learn/manipulating-the-dom-with-refs#how-to-manage-a-list-of-refs-using-a-ref-callback
Applied to files:
packages/bruno-app/src/components/Preferences/General/index.js
🧬 Code graph analysis (5)
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js (1)
packages/bruno-app/src/components/Preferences/StyledWrapper.js (1)
StyledWrapper(3-61)
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js (2)
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js (1)
StyledWrapper(3-22)packages/bruno-app/src/components/Modal/index.js (1)
Modal(60-169)
packages/bruno-app/src/components/Preferences/ProxySettings/index.js (1)
packages/bruno-app/src/components/Preferences/General/index.js (2)
preferences(15-15)debouncedSave(130-140)
packages/bruno-app/src/components/Preferences/Beta/index.js (4)
packages/bruno-app/src/components/Preferences/Display/Font/index.js (4)
handleSave(27-39)dispatch(10-10)preferences(11-11)debouncedSave(41-46)packages/bruno-app/src/components/Preferences/General/index.js (5)
handleSave(99-128)dispatch(16-16)preferences(15-15)debouncedSave(130-140)formik(66-97)packages/bruno-electron/src/store/preferences.js (2)
savePreferences(170-182)preferences(230-230)packages/bruno-app/src/utils/beta-features.js (1)
preferences(17-17)
packages/bruno-app/src/components/Preferences/General/index.js (2)
packages/bruno-app/src/components/Preferences/Display/Font/index.js (4)
handleSave(27-39)dispatch(10-10)preferences(11-11)debouncedSave(41-46)packages/bruno-electron/src/store/preferences.js (2)
preferences(230-230)preferencesSchema(60-108)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Unit Tests
- GitHub Check: CLI Tests
- GitHub Check: Playwright E2E Tests
- GitHub Check: SSL Tests - Windows
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - macOS
🔇 Additional comments (10)
packages/bruno-app/src/components/Preferences/StyledWrapper.js (1)
1-60: LGTM — theme-driven styling applied consistently.Good use of
props.themefor colors and design tokens throughout. The styling follows the project's Styled Components conventions correctly. Based on learnings, colors are managed via theme props rather than CSS variables.packages/bruno-app/src/components/Modal/StyledWrapper.js (1)
1-163: LGTM — modal styling migrated to theme tokens.The transition to theme-based values for colors, radii, and typography is consistent with the broader styling updates in this PR.
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js (1)
1-24: LGTM — new styled wrapper follows project conventions.Theme-driven styling with proper use of
props.themefor colors and typography. Based on learnings, this aligns with the project's Styled Components pattern.packages/bruno-app/src/components/Preferences/Display/Font/index.js (2)
64-73: Uncontrolled input withdefaultValuewon't sync with state changes.Using
defaultValuemeans the input won't update ifcodeFontstate changes externally (e.g., preferences reset). If bi-directional sync is needed, switch tovalue={codeFont}.
1-90: Auto-save pattern implemented correctly for basic use case.The debounced save with initial mount skip and cleanup is a reasonable approach.
packages/bruno-app/src/components/Preferences/ProxySettings/index.js (1)
119-126: Cleanup runs on every dependency change — may cancel debounce prematurely.With
debouncedSavein the dependency array, if the debounced function is recreated (due toonUpdatechanging), the cleanup cancels the pending save. This mirrors the issue in Font/index.js. Consider stabilizing the debounced function.packages/bruno-app/src/components/Preferences/General/index.js (1)
1-390: LGTM — auto-save implementation is consistent with other preference panels.The debounced save flow with validation is correctly implemented. Form values are properly synced with Formik's controlled inputs.
packages/bruno-app/src/components/Preferences/Beta/index.js (1)
1-140: LGTM — auto-save pattern consistent with other preference components.The implementation aligns with the PR's goal of debounced auto-save across preference panels.
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js (2)
46-64: Minor terminology note: header says "Close" but button says "Remove".The customHeader and title use "Close Collection" while confirmText is "Remove". The body text clarifies the action, but consider aligning button text to "Close" for consistency, unless "Remove" is intentional to match existing behavior.
1-78: LGTM — modal redesign with StyledWrapper applied correctly.The component properly wraps the Modal with the new StyledWrapper and uses the collection info card styling. The alert icon and updated messaging provide clearer UX.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (6)
tests/preferences/default-collection-location/default-collection-location.spec.js (2)
27-34: Replace fixed timeouts with locator-based waiting.The test now relies on
page.waitForTimeout()for both auto-save completion and modal close verification. Per coding guidelines, fixed timeouts should be avoided when locator-based waiting is possible.🔎 Suggested improvements
- // wait for auto-save to complete (debounce is 500ms) - await page.waitForTimeout(1000); - - // close the preferences - await page.locator('[data-test-id="modal-close-button"]').click(); - - // wait for modal to close - await page.waitForTimeout(500); + // wait for auto-save to complete (debounce is 500ms) + await page.waitForTimeout(1000); + + // close the preferences + const modalCloseButton = page.locator('[data-test-id="modal-close-button"]'); + await modalCloseButton.click(); + + // wait for modal to close + const preferencesModal = page.locator('.bruno-modal-card').filter({ hasText: 'Preferences' }); + await expect(preferencesModal).not.toBeVisible();This replaces the 500ms fixed timeout with an assertion that the modal is no longer visible, making the test more reliable and faster when the modal closes quickly.
47-54: Apply the same locator-based waiting pattern.Same issue as lines 27-34. The fixed 500ms timeout should be replaced with a locator-based assertion.
🔎 Suggested improvement
- // wait for auto-save to complete (debounce is 500ms) - await page.waitForTimeout(1000); - - // close the preferences - await page.locator('[data-test-id="modal-close-button"]').click(); - - // wait for modal to close - await page.waitForTimeout(500); + // wait for auto-save to complete (debounce is 500ms) + await page.waitForTimeout(1000); + + // close the preferences + const modalCloseButton = page.locator('[data-test-id="modal-close-button"]'); + await modalCloseButton.click(); + + // wait for modal to close + const preferencesModal = page.locator('.bruno-modal-card').filter({ hasText: 'Preferences' }); + await expect(preferencesModal).not.toBeVisible();tests/onboarding/sample-collection.spec.ts (1)
96-97: Consider wrapping modal interaction in test.step.The modal confirmation flow would benefit from being wrapped in a
test.stepfor better report readability, per coding guidelines.🔎 Suggested improvement
- // Confirm removal in the modal - await page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }).waitFor({ state: 'visible' }); - await page.locator('.bruno-modal-footer .submit').click(); + await test.step('Confirm removal in the modal', async () => { + await page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }).waitFor({ state: 'visible' }); + await page.locator('.bruno-modal-footer .submit').click(); + });This improves report readability by clearly separating the modal interaction as a distinct step.
tests/preferences/autosave/autosave.spec.ts (1)
46-51: Add assertion after modal close for reliability.While the explicit modal close is good, adding an assertion that the modal is no longer visible would make the test more robust and align with Playwright best practices.
🔎 Suggested improvement
// Wait for auto-save to complete (debounce is 500ms) await page.waitForTimeout(1000); // Close preferences modal await preferencesModal.locator('[data-testid="modal-close-button"]').click(); - await expect(preferencesModal).not.toBeVisible(); + + // Verify modal is closed + await expect(preferencesModal).not.toBeVisible();Apply the same pattern to lines 96-101 and 173-178 for consistency.
tests/utils/page/actions.ts (2)
20-24: Use locator variables for better readability.Per coding guidelines, locator variables should be used instead of repeating the same locator selector multiple times.
🔎 Suggested improvement
await firstCollection.locator('.collection-actions .icon').click(); await page.locator('.dropdown-item').getByText('Remove').click(); - // Wait for the close collection modal to be visible - await page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }).waitFor({ state: 'visible' }); + + // Wait for the close collection modal to be visible + const closeCollectionModal = page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }); + await closeCollectionModal.waitFor({ state: 'visible' }); await page.locator('.bruno-modal-footer .submit').click(); - // Wait for the close collection modal to be hidden - await page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }).waitFor({ state: 'hidden' }); + + // Wait for the close collection modal to be hidden + await closeCollectionModal.waitFor({ state: 'hidden' });This makes the code more maintainable and follows the coding guidelines for using locator variables.
291-293: Apply the same locator variable pattern.Same recommendation as lines 20-24. Use a locator variable instead of repeating the selector.
🔎 Suggested improvement
await locators.dropdown.item('Remove').click(); - // Wait for and confirm modal - await page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }).waitFor({ state: 'visible' }); + // Wait for and confirm modal + const closeCollectionModal = page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }); + await closeCollectionModal.waitFor({ state: 'visible' }); await locators.modal.button('Remove').click(); - await page.locator('[data-testid="close-collection-modal-title"]', { hasText: 'Close Collection' }).waitFor({ state: 'hidden' }); + await closeCollectionModal.waitFor({ state: 'hidden' });
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.jspackages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.jstests/onboarding/sample-collection.spec.tstests/preferences/autosave/autosave.spec.tstests/preferences/default-collection-location/default-collection-location.spec.jstests/utils/page/actions.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
packages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.jstests/onboarding/sample-collection.spec.tstests/utils/page/actions.tstests/preferences/autosave/autosave.spec.tstests/preferences/default-collection-location/default-collection-location.spec.js
tests/**/**.*
⚙️ CodeRabbit configuration file
tests/**/**.*: Review the following e2e test code written using the Playwright test library. Ensure that:
Follow best practices for Playwright code and e2e automation
Try to reduce usage of
page.waitForTimeout();in code unless absolutely necessary and the locator cannot be found using existingexpect()playwright callsAvoid using
page.pause()in codeUse locator variables for locators
Avoid using test.only
Use multiple assertions
Promote the use of
test.stepas much as possible so the generated reports are easier to readEnsure that the
fixtureslike the collections are nested inside thefixturesfolderFixture Example*: Here's an example of possible fixture and test pair
. ├── fixtures │ └── collection │ ├── base.bru │ ├── bruno.json │ ├── collection.bru │ ├── ws-test-request-with-headers.bru │ ├── ws-test-request-with-subproto.bru │ └── ws-test-request.bru ├── connection.spec.ts # <- Depends on the collection in ./fixtures/collection ├── headers.spec.ts ├── persistence.spec.ts ├── variable-interpolation │ ├── fixtures │ │ └── collection │ │ ├── environments │ │ ├── bruno.json │ │ └── ws-interpolation-test.bru │ ├── init-user-data │ └── variable-interpolation.spec.ts # <- Depends on the collection in ./variable-interpolation/fixtures/collection └── subproto.spec.ts
Files:
tests/onboarding/sample-collection.spec.tstests/utils/page/actions.tstests/preferences/autosave/autosave.spec.tstests/preferences/default-collection-location/default-collection-location.spec.js
🧠 Learnings (2)
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.jstests/preferences/default-collection-location/default-collection-location.spec.js
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
Applied to files:
tests/onboarding/sample-collection.spec.tstests/preferences/default-collection-location/default-collection-location.spec.js
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Playwright E2E Tests
- GitHub Check: Unit Tests
- GitHub Check: CLI Tests
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - macOS
- GitHub Check: SSL Tests - Windows
🔇 Additional comments (1)
tests/preferences/autosave/autosave.spec.ts (1)
46-51: LGTM! Test properly verifies modal closure.The test correctly waits for autosave debounce, closes the modal explicitly, and verifies the modal is no longer visible. This pattern is consistent across all three test steps in this file.
| </div> | ||
| <div className="flex justify-end mt-6"> | ||
| <button className="btn btn-close btn-sm mr-2" onClick={handleCancel}> | ||
| <button className="btn btn-close btn-sm mr-2" data-testid="modal-close-button" onClick={handleCancel}> |
There was a problem hiding this comment.
Inconsistent test ID placement across modal states.
The data-testid="modal-close-button" is only added to the Cancel button in the no-unsaved-changes branch (line 258), but the identical Cancel button in the hasUnsavedChanges branch (line 234) doesn't have it. Both buttons perform the same action (handleCancel), so tests relying on this test ID may fail or provide incomplete coverage when the modal displays unsaved changes.
Add the same data-testid to line 234 for consistency.
🔎 Suggested fix for consistent test ID
- <button className="btn btn-close btn-sm mr-2" onClick={handleCancel}>
+ <button className="btn btn-close btn-sm mr-2" data-testid="modal-close-button" onClick={handleCancel}>
Cancel
</button>Note: The AI summary mentions adding the test ID to "two locations," but only this line is annotated as changed. Please verify whether line 234 was also modified.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <button className="btn btn-close btn-sm mr-2" data-testid="modal-close-button" onClick={handleCancel}> | |
| <button className="btn btn-close btn-sm mr-2" data-testid="modal-close-button" onClick={handleCancel}> | |
| Cancel | |
| </button> |
🤖 Prompt for AI Agents
In
packages/bruno-app/src/components/Sidebar/Collections/RemoveCollectionsModal/index.js
around lines 234 and 258, the Cancel button in the hasUnsavedChanges branch
(around line 234) is missing the data-testid="modal-close-button" while the
Cancel button in the no-unsaved-changes branch (line 258) has it; add
data-testid="modal-close-button" to the Cancel button JSX at line 234 so both
branches use the same test id for consistent testing, ensuring the attribute is
applied exactly as on line 258 without altering the onClick handler or other
props.
| <StyledWrapper> | ||
| <Modal | ||
| size="sm" | ||
| title="Close Collection" |
| // verify success message | ||
| await expect(page.locator('text=Preferences saved successfully').first()).toBeVisible(); | ||
| // close the preferences | ||
| await page.locator('[data-test-id="modal-close-button"]').click(); |
There was a problem hiding this comment.
-
page.locator('[data-test-id="modal-close-button"]') to be replaced with page.getByTestId('modal-close-button')
-
Remove attribute data-test-id="modal-close-button" replace with
data-testid="modal-close-button" Ignore this, if this change need to be done across the test cases. But currently modified tests should usedata-testid="" and getByTestId
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (7)
tests/import/file-types/file-input-acceptance.spec.ts (1)
19-19: Extract locator to a variable per coding guidelines.The coding guidelines specify to use locator variables for locators. For consistency with line 9 and better readability, store the modal close button locator in a variable.
🔎 Suggested refactor
// Cleanup: close any open modals - await page.getByTestId('modal-close-button').click(); + const modalCloseButton = page.getByTestId('modal-close-button'); + await modalCloseButton.click();Based on coding guidelines: "Use locator variables for locators"
tests/preferences/support-links.spec.js (1)
3-27: Consider usingtest.stepto improve test reporting.The coding guidelines emphasize using
test.stepto make generated reports easier to read. Consider wrapping logical sections of this test in steps:🔎 Suggested refactor with test.step
test('Should verify all support links with correct URL in preference > Support tab', async ({ page }) => { - // Open Preferences - await page.getByLabel('Open Preferences').click(); - - // Go to Support tab - await page.getByRole('tab', { name: 'Support' }).click(); - - // Verify all support links with correct URL - const locator_twitter = page.getByRole('link', { name: 'Twitter' }); - expect(await locator_twitter.getAttribute('href')).toEqual('https://twitter.com/use_bruno'); - - const locator_github = page.getByRole('link', { name: 'GitHub', exact: true }); - expect(await locator_github.getAttribute('href')).toEqual('https://github.com/usebruno/bruno'); - - const locator_discord = page.getByRole('link', { name: 'Discord', exact: true }); - expect(await locator_discord.getAttribute('href')).toEqual('https://discord.com/invite/KgcZUncpjq'); - - const locator_reportissues = page.getByRole('link', { name: 'Report Issues', exact: true }); - expect(await locator_reportissues.getAttribute('href')).toEqual('https://github.com/usebruno/bruno/issues'); - - const locator_documentation = page.getByRole('link', { name: 'Documentation', exact: true }); - expect(await locator_documentation.getAttribute('href')).toEqual('https://docs.usebruno.com'); - - await page.getByTestId('modal-close-button').click(); + await test.step('Open Preferences and navigate to Support tab', async () => { + await page.getByLabel('Open Preferences').click(); + await page.getByRole('tab', { name: 'Support' }).click(); + }); + + await test.step('Verify all support links with correct URLs', async () => { + const locator_twitter = page.getByRole('link', { name: 'Twitter' }); + expect(await locator_twitter.getAttribute('href')).toEqual('https://twitter.com/use_bruno'); + + const locator_github = page.getByRole('link', { name: 'GitHub', exact: true }); + expect(await locator_github.getAttribute('href')).toEqual('https://github.com/usebruno/bruno'); + + const locator_discord = page.getByRole('link', { name: 'Discord', exact: true }); + expect(await locator_discord.getAttribute('href')).toEqual('https://discord.com/invite/KgcZUncpjq'); + + const locator_reportissues = page.getByRole('link', { name: 'Report Issues', exact: true }); + expect(await locator_reportissues.getAttribute('href')).toEqual('https://github.com/usebruno/bruno/issues'); + + const locator_documentation = page.getByRole('link', { name: 'Documentation', exact: true }); + expect(await locator_documentation.getAttribute('href')).toEqual('https://docs.usebruno.com'); + }); + + await test.step('Close preferences modal', async () => { + await page.getByTestId('modal-close-button').click(); + }); });As per coding guidelines.
packages/bruno-app/src/components/Modal/index.js (1)
12-13: Consider clarifying or removing the TODO comment.The TODO mentions removing
data-test-idand usingdata-testid, but this component already uses onlydata-testid(line 13). The TODO may refer to a broader codebase cleanup, but placing it here might be confusing.Either:
- Update the TODO to reflect broader scope (e.g., "TODO: Remove remaining data-test-id usage across other components")
- Remove it if the migration is complete for this component
- Move it to a tracking issue
tests/import/postman/invalid-missing-info.spec.ts (1)
23-23: LGTM! Improved selector strategy.The migration to
getByTestId('modal-close-button')is more reliable than the previous selector approach and follows Playwright best practices.Optional: Consider extracting locator and using test.step
Per coding guidelines, you could improve test readability:
+ const modalCloseButton = page.getByTestId('modal-close-button'); + // Cleanup: close any open modals - await page.getByTestId('modal-close-button').click(); + await test.step('Cleanup: close modal', async () => { + await modalCloseButton.click(); + });This makes reports easier to read and follows the locator variable pattern.
tests/import/insomnia/malformed-structure.spec.ts (1)
23-23: LGTM! Improved selector strategy.The migration to
getByTestId('modal-close-button')is more reliable than the previous selector approach and follows Playwright best practices.Optional: Consider extracting locator and using test.step
Per coding guidelines, you could improve test readability:
+ const modalCloseButton = page.getByTestId('modal-close-button'); + // Cleanup: close any open modals - await page.getByTestId('modal-close-button').click(); + await test.step('Cleanup: close modal', async () => { + await modalCloseButton.click(); + });This makes reports easier to read and follows the locator variable pattern.
tests/import/openapi/malformed-yaml.spec.ts (1)
25-25: LGTM! Improved selector strategy.The migration to
getByTestId('modal-close-button')is more reliable than the previous selector approach and follows Playwright best practices.Optional: Consider extracting locator and using test.step
Per coding guidelines, you could improve test readability:
+ const modalCloseButton = page.getByTestId('modal-close-button'); + // Cleanup: close any open modals - await page.getByTestId('modal-close-button').click(); + await test.step('Cleanup: close modal', async () => { + await modalCloseButton.click(); + });This makes reports easier to read and follows the locator variable pattern.
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js (1)
37-39: Consider simplifying the null collection guard.The current guard returns a
<div>that would render within a modal, butonConfirmalready handles the missing collection case with a toast. You could simplify this toreturn null;or rely solely on theonConfirmguard since the modal is unlikely to be rendered without a valid collection.🔎 Suggested simplification
if (!collection) { - return <div>Collection not found</div>; + return null; }
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (15)
packages/bruno-app/src/components/Modal/index.jspackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.jstests/import/file-types/file-input-acceptance.spec.tstests/import/file-types/invalid-file-handling.spec.tstests/import/insomnia/malformed-structure.spec.tstests/import/openapi/malformed-yaml.spec.tstests/import/openapi/missing-info.spec.tstests/import/postman/invalid-json.spec.tstests/import/postman/invalid-missing-info.spec.tstests/import/postman/invalid-schema.spec.tstests/onboarding/sample-collection.spec.tstests/preferences/default-collection-location/default-collection-location.spec.jstests/preferences/support-links.spec.jstests/request/encoding/curl-encoding.spec.tstests/utils/page/actions.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- tests/onboarding/sample-collection.spec.ts
- tests/preferences/default-collection-location/default-collection-location.spec.js
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (CODING_STANDARDS.md)
**/*.{js,jsx,ts,tsx}: Use 2 spaces for indentation. No tabs, just spaces
Stick to single quotes for strings. For JSX/TSX attributes, use double quotes (e.g., )
Always add semicolons at the end of statements
No trailing commas
Always use parentheses around parameters in arrow functions, even for single params
For multiline constructs, put opening braces on the same line, and ensure consistency. Minimum 2 elements for multiline
No newlines inside function parentheses
Space before and after the arrow in arrow functions.() => {}is good
No space between function name and parentheses.func()notfunc ()
Semicolons go at the end of the line, not on a new line
Names for functions need to be concise and descriptive
Add in JSDoc comments to add more details to the abstractions if needed
Add in meaningful comments instead of obvious ones where complex code flow is explained properly
Files:
tests/import/insomnia/malformed-structure.spec.tspackages/bruno-app/src/components/Modal/index.jstests/import/postman/invalid-schema.spec.tstests/import/postman/invalid-missing-info.spec.tstests/import/openapi/missing-info.spec.tstests/import/file-types/invalid-file-handling.spec.tstests/import/postman/invalid-json.spec.tstests/utils/page/actions.tstests/import/file-types/file-input-acceptance.spec.tspackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.jstests/request/encoding/curl-encoding.spec.tstests/import/openapi/malformed-yaml.spec.tstests/preferences/support-links.spec.js
tests/**/**.*
⚙️ CodeRabbit configuration file
tests/**/**.*: Review the following e2e test code written using the Playwright test library. Ensure that:
Follow best practices for Playwright code and e2e automation
Try to reduce usage of
page.waitForTimeout();in code unless absolutely necessary and the locator cannot be found using existingexpect()playwright callsAvoid using
page.pause()in codeUse locator variables for locators
Avoid using test.only
Use multiple assertions
Promote the use of
test.stepas much as possible so the generated reports are easier to readEnsure that the
fixtureslike the collections are nested inside thefixturesfolderFixture Example*: Here's an example of possible fixture and test pair
. ├── fixtures │ └── collection │ ├── base.bru │ ├── bruno.json │ ├── collection.bru │ ├── ws-test-request-with-headers.bru │ ├── ws-test-request-with-subproto.bru │ └── ws-test-request.bru ├── connection.spec.ts # <- Depends on the collection in ./fixtures/collection ├── headers.spec.ts ├── persistence.spec.ts ├── variable-interpolation │ ├── fixtures │ │ └── collection │ │ ├── environments │ │ ├── bruno.json │ │ └── ws-interpolation-test.bru │ ├── init-user-data │ └── variable-interpolation.spec.ts # <- Depends on the collection in ./variable-interpolation/fixtures/collection └── subproto.spec.ts
Files:
tests/import/insomnia/malformed-structure.spec.tstests/import/postman/invalid-schema.spec.tstests/import/postman/invalid-missing-info.spec.tstests/import/openapi/missing-info.spec.tstests/import/file-types/invalid-file-handling.spec.tstests/import/postman/invalid-json.spec.tstests/utils/page/actions.tstests/import/file-types/file-input-acceptance.spec.tstests/request/encoding/curl-encoding.spec.tstests/import/openapi/malformed-yaml.spec.tstests/preferences/support-links.spec.js
🧠 Learnings (3)
📚 Learning: 2025-12-17T21:41:24.730Z
Learnt from: naman-bruno
Repo: usebruno/bruno PR: 6407
File: packages/bruno-app/src/components/Environments/ConfirmCloseEnvironment/index.js:5-41
Timestamp: 2025-12-17T21:41:24.730Z
Learning: Do not suggest PropTypes validation for React components in the Bruno codebase. The project does not use PropTypes, so reviews should avoid proposing PropTypes and rely on the existing typing/validation approach (e.g., TypeScript or alternative runtime checks) if applicable. This guideline applies broadly to all JavaScript/JSX components in the repo.
Applied to files:
packages/bruno-app/src/components/Modal/index.jspackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.jstests/preferences/support-links.spec.js
📚 Learning: 2025-12-16T07:16:23.647Z
Learnt from: sanish-bruno
Repo: usebruno/bruno PR: 6090
File: tests/scripting/hooks/init-user-data/ui-state-snapshot.json:1-8
Timestamp: 2025-12-16T07:16:23.647Z
Learning: For e2e tests in the bruno repository: Collections that are shared between CLI and UI tests (comprehensive test suites testing core functionality) should be placed in `packages/bruno-tests/` to avoid duplication. The `tests/**/fixtures/collection` pattern should be used for test-specific collections that test particular UI behaviors or are specific to a single test file.
Applied to files:
tests/utils/page/actions.ts
📚 Learning: 2025-12-05T20:31:33.005Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-05T20:31:33.005Z
Learning: Applies to **/*.test.{js,jsx,ts,tsx} : Add tests for any new functionality or meaningful changes. If code is added, removed, or significantly modified, corresponding tests should be updated or created
Applied to files:
tests/import/file-types/file-input-acceptance.spec.ts
🧬 Code graph analysis (1)
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js (2)
packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/StyledWrapper.js (1)
StyledWrapper(3-22)packages/bruno-app/src/components/Modal/index.js (1)
Modal(60-169)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: Playwright E2E Tests
- GitHub Check: CLI Tests
- GitHub Check: Unit Tests
- GitHub Check: SSL Tests - Windows
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - macOS
🔇 Additional comments (13)
tests/import/openapi/missing-info.spec.ts (1)
22-22: LGTM - Modal selector standardization.The switch to
getByTestId('modal-close-button')aligns with the Modal component update and is more robust than CSS-based selectors.tests/import/postman/invalid-schema.spec.ts (1)
23-23: LGTM - Consistent selector update.Modal close interaction properly updated to use test-id based selector.
tests/import/file-types/invalid-file-handling.spec.ts (1)
25-25: LGTM - Modal selector updated correctly.Cleanup action properly uses the standardized test-id selector.
packages/bruno-app/src/components/Modal/index.js (1)
13-13: LGTM - Test attribute standardization.The change from
data-test-idtodata-testidaligns with Playwright's best practices and is consistent with the test selector updates across the codebase.tests/import/postman/invalid-json.spec.ts (1)
24-24: LGTM - Modal selector updated.Cleanup step correctly uses the standardized test-id selector.
tests/request/encoding/curl-encoding.spec.ts (3)
7-10: LGTM - Excellent defensive cleanup pattern.The afterEach block properly checks modal visibility before attempting to close it, preventing test failures when the modal isn't present. The selector update to
getByTestId('modal-close-button')is correct.
55-57: LGTM - Proper modal close verification.Closing the modal and explicitly waiting for the hidden state ensures test stability.
98-100: LGTM - Consistent modal close pattern.Modal interaction properly uses the standardized selector with state verification.
tests/utils/page/actions.ts (2)
291-293: Selector usage is consistent, pending UI verification.The same test-id based selector is correctly used here. Ensure the verification from lines 21-24 confirms the test-id exists in the UI.
21-24: Test-id is correctly implemented in the RemoveCollection component.The test-id
close-collection-modal-titleexists in the RemoveCollection component atpackages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.json the modal title element. The selectors in lines 21-24 are valid and properly usegetByTestId()for stable element location.packages/bruno-app/src/components/Sidebar/Collections/Collection/RemoveCollection/index.js (3)
5-5: LGTM! Appropriate icon for destructive action.The switch from
IconFilestoIconAlertCirclebetter conveys the warning nature of the remove collection action.
46-51: Well-structured custom header with proper test ID.The custom header implementation is clean:
- Alert icon with appropriate red color for destructive action
- Proper test-id for e2e testing
- Consistent flex layout
55-74: Excellent modal redesign with clear information hierarchy.The new structure improves UX:
- Compact
smsize appropriate for confirmationbtn-dangerclass correctly signals destructive action- Collection info card provides clear visual separation
- Footer note reassures users about filesystem persistence
The
StyledWrapperintegration andcustomHeaderprop usage align well with the broader modal style updates.
Description
Contribution Checklist:
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
Style & UI Updates
Theme
Tests
✏️ Tip: You can customize this high-level summary in your review settings.