Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ export const BulkImportCollectionLocation = ({
const [applyToGlobal, setApplyToGlobal] = useState(true);
const [applyToCollection, setApplyToCollection] = useState(false);
const [groupingType, setGroupingType] = useState('tags');
const [collectionFormat, setCollectionFormat] = useState('bru');
const [collectionFormat, setCollectionFormat] = useState('yml');

@vijayh-bruno vijayh-bruno Jun 26, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

we have 'yml' set as a constant for default format- https://github.com/usebruno/bruno/blob/main/packages/bruno-filestore/src/constants.ts

use that instead of hardcoding. Do this everywhere

const [renamedCollectionNames, setRenamedCollectionNames] = useState({});
const [renamedEnvironmentNames, setRenamedEnvironmentNames] = useState({});
const [importIssues, setImportIssues] = useState({});
Expand Down Expand Up @@ -585,6 +585,7 @@ export const BulkImportCollectionLocation = ({
<Modal
size="md"
title="Bulk Import"
dataTestId="bulk-import-collection-location-modal"
confirmText={importStarted ? 'Close' : 'Import'}
confirmDisabled={Boolean(!selectedCollections?.length)}
handleConfirm={onSubmit}
Expand Down Expand Up @@ -878,6 +879,7 @@ export const BulkImportCollectionLocation = ({
<select
id="format"
name="format"
data-testid="collection-format-selector"
Comment thread
sharan-bruno marked this conversation as resolved.
Outdated
className="block textbox mt-2 w-full"
value={collectionFormat}
onChange={(e) => setCollectionFormat(e.target.value)}
Expand Down
4 changes: 2 additions & 2 deletions packages/bruno-cli/src/utils/collection.js
Original file line number Diff line number Diff line change
Expand Up @@ -539,7 +539,7 @@ const safeWriteFileSync = (filePath, content) => {
* @param {string} dirPath - The output directory path
*/
const createCollectionFromBrunoObject = async (collection, dirPath, options = {}) => {
const { format = 'bru' } = options;
const { format = 'yml' } = options;
// Create brunoConfig for yml format
const brunoConfig = {
version: '1',
Expand Down Expand Up @@ -595,7 +595,7 @@ const createCollectionFromBrunoObject = async (collection, dirPath, options = {}
* @param {"bru"|"yml"} options.format - Current directory path
*/
const processCollectionItems = async (items = [], currentPath, options = {}) => {
const { format = 'bru' } = options;
const { format = 'yml' } = options;
for (const item of items) {
if (item.type === 'folder') {
// Create folder
Expand Down
65 changes: 65 additions & 0 deletions tests/import/bulk-import/yml-as-default-file-format.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { test, expect } from '../../../playwright';
import * as path from 'path';
import * as fs from 'fs';
import { closeAllCollections, openBulkImportModal } from '../../utils/page';
import { buildCommonLocators } from '../../utils/page/locators';

test.describe('Bulk Import default file format', () => {
const testDataDir = path.join(__dirname, '../test-data');
const filesToImport = [
path.join(testDataDir, 'sample-postman.json'),
path.join(testDataDir, 'sample-insomnia.json')
];

test.afterEach(async ({ page }) => {
await closeAllCollections(page);
});

test('File Format selector defaults to OpenCollection (YAML)', async ({ page }) => {
await openBulkImportModal(page, filesToImport);
const locators = buildCommonLocators(page);

await test.step('File Format defaults to OpenCollection (YAML)', async () => {
const formatSelect = locators.import.bulkFormatSelect();
await expect(formatSelect).toBeVisible();
await expect(formatSelect).toHaveValue('yml');
await expect(formatSelect.locator('option')).toHaveText(['OpenCollection (YAML)', 'BRU Format (.bru)']);
});
});

test('importing with the default format writes opencollection.yml collections', async ({ page, createTmpDir }) => {
Comment thread
sharan-bruno marked this conversation as resolved.
Outdated
Comment thread
sharan-bruno marked this conversation as resolved.
Outdated
await openBulkImportModal(page, filesToImport);
const locators = buildCommonLocators(page);
const importDir = await createTmpDir('bulk-import-default-format');

await test.step('Check the File Format defaults to OpenCollection (YAML)', async () => {
await expect(locators.import.bulkFormatSelect()).toHaveValue('yml');
});

await test.step('Import with the default format and close the modal', async () => {
await locators.import.bulkLocationInput().fill(importDir);

await expect(locators.import.bulkSubmitButton()).toHaveText('Import');
await locators.import.bulkSubmitButton().click();

await expect(locators.import.bulkSubmitButton()).toHaveText('Close');
await locators.import.bulkSubmitButton().click();
await expect(locators.import.bulkModal()).toBeHidden();
});

await test.step('Verify each collection is written as opencollection.yml, not bruno.json', async () => {
const collectionDirs = fs
.readdirSync(importDir, { withFileTypes: true })
.filter((entry) => entry.isDirectory())
.map((entry) => path.join(importDir, entry.name));

expect(collectionDirs.length).toBeGreaterThan(0);

for (const dir of collectionDirs) {
const files = fs.readdirSync(dir);
expect(files).toContain('opencollection.yml');
expect(files).not.toContain('bruno.json');
}
});
});
});
21 changes: 21 additions & 0 deletions tests/utils/page/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
await firstCollection.hover();
await firstCollection.locator('.collection-actions .icon').click({ force: true });
await expect(removeMenuItem).toBeVisible({ timeout: 2000 });
}).toPass({ timeout: 15000 });

Check failure on line 58 in tests/utils/page/actions.ts

View workflow job for this annotation

GitHub Actions / Playwright E2E Tests (macOS)

[default] › tests/codeeditor-state/fold-persistence.spec.ts:111:7 › CodeEditor — fold state persists across tab switches › Body editor: folded {} block survives Body → Headers → Body

1) [default] › tests/codeeditor-state/fold-persistence.spec.ts:111:7 › CodeEditor — fold state persists across tab switches › Body editor: folded {} block survives Body → Headers → Body Error: Test timeout of 30000ms exceeded at tests/utils/page/actions.ts:58 56 | await firstCollection.locator('.collection-actions .icon').click({ force: true }); 57 | await expect(removeMenuItem).toBeVisible({ timeout: 2000 }); > 58 | }).toPass({ timeout: 15000 }); | ^ 59 | await removeMenuItem.click(); 60 | 61 | // Wait for modal to appear - could be either regular remove or drafts confirmation at /Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:58:10 at closeAllCollections (/Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:46:3) at /Users/runner/work/bruno/bruno/tests/codeeditor-state/fold-persistence.spec.ts:108:5
await removeMenuItem.click();

// Wait for modal to appear - could be either regular remove or drafts confirmation
Expand Down Expand Up @@ -354,7 +354,7 @@
} else {
await locators.sidebar.collection(parentName).hover();
const collectionAction = locators.actions.collectionActions(parentName);
await expect(collectionAction).toBeVisible({ timeout: 2000 });

Check failure on line 357 in tests/utils/page/actions.ts

View workflow job for this annotation

GitHub Actions / Playwright E2E Tests (Linux)

[default] › tests/snapshots/basic.spec.ts:140:7 › Snapshot: Tab Persistence › closed tab stays closed after restart

7) [default] › tests/snapshots/basic.spec.ts:140:7 › Snapshot: Tab Persistence › closed tab stays closed after restart › Create two requests, open both, close one › Create HTTP request "ReqClose" in collection "TestCol" Error: Timed out 2000ms waiting for expect(locator).toBeVisible() Locator: getByTestId('collections').locator('.collection-name').filter({ hasText: 'TestCol' }).locator('.collection-actions .icon') Expected: visible Received: hidden Call log: - expect.toBeVisible with timeout 2000ms - waiting for getByTestId('collections').locator('.collection-name').filter({ hasText: 'TestCol' }).locator('.collection-actions .icon') 6 × locator resolved to <svg width="18" height="18" fill="none" stroke-width="2" viewBox="0 0 24 24" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-dots">…</svg> - unexpected value "hidden" at tests/utils/page/actions.ts:357 355 | await locators.sidebar.collection(parentName).hover(); 356 | const collectionAction = locators.actions.collectionActions(parentName); > 357 | await expect(collectionAction).toBeVisible({ timeout: 2000 }); | ^ 358 | await collectionAction.click(); 359 | } 360 | at /home/runner/work/bruno/bruno/tests/utils/page/actions.ts:357:38 at createRequest (/home/runner/work/bruno/bruno/tests/utils/page/actions.ts:348:3) at /home/runner/work/bruno/bruno/tests/snapshots/basic.spec.ts:150:7 at /home/runner/work/bruno/bruno/tests/snapshots/basic.spec.ts:147:5
await collectionAction.click();
}

Expand Down Expand Up @@ -481,7 +481,7 @@
await test.step(`Import collection from "${filePath}"`, async () => {
const locators = buildCommonLocators(page);

await page.getByTestId('collections-header-add-menu').click();

Check failure on line 484 in tests/utils/page/actions.ts

View workflow job for this annotation

GitHub Actions / Playwright E2E Tests (macOS)

[default] › tests/import/postman/import-many-issues-collection.spec.ts:12:7 › Import Postman Collection with many issues (URL too long warning) › should show URL-too-long warning when include failed request data is checked

6) [default] › tests/import/postman/import-many-issues-collection.spec.ts:12:7 › Import Postman Collection with many issues (URL too long warning) › should show URL-too-long warning when include failed request data is checked › Import collection from "/Users/runner/work/bruno/bruno/tests/import/postman/fixtures/postman-with-many-import-issues.json" Error: locator.click: Target page, context or browser has been closed Call log: - waiting for getByTestId('collections-header-add-menu') - locator resolved to <button tabindex="-1" aria-expanded="false" data-tabindex="inline" title="Add new collection" data-testid="collections-header-add-menu" class="StyledWrapper-aItkQ hdzeDa action-icon">…</button> - attempting click action 2 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper__Wrapper-jjqtyM DwvBf">…</div> subtree intercepts pointer events - retrying click action - waiting 20ms 2 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper__Wrapper-jjqtyM DwvBf">…</div> subtree intercepts pointer events - retrying click action - waiting 100ms 49 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper__Wrapper-jjqtyM DwvBf">…</div> subtree intercepts pointer events - retrying click action - waiting 500ms at tests/utils/page/actions.ts:484 482 | const locators = buildCommonLocators(page); 483 | > 484 | await page.getByTestId('collections-header-add-menu').click(); | ^ 485 | await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click(); 486 | 487 | // Wait for import modal at /Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:484:59 at importCollection (/Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:481:14) at /Users/runner/work/bruno/bruno/tests/import/postman/import-many-issues-collection.spec.ts:17:27
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();

// Wait for import modal
Expand Down Expand Up @@ -524,6 +524,26 @@
});
};

/**
* Open the Bulk Import modal by importing multiple files at once.
* Selecting more than one file routes the import flow to the Bulk Import modal
* (instead of the single-collection location modal).
* @param page - The page object
* @param filePaths - Absolute paths of the files to import (must be 2 or more)
*/
const openBulkImportModal = async (page: Page, filePaths: string[]) => {
await test.step('Open the Bulk Import modal', async () => {
const locators = buildCommonLocators(page);

await locators.plusMenu.button().click();

Check failure on line 538 in tests/utils/page/actions.ts

View workflow job for this annotation

GitHub Actions / Detect Flaky Tests

[default] › tests/import/bulk-import/yml-as-default-file-format.spec.ts:30:7 › Bulk Import default file format › importing with the default format writes opencollection.yml collections

1) [default] › tests/import/bulk-import/yml-as-default-file-format.spec.ts:30:7 › Bulk Import default file format › importing with the default format writes opencollection.yml collections › Open the Bulk Import modal Error: locator.click: Target page, context or browser has been closed Call log: - waiting for getByTestId('collections-header-add-menu') - locator resolved to <button tabindex="-1" aria-expanded="false" data-tabindex="inline" title="Add new collection" data-testid="collections-header-add-menu" class="StyledWrapper-aItkQ hdzeDa action-icon">…</button> - attempting click action 2 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper-fBcznH cNWuqT">…</div> subtree intercepts pointer events - retrying click action - waiting 20ms 2 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper-fBcznH cNWuqT">…</div> subtree intercepts pointer events - retrying click action - waiting 100ms 57 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper-fBcznH cNWuqT">…</div> subtree intercepts pointer events - retrying click action - waiting 500ms at tests/utils/page/actions.ts:538 536 | const locators = buildCommonLocators(page); 537 | > 538 | await locators.plusMenu.button().click(); | ^ 539 | await locators.plusMenu.importCollection().click(); 540 | await expect(locators.import.modal()).toBeVisible(); 541 | at /home/runner/work/bruno/bruno/tests/utils/page/actions.ts:538:38 at openBulkImportModal (/home/runner/work/bruno/bruno/tests/utils/page/actions.ts:535:14) at /home/runner/work/bruno/bruno/tests/import/bulk-import/yml-as-default-file-format.spec.ts:31:30

Check failure on line 538 in tests/utils/page/actions.ts

View workflow job for this annotation

GitHub Actions / Playwright E2E Tests (macOS)

[default] › tests/import/bulk-import/yml-as-default-file-format.spec.ts:30:7 › Bulk Import default file format › importing with the default format writes opencollection.yml collections

5) [default] › tests/import/bulk-import/yml-as-default-file-format.spec.ts:30:7 › Bulk Import default file format › importing with the default format writes opencollection.yml collections › Open the Bulk Import modal TimeoutError: locator.click: Timeout 30000ms exceeded. Call log: - waiting for getByTestId('collections-header-add-menu') - locator resolved to <button tabindex="-1" aria-expanded="false" data-tabindex="inline" title="Add new collection" data-testid="collections-header-add-menu" class="StyledWrapper-aItkQ hdzeDa action-icon">…</button> - attempting click action 2 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper-fBcznH cNWuqT">…</div> subtree intercepts pointer events - retrying click action - waiting 20ms 2 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper-fBcznH cNWuqT">…</div> subtree intercepts pointer events - retrying click action - waiting 100ms 49 × waiting for element to be visible, enabled and stable - element is visible, enabled and stable - scrolling into view if needed - done scrolling - <div class="bruno-modal-backdrop"></div> from <div class="StyledWrapper-fBcznH cNWuqT">…</div> subtree intercepts pointer events - retrying click action - waiting 500ms at tests/utils/page/actions.ts:538 536 | const locators = buildCommonLocators(page); 537 | > 538 | await locators.plusMenu.button().click(); | ^ 539 | await locators.plusMenu.importCollection().click(); 540 | await expect(locators.import.modal()).toBeVisible(); 541 | at /Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:538:38 at openBulkImportModal (/Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:535:14) at /Users/runner/work/bruno/bruno/tests/import/bulk-import/yml-as-default-file-format.spec.ts:31:30
await locators.plusMenu.importCollection().click();
await expect(locators.import.modal()).toBeVisible();

await locators.import.fileInput().setInputFiles(filePaths);
await expect(locators.import.bulkModal()).toBeVisible();
});
};

/**
* Remove a specific collection from the sidebar
* @param page - The page object
Expand Down Expand Up @@ -693,7 +713,7 @@
) => {
await test.step(`Add environment variable "${variable.name}"`, async () => {
const nameInput = page.locator(`input[name="${index}.name"]`);
await nameInput.waitFor({ state: 'visible' });

Check failure on line 716 in tests/utils/page/actions.ts

View workflow job for this annotation

GitHub Actions / Playwright E2E Tests (macOS)

[default] › tests/environments/create-environment/collection-env-create.spec.ts:15:7 › Collection Environment Create Tests › should import collection and create environment for request usage

2) [default] › tests/environments/create-environment/collection-env-create.spec.ts:15:7 › Collection Environment Create Tests › should import collection and create environment for request usage › Create environment with variables › Add 5 environment variables › Add environment variable "postBody" Error: locator.waitFor: Target page, context or browser has been closed Call log: - waiting for locator('input[name="3.name"]') to be visible at tests/utils/page/actions.ts:716 714 | await test.step(`Add environment variable "${variable.name}"`, async () => { 715 | const nameInput = page.locator(`input[name="${index}.name"]`); > 716 | await nameInput.waitFor({ state: 'visible' }); | ^ 717 | await nameInput.fill(variable.name); 718 | 719 | // Wait for the CodeMirror editor in the row to be ready at /Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:716:21 at addEnvironmentVariable (/Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:714:14) at /Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:743:13 at addEnvironmentVariables (/Users/runner/work/bruno/bruno/tests/utils/page/actions.ts:741:3) at /Users/runner/work/bruno/bruno/tests/environments/create-environment/collection-env-create.spec.ts:31:7 at /Users/runner/work/bruno/bruno/tests/environments/create-environment/collection-env-create.spec.ts:28:5
await nameInput.fill(variable.name);

// Wait for the CodeMirror editor in the row to be ready
Expand Down Expand Up @@ -2099,6 +2119,7 @@
deleteRequest,
deleteCollectionFromOverview,
importCollection,
openBulkImportModal,
removeCollection,
createFolder,
openEnvironmentSelector,
Expand Down
4 changes: 4 additions & 0 deletions tests/utils/page/locators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,10 @@ export const buildCommonLocators = (page: Page) => ({
locationModal: () => page.locator('[data-testid="import-collection-location-modal"]'),
locationInput: () => page.locator('#collection-location'),
fileInput: () => page.locator('input[type="file"]'),
bulkModal: () => page.getByTestId('bulk-import-collection-location-modal'),
bulkFormatSelect: () => page.getByTestId('bulk-import-collection-location-modal').getByTestId('collection-format-selector'),
bulkLocationInput: () => page.getByTestId('bulk-import-collection-location-modal').locator('#collection-location'),
Comment thread
sharan-bruno marked this conversation as resolved.
Outdated
bulkSubmitButton: () => page.getByTestId('bulk-import-collection-location-modal-submit-btn'),
envOption: (name: string) => page.locator('.dropdown-item').getByText(name, { exact: true }),
parsingError: () => page.getByTestId('import-error-message'),
browseLink: (root?: Locator) => (root ?? page).getByTestId('import-collection-browse-link'),
Expand Down
Loading