From ec21ae3797686cc88a190bfbc394b57e05388667 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anna=20Szcz=C4=99ch?= <30683248+szczecha@users.noreply.github.com> Date: Wed, 3 Apr 2024 15:22:08 +0200 Subject: [PATCH] [E2E] Tests for page types (#4765) * add changeset * add test data * add tests and update data-test-id * code review fixes * spaces --- .changeset/twelve-kids-pretend.md | 5 + playwright/data/e2eTestData.ts | 143 +++++++++++------- .../pages/dialogs/assignAttributeDialog.ts | 37 +++++ playwright/pages/dialogs/deleteDialog.ts | 6 + playwright/pages/pageTypesPage.ts | 64 +++++++- playwright/tests/pageTypes.spec.ts | 75 +++++++++ .../AssignAttributeDialog.tsx | 4 +- .../PageTypeDetails/PageTypeDetails.tsx | 1 + .../components/PageTypeList/PageTypeList.tsx | 2 +- .../views/PageTypeList/PageTypeList.tsx | 1 + .../ProductExportDialogInfo.tsx | 1 + 11 files changed, 279 insertions(+), 60 deletions(-) create mode 100644 .changeset/twelve-kids-pretend.md create mode 100644 playwright/pages/dialogs/assignAttributeDialog.ts create mode 100644 playwright/tests/pageTypes.spec.ts diff --git a/.changeset/twelve-kids-pretend.md b/.changeset/twelve-kids-pretend.md new file mode 100644 index 00000000000..01d51af899e --- /dev/null +++ b/.changeset/twelve-kids-pretend.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": minor +--- + +Add playwright tests for page types diff --git a/playwright/data/e2eTestData.ts b/playwright/data/e2eTestData.ts index 7f253dbc895..b1c9e09164c 100644 --- a/playwright/data/e2eTestData.ts +++ b/playwright/data/e2eTestData.ts @@ -27,14 +27,16 @@ export const ATTRIBUTES = { ], }, attributesToBeUpdated: - [ {name: - "e2e product attribute to be updated 1", + [{ + name: + "e2e product attribute to be updated 1", id: "QXR0cmlidXRlOjc0MA==" - }, - { name: "e2e content attribute to be updated 2", id: "QXR0cmlidXRlOjczOQ==" } + }, + { name: "e2e content attribute to be updated 2", id: "QXR0cmlidXRlOjczOQ==" } ], - attributeTypesWithAbilityToAddValues:{names: - ["DROPDOWN","MULTISELECT","SWATCH",] + attributeTypesWithAbilityToAddValues: { + names: + ["DROPDOWN", "MULTISELECT", "SWATCH",] }, attributeTypesWithoutAbilityToAddValues: { names: @@ -46,8 +48,9 @@ export const ATTRIBUTES = { "DATE", "DATE_TIME",] }, - attributeReferencesEntities: {names: ["PAGE", "PRODUCT", "PRODUCT_VARIANT"]}, - } + attributeReferencesEntities: { names: ["PAGE", "PRODUCT", "PRODUCT_VARIANT"] }, + attributeToBeAssignedToPageType: { name: "Attribute to be assigned to page type" }, +} export const VOUCHERS = { vouchers: { voucherToBeEditedWithFreeShipping: { @@ -77,49 +80,55 @@ export const DISCOUNTS = { name: "e2e promotion to be edited", type: "Catalog", id: "UHJvbW90aW9uOjI0MGVkZGVkLWYzMTAtNGUzZi1iNTlmLTFlMGFkYWE2ZWFkYg==" -}, -promotionWithoutRulesToBeDeleted: { - id: "UHJvbW90aW9uOjRmNTQwMDc1LTZlZGMtNDI1NC1hY2U2LTQ2MzdlMGYxZWJhOA==", - name: "e2e Order predicate promotion without rules", - type: "Order", -}, -catalogPromotionWithRulesToBeDeleted: { - id: "UHJvbW90aW9uOmYyY2VjMDhkLTVkYmUtNGVjNC05NTNjLWMzMmQ5ZGQ2MTExYw==", - name: "e2e Catalog promo with rules to be deleted", - type: "Catalog", - rules: [ - { - id: "UHJvbW90aW9uUnVsZTo3NDk4MGVhNS0zNDA2LTQxZGYtOTc3Mi1jMzg3MjNhMWEwOWM=", - name: "rule 1" - }, + }, + promotionWithoutRulesToBeDeleted: { + id: "UHJvbW90aW9uOjRmNTQwMDc1LTZlZGMtNDI1NC1hY2U2LTQ2MzdlMGYxZWJhOA==", + name: "e2e Order predicate promotion without rules", + type: "Order", + }, + catalogPromotionWithRulesToBeDeleted: { + id: "UHJvbW90aW9uOmYyY2VjMDhkLTVkYmUtNGVjNC05NTNjLWMzMmQ5ZGQ2MTExYw==", + name: "e2e Catalog promo with rules to be deleted", + type: "Catalog", + rules: [ + { + id: "UHJvbW90aW9uUnVsZTo3NDk4MGVhNS0zNDA2LTQxZGYtOTc3Mi1jMzg3MjNhMWEwOWM=", + name: "rule 1" + }, - { - id: "UHJvbW90aW9uUnVsZTozMTEyMTE0Yy1hYjFkLTQ3OTktODY0My1jZDhlODMwYzllZmE=", - name: "rule 2" - }, + { + id: "UHJvbW90aW9uUnVsZTozMTEyMTE0Yy1hYjFkLTQ3OTktODY0My1jZDhlODMwYzllZmE=", + name: "rule 2" + }, - { - id: "UHJvbW90aW9uUnVsZTozOWE3Zjc1Zi1jYTdmLTQ4ODgtOGE4NC02NzdjMTVhOGQ4Yjc=", - name: "rule 3" - } + { + id: "UHJvbW90aW9uUnVsZTozOWE3Zjc1Zi1jYTdmLTQ4ODgtOGE4NC02NzdjMTVhOGQ4Yjc=", + name: "rule 3" + } - ], -}, -orderPromotionWithRulesToBeDeleted: { - id: "UHJvbW90aW9uOjA1MDllZjhjLTc0ZTEtNGMyMC1iZDk5LWRhYWU1YWJlZDM1Nw==", - name: "e2e Order promo with rules to be deleted", - type: "Order", - rules: [ - {id: "UHJvbW90aW9uUnVsZTo2ZTdlODNkOS1kNjJlLTQ2YmQtOGE2ZS03OTdlYTZiODk2NmQ=", -name: "rule #1"}, + ], + }, + orderPromotionWithRulesToBeDeleted: { + id: "UHJvbW90aW9uOjA1MDllZjhjLTc0ZTEtNGMyMC1iZDk5LWRhYWU1YWJlZDM1Nw==", + name: "e2e Order promo with rules to be deleted", + type: "Order", + rules: [ + { + id: "UHJvbW90aW9uUnVsZTo2ZTdlODNkOS1kNjJlLTQ2YmQtOGE2ZS03OTdlYTZiODk2NmQ=", + name: "rule #1" + }, -{id: "UHJvbW90aW9uUnVsZTo1MzQwNjEyYy0wOWJhLTQxYzUtYmY2Yy1lYmUzZTQ3MjY0MjY=", -name: "rule #2"}, + { + id: "UHJvbW90aW9uUnVsZTo1MzQwNjEyYy0wOWJhLTQxYzUtYmY2Yy1lYmUzZTQ3MjY0MjY=", + name: "rule #2" + }, -{id: "UHJvbW90aW9uUnVsZTpjMzk5ZTM1Ni04OWFhLTQ0MTUtYWE0Zi01NThlZDQ2M2IwNTM=", -name: "rule #3"} + { + id: "UHJvbW90aW9uUnVsZTpjMzk5ZTM1Ni04OWFhLTQ0MTUtYWE0Zi01NThlZDQ2M2IwNTM=", + name: "rule #3" + } - ], + ], }, orderPromotionWithRulesToBeUpdated: { id: "UHJvbW90aW9uOjI0Njg3NmM5LWM1ZWMtNDBiYi1iMzExLWE3YWQ2YzBiZDc4NQ==", @@ -138,7 +147,7 @@ name: "rule #3"} name: "rule 2", channel: "Channel-PLN", channelCurrency: "PLN", - giftRewardToBeDeleted:"UHJvZHVjdFZhcmlhbnQ6MjE0" + giftRewardToBeDeleted: "UHJvZHVjdFZhcmlhbnQ6MjE0" }, ], }, @@ -162,17 +171,17 @@ name: "rule #3"} }, ], }, -promotionWithRulesToBeDeleted: { - name: "e2e Catalog predicate promotion with rules", - id: "UHJvbW90aW9uOjY0N2M2MzdhLTZjNTEtNDYxZC05MjQ2LTc0YTY0OGM0ZjAxNA==", -}, -cataloguePromotion:{ - name: "e2e Catalog promotion for adding rules", - id: "UHJvbW90aW9uOjNmODZjZDAwLTUwNWEtNGVkNC04ZTliLTJmOGI4NGM3NGNlOQ==", -}, -orderPromotion: { - name: "e2e Order promotion for adding rules", - id: "UHJvbW90aW9uOjJlM2VhNDkyLTRhMTAtNDYzOS05MWVmLTc1YzQ1OTUxNGQyMQ==", + promotionWithRulesToBeDeleted: { + name: "e2e Catalog predicate promotion with rules", + id: "UHJvbW90aW9uOjY0N2M2MzdhLTZjNTEtNDYxZC05MjQ2LTc0YTY0OGM0ZjAxNA==", + }, + cataloguePromotion: { + name: "e2e Catalog promotion for adding rules", + id: "UHJvbW90aW9uOjNmODZjZDAwLTUwNWEtNGVkNC04ZTliLTJmOGI4NGM3NGNlOQ==", + }, + orderPromotion: { + name: "e2e Order promotion for adding rules", + id: "UHJvbW90aW9uOjJlM2VhNDkyLTRhMTAtNDYzOS05MWVmLTc1YzQ1OTUxNGQyMQ==", }, } @@ -526,3 +535,23 @@ export const TRANSLATIONS = { info: "Translation used in clear translation test", } } + +export const PAGE_TYPES = { + pageTypeToBeEdited: { + id: "UGFnZVR5cGU6MzQ=", + name: "A page type to be edited", + info: "Page type used in edit page type test", + }, + pageTypeToBeRemoved: { + id: "UGFnZVR5cGU6MzU=", + name: "A page type to be removed", + info: "Page type used in delete page type test", + }, + pageTypesToBeBulkDeleted: { + names: [ + "a page type to be bulk deleted 1/2", + "a page type to be bulk deleted 2/2", + ], + ids: ["UGFnZVR5cGU6MzY=", "UGFnZVR5cGU6Mzc="] + }, +} \ No newline at end of file diff --git a/playwright/pages/dialogs/assignAttributeDialog.ts b/playwright/pages/dialogs/assignAttributeDialog.ts new file mode 100644 index 00000000000..55ac9f81b7b --- /dev/null +++ b/playwright/pages/dialogs/assignAttributeDialog.ts @@ -0,0 +1,37 @@ +import { Page, expect } from "@playwright/test"; + +export class AssignAttributeDialog { + readonly page: Page; + + constructor( + page: Page, + readonly assignAttributesSearchInput = + page.getByTestId("attribute-search-input").locator("input"), + readonly attributesList = page.getByTestId("attributes-list"), + readonly assignAndSaveButton = page.getByTestId("assign-and-save-button"), + ) { + this.page = page; + } + + async searchAttribute(attributeName: string) { + await this.assignAttributesSearchInput.fill(attributeName); + await expect(this.attributesList).toContainText(attributeName); + } + + async clickAssignAndSaveButton() { + await this.assignAndSaveButton.click(); + await this.assignAndSaveButton.waitFor({ state: "hidden" }); + } + + async assignSpecificAttributeByNameAndSave(attributeName: string) { + const specificAttributeCheckbox = await this.page + .getByRole("row", { name: attributeName }) + .getByRole("checkbox"); + await this.attributesList.waitFor({ state: "visible" }); + await this.searchAttribute(attributeName); + await specificAttributeCheckbox.click(); + await this.clickAssignAndSaveButton(); + await this.assignAndSaveButton.waitFor({ state: "hidden" }); + } + +} diff --git a/playwright/pages/dialogs/deleteDialog.ts b/playwright/pages/dialogs/deleteDialog.ts index fb27bbe706b..c94305b8f1e 100644 --- a/playwright/pages/dialogs/deleteDialog.ts +++ b/playwright/pages/dialogs/deleteDialog.ts @@ -9,6 +9,7 @@ export class DeleteDialog { readonly confirmDeletionCheckbox = page.locator( "[name='delete-assigned-items-consent']", ), + readonly confirmDeleteButton = page.getByTestId("confirm-delete") ) { this.page = page; } @@ -20,4 +21,9 @@ export class DeleteDialog { async clickConfirmDeletionCheckbox() { await this.confirmDeletionCheckbox.click(); } + + async clickConfirmDeleteButton() { + await this.confirmDeleteButton.click(); + await this.confirmDeleteButton.waitFor({ state: "hidden" }); + } } diff --git a/playwright/pages/pageTypesPage.ts b/playwright/pages/pageTypesPage.ts index 7bb1dd69ed7..dea50605fae 100644 --- a/playwright/pages/pageTypesPage.ts +++ b/playwright/pages/pageTypesPage.ts @@ -1,12 +1,74 @@ import type { Page } from "@playwright/test"; +import { URL_LIST } from "@data/url"; +import { BasePage } from "@pages/basePage"; +import { DeleteDialog } from "@pages/dialogs/deleteDialog"; +import { AssignAttributeDialog } from "@pages/dialogs/assignAttributeDialog"; -export class PageTypesPage { +export class PageTypesPage extends BasePage { readonly page: Page; + readonly basePage: BasePage; + readonly deletePageTypeDialog: DeleteDialog; + readonly attributeDialog: AssignAttributeDialog; constructor( page: Page, readonly createPageTypeButton = page.getByTestId("create-page-type"), + readonly nameInput = page.getByTestId("page-type-name").locator("input"), + readonly saveButton = page.getByTestId("button-bar-confirm"), + readonly bulkDeleteButton = page.getByTestId("bulk-delete-page-types"), + readonly pageTypeList = page.getByTestId("page-types-list"), + readonly rowCheckbox = page.getByTestId("checkbox"), + readonly assignAttributesButton = page.getByTestId("assign-attributes"), + readonly pageAttributes = page.getByTestId("page-attributes"), ) { + super(page); this.page = page; + this.basePage = new BasePage(page); + this.deletePageTypeDialog = new DeleteDialog(page); + this.attributeDialog = new AssignAttributeDialog(page); + } + async assignAttributes(attributeName: string) { + await this.assignAttributesButton.click(); + await this.attributeDialog.assignSpecificAttributeByNameAndSave(attributeName) + } + + async gotoPageTypeListPage() { + await this.page.goto(URL_LIST.pageTypes); + } + + async clickCreatePageTypeButton() { + await this.createPageTypeButton.click(); + } + + async typePageTypeName(name: string) { + await this.nameInput.fill(name); + } + + async updatePageTypeName(name: string) { + await this.nameInput.clear(); + await this.nameInput.fill(name); + } + + async clickSaveButton() { + await this.saveButton.click(); + } + + async gotoExistingPageTypePage(pageTypeId: string) { + const existingPageTypeUrl = URL_LIST.pageTypes + pageTypeId; + await console.log( + "Navigating to page type details: " + existingPageTypeUrl, + ); + await this.page.goto(existingPageTypeUrl); + } + + async clickBulkDeleteButton() { + await this.bulkDeleteButton.click(); + } + + async checkPageTypesOnList(listRows: string[]) { + for (const row of listRows) { + const rowLocator = this.page.getByTestId(`id-${row}`); + await rowLocator.locator("input").click(); + } } } diff --git a/playwright/tests/pageTypes.spec.ts b/playwright/tests/pageTypes.spec.ts new file mode 100644 index 00000000000..2c565346a6b --- /dev/null +++ b/playwright/tests/pageTypes.spec.ts @@ -0,0 +1,75 @@ +import * as faker from "faker"; +import { PAGE_TYPES, ATTRIBUTES } from "@data/e2eTestData"; +import { PageTypesPage } from "@pages/pageTypesPage"; +import { test, expect } from "@playwright/test"; + +test.use({ storageState: "./playwright/.auth/admin.json" }); +const pageTypeName = `e2e-page-type-${faker.datatype.number()}`; + +test("TC: SALEOR_187 As an admin user I can create page type @e2e @page-type", async ({ + page, +}) => { + const pageTypePage = new PageTypesPage(page); + + await pageTypePage.gotoPageTypeListPage(); + await pageTypePage.clickCreatePageTypeButton(); + await pageTypePage.typePageTypeName(pageTypeName); + await pageTypePage.clickSaveButton(); + await pageTypePage.expectSuccessBanner(); + await expect(pageTypePage.nameInput).toHaveValue(pageTypeName); + await pageTypePage.gotoPageTypeListPage(); + await expect(pageTypePage.pageTypeList).toContainText(pageTypeName); +}); + + +test("TC: SALEOR_188 As an admin user I can update page type@e2e @page-type", async ({ + page, +}) => { + const pageTypePage = new PageTypesPage(page); + + const updatedPageTypeName = `updated-e2e-page-type-${faker.datatype.number()}`; + const attributeName = ATTRIBUTES.attributeToBeAssignedToPageType.name; + + await pageTypePage.gotoExistingPageTypePage(PAGE_TYPES.pageTypeToBeEdited.id); + await pageTypePage.updatePageTypeName(updatedPageTypeName); + await pageTypePage.clickSaveButton(); + await pageTypePage.expectSuccessBanner(); + await expect(pageTypePage.nameInput).toHaveValue(updatedPageTypeName); + await pageTypePage.assignAttributes(attributeName); + await pageTypePage.expectSuccessBanner(); + await expect(pageTypePage.pageAttributes).toContainText(attributeName); +}); + +test("TC: SALEOR_189 As an admin user I can delete page type with assigned content@e2e @page-type", async ({ + page, +}) => { + const pageTypePage = new PageTypesPage(page); + + const pageType = PAGE_TYPES.pageTypeToBeRemoved; + + await pageTypePage.gotoExistingPageTypePage(pageType.id); + await pageTypePage.clickDeleteButton(); + await pageTypePage.deletePageTypeDialog.clickConfirmDeletionCheckbox(); + await pageTypePage.deletePageTypeDialog.clickConfirmDeleteButton(); + await pageTypePage.expectSuccessBanner(); + await pageTypePage.gotoPageTypeListPage(); + await expect(pageTypePage.pageTypeList).not.toContainText(pageType.name); +}); + +test("TC: SALEOR_190 As an admin user I can delete several page types@e2e @page-type", async ({ + page, +}) => { + const pageTypePage = new PageTypesPage(page); + + const rowsToBeDeleted = PAGE_TYPES.pageTypesToBeBulkDeleted.ids; + const pageTypeNames = PAGE_TYPES.pageTypesToBeBulkDeleted.names; + + await pageTypePage.gotoPageTypeListPage(); + await expect(pageTypePage.pageTypeList).toBeVisible(); + await pageTypePage.checkPageTypesOnList(rowsToBeDeleted); + await pageTypePage.clickBulkDeleteButton(); + await pageTypePage.deletePageTypeDialog.clickConfirmDeleteButton(); + await pageTypePage.expectSuccessBanner(); + await expect(pageTypePage.pageTypeList).not.toContainText(pageTypeNames[0]); + await expect(pageTypePage.pageTypeList).not.toContainText(pageTypeNames[1]); +}); \ No newline at end of file diff --git a/src/components/AssignAttributeDialog/AssignAttributeDialog.tsx b/src/components/AssignAttributeDialog/AssignAttributeDialog.tsx index c4a1a77e88a..4e534407b3e 100644 --- a/src/components/AssignAttributeDialog/AssignAttributeDialog.tsx +++ b/src/components/AssignAttributeDialog/AssignAttributeDialog.tsx @@ -132,6 +132,7 @@ const AssignAttributeDialog: React.FC = ({ = ({ scrollableTarget={scrollableTargetId} > - + {renderCollection( attributes, attribute => { @@ -225,6 +226,7 @@ const AssignAttributeDialog: React.FC = ({ transitionState={confirmButtonState} type="submit" onClick={onSubmit} + data-test-id="assign-and-save-button" > diff --git a/src/pageTypes/components/PageTypeDetails/PageTypeDetails.tsx b/src/pageTypes/components/PageTypeDetails/PageTypeDetails.tsx index 02cb8740757..f7cd01e976e 100644 --- a/src/pageTypes/components/PageTypeDetails/PageTypeDetails.tsx +++ b/src/pageTypes/components/PageTypeDetails/PageTypeDetails.tsx @@ -39,6 +39,7 @@ const PageTypeDetails: React.FC = props => { defaultMessage: "Content Type Name", })} name="name" + data-test-id="page-type-name" onChange={onChange} value={data.name} /> diff --git a/src/pageTypes/components/PageTypeList/PageTypeList.tsx b/src/pageTypes/components/PageTypeList/PageTypeList.tsx index 92667ffb7fa..a4bdeb31f37 100644 --- a/src/pageTypes/components/PageTypeList/PageTypeList.tsx +++ b/src/pageTypes/components/PageTypeList/PageTypeList.tsx @@ -89,7 +89,7 @@ const PageTypeList: React.FC = props => { /> - + {renderCollection( pageTypes, pageType => { diff --git a/src/pageTypes/views/PageTypeList/PageTypeList.tsx b/src/pageTypes/views/PageTypeList/PageTypeList.tsx index 1de88b790f3..0d8222d9f49 100644 --- a/src/pageTypes/views/PageTypeList/PageTypeList.tsx +++ b/src/pageTypes/views/PageTypeList/PageTypeList.tsx @@ -186,6 +186,7 @@ export const PageTypeList: React.FC = ({ params }) => { openModal("remove", { ids: selectedPageTypes, diff --git a/src/products/components/ProductExportDialog/ProductExportDialogInfo.tsx b/src/products/components/ProductExportDialog/ProductExportDialogInfo.tsx index 1e292bc723c..f08ae35694d 100644 --- a/src/products/components/ProductExportDialog/ProductExportDialogInfo.tsx +++ b/src/products/components/ProductExportDialog/ProductExportDialogInfo.tsx @@ -423,6 +423,7 @@ const ProductExportDialogInfo: React.FC = ({ data-test-id="attributes" >