Browse Source

Merge pull request #4393 from nocodb/refactor/playwright-refactor

refactor(test): Playwright followup
pull/4471/head
navi 2 years ago committed by GitHub
parent
commit
1de5c8f630
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 9
      packages/nc-gui/components/tabs/auth/user-management/UsersModal.vue
  2. 22
      packages/nc-gui/pages/index/index/[projectId].vue
  3. 19
      packages/nc-gui/pages/index/index/create.vue
  4. 5
      packages/nc-gui/pages/index/index/user.vue
  5. 51
      tests/playwright/pages/Account/ChangePassword.ts
  6. 3
      tests/playwright/pages/Account/Users.ts
  7. 10
      tests/playwright/pages/Account/index.ts
  8. 2
      tests/playwright/pages/Dashboard/Grid/index.ts
  9. 24
      tests/playwright/pages/Dashboard/Settings/Teams.ts
  10. 1
      tests/playwright/pages/Dashboard/TreeView.ts
  11. 1
      tests/playwright/pages/Dashboard/WebhookForm/index.ts
  12. 8
      tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts
  13. 25
      tests/playwright/pages/Dashboard/common/Toolbar/index.ts
  14. 32
      tests/playwright/pages/Dashboard/index.ts
  15. 50
      tests/playwright/pages/ProjectsPage/index.ts
  16. 2
      tests/playwright/tests/accountUserSettings.spec.ts
  17. 27
      tests/playwright/tests/authChangePassword.spec.ts
  18. 2
      tests/playwright/tests/metaSync.spec.ts
  19. 3
      tests/playwright/tests/toolbarOperations.spec.ts
  20. 7
      tests/playwright/tests/viewGridShare.spec.ts
  21. 9
      tests/playwright/tests/viewKanban.spec.ts

9
packages/nc-gui/components/tabs/auth/user-management/UsersModal.vue

@ -150,11 +150,16 @@ const emailField = (inputEl: typeof Input) => {
wrap-class-name="nc-modal-invite-user-and-share-base"
@cancel="emit('closed')"
>
<div class="flex flex-col">
<div class="flex flex-col" data-testid="invite-user-and-share-base-modal">
<div class="flex flex-row justify-between items-center pb-1.5 mb-2 border-b-1 w-full">
<a-typography-title class="select-none" :level="4"> {{ $t('activity.share') }}: {{ project.title }} </a-typography-title>
<a-button type="text" class="!rounded-md mr-1 -mt-1.5" @click="emit('closed')">
<a-button
type="text"
class="!rounded-md mr-1 -mt-1.5"
data-testid="invite-user-and-share-base-modal-close-btn"
@click="emit('closed')"
>
<template #icon>
<MaterialSymbolsCloseRounded class="flex mx-auto" />
</template>

22
packages/nc-gui/pages/index/index/[projectId].vue

@ -1,6 +1,7 @@
<script lang="ts" setup>
import type { Form } from 'ant-design-vue'
import type { ProjectType } from 'nocodb-sdk'
import type { VNodeRef } from '@vue/runtime-core'
import {
extractSdkResponseErrorMsg,
message,
@ -8,14 +9,13 @@ import {
projectTitleValidator,
reactive,
ref,
tryOnMounted,
useProject,
useRoute,
} from '#imports'
const route = useRoute()
const { project, loadProject, updateProject, isLoading, projectLoadedHook } = useProject()
const { loadProject, updateProject, isLoading } = useProject()
loadProject(false)
@ -43,21 +43,7 @@ const renameProject = async () => {
}
}
// select and focus title field on load
projectLoadedHook(async () => {
formState.title = project.value.title as string
tryOnMounted(() => {
// todo: replace setTimeout and follow better approach
setTimeout(() => {
const input = form.value?.$el?.querySelector('input[type=text]')
input.focus()
input.setSelectionRange(0, formState.title?.length)
}, 150)
})
})
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</script>
<template>
@ -89,7 +75,7 @@ projectLoadedHook(async () => {
@finish="renameProject"
>
<a-form-item :label="$t('labels.projName')" name="title" :rules="nameValidationRules">
<a-input v-model:value="formState.title" name="title" class="nc-metadb-project-name" />
<a-input :ref="focus" v-model:value="formState.title" name="title" class="nc-metadb-project-name" />
</a-form-item>
<div class="text-center">

19
packages/nc-gui/pages/index/index/create.vue

@ -1,11 +1,10 @@
<script lang="ts" setup>
import type { Form } from 'ant-design-vue'
import type { VNodeRef } from '@vue/runtime-core'
import {
extractSdkResponseErrorMsg,
message,
navigateTo,
nextTick,
onMounted,
projectTitleValidator,
reactive,
ref,
@ -47,19 +46,7 @@ const createProject = async () => {
}
}
// select and focus title field on load
onMounted(async () => {
await nextTick(() => {
// todo: replace setTimeout and follow better approach
setTimeout(() => {
const input = form.value?.$el?.querySelector('input[type=text]')
input.setSelectionRange(0, formState.title.length)
input.focus()
}, 500)
})
})
const focus: VNodeRef = (el) => (el as HTMLInputElement)?.focus()
</script>
<template>
@ -88,7 +75,7 @@ onMounted(async () => {
@finish="createProject"
>
<a-form-item :label="$t('labels.projName')" name="title" :rules="nameValidationRules" class="m-10">
<a-input v-model:value="formState.title" name="title" class="nc-metadb-project-name" />
<a-input :ref="focus" v-model:value="formState.title" name="title" class="nc-metadb-project-name" />
</a-form-item>
<div class="text-center">

5
packages/nc-gui/pages/index/index/user.vue

@ -68,7 +68,10 @@ const resetError = () => {
</script>
<template>
<div class="relative flex flex-col justify-center gap-2 w-full p-8 md:(bg-white rounded-lg border-1 border-gray-200 shadow)">
<div
class="relative flex flex-col justify-center gap-2 w-full p-8 md:(bg-white rounded-lg border-1 border-gray-200 shadow)"
data-testid="user-change-password"
>
<LazyGeneralNocoIcon class="color-transition hover:(ring ring-accent)" :animate="isLoading" />
<div

51
tests/playwright/pages/Account/ChangePassword.ts

@ -0,0 +1,51 @@
import { expect, Page } from '@playwright/test';
import BasePage from '../Base';
export class ChangePasswordPage extends BasePage {
constructor(rootPage: Page) {
super(rootPage);
}
get() {
return this.rootPage.getByTestId('nc-user-settings-form');
}
async changePassword({
oldPass,
newPass,
repeatPass,
networkValidation,
}: {
oldPass: string;
newPass: string;
repeatPass: string;
networkValidation?: boolean;
}) {
const currentPassword = this.get().locator('input[data-testid="nc-user-settings-form__current-password"]');
const newPassword = this.get().locator('input[data-testid="nc-user-settings-form__new-password"]');
const confirmPassword = this.get().locator('input[data-testid="nc-user-settings-form__new-password-repeat"]');
await currentPassword.fill(oldPass);
await newPassword.fill(newPass);
await confirmPassword.fill(repeatPass);
const submitChangePassword = this.get().locator('button[data-testid="nc-user-settings-form__submit"]').click();
if (networkValidation) {
await this.waitForResponse({
uiAction: submitChangePassword,
httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: 'api/v1/auth/password/change',
});
} else {
await submitChangePassword;
}
}
async verifyFormError({ error }: { error: string }) {
await expect(this.get().getByTestId('nc-user-settings-form__error')).toHaveText(error);
}
async verifyPasswordDontMatchError() {
await expect(this.rootPage.locator('.ant-form-item-explain-error')).toHaveText('Passwords do not match');
}
}

3
tests/playwright/pages/Account/Users.ts

@ -1,10 +1,12 @@
import { Locator } from '@playwright/test';
import BasePage from '../Base';
import { ChangePasswordPage } from './ChangePassword';
import { AccountPage } from './index';
export class AccountUsersPage extends BasePage {
readonly inviteUserBtn: Locator;
readonly inviteUserModal: Locator;
readonly changePasswordPage: ChangePasswordPage;
private accountPage: AccountPage;
constructor(accountPage: AccountPage) {
@ -12,6 +14,7 @@ export class AccountUsersPage extends BasePage {
this.accountPage = accountPage;
this.inviteUserBtn = this.get().locator(`[data-testid="nc-super-user-invite"]`);
this.inviteUserModal = accountPage.rootPage.locator(`.nc-modal-invite-user`);
this.changePasswordPage = new ChangePasswordPage(this.rootPage);
}
async goto() {

10
tests/playwright/pages/Account/index.ts

@ -1,9 +1,19 @@
import { Page } from '@playwright/test';
import BasePage from '../Base';
import { AccountSettingsPage } from './Settings';
import { AccountTokenPage } from './Token';
import { AccountUsersPage } from './Users';
export class AccountPage extends BasePage {
readonly settings: AccountSettingsPage;
readonly token: AccountTokenPage;
readonly users: AccountUsersPage;
constructor(page: Page) {
super(page);
this.settings = new AccountSettingsPage(this);
this.token = new AccountTokenPage(this);
this.users = new AccountUsersPage(this);
}
get() {

2
tests/playwright/pages/Dashboard/Grid/index.ts

@ -132,7 +132,7 @@ export class GridPage extends BasePage {
}
async deleteRow(index: number) {
await this.get().locator(`td[data-testid="cell-Title-${index}"]`).click({
await this.get().getByTestId(`cell-Title-${index}`).click({
button: 'right',
});

24
tests/playwright/pages/Dashboard/Settings/Teams.ts

@ -1,32 +1,31 @@
import { expect, Locator } from '@playwright/test';
import { Locator } from '@playwright/test';
import { SettingsPage } from '.';
import BasePage from '../../Base';
import { writeFileAsync } from 'xlsx';
import { ToolbarPage } from '../common/Toolbar';
export class TeamsPage extends BasePage {
private readonly settings: SettingsPage;
readonly inviteTeamBtn: Locator;
readonly inviteTeamModal: Locator;
private readonly inviteTeamBtn: Locator;
private readonly inviteTeamModal: Locator;
constructor(settings: SettingsPage) {
super(settings.rootPage);
this.settings = settings;
this.inviteTeamBtn = this.get().locator(`button:has-text("Invite Team")`);
this.inviteTeamModal = this.rootPage.locator(`.nc-modal-invite-user-and-share-base`);
this.inviteTeamModal = this.rootPage.getByTestId('invite-user-and-share-base-modal');
}
get() {
return this.settings.get().locator(`[data-testid="nc-settings-subtab-Users Management"]`);
return this.settings.get().getByTestId('nc-settings-subtab-Users Management');
}
// Prefixing to differentiate between emails created by the tests which are deleted after the test run
prefixEmail(email: string) {
const parallelId = process.env.TEST_PARALLEL_INDEX ?? '0';
return `nc_test_${parallelId}_${email}`;
}
getSharedBaseSubModal() {
return this.rootPage.locator(`[data-testid="nc-share-base-sub-modal"]`);
return this.rootPage.getByTestId('nc-share-base-sub-modal');
}
async invite({ email, role }: { email: string; role: string }) {
@ -44,8 +43,8 @@ export class TeamsPage extends BasePage {
}
async closeInvite() {
// two btn-icon-only in invite modal: close & copy url
await this.inviteTeamModal.locator(`button.ant-btn-icon-only:visible`).first().click();
// todo: Fix the case where there is ghost dom for previous modal
await this.inviteTeamModal.getByTestId('invite-user-and-share-base-modal-close-btn').last().click();
}
async inviteMore() {
@ -53,7 +52,7 @@ export class TeamsPage extends BasePage {
}
async toggleSharedBase({ toggle }: { toggle: boolean }) {
const toggleBtn = await this.getSharedBaseSubModal().locator(`.nc-disable-shared-base`);
const toggleBtn = this.getSharedBaseSubModal().locator(`.nc-disable-shared-base`);
const toggleBtnText = await toggleBtn.first().innerText();
const disabledBase = toggleBtnText.includes('Disable');
@ -76,8 +75,7 @@ export class TeamsPage extends BasePage {
}
async getSharedBaseUrl() {
const url = await this.getSharedBaseSubModal().locator(`.nc-url:visible`).innerText();
return url;
return await this.getSharedBaseSubModal().locator(`.nc-url:visible`).textContent();
}
async sharedBaseActions({ action }: { action: string }) {

1
tests/playwright/pages/Dashboard/TreeView.ts

@ -57,6 +57,7 @@ export class TreeViewPage extends BasePage {
responseJsonMatcher: json => json.title === title && json.type === 'table',
});
// Tab render is slow for playwright
await this.dashboard.waitForTabRender({ title });
}

1
tests/playwright/pages/Dashboard/WebhookForm/index.ts

@ -23,7 +23,6 @@ export class WebhookFormPage extends BasePage {
return this.dashboard.get().locator(`.nc-drawer-webhook-body`);
}
// todo: Removing opening webhook drawer logic as it belongs to `Toolbar` page
async create({ title, event, url = 'http://localhost:9090/hook' }: { title: string; event: string; url?: string }) {
await this.toolbar.clickActions();
await this.toolbar.actions.click('Webhooks');

8
tests/playwright/pages/Dashboard/common/Toolbar/Filter.ts

@ -40,11 +40,6 @@ export class ToolbarFilterPage extends BasePage {
value: string;
isLocallySaved: boolean;
}) {
await this.toolbar.clickFilter();
// todo: If the filter menu is open for the first time for the table, there can will be a api call which will re render the filter menu
await this.rootPage.waitForTimeout(1000);
await this.get().locator(`button:has-text("Add Filter")`).first().click();
await this.rootPage.locator('.nc-filter-field-select').last().click();
@ -82,9 +77,6 @@ export class ToolbarFilterPage extends BasePage {
requestUrlPathToMatch: isLocallySaved ? `/api/v1/db/public/` : `/api/v1/db/data/noco/`,
});
await this.toolbar.parent.dashboard.waitForLoaderToDisappear();
await this.toolbar.clickFilter();
await this.toolbar.parent.waitLoading();
}

25
tests/playwright/pages/Dashboard/common/Toolbar/index.ts

@ -69,13 +69,30 @@ export class ToolbarPage extends BasePage {
if (menuOpen) await this.sort.get().waitFor({ state: 'hidden' });
}
async clickFilter() {
async clickFilter({
// `networkValidation` is used to verify that api calls are made when the button is clicked
// which happens when the filter is opened for the first time
networkValidation,
}: { networkValidation?: boolean } = {}) {
const menuOpen = await this.filter.get().isVisible();
await this.get().locator(`button.nc-filter-menu-btn`).click();
const clickFilterAction = this.get().locator(`button.nc-filter-menu-btn`).click();
// Wait for the menu to close
if (menuOpen) await this.filter.get().waitFor({ state: 'hidden' });
if (menuOpen) {
await clickFilterAction;
await this.filter.get().waitFor({ state: 'hidden' });
} else {
if (networkValidation) {
// Since on opening filter menu, api is called to fetch filter options, and will rerender the menu
await this.waitForResponse({
uiAction: clickFilterAction,
requestUrlPathToMatch: '/api/v1/db',
httpMethodsToMatch: ['GET'],
});
} else {
await clickFilterAction;
}
}
}
async clickShareView() {

32
tests/playwright/pages/Dashboard/index.ts

@ -61,7 +61,7 @@ export class DashboardPage extends BasePage {
}
async gotoSettings() {
await this.rootPage.locator('[data-testid="nc-project-menu"]').click();
await this.rootPage.getByTestId('nc-project-menu').click();
await this.rootPage.locator('div.nc-project-menu-item:has-text(" Team & Settings")').click();
}
@ -79,9 +79,6 @@ export class DashboardPage extends BasePage {
}
async clickHome() {
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
await this.rootPage.getByTestId('nc-noco-brand-icon').click();
const projectsPage = new ProjectsPage(this.rootPage);
await projectsPage.waitToBeRendered();
@ -124,32 +121,9 @@ export class DashboardPage extends BasePage {
}
}
async openPasswordChangeModal() {
// open change password portal
await this.rootPage.locator('.nc-menu-accounts').click();
await this.rootPage
.locator('.nc-dropdown-user-accounts-menu')
.getByTestId('nc-menu-accounts__user-settings')
.click();
}
// todo: Move this to a seperate page
async changePassword({ oldPass, newPass, repeatPass }: { oldPass: string; newPass: string; repeatPass: string }) {
// change password
const currentPassword = this.rootPage.locator('input[data-testid="nc-user-settings-form__current-password"]');
const newPassword = this.rootPage.locator('input[data-testid="nc-user-settings-form__new-password"]');
const confirmPassword = this.rootPage.locator('input[data-testid="nc-user-settings-form__new-password-repeat"]');
await currentPassword.fill(oldPass);
await newPassword.fill(newPass);
await confirmPassword.fill(repeatPass);
await this.rootPage.locator('button[data-testid="nc-user-settings-form__submit"]').click();
}
async signOut() {
await this.rootPage.locator('[data-testid="nc-project-menu"]').click();
const projMenu = await this.rootPage.locator('.nc-dropdown-project-menu');
await this.rootPage.getByTestId('nc-project-menu').click();
const projMenu = this.rootPage.locator('.nc-dropdown-project-menu');
await projMenu.locator('[data-menu-id="account"]:visible').click();
await this.rootPage.locator('div.nc-project-menu-item:has-text("Sign Out"):visible').click();
await this.rootPage.locator('[data-testid="nc-form-signin"]:visible').waitFor();

50
tests/playwright/pages/ProjectsPage/index.ts

@ -28,7 +28,7 @@ export class ProjectsPage extends BasePage {
}) {
if (!withoutPrefix) name = this.prefixTitle(name);
await this.rootPage.locator('.nc-new-project-menu').click();
await this.get().locator('.nc-new-project-menu').click();
const createProjectMenu = await this.rootPage.locator('.nc-dropdown-create-project');
@ -38,20 +38,18 @@ export class ProjectsPage extends BasePage {
await createProjectMenu.locator(`.ant-dropdown-menu-title-content`).nth(1).click();
}
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
await this.rootPage.locator(`.nc-metadb-project-name`).waitFor();
await this.rootPage.locator(`input.nc-metadb-project-name`).fill(name);
await this.rootPage.waitForTimeout(2000);
await this.rootPage.locator(`button:has-text("Create")`).click({
delay: 2000,
const createProjectSubmitAction = this.rootPage.locator(`button:has-text("Create")`).click();
await this.waitForResponse({
uiAction: createProjectSubmitAction,
httpMethodsToMatch: ['POST'],
requestUrlPathToMatch: '/api/v1/db/meta/projects/',
});
// fix me! wait for page to be rendered completely
await this.rootPage.waitForTimeout(2000);
// wait for dashboard to render
await this.rootPage.locator('.nc-container').waitFor({ state: 'visible' });
}
async checkProjectCreateButton({ exists = true }) {
@ -91,9 +89,6 @@ export class ProjectsPage extends BasePage {
withoutPrefix?: boolean;
waitForAuthTab?: boolean;
}) {
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
if (!withoutPrefix) title = this.prefixTitle(title);
let project: any;
@ -138,7 +133,13 @@ export class ProjectsPage extends BasePage {
if (!withoutPrefix) title = this.prefixTitle(title);
await this.get().locator(`[data-testid="delete-project-${title}"]`).click();
await this.rootPage.locator(`button:has-text("Yes")`).click();
const deleteProjectAction = this.rootPage.locator(`button:has-text("Yes")`).click();
await this.waitForResponse({
uiAction: deleteProjectAction,
httpMethodsToMatch: ['DELETE'],
requestUrlPathToMatch: '/api/v1/db/meta/projects/',
});
await this.get().locator('.ant-table-row', { hasText: title }).waitFor({ state: 'hidden' });
}
@ -161,9 +162,6 @@ export class ProjectsPage extends BasePage {
});
await projRow.locator('.nc-action-btn').nth(0).click();
// todo: Fast page transition breaks the vue router
await this.rootPage.waitForTimeout(2000);
await project.locator('input.nc-metadb-project-name').fill(newTitle);
// press enter to save
const submitAction = project.locator('input.nc-metadb-project-name').press('Enter');
@ -172,9 +170,6 @@ export class ProjectsPage extends BasePage {
requestUrlPathToMatch: 'api/v1/db/meta/projects/',
httpMethodsToMatch: ['PATCH'],
});
// todo: vue navigation breaks if page changes very quickly
await this.rootPage.waitForTimeout(1000);
}
async openLanguageMenu() {
@ -187,10 +182,23 @@ export class ProjectsPage extends BasePage {
}
async verifyLanguage(param: { json: any }) {
const title = await this.rootPage.locator(`.nc-project-page-title`);
const title = this.rootPage.locator(`.nc-project-page-title`);
const menu = this.rootPage.locator(`.nc-new-project-menu`);
await expect(title).toHaveText(param.json.title.myProject);
await expect(menu).toHaveText(param.json.title.newProj);
await this.rootPage.locator(`[placeholder="${param.json.activity.searchProject}"]`).waitFor();
}
async openPasswordChangeModal() {
// open change password portal
await this.rootPage.locator('.nc-menu-accounts').click();
await this.rootPage
.locator('.nc-dropdown-user-accounts-menu')
.getByTestId('nc-menu-accounts__user-settings')
.click();
}
async waitForRender() {
await this.rootPage.locator('.nc-project-page-title:has-text("My Projects")').waitFor();
}
}

2
tests/playwright/tests/accountUserSettings.spec.ts

@ -13,7 +13,7 @@ test.describe('App settings', () => {
test.beforeEach(async ({ page }) => {
context = await setup({ page });
accountPage = new AccountPage(page);
accountSettingsPage = new AccountSettingsPage(accountPage);
accountSettingsPage = accountPage.settings;
});
test('Toggle invite only signup', async () => {

27
tests/playwright/tests/authChangePassword.spec.ts

@ -4,17 +4,24 @@ import setup from '../setup';
import { LoginPage } from '../pages/LoginPage';
import { SettingsPage, SettingTab } from '../pages/Dashboard/Settings';
import { SignupPage } from '../pages/SignupPage';
import { ProjectsPage } from '../pages/ProjectsPage';
import { AccountPage } from '../pages/Account';
test.describe('Auth', () => {
let context: any;
let dashboard: DashboardPage;
let settings: SettingsPage;
let context: any;
let signupPage: SignupPage;
let projectsPage: ProjectsPage;
let accountPage: AccountPage;
test.beforeEach(async ({ page }) => {
context = await setup({ page });
dashboard = new DashboardPage(page, context.project);
signupPage = new SignupPage(page);
projectsPage = new ProjectsPage(page);
accountPage = new AccountPage(page);
settings = dashboard.settings;
});
@ -37,31 +44,31 @@ test.describe('Auth', () => {
password: 'Password123.',
});
await dashboard.openPasswordChangeModal();
await projectsPage.openPasswordChangeModal();
// Existing active pass incorrect
await dashboard.changePassword({
await accountPage.users.changePasswordPage.changePassword({
oldPass: '123456789',
newPass: '123456789',
repeatPass: '123456789',
});
await dashboard.rootPage
.locator('[data-testid="nc-user-settings-form__error"]:has-text("Current password is wrong")')
.waitFor();
await accountPage.users.changePasswordPage.verifyFormError({ error: 'Current password is wrong' });
// New pass and repeat pass mismatch
await dashboard.changePassword({
await accountPage.users.changePasswordPage.changePassword({
oldPass: 'Password123.',
newPass: '123456789',
repeatPass: '987654321',
networkValidation: false,
});
await dashboard.rootPage.locator('.ant-form-item-explain-error:has-text("Passwords do not match")').waitFor();
await accountPage.users.changePasswordPage.verifyPasswordDontMatchError();
// All good
await dashboard.changePassword({
await accountPage.users.changePasswordPage.changePassword({
oldPass: 'Password123.',
newPass: 'NewPasswordConfigured',
repeatPass: 'NewPasswordConfigured',
networkValidation: true,
});
const loginPage = new LoginPage(page);
@ -69,6 +76,6 @@ test.describe('Auth', () => {
await loginPage.fillPassword('NewPasswordConfigured');
await loginPage.submit();
await page.locator('.nc-project-page-title:has-text("My Projects")').waitFor();
await projectsPage.waitForRender();
});
});

2
tests/playwright/tests/metaSync.spec.ts

@ -260,12 +260,14 @@ test.describe('Meta sync', () => {
isLocallySaved: false,
});
await dashboard.grid.toolbar.clickFilter();
await dashboard.grid.toolbar.filter.addNew({
columnTitle: 'Col1',
opType: '>=',
value: '5',
isLocallySaved: false,
});
await dashboard.grid.toolbar.clickFilter();
await dashboard.grid.verifyRowCount({ count: 5 });
});

3
tests/playwright/tests/toolbarOperations.spec.ts

@ -56,12 +56,15 @@ test.describe('Toolbar operations (GRID)', () => {
await validateFirstRow('Afghanistan');
// Filter column
await toolbar.clickFilter();
await toolbar.filter.addNew({
columnTitle: 'Country',
value: 'India',
opType: 'is equal',
isLocallySaved: false,
});
await toolbar.clickFilter();
await validateFirstRow('India');
// Reset filter

7
tests/playwright/tests/viewGridShare.spec.ts

@ -39,12 +39,14 @@ test.describe('Shared view', () => {
isLocallySaved: false,
});
// filter
await dashboard.grid.toolbar.clickFilter();
await dashboard.grid.toolbar.filter.addNew({
columnTitle: 'Address',
value: 'Ab',
opType: 'is like',
isLocallySaved: false,
});
await dashboard.grid.toolbar.clickFilter();
// share with password disabled, download enabled
await dashboard.grid.toolbar.clickShareView();
@ -106,12 +108,14 @@ test.describe('Shared view', () => {
});
if (isMysql(context)) {
await sharedPage.grid.toolbar.clickFilter();
await sharedPage.grid.toolbar.filter.addNew({
columnTitle: 'District',
value: 'Ta',
opType: 'is like',
isLocallySaved: true,
});
await sharedPage.grid.toolbar.clickFilter();
}
await sharedPage.grid.toolbar.fields.toggle({ title: 'LastUpdate', isLocallySaved: true });
expectedColumns[6].isVisible = false;
@ -191,12 +195,15 @@ test.describe('Shared view', () => {
title: 'New Column',
isVisible: true,
});
await sharedPage2.grid.toolbar.clickFilter();
await sharedPage2.grid.toolbar.filter.addNew({
columnTitle: 'Country',
value: 'New Country',
opType: 'is like',
isLocallySaved: true,
});
await sharedPage2.grid.toolbar.clickFilter();
await sharedPage2.grid.cell.verify({
index: 0,
columnHeader: 'Country',

9
tests/playwright/tests/viewKanban.spec.ts

@ -142,12 +142,17 @@ test.describe('View', () => {
});
// verify filter
await toolbar.clickFilter({
networkValidation: true,
});
await toolbar.filter.addNew({
columnTitle: 'Title',
opType: 'is like',
value: 'BA',
isLocallySaved: false,
});
await toolbar.clickFilter();
// verify card order
const order4 = [
['BAKED CLEOPATRA', 'BALLROOM MOCKINGBIRD'],
@ -188,12 +193,16 @@ test.describe('View', () => {
isAscending: false,
isLocallySaved: false,
});
await toolbar.clickFilter();
await toolbar.filter.addNew({
columnTitle: 'Title',
opType: 'is like',
value: 'BA',
isLocallySaved: false,
});
await toolbar.clickFilter();
await toolbar.fields.hideAll();
await toolbar.fields.toggle({ title: 'Title' });

Loading…
Cancel
Save