fix: tests

This commit is contained in:
naman-bruno
2025-12-03 00:06:40 +05:30
parent c8d13f16c3
commit 08c183b4ec
60 changed files with 369 additions and 382 deletions

View File

@@ -288,6 +288,7 @@ const Collection = ({ collection, searchText }) => {
className="dropdown-item"
onClick={(_e) => {
menuDropdownTippyRef.current.hide();
ensureCollectionIsMounted();
setShowNewRequestModal(true);
}}
>
@@ -300,6 +301,7 @@ const Collection = ({ collection, searchText }) => {
className="dropdown-item"
onClick={(_e) => {
menuDropdownTippyRef.current.hide();
ensureCollectionIsMounted();
setShowNewFolderModal(true);
}}
>

View File

@@ -43,7 +43,7 @@ const Collections = ({ showSearch }) => {
}
return (
<StyledWrapper>
<StyledWrapper data-testid="collections">
{createCollectionModalOpen ? (
<CreateCollection
onClose={() => setCreateCollectionModalOpen(false)}

View File

@@ -43,7 +43,7 @@ const CreateCollection = ({ onClose, workspaceUid, defaultLocation: propDefaultL
initialValues: {
collectionName: '',
collectionFolderName: '',
collectionLocation: isDefaultWorkspace ? '' : (defaultLocation || ''),
collectionLocation: defaultLocation || '',
format: 'yml'
},
validationSchema: Yup.object({

View File

@@ -29,11 +29,10 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
return sortWorkspaces(workspaces, preferences);
}, [workspaces, preferences]);
const [importedCollection, setImportedCollection] = useState(null);
const [importData, setImportData] = useState(null);
const [createCollectionModalOpen, setCreateCollectionModalOpen] = useState(false);
const [importCollectionModalOpen, setImportCollectionModalOpen] = useState(false);
const [importCollectionLocationModalOpen, setImportCollectionLocationModalOpen] = useState(false);
const [importType, setImportType] = useState(null);
const [createWorkspaceModalOpen, setCreateWorkspaceModalOpen] = useState(false);
const toTitleCase = (str) => {
@@ -45,43 +44,31 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
.join(' ');
};
const handleImportCollection = ({ rawData, type, environment }) => {
setImportedCollection(rawData);
setImportType(type);
const handleImportCollection = ({ rawData, type }) => {
setImportCollectionModalOpen(false);
if (activeWorkspace) {
if (activeWorkspace && activeWorkspace.type !== 'default') {
dispatch(importCollectionInWorkspace(rawData, activeWorkspace.uid, undefined, type))
.catch((err) => {
toast.error('An error occurred while importing the collection');
});
} else {
setImportData({ rawData, type });
setImportCollectionLocationModalOpen(true);
}
};
const handleImportCollectionLocation = (collectionLocation, selectedCollections) => {
const isMultipleImport = importType && (importType === 'multiple' || importType === 'bulk');
const collectionsToImport = !isMultipleImport ? importedCollection : importedCollection.filter((collection) =>
selectedCollections.includes(collection.uid));
const collectionsArray = Array.isArray(collectionsToImport) ? collectionsToImport : [collectionsToImport];
if (collectionsArray.length === 0 || (collectionsArray.length === 1 && !collectionsArray[0])) {
toast.error('Please select at least one collection to import.');
return;
}
setImportCollectionLocationModalOpen(false);
if (activeWorkspace) {
dispatch(importCollectionInWorkspace(collectionsToImport, activeWorkspace.uid, collectionLocation))
.catch((err) => {
console.error(err);
toast.error('An error occurred while importing the collection');
});
} else {
dispatch(importCollection(collectionsToImport, collectionLocation));
}
const handleImportCollectionLocation = (convertedCollection, collectionLocation) => {
dispatch(importCollection(convertedCollection, collectionLocation))
.then(() => {
setImportCollectionLocationModalOpen(false);
setImportData(null);
toast.success('Collection imported successfully');
})
.catch((err) => {
console.error(err);
toast.error('An error occurred while importing the collection');
});
};
const [showWorkspaceDropdown, setShowWorkspaceDropdown] = useState(false);
@@ -155,8 +142,8 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
<CreateCollection
onClose={() => setCreateCollectionModalOpen(false)}
workspaceUid={activeWorkspace?.uid}
defaultLocation={activeWorkspace?.pathname ? `${activeWorkspace.pathname}/collections` : ''}
hideLocationInput={!!activeWorkspace?.pathname}
defaultLocation={activeWorkspace?.type !== 'default' && activeWorkspace?.pathname ? `${activeWorkspace.pathname}/collections` : undefined}
hideLocationInput={activeWorkspace?.type !== 'default' && !!activeWorkspace?.pathname}
/>
)}
{importCollectionModalOpen && (
@@ -165,9 +152,10 @@ const TitleBar = ({ showSearch, setShowSearch }) => {
handleSubmit={handleImportCollection}
/>
)}
{importCollectionLocationModalOpen && (
{importCollectionLocationModalOpen && importData && (
<ImportCollectionLocation
collectionName={Array.isArray(importedCollection) ? importedCollection?.[0]?.name : importedCollection?.name}
rawData={importData.rawData}
format={importData.type}
onClose={() => setImportCollectionLocationModalOpen(false)}
handleSubmit={handleImportCollectionLocation}
/>

View File

@@ -27,15 +27,15 @@ const transformCollection = async (collection, type) => {
return postmanToBruno(collection);
}
case 'insomnia': {
const { insomniaToBruno } = await import('utils/importers/insomnia-collection');
return insomniaToBruno(collection);
const { convertInsomniaToBruno } = await import('utils/importers/insomnia-collection');
return convertInsomniaToBruno(collection);
}
case 'openapi': {
const { openapiToBruno } = await import('utils/importers/openapi-collection');
return openapiToBruno(collection);
const { convertOpenapiToBruno } = await import('utils/importers/openapi-collection');
return convertOpenapiToBruno(collection);
}
case 'wsdl': {
const { wsdlToBruno } = await import('utils/importers/wsdl-collection');
const { wsdlToBruno } = await import('@usebruno/converters');
return wsdlToBruno(collection);
}
default:

View File

@@ -1,5 +1,6 @@
const fs = require('fs');
const path = require('path');
const fsExtra = require('fs-extra');
const { ipcMain, dialog } = require('electron');
const { createDirectory, sanitizeName } = require('../utils/filesystem');
const { generateUidBasedOnHash } = require('../utils/common');
@@ -114,6 +115,8 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
validateWorkspacePath(workspacePath);
const workspaceConfig = readWorkspaceConfig(workspacePath);
validateWorkspaceConfig(workspaceConfig);
const workspaceUid = generateUidBasedOnHash(workspacePath);
lastOpenedWorkspaces.add(workspacePath, workspaceConfig);
@@ -350,7 +353,6 @@ const registerWorkspaceIpc = (mainWindow, workspaceWatcher) => {
// Delete collection files if it's a workspace collection
if (result.shouldDeleteFiles && result.removedCollection && fs.existsSync(collectionPath)) {
const fsExtra = require('fs-extra');
await fsExtra.remove(collectionPath);
}

View File

@@ -72,6 +72,7 @@ class DefaultWorkspaceManager {
const workspaceYmlPath = path.join(newWorkspacePath, 'workspace.yml');
if (!fs.existsSync(workspaceYmlPath)) {
this.defaultWorkspacePath = null;
return null;
} else {
return {
workspacePath: newWorkspacePath,

View File

@@ -1,5 +1,5 @@
import { test, expect } from '../../../playwright';
import { closeAllCollections } from '../../utils/page';
import { closeAllCollections, openCollectionAndAcceptSandbox } from '../../utils/page';
import { buildCommonLocators } from '../../utils/page/locators';
test.describe('Create GraphQL Requests', () => {
@@ -7,6 +7,7 @@ test.describe('Create GraphQL Requests', () => {
test.beforeAll(async ({ pageWithUserData: page }) => {
locators = buildCommonLocators(page);
await openCollectionAndAcceptSandbox(page, 'create-requests', 'safe');
});
test.afterAll(async ({ pageWithUserData: page }) => {

View File

@@ -1,12 +1,13 @@
import { test, expect } from '../../../playwright';
import { buildCommonLocators } from '../../utils/page/locators';
import { closeAllCollections } from '../../utils/page';
import { closeAllCollections, openCollectionAndAcceptSandbox } from '../../utils/page';
test.describe('Create gRPC Requests', () => {
let locators: ReturnType<typeof buildCommonLocators>;
test.beforeAll(async ({ pageWithUserData: page }) => {
locators = buildCommonLocators(page);
await openCollectionAndAcceptSandbox(page, 'create-requests', 'safe');
});
test.afterAll(async ({ pageWithUserData: page }) => {

View File

@@ -1,12 +1,13 @@
import { test, expect } from '../../../playwright';
import { buildCommonLocators } from '../../utils/page/locators';
import { closeAllCollections } from '../../utils/page';
import { closeAllCollections, openCollectionAndAcceptSandbox } from '../../utils/page';
test.describe('Create HTTP Requests', () => {
let locators: ReturnType<typeof buildCommonLocators>;
test.beforeAll(async ({ pageWithUserData: page }) => {
locators = buildCommonLocators(page);
await openCollectionAndAcceptSandbox(page, 'create-requests', 'safe');
});
test.afterAll(async ({ pageWithUserData: page }) => {

View File

@@ -1,12 +1,13 @@
import { test, expect } from '../../../playwright';
import { buildCommonLocators } from '../../utils/page/locators';
import { closeAllCollections } from '../../utils/page';
import { closeAllCollections, openCollectionAndAcceptSandbox } from '../../utils/page';
test.describe('Create WebSocket Requests', () => {
let locators: ReturnType<typeof buildCommonLocators>;
test.beforeAll(async ({ pageWithUserData: page }) => {
locators = buildCommonLocators(page);
await openCollectionAndAcceptSandbox(page, 'create-requests', 'safe');
});
test.afterAll(async ({ pageWithUserData: page }) => {

View File

@@ -8,14 +8,17 @@ test.describe('Create collection', () => {
});
test('Create collection and add a simple HTTP request', async ({ page, createTmpDir }) => {
// Create a new collection
await page.getByLabel('Create Collection').click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').click();
await page.getByLabel('Name').fill('test-collection');
await page.getByLabel('Name').press('Tab');
await page.getByLabel('Location').fill(await createTmpDir('test-collection'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.getByText('test-collection').click();
const locationInput = page.locator('.bruno-modal').getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('test-collection'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await page.locator('#sidebar-collection-name').filter({ hasText: 'test-collection' }).click();
// Select safe mode
await page.getByLabel('Safe Mode').check();

View File

@@ -8,12 +8,16 @@ test.describe('Tag persistence', () => {
});
test('Verify tag persistence while moving requests within a collection', async ({ page, createTmpDir }) => {
// Create first collection - click dropdown menu first
await page.getByLabel('Create Collection').click();
// Create first collection - click plus icon button to open dropdown
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('test-collection');
await page.getByLabel('Location').fill(await createTmpDir('test-collection'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.getByText('test-collection').click();
const locationInput = page.locator('.bruno-modal').getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('test-collection'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await page.locator('#sidebar-collection-name').filter({ hasText: 'test-collection' }).click();
await page.getByLabel('Safe Mode').check();
await page.getByRole('button', { name: 'Save' }).click();
@@ -74,12 +78,16 @@ test.describe('Tag persistence', () => {
});
test('verify tag persistence while moving requests between folders', async ({ page, createTmpDir }) => {
// Create first collection - click dropdown menu first
await page.getByLabel('Create Collection').click();
// Create first collection - click plus icon button to open dropdown
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('test-collection');
await page.getByLabel('Location').fill(await createTmpDir('test-collection'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.getByText('test-collection').click();
const locationInput = page.locator('.bruno-modal').getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('test-collection'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await page.locator('#sidebar-collection-name').filter({ hasText: 'test-collection' }).click();
await page.getByLabel('Safe Mode').check();
await page.getByRole('button', { name: 'Save' }).click();

View File

@@ -9,11 +9,14 @@ test.describe('Move tabs', () => {
test('Verify tab move by drag and drop', async ({ page, createTmpDir }) => {
// Create a collection
await page.locator('.dropdown-icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Create Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('source-collection-drag-drop');
await page.getByLabel('Location').fill(await createTmpDir('source-collection-drag-drop'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
const locationInput = page.locator('.bruno-modal').getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('source-collection-drag-drop'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
// Wait for collection to appear and click on it
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'source-collection-drag-drop' })).toBeVisible();
@@ -97,11 +100,14 @@ test.describe('Move tabs', () => {
test('Verify tab move by keyboard shortcut', async ({ page, createTmpDir }) => {
// Create a collection
await page.locator('.dropdown-icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Create Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('source-collection-keyboard-shortcut');
await page.getByLabel('Location').fill(await createTmpDir('source-collection-keyboard-shortcut'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
const locationInput2 = page.locator('.bruno-modal').getByLabel('Location');
if (await locationInput2.isVisible()) {
await locationInput2.fill(await createTmpDir('source-collection-keyboard-shortcut'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
// Wait for collection to appear and click on it
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'source-collection-keyboard-shortcut' })).toBeVisible();

View File

@@ -1,7 +1,6 @@
import { test, expect } from '../../../playwright';
import * as path from 'path';
import * as fs from 'fs';
import { closeAllCollections } from '../../utils/page';
test.describe('Open Multiple Collections', () => {
@@ -57,8 +56,9 @@ test.describe('Open Multiple Collections', () => {
await expect(page.locator('#sidebar-collection-name').getByText('Test Collection 1')).not.toBeVisible();
// Click on Open Collection button
await page.locator('button').filter({ hasText: 'Open Collection' }).click();
// Click on plus icon button and then "Open collection" in the dropdown
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Open collection' }).click();
// Wait for both collections to appear in the sidebar
const collection1Element = page.locator('#sidebar-collection-name').getByText('Test Collection 1');
@@ -80,6 +80,9 @@ test.describe('Open Multiple Collections', () => {
const collection1Dir = await createTmpDir('collection-1');
const collection2Dir = 'invalid-collection-path';
// Count collections before attempting to open invalid ones
const collectionCountBefore = await page.locator('#sidebar-collection-name').count();
// Mock the electron dialog to return multiple folder selections
await electronApp.evaluate(({ dialog }, { collection1Dir, collection2Dir }) => {
dialog.showOpenDialog = async () => ({
@@ -89,20 +92,17 @@ test.describe('Open Multiple Collections', () => {
},
{ collection1Dir, collection2Dir });
await expect(page.locator('#sidebar-collection-name').getByText('Test Collection 1')).not.toBeVisible();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Open collection' }).click();
// Click on Open Collection button
await page.getByRole('button', { name: 'Open Collection' }).click();
// Wait for error toasts to appear
await page.waitForTimeout(1000);
// Verify no collections were opened
await expect(page.locator('#sidebar-collection-name')).toHaveCount(0);
await expect(page.locator('#sidebar-collection-name')).toHaveCount(collectionCountBefore);
// Verify invalid collection error
const invalidCollectionError = page.getByText('The collection is not valid').first();
await expect(invalidCollectionError).toBeVisible();
// Verify invalid path error
const invalidPathError = page.getByText('Some selected folders could not be opened').getByText('invalid-collection-path').first();
await expect(invalidPathError).toBeVisible();
});
});

View File

@@ -9,7 +9,8 @@ test.describe('Collection Environment Create Tests', () => {
const openApiFile = path.join(__dirname, 'fixtures', 'bruno-collection.json');
// Import test collection
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
const importModal = page.locator('[data-testid="import-collection-modal"]');
await importModal.waitFor({ state: 'visible' });
@@ -21,7 +22,7 @@ test.describe('Collection Environment Create Tests', () => {
await expect(locationModal.getByText('test_collection')).toBeVisible();
await page.locator('#collection-location').fill(await createTmpDir('env-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'test_collection' })).toBeVisible();
@@ -113,18 +114,13 @@ test.describe('Collection Environment Create Tests', () => {
await expect(responsePane).toContainText('"body": "This is a test post body with environment variables"');
await expect(responsePane).toContainText('"apiToken": "super-secret-token-12345"');
// Cleanup
await page
.locator('.collection-name')
.filter({ has: page.locator('#sidebar-collection-name:has-text("test_collection")') })
.locator('.collection-actions')
.click();
await page.locator('.dropdown-item').filter({ hasText: 'Close' }).click();
// Scope the Close button to the confirmation modal to avoid matching the dropdown close button
// Wait for the confirmation modal with "Close Collection" title to appear
const closeModal = page.getByRole('dialog').filter({ has: page.getByText('Close Collection') });
await closeModal.getByRole('button', { name: 'Close' }).click();
// Cleanup - use new "Remove" action in workspace UI
const collectionRow = page.locator('.collection-name').filter({ has: page.locator('#sidebar-collection-name:has-text("test_collection")') });
await collectionRow.hover();
await collectionRow.locator('.collection-actions .icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Remove' }).click();
await page.locator('.bruno-logo').click();
const closeModal = page.getByRole('dialog').filter({ has: page.getByText('Remove Collection') });
await closeModal.getByRole('button', { name: 'Remove' }).click();
});
});

View File

@@ -1,5 +1,6 @@
import { test, expect } from '../../../playwright';
import path from 'path';
import { closeAllCollections } from '../../utils/page';
test.describe('Global Environment Create Tests', () => {
test('should import collection and create global environment for request usage', async ({
@@ -9,20 +10,22 @@ test.describe('Global Environment Create Tests', () => {
const openApiFile = path.join(__dirname, 'fixtures', 'bruno-collection.json');
// Import test collection
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
const importModal = page.locator('[data-testid="import-collection-modal"]');
await importModal.waitFor({ state: 'visible' });
await page.setInputFiles('input[type="file"]', openApiFile);
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await expect(locationModal.getByText('test_collection')).toBeVisible();
await page.locator('#collection-location').fill(await createTmpDir('global-env-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'test_collection' })).toBeVisible();
@@ -116,18 +119,7 @@ test.describe('Global Environment Create Tests', () => {
await expect(responsePane).toContainText('"body": "This is a global test post body with environment variables"');
await expect(responsePane).toContainText('"apiToken": "global-secret-token-12345"');
// Cleanup
await page
.locator('.collection-name')
.filter({ has: page.locator('#sidebar-collection-name:has-text("test_collection")') })
.locator('.collection-actions')
.click();
await page.locator('.dropdown-item').filter({ hasText: 'Close' }).click();
// Scope the Close button to the confirmation modal to avoid matching the dropdown close button
// Wait for the confirmation modal with "Close Collection" title to appear
const closeModal = page.getByRole('dialog').filter({ has: page.getByText('Close Collection') });
await closeModal.getByRole('button', { name: 'Close' }).click();
await page.locator('.bruno-logo').click();
// cleanup: close all collections
await closeAllCollections(page);
});
});

View File

@@ -12,24 +12,24 @@ test.describe('Collection Environment Import Tests', () => {
const envFile = path.join(__dirname, 'fixtures', 'collection-env.json');
// Import test collection
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
const importModal = page.locator('[data-testid="import-collection-modal"]');
await importModal.waitFor({ state: 'visible' });
await page.setInputFiles('input[type="file"]', openApiFile);
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await expect(locationModal.getByText('Environment Test Collection')).toBeVisible();
// Select a location and import
await page.locator('#collection-location').fill(await createTmpDir('collection-env-import-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(
page.locator('#sidebar-collection-name').filter({ hasText: 'Environment Test Collection' })
).toBeVisible();
page.locator('#sidebar-collection-name').filter({ hasText: 'Environment Test Collection' })).toBeVisible({ timeout: 10000 });
// Configure collection
await page.locator('#sidebar-collection-name').filter({ hasText: 'Environment Test Collection' }).click();

View File

@@ -1,5 +1,6 @@
import { test, expect } from '../../../playwright';
import path from 'path';
import { closeAllCollections } from '../../utils/page';
test.describe('Global Environment Import Tests', () => {
test('should import global environment from file', async ({ newPage: page, createTmpDir }) => {
@@ -7,24 +8,23 @@ test.describe('Global Environment Import Tests', () => {
const globalEnvFile = path.join(__dirname, 'fixtures', 'global-env.json');
// Import test collection
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
const importModal = page.locator('[data-testid="import-collection-modal"]');
await importModal.waitFor({ state: 'visible' });
await page.setInputFiles('input[type="file"]', openApiFile);
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await expect(locationModal.getByText('Environment Test Collection')).toBeVisible();
await page.locator('#collection-location').fill(await createTmpDir('global-env-import-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(
page.locator('#sidebar-collection-name').filter({ hasText: 'Environment Test Collection' })
).toBeVisible();
page.locator('#sidebar-collection-name').filter({ hasText: 'Environment Test Collection' })).toBeVisible({ timeout: 10000 });
// Configure collection
await page.locator('#sidebar-collection-name').filter({ hasText: 'Environment Test Collection' }).click();
@@ -79,16 +79,7 @@ test.describe('Global Environment Import Tests', () => {
await page.locator('[data-testid="response-status-code"]').waitFor({ state: 'visible' });
await expect(page.locator('[data-testid="response-status-code"]')).toContainText('201');
// Cleanup
await page.locator('#sidebar-collection-name').filter({ hasText: 'Environment Test Collection' }).click();
await page
.locator('.collection-name')
.filter({ has: page.locator('#sidebar-collection-name:has-text("Environment Test Collection")') })
.locator('.collection-actions')
.click();
await page.locator('.dropdown-item').filter({ hasText: 'Close' }).click();
await page.locator('.dropdown-item').filter({ hasText: 'Close' }).waitFor({ state: 'detached' });
const closeModal = page.getByRole('dialog').filter({ has: page.getByText('Close Collection') });
await closeModal.getByRole('button', { name: 'Close' }).click();
// cleanup: close all collections
await closeAllCollections(page);
});
});

View File

@@ -5,8 +5,9 @@ test.describe('Multiline Variables - Read Environment Test', () => {
test.setTimeout(30 * 1000);
// open the collection
await expect(page.getByTitle('multiline-variables')).toBeVisible();
await page.getByTitle('multiline-variables').click();
const collection = page.getByTestId('collections').locator('#sidebar-collection-name').filter({ hasText: 'multiline-variables' });
await expect(collection).toBeVisible();
await collection.click();
// open request
await expect(page.getByTitle('request', { exact: true })).toBeVisible();

View File

@@ -5,8 +5,9 @@ test.describe('Multiline Variables - Write Test', () => {
test.setTimeout(60 * 1000);
// open the collection
await expect(page.getByTitle('multiline-variables')).toBeVisible();
await page.getByTitle('multiline-variables').click();
const collection = page.getByTestId('collections').locator('#sidebar-collection-name').filter({ hasText: 'multiline-variables' });
await expect(collection).toBeVisible();
await collection.click();
// open request
await expect(page.getByTitle('multiline-test', { exact: true })).toBeVisible();
@@ -89,7 +90,4 @@ test.describe('Multiline Variables - Write Test', () => {
fs.writeFileSync(testBruPath, content);
});
test.afterAll(async ({ page }) => {
await page.locator('.bruno-logo').click();
});
});

View File

@@ -5,7 +5,8 @@ test.describe('Import Corrupted Bruno Collection - Should Fail', () => {
test('Import Bruno collection with invalid JSON structure should fail', async ({ page }) => {
const brunoFile = path.resolve(__dirname, 'fixtures', 'bruno-malformed.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,16 +15,13 @@ test.describe('Import Corrupted Bruno Collection - Should Fail', () => {
await page.setInputFiles('input[type="file"]', brunoFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for JSON parsing error
const hasImportError = await page.getByText('Failed to parse the file ensure it is valid JSON or YAML').first().isVisible();
const hasImportError = await page.getByText('Failed to parse the file ensure it is valid JSON or YAML').first().isVisible({ timeout: 5000 });
// Either parsing error or import error should be shown
expect(hasImportError).toBe(true);
// Cleanup: close any open modals
await page.locator('[data-test-id="modal-close-button"]').click();
await page.getByTestId('modal-close-button').click();
});
});

View File

@@ -5,7 +5,8 @@ test.describe('Import Bruno Collection - Missing Required Schema Fields', () =>
test('Import Bruno collection missing required version field should fail', async ({ page }) => {
const brunoFile = path.resolve(__dirname, 'fixtures', 'bruno-missing-required-fields.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,15 +15,12 @@ test.describe('Import Bruno Collection - Missing Required Schema Fields', () =>
await page.setInputFiles('input[type="file"]', brunoFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for schema validation error messages
const hasImportError = await page.getByText('Unsupported collection format').first().isVisible();
const hasImportError = await page.getByText('Unsupported collection format').first().isVisible({ timeout: 5000 });
expect(hasImportError).toBe(true);
// Cleanup: close any open modals
await page.locator('[data-test-id="modal-close-button"]').click();
await page.getByTestId('modal-close-button').click();
});
});

View File

@@ -3,20 +3,15 @@ import * as path from 'path';
import { closeAllCollections } from '../../utils/page';
test.describe('Import Bruno Testbench Collection', () => {
test.beforeAll(async ({ page }) => {
// Navigate back to homescreen after all tests
await page.locator('.bruno-logo').click();
});
test.afterEach(async ({ page }) => {
// cleanup: close all collections
test.afterAll(async ({ page }) => {
await closeAllCollections(page);
});
test('Import Bruno Testbench collection successfully', async ({ page, createTmpDir }) => {
const brunoFile = path.resolve(__dirname, 'fixtures', 'bruno-testbench.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -25,18 +20,16 @@ test.describe('Import Bruno Testbench Collection', () => {
await page.setInputFiles('input[type="file"]', brunoFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the Import Collection modal is displayed (for location selection)
const locationModal = page.getByRole('dialog');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
// Wait for collection to appear in the location modal
await expect(locationModal.getByText('bruno-testbench')).toBeVisible();
await page.locator('#collection-location').fill(await createTmpDir('bruno-testbench-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sidebar-collection-name').getByText('bruno-testbench')).toBeVisible();
});

View File

@@ -11,7 +11,8 @@ test.describe('Import Bruno Collection with Examples', () => {
const brunoFile = path.resolve(__dirname, 'fixtures', 'bruno-with-examples.json');
await test.step('Open import collection modal', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
});
await test.step('Wait for import modal and verify title', async () => {
@@ -24,10 +25,6 @@ test.describe('Import Bruno Collection with Examples', () => {
await page.setInputFiles('input[type="file"]', brunoFile);
});
await test.step('Wait for file processing to complete', async () => {
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
});
await test.step('Verify no parsing errors occurred', async () => {
const hasError = await page.getByText('Failed to parse the file').isVisible().catch(() => false);
if (hasError) {
@@ -36,12 +33,12 @@ test.describe('Import Bruno Collection with Examples', () => {
});
await test.step('Verify location selection modal appears', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
});
await test.step('Verify collection name appears in location modal', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.getByText('bruno-with-examples')).toBeVisible();
await page.getByTestId('modal-close-button').click();
});

View File

@@ -2,7 +2,8 @@ import { test, expect } from '../../../playwright';
test.describe('File Input Acceptance', () => {
test('File input accepts expected file types', async ({ page }) => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Check that file input exists (even if hidden)
const fileInput = page.locator('input[type="file"]');

View File

@@ -5,7 +5,8 @@ test.describe('Invalid File Handling', () => {
test('Handle invalid file without crashing', async ({ page }) => {
const invalidFile = path.resolve(__dirname, 'fixtures', 'invalid.txt');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');

View File

@@ -23,7 +23,8 @@ test.describe('Import Insomnia v4 Collection - Environment Import', () => {
const insomniaFile = path.resolve(__dirname, 'fixtures', 'insomnia-v4-with-envs.json');
await test.step('Import Insomnia v4 collection with environments', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
const importModal = page.getByTestId('import-collection-modal');
await importModal.waitFor({ state: 'visible' });
@@ -31,13 +32,13 @@ test.describe('Import Insomnia v4 Collection - Environment Import', () => {
await page.setInputFiles('input[type="file"]', insomniaFile);
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
const locationModal = page.getByTestId('import-collection-location-modal');
await expect(locationModal.getByText('Test API Collection v4 with Environments')).toBeVisible();
await page.locator('#collection-location').fill(await createTmpDir('insomnia-v4-env-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sidebar-collection-name').getByText('Test API Collection v4 with Environments')).toBeVisible();

View File

@@ -11,7 +11,8 @@ test.describe('Import Insomnia Collection v4', () => {
test('Import Insomnia Collection v4 successfully', async ({ page, createTmpDir }) => {
const insomniaFile = path.resolve(__dirname, 'fixtures', 'insomnia-v4.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -20,15 +21,13 @@ test.describe('Import Insomnia Collection v4', () => {
await page.setInputFiles('input[type="file"]', insomniaFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the Import Collection modal is displayed (for location selection)
const locationModal = page.getByRole('dialog');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await page.locator('#collection-location').fill(await createTmpDir('insomnia-v4-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sidebar-collection-name').getByText('Test API Collection v4')).toBeVisible();
});

View File

@@ -23,7 +23,8 @@ test.describe('Import Insomnia v5 Collection - Environment Import', () => {
const insomniaFile = path.resolve(__dirname, 'fixtures', 'insomnia-v5-with-envs.yaml');
await test.step('Import Insomnia v5 collection with environments', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
const importModal = page.getByTestId('import-collection-modal');
await importModal.waitFor({ state: 'visible' });
@@ -31,15 +32,12 @@ test.describe('Import Insomnia v5 Collection - Environment Import', () => {
await page.setInputFiles('input[type="file"]', insomniaFile);
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
const locationModal = page.getByTestId('import-collection-location-modal');
await expect(locationModal.getByText('Test API Collection v5 with Environments')).toBeVisible();
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await page.locator('#collection-location').fill(await createTmpDir('insomnia-v5-env-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await expect(page.getByText('Test API Collection v5 with Environments')).toBeVisible();
await locationModal.getByRole('button', { name: 'Import' }).click();
await openCollectionAndAcceptSandbox(page, 'Test API Collection v5 with Environments', 'safe');
});

View File

@@ -11,7 +11,8 @@ test.describe('Import Insomnia Collection v5', () => {
test('Import Insomnia Collection v5 successfully', async ({ page, createTmpDir }) => {
const insomniaFile = path.resolve(__dirname, 'fixtures', 'insomnia-v5.yaml');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -20,15 +21,13 @@ test.describe('Import Insomnia Collection v5', () => {
await page.setInputFiles('input[type="file"]', insomniaFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the Import Collection modal is displayed (for location selection)
const locationModal = page.getByRole('dialog');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await page.locator('#collection-location').fill(await createTmpDir('insomnia-v5-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sidebar-collection-name').getByText('Test API Collection v5')).toBeVisible();
});

View File

@@ -5,7 +5,8 @@ test.describe('Invalid Insomnia Collection - Missing Collection Array', () => {
test('Handle Insomnia v5 collection missing collection array', async ({ page }) => {
const insomniaFile = path.resolve(__dirname, 'fixtures', 'insomnia-v5-invalid-missing-collection.yaml');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,9 +15,6 @@ test.describe('Invalid Insomnia Collection - Missing Collection Array', () => {
await page.setInputFiles('input[type="file"]', insomniaFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for error message
const hasError = await page.getByText('Unsupported collection format').first().isVisible();
expect(hasError).toBe(true);

View File

@@ -5,7 +5,8 @@ test.describe('Invalid Insomnia Collection - Malformed Structure', () => {
test('Handle malformed Insomnia collection structure', async ({ page }) => {
const insomniaFile = path.resolve(__dirname, 'fixtures', 'insomnia-malformed.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,8 +15,6 @@ test.describe('Invalid Insomnia Collection - Malformed Structure', () => {
await page.setInputFiles('input[type="file"]', insomniaFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for error message - this should fail during JSON parsing
const hasError = await page.getByText('Failed to parse the file').first().isVisible();

View File

@@ -12,7 +12,8 @@ test.describe('OpenAPI Duplicate Names Handling', () => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-duplicate-operation-name.yaml');
// start the import process
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// wait for the import collection modal to appear
const importModal = page.getByTestId('import-collection-modal');
@@ -21,12 +22,15 @@ test.describe('OpenAPI Duplicate Names Handling', () => {
// upload the OpenAPI file with duplicate operation names
await page.setInputFiles('input[type="file"]', openApiFile);
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
// wait for the file processing to complete
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// select a location
await page.locator('#collection-location').fill(await createTmpDir('duplicate-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
// verify the collection was imported successfully
await expect(page.locator('#sidebar-collection-name').getByText('Duplicate Test Collection')).toBeVisible();

View File

@@ -11,7 +11,8 @@ test.describe('Import OpenAPI v3 JSON Collection', () => {
test('Import simple OpenAPI v3 JSON successfully', async ({ page, createTmpDir }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-simple.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -20,11 +21,9 @@ test.describe('Import OpenAPI v3 JSON Collection', () => {
await page.setInputFiles('input[type="file"]', openApiFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the Import Collection modal is displayed (for location selection)
const locationModal = page.getByRole('dialog');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
// Wait for collection to appear in the location modal
@@ -32,7 +31,7 @@ test.describe('Import OpenAPI v3 JSON Collection', () => {
// Select a location and import
await page.locator('#collection-location').fill(await createTmpDir('simple-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
// Verify the collection was imported successfully
await expect(page.locator('#sidebar-collection-name').getByText('Simple Test API')).toBeVisible();

View File

@@ -35,7 +35,8 @@ test.describe('Import OpenAPI Collection with Examples', () => {
}, { importDir });
await test.step('Open import collection modal', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
});
await test.step('Wait for import modal and verify title', async () => {
@@ -47,10 +48,10 @@ test.describe('Import OpenAPI Collection with Examples', () => {
await test.step('Upload OpenAPI collection file using hidden file input', async () => {
// The "choose a file" button triggers a hidden file input, so we can directly set files on it
await page.setInputFiles('input[type="file"]', openApiFile);
});
await test.step('Wait for file processing to complete', async () => {
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
});
await test.step('Verify no parsing errors occurred', async () => {
@@ -61,18 +62,18 @@ test.describe('Import OpenAPI Collection with Examples', () => {
});
await test.step('Verify Import Collection location modal appears', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await expect(locationModal.getByText('API with Examples')).toBeVisible();
});
await test.step('Click Browse link to select collection folder', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.getByText('Browse').click();
});
await test.step('Complete import by clicking import button', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.getByRole('button', { name: 'Import' }).click();
});
@@ -151,7 +152,8 @@ test.describe('Import OpenAPI Collection with Examples', () => {
}, { importDir });
await test.step('Open import collection modal', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
});
await test.step('Wait for import modal and verify title', async () => {
@@ -162,10 +164,10 @@ test.describe('Import OpenAPI Collection with Examples', () => {
await test.step('Upload OpenAPI collection file using hidden file input', async () => {
await page.setInputFiles('input[type="file"]', openApiFile);
});
await test.step('Wait for file processing to complete', async () => {
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
});
await test.step('Verify no parsing errors occurred', async () => {
@@ -176,13 +178,13 @@ test.describe('Import OpenAPI Collection with Examples', () => {
});
await test.step('Verify Import Collection location modal appears', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
await expect(locationModal.getByText('API with Examples')).toBeVisible();
});
await test.step('Select path-based grouping option from dropdown', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
// Click on the grouping dropdown to open it
const groupingDropdown = locationModal.getByTestId('grouping-dropdown');
@@ -194,12 +196,12 @@ test.describe('Import OpenAPI Collection with Examples', () => {
});
await test.step('Click Browse link to select collection folder', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.getByText('Browse').click();
});
await test.step('Complete import by clicking import button', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.getByRole('button', { name: 'Import' }).click();
});

View File

@@ -11,7 +11,8 @@ test.describe('Import OpenAPI v3 YAML Collection', () => {
test('Import comprehensive OpenAPI v3 YAML successfully', async ({ page, createTmpDir }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-comprehensive.yaml');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -20,11 +21,9 @@ test.describe('Import OpenAPI v3 YAML Collection', () => {
await page.setInputFiles('input[type="file"]', openApiFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the Import Collection modal is displayed (for location selection)
const locationModal = page.getByRole('dialog');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
// Wait for collection to appear in the location modal
@@ -32,7 +31,7 @@ test.describe('Import OpenAPI v3 YAML Collection', () => {
// Select a location and import
await page.locator('#collection-location').fill(await createTmpDir('comprehensive-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
// Verify the collection was imported successfully
await expect(page.locator('#sidebar-collection-name').getByText('Comprehensive API Test Collection')).toBeVisible();

View File

@@ -5,7 +5,8 @@ test.describe('Invalid OpenAPI - Malformed YAML', () => {
test('Handle malformed OpenAPI YAML structure', async ({ page }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-malformed.yaml');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,9 +15,6 @@ test.describe('Invalid OpenAPI - Malformed YAML', () => {
await page.setInputFiles('input[type="file"]', openApiFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for error message - this should fail during YAML parsing
const hasParseError = await page.getByText('Failed to parse the file').isVisible();
const hasImportError = await page.getByText('Import collection failed').isVisible();

View File

@@ -5,7 +5,8 @@ test.describe('Invalid OpenAPI - Missing Info Section', () => {
test('Handle OpenAPI specification missing required info section', async ({ page }) => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-missing-info.yaml');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,9 +15,6 @@ test.describe('Invalid OpenAPI - Missing Info Section', () => {
await page.setInputFiles('input[type="file"]', openApiFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// The OpenAPI parser might handle missing info gracefully with defaults
const hasError = await page.getByText('Unsupported collection format').first().isVisible();

View File

@@ -12,7 +12,8 @@ test.describe('OpenAPI Newline Handling', () => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-newline-in-operation-name.yaml');
// start the import process
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// wait for the import collection modal to appear
const importModal = page.getByTestId('import-collection-modal');
@@ -21,13 +22,14 @@ test.describe('OpenAPI Newline Handling', () => {
// upload the OpenAPI file with problematic operation names
await page.setInputFiles('input[type="file"]', openApiFile);
// verify that the collection location modal appears (OpenAPI files go directly to location modal)
const locationModal = page.getByTestId('import-collection-location-modal');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.getByText('Newline Test Collection')).toBeVisible();
// select a location
await page.locator('#collection-location').fill(await createTmpDir('newline-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
// verify the collection was imported successfully
await expect(page.locator('#sidebar-collection-name').getByText('Newline Test Collection')).toBeVisible();

View File

@@ -12,7 +12,8 @@ test.describe('OpenAPI Path-Based Grouping', () => {
const openApiFile = path.resolve(__dirname, 'fixtures', 'openapi-path-grouping.json');
// Start the import process
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByTestId('import-collection-modal');
@@ -21,11 +22,9 @@ test.describe('OpenAPI Path-Based Grouping', () => {
// Upload the OpenAPI file
await page.setInputFiles('input[type="file"]', openApiFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the collection location modal appears
const locationModal = page.getByTestId('import-collection-location-modal');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.getByText('Path Grouping Test API')).toBeVisible();
// Select path-based grouping from dropdown
@@ -34,7 +33,7 @@ test.describe('OpenAPI Path-Based Grouping', () => {
// Select a location and import
await page.locator('#collection-location').fill(await createTmpDir('path-grouping-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
// Verify the collection was imported successfully
await expect(page.locator('#sidebar-collection-name').getByText('Path Grouping Test API')).toBeVisible();

View File

@@ -11,7 +11,8 @@ test.describe('Import Postman Collection v2.0', () => {
test('Import Postman Collection v2.0 successfully', async ({ page, createTmpDir }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-v20.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -20,11 +21,9 @@ test.describe('Import Postman Collection v2.0', () => {
await page.setInputFiles('input[type="file"]', postmanFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the Import Collection modal is displayed (for location selection)
const locationModal = page.getByRole('dialog');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
// Wait for collection to appear in the location modal
@@ -32,7 +31,7 @@ test.describe('Import Postman Collection v2.0', () => {
// Select a location and import
await page.locator('#collection-location').fill(await createTmpDir('postman-v20-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
// Verify the collection was imported successfully
await expect(page.locator('#sidebar-collection-name').getByText('Postman v2.0 Collection')).toBeVisible();

View File

@@ -11,7 +11,8 @@ test.describe('Import Postman Collection v2.1', () => {
test('Import Postman Collection v2.1 successfully', async ({ page, createTmpDir }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-v21.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -20,11 +21,9 @@ test.describe('Import Postman Collection v2.1', () => {
await page.setInputFiles('input[type="file"]', postmanFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Verify that the Import Collection modal is displayed (for location selection)
const locationModal = page.getByRole('dialog');
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
// Wait for collection to appear in the location modal
@@ -32,7 +31,7 @@ test.describe('Import Postman Collection v2.1', () => {
// Select a location and import
await page.locator('#collection-location').fill(await createTmpDir('postman-v21-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
// Verify the collection was imported successfully
await expect(page.locator('#sidebar-collection-name').getByText('Postman v2.1 Collection')).toBeVisible();

View File

@@ -35,7 +35,8 @@ test.describe('Import Postman Collection with Examples', () => {
}, { importDir });
await test.step('Open import collection modal', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
});
await test.step('Wait for import modal and verify title', async () => {
@@ -47,10 +48,10 @@ test.describe('Import Postman Collection with Examples', () => {
await test.step('Upload Postman collection file using hidden file input', async () => {
// The "choose a file" button triggers a hidden file input, so we can directly set files on it
await page.setInputFiles('input[type="file"]', postmanFile);
});
await test.step('Wait for file processing to complete', async () => {
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
});
await test.step('Verify no parsing errors occurred', async () => {
@@ -61,22 +62,22 @@ test.describe('Import Postman Collection with Examples', () => {
});
await test.step('Verify location selection modal appears', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
});
await test.step('Verify collection name appears in location modal', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.getByText('collection with examples')).toBeVisible();
});
await test.step('Click Browse link to select collection folder', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.getByText('Browse').click();
});
await test.step('Complete import by clicking import button', async () => {
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.getByRole('button', { name: 'Import' }).click();
});

View File

@@ -5,7 +5,8 @@ test.describe('Invalid Postman Collection - Invalid JSON', () => {
test('Handle invalid JSON syntax', async ({ page }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-invalid-schema.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,9 +15,6 @@ test.describe('Invalid Postman Collection - Invalid JSON', () => {
await page.setInputFiles('input[type="file"]', postmanFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for error message
const hasError = await page.getByText('Unsupported collection format').first().isVisible();

View File

@@ -5,7 +5,8 @@ test.describe('Invalid Postman Collection - Missing Info', () => {
test('Handle Postman collection missing required info field', async ({ page }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-invalid-missing-info.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,9 +15,6 @@ test.describe('Invalid Postman Collection - Missing Info', () => {
await page.setInputFiles('input[type="file"]', postmanFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for error message
const hasError = await page.getByText('Unsupported collection format').first().isVisible();
expect(hasError).toBe(true);

View File

@@ -5,7 +5,8 @@ test.describe('Invalid Postman Collection - Invalid Schema', () => {
test('Handle Postman collection with invalid schema version', async ({ page }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-invalid-schema.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,9 +15,6 @@ test.describe('Invalid Postman Collection - Invalid Schema', () => {
await page.setInputFiles('input[type="file"]', postmanFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for error message
const hasError = await page.getByText('Unsupported collection format').first().isVisible();
expect(hasError).toBe(true);

View File

@@ -5,7 +5,8 @@ test.describe('Invalid Postman Collection - Malformed Structure', () => {
test('Handle malformed Postman collection structure', async ({ page }) => {
const postmanFile = path.resolve(__dirname, 'fixtures', 'postman-malformed.json');
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -14,9 +15,6 @@ test.describe('Invalid Postman Collection - Malformed Structure', () => {
await page.setInputFiles('input[type="file"]', postmanFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Check for error message
const hasError = await page.getByText('Unsupported collection format').first().isVisible();
expect(hasError).toBe(true);

View File

@@ -13,7 +13,8 @@ test.describe('Import WSDL Collection', () => {
const wsdlFile = path.join(testDataDir, 'wsdl.xml');
await test.step('Open import collection modal', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -23,18 +24,19 @@ test.describe('Import WSDL Collection', () => {
await test.step('Choose WSDL XML file', async () => {
await page.setInputFiles('input[type="file"]', wsdlFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
});
await test.step('Select the location for the collection and submit to import', async () => {
// Verify that the location selection modal is displayed to import the collection
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
// select a location
await page.locator('#collection-location').fill(await createTmpDir('wsdl-xml-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
await expect(page.locator('#sidebar-collection-name').getByText('TestWSDLServiceXML')).toBeVisible();
});
@@ -69,7 +71,8 @@ test.describe('Import WSDL Collection', () => {
const wsdlFile = path.join(testDataDir, 'wsdl-bruno.json');
await test.step('Open import collection modal', async () => {
await page.getByRole('button', { name: 'Import Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Import collection' }).click();
// Wait for import collection modal to be ready
const importModal = page.getByRole('dialog');
@@ -79,13 +82,14 @@ test.describe('Import WSDL Collection', () => {
await test.step('Choose WSDL JSON file', async () => {
await page.setInputFiles('input[type="file"]', wsdlFile);
// Wait for the loader to disappear
await page.locator('#import-collection-loader').waitFor({ state: 'hidden' });
// Wait for location modal to appear after file processing
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await locationModal.waitFor({ state: 'visible', timeout: 10000 });
});
await test.step('Select the location for the collection and submit to import', async () => {
// Verify that the location selection modal is displayed to import the collection
const locationModal = page.getByRole('dialog');
const locationModal = page.locator('[data-testid="import-collection-location-modal"]');
await expect(locationModal.locator('.bruno-modal-header-title')).toContainText('Import Collection');
// Wait for collection to appear in the location modal
@@ -93,7 +97,7 @@ test.describe('Import WSDL Collection', () => {
// select a location
await page.locator('#collection-location').fill(await createTmpDir('wsdl-json-test'));
await page.getByRole('button', { name: 'Import', exact: true }).click();
await locationModal.getByRole('button', { name: 'Import' }).click();
});
await test.step('Verify that the collection was imported successfully', async () => {

View File

@@ -87,23 +87,22 @@ test.describe('Onboarding', () => {
const page = await app.firstWindow();
// First launch - sample collection should be created
const sampleCollection = page.locator('.collection-name').filter({ hasText: 'Sample API Collection' });
const sampleCollection = page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'Sample API Collection' });
await expect(sampleCollection).toBeVisible();
// User closes the sample collection (hover on the collection and open context menu)
// User removes the sample collection from workspace (hover on the collection and open context menu)
await sampleCollection.hover();
await sampleCollection.locator('.collection-actions .icon').click();
// Close the sample collection
const closeOption = page.locator('.dropdown-item').getByText('Close');
await expect(closeOption).toBeVisible();
await closeOption.click();
// Remove the sample collection
const removeOption = page.locator('.dropdown-item').getByText('Remove');
await expect(removeOption).toBeVisible();
await removeOption.click();
// Handle the confirmation dialog - click the 'Close' button to confirm
const confirmCloseButton = page.locator('.bruno-modal').getByRole('button', { name: 'Close' });
await expect(confirmCloseButton).toBeVisible();
await confirmCloseButton.click();
// Confirm removal in the modal
const removeModal = page.getByRole('dialog').filter({ has: page.getByText('Remove Collection') });
await removeModal.getByRole('button', { name: 'Remove' }).click();
// Verify collection is closed (no longer visible in sidebar)
await expect(sampleCollection).not.toBeVisible();

View File

@@ -56,14 +56,17 @@ test.describe('Default Collection Location Feature', () => {
test('Should use default location in Create Collection modal', async ({ pageWithUserData: page }) => {
// test Create Collection modal
await page.locator('[data-testid="create-collection"]').click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
// verify the default location is pre-filled
// verify the default location is pre-filled (if location input is visible)
const collectionLocationInput = page.getByLabel('Location');
await expect(collectionLocationInput).toHaveValue('/tmp/bruno-collections');
if (await collectionLocationInput.isVisible()) {
await expect(collectionLocationInput).toHaveValue('/tmp/bruno-collections');
}
// cancel the collection creation
await page.getByRole('button', { name: 'Cancel' }).click();
await page.locator('.bruno-modal').getByRole('button', { name: 'Cancel' }).click();
// wait for 2 seconds
await page.waitForTimeout(2000);
@@ -71,12 +74,19 @@ test.describe('Default Collection Location Feature', () => {
test('Should use default location in Clone Collection modal', async ({ pageWithUserData: page }) => {
// open the clone collection modal
await page.locator('[data-testid="collection-actions"]').click();
await page.getByTestId('clone-collection').click();
const collection = page.locator('.collection-name').first();
await collection.hover();
await collection.locator('.collection-actions .icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Clone' }).click();
// verify the default location is pre-filled
const cloneLocationInput = page.getByLabel('Location');
await expect(cloneLocationInput).toHaveValue('/tmp/bruno-collections');
if (await cloneLocationInput.isVisible()) {
await expect(cloneLocationInput).toHaveValue('/tmp/bruno-collections');
}
// cancel the clone operation
await page.locator('.bruno-modal').getByRole('button', { name: 'Cancel' }).click();
// wait for 2 seconds
await page.waitForTimeout(2000);

View File

@@ -18,11 +18,15 @@ test.describe('Code Generation URL Encoding', () => {
page,
createTmpDir
}) => {
await page.locator('.dropdown-icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Create Collection' }).click();
// Use plus icon button in new workspace UI
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('unencoded-test-collection');
await page.getByLabel('Location').fill(await createTmpDir('unencoded-test-collection'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
const locationInput = page.getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('unencoded-test-collection'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'unencoded-test-collection' })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: 'unencoded-test-collection' }).click();
@@ -60,11 +64,15 @@ test.describe('Code Generation URL Encoding', () => {
page,
createTmpDir
}) => {
await page.locator('.dropdown-icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Create Collection' }).click();
// Use plus icon button in new workspace UI
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('encoded-test-collection');
await page.getByLabel('Location').fill(await createTmpDir('encoded-test-collection'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
const locationInput = page.getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('encoded-test-collection'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'encoded-test-collection' })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: 'encoded-test-collection' }).click();

View File

@@ -10,20 +10,20 @@ test('should persist request with newlines across app restarts', async ({ create
const app1 = await launchElectronApp({ userDataPath });
const page = await app1.firstWindow();
await page.locator('.dropdown-icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Create Collection' }).click();
await page.getByLabel('Name').fill('newlines-persistence');
await page.getByLabel('Location').fill(collectionPath);
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.locator('.bruno-modal').getByLabel('Name').fill('newlines-persistence');
await page.locator('.bruno-modal').getByLabel('Location').fill(collectionPath);
await page.locator('.bruno-modal').getByRole('button', { name: 'Create' }).click();
const collection = page.locator('.collection-name').filter({ hasText: 'newlines-persistence' });
const collection = page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'newlines-persistence' });
await collection.locator('.collection-actions').hover();
await collection.locator('.collection-actions .icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'New Request' }).click();
await page.getByPlaceholder('Request Name').fill('persistence-test');
await page.locator('#new-request-url').locator('.CodeMirror').click();
await page.locator('#new-request-url').locator('textarea').fill('https://httpbin.org/get');
await page.getByRole('button', { name: 'Create', exact: true }).click();
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await openCollectionAndAcceptSandbox(page, 'newlines-persistence', 'safe');
await page.locator('.collection-item-name').filter({ hasText: 'persistence-test' }).dblclick();
@@ -60,7 +60,7 @@ test('should persist request with newlines across app restarts', async ({ create
const app2 = await launchElectronApp({ userDataPath });
const page2 = await app2.firstWindow();
await page2.locator('.collection-name').filter({ hasText: 'newlines-persistence' }).click();
await page2.getByTestId('collections').locator('.collection-name').filter({ hasText: 'newlines-persistence' }).click();
await page2.locator('.collection-item-name').filter({ hasText: 'persistence-test' }).dblclick();
// Verify params persisted

View File

@@ -9,11 +9,14 @@ const isRequestSaved = async (saveButton: Locator) => {
};
const setup = async (page: Page, createTmpDir: (tag?: string | undefined) => Promise<string>) => {
await page.locator('.dropdown-icon').click();
await page.locator('.dropdown-item').filter({ hasText: 'Create Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
await page.getByLabel('Name').fill('source-collection');
await page.getByLabel('Location').fill(await createTmpDir('source-collection'));
await page.getByRole('button', { name: 'Create', exact: true }).click();
const locationInput = page.getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(await createTmpDir('source-collection'));
}
await page.locator('.bruno-modal').getByRole('button', { name: 'Create', exact: true }).click();
await expect(page.locator('#sidebar-collection-name').filter({ hasText: 'source-collection' })).toBeVisible();
await page.locator('#sidebar-collection-name').filter({ hasText: 'source-collection' }).click();
await page.getByLabel('Safe Mode').check();

View File

@@ -2,7 +2,7 @@ import { test, expect } from '../../../../playwright';
test.describe('Custom Search Functionality in Scripts Tab', () => {
test('should open search box when Cmd+F or Ctrl+F is pressed in scripts tab', async ({ pageWithUserData: page }) => {
await page.getByTitle('custom-search').click();
await page.getByTestId('collections').locator('#sidebar-collection-name').filter({ hasText: 'custom-search' }).click();
await page.getByText('search-test-request').click();
@@ -62,7 +62,7 @@ test.describe('Custom Search Functionality in Scripts Tab', () => {
});
test('should handle search in different script editors independently', async ({ pageWithUserData: page }) => {
await page.getByTitle('custom-search').click();
await page.getByTestId('collections').locator('#sidebar-collection-name').filter({ hasText: 'custom-search' }).click();
await page.getByText('search-test-request').click();
@@ -96,7 +96,7 @@ test.describe('Custom Search Functionality in Scripts Tab', () => {
});
test('should maintain search state when switching between tabs', async ({ pageWithUserData: page }) => {
await page.getByTitle('custom-search').click();
await page.getByTestId('collections').locator('#sidebar-collection-name').filter({ hasText: 'custom-search' }).click();
await page.getByText('search-test-request').click();

View File

@@ -1,4 +1,4 @@
import { test } from '../../playwright';
import { test, expect } from '../../playwright';
import { setSandboxMode, runCollection, validateRunnerResults } from '../utils/page/index';
test.describe.parallel('Collection Run', () => {
@@ -29,7 +29,7 @@ test.describe.parallel('Collection Run', () => {
await page.getByRole('button', { name: 'Save' }).click();
await page.locator('.environment-selector').nth(1).click();
await page.locator('.dropdown-item').getByText('Prod').click();
const collectionContainer = page.locator('.collection-name').filter({ hasText: 'bruno-testbench' });
const collectionContainer = page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'bruno-testbench' });
await collectionContainer.locator('.collection-actions').hover();
await collectionContainer.locator('.collection-actions .icon').waitFor({ state: 'visible' });
await collectionContainer.locator('.collection-actions .icon').click();

View File

@@ -1,5 +1,9 @@
import { test, expect } from '../../playwright';
test('Check if the logo on top left is visible', async ({ page }) => {
await expect(page.getByRole('button', { name: 'bruno' })).toBeVisible();
test('Check if the workspace name is visible in the sidebar', async ({ page }) => {
// Wait for the app to be loaded
await page.locator('[data-app-state="loaded"]').waitFor({ timeout: 30000 });
// Wait for the workspace name container to be visible (contains workspace name like "My Workspace" or "Default Workspace")
await expect(page.locator('.workspace-name-container')).toBeVisible();
});

View File

@@ -8,20 +8,20 @@ import { buildCommonLocators } from './locators';
*/
const closeAllCollections = async (page) => {
await test.step('Close all collections', async () => {
const numberOfCollections = await page.locator('.collection-name').count();
const numberOfCollections = await page.locator('[data-testid="collections"] .collection-name').count();
for (let i = 0; i < numberOfCollections; i++) {
await page.locator('.collection-name').first().locator('.collection-actions').click();
await page.locator('.dropdown-item').getByText('Close').click();
// Wait for the close collection modal to be visible
await page.locator('.bruno-modal-header-title', { hasText: 'Close Collection' }).waitFor({ state: 'visible' });
await page.locator('[data-testid="collections"] .collection-name').first().locator('.collection-actions').click();
await page.locator('.dropdown-item').getByText('Remove').click();
// Wait for the remove collection modal to be visible
await page.locator('.bruno-modal-header-title', { hasText: 'Remove Collection' }).waitFor({ state: 'visible' });
await page.locator('.bruno-modal-footer .submit').click();
// Wait for the close collection modal to be hidden
await page.locator('.bruno-modal-header-title', { hasText: 'Close Collection' }).waitFor({ state: 'hidden' });
// Wait for the remove collection modal to be hidden
await page.locator('.bruno-modal-header-title', { hasText: 'Remove Collection' }).waitFor({ state: 'hidden' });
}
// Wait until no collections are left open
await expect(page.locator('.collection-name')).toHaveCount(0);
// Wait until no collections are left open (check sidebar only)
await expect(page.getByTestId('collections').locator('.collection-name')).toHaveCount(0);
});
};
@@ -62,13 +62,16 @@ type CreateCollectionOptions = {
*/
const createCollection = async (page, collectionName: string, collectionLocation: string, options: CreateCollectionOptions = {}) => {
await test.step(`Create collection "${collectionName}"`, async () => {
await page.locator('.collection-dropdown .dropdown-icon').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create Collection' }).click();
await page.locator('.plus-icon-button').click();
await page.locator('.tippy-box .dropdown-item').filter({ hasText: 'Create collection' }).click();
const createCollectionModal = page.locator('.bruno-modal-card').filter({ hasText: 'Create Collection' });
await createCollectionModal.getByLabel('Name').fill(collectionName);
await createCollectionModal.getByLabel('Location').fill(collectionLocation);
const locationInput = createCollectionModal.getByLabel('Location');
if (await locationInput.isVisible()) {
await locationInput.fill(collectionLocation);
}
await createCollectionModal.getByRole('button', { name: 'Create', exact: true }).click();
await createCollectionModal.waitFor({ state: 'detached' });
@@ -115,8 +118,8 @@ const deleteRequest = async (page, requestName: string, collectionName: string)
await locators.sidebar.collection(collectionName).click();
// Find the request within the collection's context
// Use the collection container (.collection-name) to scope the search
const collectionContainer = page.locator('.collection-name').filter({ hasText: collectionName });
// Use the collection container (.collection-name) scoped to sidebar to scope the search
const collectionContainer = page.getByTestId('collections').locator('.collection-name').filter({ hasText: collectionName });
const collectionWrapper = collectionContainer.locator('..');
const request = collectionWrapper.locator('.collection-item-name').filter({ hasText: requestName });

View File

@@ -21,7 +21,7 @@ export const buildCommonLocators = (page: Page) => ({
},
actions: {
collectionActions: (collectionName: string) =>
page.locator('.collection-name')
page.getByTestId('collections').locator('.collection-name')
.filter({ hasText: collectionName })
.locator('.collection-actions .icon'),
collectionItemActions: (itemName: string) =>
@@ -43,7 +43,7 @@ export const buildCommonLocators = (page: Page) => ({
modal: {
title: (title: string) => page.locator('.bruno-modal-header-title').filter({ hasText: title }),
byTitle: (title: string) => page.locator('.bruno-modal').filter({ has: page.locator('.bruno-modal-header-title').filter({ hasText: title }) }),
button: (name: string) => page.getByRole('button', { name: name, exact: true }),
button: (name: string) => page.locator('.bruno-modal').getByRole('button', { name: name, exact: true }),
closeButton: () => page.locator('.bruno-modal').getByTestId('modal-close-button')
},
environment: {

View File

@@ -27,8 +27,8 @@ export const getRunnerResultCounts = async (page: Page) => {
* @returns void
*/
export const runCollection = async (page: Page, collectionName: string) => {
// Ensure collection is visible and loaded
const collectionContainer = page.locator('.collection-name').filter({ hasText: collectionName });
// Ensure collection is visible and loaded (scope to sidebar)
const collectionContainer = page.getByTestId('collections').locator('.collection-name').filter({ hasText: collectionName });
await collectionContainer.waitFor({ state: 'visible' });
// Wait a bit for the UI to stabilize
await page.waitForTimeout(300);
@@ -71,24 +71,14 @@ export const runCollection = async (page: Page, collectionName: string) => {
* @returns void
*/
export const setSandboxMode = async (page: Page, collectionName: string, mode: 'developer' | 'safe') => {
// Click on the collection name - try sidebar first, then fall back to collection tab/name
// First try sidebar collection name (more reliable)
const sidebarCollection = page.locator('#sidebar-collection-name').filter({ hasText: collectionName });
const sidebarExists = await sidebarCollection.count().then((count) => count > 0).catch(() => false);
// Click on the collection name in the sidebar
// Use the collections testid to scope to the sidebar, then find the specific collection
const sidebarCollection = page.getByTestId('collections').locator('#sidebar-collection-name').filter({ hasText: collectionName }).first();
if (sidebarExists) {
await sidebarCollection.click();
} else {
// Fall back to collection by title or text
const collectionByTitle = page.getByTitle(collectionName);
const collectionByText = page.getByText(collectionName);
const titleExists = await collectionByTitle.count().then((count) => count > 0).catch(() => false);
if (titleExists) {
await collectionByTitle.click();
} else {
await collectionByText.click();
}
}
// Wait for the sidebar to be loaded
await page.waitForTimeout(500);
await sidebarCollection.click();
// Wait a moment for the UI to load
await page.waitForTimeout(300);