From 809f951a478460cf832256ebdbd96ee599dbc3a6 Mon Sep 17 00:00:00 2001 From: Sid Date: Tue, 26 May 2026 13:03:57 +0530 Subject: [PATCH] fix: tab type resolution for non request types (#8097) * fix: tab type resolution for non request types * Remove console log from snapshot test Removed console log statement from folder.spec.ts * test(snapshot): deserializeTab test addition for the removed guard --- .../bruno-app/src/utils/snapshot/index.js | 6 +- .../src/utils/snapshot/index.spec.js | 50 ++++++++ tests/snapshots/folder.spec.ts | 118 ++++++++++++++++++ tests/utils/page/actions.ts | 39 ++++++ tests/utils/page/locators.ts | 1 + 5 files changed, 213 insertions(+), 1 deletion(-) create mode 100644 tests/snapshots/folder.spec.ts diff --git a/packages/bruno-app/src/utils/snapshot/index.js b/packages/bruno-app/src/utils/snapshot/index.js index 9c7a17a2d..066b75be8 100644 --- a/packages/bruno-app/src/utils/snapshot/index.js +++ b/packages/bruno-app/src/utils/snapshot/index.js @@ -350,6 +350,10 @@ const getAccessor = (tab) => { }; const getDefaultRequestPaneTabForType = (type) => { + if (type === 'folder-settings') { + return 'headers'; + } + if (type === 'grpc-request' || type === 'ws-request') { return 'body'; } @@ -558,7 +562,7 @@ export const deserializeTab = (snapshotTab, collection) => { if (accessor === 'pathname' && pathname) { const item = findItemInCollectionByPathname(collection, pathname); - const resolvedType = item?.type || type; + const resolvedType = (item && isRequestTab(item.type)) ? item.type : type; tab.type = resolvedType; if (!restoredRequestPaneTab) { tab.requestPaneTab = getDefaultRequestPaneTabForType(resolvedType); diff --git a/packages/bruno-app/src/utils/snapshot/index.spec.js b/packages/bruno-app/src/utils/snapshot/index.spec.js index bf6b8508f..a71ca644a 100644 --- a/packages/bruno-app/src/utils/snapshot/index.spec.js +++ b/packages/bruno-app/src/utils/snapshot/index.spec.js @@ -286,6 +286,56 @@ describe('deserializeTab', () => { expect(tab.uid).toBe('collection-uid-preferences'); }); + it('defaults folder settings request pane tab to headers', () => { + const snapshotTab = { + type: 'folder-settings', + accessor: 'pathname', + pathname: '/collections/a/folder', + permanent: true + }; + + const tab = deserializeTab(snapshotTab, collection); + expect(tab.requestPaneTab).toBe('headers'); + }); + + it('restores folder settings request pane tab from snapshot', () => { + const snapshotTab = { + type: 'folder-settings', + accessor: 'pathname', + pathname: '/collections/a/folder', + request: { tab: 'auth' }, + permanent: true + }; + + const tab = deserializeTab(snapshotTab, collection); + expect(tab.requestPaneTab).toBe('auth'); + }); + + it('keeps folder-settings type when pathname resolves to a non-request item', () => { + const collectionWithFolderItem = { + ...collection, + items: [ + { + uid: 'folder-1', + pathname: '/collections/a/folder', + type: 'folder' + } + ] + }; + + const snapshotTab = { + type: 'folder-settings', + accessor: 'pathname', + pathname: '/collections/a/folder', + permanent: true + }; + + const tab = deserializeTab(snapshotTab, collectionWithFolderItem); + expect(tab.type).toBe('folder-settings'); + expect(tab.folderUid).toBe('folder-1'); + expect(tab.requestPaneTab).toBe('headers'); + }); + it('restores response example by index when duplicate names exist', () => { const collectionWithDuplicateExamples = { uid: 'collection-uid', diff --git a/tests/snapshots/folder.spec.ts b/tests/snapshots/folder.spec.ts new file mode 100644 index 000000000..c45ed9a2d --- /dev/null +++ b/tests/snapshots/folder.spec.ts @@ -0,0 +1,118 @@ +import path from 'path'; +import fs from 'fs'; +import { test, expect, closeElectronApp } from '../../playwright'; +import { + createCollection, + createFolder, + createWorkspace, + openfolder, + selectfolderPaneTab, + switchWorkspace, + waitForReadyPage +} from '../utils/page'; +import { buildCommonLocators } from '../utils/page/locators'; + +const readSnapshot = (userDataPath: string) => { + const snapshotPath = path.join(userDataPath, 'ui-state-snapshot.json'); + if (!fs.existsSync(snapshotPath)) return null; + return JSON.parse(fs.readFileSync(snapshotPath, 'utf-8')); +}; + +const findSnapshotFolderTab = (snapshot: any, folderName: string) => { + if (!snapshot || !Array.isArray(snapshot.collections)) return null; + for (const collection of snapshot.collections) { + if (!Array.isArray(collection?.tabs)) continue; + const tab = collection.tabs.find( + (t: any) => t?.type === 'folder-settings' && typeof t?.pathname === 'string' && t.pathname.includes(folderName) + ); + if (tab) return tab; + } + return null; +}; + +test.describe('Snapshot: folder Pane Interactivity', () => { + test('folder pane tab interactivity is preserved after workspace switch', async ({ launchElectronApp, createTmpDir }) => { + const userDataPath = await createTmpDir('snap-folder-workspace-switch'); + const colPath = await createTmpDir('col'); + + const app = await launchElectronApp({ userDataPath }); + const page = await waitForReadyPage(app); + + await test.step('Create collection and folder, open folder settings', async () => { + await createCollection(page, 'TestCol', colPath); + await createFolder(page, 'TestFolder', 'TestCol'); + await openfolder(page, 'TestCol', 'TestFolder', { persist: true }); + await selectfolderPaneTab(page, 'auth'); + }); + + await test.step('Switch to a new workspace', async () => { + await page.waitForTimeout(1000); + await createWorkspace(page, 'SecondWorkspace'); + await expect(page.getByTestId('workspace-name')).toHaveText('SecondWorkspace', { timeout: 5000 }); + }); + + await test.step('Switch back to original workspace and verify folder pane interactivity', async () => { + await switchWorkspace(page, 'My Workspace'); + await openfolder(page, 'TestCol', 'TestFolder', { persist: true }); + + const locators = buildCommonLocators(page); + + await expect(locators.tabs.folderTab('TestFolder')).toBeVisible({ timeout: 10000 }); + await locators.tabs.folderTab('TestFolder').click({ force: true }); + + await selectfolderPaneTab(page, 'auth'); + await selectfolderPaneTab(page, 'headers'); + await selectfolderPaneTab(page, 'docs'); + await selectfolderPaneTab(page, 'script'); + await selectfolderPaneTab(page, 'vars'); + }); + + await closeElectronApp(app); + }); + + test('folder pane tab interactivity is preserved after app restart', async ({ launchElectronApp, createTmpDir }) => { + const userDataPath = await createTmpDir('snap-folder-restart'); + const colPath = await createTmpDir('col'); + + const app = await launchElectronApp({ userDataPath }); + const page = await waitForReadyPage(app); + + await test.step('Create collection and folder, open folder settings on auth tab', async () => { + await createCollection(page, 'TestCol', colPath); + await createFolder(page, 'TestFolder', 'TestCol'); + await openfolder(page, 'TestCol', 'TestFolder', { persist: true }); + await selectfolderPaneTab(page, 'auth'); + }); + + await test.step('Close app and verify snapshot stores folder-settings tab', async () => { + await page.waitForTimeout(2000); + await closeElectronApp(app); + + const snapshotPath = path.join(userDataPath, 'ui-state-snapshot.json'); + await expect.poll(() => fs.existsSync(snapshotPath)).toBe(true); + + const snapshot = readSnapshot(userDataPath); + const tab = findSnapshotFolderTab(snapshot, 'TestFolder'); + expect(tab).toBeTruthy(); + expect(tab.type).toBe('folder-settings'); + expect(tab.permanent).toBe(true); + }); + + await test.step('Restart app and verify folder pane interactivity is restored', async () => { + const app2 = await launchElectronApp({ userDataPath }); + const page2 = await waitForReadyPage(app2); + + const locators = buildCommonLocators(page2); + await expect(locators.tabs.folderTab('TestFolder')).toBeVisible({ timeout: 15000 }); + await locators.tabs.folderTab('TestFolder').click({ force: true }); + + await selectfolderPaneTab(page2, 'auth'); + await selectfolderPaneTab(page2, 'headers'); + await selectfolderPaneTab(page2, 'docs'); + await selectfolderPaneTab(page2, 'script'); + await selectfolderPaneTab(page2, 'vars'); + + await closeElectronApp(app2); + }); + }); +}); diff --git a/tests/utils/page/actions.ts b/tests/utils/page/actions.ts index 05828f801..11f14cb20 100644 --- a/tests/utils/page/actions.ts +++ b/tests/utils/page/actions.ts @@ -776,6 +776,43 @@ const openRequest = async (page: Page, collectionName: string, requestName: stri } }); }; +/** + * Open a folder's settings tab by clicking on it in the sidebar + * @param page - The page object + * @param collectionName - The name of the collection + * @param folderName - The name of the folder + * @param options - Optional settings (persist: double-click to make tab permanent) + * @returns void + */ +const openfolder = async (page: Page, collectionName: string, folderName: string, { persist = false } = {}) => { + await test.step(`Open folder "${folderName}" in collection "${collectionName}"`, async () => { + const collectionContainer = page.getByTestId('sidebar-collection-row').filter({ hasText: collectionName }); + await collectionContainer.click(); + const collectionWrapper = collectionContainer.locator('..'); + const folder = collectionWrapper.getByTestId('sidebar-collection-item-row').filter({ hasText: folderName }); + if (!persist) { + await folder.click(); + } else { + await folder.dblclick(); + } + }); +}; + +/** + * Select a tab in the folder settings pane + * @param page - The page object + * @param tabName - The tab name key (e.g. 'auth', 'headers', 'docs', 'script', 'vars', 'test') + * @returns void + */ +const selectfolderPaneTab = async (page: Page, tabName: string) => { + await test.step(`Select folder pane tab "${tabName}"`, async () => { + const locators = buildCommonLocators(page); + const tab = locators.paneTabs.folderSettingsTab(tabName.toLowerCase()); + await tab.click(); + await expect(tab).toContainClass('active'); + }); +}; + /** * Open a request within a folder * @param page - The page object @@ -1530,7 +1567,9 @@ export { selectEnvironment, sendRequest, openRequest, + openfolder, openFolderRequest, + selectfolderPaneTab, getResponseBody, expectResponseContains, selectRequestPaneTab, diff --git a/tests/utils/page/locators.ts b/tests/utils/page/locators.ts index 953ceda2f..4dda96a4f 100644 --- a/tests/utils/page/locators.ts +++ b/tests/utils/page/locators.ts @@ -37,6 +37,7 @@ export const buildCommonLocators = (page: Page) => ({ }, tabs: { requestTab: (requestName: string) => page.locator('.request-tab .tab-label').filter({ hasText: requestName }), + folderTab: (folderName: string) => page.locator('.request-tab .tab-label').filter({ hasText: folderName }), activeRequestTab: () => page.locator('.request-tab.active'), closeTab: (requestName: string) => page.locator('.request-tab').filter({ hasText: requestName }).getByTestId('request-tab-close-icon'), draftIndicator: () => page.locator('.request-tab.active .has-changes-icon')