Skip to content

Commit

Permalink
Delete single product test (#4506)
Browse files Browse the repository at this point in the history
* delete single product from details test

* fix tag for test

* Create real-olives-change.md
  • Loading branch information
wojteknowacki authored Dec 1, 2023
1 parent 8f1a90b commit 07d5f35
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 163 deletions.
6 changes: 6 additions & 0 deletions .changeset/real-olives-change.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"saleor-dashboard": minor
---

Delete single product test
Refactor page class files to eliminate duplication of variables
5 changes: 5 additions & 0 deletions playwright/data/e2eTestData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export const PRODUCTS = {
id: "UHJvZHVjdDo3MzM%3D",
info: "Product that contains single variant",
},
productWithOneVariantToBeDeletedFromDetails: {
name: "beer to be deleted",
id: "UHJvZHVjdDo3NTc%3D",
info: "Product that contains single variant - to be deleted from details view",
},
};

export const SHIPPING_METHODS = {
Expand Down
79 changes: 42 additions & 37 deletions playwright/pages/basePage.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
import { LOCATORS } from "@data/commonLocators";
import { URL_LIST } from "@data/url";
import type { Locator, Page } from "@playwright/test";
import type { Page } from "@playwright/test";
import { expect } from "@playwright/test";

export class BasePage {
readonly page: Page;
readonly pageHeader: Locator;
readonly gridCanvas: Locator;
readonly successBanner: Locator;
readonly errorBanner: Locator;
readonly gridInput: Locator;

constructor(page: Page) {
constructor(
page: Page,
readonly pageHeader = page.getByTestId("page-header"),
readonly gridCanvas = page.locator('[data-testid="data-grid-canvas"]'),
readonly gridInput = page
.locator('[class="clip-region"]')
.locator("textarea"),
readonly successBanner = page.locator(LOCATORS.successBanner),
readonly errorBanner = page.locator(LOCATORS.errorBanner),
) {
this.page = page;
this.pageHeader = page.getByTestId("page-header");
this.gridCanvas = page.locator('[data-testid="data-grid-canvas"]');
this.gridInput = this.page.locator('[class="clip-region"]').locator("textarea")
this.successBanner = page.locator(LOCATORS.successBanner);
this.errorBanner = page.locator(LOCATORS.errorBanner);
}
async gotoCreateProductPage(productTypeId: string) {
await this.page.goto(
Expand Down Expand Up @@ -50,44 +49,49 @@ export class BasePage {
async getRandomInt(max: number) {
return Math.floor(Math.random() * (max + 1));
}

async waitForGrid() {
await this.gridCanvas.locator("table")
.waitFor({ state: "attached", timeout: 10000 })
await this.gridCanvas
.locator("table")
.waitFor({ state: "attached", timeout: 10000 });
}

async findGridCellBounds(col: number, row: number) {
return this.gridCanvas.evaluate((node, { col, row }) => {
const fiberKey = Object.keys(node).find(x => x && x.includes("__reactFiber"));

if (!fiberKey || !node.parentNode) return null
return this.gridCanvas.evaluate(
(node, { col, row }) => {
const fiberKey = Object.keys(node).find(
x => x && x.includes("__reactFiber"),
);

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

/*
/*
We seek over the fiber node (hack), ignore typings for it.
*/
const fiberParent = node.parentNode[fiberKey as keyof typeof node.parentNode] as any
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)
const bounds: { x: number; y: number; width: number; height: number } =
fiberParent.pendingProps.children.props.gridRef.current.getBounds(
col,
row,
);

if (!bounds) return null
if (!bounds) return null;

return {
return {
...bounds,
center: {
x: bounds.x + bounds.width / 2,
y: bounds.y + bounds.height / 2,
}
}
}, { col, row })
},
};
},
{ col, row },
);
}


/*
Example:
Expand All @@ -101,11 +105,12 @@ export class BasePage {
*/

async fillGridCell(col: number, row: number, content: string) {
const bounds = await this.findGridCellBounds(col, row)
const bounds = await this.findGridCellBounds(col, row);

if (!bounds) throw new Error(`Unable to find cell, col: ${col}, row: ${row}`)
if (!bounds)
throw new Error(`Unable to find cell, col: ${col}, row: ${row}`);

await this.page.mouse.dblclick(bounds.center.x, bounds.center.y)
await this.page.mouse.dblclick(bounds.center.x, bounds.center.y);
await this.gridInput.waitFor({ state: "attached" });
await this.gridInput.fill(content);
}
Expand Down
17 changes: 17 additions & 0 deletions playwright/pages/dialogs/deleteProductDialog.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import type { Locator, Page } from "@playwright/test";

export class DeleteProductDialog {
readonly page: Page;

readonly deleteButton: Locator;

constructor(page: Page) {
this.page = page;

this.deleteButton = page.getByTestId("submit");
}

async clickDeleteButton() {
await this.deleteButton.first().click();
}
}
144 changes: 62 additions & 82 deletions playwright/pages/productPage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,103 +4,83 @@ import { URL_LIST } from "@data/url";
import { ChannelSelectDialog } from "@pages/dialogs/channelSelectDialog";
import { MetadataSeoPage } from "@pages/pageElements/metadataSeoPage";
import { RightSideDetailsPage } from "@pages/pageElements/rightSideDetailsSection";
import type { Locator, Page } from "@playwright/test";
import type { Page } from "@playwright/test";

import { BasePage } from "./basePage";
import { DeleteProductDialog } from "./dialogs/deleteProductDialog";

const productName = `e2e-productName-${faker.datatype.number()}`;
const productDescription = `e2e-productDescription-${faker.datatype.number()}`;

export class ProductPage {
readonly page: Page;

readonly productNameInput: Locator;
readonly productTypeInput: Locator;
readonly categoryInput: Locator;
readonly productsNames: Locator;
readonly createProductButton: Locator;
readonly searchProducts: Locator;
readonly categoryItem: Locator;
readonly collectionInput: Locator;
readonly autocompleteDropdown: Locator;
readonly firstCategoryItem: Locator;
readonly visibleRadioBtn: Locator;
readonly channelAvailabilityItem: Locator;
readonly addVariantButton: Locator;
readonly descriptionInput: Locator;
readonly ratingInput: Locator;
readonly variantRow: Locator;
readonly variantPrice: Locator;
readonly collectionRemoveButtons: Locator;
readonly addWarehouseButton: Locator;
readonly warehouseOption: Locator;
readonly stockInput: Locator;
readonly costPriceInput: Locator;
readonly sellingPriceInput: Locator;
readonly productImage: Locator;
readonly uploadImageButton: Locator;
readonly uploadSavedImagesButton: Locator;
readonly uploadMediaUrlButton: Locator;
readonly saveUploadUrlButton: Locator;
readonly editVariantButton: Locator;
readonly saveButton: Locator;
readonly firstRowDataGrid: Locator;
readonly addProductButton: Locator;
readonly productUpdateFormSection: Locator;
readonly manageChannelsButton: Locator;
metadataSeoPage: MetadataSeoPage;
rightSideDetailsPage: RightSideDetailsPage;
basePage: BasePage;
channelSelectDialog: ChannelSelectDialog;
readonly metadataSeoPage: MetadataSeoPage;
readonly rightSideDetailsPage: RightSideDetailsPage;
readonly basePage: BasePage;
readonly channelSelectDialog: ChannelSelectDialog;
readonly deleteProductDialog: DeleteProductDialog;

constructor(page: Page) {
constructor(
page: Page,
readonly productsNames = page.getByTestId("name"),
readonly createProductButton = page.getByTestId("add-product"),
readonly deleteProductButton = page.getByTestId("button-bar-delete"),
readonly searchProducts = page.locator(
"[placeholder='Search Products...']",
),
readonly productNameInput = page.locator("[name='name']"),
readonly addProductButton = page.getByTestId("add-product"),
readonly productTypeInput = page.getByTestId("product-type"),
readonly saveButton = page.getByTestId("button-bar-confirm"),
readonly categoryInput = page.getByTestId("category"),
readonly categoryItem = page.getByTestId(
"single-autocomplete-select-option",
),
readonly collectionInput = page.getByTestId("collections"),
readonly autocompleteDropdown = page.getByTestId("autocomplete-dropdown"),
readonly descriptionInput = page
.getByTestId("rich-text-editor-description")
.locator("[contenteditable]"),
readonly variantRow = page.getByTestId("product-variant-row"),
readonly variantPrice = page.getByTestId("price"),
readonly collectionRemoveButtons = page.getByTestId("collection-remove"),
readonly addWarehouseButton = page.getByTestId("add-warehouse"),
readonly stockInput = page.getByTestId("stock-input"),
readonly productImage = page.getByTestId("product-image"),
readonly uploadImageButton = page.getByTestId("button-upload-image"),
readonly uploadSavedImagesButton = page.getByTestId("upload-images"),
readonly uploadMediaUrlButton = page.getByTestId("upload-media-url"),
readonly saveUploadUrlButton = page.getByTestId("upload-url-button"),
readonly editVariantButton = page.getByTestId("row-action-button"),
readonly productUpdateFormSection = page.getByTestId("product-update-form"),
readonly firstCategoryItem = page.locator("#downshift-0-item-0"),
readonly visibleRadioBtn = page.locator("[name='isPublished']"),
readonly channelAvailabilityItem = page.locator(
"[data-test-id*='channel-availability-item']",
),
readonly manageChannelsButton = page.getByTestId(
"channels-availability-manage-button",
),
readonly addVariantButton = page.locator(
"[data-test-id*='button-add-variant']",
),
readonly ratingInput = page.locator("[name='rating']"),
readonly warehouseOption = page.locator("[role='menuitem']"),
readonly costPriceInput = page.locator("[name*='costPrice']"),
readonly sellingPriceInput = page.locator("[name*='channel-price']"),
readonly firstRowDataGrid = page.locator("[data-testid='glide-cell-1-0']"),
) {
this.page = page;
this.basePage = new BasePage(page);
this.deleteProductDialog = new DeleteProductDialog(page);
this.channelSelectDialog = new ChannelSelectDialog(page);
this.metadataSeoPage = new MetadataSeoPage(page);
this.rightSideDetailsPage = new RightSideDetailsPage(page);
this.productsNames = page.getByTestId("name");
this.createProductButton = page.getByTestId("add-product");
this.searchProducts = page.locator("[placeholder='Search Products...']");
this.productNameInput = page.locator("[name='name']");
this.addProductButton = page.getByTestId("add-product");
this.productTypeInput = page.getByTestId("product-type");
this.saveButton = page.getByTestId("button-bar-confirm");
this.categoryInput = page.getByTestId("category");
this.categoryItem = page.getByTestId("single-autocomplete-select-option");
this.collectionInput = page.getByTestId("collections");
this.autocompleteDropdown = page.getByTestId("autocomplete-dropdown");
this.descriptionInput = page
.getByTestId("rich-text-editor-description")
.locator("[contenteditable]");
this.variantRow = page.getByTestId("product-variant-row");
this.variantPrice = page.getByTestId("price");
this.collectionRemoveButtons = page.getByTestId("collection-remove");
this.addWarehouseButton = page.getByTestId("add-warehouse");
this.stockInput = page.getByTestId("stock-input");
this.productImage = page.getByTestId("product-image");
this.uploadImageButton = page.getByTestId("button-upload-image");
this.uploadSavedImagesButton = page.getByTestId("upload-images");
this.uploadMediaUrlButton = page.getByTestId("upload-media-url");
this.saveUploadUrlButton = page.getByTestId("upload-url-button");
this.editVariantButton = page.getByTestId("row-action-button");
this.productUpdateFormSection = page.getByTestId("product-update-form");
this.firstCategoryItem = page.locator("#downshift-0-item-0");
this.visibleRadioBtn = page.locator("[name='isPublished']");
this.channelAvailabilityItem = page.locator(
"[data-test-id*='channel-availability-item']",
);
this.manageChannelsButton = page.getByTestId(
"channels-availability-manage-button",
);
this.addVariantButton = page.locator(
"[data-test-id*='button-add-variant']",
);
this.ratingInput = page.locator("[name='rating']");
this.warehouseOption = page.locator("[role='menuitem']");
this.costPriceInput = page.locator("[name*='costPrice']");
this.sellingPriceInput = page.locator("[name*='channel-price']");
this.firstRowDataGrid = page.locator("[data-testid='glide-cell-1-0']");
}

async clickDeleteProductButton() {
await this.deleteProductButton.click();
}

async addSeo() {
Expand Down
Loading

0 comments on commit 07d5f35

Please sign in to comment.