Skip to content

Commit

Permalink
e2e tests for customer CRUD (#4657)
Browse files Browse the repository at this point in the history
Co-authored-by: yellowee <[email protected]>
  • Loading branch information
karola312 and yellowee authored Apr 26, 2024
1 parent f99fc51 commit cb5988f
Show file tree
Hide file tree
Showing 30 changed files with 881 additions and 92 deletions.
5 changes: 5 additions & 0 deletions .changeset/brown-mayflies-check.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---

E2E tests for customer CRUD
59 changes: 59 additions & 0 deletions playwright/data/addresses.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import faker from "faker";

export type AddressType = {
addressUK: AddressFieldsType;
addressPL: AddressFieldsType;
addressUS: AddressFieldsType;
};

export type AddressFieldsType = {
firstName: string;
lastName: string;
companyName: string;
phone: string;
addressLine1: string;
addressLine2: string;
zip: string;
city: string;
country: string;
countryArea: string;
};

export const ADDRESS: AddressType = {
addressUS: {
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
companyName: faker.company.companyName(),
phone: "+12125771133",
addressLine1: "69 W 9th Street",
addressLine2: faker.address.county(),
city: "New York",
zip: "10001",
country: "United States of America",
countryArea: "New York",
},
addressPL: {
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
companyName: faker.company.companyName(),
phone: "+48225042123",
addressLine1: "Teczowa",
addressLine2: "7",
city: "WROCLAW",
zip: "53-601",
country: "Poland",
countryArea: "",
},
addressUK: {
firstName: faker.name.firstName(),
lastName: faker.name.lastName(),
companyName: faker.company.companyName(),
phone: "+445556667777",
addressLine1: "Albert Street",
addressLine2: "78/2",
city: "Edinburgh",
zip: "EH7 5LR",
country: "United Kingdom",
countryArea: "",
},
};
60 changes: 60 additions & 0 deletions playwright/data/e2eTestData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -619,3 +619,63 @@ export const PRODUCT_TYPES = {
ids: ["UHJvZHVjdFR5cGU6NzAw", "UHJvZHVjdFR5cGU6NzAx"],
},
};
export const CUSTOMERS = {
deleteCustomer: {
id: "VXNlcjoxMzY3",
email: "[email protected]",
},
editCustomer: {
id: "VXNlcjoxMzY2",
email: "[email protected]",
note: "simple note",
initialShippingAddress: {
firstName: "e2e_customer_with_addresses",
lastName: "to-be-edited",
companyName: "Saleor",
phone: "+48225042123",
addressLine1: "Teczowa",
addressLine2: "7",
city: "WROCLAW",
zip: "53-601",
country: "Poland",
},
initialBillingAddress: {
firstName: "address",
lastName: "to-be-deleted",
companyName: "Saleor",
phone: "+48225042123",
addressLine1: "Teczowa",
addressLine2: "7",
city: "WROCLAW",
zip: "53-601",
country: "Poland",
},
additionalAddress: {
firstName: "Test",
lastName: "Test",
addressLine1: "Nowy Świat",
city: "WARSZAWA",
zip: "00-504",
country: "Poland",
},
},
customersToBeBulkDeleted: {
names: [
"e2e_customer_1 bulk-delete",
"e2e_customer_2 bulk-delete",
"e2e_customer_3 bulk-delete",
],
},
customerToBeActivated: {
id: "VXNlcjoxMzY0",
email: "[email protected]",
firstName: "e2e-customer",
lastName: "to-be-activated",
},
customerToBeDeactivated: {
id: "VXNlcjoxMzY1",
email: "[email protected]",
firstName: "e2e-customer",
lastName: "to-be-deactivated",
},
};
104 changes: 104 additions & 0 deletions playwright/pages/addressesListPage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { AddressFieldsType } from "@data/addresses";
import { expect, Page } from "@playwright/test";

import { BasePage } from "./basePage";

export class AddressesListPage extends BasePage {
constructor(
page: Page,
readonly editAddressButton = page.getByTestId("edit-address"),
readonly deleteAddressButton = page.getByTestId("delete-address"),
readonly addAddressButton = page.getByTestId("add-address"),
readonly addressTypeTitle = page.getByTestId("address-type-title"),
readonly addressCard = page.getByTestId("address-card"),
readonly savedAddress = page.getByTestId("address"),
readonly menageAddressButton = page.getByTestId("manage-addresses"),
readonly showMoreMenuButton = page.getByTestId("show-more-button"),
readonly addAddressDialog = page.getByTestId("add-address-dialog"),
readonly setAsDefaultBilling = page.getByTestId("set-default-billing-address"),
readonly setAsDefaultShipping = page.getByTestId("set-default-shipping-address"),
readonly deleteDialog = page.getByTestId("delete-address-dialog-content"),
readonly companyName = page.getByTestId("company-name"),
readonly addressLines = page.getByTestId("addressLines"),
readonly postalCodeAndCity = page.getByTestId("postal-code-and-city"),
readonly countryAreaAndCountry = page.getByTestId("country-area-and-country"),
readonly name = page.getByTestId("name"),
readonly phone = page.getByTestId("phone"),
) {
super(page);
}

async clickShowMoreMenu(addressPart: string) {
await this.addressCard
.filter({ hasText: addressPart })
.locator(this.showMoreMenuButton)
.click();
}

async clickManageAddresses() {
await this.menageAddressButton.click();
}

async clickAddAddressButton() {
await this.addAddressButton.click();
}

async clickEditAddress() {
await this.editAddressButton.click();
}

async clickDeleteAddress() {
await this.deleteAddressButton.click();
await this.waitForDOMToFullyLoad();
}

async setAsDeafultShippingAddress() {
await this.setAsDefaultShipping.click();
}

async setAsDeafultBillingAddress() {
await this.setAsDefaultBilling.click();
}

async verifyRequiredAddressFields(addressPart: string, address: AddressFieldsType) {
const addressToVerify = await this.savedAddress.filter({
hasText: addressPart,
});
const city = address.city.toUpperCase();

await expect(addressToVerify.locator(this.name)).toContainText(
`${address.firstName} ${address.lastName}`,
);
await expect(addressToVerify.locator(this.addressLines)).toContainText(address.addressLine1);
await expect(addressToVerify.locator(this.postalCodeAndCity)).toContainText(
` ${address.zip} ${city}`,
);
await expect(addressToVerify.locator(this.countryAreaAndCountry)).toContainText(
address.country,
);
}

async verifyPhoneField(addressPart: string, address: AddressFieldsType) {
const addressToVerify = await this.savedAddress.filter({
hasText: addressPart,
});

await expect(addressToVerify.locator(this.phone)).toContainText(address.phone);
}

async verifyCompanyField(addressPart: string, address: AddressFieldsType) {
const addressToVerify = await this.savedAddress.filter({
hasText: addressPart,
});

await expect(addressToVerify.locator(this.companyName)).toContainText(address.companyName);
}

async verifyAddressLine2Field(addressPart: string, address: AddressFieldsType) {
const addressToVerify = await this.savedAddress.filter({
hasText: addressPart,
});

await expect(addressToVerify.locator(this.addressLines)).toContainText(address.addressLine2);
}
}
40 changes: 38 additions & 2 deletions playwright/pages/basePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ export class BasePage {
readonly searchInputListView = page.getByTestId("search-input"),
readonly emptyDataGridListView = page.getByTestId("empty-data-grid-text"),
readonly dialog = page.getByRole("dialog"),
readonly giftCardInTable = page.locator('[href*="/dashboard/gift-cards/.*]'),
readonly selectAllCheckbox = page.getByTestId("select-all-checkbox").locator("input"),
) {
this.page = page;
Expand Down Expand Up @@ -63,7 +64,10 @@ export class BasePage {
}

async typeInSearchOnListView(searchItem: string) {
await this.searchInputListView.fill(searchItem);
await this.waitForNetworkIdle(async () => {
await this.searchInputListView.fill(searchItem);
await this.waitForDOMToFullyLoad();
});
}

async clickNextPageButton() {
Expand Down Expand Up @@ -95,6 +99,10 @@ export class BasePage {
await expect(this.errorBanner, "No error banner should be visible").not.toBeVisible();
}

async expectErrorBannerMessage(msg: string) {
await this.errorBanner.locator(`text=${msg}`).waitFor({ state: "visible", timeout: 10000 });
}

async expectSuccessBanner() {
await this.successBanner.first().waitFor({ state: "visible", timeout: 15000 });
await expect(this.errorBanner, "No error banner should be visible").not.toBeVisible();
Expand All @@ -105,7 +113,7 @@ export class BasePage {
await expect(this.errorBanner, "No error banner should be visible").not.toBeVisible();
}

async waitForNetworkIdle(action: () => Promise<void>, timeoutMs = 50000) {
async waitForNetworkIdle(action: () => Promise<void>, timeoutMs = 60000) {
const responsePromise = this.page.waitForResponse("**/graphql/", {
timeout: timeoutMs,
});
Expand Down Expand Up @@ -146,6 +154,7 @@ export class BasePage {
We seek over the fiber node (hack), ignore typings for it.
*/
const fiberParent = node.parentNode[fiberKey as keyof typeof node.parentNode] as any;

const bounds: { x: number; y: number; width: number; height: number } =
fiberParent.pendingProps.children.props.gridRef.current.getBounds(col, row);

Expand All @@ -163,6 +172,21 @@ export class BasePage {
);
}

async checkGridCellTextAndClick(
columnNumber: number,
rowsToCheck: number[],
listToCheck: string[],
) {
const searchResults = [];

for (let i = 0; i < rowsToCheck.length; i++) {
const searchResult = await this.getGridCellText(rowsToCheck[i], columnNumber);

searchResults.push(searchResult);
await expect(searchResult).toEqual(listToCheck[i]);
await this.clickGridCell(columnNumber, rowsToCheck[i]);
}
}
/*
Example:
Expand Down Expand Up @@ -197,6 +221,7 @@ export class BasePage {
await this.gridCanvas.locator("table tr").first().waitFor({ state: "attached" });

const rowIndexes: number[] = [];

const rows = await this.page.$$eval("table tr", rows => rows.map(row => row.textContent));

for (const searchedText of searchTextArray) {
Expand Down Expand Up @@ -263,4 +288,15 @@ export class BasePage {
async waitForDOMToFullyLoad() {
await this.page.waitForLoadState("domcontentloaded", { timeout: 70000 });
}

async expectElementIsHidden(locator: Locator) {
await locator.first().waitFor({
state: "hidden",
timeout: 30000,
});
}

async waitForCanvasContainsText(text: string) {
await this.gridCanvas.getByText(text).waitFor({ state: "attached", timeout: 50000 });
}
}
Loading

0 comments on commit cb5988f

Please sign in to comment.