From b7f240f5292e6e934fe73a1342815b485b3ac1c2 Mon Sep 17 00:00:00 2001 From: wojteknowacki <124166231+wojteknowacki@users.noreply.github.com> Date: Tue, 19 Dec 2023 16:10:44 +0100 Subject: [PATCH] Create order with activated transaction flow in channel test (#4558) * Create order with activated transaction flow in channel test * new assertions --- .changeset/famous-otters-rest.md | 5 ++ playwright.config.ts | 2 +- playwright/data/e2eTestData.ts | 6 ++ playwright/pages/dialogs/addProductsDialog.ts | 4 +- playwright/pages/dialogs/orderCreateDialog.ts | 7 ++ playwright/pages/ordersPage.ts | 59 +++++++------ playwright/pages/productPage.ts | 6 +- playwright/tests/orders.spec.ts | 43 ++++++++-- playwright/tests/product.spec.ts | 83 +++++++++---------- .../OrderPaymentSummaryCard.tsx | 5 +- .../OrderUnfulfilledProductsCard.tsx | 1 + 11 files changed, 130 insertions(+), 91 deletions(-) create mode 100644 .changeset/famous-otters-rest.md diff --git a/.changeset/famous-otters-rest.md b/.changeset/famous-otters-rest.md new file mode 100644 index 00000000000..d13cfcf35d9 --- /dev/null +++ b/.changeset/famous-otters-rest.md @@ -0,0 +1,5 @@ +--- +"saleor-dashboard": minor +--- + +Create order with activated transaction flow in channel test diff --git a/playwright.config.ts b/playwright.config.ts index 37c2e22d0c9..44e834b8009 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -12,7 +12,7 @@ export default defineConfig({ retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 2 : undefined, reporter: process.env.CI ? "blob" : "html", - timeout: process.env.CI ? 60000 : 20000, + timeout: process.env.CI ? 60000 : 30000, // webServer: { // command: "npm run dev", // url: "http://localhost:9000/", diff --git a/playwright/data/e2eTestData.ts b/playwright/data/e2eTestData.ts index edbc18e6e97..2a261c4aa2d 100644 --- a/playwright/data/e2eTestData.ts +++ b/playwright/data/e2eTestData.ts @@ -49,6 +49,12 @@ export const PRODUCTS = { id: "UHJvZHVjdDo3NTc%3D", info: "Product that contains single variant - to be deleted from details view", }, + productAvailableWithTransactionFlow: { + name: "Coconut Juice transaction flow", + id: "UHJvZHVjdDo3Ng%3D%3D", + variant1sku: "84725784", + info: "Product which is available within channel with activated transaction flow", + }, productsToBeBulkDeleted: { names: [ "a product to be deleted via bulk 1/3", diff --git a/playwright/pages/dialogs/addProductsDialog.ts b/playwright/pages/dialogs/addProductsDialog.ts index c073a76ef53..95a598f93b2 100644 --- a/playwright/pages/dialogs/addProductsDialog.ts +++ b/playwright/pages/dialogs/addProductsDialog.ts @@ -26,9 +26,9 @@ export class AddProductsDialog { await this.confirmButton.click(); } - async selectVariantOnListAndConfirm(variantSku = "SKU 61630747") { + async selectVariantWithSkuOnListAndConfirm(variantSku = "61630747") { await this.variantRow - .filter({ has: this.page.locator(`text=${variantSku}`) }) + .filter({ has: this.page.locator(`text=SKU ${variantSku}`) }) .locator(this.productRowCheckbox) .click(); await this.clickConfirmButton(); diff --git a/playwright/pages/dialogs/orderCreateDialog.ts b/playwright/pages/dialogs/orderCreateDialog.ts index 9db65225624..987f120282a 100644 --- a/playwright/pages/dialogs/orderCreateDialog.ts +++ b/playwright/pages/dialogs/orderCreateDialog.ts @@ -25,4 +25,11 @@ export class OrderCreateDialog { await this.channelOption.first().click(); await this.clickConfirmButton(); } + async completeOrderCreateDialogWithTransactionChannel() { + await this.expandChannelsSearchList(); + await this.channelOption + .filter({ hasText: "transaction flow channel" }) + .click(); + await this.clickConfirmButton(); + } } diff --git a/playwright/pages/ordersPage.ts b/playwright/pages/ordersPage.ts index 756800c758f..1de3a6a6e7b 100644 --- a/playwright/pages/ordersPage.ts +++ b/playwright/pages/ordersPage.ts @@ -1,52 +1,45 @@ +import { URL_LIST } from "@data/url"; import { AddProductsDialog } from "@pages/dialogs/addProductsDialog"; import { AddressDialog } from "@pages/dialogs/addressDialog"; import { OrderCreateDialog } from "@pages/dialogs/orderCreateDialog"; import { ShippingAddressDialog } from "@pages/dialogs/shippingMethodDialog"; -import { Locator, Page } from "@playwright/test"; +import { Page } from "@playwright/test"; import { BasePage } from "./basePage"; -export class OrdersPage { - readonly page: Page; - readonly createOrderButton: Locator; - - readonly addProducts: Locator; - readonly salesChannel: Locator; - readonly editCustomerButton: Locator; - readonly searchCustomerInput: Locator; - readonly addShippingCarrierLink: Locator; - readonly finalizeButton: Locator; - readonly selectCustomerOption: Locator; - - readonly editShippingAddress: Locator; - readonly editBillingAddress: Locator; - readonly customerEmail: Locator; +export class OrdersPage extends BasePage { orderCreateDialog: OrderCreateDialog; addProductsDialog: AddProductsDialog; addressDialog: AddressDialog; shippingAddressDialog: ShippingAddressDialog; basePage: BasePage; - constructor(page: Page) { - this.page = page; + constructor( + page: Page, + readonly createOrderButton = page.getByTestId("create-order-button"), + readonly markAsPaidButton = page.getByTestId("markAsPaidButton"), + readonly orderSummarySection = page.getByTestId("OrderSummaryCard"), + readonly paymentSummarySection = page.getByTestId("payment-section"), + readonly fulfillButton = page.getByTestId("fulfill-button"), + readonly addProducts = page.getByTestId("add-products-button"), + readonly salesChannel = page.getByTestId("salesChannel"), + readonly editCustomerButton = page.getByTestId("edit-customer"), + readonly searchCustomerInput = page.getByTestId("select-customer"), + readonly addShippingCarrierLink = page.getByTestId("add-shipping-carrier"), + readonly finalizeButton = page.getByTestId("button-bar-confirm"), + readonly editShippingAddress = page.getByTestId("edit-shipping-address"), + readonly editBillingAddress = page.getByTestId("edit-billing-address"), + readonly customerEmail = page.getByTestId("customer-email"), + readonly selectCustomerOption = page.getByTestId( + "single-autocomplete-select-option", + ), + ) { + super(page); this.orderCreateDialog = new OrderCreateDialog(page); this.basePage = new BasePage(page); this.addProductsDialog = new AddProductsDialog(page); this.addressDialog = new AddressDialog(page); this.shippingAddressDialog = new ShippingAddressDialog(page); - this.createOrderButton = page.getByTestId("create-order-button"); - this.addProducts = page.getByTestId("add-products-button"); - this.salesChannel = page.getByTestId("salesChannel"); - this.editCustomerButton = page.getByTestId("edit-customer"); - this.searchCustomerInput = page.getByTestId("select-customer"); - this.addShippingCarrierLink = page.getByTestId("add-shipping-carrier"); - this.finalizeButton = page.getByTestId("button-bar-confirm"); - this.editShippingAddress = page.getByTestId("edit-shipping-address"); - this.editBillingAddress = page.getByTestId("edit-billing-address"); - this.customerEmail = page.getByTestId("customer-email"); - this.selectCustomerOption = page.getByTestId( - "single-autocomplete-select-option", - ); } async selectCustomer(customer = "allison.freeman@example.com") { @@ -73,4 +66,8 @@ export class OrdersPage { async expectSuccessBanner() { await this.basePage.expectSuccessBanner(); } + + async goToOrdersListView() { + await this.page.goto(URL_LIST.orders); + } } diff --git a/playwright/pages/productPage.ts b/playwright/pages/productPage.ts index 8cb489f5104..1f9fa37fd87 100644 --- a/playwright/pages/productPage.ts +++ b/playwright/pages/productPage.ts @@ -15,9 +15,7 @@ import { FiltersPage } from "./pageElements/filtersPage"; const productName = `e2e-productName-${faker.datatype.number()}`; const productDescription = `e2e-productDescription-${faker.datatype.number()}`; -export class ProductPage { - readonly page: Page; - +export class ProductPage extends BasePage { readonly metadataSeoPage: MetadataSeoPage; readonly exportProductsDialog: ExportProductsDialog; readonly rightSideDetailsPage: RightSideDetailsPage; @@ -81,7 +79,7 @@ export class ProductPage { readonly sellingPriceInput = page.locator("[name*='channel-price']"), readonly firstRowDataGrid = page.locator("[data-testid='glide-cell-1-0']"), ) { - this.page = page; + super(page); this.basePage = new BasePage(page); this.exportProductsDialog = new ExportProductsDialog(page); this.deleteProductDialog = new DeleteProductDialog(page); diff --git a/playwright/tests/orders.spec.ts b/playwright/tests/orders.spec.ts index 7027c5860df..058aaefd83f 100644 --- a/playwright/tests/orders.spec.ts +++ b/playwright/tests/orders.spec.ts @@ -1,17 +1,42 @@ -import { URL_LIST } from "@data/url"; +import { PRODUCTS } from "@data/e2eTestData"; import { OrdersPage } from "@pages/ordersPage"; import { expect, test } from "@playwright/test"; test.use({ storageState: "playwright/.auth/admin.json" }); +let ordersPage: OrdersPage; -test("TC: SALEOR_28 Create basic order @e2e @order", async ({ page }) => { - const ordersPage = new OrdersPage(page); +test.beforeEach(({ page }) => { + ordersPage = new OrdersPage(page); +}); - await page.goto(URL_LIST.orders); +test("TC: SALEOR_28 Create basic order @e2e @order", async () => { + await ordersPage.goToOrdersListView(); await ordersPage.clickCreateOrderButton(); await ordersPage.orderCreateDialog.completeOrderCreateDialogWithFirstChannel(); await ordersPage.clickAddProductsButton(); - await ordersPage.addProductsDialog.selectVariantOnListAndConfirm(); + await ordersPage.addProductsDialog.selectVariantWithSkuOnListAndConfirm(); + await ordersPage.clickEditCustomerButton(); + await ordersPage.clickSearchCustomerInput(); + await ordersPage.selectCustomer(); + await expect( + ordersPage.addressDialog.existingAddressRadioButton, + ).toBeVisible(); + await ordersPage.addressDialog.clickConfirmButton(); + await ordersPage.clickAddShippingCarrierButton(); + await ordersPage.shippingAddressDialog.pickAndConfirmFirstShippingMethod(); + await ordersPage.clickFinalizeButton(); + await ordersPage.successBanner + .filter({ hasText: "finalized" }) + .waitFor({ state: "visible" }); +}); +test("TC: SALEOR_76 Create order with transaction flow activated @e2e @order", async () => { + await ordersPage.goToOrdersListView(); + await ordersPage.clickCreateOrderButton(); + await ordersPage.orderCreateDialog.completeOrderCreateDialogWithTransactionChannel(); + await ordersPage.clickAddProductsButton(); + await ordersPage.addProductsDialog.selectVariantWithSkuOnListAndConfirm( + PRODUCTS.productAvailableWithTransactionFlow.variant1sku, + ); await ordersPage.clickEditCustomerButton(); await ordersPage.clickSearchCustomerInput(); await ordersPage.selectCustomer(); @@ -22,5 +47,11 @@ test("TC: SALEOR_28 Create basic order @e2e @order", async ({ page }) => { await ordersPage.clickAddShippingCarrierButton(); await ordersPage.shippingAddressDialog.pickAndConfirmFirstShippingMethod(); await ordersPage.clickFinalizeButton(); - await ordersPage.basePage.expectSuccessBannerMessage("finalize"); + await ordersPage.successBanner + .filter({ hasText: "finalized" }) + .waitFor({ state: "visible" }); + await expect(ordersPage.markAsPaidButton).toBeVisible(); + await expect(ordersPage.paymentSummarySection).toBeVisible(); + await expect(ordersPage.orderSummarySection).toBeVisible(); + await expect(ordersPage.fulfillButton).toBeDisabled(); }); diff --git a/playwright/tests/product.spec.ts b/playwright/tests/product.spec.ts index 2fda3e7ece3..6072577304e 100644 --- a/playwright/tests/product.spec.ts +++ b/playwright/tests/product.spec.ts @@ -1,6 +1,5 @@ import { MailpitService } from "@api/mailpit"; import { PRODUCTS } from "@data/e2eTestData"; -import { BasePage } from "@pages/basePage"; import { ProductCreateDialog } from "@pages/dialogs/productCreateDialog"; import { ProductPage } from "@pages/productPage"; import { VariantsPage } from "@pages/variantsPage"; @@ -11,14 +10,12 @@ test.use({ storageState: "playwright/.auth/admin.json" }); let productPage: ProductPage; let productCreateDialog: ProductCreateDialog; let variantsPage: VariantsPage; -let basePage: BasePage; let mailpitService: MailpitService; test.beforeEach(({ page, request }) => { productPage = new ProductPage(page); productCreateDialog = new ProductCreateDialog(page); variantsPage = new VariantsPage(page); - basePage = new BasePage(page); mailpitService = new MailpitService(request); }); @@ -107,15 +104,15 @@ test("TC: SALEOR_27 Create full info variant - via edit variant page @e2e @produ test("TC: SALEOR_44 As an admin I should be able to delete a several products @basic-regression @product @e2e", async () => { await productPage.gotoProductListPage(); - await basePage.checkListRowsBasedOnContainingText( + await productPage.checkListRowsBasedOnContainingText( PRODUCTS.productsToBeBulkDeleted.names, ); await productPage.clickBulkDeleteButton(); await productPage.deleteProductDialog.clickDeleteButton(); - await basePage.expectSuccessBanner(); - await basePage.waitForGrid(); + await productPage.expectSuccessBanner(); + await productPage.waitForGrid(); await expect( - await basePage.findRowIndexBasedOnText( + await productPage.findRowIndexBasedOnText( PRODUCTS.productsToBeBulkDeleted.names, ), `Given products: ${PRODUCTS.productsToBeBulkDeleted.names} should be deleted from the list`, @@ -128,9 +125,9 @@ test("TC: SALEOR_45 As an admin I should be able to delete a single products @ba ); await productPage.clickDeleteProductButton(); await productPage.deleteProductDialog.clickDeleteButton(); - await await basePage.expectSuccessBannerMessage("Product Removed"); + await await productPage.expectSuccessBannerMessage("Product Removed"); await expect( - basePage.gridCanvas.locator("table"), + productPage.gridCanvas.locator("table"), `Given product: ${PRODUCTS.productWithOneVariantToBeDeletedFromDetails.name} should be deleted from the list`, ).not.toContainText( PRODUCTS.productWithOneVariantToBeDeletedFromDetails.name, @@ -150,14 +147,14 @@ test("TC: SALEOR_46 As an admin, I should be able to update a product by uploadi const preSaveTax = await productPage.rightSideDetailsPage.taxInput .locator("input") .inputValue(); - await productPage.basePage.waitForGrid(); + await productPage.waitForGrid(); await productPage.clickAddVariantButton(); await productPage.editVariantButton.nth(1).scrollIntoViewIfNeeded(); // click and fill variant name cell - await productPage.basePage.clickGridCell(1, 1); - await productPage.basePage.fillGridCell(1, 1, newVariantName); + await productPage.clickGridCell(1, 1); + await productPage.fillGridCell(1, 1, newVariantName); await productPage.clickSaveButton(); - await productPage.basePage.expectSuccessBanner(); + await productPage.expectSuccessBanner(); const postSaveTax = await productPage.rightSideDetailsPage.taxInput .locator("input") .inputValue(); @@ -165,7 +162,7 @@ test("TC: SALEOR_46 As an admin, I should be able to update a product by uploadi preSaveTax, "Pre save tax name should be equal as the one after save", ).toEqual(postSaveTax); - await productPage.basePage.gridCanvas + await productPage.gridCanvas .getByText(newVariantName) .waitFor({ state: "attached" }); await expect( @@ -188,7 +185,7 @@ test.skip("TC: SALEOR_56 As an admin, I should be able to export products from s await productPage.exportProductsDialog.clickNextButton(); await productPage.exportProductsDialog.clickExportSearchedProductsRadioButton(); await productPage.exportProductsDialog.clickSubmitButton(); - await productPage.basePage.expectInfoBanner(); + await productPage.expectInfoBanner(); await mailpitService.checkDoesUserReceivedExportedData( process.env.E2E_USER_NAME!, "Your exported products data is ready", @@ -197,68 +194,63 @@ test.skip("TC: SALEOR_56 As an admin, I should be able to export products from s test("TC: SALEOR_57 As an admin, I should be able to search products on list view @basic-regression @product @e2e", async () => { await productPage.gotoProductListPage(); - await productPage.basePage.typeInSearchOnListView( - PRODUCTS.productToAddVariants.name, - ); - await productPage.basePage.waitForGrid(); - await productPage.basePage.checkListRowsBasedOnContainingText([ + await productPage.typeInSearchOnListView(PRODUCTS.productToAddVariants.name); + await productPage.waitForGrid(); + await productPage.checkListRowsBasedOnContainingText([ PRODUCTS.productToAddVariants.name, ]); expect( - await productPage.basePage.gridCanvas.locator("table tbody tr").count(), + await productPage.gridCanvas.locator("table tbody tr").count(), "There should be only one product visible on list", ).toEqual(1); }); test("TC: SALEOR_58 As an admin I should be able use pagination on product list view @basic-regression @product @e2e", async () => { await productPage.gotoProductListPage(); - await productPage.basePage.waitForGrid(); - const firstPageProductName = await productPage.basePage.getGridCellText(0, 0); - await productPage.basePage.clickNextPageButton(); - await productPage.basePage.waitForGrid(); - const secondPageProductName = await productPage.basePage.getGridCellText( - 1, - 1, - ); + await productPage.waitForGrid(); + const firstPageProductName = await productPage.getGridCellText(0, 0); + await productPage.clickNextPageButton(); + await productPage.waitForGrid(); + const secondPageProductName = await productPage.getGridCellText(1, 1); await expect( firstPageProductName, `Second side first product name: ${secondPageProductName} should be visible and be different than: ${firstPageProductName}`, ).not.toEqual(secondPageProductName); await expect( - productPage.basePage.gridCanvas, + productPage.gridCanvas, `Product from first page: ${firstPageProductName} should not be visible`, ).not.toContainText(firstPageProductName); - await productPage.basePage.clickPreviousPageButton(); - await productPage.basePage.waitForGrid(); + await productPage.clickPreviousPageButton(); + await productPage.waitForGrid(); await expect( - productPage.basePage.gridCanvas, + productPage.gridCanvas, `Product from first page: ${firstPageProductName} should be visible again`, ).toContainText(firstPageProductName); }); test("TC: SALEOR_59 As an admin I should be able to filter products by channel on product list view @basic-regression @product @e2e", async () => { await productPage.gotoProductListPage(); - await productPage.basePage.waitForGrid(); + await productPage.waitForGrid(); await expect( - productPage.basePage.gridCanvas, + productPage.gridCanvas, `Product: ${PRODUCTS.productAvailableOnlyInUsdChannel.name} should be visible on grid table`, ).toContainText(PRODUCTS.productAvailableOnlyInUsdChannel.name); - await productPage.basePage.clickFilterButton(); + await productPage.clickFilterButton(); await productPage.filtersPage.pickFilter("Channel", "Channel-PLN"); await productPage.filtersPage.clickSaveFiltersButton(); - await productPage.basePage.waitForGrid(); + await productPage.waitForGrid(); await expect( - productPage.basePage.gridCanvas, + productPage.gridCanvas, `Product: ${PRODUCTS.productAvailableOnlyInUsdChannel.name} should not be visible on grid table`, ).not.toContainText(PRODUCTS.productAvailableOnlyInUsdChannel.name); await expect( - productPage.basePage.gridCanvas, + productPage.gridCanvas, `Product: ${PRODUCTS.productAvailableOnlyInPlnChannel.name} should be visible on grid table`, ).toContainText(PRODUCTS.productAvailableOnlyInPlnChannel.name); }); @@ -318,14 +310,13 @@ test("TC: SALEOR_62 As an admin I should be able to bulk delete existing variant await productPage.gotoExistingProductPage( PRODUCTS.multipleVariantsBulkDeleteProduct.productId, ); - - await productPage.basePage.waitForGrid(); - await productPage.basePage.gridCanvas.scrollIntoViewIfNeeded(); + await productPage.waitForGrid(); + await productPage.gridCanvas.scrollIntoViewIfNeeded(); // there should be 3 variants present and checked in next steps - await productPage.basePage.clickGridCell(0, 0); - await productPage.basePage.clickGridCell(0, 1); - await productPage.basePage.clickGridCell(0, 2); - await productPage.basePage.clickBulkDeleteGridRowsButton(); + await productPage.clickGridCell(0, 0); + await productPage.clickGridCell(0, 1); + await productPage.clickGridCell(0, 2); + await productPage.clickBulkDeleteGridRowsButton(); await expect( productPage.noVariantsText, "Message about how to add new variant should be visible in place of list of variants", diff --git a/src/orders/components/OrderPaymentSummaryCard/OrderPaymentSummaryCard.tsx b/src/orders/components/OrderPaymentSummaryCard/OrderPaymentSummaryCard.tsx index 24dd8994130..34e6c5ea925 100644 --- a/src/orders/components/OrderPaymentSummaryCard/OrderPaymentSummaryCard.tsx +++ b/src/orders/components/OrderPaymentSummaryCard/OrderPaymentSummaryCard.tsx @@ -79,7 +79,10 @@ const OrderPaymentSummaryCard: React.FC = ({ !shouldDisplay.charged && !shouldDisplay.authorized && !hasGiftCards && ( - + diff --git a/src/orders/components/OrderUnfulfilledProductsCard/OrderUnfulfilledProductsCard.tsx b/src/orders/components/OrderUnfulfilledProductsCard/OrderUnfulfilledProductsCard.tsx index e1a812e1fcf..dea61da1fb8 100644 --- a/src/orders/components/OrderUnfulfilledProductsCard/OrderUnfulfilledProductsCard.tsx +++ b/src/orders/components/OrderUnfulfilledProductsCard/OrderUnfulfilledProductsCard.tsx @@ -53,6 +53,7 @@ const OrderUnfulfilledProductsCard: React.FC< {showFulfillmentAction && (