Prototype/simplify request creation#6295
Conversation
- Create reusable CreateUntitledRequest component with customizable trigger - Add generateUniqueRequestName utility for unique request naming - Replace modal-based request creation with dropdown in tab bar - Support HTTP, GraphQL, WebSocket, and gRPC request types - Generate unique names (Untitled, Untitled1, etc.) automatically - Create requests at collection root level
- Change appendTo from 'parent' to document.body for absolute positioning - Add comprehensive styling via onShow handler to ensure proper width, padding, text color, and opacity - Add global styles as fallback for dropdown elements - Ensure dropdown overlaps parent without expanding it
Add helpful placeholder text 'Enter URL or paste a cURL request' to the HTTP request URL input field. This guides users on how to use the input field, indicating they can either enter a URL directly or paste a cURL command which will be automatically parsed.
WalkthroughAdds an inline CreateUntitledRequest dropdown to create HTTP/GraphQL/WebSocket/gRPC requests, curl-paste handlers in the URL editor to parse cURL into request fields, a generateUniqueRequestName utility (duplicated), and test helpers + tests updated to use the new untitled-request flow. (45 words) Changes
Sequence DiagramsequenceDiagram
actor User
participant Browser as Browser UI
participant Dropdown as CreateUntitledRequest (Dropdown)
participant Utils as generateUniqueRequestName
participant Redux as Redux Store / Actions
participant Toast as Toast Notification
User->>Browser: open tabs area, click dropdown
Browser->>Dropdown: onSelect(requestType)
Dropdown->>Utils: generateUniqueRequestName(collection, "Untitled")
Utils-->>Dropdown: uniqueName
Dropdown->>Redux: dispatch new<RequestType>Request({ name: uniqueName, filename, type-specific payload, collectionUid, itemUid })
Redux-->>Dropdown: success / error
alt success
Dropdown->>Toast: show success
Dropdown->>Browser: call onRequestCreated callback (if provided)
else failure
Dropdown->>Toast: show error message
end
Dropdown->>Browser: hide dropdown
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
📜 Recent review detailsConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ 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)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (7)
packages/bruno-app/src/utils/collections/index.js (2)
1644-1647: Remove unnecessaryasynckeyword.The function doesn't contain any
awaitexpressions, making theasyncdeclaration superfluous. This adds overhead by wrapping the return value in a Promise unnecessarily.-export const generateUniqueRequestName = async (collection, baseName = 'Untitled', itemUid = null) => { +export const generateUniqueRequestName = (collection, baseName = 'Untitled', itemUid = null) => { if (!collection) { return baseName; }
1649-1652: Moverequireto top-level import and escape regex special characters.Using
require()inside functions is non-idiomatic for ES modules and incurs repeated resolution overhead. Additionally, ifbaseNamecontains regex special characters (e.g., parentheses, dots), the pattern will fail.import {cloneDeep, isEqual, sortBy, filter, map, isString, findIndex, find, each, get } from 'lodash'; +import trim from 'lodash/trim'; // ... other importsThen update the function:
- const trim = require('lodash/trim'); const parentItem = itemUid ? findItemInCollection(collection, itemUid) : null; const parentItems = parentItem ? (parentItem.items || []) : (collection.items || []); - const baseNamePattern = new RegExp(`^${baseName}(\\d+)?$`); + const escapedBaseName = baseName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + const baseNamePattern = new RegExp(`^${escapedBaseName}(\\d+)?$`);packages/bruno-app/src/components/RequestPane/QueryUrl/index.js (3)
95-107: Inconsistent UX: error toast shown for non-cURL regular paste.When pasting a regular URL (not a cURL command) into a GraphQL request, this shows an error toast and then allows the paste to proceed. This could confuse users pasting normal URLs.
Consider silently allowing non-cURL pastes without the error:
const curlCommandRegex = /^\s*curl\s/i; if (!curlCommandRegex.test(pastedData)) { - toast.error('Invalid cURL command'); return; }
178-186: Fix inconsistent indentation.Lines 181-185 have extra indentation that doesn't match the surrounding code structure, making the control flow harder to follow.
const curlCommandRegex = /^\s*curl\s/i; if (!curlCommandRegex.test(pastedData)) { // Not a curl command, allow normal paste behavior - return; - } - - // Prevent the default paste behavior - event.preventDefault(); + return; + } + + // Prevent the default paste behavior + event.preventDefault();
283-291: TODOs for formUrlEncoded and multipartForm remain unimplemented.The cURL import silently ignores body content for these modes, which may confuse users expecting full import support.
Consider at minimum showing a toast warning when these body modes are detected but not fully imported. Would you like me to help implement proper param setting for these modes, or open an issue to track this?
packages/bruno-app/src/components/CreateUntitledRequest/index.js (2)
22-116: Unify async handling and reduce duplication across create handlersAll four
handleCreate*Requestfunctions follow the same pattern: hide dropdown, compute a unique name, dispatch an async action, then show a success/error toast and optionally callonRequestCreated. Right now they:
- Are marked
asyncbut use.then/.catchinstead ofawait- Duplicate the same success/error handling logic 4 times
Consider refactoring to a shared helper that takes the payload/action creator as input and uses
try/catchwithawaitfor consistency:-const handleCreateHttpRequest = async () => { - dropdownTippyRef.current?.hide(); - const uniqueName = await generateUniqueRequestName(collection, 'Untitled', itemUid); - const filename = sanitizeName(uniqueName); - - dispatch( - newHttpRequest({ - requestName: uniqueName, - filename: filename, - requestType: 'http-request', - requestUrl: '', - requestMethod: 'GET', - collectionUid: collection.uid, - itemUid: itemUid - }) - ) - .then(() => { - toast.success('New request created!'); - onRequestCreated?.(); - }) - .catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request')); -}; +const createRequest = async (actionPayloadBuilder) => { + dropdownTippyRef.current?.hide(); + const uniqueName = await generateUniqueRequestName(collection, 'Untitled', itemUid); + const filename = sanitizeName(uniqueName); + + try { + await dispatch(actionPayloadBuilder({ uniqueName, filename })); + toast.success('New request created!'); + onRequestCreated?.(); + } catch (err) { + toast.error(err ? err.message : 'An error occurred while adding the request'); + } +}; + +const handleCreateHttpRequest = () => + createRequest(({ uniqueName, filename }) => + newHttpRequest({ + requestName: uniqueName, + filename, + requestType: 'http-request', + requestUrl: '', + requestMethod: 'GET', + collectionUid: collection.uid, + itemUid + }) + );You can apply the same pattern to the GraphQL, WebSocket, and gRPC handlers to keep their differences (payload shape) focused and avoid repeating the toast logic.
10-171: Add a brief JSDoc for theCreateUntitledRequestabstractionGiven this component is now the central entry point for creating new requests of multiple types at the collection root, a short JSDoc on the component describing props (
collectionUid,itemUid,onRequestCreated,placement) and behavior would make its purpose clearer to future readers.Example:
/** * Renders a dropdown button that creates new untitled requests (HTTP, GraphQL, WebSocket, gRPC) * at the given collection (and optional parent item) using sane defaults. * * @param {Object} props * @param {string} props.collectionUid - Target collection UID. * @param {string|null} [props.itemUid=null] - Optional parent item UID within the collection. * @param {Function} [props.onRequestCreated] - Callback invoked after a request is successfully created. * @param {('top'|'bottom'|'left'|'right')} [props.placement='bottom'] - Dropdown placement. */ const CreateUntitledRequest = ({ collectionUid, itemUid = null, onRequestCreated, placement = 'bottom' }) => {This aligns with your guideline to document abstractions without adding noise.
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
packages/bruno-app/src/components/CreateUntitledRequest/StyledWrapper.js(1 hunks)packages/bruno-app/src/components/CreateUntitledRequest/index.js(1 hunks)packages/bruno-app/src/components/RequestPane/QueryUrl/index.js(3 hunks)packages/bruno-app/src/components/RequestTabs/index.js(2 hunks)packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js(1 hunks)packages/bruno-app/src/utils/collections/index.js(1 hunks)
🧰 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, never tabs
Use single quotes for strings instead of double quotes
Always add semicolons at the end of statements
No trailing commas in code
Always use parentheses around parameters in arrow functions, even for single parameters
For multiline constructs, put opening braces on the same line with a minimum of 2 elements for multiline formatting
No newlines inside function parentheses
Space before and after the arrow in arrow functions:() => {}
No space between function name and parentheses:func()notfunc ()
Semicolons should go at the end of the line, not on a new line
Function names should be concise and descriptive
Add JSDoc comments to provide details to abstractions
Avoid single-line abstractions where all that is being done is increasing the call stack with one additional function
Add meaningful comments to explain complex code flow instead of obvious comments
Files:
packages/bruno-app/src/components/CreateUntitledRequest/StyledWrapper.jspackages/bruno-app/src/components/RequestTabs/index.jspackages/bruno-app/src/components/RequestPane/QueryUrl/index.jspackages/bruno-app/src/utils/collections/index.jspackages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.jspackages/bruno-app/src/components/CreateUntitledRequest/index.js
🧠 Learnings (1)
📚 Learning: 2025-12-03T08:09:57.124Z
Learnt from: CR
Repo: usebruno/bruno PR: 0
File: CODING_STANDARDS.md:0-0
Timestamp: 2025-12-03T08:09:57.124Z
Learning: Applies to **/*.{jsx,tsx} : Styled Components should be used as wrappers to define both self and children component styles; Tailwind classes should be used specifically for layout-based styles
Applied to files:
packages/bruno-app/src/components/CreateUntitledRequest/StyledWrapper.js
🧬 Code graph analysis (3)
packages/bruno-app/src/components/RequestTabs/index.js (1)
packages/bruno-app/src/components/CreateUntitledRequest/index.js (1)
CreateUntitledRequest(10-171)
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js (2)
packages/bruno-app/src/utils/curl/curl-to-json.js (1)
request(126-126)packages/bruno-app/src/utils/curl/index.js (3)
request(37-37)getRequestFromCurlCommand(6-103)getRequestFromCurlCommand(6-103)
packages/bruno-app/src/utils/collections/index.js (2)
packages/bruno-cli/src/utils/collection.js (1)
findItemInCollection(252-256)packages/bruno-electron/src/utils/collection.js (1)
findItemInCollection(166-170)
🪛 Biome (2.1.2)
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js
[error] 151-151: variables is assigned to itself.
This is where is assigned.
Self assignments have no effect and can be removed.
(lint/correctness/noSelfAssign)
⏰ 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: CLI Tests
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - Windows
- GitHub Check: Playwright E2E Tests
- GitHub Check: SSL Tests - macOS
- GitHub Check: Unit Tests
🔇 Additional comments (6)
packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/index.js (1)
617-617: LGTM!Minor indentation adjustment. No functional impact.
packages/bruno-app/src/utils/collections/index.js (1)
1674-1682: LGTM!The suffix calculation logic correctly handles the edge cases: returns base name when no matches exist, and increments from the highest existing suffix otherwise.
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js (1)
401-406: LGTM!Clean integration of the paste handlers with appropriate conditional binding based on request type. The placeholder text clearly communicates the cURL paste capability.
packages/bruno-app/src/components/CreateUntitledRequest/StyledWrapper.js (1)
1-8: LGTM!Minimal styled wrapper appropriate for the dropdown positioning context. Follows project conventions for using styled-components as wrappers.
packages/bruno-app/src/components/RequestTabs/index.js (1)
144-153: LGTM!Clean integration of
CreateUntitledRequestin the tab bar. The conditional render onactiveCollectionprevents errors when no collection is active, anditemUid={null}correctly indicates root-level request creation.packages/bruno-app/src/components/CreateUntitledRequest/index.js (1)
10-21: Collection lookup and null guard look goodUsing
useSelectorto pullcollectionsand early‑returningnullwhen the target collection is missing is a reasonable defensive pattern for this component.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js (1)
166-166: Missingitem.typein dependency array.The callback checks
item.typeon line 96, but the dependency array only includesitem.uid. Additem.typeto avoid stale closures if the type changes.- }, [dispatch, item.uid, collection.uid]); + }, [dispatch, item.uid, item.type, collection.uid]);
🧹 Nitpick comments (2)
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js (2)
283-291: Empty conditional branches with TODO comments.These empty branches set the body mode but don't populate the params, which may confuse users when their form data doesn't appear. Consider logging a warning or showing a toast indicating partial import.
} else if (bodyMode === 'formUrlEncoded' && request.body.formUrlEncoded) { - // For formUrlEncoded, we need to set each param individually - // This is a limitation - we'd need to clear existing params first - // For now, we'll set the body mode and the user can manually adjust - // TODO: Implement proper formUrlEncoded param setting + // TODO: Implement proper formUrlEncoded param setting + console.warn('formUrlEncoded body detected but params not fully imported'); } else if (bodyMode === 'multipartForm' && request.body.multipartForm) { - // For multipartForm, similar limitation - // TODO: Implement proper multipartForm param setting + // TODO: Implement proper multipartForm param setting + console.warn('multipartForm body detected but params not fully imported'); }Would you like me to open an issue to track the implementation of formUrlEncoded and multipartForm param setting?
95-372: Significant code duplication between paste handlers.Both
handleGraphqlPasteandhandleHttpPasteshare nearly identical logic for URL updates, method updates, and header updates. Consider extracting shared logic into a helper function to reduce maintenance burden.const applyParsedRequest = (request) => { dispatch(requestUrlChanged({ itemUid: item.uid, collectionUid: collection.uid, url: request.url })); if (request.method) { dispatch(updateRequestMethod({ method: request.method.toUpperCase(), itemUid: item.uid, collectionUid: collection.uid })); } if (request.headers?.length > 0) { dispatch(setRequestHeaders({ collectionUid: collection.uid, itemUid: item.uid, headers: request.headers })); } };
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js(3 hunks)
🧰 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/RequestPane/QueryUrl/index.js
🧬 Code graph analysis (1)
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js (1)
packages/bruno-app/src/utils/curl/index.js (3)
request(37-37)getRequestFromCurlCommand(6-103)getRequestFromCurlCommand(6-103)
⏰ 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: CLI Tests
- GitHub Check: Playwright E2E Tests
- GitHub Check: Unit Tests
- GitHub Check: SSL Tests - Windows
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - macOS
🔇 Additional comments (2)
packages/bruno-app/src/components/RequestPane/QueryUrl/index.js (2)
1-16: LGTM!Imports are appropriately organized and all appear to be used by the new paste handling functionality.
401-406: LGTM!Placeholder text improves discoverability of the cURL paste feature. The conditional
onPastebinding correctly routes to the appropriate handler based on request type.
- Replace #create-new-tab selector with new dropdown flow using createUntitledRequest helper - Update generateUniqueRequestName to handle .bru, .yml, and .yaml file extensions - Add createUntitledRequest helper function with optional URL and tag parameters - Update all failing tests to use the new helper function - Fix selectors from .collection-item-name to .item-name where needed - All 13 previously failing tests now pass
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (5)
packages/bruno-app/src/utils/collections/index.js (1)
1633-1681: SimplifygenerateUniqueRequestNameand align implementation with docsThe logic looks correct for the current
Untitleduse case, but a few cleanups would make this helper more robust and consistent:
- The function is
asyncbut only does synchronous work; droppingasyncavoids returning aPromiseunnecessarily.- Inside this ES‑module style file, prefer a top‑level import for
trimoverrequire('lodash/trim')for consistency and bundler friendliness.- The JSDoc mentions checking the filesystem, but the current implementation only inspects
collection.items; either update the comment or add the filesystem behavior if still needed.- If you ever pass arbitrary
baseNamevalues, consider escaping regex metacharacters inbaseNamePatternto avoid surprising matches.A possible refactor:
-export const generateUniqueRequestName = async (collection, baseName = 'Untitled', itemUid = null) => { +export const generateUniqueRequestName = (collection, baseName = 'Untitled', itemUid = null) => { if (!collection) { return baseName; } - const trim = require('lodash/trim'); + // using lodash.trim via top-level import keeps this helper tree-shakable and consistent with other lodash usage const parentItem = itemUid ? findItemInCollection(collection, itemUid) : null; const parentItems = parentItem ? (parentItem.items || []) : (collection.items || []); - const baseNamePattern = new RegExp(`^${baseName}(\\d+)?$`); + const baseNamePattern = new RegExp(`^${baseName}(\\d+)?$`);And add a top‑level import alongside the other lodash utilities:
import trim from 'lodash/trim';tests/request/encoding/curl-encoding.spec.ts (1)
2-60: Nice use ofcreateUntitledRequest; consider extracting the Untitled locatorSwitching to
createUntitledRequestmakes these tests much closer to the real user flow and easier to maintain; the subsequent steps to open the generated request and assert code generation look solid.You might optionally extract the repeated locator for the Untitled request into a variable to improve readability and keep selectors consistent across both tests, e.g.:
const untitledRequest = page.locator('.item-name').filter({ hasText: /^Untitled/ }).first(); await untitledRequest.click();As per coding guidelines, extracting locator variables where reused keeps Playwright tests easier to read and maintain.
Also applies to: 62-105
tests/collection/create/create-collection.spec.ts (1)
27-34: Tighten URL textarea selector after usingcreateUntitledRequestThe switch to
createUntitledRequestlooks good here. One small robustness tweak: after clicking#request-url .CodeMirror, using a globalpage.locator('textarea')can become fragile if another textarea appears in the UI.You can scope the selector to the URL editor (matching what the helper does) and keep the flow the same:
- await page.locator('#request-url .CodeMirror').click(); - await page.locator('textarea').fill('http://localhost:8081'); + await page.locator('#request-url .CodeMirror').click(); + await page.locator('#request-url textarea').fill('http://localhost:8081');Optionally, you could also pass
urlintocreateUntitledRequestto avoid duplicating this step, but that’s not required for correctness.As per coding guidelines, tighter locators help keep Playwright tests stable over time.
tests/collection/moving-requests/tag-persistence.spec.ts (1)
2-69: Avoid the fixedwaitForTimeout(1000)before creating untitled requestsThe refactor to use
createUntitledRequestwithtag: 'smoke'and to work purely with the three Untitled requests in the sidebar is solid and reads much better than the manual flow.The one questionable bit is the explicit
await page.waitForTimeout(1000);after saving the collection, especially since eachcreateUntitledRequestalready waits for the new-request toast and the lateruntitledRequestslocator assertstoHaveCount(3). If there isn’t a known race here, you can likely drop or replace this with a more targeted wait (e.g., anexpecton whatever element indicates the collection is ready) to keep the test fast and less brittle:- await page.getByRole('button', { name: 'Save' }).click(); - await page.waitForTimeout(1000); + await page.getByRole('button', { name: 'Save' }).click(); + // Rely on subsequent `createUntitledRequest` + `toHaveCount(3)` to synchronize instead of a fixed timeoutAs per coding guidelines, we try to avoid
page.waitForTimeoutin Playwright tests unless there’s no reliable locator-based condition to wait on.tests/collection/moving-requests/cross-collection-drag-drop-request.spec.ts (1)
2-62: Stabilize URL and Untitled locators in cross-collection drag-and-drop testsThe move to
createUntitledRequestmakes both drag‑and‑drop tests much cleaner, and the assertions around presence/absence of Untitled requests in source/target collections look correct.Two small improvements for robustness/readability:
- As in the collection‑creation test, after clicking
#request-url .CodeMirror, scope the textarea to the URL editor to avoid accidentally hitting another textarea:- await page.locator('#request-url .CodeMirror').click(); - await page.locator('textarea').fill('https://echo.usebruno.com'); + await page.locator('#request-url .CodeMirror').click(); + await page.locator('#request-url textarea').fill('https://echo.usebruno.com');
- You reuse the
.item-name+/^Untitled/selector multiple times; consider assigning it to a localconst(or two, one per collection container) for clarity and to keep selectors consistent.As per coding guidelines, tighter locators and shared locator variables help keep Playwright tests less flaky.
Also applies to: 64-124
📜 Review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
packages/bruno-app/src/utils/collections/index.js(2 hunks)tests/collection/create/create-collection.spec.ts(2 hunks)tests/collection/moving-requests/cross-collection-drag-drop-request.spec.ts(7 hunks)tests/collection/moving-requests/tag-persistence.spec.ts(2 hunks)tests/request/encoding/curl-encoding.spec.ts(3 hunks)tests/response/large-response-crash-prevention.spec.ts(2 hunks)tests/utils/page/actions.ts(3 hunks)
🧰 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/response/large-response-crash-prevention.spec.tstests/collection/create/create-collection.spec.tstests/utils/page/actions.tspackages/bruno-app/src/utils/collections/index.jstests/request/encoding/curl-encoding.spec.tstests/collection/moving-requests/cross-collection-drag-drop-request.spec.tstests/collection/moving-requests/tag-persistence.spec.ts
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/response/large-response-crash-prevention.spec.tstests/collection/create/create-collection.spec.tstests/utils/page/actions.tstests/request/encoding/curl-encoding.spec.tstests/collection/moving-requests/cross-collection-drag-drop-request.spec.tstests/collection/moving-requests/tag-persistence.spec.ts
🧠 Learnings (1)
📚 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 **/*.{js,jsx,ts,tsx} : Use 2 spaces for indentation. No tabs, just spaces
Applied to files:
packages/bruno-app/src/utils/collections/index.js
🧬 Code graph analysis (2)
tests/response/large-response-crash-prevention.spec.ts (1)
tests/utils/page/actions.ts (1)
createUntitledRequest(586-586)
packages/bruno-app/src/utils/collections/index.js (1)
packages/bruno-cli/src/utils/collection.js (1)
findItemInCollection(336-340)
⏰ 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: CLI Tests
- GitHub Check: Unit Tests
- GitHub Check: Playwright E2E Tests
- GitHub Check: SSL Tests - Linux
- GitHub Check: SSL Tests - Windows
- GitHub Check: SSL Tests - macOS
🔇 Additional comments (2)
tests/response/large-response-crash-prevention.spec.ts (1)
2-39: LGTM on usingcreateUntitledRequestfor the large-response scenarioMoving the request-creation steps into
createUntitledRequestmakes this test much leaner and focused purely on the large-response behavior; the subsequent send and assertions are unchanged and still clear.tests/utils/page/actions.ts (1)
92-152: RefinecreateUntitledRequestto reduce timeouts and unused optionsThis helper is a nice abstraction over the new dropdown flow and the use of
test.stepmakes traces readable. A couple of tweaks would improve it further:
CreateUntitledRequestOptions.requestNameis currently unused; either wire it into a rename flow or drop it from the type to avoid confusion for callers.- Several
waitForTimeoutcalls are probably redundant given the precedingwaitFor/expectchecks and can be removed or replaced with locator-based waits to reduce flakiness and overall test time.For example, you can rely on the existing waits and assertions:
- // Wait for the request tab to be active - await page.locator('.request-tab.active').waitFor({ state: 'visible' }); - await page.waitForTimeout(300); + // Wait for the request tab to be active + await page.locator('.request-tab.active').waitFor({ state: 'visible' }); @@ - if (url) { - await page.locator('#request-url .CodeMirror').click(); - await page.locator('#request-url textarea').fill(url); - await page.locator('#send-request').getByTitle('Save Request').click(); - await page.waitForTimeout(200); - } + if (url) { + await page.locator('#request-url .CodeMirror').click(); + await page.locator('#request-url textarea').fill(url); + await page.locator('#send-request').getByTitle('Save Request').click(); + // rely on downstream assertions (and the toast) instead of a fixed delay + } @@ - if (tag) { - await page.getByRole('tab', { name: 'Settings' }).click(); - await page.waitForTimeout(200); - const tagInput = await page.getByTestId('tag-input').getByRole('textbox'); - await tagInput.fill(tag); - await tagInput.press('Enter'); - await page.waitForTimeout(200); - await expect(page.locator('.tag-item', { hasText: tag })).toBeVisible(); - await page.keyboard.press('Meta+s'); - await page.waitForTimeout(200); - } + if (tag) { + await page.getByRole('tab', { name: 'Settings' }).click(); + const tagInput = await page.getByTestId('tag-input').getByRole('textbox'); + await tagInput.fill(tag); + await tagInput.press('Enter'); + await expect(page.locator('.tag-item', { hasText: tag })).toBeVisible(); + await page.keyboard.press('Meta+s'); + }And if
requestNameisn’t going to be implemented immediately, simplifying the type keeps the API honest:-type CreateUntitledRequestOptions = { - requestType?: 'HTTP' | 'GraphQL' | 'WebSocket' | 'gRPC'; - requestName?: string; - url?: string; - tag?: string; -}; +type CreateUntitledRequestOptions = { + requestType?: 'HTTP' | 'GraphQL' | 'WebSocket' | 'gRPC'; + url?: string; + tag?: string; +};[ suggest_recommended_refactor ]
As per coding guidelines for tests, minimizingpage.waitForTimeoutand unused surface area makes the helper more reliable and easier to use.Also applies to: 586-603, 605-605
| import path from 'utils/common/path'; | ||
| import { isRequestTagsIncluded } from '@usebruno/common'; | ||
|
|
||
| import { writeFileSync } from 'node:fs'; |
There was a problem hiding this comment.
Invalid and unused import
Description
This PR addresses https://usebruno.atlassian.net/browse/BRU-2114.
This update enables users to create requests with a default name at the collection root level
Contribution Checklist:
Summary by CodeRabbit
New Features
Style
Tests
✏️ Tip: You can customize this high-level summary in your review settings.