Browse Source

feat(testing): Stability

pull/3848/head
Muhammed Mustafa 2 years ago
parent
commit
f476c3d927
  1. 2
      packages/nc-gui/composables/useApi/index.ts
  2. 2
      packages/nc-gui/layouts/base.vue
  3. 2
      packages/nc-gui/layouts/shared-view.vue
  4. 6
      scripts/playwright/pages/Dashboard/ExpandedForm/index.ts
  5. 7
      scripts/playwright/pages/Dashboard/Grid/index.ts
  6. 9
      scripts/playwright/pages/Dashboard/Import/ImportTemplate.ts
  7. 2
      scripts/playwright/pages/Dashboard/common/ProjectMenu/index.ts
  8. 53
      scripts/playwright/pages/Dashboard/common/Toolbar/Fields.ts
  9. 48
      scripts/playwright/pages/Dashboard/common/Toolbar/Filter.ts
  10. 19
      scripts/playwright/pages/Dashboard/common/Toolbar/Sort.ts
  11. 6
      scripts/playwright/pages/Dashboard/index.ts
  12. 4
      scripts/playwright/pages/LoginPage/index.ts
  13. 2
      scripts/playwright/playwright.config.ts
  14. 2
      scripts/playwright/tests/import.spec.ts
  15. 2
      scripts/playwright/tests/rolesCreate.spec.ts
  16. 2
      scripts/playwright/tests/viewGridShare.spec.ts

2
packages/nc-gui/composables/useApi/index.ts

@ -41,8 +41,6 @@ export function useApi<Data = any, RequestConfig = any>({
*/ */
const { count, inc, dec } = useCounter(0) const { count, inc, dec } = useCounter(0)
watchEffect(() => console.log('useApi: count', count.value))
/** is request loading */ /** is request loading */
const isLoading = ref(false) const isLoading = ref(false)

2
packages/nc-gui/layouts/base.vue

@ -57,7 +57,7 @@ hooks.hook('page:finish', () => {
</div> </div>
<div class="!text-white flex justify-center"> <div class="!text-white flex justify-center">
<div v-show="isLoading" class="flex items-center gap-2 ml-3"> <div class="flex items-center gap-2 ml-3" pw-data="nc-loading">
{{ $t('general.loading') }} {{ $t('general.loading') }}
<MdiReload :class="{ 'animate-infinite animate-spin': isLoading }" /> <MdiReload :class="{ 'animate-infinite animate-spin': isLoading }" />

2
packages/nc-gui/layouts/shared-view.vue

@ -53,7 +53,7 @@ export default {
<div class="flex justify-center items-center"> <div class="flex justify-center items-center">
<div class="flex items-center gap-2 ml-3 text-white"> <div class="flex items-center gap-2 ml-3 text-white">
<template v-if="isLoading"> <template v-if="isLoading">
<span class="text-white">{{ $t('general.loading') }}</span> <span class="text-white" pw-data="nc-loading">{{ $t('general.loading') }}</span>
<MdiReload :class="{ 'animate-infinite animate-spin ': isLoading }" /> <MdiReload :class="{ 'animate-infinite animate-spin ': isLoading }" />
</template> </template>

6
scripts/playwright/pages/Dashboard/ExpandedForm/index.ts

@ -85,10 +85,8 @@ export class ExpandedFormPage extends BasePage {
} }
async verify({ header, url }: { header: string; url: string }) { async verify({ header, url }: { header: string; url: string }) {
await expect( await expect(this.get().locator(`.nc-expanded-form-header`).last()).toContainText(header);
await this.get().locator(`.nc-expanded-form-header`).last().innerText() await expect.poll(() => this.rootPage.url()).toContain(url);
).toContain(header);
await expect(await this.rootPage.url()).toContain(url);
} }
async close() { async close() {

7
scripts/playwright/pages/Dashboard/Grid/index.ts

@ -94,6 +94,8 @@ export class GridPage extends BasePage {
} else { } else {
await this.rootPage.waitForTimeout(300); await this.rootPage.waitForTimeout(300);
} }
await this.dashboard.waitForLoaderToDisappear();
} }
async editRow({ async editRow({
@ -124,6 +126,8 @@ export class GridPage extends BasePage {
} else { } else {
await this.rootPage.waitForTimeout(300); await this.rootPage.waitForTimeout(300);
} }
await this.dashboard.waitForLoaderToDisappear();
} }
async verifyRow({ index }: { index: number }) { async verifyRow({ index }: { index: number }) {
@ -151,7 +155,9 @@ export class GridPage extends BasePage {
await this.rootPage await this.rootPage
.locator("span.ant-dropdown-menu-title-content > nc-project-menu-item") .locator("span.ant-dropdown-menu-title-content > nc-project-menu-item")
.waitFor({ state: "hidden" }); .waitFor({ state: "hidden" });
await this.rootPage.waitForTimeout(300); await this.rootPage.waitForTimeout(300);
await this.dashboard.waitForLoaderToDisappear();
} }
async addRowRightClickMenu(index: number) { async addRowRightClickMenu(index: number) {
@ -197,6 +203,7 @@ export class GridPage extends BasePage {
button: "right", button: "right",
}); });
await this.rootPage.locator("text=Delete Selected Rows").click(); await this.rootPage.locator("text=Delete Selected Rows").click();
await this.dashboard.waitForLoaderToDisappear();
} }
private async pagination({ page }: { page: string }) { private async pagination({ page }: { page: string }) {

9
scripts/playwright/pages/Dashboard/Import/ImportTemplate.ts

@ -66,7 +66,14 @@ export class ImportTemplatePage extends BasePage {
} }
await this.get().locator('button:has-text("Back"):visible').waitFor(); await this.get().locator('button:has-text("Back"):visible').waitFor();
await this.get().locator('button:has-text("Import"):visible').click(); await this.waitForResponse({
requestUrlPathToMatch: '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
uiAction: this.get().locator('button:has-text("Import"):visible').click()
});
await this.dashboard.waitForTabRender({
title: tblList[0],
})
} }
private async expandTableList(param: { index: number }) { private async expandTableList(param: { index: number }) {

2
scripts/playwright/pages/Dashboard/common/ProjectMenu/index.ts

@ -30,7 +30,7 @@ export class ProjectMenuObject extends BasePage {
await this.rootPage await this.rootPage
.locator(`div.nc-project-menu-item:has-text("${subMenu}"):visible`) .locator(`div.nc-project-menu-item:has-text("${subMenu}"):visible`)
.click(); .click();
await this.rootPage.waitForTimeout(10000); await this.rootPage.waitForTimeout(1000);
} }
} }
} }

53
scripts/playwright/pages/Dashboard/common/Toolbar/Fields.ts

@ -14,12 +14,17 @@ export class ToolbarFieldsPage extends BasePage {
return this.rootPage.locator(`[pw-data="nc-fields-menu"]`); return this.rootPage.locator(`[pw-data="nc-fields-menu"]`);
} }
async toggle({ title }: { title: string }) { // todo: Click and toggle are similar method. Remove one of them
async toggle({ title, isLocallySaved }: { title: string; isLocallySaved?: boolean }) {
await this.toolbar.clickFields(); await this.toolbar.clickFields();
await this.get() await this.waitForResponse({
.locator(`[pw-data="nc-fields-menu-${title}"]`) uiAction: this.get()
.locator('input[type="checkbox"]') .locator(`[pw-data="nc-fields-menu-${title}"]`)
.click(); .locator('input[type="checkbox"]')
.click(),
requestUrlPathToMatch: isLocallySaved ? '/api/v1/db/public/' : '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
});
await this.toolbar.clickFields(); await this.toolbar.clickFields();
} }
@ -35,29 +40,45 @@ export class ToolbarFieldsPage extends BasePage {
} }
} }
async click({ title }: { title: string }) { async click({ title, isLocallySaved }: { title: string; isLocallySaved?: boolean }) {
await this.get() await this.waitForResponse({
.locator(`[pw-data="nc-fields-menu-${title}"]`) uiAction: this.get()
.locator('input[type="checkbox"]') .locator(`[pw-data="nc-fields-menu-${title}"]`)
.click(); .locator('input[type="checkbox"]')
.click(),
requestUrlPathToMatch: isLocallySaved ? '/api/v1/db/public/' : '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
});
await this.toolbar.parent.waitLoading(); await this.toolbar.parent.waitLoading();
} }
async hideAll() { async hideAll({ isLocallySaved }: { isLocallySaved?: boolean } = {}) {
await this.toolbar.clickFields(); await this.toolbar.clickFields();
await this.get().locator(`button:has-text("Hide all")`).click(); await this.waitForResponse({
uiAction: this.get().locator(`button:has-text("Hide all")`).click(),
requestUrlPathToMatch: isLocallySaved ? '/api/v1/db/public/' : '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
});
await this.toolbar.clickFields(); await this.toolbar.clickFields();
} }
async showAll() { async showAll({ isLocallySaved }: { isLocallySaved? : boolean } = {}) {
await this.toolbar.clickFields(); await this.toolbar.clickFields();
await this.get().locator(`button:has-text("Show all")`).click(); await this.waitForResponse({
uiAction: this.get().locator(`button:has-text("Show all")`).click(),
requestUrlPathToMatch: isLocallySaved ? '/api/v1/db/public/' : '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
});
await this.toolbar.clickFields(); await this.toolbar.clickFields();
} }
async toggleShowSystemFields() { async toggleShowSystemFields({ isLocallySaved }: { isLocallySaved?: boolean } = {}) {
await this.toolbar.clickFields(); await this.toolbar.clickFields();
await this.get().locator(`.nc-fields-show-system-fields`).click(); await this.waitForResponse({
uiAction: this.get().locator(`.nc-fields-show-system-fields`).click(),
requestUrlPathToMatch: isLocallySaved ? '/api/v1/db/public/' : '/api/v1/db/data/noco/',
httpMethodsToMatch: ['GET'],
});
await this.toolbar.clickFields(); await this.toolbar.clickFields();
} }
} }

48
scripts/playwright/pages/Dashboard/common/Toolbar/Filter.ts

@ -52,48 +52,50 @@ export class ToolbarFilterPage extends BasePage {
await this.get().locator(`button:has-text("Add Filter")`).first().click(); await this.get().locator(`button:has-text("Add Filter")`).first().click();
const selectedColumnTitle = await this.rootPage.locator('.nc-filter-field-select').textContent();
await this.rootPage.locator(".nc-filter-field-select").last().click(); await this.rootPage.locator(".nc-filter-field-select").last().click();
await this.rootPage if(selectedColumnTitle !== columnTitle) {
const selectColumn = this.rootPage
.locator("div.ant-select-dropdown.nc-dropdown-toolbar-field-list") .locator("div.ant-select-dropdown.nc-dropdown-toolbar-field-list")
.locator(`div[label="${columnTitle}"][aria-selected="false"]:visible`) .locator(`div[label="${columnTitle}"][aria-selected="false"]:visible`)
.click(); .click();
await this.waitForResponse({
uiAction: selectColumn,
httpMethodsToMatch: isLocallySaved ? [ "GET" ] : ["POST", "PATCH" ],
requestUrlPathToMatch: isLocallySaved ? `/api/v1/db/public/` : `/filters`,
});
}
await this.rootPage.locator(".nc-filter-operation-select").last().click(); const selectedOpType = await this.rootPage.locator('.nc-filter-operation-select').textContent();
await this.rootPage if(selectedOpType !== opType) {
await this.rootPage.locator(".nc-filter-operation-select").last().click();
const selectOpType = this.rootPage
.locator(".nc-dropdown-filter-comp-op") .locator(".nc-dropdown-filter-comp-op")
.locator(`.ant-select-item:has-text("${opType}")`) .locator(`.ant-select-item:has-text("${opType}")`)
.click(); .click();
await this.waitForResponse({
uiAction: selectOpType,
httpMethodsToMatch: isLocallySaved ? [ "GET" ] : ["POST", "PATCH"],
requestUrlPathToMatch: isLocallySaved ? `/api/v1/db/public/` : `/filters`,
});
}
const fillFilter = this.rootPage const fillFilter = this.rootPage
.locator(".nc-filter-value-select") .locator(".nc-filter-value-select")
.last() .last()
.fill(value); .fill(value);
await this.waitForResponse({
uiAction: fillFilter,
httpMethodsToMatch: ["GET"],
requestUrlPathToMatch: isLocallySaved ? `/api/v1/db/public/` : `/api/v1/db/data/noco/`,
});
if (isLocallySaved) {
await this.waitForResponse({
uiAction: fillFilter,
httpMethodsToMatch: ["GET"],
requestUrlPathToMatch: `${value.replace(" ", "+")}`,
});
} else {
await this.waitForResponse({
uiAction: fillFilter,
httpMethodsToMatch: ["POST", "PATCH"],
requestUrlPathToMatch: "/filters",
});
}
await this.toolbar.clickFilter(); await this.toolbar.clickFilter();
await this.toolbar.parent.waitLoading() await this.toolbar.parent.waitLoading()
} }
click({ title }: { title: string }) {
return this.get()
.locator(`[pw-data="nc-fields-menu-${title}"]`)
.locator('input[type="checkbox"]')
.click();
}
async resetFilter() { async resetFilter() {
await this.toolbar.clickFilter(); await this.toolbar.clickFilter();
await this.waitForResponse({ await this.waitForResponse({

19
scripts/playwright/pages/Dashboard/common/Toolbar/Sort.ts

@ -55,20 +55,11 @@ export class ToolbarSortPage extends BasePage {
.nth(isAscending ? 0 : 1) .nth(isAscending ? 0 : 1)
.click(); .click();
if(isLocallySaved) { await this.waitForResponse({
await this.waitForResponse({ uiAction: selectSortDirection,
uiAction: selectSortDirection, httpMethodsToMatch: ["GET"],
httpMethodsToMatch: ["GET"], requestUrlPathToMatch: isLocallySaved ? `/api/v1/db/public/`: `/api/v1/db/data/noco/`,
requestUrlPathToMatch: `${isAscending ? "asc" : "desc"}`, });
})
} else {
await this.waitForResponse({
uiAction: selectSortDirection,
httpMethodsToMatch: ["POST", "PATCH"],
requestUrlPathToMatch: "/sorts",
})
}
// close sort menu // close sort menu
await this.toolbar.clickSort(); await this.toolbar.clickSort();

6
scripts/playwright/pages/Dashboard/index.ts

@ -234,4 +234,10 @@ export class DashboardPage extends BasePage {
} }
await this.rootPage.locator('[pw-data="nc-project-menu"]').click(); await this.rootPage.locator('[pw-data="nc-project-menu"]').click();
} }
async waitForLoaderToDisappear() {
await this.rootPage
.locator('[pw-data="nc-loading"]')
.waitFor({ state: "hidden" });
}
} }

4
scripts/playwright/pages/LoginPage/index.ts

@ -35,11 +35,15 @@ export class LoginPage extends BasePage {
async submit() { async submit() {
await this.get().locator(`[pw-data="nc-form-signin__submit"]`).click(); await this.get().locator(`[pw-data="nc-form-signin__submit"]`).click();
await expect(this.rootPage).toHaveURL("http://localhost:3000/#/"); await expect(this.rootPage).toHaveURL("http://localhost:3000/#/");
} }
async signIn({ email, password, withoutPrefix }: { email: string; password: string, withoutPrefix?: boolean }) { async signIn({ email, password, withoutPrefix }: { email: string; password: string, withoutPrefix?: boolean }) {
await this.goto(); await this.goto();
// todo: Login page is sometimes not loaded. Probably because of lazy loading
await this.rootPage.waitForTimeout(1500);
await this.fillEmail({email, withoutPrefix}); await this.fillEmail({email, withoutPrefix});
await this.fillPassword(password); await this.fillPassword(password);
await this.submit(); await this.submit();

2
scripts/playwright/playwright.config.ts

@ -13,7 +13,7 @@ require('dotenv').config();
const config: PlaywrightTestConfig = { const config: PlaywrightTestConfig = {
testDir: process.env.PW_QUICK_TEST ? './quickTests' : './tests', testDir: process.env.PW_QUICK_TEST ? './quickTests' : './tests',
/* Maximum time one test can run for. */ /* Maximum time one test can run for. */
timeout: process.env.CI ? 80 * 1000 : 65 * 1000, timeout: process.env.CI ? 140 * 1000 : 100 * 1000,
expect: { expect: {
/** /**
* Maximum time expect() should wait for the condition to be met. * Maximum time expect() should wait for the condition to be met.

2
scripts/playwright/tests/import.spec.ts

@ -11,7 +11,7 @@ test.describe("Import", () => {
test.setTimeout(150000); test.setTimeout(150000);
test.beforeEach(async ({ page }) => { test.beforeEach(async ({ page }) => {
page.setDefaultTimeout(50000); page.setDefaultTimeout(70000);
context = await setup({ page, isEmptyProject: true }); context = await setup({ page, isEmptyProject: true });
dashboard = new DashboardPage(page, context.project); dashboard = new DashboardPage(page, context.project);
}); });

2
scripts/playwright/tests/rolesCreate.spec.ts

@ -32,6 +32,8 @@ test.describe("User roles", () => {
}); });
test("Create role", async () => { test("Create role", async () => {
test.setTimeout(150000);
// close 'Team & Auth' tab // close 'Team & Auth' tab
await dashboard.closeTab({ title: "Team & Auth" }); await dashboard.closeTab({ title: "Team & Auth" });
await dashboard.gotoSettings(); await dashboard.gotoSettings();

2
scripts/playwright/tests/viewGridShare.spec.ts

@ -133,7 +133,7 @@ test.describe("Shared view", () => {
opType: "is like", opType: "is like",
isLocallySaved: true, isLocallySaved: true,
}); });
await sharedPage.grid.toolbar.fields.toggle({ title: "LastUpdate" }); await sharedPage.grid.toolbar.fields.toggle({ title: "LastUpdate", isLocallySaved: true });
expectedColumns[6].isVisible = false; expectedColumns[6].isVisible = false;
// verify new sort & filter criteria // verify new sort & filter criteria

Loading…
Cancel
Save