From 08c183b4ec6ba39860531820e4fbf56f44139f49 Mon Sep 17 00:00:00 2001 From: naman-bruno Date: Wed, 3 Dec 2025 00:06:40 +0530 Subject: [PATCH] fix: tests --- .../Sidebar/Collections/Collection/index.js | 2 + .../components/Sidebar/Collections/index.js | 2 +- .../Sidebar/CreateCollection/index.js | 2 +- .../src/components/Sidebar/TitleBar/index.js | 52 +++++++------------ .../ReduxStore/slices/workspaces/actions.js | 10 ++-- packages/bruno-electron/src/ipc/workspace.js | 4 +- .../src/store/default-workspace.js | 1 + .../create-requests/graphql-requests.spec.ts | 3 +- .../create-requests/grpc-requests.spec.ts | 3 +- .../create-requests/http-requests.spec.ts | 3 +- .../create-requests/ws-requests.spec.ts | 3 +- .../create/create-collection.spec.ts | 13 +++-- .../moving-requests/tag-persistence.spec.ts | 28 ++++++---- .../collection/moving-tabs/move-tabs.spec.ts | 22 +++++--- .../open/open-multiple-collections.spec.ts | 22 ++++---- .../collection-env-create.spec.ts | 24 ++++----- .../global-env-create.spec.ts | 24 +++------ .../collection-env-import.spec.ts | 10 ++-- .../global-env-import.spec.ts | 23 +++----- .../read-multiline-environment.spec.ts | 5 +- .../write-multiline-variable.spec.ts | 8 ++- .../import-bruno-corrupted-fails.spec.ts | 10 ++-- ...port-bruno-missing-required-schema.spec.ts | 10 ++-- .../bruno/import-bruno-testbench.spec.ts | 21 +++----- .../bruno/import-bruno-with-examples.spec.ts | 11 ++-- .../file-types/file-input-acceptance.spec.ts | 3 +- .../file-types/invalid-file-handling.spec.ts | 3 +- .../import-insomnia-v4-environments.spec.ts | 9 ++-- .../insomnia/import-insomnia-v4.spec.ts | 13 +++-- .../import-insomnia-v5-environments.spec.ts | 14 +++-- .../insomnia/import-insomnia-v5.spec.ts | 13 +++-- .../invalid-missing-collection.spec.ts | 6 +-- .../insomnia/malformed-structure.spec.ts | 5 +- .../duplicate-operation-names-fix.spec.ts | 10 ++-- .../openapi/import-openapi-json.spec.ts | 13 +++-- .../import-openapi-with-examples.spec.ts | 32 ++++++------ .../openapi/import-openapi-yaml.spec.ts | 13 +++-- tests/import/openapi/malformed-yaml.spec.ts | 6 +-- tests/import/openapi/missing-info.spec.ts | 6 +-- .../operation-name-with-newlines-fix.spec.ts | 10 ++-- .../openapi/path-based-grouping.spec.ts | 13 +++-- .../import/postman/import-postman-v20.spec.ts | 13 +++-- .../import/postman/import-postman-v21.spec.ts | 13 +++-- .../import-postman-with-examples.spec.ts | 17 +++--- tests/import/postman/invalid-json.spec.ts | 6 +-- .../postman/invalid-missing-info.spec.ts | 6 +-- tests/import/postman/invalid-schema.spec.ts | 6 +-- .../postman/malformed-structure.spec.ts | 6 +-- tests/import/wsdl/import-wsdl.spec.ts | 24 +++++---- tests/onboarding/sample-collection.spec.ts | 19 ++++--- .../default-collection-location.spec.js | 24 ++++++--- tests/request/encoding/curl-encoding.spec.ts | 24 ++++++--- .../newlines/newlines-persistence.spec.ts | 16 +++--- tests/request/save/save.spec.ts | 11 ++-- .../tests/custom-search/custom-search.spec.ts | 6 +-- tests/runner/collection-run.ts | 4 +- tests/start/app-open.spec.ts | 8 ++- tests/utils/page/actions.ts | 31 ++++++----- tests/utils/page/locators.ts | 4 +- tests/utils/page/runner.ts | 28 ++++------ 60 files changed, 369 insertions(+), 382 deletions(-) diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js index 424a004e8..ff28a099c 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/index.js @@ -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); }} > diff --git a/packages/bruno-app/src/components/Sidebar/Collections/index.js b/packages/bruno-app/src/components/Sidebar/Collections/index.js index 767de168a..52dfc440b 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/index.js @@ -43,7 +43,7 @@ const Collections = ({ showSearch }) => { } return ( - + {createCollectionModalOpen ? ( setCreateCollectionModalOpen(false)} diff --git a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js index d7ae6bdc9..1706550d9 100644 --- a/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js +++ b/packages/bruno-app/src/components/Sidebar/CreateCollection/index.js @@ -43,7 +43,7 @@ const CreateCollection = ({ onClose, workspaceUid, defaultLocation: propDefaultL initialValues: { collectionName: '', collectionFolderName: '', - collectionLocation: isDefaultWorkspace ? '' : (defaultLocation || ''), + collectionLocation: defaultLocation || '', format: 'yml' }, validationSchema: Yup.object({ diff --git a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js index ebaaba634..ec333dab8 100644 --- a/packages/bruno-app/src/components/Sidebar/TitleBar/index.js +++ b/packages/bruno-app/src/components/Sidebar/TitleBar/index.js @@ -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 }) => { 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 && ( setImportCollectionLocationModalOpen(false)} handleSubmit={handleImportCollectionLocation} /> diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js index 121a07a8f..c669c8fd9 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/actions.js @@ -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: diff --git a/packages/bruno-electron/src/ipc/workspace.js b/packages/bruno-electron/src/ipc/workspace.js index 3f37142ef..06523959c 100644 --- a/packages/bruno-electron/src/ipc/workspace.js +++ b/packages/bruno-electron/src/ipc/workspace.js @@ -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); } diff --git a/packages/bruno-electron/src/store/default-workspace.js b/packages/bruno-electron/src/store/default-workspace.js index bc1e195bb..8f259a9b9 100644 --- a/packages/bruno-electron/src/store/default-workspace.js +++ b/packages/bruno-electron/src/store/default-workspace.js @@ -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, diff --git a/tests/collection/create-requests/graphql-requests.spec.ts b/tests/collection/create-requests/graphql-requests.spec.ts index 49f9915ae..23e94f927 100644 --- a/tests/collection/create-requests/graphql-requests.spec.ts +++ b/tests/collection/create-requests/graphql-requests.spec.ts @@ -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 }) => { diff --git a/tests/collection/create-requests/grpc-requests.spec.ts b/tests/collection/create-requests/grpc-requests.spec.ts index b3df569d9..ccd731290 100644 --- a/tests/collection/create-requests/grpc-requests.spec.ts +++ b/tests/collection/create-requests/grpc-requests.spec.ts @@ -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; test.beforeAll(async ({ pageWithUserData: page }) => { locators = buildCommonLocators(page); + await openCollectionAndAcceptSandbox(page, 'create-requests', 'safe'); }); test.afterAll(async ({ pageWithUserData: page }) => { diff --git a/tests/collection/create-requests/http-requests.spec.ts b/tests/collection/create-requests/http-requests.spec.ts index 64c05f4d9..b44e19003 100644 --- a/tests/collection/create-requests/http-requests.spec.ts +++ b/tests/collection/create-requests/http-requests.spec.ts @@ -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; test.beforeAll(async ({ pageWithUserData: page }) => { locators = buildCommonLocators(page); + await openCollectionAndAcceptSandbox(page, 'create-requests', 'safe'); }); test.afterAll(async ({ pageWithUserData: page }) => { diff --git a/tests/collection/create-requests/ws-requests.spec.ts b/tests/collection/create-requests/ws-requests.spec.ts index cdd2cc377..86d112d6f 100644 --- a/tests/collection/create-requests/ws-requests.spec.ts +++ b/tests/collection/create-requests/ws-requests.spec.ts @@ -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; test.beforeAll(async ({ pageWithUserData: page }) => { locators = buildCommonLocators(page); + await openCollectionAndAcceptSandbox(page, 'create-requests', 'safe'); }); test.afterAll(async ({ pageWithUserData: page }) => { diff --git a/tests/collection/create/create-collection.spec.ts b/tests/collection/create/create-collection.spec.ts index 56124a41f..05105d228 100644 --- a/tests/collection/create/create-collection.spec.ts +++ b/tests/collection/create/create-collection.spec.ts @@ -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(); diff --git a/tests/collection/moving-requests/tag-persistence.spec.ts b/tests/collection/moving-requests/tag-persistence.spec.ts index 78681d6b9..e4e75cc00 100644 --- a/tests/collection/moving-requests/tag-persistence.spec.ts +++ b/tests/collection/moving-requests/tag-persistence.spec.ts @@ -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(); diff --git a/tests/collection/moving-tabs/move-tabs.spec.ts b/tests/collection/moving-tabs/move-tabs.spec.ts index 8a590e0c6..6700ff05b 100644 --- a/tests/collection/moving-tabs/move-tabs.spec.ts +++ b/tests/collection/moving-tabs/move-tabs.spec.ts @@ -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(); diff --git a/tests/collection/open/open-multiple-collections.spec.ts b/tests/collection/open/open-multiple-collections.spec.ts index 3d12b3b81..835ffbe5f 100644 --- a/tests/collection/open/open-multiple-collections.spec.ts +++ b/tests/collection/open/open-multiple-collections.spec.ts @@ -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(); }); }); diff --git a/tests/environments/create-environment/collection-env-create.spec.ts b/tests/environments/create-environment/collection-env-create.spec.ts index 1a34e2fc8..f44439f2d 100644 --- a/tests/environments/create-environment/collection-env-create.spec.ts +++ b/tests/environments/create-environment/collection-env-create.spec.ts @@ -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(); }); }); diff --git a/tests/environments/create-environment/global-env-create.spec.ts b/tests/environments/create-environment/global-env-create.spec.ts index 5ca860fce..32ffa6641 100644 --- a/tests/environments/create-environment/global-env-create.spec.ts +++ b/tests/environments/create-environment/global-env-create.spec.ts @@ -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); }); }); diff --git a/tests/environments/import-environment/collection-env-import.spec.ts b/tests/environments/import-environment/collection-env-import.spec.ts index 0e5097f54..fa6ac1c8c 100644 --- a/tests/environments/import-environment/collection-env-import.spec.ts +++ b/tests/environments/import-environment/collection-env-import.spec.ts @@ -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(); diff --git a/tests/environments/import-environment/global-env-import.spec.ts b/tests/environments/import-environment/global-env-import.spec.ts index 8e5205296..917675ef9 100644 --- a/tests/environments/import-environment/global-env-import.spec.ts +++ b/tests/environments/import-environment/global-env-import.spec.ts @@ -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); }); }); diff --git a/tests/environments/multiline-variables/read-multiline-environment.spec.ts b/tests/environments/multiline-variables/read-multiline-environment.spec.ts index fdf2fefc7..d9ec80636 100644 --- a/tests/environments/multiline-variables/read-multiline-environment.spec.ts +++ b/tests/environments/multiline-variables/read-multiline-environment.spec.ts @@ -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(); diff --git a/tests/environments/multiline-variables/write-multiline-variable.spec.ts b/tests/environments/multiline-variables/write-multiline-variable.spec.ts index 1127ed369..fda98b665 100644 --- a/tests/environments/multiline-variables/write-multiline-variable.spec.ts +++ b/tests/environments/multiline-variables/write-multiline-variable.spec.ts @@ -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(); - }); }); diff --git a/tests/import/bruno/import-bruno-corrupted-fails.spec.ts b/tests/import/bruno/import-bruno-corrupted-fails.spec.ts index 6fe2a0799..76da05539 100644 --- a/tests/import/bruno/import-bruno-corrupted-fails.spec.ts +++ b/tests/import/bruno/import-bruno-corrupted-fails.spec.ts @@ -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(); }); }); diff --git a/tests/import/bruno/import-bruno-missing-required-schema.spec.ts b/tests/import/bruno/import-bruno-missing-required-schema.spec.ts index 53dcd08bc..f9a131bf2 100644 --- a/tests/import/bruno/import-bruno-missing-required-schema.spec.ts +++ b/tests/import/bruno/import-bruno-missing-required-schema.spec.ts @@ -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(); }); }); diff --git a/tests/import/bruno/import-bruno-testbench.spec.ts b/tests/import/bruno/import-bruno-testbench.spec.ts index a2590fd60..3ddf3d484 100644 --- a/tests/import/bruno/import-bruno-testbench.spec.ts +++ b/tests/import/bruno/import-bruno-testbench.spec.ts @@ -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(); }); diff --git a/tests/import/bruno/import-bruno-with-examples.spec.ts b/tests/import/bruno/import-bruno-with-examples.spec.ts index 7f188a3ec..71078e8c5 100644 --- a/tests/import/bruno/import-bruno-with-examples.spec.ts +++ b/tests/import/bruno/import-bruno-with-examples.spec.ts @@ -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(); }); diff --git a/tests/import/file-types/file-input-acceptance.spec.ts b/tests/import/file-types/file-input-acceptance.spec.ts index 3718ffd13..481440ede 100644 --- a/tests/import/file-types/file-input-acceptance.spec.ts +++ b/tests/import/file-types/file-input-acceptance.spec.ts @@ -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"]'); diff --git a/tests/import/file-types/invalid-file-handling.spec.ts b/tests/import/file-types/invalid-file-handling.spec.ts index e8439fa51..bccf0c81f 100644 --- a/tests/import/file-types/invalid-file-handling.spec.ts +++ b/tests/import/file-types/invalid-file-handling.spec.ts @@ -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'); diff --git a/tests/import/insomnia/import-insomnia-v4-environments.spec.ts b/tests/import/insomnia/import-insomnia-v4-environments.spec.ts index fa1e0d8dc..ac6df41d7 100644 --- a/tests/import/insomnia/import-insomnia-v4-environments.spec.ts +++ b/tests/import/insomnia/import-insomnia-v4-environments.spec.ts @@ -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(); diff --git a/tests/import/insomnia/import-insomnia-v4.spec.ts b/tests/import/insomnia/import-insomnia-v4.spec.ts index 042ad948b..1cb0a55ec 100644 --- a/tests/import/insomnia/import-insomnia-v4.spec.ts +++ b/tests/import/insomnia/import-insomnia-v4.spec.ts @@ -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(); }); diff --git a/tests/import/insomnia/import-insomnia-v5-environments.spec.ts b/tests/import/insomnia/import-insomnia-v5-environments.spec.ts index 178621667..745ab753a 100644 --- a/tests/import/insomnia/import-insomnia-v5-environments.spec.ts +++ b/tests/import/insomnia/import-insomnia-v5-environments.spec.ts @@ -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'); }); diff --git a/tests/import/insomnia/import-insomnia-v5.spec.ts b/tests/import/insomnia/import-insomnia-v5.spec.ts index 8c66ed582..7a00b6ebf 100644 --- a/tests/import/insomnia/import-insomnia-v5.spec.ts +++ b/tests/import/insomnia/import-insomnia-v5.spec.ts @@ -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(); }); diff --git a/tests/import/insomnia/invalid-missing-collection.spec.ts b/tests/import/insomnia/invalid-missing-collection.spec.ts index 2882b4a61..db1f2cfea 100644 --- a/tests/import/insomnia/invalid-missing-collection.spec.ts +++ b/tests/import/insomnia/invalid-missing-collection.spec.ts @@ -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); diff --git a/tests/import/insomnia/malformed-structure.spec.ts b/tests/import/insomnia/malformed-structure.spec.ts index 05e9be062..02d1629a8 100644 --- a/tests/import/insomnia/malformed-structure.spec.ts +++ b/tests/import/insomnia/malformed-structure.spec.ts @@ -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(); diff --git a/tests/import/openapi/duplicate-operation-names-fix.spec.ts b/tests/import/openapi/duplicate-operation-names-fix.spec.ts index 6f2570508..64f2e8d84 100644 --- a/tests/import/openapi/duplicate-operation-names-fix.spec.ts +++ b/tests/import/openapi/duplicate-operation-names-fix.spec.ts @@ -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(); diff --git a/tests/import/openapi/import-openapi-json.spec.ts b/tests/import/openapi/import-openapi-json.spec.ts index 7923303ab..77f455939 100644 --- a/tests/import/openapi/import-openapi-json.spec.ts +++ b/tests/import/openapi/import-openapi-json.spec.ts @@ -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(); diff --git a/tests/import/openapi/import-openapi-with-examples.spec.ts b/tests/import/openapi/import-openapi-with-examples.spec.ts index a644ce0eb..ad64b371c 100644 --- a/tests/import/openapi/import-openapi-with-examples.spec.ts +++ b/tests/import/openapi/import-openapi-with-examples.spec.ts @@ -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(); }); diff --git a/tests/import/openapi/import-openapi-yaml.spec.ts b/tests/import/openapi/import-openapi-yaml.spec.ts index e7110bf93..b6948a18c 100644 --- a/tests/import/openapi/import-openapi-yaml.spec.ts +++ b/tests/import/openapi/import-openapi-yaml.spec.ts @@ -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(); diff --git a/tests/import/openapi/malformed-yaml.spec.ts b/tests/import/openapi/malformed-yaml.spec.ts index ec596d18a..5e0a1f5a8 100644 --- a/tests/import/openapi/malformed-yaml.spec.ts +++ b/tests/import/openapi/malformed-yaml.spec.ts @@ -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(); diff --git a/tests/import/openapi/missing-info.spec.ts b/tests/import/openapi/missing-info.spec.ts index dc5d230fc..e58607426 100644 --- a/tests/import/openapi/missing-info.spec.ts +++ b/tests/import/openapi/missing-info.spec.ts @@ -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(); diff --git a/tests/import/openapi/operation-name-with-newlines-fix.spec.ts b/tests/import/openapi/operation-name-with-newlines-fix.spec.ts index 6ca401c26..72d621be9 100644 --- a/tests/import/openapi/operation-name-with-newlines-fix.spec.ts +++ b/tests/import/openapi/operation-name-with-newlines-fix.spec.ts @@ -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(); diff --git a/tests/import/openapi/path-based-grouping.spec.ts b/tests/import/openapi/path-based-grouping.spec.ts index 9f98939bc..9a2494d63 100644 --- a/tests/import/openapi/path-based-grouping.spec.ts +++ b/tests/import/openapi/path-based-grouping.spec.ts @@ -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(); diff --git a/tests/import/postman/import-postman-v20.spec.ts b/tests/import/postman/import-postman-v20.spec.ts index d107d47de..4611405a1 100644 --- a/tests/import/postman/import-postman-v20.spec.ts +++ b/tests/import/postman/import-postman-v20.spec.ts @@ -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(); diff --git a/tests/import/postman/import-postman-v21.spec.ts b/tests/import/postman/import-postman-v21.spec.ts index cc4312446..be2c3f986 100644 --- a/tests/import/postman/import-postman-v21.spec.ts +++ b/tests/import/postman/import-postman-v21.spec.ts @@ -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(); diff --git a/tests/import/postman/import-postman-with-examples.spec.ts b/tests/import/postman/import-postman-with-examples.spec.ts index 7fca83f0e..8181c58ea 100644 --- a/tests/import/postman/import-postman-with-examples.spec.ts +++ b/tests/import/postman/import-postman-with-examples.spec.ts @@ -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(); }); diff --git a/tests/import/postman/invalid-json.spec.ts b/tests/import/postman/invalid-json.spec.ts index 5263dec9e..f47d1d2f1 100644 --- a/tests/import/postman/invalid-json.spec.ts +++ b/tests/import/postman/invalid-json.spec.ts @@ -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(); diff --git a/tests/import/postman/invalid-missing-info.spec.ts b/tests/import/postman/invalid-missing-info.spec.ts index d1f571382..a71ac4388 100644 --- a/tests/import/postman/invalid-missing-info.spec.ts +++ b/tests/import/postman/invalid-missing-info.spec.ts @@ -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); diff --git a/tests/import/postman/invalid-schema.spec.ts b/tests/import/postman/invalid-schema.spec.ts index ac549b0e0..bd8d26eb1 100644 --- a/tests/import/postman/invalid-schema.spec.ts +++ b/tests/import/postman/invalid-schema.spec.ts @@ -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); diff --git a/tests/import/postman/malformed-structure.spec.ts b/tests/import/postman/malformed-structure.spec.ts index 9facbac62..30cf4c540 100644 --- a/tests/import/postman/malformed-structure.spec.ts +++ b/tests/import/postman/malformed-structure.spec.ts @@ -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); diff --git a/tests/import/wsdl/import-wsdl.spec.ts b/tests/import/wsdl/import-wsdl.spec.ts index 23bdd4ab9..71dd220fb 100644 --- a/tests/import/wsdl/import-wsdl.spec.ts +++ b/tests/import/wsdl/import-wsdl.spec.ts @@ -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 () => { diff --git a/tests/onboarding/sample-collection.spec.ts b/tests/onboarding/sample-collection.spec.ts index 5c842c90e..c36502783 100644 --- a/tests/onboarding/sample-collection.spec.ts +++ b/tests/onboarding/sample-collection.spec.ts @@ -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(); diff --git a/tests/preferences/default-collection-location/default-collection-location.spec.js b/tests/preferences/default-collection-location/default-collection-location.spec.js index 3eeda754f..edb751bd9 100644 --- a/tests/preferences/default-collection-location/default-collection-location.spec.js +++ b/tests/preferences/default-collection-location/default-collection-location.spec.js @@ -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); diff --git a/tests/request/encoding/curl-encoding.spec.ts b/tests/request/encoding/curl-encoding.spec.ts index 255d22a55..c6a7b7f78 100644 --- a/tests/request/encoding/curl-encoding.spec.ts +++ b/tests/request/encoding/curl-encoding.spec.ts @@ -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(); diff --git a/tests/request/newlines/newlines-persistence.spec.ts b/tests/request/newlines/newlines-persistence.spec.ts index 22ce33783..249ee7ab5 100644 --- a/tests/request/newlines/newlines-persistence.spec.ts +++ b/tests/request/newlines/newlines-persistence.spec.ts @@ -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 diff --git a/tests/request/save/save.spec.ts b/tests/request/save/save.spec.ts index 3cd18df30..a40d3161f 100644 --- a/tests/request/save/save.spec.ts +++ b/tests/request/save/save.spec.ts @@ -9,11 +9,14 @@ const isRequestSaved = async (saveButton: Locator) => { }; const setup = async (page: Page, createTmpDir: (tag?: string | undefined) => Promise) => { - 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(); diff --git a/tests/request/tests/custom-search/custom-search.spec.ts b/tests/request/tests/custom-search/custom-search.spec.ts index b6c620224..9806782b4 100644 --- a/tests/request/tests/custom-search/custom-search.spec.ts +++ b/tests/request/tests/custom-search/custom-search.spec.ts @@ -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(); diff --git a/tests/runner/collection-run.ts b/tests/runner/collection-run.ts index 8ac19857c..5cb54f2a1 100644 --- a/tests/runner/collection-run.ts +++ b/tests/runner/collection-run.ts @@ -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(); diff --git a/tests/start/app-open.spec.ts b/tests/start/app-open.spec.ts index 326ff895c..d2df08383 100644 --- a/tests/start/app-open.spec.ts +++ b/tests/start/app-open.spec.ts @@ -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(); }); diff --git a/tests/utils/page/actions.ts b/tests/utils/page/actions.ts index a0589e149..fd41eab73 100644 --- a/tests/utils/page/actions.ts +++ b/tests/utils/page/actions.ts @@ -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 }); diff --git a/tests/utils/page/locators.ts b/tests/utils/page/locators.ts index 7ee6e660a..833913ef3 100644 --- a/tests/utils/page/locators.ts +++ b/tests/utils/page/locators.ts @@ -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: { diff --git a/tests/utils/page/runner.ts b/tests/utils/page/runner.ts index d6454b4ed..a3aa1ae23 100644 --- a/tests/utils/page/runner.ts +++ b/tests/utils/page/runner.ts @@ -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);