From 4f31e9b073973deac9d3a53514ca6df89c42fba3 Mon Sep 17 00:00:00 2001 From: sharan-bruno Date: Wed, 1 Jul 2026 14:37:23 +0530 Subject: [PATCH] fix(import): Import fails for gRPC request without URL in exported collection (#8367) * fix(import): Import fails for gRPC request without URL in exported collection * changed the approach for import request with missing url * addressed review comment * added a fixture for http example request * added an assertion to check whether the request is being imported or not * added an assertion to check whether the request is being imported or not * refactored test scripts --- .../CollectionItem/ExampleItem/index.js | 1 + .../bruno-app/src/utils/importers/common.js | 6 ++ .../bruno-grpc-request-missing-url.json | 51 ++++++++++++ ...runo-http-example-request-missing-url.json | 83 +++++++++++++++++++ .../bruno-http-request-missing-url.json | 50 +++++++++++ .../import-bruno-request-missing-url.spec.ts | 40 +++++++++ tests/utils/page/locators.ts | 4 + 7 files changed, 235 insertions(+) create mode 100644 tests/import/bruno/fixtures/bruno-grpc-request-missing-url.json create mode 100644 tests/import/bruno/fixtures/bruno-http-example-request-missing-url.json create mode 100644 tests/import/bruno/fixtures/bruno-http-request-missing-url.json create mode 100644 tests/import/bruno/import-bruno-request-missing-url.spec.ts diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js index b1fea8b2d..1f020d32d 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/ExampleItem/index.js @@ -185,6 +185,7 @@ const ExampleItem = ({ example, item, collection }) => { return ( { collections = Array.isArray(collections) ? collections : [collections]; @@ -98,6 +99,7 @@ export const transformItemsInCollection = (collection) => { item.type = `${item.type}-request`; const isGrpcRequest = item.type === 'grpc-request'; const isWSRequest = item.type === 'ws-request'; + item.request.url = valueToString(item.request.url); if (item.request.query) { item.request.params = item.request.query.map((queryItem) => ({ @@ -137,6 +139,10 @@ export const transformItemsInCollection = (collection) => { const isGrpcExample = example.type === 'grpc-request'; const isWSExample = example.type === 'ws-request'; + if (example.request) { + example.request.url = valueToString(example.request.url); + } + if (example.request && example.request.query) { example.request.params = example.request.query.map((queryItem) => ({ ...queryItem, diff --git a/tests/import/bruno/fixtures/bruno-grpc-request-missing-url.json b/tests/import/bruno/fixtures/bruno-grpc-request-missing-url.json new file mode 100644 index 000000000..e8922e7d0 --- /dev/null +++ b/tests/import/bruno/fixtures/bruno-grpc-request-missing-url.json @@ -0,0 +1,51 @@ +{ + "name": "GRPC Collection", + "version": "1", + "items": [ + { + "type": "grpc", + "name": "grpc request without url", + "filename": "request-without-url.bru", + "seq": 2, + "settings": {}, + "tags": [], + "examples": [], + "request": { + "method": "", + "headers": [], + "body": { + "mode": "grpc", + "formUrlEncoded": [], + "multipartForm": [], + "file": [], + "grpc": [ + { + "name": "message 1", + "content": "{}" + } + ] + }, + "script": {}, + "vars": {}, + "assertions": [], + "tests": "", + "docs": "", + "auth": { + "mode": "none" + } + } + } + ], + "environments": [], + "brunoConfig": { + "version": "1", + "name": "GRPC Collection", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ], + "size": 0, + "filesCount": 0 + } +} \ No newline at end of file diff --git a/tests/import/bruno/fixtures/bruno-http-example-request-missing-url.json b/tests/import/bruno/fixtures/bruno-http-example-request-missing-url.json new file mode 100644 index 000000000..9e06229e5 --- /dev/null +++ b/tests/import/bruno/fixtures/bruno-http-example-request-missing-url.json @@ -0,0 +1,83 @@ +{ + "name": "HTTP Example Collection", + "version": "1", + "items": [ + { + "type": "http", + "name": "http example request without url", + "filename": "request-with-example.bru", + "seq": 1, + "settings": {}, + "tags": [], + "examples": [ + { + "uid": "ex0011223344556677889", + "itemUid": "it0011223344556677889", + "name": "Http request example response", + "description": "Example whose request has no url", + "type": "http", + "request": { + "method": "GET", + "headers": [], + "params": [], + "body": { + "mode": "none" + } + }, + "response": { + "status": 200, + "statusText": "OK", + "headers": [ + { + "uid": "hd0011223344556677889", + "name": "content-type", + "value": "application/json", + "enabled": true + } + ], + "body": { + "type": "json", + "content": "{\n \"message\": \"hello\"\n}" + } + } + } + ], + "request": { + "method": "GET", + "headers": [], + "url": "", + "params": [], + "body": { + "mode": "none", + "json": null, + "text": null, + "xml": null, + "sparql": null, + "formUrlEncoded": [], + "multipartForm": [], + "file": [] + }, + "script": {}, + "vars": {}, + "assertions": [], + "tests": "", + "docs": "", + "auth": { + "mode": "none" + } + } + } + ], + "environments": [], + "brunoConfig": { + "version": "1", + "name": "HTTP Example Collection", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ], + "size": 0, + "filesCount": 0 + } +} \ No newline at end of file diff --git a/tests/import/bruno/fixtures/bruno-http-request-missing-url.json b/tests/import/bruno/fixtures/bruno-http-request-missing-url.json new file mode 100644 index 000000000..3b5659ad5 --- /dev/null +++ b/tests/import/bruno/fixtures/bruno-http-request-missing-url.json @@ -0,0 +1,50 @@ +{ + "name": "HTTP Collection", + "version": "1", + "items": [ + { + "type": "http", + "name": "http request without url", + "filename": "request-without-url.bru", + "seq": 2, + "settings": {}, + "tags": [], + "examples": [], + "request": { + "method": "GET", + "headers": [], + "params": [], + "body": { + "mode": "none", + "json": null, + "text": null, + "xml": null, + "sparql": null, + "formUrlEncoded": [], + "multipartForm": [], + "file": [] + }, + "script": {}, + "vars": {}, + "assertions": [], + "tests": "", + "docs": "", + "auth": { + "mode": "none" + } + } + } + ], + "environments": [], + "brunoConfig": { + "version": "1", + "name": "HTTP Collection", + "type": "collection", + "ignore": [ + "node_modules", + ".git" + ], + "size": 0, + "filesCount": 0 + } +} \ No newline at end of file diff --git a/tests/import/bruno/import-bruno-request-missing-url.spec.ts b/tests/import/bruno/import-bruno-request-missing-url.spec.ts new file mode 100644 index 000000000..de72132d9 --- /dev/null +++ b/tests/import/bruno/import-bruno-request-missing-url.spec.ts @@ -0,0 +1,40 @@ +import { test, expect } from '../../../playwright'; +import * as path from 'path'; +import { importCollection, closeAllCollections, buildCommonLocators } from '../../utils/page'; + +test.describe('Import Bruno Collection - request with missing URL', () => { + test.afterAll(async ({ page }) => { + await closeAllCollections(page); + }); + + const cases = [ + { fixture: 'bruno-http-request-missing-url.json', collectionName: 'HTTP Collection', type: 'HTTP', requestName: 'http request without url' }, + { fixture: 'bruno-grpc-request-missing-url.json', collectionName: 'GRPC Collection', type: 'gRPC', requestName: 'grpc request without url' }, + { fixture: 'bruno-http-example-request-missing-url.json', collectionName: 'HTTP Example Collection', type: 'HTTP example', requestName: 'http example request without url', exampleName: 'Http request example response' } + ]; + + for (const { fixture, collectionName, type, requestName, exampleName } of cases) { + test(`imports a ${type} request without a URL`, async ({ page, createTmpDir }) => { + const brunoFile = path.resolve(__dirname, 'fixtures', fixture); + const location = await createTmpDir(collectionName); + + await test.step('Import the collection', async () => { + await importCollection(page, brunoFile, location, { + expectedCollectionName: collectionName + }); + }); + + await test.step(`Verify the collection, request${exampleName ? ' and example' : ''} appear in the sidebar`, async () => { + const locators = buildCommonLocators(page); + + await expect(locators.sidebar.collection(collectionName)).toBeVisible(); + await expect(locators.sidebar.itemRow(requestName)).toBeVisible(); + + if (exampleName) { + await locators.sidebar.requestExamplesToggle(requestName).click(); + await expect(locators.sidebar.example(exampleName)).toBeVisible(); + } + }); + }); + } +}); diff --git a/tests/utils/page/locators.ts b/tests/utils/page/locators.ts index 37d1bcc5f..803a44ce8 100644 --- a/tests/utils/page/locators.ts +++ b/tests/utils/page/locators.ts @@ -20,6 +20,10 @@ export const buildCommonLocators = (page: Page) => ({ }, closeAllCollectionsButton: () => page.getByTestId('collections-header-actions-menu-close-all'), collectionRow: (name: string) => page.getByTestId('sidebar-collection-row').filter({ hasText: name }), + itemRow: (name: string) => page.getByTestId('sidebar-collection-item-row').filter({ hasText: name }), + requestExamplesToggle: (requestName: string) => + page.getByTestId('sidebar-collection-item-row').filter({ hasText: requestName }).getByTestId('request-item-chevron'), + example: (name: string) => page.getByTestId('sidebar-response-example-item').filter({ hasText: name }), // The sidebar tree wraps each collection in `#collection-`; scope queries // to it to disambiguate items that share names across collections. collectionScope: (name: string) => page.locator(`#collection-${name.replace(/\s+/g, '-').toLowerCase()}`)