Skip to content

Commit

Permalink
adding tests for creating promotions (#4683)
Browse files Browse the repository at this point in the history
  • Loading branch information
yellowee authored Feb 29, 2024
1 parent 4d778e4 commit 1dcb956
Show file tree
Hide file tree
Showing 20 changed files with 252 additions and 24 deletions.
5 changes: 5 additions & 0 deletions .changeset/cold-grapes-compete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"saleor-dashboard": minor
---

Adding e2e tests for promotion CRUD
2 changes: 2 additions & 0 deletions playwright/data/commonLocators.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export const LOCATORS = {
saveButton: "[data-test-id=\"button-bar-confirm\"]",
successBanner: "[data-test-type=\"success\"]",
errorBanner: "[data-test-type=\"error\"]",
infoBanner: "[data-test-type=\"info\"]",
dataGridTable: "[data-testid=\"data-grid-canvas\"]",
deleteButton: "[data-test-id=\"button-bar-delete\"]",
};
19 changes: 18 additions & 1 deletion playwright/data/e2eTestData.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const VOUCHERS_AND_DISCOUNTS = {
export const VOUCHERS = {
vouchers: {
voucherToBeEditedWithFreeShipping: {
id: "Vm91Y2hlcjoyMDI%3D",
Expand All @@ -22,6 +22,23 @@ export const VOUCHERS_AND_DISCOUNTS = {
},
},
};
export const DISCOUNTS = {
promotionToBeEdited: {
name: "e2e promotion to be edited",
type: "Catalog",
id: "UHJvbW90aW9uOjI0MGVkZGVkLWYzMTAtNGUzZi1iNTlmLTFlMGFkYWE2ZWFkYg=="
},
promotionWithoutRulesToBeDeleted: {
id: "UHJvbW90aW9uOjRmNTQwMDc1LTZlZGMtNDI1NC1hY2U2LTQ2MzdlMGYxZWJhOA==",
name: "e2e Order predicate promotion without rules",
type: "Order",

},
promotionWithRulesToBeDeleted: {
name: "e2e Catalog predicate promotion with rules",
id: "UHJvbW90aW9uOjY0N2M2MzdhLTZjNTEtNDYxZC05MjQ2LTc0YTY0OGM0ZjAxNA==",
}}

export const CUSTOMER_ADDRESS = {
changeBillingAddress: {
firstName: "Change Billing Address",
Expand Down
3 changes: 2 additions & 1 deletion playwright/data/url.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export const URL_LIST = {
productsAdd: "add?product-type-id=",
productTypes: "product-types/",
productTypesAdd: "product-types/add",
sales: "discounts/sales/",
discounts: "discounts/sales/",
discountAddPage: "discounts/sales/add",
shippingMethods: "shipping/",
siteSettings: "site-settings/",
staffMembers: "staff/",
Expand Down
11 changes: 9 additions & 2 deletions playwright/pages/basePage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@ export class BasePage {
.locator('[class="clip-region"]')
.locator("textarea"),
readonly successBanner = page.locator(LOCATORS.successBanner),
readonly deleteButton = page.locator(LOCATORS.deleteButton),
readonly filterButton = page.getByTestId("filters-button"),
readonly errorBanner = page.locator(LOCATORS.errorBanner),
readonly saveButton = page.locator(LOCATORS.saveButton),
readonly infoBanner = page.locator(LOCATORS.infoBanner),
readonly previousPagePaginationButton = page.getByTestId(
"button-pagination-back",
Expand Down Expand Up @@ -47,7 +49,9 @@ export class BasePage {
async clickBulkDeleteGridRowsButton() {
await this.bulkDeleteGridRowsButton.click();
}

async clickDeleteButton() {
await this.deleteButton.click();
}
async typeInSearchOnListView(searchItem: string) {
await this.searchInputListView.fill(searchItem);
}
Expand All @@ -73,6 +77,9 @@ export class BasePage {
timeout: 10000,
});
}
async clickSaveButton() {
await this.saveButton.click();
}
async expectSuccessBannerMessage(msg: string) {
await this.successBanner
.locator(`text=${msg}`)
Expand Down Expand Up @@ -121,7 +128,7 @@ export class BasePage {

if (!fiberKey || !node.parentNode) return null;

/*
/*
We seek over the fiber node (hack), ignore typings for it.
*/
const fiberParent = node.parentNode[
Expand Down
18 changes: 18 additions & 0 deletions playwright/pages/dialogs/deleteDiscountDialog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import type { Page } from "@playwright/test";

export class DeleteDiscountDialog {
readonly page: Page;

constructor(
page: Page,
readonly deleteButton = page.getByTestId(
"delete-confirmation-button",
),
) {
this.page = page;
}

async clickConfirmDeleteButton() {
await this.deleteButton.click();
}
}
100 changes: 97 additions & 3 deletions playwright/pages/discountsPage.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,106 @@
import type { Page } from "@playwright/test";
import { URL_LIST } from "@data/url";
import { DeleteDiscountDialog } from "@dialogs/deleteDiscountDialog";

import { BasePage } from "@pages/basePage";
import { date } from "faker";

export class DiscountsPage extends BasePage {
deleteDialog: DeleteDiscountDialog;

export class DiscountsPage {
readonly page: Page;

constructor(
page: Page,
readonly createDiscountButton = page.getByTestId("create-sale"),
readonly discountForm = page.getByTestId("discount-form"),
readonly discountNameInput = page.getByTestId("discount-name-input"),
readonly discountTypeSelect = page.getByTestId("discount-type-select"),
readonly activeDatesSection = page.getByTestId("active-dates-section"),
readonly startDateInput = page.getByTestId("start-date-input"),
readonly startHourInput = page.getByTestId("start-hour-input"),
readonly endDateCheckbox = page.getByTestId("has-end-date"),
readonly endDateInput = page.getByTestId("end-date-input"),
readonly endHourInput = page.getByTestId("end-hour-input"),
readonly discountDescriptionInput = page.getByTestId("rich-text-editor-description"),
readonly addRuleButton = page.getByTestId("add-rule"),
readonly editRuleButton = page.getByTestId("rule-edit-button"),
readonly deleteRuleButton = page.getByTestId("rule-delete-button"),
readonly existingRule = page.getByTestId("added-rule"),
readonly addRuleDialog = page.getByTestId("add-rule-dialog"),
readonly ruleSection = page.getByTestId("rule-list"),
) {
this.page = page;
super(page)
this.deleteDialog = new DeleteDiscountDialog(page);
}
async clickCreateDiscountButton() {
await this.createDiscountButton.click();
}

async typeDiscountName(name: string) { await this.discountNameInput.fill(name) }

async selectDiscountType(type: string) {
await this.discountTypeSelect.click()
await this.page.getByRole("listbox").waitFor({
state: "visible",
timeout: 10000,
});
await this.page.getByTestId("select-option").filter({ hasText: type }).click();
}

async typePromotionDescription(description: string) {
await this.discountDescriptionInput.locator('[contenteditable="true"]').fill(description);
}

async typeStartDate() {
await this.startDateInput.fill(date.recent().toISOString().split("T")[0])
}

async typeStartHour() {
await this.startHourInput.fill("12:00");
}

async clickEndDateCheckbox() {
await this.endDateCheckbox.click();
}

async typeEndDate() {
await this.endDateInput.fill(date.future().toISOString().split("T")[0]);
}
async typeEndHour() {
await this.endHourInput.fill("12:00")
}
async gotoListView() {
await this.page.goto(URL_LIST.discounts);
await this.createDiscountButton.waitFor({
state: "visible",
timeout: 10000,
});
}
async gotoExistingDiscount(promotionId: string) {
const existingDiscountUrl = `${URL_LIST.discounts}${promotionId}`;
await console.log(
`Navigates to existing discount page: ${existingDiscountUrl}`,
);
await this.page.goto(existingDiscountUrl);

await this.discountForm.waitFor({
state: "visible",
timeout: 10000,
});
}

async clickEditRuleButton() {
await this.editRuleButton.click();
}
async clickDeleteRuleButton() {
await this.deleteRuleButton.click() }

async openExistingPromotionRuleModal(promotionId: string) {
await this.gotoExistingDiscount(promotionId);
await this.editRuleButton.click();
await this.addRuleDialog.waitFor({
state: "visible",
timeout: 10000,
});
}
}
70 changes: 70 additions & 0 deletions playwright/tests/discounts.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { DISCOUNTS } from "@data/e2eTestData";
import { DiscountsPage } from "@pages/discountsPage";
import { expect, test } from "@playwright/test";
import faker from "faker";

test.use({ storageState: "playwright/.auth/admin.json" });
let discounts: DiscountsPage;


test.beforeEach(({ page }) => {
discounts = new DiscountsPage(page);
});

const discountType = ['Order', 'Catalog'];
for (const type of discountType) {
test(`TC: SALEOR_97 Create promotion with ${type} predicate @discounts @e2e`, async () => {
const discountName = `${faker.lorem.word()}+${type}`;
await discounts.gotoListView();
await discounts.clickCreateDiscountButton();
await discounts.typeDiscountName(discountName);
await discounts.selectDiscountType(type);
await discounts.typePromotionDescription(faker.lorem.sentence());
await discounts.typeStartDate();
await discounts.typeStartHour();
await discounts.clickEndDateCheckbox();
await discounts.typeEndDate();
await discounts.typeEndHour();
await discounts.clickSaveButton();
await expect(discounts.successBanner).toBeVisible({ timeout: 10000 });
await expect(discounts.pageHeader).toHaveText(discountName);
await expect(discounts.discountTypeSelect).toHaveText(type);
await expect(discounts.ruleSection).toHaveText("Add your first rule to set up a promotion");
})};


test(`TC: SALEOR_98 Update existing promotion @discounts @e2e`, async () => {
const newDiscountName = `${faker.lorem.word()}`;
await discounts.gotoExistingDiscount(DISCOUNTS.promotionToBeEdited.id);
await discounts.ruleSection.waitFor({
state: "visible",
timeout: 10000,
});
await expect(discounts.discountNameInput).toHaveValue(DISCOUNTS.promotionToBeEdited.name, {timeout: 30000});
await discounts.discountNameInput.clear();
await discounts.typeDiscountName(newDiscountName);
await discounts.typePromotionDescription(faker.lorem.sentence());
await discounts.typeStartDate();
await discounts.typeStartHour();
await discounts.clickEndDateCheckbox();
await expect(discounts.endDateInput).not.toBeAttached();
await expect(discounts.endHourInput).not.toBeAttached();
await discounts.clickSaveButton();
await expect(discounts.successBanner).toBeVisible({ timeout: 10000 });
await expect(discounts.pageHeader).toHaveText(newDiscountName);
await expect(discounts.discountTypeSelect).toHaveText(DISCOUNTS.promotionToBeEdited.type);
})

const promotions = [DISCOUNTS.promotionWithoutRulesToBeDeleted, DISCOUNTS.promotionWithRulesToBeDeleted];
for (const promotion of promotions) {
test(`TC: SALEOR_99 Delete existing ${promotion.name} @discounts @e2e`, async () => {
await discounts.gotoExistingDiscount(promotion.id);
await discounts.ruleSection.waitFor({
state: "visible",
timeout: 10000,
});
await expect(discounts.discountNameInput).toHaveValue(promotion.name, {timeout: 30000});
await discounts.clickDeleteButton();
await discounts.deleteDialog.clickConfirmDeleteButton();
await expect(discounts.successBanner).toBeVisible({ timeout: 10000 });
})};
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { AVAILABILITY } from "@data/copy";
import { VOUCHERS_AND_DISCOUNTS } from "@data/e2eTestData";
import { VOUCHERS } from "@data/e2eTestData";
import { VouchersPage } from "@pages/vouchersPage";
import { expect, test } from "@playwright/test";

Expand Down Expand Up @@ -92,7 +92,7 @@ test("TC: SALEOR_85 Create voucher with manual code and percentage discount @vou

test("TC: SALEOR_86 Edit voucher to have free shipping discount @vouchers @e2e", async () => {
await vouchersPage.gotoExistingVoucherPage(
VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeEditedWithFreeShipping.id,
VOUCHERS.vouchers.voucherToBeEditedWithFreeShipping.id,
);
await vouchersPage.waitForGrid();
const codesRows = await vouchersPage.getNumberOfGridRows();
Expand All @@ -117,7 +117,7 @@ test("TC: SALEOR_86 Edit voucher to have free shipping discount @vouchers @e2e",
});
test("TC: SALEOR_87 Edit voucher Usage Limits: used in total, per customer, staff only, code used once @vouchers @e2e", async () => {
await vouchersPage.gotoExistingVoucherPage(
VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeEditedUsageLimits.id,
VOUCHERS.vouchers.voucherToBeEditedUsageLimits.id,
);
await vouchersPage.waitForGrid();

Expand Down Expand Up @@ -171,7 +171,7 @@ test("TC: SALEOR_89 Create voucher with minimum value of order @vouchers @e2e",
});
test("TC: SALEOR_90 Edit voucher minimum quantity of items @vouchers @e2e", async () => {
await vouchersPage.gotoExistingVoucherPage(
VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeEditedMinimumQuantity.id,
VOUCHERS.vouchers.voucherToBeEditedMinimumQuantity.id,
);
await vouchersPage.clickMinimumQuantityOfItemsButton();
await vouchersPage.typeMinimumQuantityOfItems("4");
Expand All @@ -182,7 +182,7 @@ test("TC: SALEOR_90 Edit voucher minimum quantity of items @vouchers @e2e", asyn

test("TC: SALEOR_92 Delete voucher @vouchers @e2e", async () => {
await vouchersPage.gotoExistingVoucherPage(
VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeDeleted.id,
VOUCHERS.vouchers.voucherToBeDeleted.id,
);

await vouchersPage.clickDeleteSingleVoucherButton();
Expand All @@ -192,15 +192,15 @@ test("TC: SALEOR_92 Delete voucher @vouchers @e2e", async () => {
await vouchersPage.waitForGrid();
await expect(
await vouchersPage.findRowIndexBasedOnText([
VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeDeleted.name,
VOUCHERS.vouchers.voucherToBeDeleted.name,
]),
`Given vouchers: ${VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeBulkDeleted.names} should be deleted from the list`,
`Given vouchers: ${VOUCHERS.vouchers.voucherToBeBulkDeleted.names} should be deleted from the list`,
).toEqual([]);
});
test("TC: SALEOR_93 Bulk delete voucher @vouchers @e2e", async () => {
await vouchersPage.gotoVouchersListPage();
await vouchersPage.checkListRowsBasedOnContainingText(
VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeBulkDeleted.names,
VOUCHERS.vouchers.voucherToBeBulkDeleted.names,
);

await vouchersPage.clickBulkDeleteButton();
Expand All @@ -209,9 +209,9 @@ test("TC: SALEOR_93 Bulk delete voucher @vouchers @e2e", async () => {
await vouchersPage.waitForGrid();
await expect(
await vouchersPage.findRowIndexBasedOnText(
VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeBulkDeleted.names,
VOUCHERS.vouchers.voucherToBeBulkDeleted.names,
),
`Given vouchers: ${VOUCHERS_AND_DISCOUNTS.vouchers.voucherToBeBulkDeleted.names} should be deleted from the list`,
`Given vouchers: ${VOUCHERS.vouchers.voucherToBeBulkDeleted.names} should be deleted from the list`,
).toEqual([]);
});

Expand All @@ -220,7 +220,7 @@ test.skip("TC: SALEOR_94 Edit voucher - assign voucher to specific category @vou
const categoryToBeAssigned = "Accessories";

await vouchersPage.gotoExistingVoucherPage(
VOUCHERS_AND_DISCOUNTS.vouchers
VOUCHERS.vouchers
.voucherToBeEditedAssignCategoryProductCollection.id,
);
await vouchersPage.clickSpecificProductsButton();
Expand All @@ -243,7 +243,7 @@ test("TC:SALEOR_95 Edit voucher - assign voucher to specific collection @vouche
const collectionToBeAssigned = "Featured Products";

await vouchersPage.gotoExistingVoucherPage(
VOUCHERS_AND_DISCOUNTS.vouchers
VOUCHERS.vouchers
.voucherToBeEditedAssignCategoryProductCollection.id,
);
await vouchersPage.clickSpecificProductsButton();
Expand All @@ -267,7 +267,7 @@ test("TC: SALEOR_96 Edit voucher - assign voucher to specific product @vouchers
const productToBeAssigned = "Bean Juice";

await vouchersPage.gotoExistingVoucherPage(
VOUCHERS_AND_DISCOUNTS.vouchers
VOUCHERS.vouchers
.voucherToBeEditedAssignCategoryProductCollection.id,
);
await vouchersPage.clickSpecificProductsButton();
Expand Down
Loading

0 comments on commit 1dcb956

Please sign in to comment.