From d62f2cccfc4cf4cbf2061323ff234d5c692d9984 Mon Sep 17 00:00:00 2001 From: Pranav C Date: Tue, 18 Jun 2024 19:06:18 +0000 Subject: [PATCH] tests: playwright --- .../dashboard/settings/DataSources.vue | 8 +- .../settings/data-sources/CreateBase.vue | 4 +- .../settings/data-sources/EditBase.vue | 4 +- .../pages/Dashboard/Settings/Source.ts | 44 ++++++++++ .../pages/Dashboard/Settings/index.ts | 3 + tests/playwright/pages/Dashboard/TreeView.ts | 8 +- .../db/general/sourceRestrictions.spec.ts | 83 +++++++++++++++++++ 7 files changed, 140 insertions(+), 14 deletions(-) create mode 100644 tests/playwright/pages/Dashboard/Settings/Source.ts create mode 100644 tests/playwright/tests/db/general/sourceRestrictions.spec.ts diff --git a/packages/nc-gui/components/dashboard/settings/DataSources.vue b/packages/nc-gui/components/dashboard/settings/DataSources.vue index ca1a0bde0b..9df14a0fa4 100644 --- a/packages/nc-gui/components/dashboard/settings/DataSources.vue +++ b/packages/nc-gui/components/dashboard/settings/DataSources.vue @@ -260,7 +260,7 @@ const openedTab = ref('erd') - + - +
diff --git a/tests/playwright/pages/Dashboard/Settings/Source.ts b/tests/playwright/pages/Dashboard/Settings/Source.ts new file mode 100644 index 0000000000..70d2456b14 --- /dev/null +++ b/tests/playwright/pages/Dashboard/Settings/Source.ts @@ -0,0 +1,44 @@ +import { expect } from '@playwright/test'; +import { SettingsPage } from '.'; +import BasePage from '../../Base'; + +export class SourcePage extends BasePage { + private readonly settings: SettingsPage; + + constructor(settings: SettingsPage) { + super(settings.rootPage); + this.settings = settings; + } + + get() { + return this.rootPage.getByTestId('nc-settings-datasources'); + } + + async openEditWindow({ sourceName }: { sourceName: string }) { + await this.get().locator('.ds-table-row', { hasText: sourceName }).click(); + await this.get().getByTestId('nc-connection-tab').click(); + } + + async updateSchemaReadOnly({ sourceName, readOnly }: { sourceName: string; readOnly: boolean }) { + await this.openEditWindow({ sourceName }); + const switchBtn = this.get().getByTestId('nc-allow-meta-write'); + if (switchBtn.getAttribute('checked') !== readOnly.toString()) { + await switchBtn.click(); + } + await this.saveConnection(); + } + + async updateDataReadOnly({ sourceName, readOnly = true }: { sourceName: string; readOnly?: boolean }) { + await this.openEditWindow({ sourceName }); + const switchBtn = this.get().getByTestId('nc-allow-data-write'); + if (switchBtn.getAttribute('checked') !== readOnly.toString()) { + await switchBtn.click(); + } + await this.saveConnection(); + } + + async saveConnection() { + await this.get().locator('.nc-extdb-btn-test-connection').click(); + await this.get().locator('.nc-extdb-btn-submit:enabled').click(); + } +} diff --git a/tests/playwright/pages/Dashboard/Settings/index.ts b/tests/playwright/pages/Dashboard/Settings/index.ts index dfe12a127d..e2adc3329a 100644 --- a/tests/playwright/pages/Dashboard/Settings/index.ts +++ b/tests/playwright/pages/Dashboard/Settings/index.ts @@ -4,6 +4,7 @@ import { AuditSettingsPage } from './Audit'; import { MiscSettingsPage } from './Miscellaneous'; import { TeamsPage } from './Teams'; import { DataSourcesPage } from './DataSources'; +import { SourcePage } from './Source'; export enum SettingTab { TeamAuth = 'teamAndAuth', @@ -20,6 +21,7 @@ export enum SettingsSubTab { export class SettingsPage extends BasePage { readonly audit: AuditSettingsPage; + readonly source: SourcePage; readonly miscellaneous: MiscSettingsPage; readonly dataSources: DataSourcesPage; readonly teams: TeamsPage; @@ -30,6 +32,7 @@ export class SettingsPage extends BasePage { this.miscellaneous = new MiscSettingsPage(this); this.dataSources = new DataSourcesPage(this); this.teams = new TeamsPage(this); + this.source = new SourcePage(this); } get() { diff --git a/tests/playwright/pages/Dashboard/TreeView.ts b/tests/playwright/pages/Dashboard/TreeView.ts index b8e808eda3..d7847114e8 100644 --- a/tests/playwright/pages/Dashboard/TreeView.ts +++ b/tests/playwright/pages/Dashboard/TreeView.ts @@ -366,16 +366,12 @@ export class TreeViewPage extends BasePage { await this.rootPage.locator('div.ant-modal-content').locator(`button.ant-btn:has-text("Delete")`).click(); } - async duplicateProject(param: { title: string; context: NcContext }) { + async openProjectSourceSettings(param: { title: string; context: NcContext }) { param.title = this.scopedProjectTitle({ title: param.title, context: param.context }); await this.openProjectContextMenu({ baseTitle: param.title }); const contextMenu = this.dashboard.get().locator('.ant-dropdown-menu.nc-scrollbar-md:visible'); await contextMenu.waitFor(); - await contextMenu.locator(`.ant-dropdown-menu-item:has-text("Duplicate")`).click(); - - await this.rootPage.locator('div.ant-modal-content').locator(`button.ant-btn:has-text("Confirm")`).click(); - - await this.rootPage.waitForTimeout(10000); + await contextMenu.locator(`.ant-dropdown-menu-item:has-text("Settings")`).click(); } } diff --git a/tests/playwright/tests/db/general/sourceRestrictions.spec.ts b/tests/playwright/tests/db/general/sourceRestrictions.spec.ts new file mode 100644 index 0000000000..de6c1e00b1 --- /dev/null +++ b/tests/playwright/tests/db/general/sourceRestrictions.spec.ts @@ -0,0 +1,83 @@ +import { expect, test } from '@playwright/test'; +import { DashboardPage } from '../../../pages/Dashboard'; +import setup, { NcContext, unsetup } from '../../../setup'; +import { Api } from 'nocodb-sdk'; +import { SettingsPage } from '../../../pages/Dashboard/Settings'; + +test.describe('Source Restrictions', () => { + let dashboard: DashboardPage; + let settingsPage: SettingsPage; + let context: NcContext; + let api: Api; + test.setTimeout(150000); + + test.beforeEach(async ({ page }) => { + page.setDefaultTimeout(70000); + context = await setup({ page }); + dashboard = new DashboardPage(page, context.base); + settingsPage = new SettingsPage(dashboard); + api = new Api({ + baseURL: `http://localhost:8080/`, + headers: { + 'xc-auth': context.token, + }, + }); + }); + + test.afterEach(async () => { + await unsetup(context); + }); + + test('Readonly data source', async () => { + await dashboard.treeView.openProjectSourceSettings({ title: context.defaultProjectTitle, context }); + + await settingsPage.selectTab({ tab: 'dataSources' }); + await dashboard.rootPage.waitForTimeout(300); + + await settingsPage.source.updateDataReadOnly({ sourceName: 'Default', readOnly: true }); + await settingsPage.close(); + + // reload page to reflect source changes + await dashboard.rootPage.reload(); + + await dashboard.treeView.verifyTable({ title: 'Actor' }); + + // open table and verify that it is readonly + await dashboard.treeView.openTable({ title: 'Actor' }); + await expect(dashboard.grid.get().locator('.nc-grid-add-new-cell')).toHaveCount(0); + + await dashboard.grid.get().getByTestId(`cell-FirstName-0`).click({ + button: 'right', + }); + + await expect(dashboard.rootPage.locator('.ant-dropdown-menu-item:has-text("Copy")')).toHaveCount(1); + await expect(dashboard.rootPage.locator('.ant-dropdown-menu-item:has-text("Delete record")')).toHaveCount(0); + }); + + test('Readonly schema source', async () => { + await dashboard.treeView.openProjectSourceSettings({ title: context.defaultProjectTitle, context }); + + await settingsPage.selectTab({ tab: 'dataSources' }); + await dashboard.rootPage.waitForTimeout(300); + + await settingsPage.source.updateSchemaReadOnly({ sourceName: 'Default', readOnly: true }); + await settingsPage.close(); + + // reload page to reflect source changes + await dashboard.rootPage.reload(); + + await dashboard.treeView.verifyTable({ title: 'Actor' }); + + // open table and verify that it is readonly + await dashboard.treeView.openTable({ title: 'Actor' }); + + await dashboard.grid + .get() + .locator(`th[data-title="LastName"]`) + .first() + .locator('.nc-ui-dt-dropdown') + .scrollIntoViewIfNeeded(); + await dashboard.grid.get().locator(`th[data-title="LastName"]`).first().locator('.nc-ui-dt-dropdown').click(); + await expect(await dashboard.rootPage.locator('li[role="menuitem"]:has-text("Edit"):visible').last()).toBeVisible(); + }); +});