From c5804b1dd07d68b1b9672e53a8b72335e2308b34 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Wed, 30 Nov 2022 20:28:26 +0530 Subject: [PATCH 1/8] test(playwright): test for column duplicate Signed-off-by: Pranav C --- .../pages/Dashboard/Grid/Column/index.ts | 8 +++ .../playwright/tests/columnDuplicate.spec.ts | 69 +++++++++++++++++++ 2 files changed, 77 insertions(+) create mode 100644 tests/playwright/tests/columnDuplicate.spec.ts diff --git a/tests/playwright/pages/Dashboard/Grid/Column/index.ts b/tests/playwright/pages/Dashboard/Grid/Column/index.ts index 1116e886e5..b69be265a7 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/index.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/index.ts @@ -213,6 +213,14 @@ export class ColumnPageObject extends BasePage { } } + async duplicateColumn({ title, expectedTitle = `${title}_copy` }: { title: string; expectedTitle?: string }) { + await this.grid.get().locator(`th[data-title="${title}"] .nc-ui-dt-dropdown`).click(); + await this.rootPage.locator('li[role="menuitem"]:has-text("Duplicate"):visible').click(); + + await this.verifyToast({ message: 'Column duplicated successfully' }); + await this.grid.get().locator(`th[data-title="${expectedTitle}"]`).isVisible(); + } + async save({ isUpdated }: { isUpdated?: boolean } = {}) { await this.waitForResponse({ uiAction: this.get().locator('button:has-text("Save")').click(), diff --git a/tests/playwright/tests/columnDuplicate.spec.ts b/tests/playwright/tests/columnDuplicate.spec.ts new file mode 100644 index 0000000000..ce3b8b1006 --- /dev/null +++ b/tests/playwright/tests/columnDuplicate.spec.ts @@ -0,0 +1,69 @@ +import { test } from '@playwright/test'; +import { DashboardPage } from '../pages/Dashboard'; +import setup from '../setup'; + +const columns = [ + { + title: 'SingleLineText', + type: 'SingleLineText', + }, + { + title: 'LongText', + type: 'LongText', + }, + // todo: Number column creation not works + // { + // title: 'Number', + // type: 'Number', + // }, + { + title: 'Decimal', + type: 'Decimal', + }, + { + title: 'Checkbox', + type: 'Checkbox', + }, + { + title: 'Email', + type: 'Email', + }, + { + title: 'PhoneNumber', + type: 'PhoneNumber', + }, + { + title: 'Url', + type: 'Url', + }, +]; + +test.describe('Duplicate column', () => { + let dashboard: DashboardPage; + let context: any; + + test.beforeEach(async ({ page }) => { + context = await setup({ page }); + dashboard = new DashboardPage(page, context.project); + }); + + test('Duplicate text field', async () => { + await dashboard.treeView.openTable({ title: 'Film' }); + + for (const { title, type } of columns) { + await dashboard.grid.column.create({ + title, + type, + }); + + await dashboard.grid.column.duplicateColumn({ + title, + }); + await dashboard.grid.column.duplicateColumn({ + title, + expectedTitle: `${title}_copy_1`, + }); + } + await dashboard.closeTab({ title: 'Film' }); + }); +}); From 79fe6ecbae6b15d81ec35eb78db57de1f8c90552 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 1 Dec 2022 12:52:37 +0530 Subject: [PATCH 2/8] test(playwright): add test for insert before/after option Signed-off-by: Pranav C --- .../pages/Dashboard/Grid/Column/index.ts | 45 ++++++++++++++++--- ...e.spec.ts => columnMenuOperations.spec.ts} | 39 +++++++++++++++- 2 files changed, 77 insertions(+), 7 deletions(-) rename tests/playwright/tests/{columnDuplicate.spec.ts => columnMenuOperations.spec.ts} (55%) diff --git a/tests/playwright/pages/Dashboard/Grid/Column/index.ts b/tests/playwright/pages/Dashboard/Grid/Column/index.ts index b69be265a7..25dfcf1705 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/index.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/index.ts @@ -1,4 +1,4 @@ -import { expect, Page } from '@playwright/test'; +import { expect } from '@playwright/test'; import { GridPage } from '..'; import BasePage from '../../../Base'; import { SelectOptionColumnPageObject } from './SelectOptionColumn'; @@ -35,6 +35,8 @@ export class ColumnPageObject extends BasePage { relationType = '', rollupType = '', format = '', + insertAfterColumnTitle, + insertBeforeColumnTitle, }: { title: string; type?: string; @@ -45,8 +47,19 @@ export class ColumnPageObject extends BasePage { relationType?: string; rollupType?: string; format?: string; + insertBeforeColumnTitle?: string; + insertAfterColumnTitle?: string; }) { - await this.grid.get().locator('.nc-column-add').click(); + if (insertBeforeColumnTitle) { + await this.grid.get().locator(`th[data-title="${insertBeforeColumnTitle}"] .nc-ui-dt-dropdown`).click(); + await this.rootPage.locator('li[role="menuitem"]:has-text("Insert Before"):visible').click(); + } else if (insertAfterColumnTitle) { + await this.grid.get().locator(`th[data-title="${insertAfterColumnTitle}"] .nc-ui-dt-dropdown`).click(); + await this.rootPage.locator('li[role="menuitem"]:has-text("Insert After"):visible').click(); + } else { + await this.grid.get().locator('.nc-column-add').click(); + } + await this.rootPage.waitForTimeout(500); await this.fillTitle({ title }); await this.rootPage.waitForTimeout(500); @@ -54,8 +67,6 @@ export class ColumnPageObject extends BasePage { await this.rootPage.waitForTimeout(500); switch (type) { - case 'SingleTextLine': - break; case 'SingleSelect': case 'MultiSelect': await this.selectOption.addOption({ @@ -142,6 +153,30 @@ export class ColumnPageObject extends BasePage { } await this.save(); + + // verify column inserted after the target column + if (insertAfterColumnTitle) { + const headersText = await this.grid.get().locator(`th`).allTextContents(); + + await expect( + this.grid + .get() + .locator(`th`) + .nth(headersText.findIndex(title => title.startsWith(insertAfterColumnTitle)) + 1) + ).toHaveText(title); + } + + // verify column inserted before the target column + if (insertBeforeColumnTitle) { + const headersText = await this.grid.get().locator(`th`).allTextContents(); + + await expect( + this.grid + .get() + .locator(`th`) + .nth(headersText.findIndex(title => title.startsWith(insertBeforeColumnTitle)) - 1) + ).toHaveText(title); + } } async fillTitle({ title }: { title: string }) { @@ -155,7 +190,7 @@ export class ColumnPageObject extends BasePage { await this.get().locator('.ant-select-selection-search-input[aria-expanded="true"]').fill(type); // Select column type - await this.rootPage.locator('.rc-virtual-list-holder-inner > div').locator(`text="${type}"`).click(); + await this.rootPage.locator(`text=${type}:visible`).nth(1).click(); } async changeReferencedColumnForQrCode({ titleOfReferencedColumn }: { titleOfReferencedColumn: string }) { diff --git a/tests/playwright/tests/columnDuplicate.spec.ts b/tests/playwright/tests/columnMenuOperations.spec.ts similarity index 55% rename from tests/playwright/tests/columnDuplicate.spec.ts rename to tests/playwright/tests/columnMenuOperations.spec.ts index ce3b8b1006..bff597c40c 100644 --- a/tests/playwright/tests/columnDuplicate.spec.ts +++ b/tests/playwright/tests/columnMenuOperations.spec.ts @@ -38,7 +38,7 @@ const columns = [ }, ]; -test.describe('Duplicate column', () => { +test.describe('Column menu operations', () => { let dashboard: DashboardPage; let context: any; @@ -47,7 +47,7 @@ test.describe('Duplicate column', () => { dashboard = new DashboardPage(page, context.project); }); - test('Duplicate text field', async () => { + test('Duplicate fields', async () => { await dashboard.treeView.openTable({ title: 'Film' }); for (const { title, type } of columns) { @@ -66,4 +66,39 @@ test.describe('Duplicate column', () => { } await dashboard.closeTab({ title: 'Film' }); }); + test('Insert after', async () => { + await dashboard.treeView.openTable({ title: 'Film' }); + + await dashboard.grid.column.create({ + title: 'InsertAfterColumn', + type: 'SingleLineText', + insertAfterColumnTitle: 'Title', + }); + + await dashboard.grid.column.create({ + title: 'InsertAfterColumn1', + type: 'SingleLineText', + insertAfterColumnTitle: 'Store List', + }); + + await dashboard.closeTab({ title: 'Film' }); + }); + + test('Insert before', async () => { + await dashboard.treeView.openTable({ title: 'Film' }); + + await dashboard.grid.column.create({ + title: 'InsertBeforeColumn', + type: 'SingleLineText', + insertBeforeColumnTitle: 'Title', + }); + + await dashboard.grid.column.create({ + title: 'InsertBeforeColumn1', + type: 'SingleLineText', + insertBeforeColumnTitle: 'Store List', + }); + + await dashboard.closeTab({ title: 'Film' }); + }); }); From 96af879d0dfc0c60c802144103e1cacf241ff4d2 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 1 Dec 2022 13:05:17 +0530 Subject: [PATCH 3/8] test(playwright): add test for hide field option Signed-off-by: Pranav C --- .../pages/Dashboard/Grid/Column/index.ts | 7 +++++++ .../playwright/tests/columnMenuOperations.spec.ts | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/tests/playwright/pages/Dashboard/Grid/Column/index.ts b/tests/playwright/pages/Dashboard/Grid/Column/index.ts index 25dfcf1705..f0a6fe9d2a 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/index.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/index.ts @@ -256,6 +256,13 @@ export class ColumnPageObject extends BasePage { await this.grid.get().locator(`th[data-title="${expectedTitle}"]`).isVisible(); } + async hideColumn({ title }: { title: string }) { + await this.grid.get().locator(`th[data-title="${title}"] .nc-ui-dt-dropdown`).click(); + await this.rootPage.locator('li[role="menuitem"]:has-text("Hide Field"):visible').click(); + + await expect(this.grid.get().locator(`th[data-title="${title}"]`)).toHaveCount(0); + } + async save({ isUpdated }: { isUpdated?: boolean } = {}) { await this.waitForResponse({ uiAction: this.get().locator('button:has-text("Save")').click(), diff --git a/tests/playwright/tests/columnMenuOperations.spec.ts b/tests/playwright/tests/columnMenuOperations.spec.ts index bff597c40c..f7725e3237 100644 --- a/tests/playwright/tests/columnMenuOperations.spec.ts +++ b/tests/playwright/tests/columnMenuOperations.spec.ts @@ -101,4 +101,18 @@ test.describe('Column menu operations', () => { await dashboard.closeTab({ title: 'Film' }); }); + + test('Hide column', async () => { + await dashboard.treeView.openTable({ title: 'Film' }); + + await dashboard.grid.column.hideColumn({ + title: 'Title', + }); + + await dashboard.grid.column.hideColumn({ + title: 'Store List', + }); + + await dashboard.closeTab({ title: 'Film' }); + }); }); From b5c06a537a8a54b7e33bc65bec7ab5d8a809e8a1 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 1 Dec 2022 13:52:41 +0530 Subject: [PATCH 4/8] test(playwright): test for add sort options in column menu Signed-off-by: Pranav C --- .../pages/Dashboard/Grid/Column/index.ts | 30 +++++++++++++++++++ .../tests/columnMenuOperations.spec.ts | 16 ++++++++++ 2 files changed, 46 insertions(+) diff --git a/tests/playwright/pages/Dashboard/Grid/Column/index.ts b/tests/playwright/pages/Dashboard/Grid/Column/index.ts index f0a6fe9d2a..7c599d1211 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/index.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/index.ts @@ -295,4 +295,34 @@ export class ColumnPageObject extends BasePage { await this.grid.get().locator('.nc-ui-dt-dropdown:visible').first().click(); } } + + async sortColumn({ title, direction = 'asc' }: { title: string; direction: 'asc' | 'desc' }) { + await this.grid.get().locator(`th[data-title="${title}"] .nc-ui-dt-dropdown`).click(); + let menuOption; + if (direction === 'desc') { + menuOption = this.rootPage.locator('li[role="menuitem"]:has-text("Sort Descending"):visible').click(); + } else { + menuOption = this.rootPage.locator('li[role="menuitem"]:has-text("Sort Ascending"):visible').click(); + } + + await this.waitForResponse({ + uiAction: menuOption, + httpMethodsToMatch: ['POST'], + requestUrlPathToMatch: `/sorts`, + }); + + await this.grid.toolbar.parent.dashboard.waitForLoaderToDisappear(); + + await this.grid.toolbar.clickSort(); + + await this.rootPage.locator(`.ant-select-selection-item:has-text("${title}")`).first().isVisible(); + await this.rootPage + .locator( + `.nc-sort-dir-select:has-text("${direction === 'asc' ? '1 → 9' : '9 → 1'}"),.nc-sort-dir-select:has-text("${ + direction === 'asc' ? 'A → Z' : 'Z → A' + }")` + ) + .first() + .isVisible(); + } } diff --git a/tests/playwright/tests/columnMenuOperations.spec.ts b/tests/playwright/tests/columnMenuOperations.spec.ts index f7725e3237..6f473b0579 100644 --- a/tests/playwright/tests/columnMenuOperations.spec.ts +++ b/tests/playwright/tests/columnMenuOperations.spec.ts @@ -115,4 +115,20 @@ test.describe('Column menu operations', () => { await dashboard.closeTab({ title: 'Film' }); }); + + test('Sort column', async () => { + await dashboard.treeView.openTable({ title: 'Film' }); + + await dashboard.grid.column.sortColumn({ + title: 'Title', + direction: 'asc', + }); + + await dashboard.grid.column.sortColumn({ + title: 'ReleaseYear', + direction: 'desc', + }); + + await dashboard.closeTab({ title: 'Film' }); + }); }); From 51834d8a788e6e50a7aba4c06e63507d283f8880 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 1 Dec 2022 14:31:43 +0530 Subject: [PATCH 5/8] chore(github-action): add test folder in ci-cd trigger filter Signed-off-by: Pranav C --- .github/workflows/ci-cd.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml index 8a7cb36d56..2b3c64550b 100644 --- a/.github/workflows/ci-cd.yml +++ b/.github/workflows/ci-cd.yml @@ -18,6 +18,7 @@ on: - "packages/nc-gui/**" - "packages/nocodb/**" - ".github/workflows/ci-cd.yml" + - "tests/playwright/**" concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} @@ -97,4 +98,4 @@ jobs: uses: ./.github/workflows/playwright-test-workflow.yml with: db: pg - shard: 2 \ No newline at end of file + shard: 2 From 3d753343327b0ff1fe63febfa19cc61ecc377d08 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 1 Dec 2022 14:49:39 +0530 Subject: [PATCH 6/8] chore(gui): move label to i18n Signed-off-by: Pranav C --- .../components/smartsheet/header/Menu.vue | 30 +++++++++++-------- packages/nc-gui/lang/en.json | 8 ++++- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/header/Menu.vue b/packages/nc-gui/components/smartsheet/header/Menu.vue index 411a3877fe..ac2d15d5fe 100644 --- a/packages/nc-gui/components/smartsheet/header/Menu.vue +++ b/packages/nc-gui/components/smartsheet/header/Menu.vue @@ -225,23 +225,26 @@ const hideField = async () => { -
+
- Hide Field + + {{ $t('general.hideField') }}
@@ -251,21 +254,24 @@ const hideField = async () => { v-if="column.uidt !== UITypes.LinkToAnotherRecord && column.uidt !== UITypes.Lookup && !column.pk" @click="duplicateColumn" > -
+
- Duplicate + + {{ t('general.duplicate') }}
-
+
- Insert After + + {{ t('general.insertAfter') }}
-
+
- Insert before + + {{ t('general.insertBefore') }}
diff --git a/packages/nc-gui/lang/en.json b/packages/nc-gui/lang/en.json index 09c4984f1c..c2cb7b8909 100644 --- a/packages/nc-gui/lang/en.json +++ b/packages/nc-gui/lang/en.json @@ -69,7 +69,13 @@ "betaNote": "This feature is currently in beta.", "moreInfo": "More information can be found here", "logs": "Logs", - "groupingField": "Grouping Field" + "groupingField": "Grouping Field", + "duplicate": "Duplicate", + "insertAfter": "Insert After", + "insertBefore": "Insert Before", + "hideField": "Hide Field", + "sortAsc": "Sort Ascending", + "sortDesc": "Sort Descending" }, "objects": { "project": "Project", From d70b18f50b29b27ea8022fcf974d04bb7f6b5539 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 1 Dec 2022 15:33:59 +0530 Subject: [PATCH 7/8] test(playwright): corrections Signed-off-by: Pranav C --- .../nc-gui/components/smartsheet/header/Menu.vue | 12 ++++++------ .../playwright/pages/Dashboard/Grid/Column/index.ts | 9 +++++++-- .../playwright/pages/Dashboard/common/Cell/index.ts | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/nc-gui/components/smartsheet/header/Menu.vue b/packages/nc-gui/components/smartsheet/header/Menu.vue index ac2d15d5fe..bbd30a8ddb 100644 --- a/packages/nc-gui/components/smartsheet/header/Menu.vue +++ b/packages/nc-gui/components/smartsheet/header/Menu.vue @@ -225,14 +225,14 @@ const hideField = async () => { -
+
{{ $t('general.hideField') }} @@ -254,21 +254,21 @@ const hideField = async () => { v-if="column.uidt !== UITypes.LinkToAnotherRecord && column.uidt !== UITypes.Lookup && !column.pk" @click="duplicateColumn" > -
+
{{ t('general.duplicate') }}
-
+
{{ t('general.insertAfter') }}
-
+
{{ t('general.insertBefore') }} diff --git a/tests/playwright/pages/Dashboard/Grid/Column/index.ts b/tests/playwright/pages/Dashboard/Grid/Column/index.ts index 7c599d1211..48107c7800 100644 --- a/tests/playwright/pages/Dashboard/Grid/Column/index.ts +++ b/tests/playwright/pages/Dashboard/Grid/Column/index.ts @@ -190,7 +190,7 @@ export class ColumnPageObject extends BasePage { await this.get().locator('.ant-select-selection-search-input[aria-expanded="true"]').fill(type); // Select column type - await this.rootPage.locator(`text=${type}:visible`).nth(1).click(); + await this.rootPage.locator('.rc-virtual-list-holder-inner > div').locator(`text="${type}"`).click(); } async changeReferencedColumnForQrCode({ titleOfReferencedColumn }: { titleOfReferencedColumn: string }) { @@ -258,7 +258,12 @@ export class ColumnPageObject extends BasePage { async hideColumn({ title }: { title: string }) { await this.grid.get().locator(`th[data-title="${title}"] .nc-ui-dt-dropdown`).click(); - await this.rootPage.locator('li[role="menuitem"]:has-text("Hide Field"):visible').click(); + + await this.waitForResponse({ + uiAction: this.rootPage.locator('li[role="menuitem"]:has-text("Hide Field"):visible').click(), + requestUrlPathToMatch: 'api/v1/db/meta/views', + httpMethodsToMatch: ['PATCH'], + }); await expect(this.grid.get().locator(`th[data-title="${title}"]`)).toHaveCount(0); } diff --git a/tests/playwright/pages/Dashboard/common/Cell/index.ts b/tests/playwright/pages/Dashboard/common/Cell/index.ts index ca04a11b83..22052a2ca6 100644 --- a/tests/playwright/pages/Dashboard/common/Cell/index.ts +++ b/tests/playwright/pages/Dashboard/common/Cell/index.ts @@ -193,6 +193,6 @@ export class CellPageObject extends BasePage { ) { await this.get({ index, columnHeader }).click(...clickOptions); - await this.get({ index, columnHeader }).press('Control+C'); + await this.get({ index, columnHeader }).press((await this.isMacOs()) ? 'Meta+C' : 'Control+C'); } } From e62da927b582533a14af8ec6cdd8a9f817e11415 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Thu, 1 Dec 2022 15:50:09 +0530 Subject: [PATCH 8/8] test(playwright): type correction Url => URL Signed-off-by: Pranav C --- tests/playwright/tests/columnMenuOperations.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/playwright/tests/columnMenuOperations.spec.ts b/tests/playwright/tests/columnMenuOperations.spec.ts index 6f473b0579..8217fd6964 100644 --- a/tests/playwright/tests/columnMenuOperations.spec.ts +++ b/tests/playwright/tests/columnMenuOperations.spec.ts @@ -34,7 +34,7 @@ const columns = [ }, { title: 'Url', - type: 'Url', + type: 'URL', }, ];