From 0aa003dd2cd0d9b0fde9f7ef0fcaf4ac555cab3a Mon Sep 17 00:00:00 2001 From: Sergey Petushkov Date: Tue, 25 Jun 2024 18:02:12 +0200 Subject: [PATCH] chore: add e2e tests for tab behavior --- .../helpers/commands/close-workspace-tabs.ts | 11 +- .../helpers/commands/collection-workspaces.ts | 24 ++-- .../compass-e2e-tests/helpers/selectors.ts | 7 +- packages/compass-e2e-tests/tests/tabs.test.ts | 115 ++++++++++++++++++ .../src/stores/workspaces.ts | 1 + 5 files changed, 149 insertions(+), 9 deletions(-) create mode 100644 packages/compass-e2e-tests/tests/tabs.test.ts diff --git a/packages/compass-e2e-tests/helpers/commands/close-workspace-tabs.ts b/packages/compass-e2e-tests/helpers/commands/close-workspace-tabs.ts index 3dce959b54c..abf855745f7 100644 --- a/packages/compass-e2e-tests/helpers/commands/close-workspace-tabs.ts +++ b/packages/compass-e2e-tests/helpers/commands/close-workspace-tabs.ts @@ -2,7 +2,8 @@ import type { CompassBrowser } from '../compass-browser'; import * as Selectors from '../selectors'; export async function closeWorkspaceTabs( - browser: CompassBrowser + browser: CompassBrowser, + autoConfirmTabClose = true ): Promise { const countTabs = async () => { return (await browser.$$(Selectors.workspaceTab(null))).length; @@ -15,6 +16,14 @@ export async function closeWorkspaceTabs( await currentActiveTab.click(); await browser.waitUntil(async () => { await currentActiveTab.$(Selectors.CloseWorkspaceTab).click(); + if (autoConfirmTabClose) { + // Tabs in "dirty" state can't be closed without confirmation + if (await browser.$(Selectors.ConfirmTabCloseModal).isExisting()) { + await browser.clickVisible( + browser.$(Selectors.ConfirmTabCloseModal).$('button=Close tab') + ); + } + } return (await currentActiveTab.isExisting()) === false; }); } diff --git a/packages/compass-e2e-tests/helpers/commands/collection-workspaces.ts b/packages/compass-e2e-tests/helpers/commands/collection-workspaces.ts index 4456568c1ad..7399dca5ee5 100644 --- a/packages/compass-e2e-tests/helpers/commands/collection-workspaces.ts +++ b/packages/compass-e2e-tests/helpers/commands/collection-workspaces.ts @@ -5,17 +5,21 @@ async function navigateToCollection( browser: CompassBrowser, // TODO(COMPASS-8002): take connectionName into account dbName: string, - collectionName: string + collectionName: string, + + // Close all the workspace tabs to get rid of all the state we + // might have accumulated. This is the only way to get back to the zero + // state of Schema, and Validation tabs without re-connecting. + closeExistingTabs = true ): Promise { const collectionSelector = Selectors.sidebarCollection( dbName, collectionName ); - // Close all the workspace tabs to get rid of all the state we - // might have accumulated. This is the only way to get back to the zero - // state of Schema, and Validation tabs without re-connecting. - await browser.closeWorkspaceTabs(); + if (closeExistingTabs) { + await browser.closeWorkspaceTabs(); + } // search for the collection and wait for the collection to be there and visible await browser.clickVisible(Selectors.SidebarFilterInput); @@ -39,9 +43,15 @@ export async function navigateToCollectionTab( | 'Aggregations' | 'Schema' | 'Indexes' - | 'Validation' = 'Documents' + | 'Validation' = 'Documents', + closeExistingTabs = true ): Promise { - await navigateToCollection(browser, dbName, collectionName); + await navigateToCollection( + browser, + dbName, + collectionName, + closeExistingTabs + ); await navigateWithinCurrentCollectionTabs(browser, tabName); } diff --git a/packages/compass-e2e-tests/helpers/selectors.ts b/packages/compass-e2e-tests/helpers/selectors.ts index 52a3d98d362..4e052449dc7 100644 --- a/packages/compass-e2e-tests/helpers/selectors.ts +++ b/packages/compass-e2e-tests/helpers/selectors.ts @@ -1158,6 +1158,8 @@ export const sidebarInstanceNavigationItem = ( return `${Sidebar} [aria-label="${tabName}"]`; }; export const SidebarMyQueriesTab = `${Sidebar} [aria-label="My Queries"]`; +export const WorkspaceTab = + '[role="tablist"][aria-label="Workspace Tabs"] [role="tab"]'; export const workspaceTab = ( title: string | null, active: boolean | null = null @@ -1169,7 +1171,7 @@ export const workspaceTab = ( : ['My Queries', 'Performance', 'Databases'].includes(title) ? `[title="${title}"]` : `[data-namespace="${title}"]`; - return `[role="tablist"][aria-label="Workspace Tabs"] [role="tab"]${_title}${_active}`; + return `${WorkspaceTab}${_title}${_active}`; }; export const instanceWorkspaceTab = ( tabName: 'Performance' | 'Databases', @@ -1301,3 +1303,6 @@ export const AgreeAndContinueButton = 'button=Agree and continue'; // Any toast export const AnyToastDismissButton = '[data-testid="lg-toast-dismiss-button"]'; + +// Close tab confirmation +export const ConfirmTabCloseModal = '[data-testid="confirm-tab-close"]'; diff --git a/packages/compass-e2e-tests/tests/tabs.test.ts b/packages/compass-e2e-tests/tests/tabs.test.ts new file mode 100644 index 00000000000..9b785a43961 --- /dev/null +++ b/packages/compass-e2e-tests/tests/tabs.test.ts @@ -0,0 +1,115 @@ +import type { CompassBrowser } from '../helpers/compass-browser'; +import { init, cleanup, screenshotIfFailed } from '../helpers/compass'; +import type { Compass } from '../helpers/compass'; +import * as Selectors from '../helpers/selectors'; +import { createNumbersCollection } from '../helpers/insert-data'; +import { expect } from 'chai'; + +describe('Global Tabs', function () { + let compass: Compass; + let browser: CompassBrowser; + + const collections = ['a', 'b', 'c']; + + before(async function () { + compass = await init(this.test?.fullTitle()); + browser = compass.browser; + }); + + beforeEach(async function () { + for (const collName of collections) { + await createNumbersCollection(collName, 1); + await createNumbersCollection(collName, 1); + await createNumbersCollection(collName, 1); + } + await browser.connectWithConnectionString(); + }); + + afterEach(async function () { + await screenshotIfFailed(compass, this.currentTest); + }); + + after(async function () { + await cleanup(compass); + }); + + it('should open tabs over each other when not modified', async function () { + for (const collName of collections) { + await browser.navigateToCollectionTab( + 'test', + collName, + 'Documents', + false + ); + } + expect(await browser.$$(Selectors.workspaceTab(null))).to.have.lengthOf(1); + }); + + it('should open tabs over each other when not modified', async function () { + for (const collName of collections) { + await browser.navigateToCollectionTab( + 'test', + collName, + 'Documents', + false + ); + // Click something to make sure we "modified" the tab + await browser.clickVisible(Selectors.queryBar('Documents')); + } + expect(await browser.$$(Selectors.workspaceTab(null))).to.have.lengthOf(3); + }); + + it('should close tabs without warning even when "modified" by interacting with the tab', async function () { + for (const collName of collections) { + await browser.navigateToCollectionTab( + 'test', + collName, + 'Documents', + false + ); + // Click something to make sure we "modified" the tab + await browser.clickVisible(Selectors.queryBar('Documents')); + } + await browser.closeWorkspaceTabs(false); + expect(await browser.$$(Selectors.workspaceTab(null))).to.have.lengthOf(0); + }); + + it('should ask for confirmation when closing modified Aggregations tab', async function () { + await browser.navigateToCollectionTab('test', 'a', 'Aggregations'); + + await browser.clickVisible( + Selectors.aggregationPipelineModeToggle('as-text') + ); + + await browser.setCodemirrorEditorValue( + Selectors.AggregationAsTextEditor, + '[{$match: { i: 0 }}]' + ); + + await browser.clickVisible(Selectors.CloseWorkspaceTab); + await browser.$(Selectors.ConfirmTabCloseModal).waitForDisplayed(); + + await browser.clickVisible( + browser.$(Selectors.ConfirmTabCloseModal).$('button=Cancel') + ); + await browser + .$(Selectors.ConfirmTabCloseModal) + .waitForExist({ reverse: true }); + + // Checking first that cancel leaves the tab on the screen + expect(await browser.$$(Selectors.workspaceTab(null))).to.have.lengthOf(1); + + await browser.clickVisible(Selectors.CloseWorkspaceTab); + await browser.$(Selectors.ConfirmTabCloseModal).waitForDisplayed(); + + await browser.clickVisible( + browser.$(Selectors.ConfirmTabCloseModal).$('button=Close tab') + ); + await browser + .$(Selectors.ConfirmTabCloseModal) + .waitForExist({ reverse: true }); + + // When confirmed, should remove the tab + expect(await browser.$$(Selectors.workspaceTab(null))).to.have.lengthOf(0); + }); +}); diff --git a/packages/compass-workspaces/src/stores/workspaces.ts b/packages/compass-workspaces/src/stores/workspaces.ts index cd562db45cb..1b25e807193 100644 --- a/packages/compass-workspaces/src/stores/workspaces.ts +++ b/packages/compass-workspaces/src/stores/workspaces.ts @@ -768,6 +768,7 @@ export const closeTab = ( 'The content of this tab has been modified. You will lose your changes if you close it.', buttonText: 'Close tab', variant: 'danger', + 'data-testid': 'confirm-tab-close', }); if (!confirmClose) { return;