mirror of https://github.com/nocodb/nocodb
Raju Udava
2 years ago
committed by
Muhammed Mustafa
9 changed files with 595 additions and 28 deletions
@ -0,0 +1,22 @@
|
||||
import { test } from "@playwright/test"; |
||||
import { DashboardPage } from "../pages/Dashboard"; |
||||
import setup from "../setup"; |
||||
|
||||
test.describe("Test block name", () => { |
||||
let dashboard: DashboardPage; |
||||
let context: any; |
||||
|
||||
test.beforeEach(async ({ page }) => { |
||||
context = await setup({ page }); |
||||
dashboard = new DashboardPage(page, context.project); |
||||
}); |
||||
|
||||
test("Test case name", async () => { |
||||
// close 'Team & Auth' tab
|
||||
await dashboard.closeTab({ title: "Team & Auth" }); |
||||
await dashboard.treeView.openTable({ title: "Country" }); |
||||
|
||||
// ...
|
||||
// ..
|
||||
}); |
||||
}); |
@ -0,0 +1,276 @@
|
||||
// playwright-dev-page.ts
|
||||
import { Locator, expect } from "@playwright/test"; |
||||
import { DashboardPage } from ".."; |
||||
import BasePage from "../../Base"; |
||||
|
||||
export class FormPage extends BasePage { |
||||
readonly dashboard: DashboardPage; |
||||
readonly dashboardPage: DashboardPage; |
||||
|
||||
readonly addAllButton: Locator; |
||||
readonly removeAllButton: Locator; |
||||
readonly submitButton: Locator; |
||||
|
||||
readonly showAnotherFormRadioButton: Locator; |
||||
readonly showAnotherFormAfter5SecRadioButton: Locator; |
||||
readonly emailMeRadioButton: Locator; |
||||
|
||||
readonly formHeading: Locator; |
||||
readonly formSubHeading: Locator; |
||||
readonly afterSubmitMsg: Locator; |
||||
|
||||
constructor(dashboardPage: DashboardPage) { |
||||
super(dashboardPage.rootPage); |
||||
this.dashboard = dashboardPage; |
||||
this.addAllButton = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-add-all"]'); |
||||
this.removeAllButton = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-remove-all"]'); |
||||
this.submitButton = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-submit"]'); |
||||
|
||||
this.showAnotherFormRadioButton = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-checkbox-submit-another-form"]'); |
||||
this.showAnotherFormAfter5SecRadioButton = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-checkbox-show-blank-form"]'); |
||||
this.emailMeRadioButton = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-checkbox-send-email"]'); |
||||
this.formHeading = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-heading"]'); |
||||
this.formSubHeading = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-sub-heading"]'); |
||||
this.afterSubmitMsg = dashboardPage |
||||
.get() |
||||
.locator('[data-pw="nc-form-after-submit-msg"]'); |
||||
} |
||||
|
||||
/* |
||||
data-pw="nc-form-wrapper-submit" |
||||
data-pw="nc-form-wrapper" |
||||
|
||||
data-pw="nc-form-heading" |
||||
data-pw="nc-form-sub-heading" |
||||
data-pw="nc-form-field" |
||||
data-pw="nc-form-input-label" |
||||
data-pw="nc-field-remove-icon" |
||||
data-pw="nc-form-input-required" |
||||
data-pw="nc-form-input-label" |
||||
data-pw="nc-form-input-help-text" |
||||
:data-pw="`nc-form-input-${element.title.replaceAll(' ', '')}`" |
||||
data-pw="nc-form-submit" |
||||
|
||||
data-pw="nc-form-after-submit-msg" |
||||
data-pw="nc-form-checkbox-submit-another-form" |
||||
data-pw="nc-form-checkbox-show-blank-form" |
||||
data-pw="nc-form-checkbox-send-email" |
||||
|
||||
data-pw="nc-form-add-all" |
||||
data-pw="nc-form-remove-all" |
||||
:data-pw="`nc-form-hidden-column-${element.label}`" |
||||
data-pw="nc-drag-n-drop-to-hide" |
||||
*/ |
||||
|
||||
get() { |
||||
return this.dashboard.get().locator('[data-pw="nc-form-wrapper"]'); |
||||
} |
||||
|
||||
getFormAfterSubmit() { |
||||
return this.dashboard.get().locator('[data-pw="nc-form-wrapper-submit"]'); |
||||
} |
||||
|
||||
getFormHiddenColumn() { |
||||
return this.get().locator('[data-pw="nc-form-hidden-column"]'); |
||||
} |
||||
|
||||
getFormFields() { |
||||
return this.get().locator('[data-pw="nc-form-field"]'); |
||||
} |
||||
|
||||
getDragNDropToHide() { |
||||
return this.get().locator('[data-pw="nc-drag-n-drop-to-hide"]'); |
||||
} |
||||
|
||||
getFormFieldsRemoveIcon() { |
||||
return this.get().locator('[data-pw="nc-field-remove-icon"]'); |
||||
} |
||||
|
||||
getFormFieldsRequired() { |
||||
return this.get().locator('[data-pw="nc-form-input-required"]'); |
||||
} |
||||
|
||||
getFormFieldsInputLabel() { |
||||
return this.get().locator('[data-pw="nc-form-input-label"]'); |
||||
} |
||||
|
||||
getFormFieldsInputHelpText() { |
||||
return this.get().locator('[data-pw="nc-form-input-help-text"]'); |
||||
} |
||||
|
||||
///////////////////////////
|
||||
// Form Actions
|
||||
|
||||
async verifyFormViewFieldsOrder({ fields }: { fields: string[] }) { |
||||
let fieldLabels = await this.get().locator( |
||||
'[data-pw="nc-form-input-label"]' |
||||
); |
||||
expect(await fieldLabels.count()).toBe(fields.length); |
||||
for (let i = 0; i < fields.length; i++) { |
||||
// using toContainText instead of toBe because of the extra
|
||||
// text (*) in the label for required fields
|
||||
await expect(await fieldLabels.nth(i)).toContainText(fields[i]); |
||||
} |
||||
} |
||||
|
||||
async reorderFields({ |
||||
sourceField, |
||||
destinationField, |
||||
}: { |
||||
sourceField: string; |
||||
destinationField: string; |
||||
}) { |
||||
expect( |
||||
await this.get().locator(`.nc-form-drag-${sourceField}`) |
||||
).toBeVisible(); |
||||
expect( |
||||
await this.get().locator(`.nc-form-drag-${destinationField}`) |
||||
).toBeVisible(); |
||||
let src = await this.get().locator( |
||||
`.nc-form-drag-${sourceField.replace(" ", "")}` |
||||
); |
||||
let dst = await this.get().locator( |
||||
`.nc-form-drag-${destinationField.replace(" ", "")}` |
||||
); |
||||
await src.dragTo(dst); |
||||
} |
||||
|
||||
async removeField({ field, mode }: { mode: string; field: string }) { |
||||
if (mode === "dragDrop") { |
||||
let src = await this.get().locator( |
||||
`.nc-form-drag-${field.replace(" ", "")}` |
||||
); |
||||
let dst = await this.get().locator(`[data-pw="nc-drag-n-drop-to-hide"]`); |
||||
await src.dragTo(dst); |
||||
} else if (mode === "hideField") { |
||||
let src = await this.get().locator( |
||||
`.nc-form-drag-${field.replace(" ", "")}` |
||||
); |
||||
await src.locator(`[data-pw="nc-field-remove-icon"]`).click(); |
||||
} |
||||
} |
||||
|
||||
async addField({ field, mode }: { mode: string; field: string }) { |
||||
if (mode === "dragDrop") { |
||||
let src = await this.get().locator( |
||||
`[data-pw="nc-form-hidden-column-${field}"]` |
||||
); |
||||
let dst = await this.get().locator(`.nc-form-drag-Country`); |
||||
await src.dragTo(dst); |
||||
} else if (mode === "clickField") { |
||||
let src = await this.get().locator( |
||||
`[data-pw="nc-form-hidden-column-${field}"]` |
||||
); |
||||
await src.click(); |
||||
} |
||||
} |
||||
|
||||
async removeAllFields() { |
||||
await this.removeAllButton.click(); |
||||
} |
||||
|
||||
async addAllFields() { |
||||
await this.addAllButton.click(); |
||||
} |
||||
|
||||
async configureHeader(param: { subtitle: string; title: string }) { |
||||
await this.formHeading.fill(param.title); |
||||
await this.formSubHeading.fill(param.subtitle); |
||||
} |
||||
|
||||
async verifyHeader(param: { subtitle: string; title: string }) { |
||||
expect(await this.formHeading.inputValue()).toBe(param.title); |
||||
expect(await this.formSubHeading.inputValue()).toBe(param.subtitle); |
||||
} |
||||
|
||||
async fillForm(param: { field: string; value: string }[]) { |
||||
for (let i = 0; i < param.length; i++) { |
||||
await this.get() |
||||
.locator( |
||||
`[data-pw="nc-form-input-${param[i].field.replace( |
||||
" ", |
||||
"" |
||||
)}"] >> input` |
||||
) |
||||
.fill(param[i].value); |
||||
} |
||||
} |
||||
|
||||
async submitForm() { |
||||
await this.submitButton.click(); |
||||
} |
||||
|
||||
async verifyStatePostSubmit(param: { |
||||
message?: string; |
||||
submitAnotherForm?: boolean; |
||||
showBlankForm?: boolean; |
||||
}) { |
||||
if (undefined !== param.message) { |
||||
expect(await this.getFormAfterSubmit()).toContainText(param.message); |
||||
} |
||||
if (true === param.submitAnotherForm) { |
||||
expect( |
||||
await this.getFormAfterSubmit().locator( |
||||
'button:has-text("Submit Another Form")' |
||||
) |
||||
).toBeVisible(); |
||||
} |
||||
if (true === param.showBlankForm) { |
||||
await this.get().waitFor(); |
||||
} |
||||
} |
||||
|
||||
async configureSubmitMessage(param: { message: string }) { |
||||
await this.afterSubmitMsg.fill(param.message); |
||||
} |
||||
|
||||
submitAnotherForm() { |
||||
return this.getFormAfterSubmit().locator( |
||||
'button:has-text("Submit Another Form")' |
||||
); |
||||
} |
||||
|
||||
verifyAfterSubmitMenuState(param: { |
||||
showBlankForm?: boolean; |
||||
submitAnotherForm?: boolean; |
||||
emailMe?: boolean; |
||||
}) { |
||||
if (true === param.showBlankForm) { |
||||
expect( |
||||
this.get().locator( |
||||
'[data-pw="nc-form-checkbox-show-blank-form"][aria-checked="true"]' |
||||
) |
||||
).toBeVisible(); |
||||
} |
||||
if (true === param.submitAnotherForm) { |
||||
expect( |
||||
this.get().locator( |
||||
'[data-pw="nc-form-checkbox-submit-another-form"][aria-checked="true"]' |
||||
) |
||||
).toBeVisible(); |
||||
} |
||||
if (true === param.emailMe) { |
||||
expect( |
||||
this.get().locator( |
||||
'[data-pw="nc-form-checkbox-send-email"][aria-checked="true"]' |
||||
) |
||||
).toBeVisible(); |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,56 @@
|
||||
import { expect } from "@playwright/test"; |
||||
import { SettingsPage } from "."; |
||||
import BasePage from "../../Base"; |
||||
|
||||
export class AppStoreSettingsPage extends BasePage { |
||||
private readonly settings: SettingsPage; |
||||
|
||||
constructor(settings: SettingsPage) { |
||||
super(settings.rootPage); |
||||
this.settings = settings; |
||||
} |
||||
|
||||
get() { |
||||
return this.settings |
||||
.get() |
||||
.locator(`[pw-data="nc-settings-subtab-appStore"]`); |
||||
} |
||||
|
||||
async install({ name }: { name: string }) { |
||||
let card = this.settings.get().locator(`.nc-app-store-card-${name}`); |
||||
// get()
|
||||
// .locator(`[pw-data="nc-app-store-card-${name}"]`)
|
||||
// .scrollIntoViewIfNeeded();
|
||||
|
||||
// await card.scrollIntoViewIfNeeded();
|
||||
await card.click(); |
||||
await card.locator(".nc-app-store-card-install").click(); |
||||
} |
||||
|
||||
async configureSMTP({ |
||||
email, |
||||
host, |
||||
port, |
||||
}: { |
||||
email: string; |
||||
host: string; |
||||
port: string; |
||||
}) { |
||||
let appStoreCard = this.rootPage.locator(".nc-modal-plugin-install"); |
||||
|
||||
await appStoreCard.locator('[id="form_item_from"]').fill(email); |
||||
await appStoreCard.locator('[id="form_item_host"]').fill(host); |
||||
await appStoreCard.locator('[id="form_item_port"]').fill(port); |
||||
|
||||
await appStoreCard.locator('button:has-text("Save")').click(); |
||||
} |
||||
|
||||
async uninstall(param: { name: string }) { |
||||
let card = this.settings.get().locator(`.nc-app-store-card-${param.name}`); |
||||
|
||||
// await card.scrollIntoViewIfNeeded();
|
||||
await card.click(); |
||||
await card.locator(".nc-app-store-card-reset").click(); |
||||
await this.rootPage.locator("button.ant-btn-dangerous").click(); |
||||
} |
||||
} |
@ -1,37 +1,39 @@
|
||||
import { DashboardPage } from '..'; |
||||
import BasePage from '../../Base'; |
||||
import { AuditSettingsPage } from './Audit'; |
||||
import { MetaDataPage } from './Metadata'; |
||||
import { DashboardPage } from ".."; |
||||
import BasePage from "../../Base"; |
||||
import { AuditSettingsPage } from "./Audit"; |
||||
import { AppStoreSettingsPage } from "./AppStore"; |
||||
import { MetaDataPage } from "./Metadata"; |
||||
|
||||
const tabInfo = { |
||||
'Team & Auth': 'teamAndAuth', |
||||
'App Store': 'appStore', |
||||
'Project Metadata': 'projMetaData', |
||||
'Audit': 'audit', |
||||
} |
||||
|
||||
"Team & Auth": "teamAndAuth", |
||||
"App Store": "appStore", |
||||
"Project Metadata": "projMetaData", |
||||
Audit: "audit", |
||||
}; |
||||
|
||||
export class SettingsPage extends BasePage { |
||||
private readonly dashboard: DashboardPage; |
||||
readonly audit: AuditSettingsPage; |
||||
readonly appStore: AppStoreSettingsPage; |
||||
readonly metaData: MetaDataPage; |
||||
|
||||
constructor(dashboard: DashboardPage) { |
||||
super(dashboard.rootPage); |
||||
this.dashboard = dashboard; |
||||
this.audit = new AuditSettingsPage(this); |
||||
this.appStore = new AppStoreSettingsPage(this); |
||||
this.metaData = new MetaDataPage(this); |
||||
} |
||||
|
||||
get() { |
||||
return this.rootPage.locator('.nc-modal-settings'); |
||||
return this.rootPage.locator(".nc-modal-settings"); |
||||
} |
||||
|
||||
async selectTab({title}: {title: string}) { |
||||
async selectTab({ title }: { title: string }) { |
||||
await this.get().locator(`li[data-menu-id="${tabInfo[title]}"]`).click(); |
||||
} |
||||
|
||||
async close() { |
||||
await this.get().locator('[pw-data="settings-modal-close-button"]').click(); |
||||
} |
||||
} |
||||
} |
||||
|
@ -0,0 +1,177 @@
|
||||
import { test } from "@playwright/test"; |
||||
import { DashboardPage } from "../pages/Dashboard"; |
||||
import setup from "../setup"; |
||||
|
||||
test.describe("Form view", () => { |
||||
let dashboard: DashboardPage; |
||||
let context: any; |
||||
|
||||
test.beforeEach(async ({ page }) => { |
||||
context = await setup({ page }); |
||||
dashboard = new DashboardPage(page, context.project); |
||||
}); |
||||
|
||||
test("Field re-order operations", async () => { |
||||
// close 'Team & Auth' tab
|
||||
await dashboard.closeTab({ title: "Team & Auth" }); |
||||
await dashboard.treeView.openTable({ title: "Country" }); |
||||
|
||||
await dashboard.viewSidebar.createFormView({ title: "CountryForm" }); |
||||
await dashboard.viewSidebar.verifyView({ title: "CountryForm", index: 1 }); |
||||
|
||||
// verify form-view fields order
|
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["Country", "LastUpdate", "City List"], |
||||
}); |
||||
|
||||
// reorder & verify
|
||||
await dashboard.form.reorderFields({ |
||||
sourceField: "LastUpdate", |
||||
destinationField: "Country", |
||||
}); |
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["LastUpdate", "Country", "City List"], |
||||
}); |
||||
|
||||
// remove & verify (drag-drop)
|
||||
await dashboard.form.removeField({ field: "City List", mode: "dragDrop" }); |
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["LastUpdate", "Country"], |
||||
}); |
||||
|
||||
// add & verify (drag-drop)
|
||||
await dashboard.form.addField({ field: "City List", mode: "dragDrop" }); |
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["LastUpdate", "City List", "Country"], |
||||
}); |
||||
|
||||
// remove & verify (hide field button)
|
||||
await dashboard.form.removeField({ field: "City List", mode: "hideField" }); |
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["LastUpdate", "Country"], |
||||
}); |
||||
|
||||
// add & verify (hide field button)
|
||||
await dashboard.form.addField({ field: "City List", mode: "clickField" }); |
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["LastUpdate", "Country", "City List"], |
||||
}); |
||||
|
||||
// remove-all & verify
|
||||
await dashboard.form.removeAllFields(); |
||||
await dashboard.rootPage.waitForTimeout(2000); |
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["Country"], |
||||
}); |
||||
|
||||
// // add-all & verify
|
||||
await dashboard.form.addAllFields(); |
||||
await dashboard.rootPage.waitForTimeout(2000); |
||||
await dashboard.form.verifyFormViewFieldsOrder({ |
||||
fields: ["LastUpdate", "Country", "City List"], |
||||
}); |
||||
}); |
||||
|
||||
test("Form elements validation", async () => { |
||||
// close 'Team & Auth' tab
|
||||
await dashboard.closeTab({ title: "Team & Auth" }); |
||||
await dashboard.treeView.openTable({ title: "Country" }); |
||||
|
||||
await dashboard.viewSidebar.createFormView({ title: "CountryForm" }); |
||||
await dashboard.viewSidebar.verifyView({ title: "CountryForm", index: 1 }); |
||||
|
||||
await dashboard.form.configureHeader({ |
||||
title: "Country", |
||||
subtitle: "Country subtitle", |
||||
}); |
||||
await dashboard.form.verifyHeader({ |
||||
title: "Country", |
||||
subtitle: "Country subtitle", |
||||
}); |
||||
|
||||
// retain only 'Country' field
|
||||
await dashboard.form.removeAllFields(); |
||||
|
||||
// submit default form validation
|
||||
await dashboard.form.fillForm([{ field: "Country", value: "_abc" }]); |
||||
await dashboard.form.submitForm(); |
||||
await dashboard.form.verifyStatePostSubmit({ |
||||
message: "Successfully submitted form data", |
||||
}); |
||||
|
||||
// submit custom form validation
|
||||
await dashboard.viewSidebar.openView({ title: "CountryForm" }); |
||||
await dashboard.form.configureSubmitMessage({ |
||||
message: "Custom submit message", |
||||
}); |
||||
await dashboard.form.fillForm([{ field: "Country", value: "_abc" }]); |
||||
await dashboard.form.submitForm(); |
||||
await dashboard.form.verifyStatePostSubmit({ |
||||
message: "Custom submit message", |
||||
}); |
||||
|
||||
// enable 'submit another form' option
|
||||
await dashboard.viewSidebar.openView({ title: "CountryForm" }); |
||||
await dashboard.form.showAnotherFormRadioButton.click(); |
||||
await dashboard.form.fillForm([{ field: "Country", value: "_abc" }]); |
||||
await dashboard.form.submitForm(); |
||||
await dashboard.rootPage.waitForTimeout(2000); |
||||
await dashboard.form.verifyStatePostSubmit({ |
||||
submitAnotherForm: true, |
||||
}); |
||||
await dashboard.form.submitAnotherForm().click(); |
||||
|
||||
// enable 'show another form' option
|
||||
await dashboard.form.showAnotherFormRadioButton.click(); |
||||
await dashboard.form.showAnotherFormAfter5SecRadioButton.click(); |
||||
await dashboard.form.fillForm([{ field: "Country", value: "_abc" }]); |
||||
await dashboard.form.fillForm([{ field: "Country", value: "_abc" }]); |
||||
await dashboard.form.submitForm(); |
||||
await dashboard.rootPage.waitForTimeout(6000); |
||||
await dashboard.form.verifyStatePostSubmit({ |
||||
showBlankForm: true, |
||||
}); |
||||
|
||||
// enable 'email-me' option
|
||||
await dashboard.form.showAnotherFormAfter5SecRadioButton.click(); |
||||
await dashboard.form.emailMeRadioButton.click(); |
||||
await dashboard.toastWait({ |
||||
message: |
||||
"Please activate SMTP plugin in App store for enabling email notification", |
||||
}); |
||||
|
||||
// activate SMTP plugin
|
||||
await dashboard.gotoSettings(); |
||||
await dashboard.settings.selectTab({ title: "App Store" }); |
||||
await dashboard.settings.appStore.install({ name: "SMTP" }); |
||||
await dashboard.settings.appStore.configureSMTP({ |
||||
email: "a@b.com", |
||||
host: "smtp.gmail.com", |
||||
port: "587", |
||||
}); |
||||
await dashboard.toastWait({ |
||||
message: |
||||
"Successfully installed and email notification will use SMTP configuration", |
||||
}); |
||||
await dashboard.settings.close(); |
||||
|
||||
// enable 'email-me' option
|
||||
await dashboard.viewSidebar.openView({ title: "CountryForm" }); |
||||
await dashboard.form.emailMeRadioButton.click(); |
||||
await dashboard.form.verifyAfterSubmitMenuState({ |
||||
emailMe: true, |
||||
submitAnotherForm: false, |
||||
showBlankForm: false, |
||||
}); |
||||
|
||||
// reset SMTP
|
||||
await dashboard.gotoSettings(); |
||||
await dashboard.settings.selectTab({ title: "App Store" }); |
||||
await dashboard.settings.appStore.uninstall({ name: "SMTP" }); |
||||
|
||||
await dashboard.toastWait({ |
||||
message: "Plugin uninstalled successfully", |
||||
}); |
||||
await dashboard.settings.close(); |
||||
}); |
||||
}); |
Loading…
Reference in new issue