From e71633a5247687fb0c7ff71274526e07a1ad3c68 Mon Sep 17 00:00:00 2001 From: wojteknowacki <124166231+wojteknowacki@users.noreply.github.com> Date: Tue, 3 Oct 2023 12:08:13 +0200 Subject: [PATCH] migrated create products tests to Playwright (#4273) --- .changeset/tame-radios-beam.md | 5 +++ cypress/e2e/products/createProduct.js | 2 +- playwright/data/test-data.ts | 6 ++++ playwright/data/url.ts | 1 + playwright/pages/base-page.ts | 19 +++++++++++ .../pages/dialogs/channel-select-dialog.ts | 30 +++++++++++++++++ .../pages/dialogs/product-create-dialog.ts | 5 +-- playwright/pages/product-page.ts | 32 +++++++++++++++++-- .../pages/right-side-details-section.ts | 9 +++--- playwright/tests/product.spec.ts | 23 ++++++++++++- playwright/tsconfig.json | 3 +- .../ProductVariantPrice.tsx | 5 ++- 12 files changed, 126 insertions(+), 14 deletions(-) create mode 100644 .changeset/tame-radios-beam.md create mode 100644 playwright/data/test-data.ts create mode 100644 playwright/pages/base-page.ts create mode 100644 playwright/pages/dialogs/channel-select-dialog.ts diff --git a/.changeset/tame-radios-beam.md b/.changeset/tame-radios-beam.md new file mode 100644 index 00000000000..0f604022a98 --- /dev/null +++ b/.changeset/tame-radios-beam.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": minor +--- + +migrated create products tests to Playwright diff --git a/cypress/e2e/products/createProduct.js b/cypress/e2e/products/createProduct.js index eba1d37c033..50b16ff2f35 100644 --- a/cypress/e2e/products/createProduct.js +++ b/cypress/e2e/products/createProduct.js @@ -101,7 +101,7 @@ describe("As an admin I should be able to create product", () => { ); it( - "should be able to create product without variants as an admin. SALEOR_2702", + "should be able to create product without variants as an admin. SALEOR_2702 - migration in progress - to delete when done", { tags: ["@products", "@allEnv", "@critical", "@stable", "@oldRelease"] }, () => { const prices = { sellingPrice: 6, costPrice: 3 }; diff --git a/playwright/data/test-data.ts b/playwright/data/test-data.ts new file mode 100644 index 00000000000..ec729c4100e --- /dev/null +++ b/playwright/data/test-data.ts @@ -0,0 +1,6 @@ +export const PRODUCTS = { + singleProductType: { + id: "UHJvZHVjdFR5cGU6Njcy", + name: "Single product type", + }, +}; diff --git a/playwright/data/url.ts b/playwright/data/url.ts index 39ae9c30672..485623bafd7 100644 --- a/playwright/data/url.ts +++ b/playwright/data/url.ts @@ -20,6 +20,7 @@ export const URL_LIST = { permissionsGroups: "permission-groups/", plugins: "plugins/", products: "products/", + productsAdd: "add?product-type-id=", productTypes: "product-types/", productTypesAdd: "product-types/add", sales: "discounts/sales/", diff --git a/playwright/pages/base-page.ts b/playwright/pages/base-page.ts new file mode 100644 index 00000000000..e87b9dc922c --- /dev/null +++ b/playwright/pages/base-page.ts @@ -0,0 +1,19 @@ +import { URL_LIST } from "@data/url"; +import type { Locator, Page } from "@playwright/test"; +import { expect } from "@playwright/test"; + +export class BasePage { + public page: Page; + public pageHeader: Locator; + + constructor(page: Page) { + this.page = page; + this.pageHeader = page.getByTestId("page-header"); + } + async gotoCreateProductPage(productTypeId: string) { + await this.page.goto( + `${URL_LIST.products}${URL_LIST.productsAdd}${productTypeId}`, + ); + await expect(this.pageHeader).toBeVisible({ timeout: 10000 }); + } +} diff --git a/playwright/pages/dialogs/channel-select-dialog.ts b/playwright/pages/dialogs/channel-select-dialog.ts new file mode 100644 index 00000000000..13999dfe750 --- /dev/null +++ b/playwright/pages/dialogs/channel-select-dialog.ts @@ -0,0 +1,30 @@ +import type { Locator, Page } from "@playwright/test"; + +export class ChannelSelectDialog { + readonly page: Page; + readonly allChannelsCheckbox: Locator; + readonly displayedChannels: Locator; + readonly confirmButton: Locator; + readonly displayedChannelsCheckboxes: Locator; + + constructor(page: Page) { + this.page = page; + this.allChannelsCheckbox = page.locator("[name='allChannels']"); + this.displayedChannels = page.getByTestId("channel-row"); + this.displayedChannelsCheckboxes = page.locator("[type=checkbox]"); + this.confirmButton = page.getByTestId("submit"); + } + + async clickAllChannelsCheckbox() { + await this.allChannelsCheckbox.click(); + } + async selectFirstChannel() { + await this.displayedChannels + .first() + .locator(this.displayedChannelsCheckboxes) + .click(); + } + async clickConfirmButton() { + await this.confirmButton.first().click(); + } +} diff --git a/playwright/pages/dialogs/product-create-dialog.ts b/playwright/pages/dialogs/product-create-dialog.ts index 1cb56857692..5b8fb491605 100644 --- a/playwright/pages/dialogs/product-create-dialog.ts +++ b/playwright/pages/dialogs/product-create-dialog.ts @@ -1,7 +1,4 @@ -import type { - Locator, - Page, -} from "@playwright/test"; +import type { Locator, Page } from "@playwright/test"; export class ProductCreateDialog { readonly page: Page; diff --git a/playwright/pages/product-page.ts b/playwright/pages/product-page.ts index b80c2e4073f..817c4cdadfe 100644 --- a/playwright/pages/product-page.ts +++ b/playwright/pages/product-page.ts @@ -1,6 +1,7 @@ import * as faker from "faker"; import { LOCATORS } from "@data/common-locators"; +import { ChannelSelectDialog } from "@dialogs/channel-select-dialog"; import { MetadataSeoPage } from "@pages/metadata-seo-page"; import { RightSideDetailsPage } from "@pages/right-side-details-section"; import type { Locator, Page } from "@playwright/test"; @@ -8,7 +9,6 @@ import { expect } from "@playwright/test"; const productName = `e2e-productName-${faker.datatype.number()}`; const productDescription = `e2e-productDescription-${faker.datatype.number()}`; -const productRating = `9`; export class ProductPage { readonly page: Page; @@ -42,11 +42,14 @@ export class ProductPage { readonly saveButton: Locator; readonly firstRowDataGrid: Locator; readonly productUpdateFormSection: Locator; + readonly manageChannelsButton: Locator; metadataSeoPage: MetadataSeoPage; rightSideDetailsPage: RightSideDetailsPage; + channelSelectDialog: ChannelSelectDialog; constructor(page: Page) { this.page = page; + this.channelSelectDialog = new ChannelSelectDialog(page); this.metadataSeoPage = new MetadataSeoPage(page); this.rightSideDetailsPage = new RightSideDetailsPage(page); this.productNameInput = page.locator("[name='name']"); @@ -76,6 +79,9 @@ export class ProductPage { 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']", ); @@ -111,9 +117,25 @@ export class ProductPage { async typeProductDescription(description = productDescription) { await this.descriptionInput.type(description); } - async typeProductRating(rating = productRating) { + async typeProductRating(rating = "9") { await this.ratingInput.fill(rating); } + async typeSellingPriceForChannel( + channelName: string, + sellingPriceValue = "50", + ) { + const channel = this.page.locator( + `[data-test-id="Channel-${channelName}"]`, + ); + await channel.locator(this.sellingPriceInput).fill(sellingPriceValue); + } + + async typeCostPrice(channelName: string, costPriceValue = "40") { + const channel = this.page.locator( + `[data-test-id="Channel-${channelName}"]`, + ); + await channel.locator(this.costPriceInput).fill(costPriceValue); + } async clickSaveButton() { await this.saveButton.click(); @@ -121,4 +143,10 @@ export class ProductPage { async expectSuccessBanner() { await expect(this.page.locator(LOCATORS.successBanner)).toBeVisible(); } + async selectOneChannelAsAvailable() { + await this.manageChannelsButton.click(); + await this.channelSelectDialog.clickAllChannelsCheckbox(); + await this.channelSelectDialog.selectFirstChannel(); + await this.channelSelectDialog.clickConfirmButton(); + } } diff --git a/playwright/pages/right-side-details-section.ts b/playwright/pages/right-side-details-section.ts index 4b2468fa4d8..e122d3d681c 100644 --- a/playwright/pages/right-side-details-section.ts +++ b/playwright/pages/right-side-details-section.ts @@ -1,7 +1,4 @@ -import type { - Locator, - Page, -} from "@playwright/test"; +import type { Locator, Page } from "@playwright/test"; export class RightSideDetailsPage { readonly page: Page; @@ -51,6 +48,10 @@ export class RightSideDetailsPage { ); } + async openChannelsDialog() { + await this.manageChannelsButton.click(); + } + async selectFirstCategory() { await this.categoryInput.click(); await this.categorySelectOption.first().click(); diff --git a/playwright/tests/product.spec.ts b/playwright/tests/product.spec.ts index 6e0847ce2d6..38cb7faa8fc 100644 --- a/playwright/tests/product.spec.ts +++ b/playwright/tests/product.spec.ts @@ -1,3 +1,5 @@ +import { PRODUCTS } from "@data/test-data"; +import { BasePage } from "@pages/base-page"; import { ProductCreateDialog } from "@pages/dialogs/product-create-dialog"; import { ProductListPage } from "@pages/product-list-page"; import { ProductPage } from "@pages/product-page"; @@ -5,7 +7,7 @@ import { test } from "@playwright/test"; test.use({ storageState: "playwright/.auth/admin.json" }); -test("TC: SALEOR_3 Create basic product with variants @basic-regression @product-type", async ({ +test("TC: SALEOR_3 Create basic product with variants @basic-regression @product", async ({ page, }) => { const productListPage = new ProductListPage(page); @@ -24,3 +26,22 @@ test("TC: SALEOR_3 Create basic product with variants @basic-regression @product await productPage.clickSaveButton(); await productPage.expectSuccessBanner(); }); +test("TC: SALEOR_5 Create basic product without variants @basic-regression @product", async ({ + page, +}) => { + const basePage = new BasePage(page); + const productCreateDialog = new ProductCreateDialog(page); + const productPage = new ProductPage(page); + + await basePage.gotoCreateProductPage(PRODUCTS.singleProductType.id); + await productPage.selectOneChannelAsAvailable(); + await productPage.typeNameDescAndRating(); + await productPage.addSeo(); + await productPage.addAllMetaData(); + await productPage.selectFirstCategory(); + await productPage.selectFirstTaxOption(); + await productPage.typeSellingPriceForChannel("PLN"); + await productPage.typeCostPrice("PLN"); + await productPage.clickSaveButton(); + await productPage.expectSuccessBanner(); +}); diff --git a/playwright/tsconfig.json b/playwright/tsconfig.json index 18239bb62e7..8ea631e961c 100644 --- a/playwright/tsconfig.json +++ b/playwright/tsconfig.json @@ -12,7 +12,8 @@ "paths": { "@pages/*": ["./pages/*"], "@api/*": ["./api/*"], - "@data/*": ["./data/*"] + "@data/*": ["./data/*"], + "@dialogs/*": ["./pages/dialogs/*"] } } } diff --git a/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx b/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx index c68eb112024..13555ef149d 100644 --- a/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx +++ b/src/products/components/ProductVariantPrice/ProductVariantPrice.tsx @@ -140,7 +140,10 @@ export const ProductVariantPrice: React.FC< ); return ( - + {listing?.name || }