diff --git a/packages/bruno-app/src/components/Sidebar/BulkImportCollectionLocation/index.js b/packages/bruno-app/src/components/Sidebar/BulkImportCollectionLocation/index.js index f4f051637..078811b8d 100644 --- a/packages/bruno-app/src/components/Sidebar/BulkImportCollectionLocation/index.js +++ b/packages/bruno-app/src/components/Sidebar/BulkImportCollectionLocation/index.js @@ -22,6 +22,7 @@ import StyledWrapper from './StyledWrapper'; import toast from 'react-hot-toast'; import { showImportIssuesToast } from 'components/Toast/ImportIssuesToast'; import get from 'lodash/get'; +import { DEFAULT_COLLECTION_FORMAT } from 'utils/common/constants'; const STATUS = { LOADING: 'loading', @@ -154,7 +155,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(DEFAULT_COLLECTION_FORMAT); const [renamedCollectionNames, setRenamedCollectionNames] = useState({}); const [renamedEnvironmentNames, setRenamedEnvironmentNames] = useState({}); const [importIssues, setImportIssues] = useState({}); @@ -585,6 +586,7 @@ export const BulkImportCollectionLocation = ({ Location setCollectionFormat(e.target.value)} diff --git a/packages/bruno-cli/src/utils/collection.js b/packages/bruno-cli/src/utils/collection.js index c9d5fbb1e..6bcf36124 100644 --- a/packages/bruno-cli/src/utils/collection.js +++ b/packages/bruno-cli/src/utils/collection.js @@ -3,7 +3,7 @@ const os = require('os'); const fs = require('fs'); const path = require('path'); const { sanitizeName } = require('./filesystem'); -const { parseRequest, parseCollection, parseFolder, stringifyCollection, stringifyFolder, stringifyEnvironment, stringifyRequest } = require('@usebruno/filestore'); +const { parseRequest, parseCollection, parseFolder, stringifyCollection, stringifyFolder, stringifyEnvironment, stringifyRequest, DEFAULT_COLLECTION_FORMAT } = require('@usebruno/filestore'); const constants = require('../constants'); const chalk = require('chalk'); @@ -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 = DEFAULT_COLLECTION_FORMAT } = options; // Create brunoConfig for yml format const brunoConfig = { version: '1', @@ -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 = DEFAULT_COLLECTION_FORMAT } = options; for (const item of items) { if (item.type === 'folder') { // Create folder diff --git a/tests/import/bulk-import/yml-as-default-file-format.spec.ts b/tests/import/bulk-import/yml-as-default-file-format.spec.ts new file mode 100644 index 000000000..48aacb85a --- /dev/null +++ b/tests/import/bulk-import/yml-as-default-file-format.spec.ts @@ -0,0 +1,57 @@ +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('Bulk import defaults to OpenCollection (YAML) and writes opencollection.yml collections', async ({ page, createTmpDir }) => { + const locators = buildCommonLocators(page); + const importDir = await createTmpDir('bulk-import-default-format'); + + await test.step('Open the bulk import modal and verify the File Format defaults to OpenCollection (YAML)', async () => { + await openBulkImportModal(page, filesToImport); + + 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)']); + }); + + await test.step('Set the location, Click Import, then 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'); + } + }); + }); +}); diff --git a/tests/utils/page/actions.ts b/tests/utils/page/actions.ts index d576795c3..bd98f6997 100644 --- a/tests/utils/page/actions.ts +++ b/tests/utils/page/actions.ts @@ -524,6 +524,26 @@ const importCollection = async ( }); }; +/** + * 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(); + 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 @@ -2220,6 +2240,7 @@ export { deleteRequest, deleteCollectionFromOverview, importCollection, + openBulkImportModal, removeCollection, createFolder, openEnvironmentSelector, diff --git a/tests/utils/page/locators.ts b/tests/utils/page/locators.ts index 485e4da4d..37d1bcc5f 100644 --- a/tests/utils/page/locators.ts +++ b/tests/utils/page/locators.ts @@ -240,6 +240,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('bulk-import-collection-format-selector'), + bulkLocationInput: () => page.getByTestId('bulk-import-collection-location-modal').getByTestId('bulk-import-collection-location-input'), + 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'),