diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js index c1b4aa7f9..afac7998a 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/tabs.js @@ -344,7 +344,8 @@ export const tabsSlice = createSlice({ if (siblingTabs && siblingTabs.length) { state.activeTabUid = last(siblingTabs).uid; } else { - state.activeTabUid = last(state.tabs).uid; + const overviewTab = find(state.tabs, (t) => t.type === 'workspaceOverview'); + state.activeTabUid = overviewTab ? overviewTab.uid : last(state.tabs).uid; } } } @@ -360,7 +361,12 @@ export const tabsSlice = createSlice({ const activeTabStillExists = state.tabs.some((t) => t.uid === prevActiveTabUid); if (!activeTabStillExists) { - state.activeTabUid = state.tabs.length > 0 ? last(state.tabs).uid : null; + if (state.tabs.length === 0) { + state.activeTabUid = null; + } else { + const overviewTab = find(state.tabs, (t) => t.type === 'workspaceOverview'); + state.activeTabUid = overviewTab ? overviewTab.uid : last(state.tabs).uid; + } } }, makeTabPermanent: (state, action) => { diff --git a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/getTabToFocusForCurrentWorkspace.js b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/getTabToFocusForCurrentWorkspace.js index 0274adbc8..fed34de73 100644 --- a/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/getTabToFocusForCurrentWorkspace.js +++ b/packages/bruno-app/src/providers/ReduxStore/slices/workspaces/getTabToFocusForCurrentWorkspace.js @@ -54,7 +54,8 @@ export function getTabToFocusForCurrentWorkspace(state) { } const inWorkspaceTabs = filter(state.tabs.tabs, (t) => workspaceCollectionUids.has(t.collectionUid)); if (inWorkspaceTabs.length > 0) { - return { uid: last(inWorkspaceTabs).uid }; + const overviewTab = inWorkspaceTabs.find((t) => t.type === 'workspaceOverview'); + return { uid: (overviewTab || last(inWorkspaceTabs)).uid }; } const scratchCollectionUid = activeWorkspace.scratchCollectionUid; if (!scratchCollectionUid) { diff --git a/tests/shortcuts/bound-actions.spec.ts b/tests/shortcuts/bound-actions.spec.ts index 32c2e875c..d0c873815 100644 --- a/tests/shortcuts/bound-actions.spec.ts +++ b/tests/shortcuts/bound-actions.spec.ts @@ -242,7 +242,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { test.describe('SHORTCUT: Save', () => { test('default Cmd/Ctrl+S save tab', async ({ page, createTmpDir }) => { - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 }); // Verify initially there is NO draft indicator (close icon is present) @@ -295,7 +295,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await closePreferencesTab(page); - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 }); // Verify initially there is NO draft indicator (close icon is present) @@ -336,7 +336,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { test.describe('SHORTCUT: Save All Tabs', () => { test('default Cmd/Ctrl+Shift+S save all tabs', async ({ page }) => { - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 }); // Verify initially there is NO draft indicator (close icon is present) @@ -422,7 +422,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await closePreferencesTab(page); - await page.locator('.collection-name').filter({ hasText: collectionName }).dblclick(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: collectionName }).dblclick(); await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 }); // Verify initially there is NO draft indicator (close icon is present) @@ -801,7 +801,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await openRequest(page, collectionName, 'req-2', { persist: true }); // Open Collection-Settings tab (double-click collection name) - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 }); // Open Runner tab @@ -923,7 +923,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await page.keyboard.up('KeyN'); await page.keyboard.up('Alt'); - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); await page.keyboard.down('Alt'); await page.keyboard.down('KeyN'); @@ -946,7 +946,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await page.keyboard.up('KeyY'); await page.keyboard.up('Alt'); - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).dblclick(); await openRequest(page, 'kb-collection', 'req-1', { persist: true }); await page.keyboard.press(`${modifier}+KeyR`); @@ -996,7 +996,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await page.keyboard.up('KeyY'); await page.keyboard.up('Alt'); - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); await page.keyboard.press(`${modifier}+KeyR`); // Verify rename modal opens @@ -1011,7 +1011,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await page.locator('.submit').click(); // Verify renamed request appears in sidebar - await expect(page.locator('.collection-name').filter({ hasText: 'kb-collection-renamed' })).toBeVisible({ timeout: 3000 }); + await expect(page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection-renamed' })).toBeVisible({ timeout: 3000 }); }); test('customized Alt+X open rename item modal for request', async ({ page, createTmpDir }) => { @@ -1097,7 +1097,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await page.keyboard.press('Alt+KeyX'); }); - await page.locator('.collection-name').filter({ hasText: collectionName }).click(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: collectionName }).click(); await page.keyboard.down('Alt'); await page.keyboard.down('KeyX'); await page.keyboard.up('KeyX'); @@ -1115,7 +1115,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await page.locator('.submit').click(); // Verify renamed request appears in sidebar - await expect(page.locator('.collection-name').filter({ hasText: 'kb-collection-renamed-altx' })).toBeVisible({ timeout: 2000 }); + await expect(page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection-renamed-altx' })).toBeVisible({ timeout: 2000 }); }); }); @@ -1417,7 +1417,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { test.describe('SHORTCUT: Open Terminal', () => { test('default Cmd/Ctrl+T opens terminal', async ({ page, createTmpDir }) => { // Open Collection-Settings tab (double-click collection name) - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 }); // Press Cmd/Ctrl+T to open terminal at workspace level @@ -1467,7 +1467,7 @@ test.describe('Shortcut Keys - BOUND_ACTIONS', () => { await page.keyboard.up('KeyT'); await page.keyboard.up('Alt'); - await page.locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); + await page.getByTestId('collections').locator('.collection-name').filter({ hasText: 'kb-collection' }).click(); await expect(page.locator('.request-tab').filter({ hasText: 'collection' })).toBeVisible({ timeout: 2000 }); // Press Cmd/Ctrl+T to open terminal at workspace level diff --git a/tests/workspace/close-all-tabs-lands-on-overview.spec.ts b/tests/workspace/close-all-tabs-lands-on-overview.spec.ts new file mode 100644 index 000000000..13508fec3 --- /dev/null +++ b/tests/workspace/close-all-tabs-lands-on-overview.spec.ts @@ -0,0 +1,51 @@ +import { test, expect, closeElectronApp } from '../../playwright'; +import { + createCollection, + createRequest, + openRequest, + waitForReadyPage +} from '../utils/page'; +import { buildCommonLocators } from '../utils/page/locators'; + +test.describe('Close all tabs lands on workspace overview', () => { + test('closing the last request tab focuses the workspace Overview tab', async ({ + launchElectronApp, + createTmpDir + }) => { + const userDataPath = await createTmpDir('close-all-tabs-overview'); + const collectionPath = await createTmpDir('col-overview'); + + let app; + try { + app = await launchElectronApp({ userDataPath }); + const page = await waitForReadyPage(app); + const locators = buildCommonLocators(page); + + await test.step('Create a collection and open two requests', async () => { + await createCollection(page, 'ColOverview', collectionPath); + await createRequest(page, 'ReqOne', 'ColOverview', { url: 'https://echo.usebruno.com', method: 'GET' }); + await createRequest(page, 'ReqTwo', 'ColOverview', { url: 'https://echo.usebruno.com', method: 'GET' }); + await openRequest(page, 'ColOverview', 'ReqOne', { persist: true }); + await openRequest(page, 'ColOverview', 'ReqTwo', { persist: true }); + await expect(locators.tabs.requestTab('ReqOne')).toBeVisible(); + await expect(locators.tabs.requestTab('ReqTwo')).toBeVisible(); + }); + + await test.step('Close both request tabs', async () => { + await locators.tabs.closeTab('ReqTwo').click({ force: true }); + await expect(locators.tabs.requestTab('ReqTwo')).toHaveCount(0); + await locators.tabs.closeTab('ReqOne').click({ force: true }); + await expect(locators.tabs.requestTab('ReqOne')).toHaveCount(0); + }); + + await test.step('Active tab must be the workspace Overview, not Environments', async () => { + const activeTab = locators.tabs.activeRequestTab(); + await expect(activeTab).toBeVisible({ timeout: 5000 }); + await expect(activeTab.locator('.tab-label')).toHaveText('Overview'); + await expect(activeTab.locator('.tab-label')).not.toHaveText('Environments'); + }); + } finally { + if (app) await closeElectronApp(app); + } + }); +});