@ -0,0 +1,36 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
|
||||
export class ConfirmationModal {
|
||||
private readonly input: Locator;
|
||||
private readonly cancelButton: Locator;
|
||||
private readonly confirmButton: Locator;
|
||||
|
||||
constructor(public readonly page: Page) {
|
||||
this.page = page;
|
||||
this.input = page.getByTestId('confirmation-modal-input');
|
||||
this.cancelButton = page.getByRole('button', { name: 'Cancel' });
|
||||
this.confirmButton = page.getByTestId('confirmation-modal-confirm-button');
|
||||
}
|
||||
|
||||
async typePlaceholderToInput() {
|
||||
await this.page
|
||||
.getByTestId('confirmation-modal-input')
|
||||
.fill(
|
||||
await this.page
|
||||
.getByTestId('confirmation-modal-input')
|
||||
.getAttribute('placeholder'),
|
||||
);
|
||||
}
|
||||
|
||||
async typePhraseToInput(value: string) {
|
||||
await this.page.getByTestId('confirmation-modal-input').fill(value);
|
||||
}
|
||||
|
||||
async clickCancelButton() {
|
||||
await this.page.getByRole('button', { name: 'Cancel' }).click();
|
||||
}
|
||||
|
||||
async clickConfirmButton() {
|
||||
await this.page.getByTestId('confirmation-modal-confirm-button').click();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,28 @@
|
||||
const nth = (d: number) => {
|
||||
if (d > 3 && d < 21) return 'th';
|
||||
switch (d % 10) {
|
||||
case 1:
|
||||
return 'st';
|
||||
case 2:
|
||||
return 'nd';
|
||||
case 3:
|
||||
return 'rd';
|
||||
default:
|
||||
return 'th';
|
||||
}
|
||||
};
|
||||
|
||||
// label looks like this: Choose Wednesday, October 30th, 2024
|
||||
// eslint-disable-next-line prefer-arrow/prefer-arrow-functions
|
||||
export function formatDate(value: string): string {
|
||||
const date = new Date(value);
|
||||
return 'Choose '.concat(
|
||||
date.toLocaleDateString('en-US', { weekday: 'long' }),
|
||||
', ',
|
||||
date.toLocaleDateString('en-US', { month: 'long' }),
|
||||
' ',
|
||||
nth(date.getDate()),
|
||||
', ',
|
||||
date.toLocaleDateString('en-US', { year: 'numeric' }),
|
||||
);
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
|
||||
export class GoogleLogin {
|
||||
// TODO: map all things like inputs and buttons
|
||||
// (what's the correct way for proceeding with Google interaction? log in each time test is performed?)
|
||||
}
|
||||
23
packages/twenty-e2e-testing/lib/pom/helper/iconSelect.ts
Normal file
23
packages/twenty-e2e-testing/lib/pom/helper/iconSelect.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
|
||||
export class IconSelect {
|
||||
private readonly iconSelectButton: Locator;
|
||||
private readonly iconSearchInput: Locator;
|
||||
|
||||
constructor(public readonly page: Page) {
|
||||
this.iconSelectButton = page.getByLabel('Click to select icon (');
|
||||
this.iconSearchInput = page.getByPlaceholder('Search icon');
|
||||
}
|
||||
|
||||
async selectIcon(name: string) {
|
||||
await this.iconSelectButton.click();
|
||||
await this.iconSearchInput.fill(name);
|
||||
await this.page.getByTitle(name).click();
|
||||
}
|
||||
|
||||
async selectRelationIcon(name: string) {
|
||||
await this.iconSelectButton.nth(1).click();
|
||||
await this.iconSearchInput.fill(name);
|
||||
await this.page.getByTitle(name).click();
|
||||
}
|
||||
}
|
||||
267
packages/twenty-e2e-testing/lib/pom/helper/insertFieldData.ts
Normal file
267
packages/twenty-e2e-testing/lib/pom/helper/insertFieldData.ts
Normal file
@ -0,0 +1,267 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
import { formatDate } from './formatDate.function';
|
||||
|
||||
export class InsertFieldData {
|
||||
private readonly address1Input: Locator;
|
||||
private readonly address2Input: Locator;
|
||||
private readonly cityInput: Locator;
|
||||
private readonly stateInput: Locator;
|
||||
private readonly postCodeInput: Locator;
|
||||
private readonly countrySelect: Locator;
|
||||
private readonly arrayValueInput: Locator;
|
||||
private readonly arrayAddValueButton: Locator;
|
||||
// boolean react after click so no need to write special locator
|
||||
private readonly currencySelect: Locator;
|
||||
private readonly currencyAmountInput: Locator;
|
||||
private readonly monthSelect: Locator;
|
||||
private readonly yearSelect: Locator;
|
||||
private readonly previousMonthButton: Locator;
|
||||
private readonly nextMonthButton: Locator;
|
||||
private readonly clearDateButton: Locator;
|
||||
private readonly dateInput: Locator;
|
||||
private readonly firstNameInput: Locator;
|
||||
private readonly lastNameInput: Locator;
|
||||
private readonly addURLButton: Locator;
|
||||
private readonly setAsPrimaryButton: Locator;
|
||||
private readonly addPhoneButton: Locator;
|
||||
private readonly addMailButton: Locator;
|
||||
|
||||
constructor(public readonly page: Page) {
|
||||
this.page = page;
|
||||
this.address1Input = page.locator(
|
||||
'//label[contains(., "ADDRESS 1")]/../div[last()]/input',
|
||||
);
|
||||
this.address2Input = page.locator(
|
||||
'//label[contains(., "ADDRESS 2")]/../div[last()]/input',
|
||||
);
|
||||
this.cityInput = page.locator(
|
||||
'//label[contains(., "CITY")]/../div[last()]/input',
|
||||
);
|
||||
this.stateInput = page.locator(
|
||||
'//label[contains(., "STATE")]/../div[last()]/input',
|
||||
);
|
||||
this.postCodeInput = page.locator(
|
||||
'//label[contains(., "POST CODE")]/../div[last()]/input',
|
||||
);
|
||||
this.countrySelect = page.locator(
|
||||
'//span[contains(., "COUNTRY")]/../div[last()]/input',
|
||||
);
|
||||
this.arrayValueInput = page.locator("//input[@placeholder='Enter value']");
|
||||
this.arrayAddValueButton = page.locator(
|
||||
"//div[@data-testid='tooltip' and contains(.,'Add item')]",
|
||||
);
|
||||
this.currencySelect = page.locator(
|
||||
'//body/div[last()]/div/div/div[first()]/div/div',
|
||||
);
|
||||
this.currencyAmountInput = page.locator("//input[@placeholder='Currency']");
|
||||
this.monthSelect; // TODO: add once some other attributes are added
|
||||
this.yearSelect;
|
||||
this.previousMonthButton;
|
||||
this.nextMonthButton;
|
||||
this.clearDateButton = page.locator(
|
||||
"//div[@data-testid='tooltip' and contains(., 'Clear')]",
|
||||
);
|
||||
this.dateInput = page.locator("//input[@placeholder='Type date and time']");
|
||||
this.firstNameInput = page.locator("//input[@placeholder='First name']"); // may fail if placeholder is `F‌‌irst name` instead of `First name`
|
||||
this.lastNameInput = page.locator("//input[@placeholder='Last name']"); // may fail if placeholder is `L‌‌ast name` instead of `Last name`
|
||||
this.addURLButton = page.locator(
|
||||
"//div[@data-testid='tooltip' and contains(., 'Add URL')]",
|
||||
);
|
||||
this.setAsPrimaryButton = page.locator(
|
||||
"//div[@data-testid='tooltip' and contains(., 'Set as primary')]",
|
||||
);
|
||||
this.addPhoneButton = page.locator(
|
||||
"//div[@data-testid='tooltip' and contains(., 'Add Phone')]",
|
||||
);
|
||||
this.addMailButton = page.locator(
|
||||
"//div[@data-testid='tooltip' and contains(., 'Add Email')]",
|
||||
);
|
||||
}
|
||||
|
||||
// address
|
||||
async typeAddress1(value: string) {
|
||||
await this.address1Input.fill(value);
|
||||
}
|
||||
|
||||
async typeAddress2(value: string) {
|
||||
await this.address2Input.fill(value);
|
||||
}
|
||||
|
||||
async typeCity(value: string) {
|
||||
await this.cityInput.fill(value);
|
||||
}
|
||||
|
||||
async typeState(value: string) {
|
||||
await this.stateInput.fill(value);
|
||||
}
|
||||
|
||||
async typePostCode(value: string) {
|
||||
await this.postCodeInput.fill(value);
|
||||
}
|
||||
|
||||
async selectCountry(value: string) {
|
||||
await this.countrySelect.click();
|
||||
await this.page
|
||||
.locator(`//div[@data-testid='tooltip' and contains(., '${value}')]`)
|
||||
.click();
|
||||
}
|
||||
|
||||
// array
|
||||
async typeArrayValue(value: string) {
|
||||
await this.arrayValueInput.fill(value);
|
||||
}
|
||||
|
||||
async clickAddItemButton() {
|
||||
await this.arrayAddValueButton.click();
|
||||
}
|
||||
|
||||
// currency
|
||||
async selectCurrency(value: string) {
|
||||
await this.currencySelect.click();
|
||||
await this.page
|
||||
.locator(`//div[@data-testid='tooltip' and contains(., '${value}')]`)
|
||||
.click();
|
||||
}
|
||||
|
||||
async typeCurrencyAmount(value: string) {
|
||||
await this.currencyAmountInput.fill(value);
|
||||
}
|
||||
|
||||
// date(-time)
|
||||
async typeDate(value: string) {
|
||||
await this.dateInput.fill(value);
|
||||
}
|
||||
|
||||
async selectMonth(value: string) {
|
||||
await this.monthSelect.click();
|
||||
await this.page
|
||||
.locator(`//div[@data-testid='tooltip' and contains(., '${value}')]`)
|
||||
.click();
|
||||
}
|
||||
|
||||
async selectYear(value: string) {
|
||||
await this.yearSelect.click();
|
||||
await this.page
|
||||
.locator(`//div[@data-testid='tooltip' and contains(., '${value}')]`)
|
||||
.click();
|
||||
}
|
||||
|
||||
async clickPreviousMonthButton() {
|
||||
await this.previousMonthButton.click();
|
||||
}
|
||||
|
||||
async clickNextMonthButton() {
|
||||
await this.nextMonthButton.click();
|
||||
}
|
||||
|
||||
async selectDay(value: string) {
|
||||
await this.page
|
||||
.locator(`//div[@aria-label='${formatDate(value)}']`)
|
||||
.click();
|
||||
}
|
||||
|
||||
async clearDate() {
|
||||
await this.clearDateButton.click();
|
||||
}
|
||||
|
||||
// email
|
||||
async typeEmail(value: string) {
|
||||
await this.page.locator(`//input[@placeholder='Email']`).fill(value);
|
||||
}
|
||||
|
||||
async clickAddMailButton() {
|
||||
await this.addMailButton.click();
|
||||
}
|
||||
|
||||
// full name
|
||||
async typeFirstName(name: string) {
|
||||
await this.firstNameInput.fill(name);
|
||||
}
|
||||
|
||||
async typeLastName(name: string) {
|
||||
await this.lastNameInput.fill(name);
|
||||
}
|
||||
|
||||
// JSON
|
||||
// placeholder is dependent on the name of field
|
||||
async typeJSON(placeholder: string, value: string) {
|
||||
await this.page
|
||||
.locator(`//input[@placeholder='${placeholder}']`)
|
||||
.fill(value);
|
||||
}
|
||||
|
||||
// link
|
||||
async typeLink(value: string) {
|
||||
await this.page.locator("//input[@placeholder='URL']").fill(value);
|
||||
}
|
||||
|
||||
async clickAddURL() {
|
||||
await this.addURLButton.click();
|
||||
}
|
||||
|
||||
// (multi-)select
|
||||
async selectValue(value: string) {
|
||||
await this.page
|
||||
.locator(`//div[@data-testid='tooltip' and contains(., '${value}')]`)
|
||||
.click();
|
||||
}
|
||||
|
||||
// number
|
||||
// placeholder is dependent on the name of field
|
||||
async typeNumber(placeholder: string, value: string) {
|
||||
await this.page
|
||||
.locator(`//input[@placeholder='${placeholder}']`)
|
||||
.fill(value);
|
||||
}
|
||||
|
||||
// phones
|
||||
async selectCountryPhoneCode(countryCode: string) {
|
||||
await this.page
|
||||
.locator(
|
||||
`//div[@data-testid='tooltip' and contains(., '${countryCode}')]`,
|
||||
)
|
||||
.click();
|
||||
}
|
||||
|
||||
async typePhoneNumber(value: string) {
|
||||
await this.page.locator(`//input[@placeholder='Phone']`).fill(value);
|
||||
}
|
||||
|
||||
async clickAddPhoneButton() {
|
||||
await this.addPhoneButton.click();
|
||||
}
|
||||
|
||||
// rating
|
||||
// if adding rating for the first time, hover must be used
|
||||
async selectRating(rating: number) {
|
||||
await this.page.locator(`//div[@role='slider']/div[${rating}]`).click();
|
||||
}
|
||||
|
||||
// text
|
||||
// placeholder is dependent on the name of field
|
||||
async typeText(placeholder: string, value: string) {
|
||||
await this.page
|
||||
.locator(`//input[@placeholder='${placeholder}']`)
|
||||
.fill(value);
|
||||
}
|
||||
|
||||
async clickSetAsPrimaryButton() {
|
||||
await this.setAsPrimaryButton.click();
|
||||
}
|
||||
|
||||
async searchValue(value: string) {
|
||||
await this.page.locator(`//div[@placeholder='Search']`).fill(value);
|
||||
}
|
||||
|
||||
async clickEditButton() {
|
||||
await this.page
|
||||
.locator("//div[@data-testid='tooltip' and contains(., 'Edit')]")
|
||||
.click();
|
||||
}
|
||||
|
||||
async clickDeleteButton() {
|
||||
await this.page
|
||||
.locator("//div[@data-testid='tooltip' and contains(., 'Delete')]")
|
||||
.click();
|
||||
}
|
||||
}
|
||||
5
packages/twenty-e2e-testing/lib/pom/helper/stripePage.ts
Normal file
5
packages/twenty-e2e-testing/lib/pom/helper/stripePage.ts
Normal file
@ -0,0 +1,5 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
|
||||
export class StripePage {
|
||||
// TODO: implement all necessary methods (staging/sandbox page - does it differ anyhow from normal page?)
|
||||
}
|
||||
25
packages/twenty-e2e-testing/lib/pom/helper/uploadImage.ts
Normal file
25
packages/twenty-e2e-testing/lib/pom/helper/uploadImage.ts
Normal file
@ -0,0 +1,25 @@
|
||||
import { Locator, Page } from '@playwright/test';
|
||||
|
||||
export class UploadImage {
|
||||
private readonly imagePreview: Locator;
|
||||
private readonly uploadButton: Locator;
|
||||
private readonly removeButton: Locator;
|
||||
|
||||
constructor(public readonly page: Page) {
|
||||
this.imagePreview = page.locator('.css-6eut39'); //TODO: add attribute to make it independent of theme
|
||||
this.uploadButton = page.getByRole('button', { name: 'Upload' });
|
||||
this.removeButton = page.getByRole('button', { name: 'Remove' });
|
||||
}
|
||||
|
||||
async clickImagePreview() {
|
||||
await this.imagePreview.click();
|
||||
}
|
||||
|
||||
async clickUploadButton() {
|
||||
await this.uploadButton.click();
|
||||
}
|
||||
|
||||
async clickRemoveButton() {
|
||||
await this.removeButton.click();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user