diff --git a/tests/pw/package-lock.json b/tests/pw/package-lock.json index 1a4d6ed0eb..b763cd344e 100644 --- a/tests/pw/package-lock.json +++ b/tests/pw/package-lock.json @@ -499,6 +499,12 @@ "undici-types": "~6.20.0" } }, + "node_modules/@types/randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-kCP61wludjY7oNUeFiMxfswHB3Wn/aC03Cu82oQsNTO6OCuhVN/rCbBs68Cq6Nkgjmp2Sh3Js6HearJPkk7KQA==", + "dev": true + }, "node_modules/@types/responselike": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", @@ -2644,6 +2650,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/randombytes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==" + }, + "node_modules/randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-gY7aQ4i1BgwZ8I1Op4YseITAyiDiajeZOPQUbIq9TPGPhUm5FX59izIaOpmKbME1nmnEiABf28d9K2VSii6BBg==", + "dependencies": { + "randombytes": "2.0.3" + }, + "bin": { + "randomstring": "bin/randomstring" + }, + "engines": { + "node": "*" + } + }, "node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -3659,6 +3684,12 @@ "undici-types": "~6.20.0" } }, + "@types/randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@types/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-kCP61wludjY7oNUeFiMxfswHB3Wn/aC03Cu82oQsNTO6OCuhVN/rCbBs68Cq6Nkgjmp2Sh3Js6HearJPkk7KQA==", + "dev": true + }, "@types/responselike": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", @@ -5179,6 +5210,19 @@ "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" }, + "randombytes": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz", + "integrity": "sha512-lDVjxQQFoCG1jcrP06LNo2lbWp4QTShEXnhActFBwYuHprllQV6VUpwreApsYqCgD+N1mHoqJ/BI/4eV4R2GYg==" + }, + "randomstring": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/randomstring/-/randomstring-1.3.0.tgz", + "integrity": "sha512-gY7aQ4i1BgwZ8I1Op4YseITAyiDiajeZOPQUbIq9TPGPhUm5FX59izIaOpmKbME1nmnEiABf28d9K2VSii6BBg==", + "requires": { + "randombytes": "2.0.3" + } + }, "readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", diff --git a/tests/pw/pages/frontend/cart.page.ts b/tests/pw/pages/frontend/cart.page.ts new file mode 100644 index 0000000000..6ffb84491d --- /dev/null +++ b/tests/pw/pages/frontend/cart.page.ts @@ -0,0 +1,23 @@ +import { BasePage } from '@pages/basePage'; + +export default class CartPage extends BasePage { + quantityErrorElement() { + return this.page.locator('//td[@class="product-quantity"]/div[@class="required"]'); + } + + woocommerceErrorMessage() { + return this.page.locator('//div[@class="woocommerce-notices-wrapper"]/ul[@class="woocommerce-error"]/li'); + } + + async enterQuantityValue(productTitle: string, quantityValue: string) { + await this.page.locator(`//div[@class="quantity"]/label[contains(text(), "${productTitle}")]/following-sibling::input`).fill(quantityValue); + } + + async clickOnUpdateCartButton() { + await this.page.locator('//button[@name="update_cart"]').click(); + } + + async removeProductByName(productName: string) { + await this.page.locator(`//div[@class="quantity"]/label[contains(text(), "${productName}")]/../../../td[1]/a`).click(); + } +} diff --git a/tests/pw/pages/frontend/my-account/auth/my-account-auth.page.ts b/tests/pw/pages/frontend/my-account/auth/my-account-auth.page.ts new file mode 100644 index 0000000000..071cf1f1b7 --- /dev/null +++ b/tests/pw/pages/frontend/my-account/auth/my-account-auth.page.ts @@ -0,0 +1,15 @@ +import { BasePage } from '@pages/basePage'; + +export default class MyAccountAuthPage extends BasePage { + async enterUsername(username: string) { + await this.page.locator('#username').fill(username); + } + + async enterPassword(password: string) { + await this.page.locator('#password').fill(password); + } + + async clickOnLoginButton() { + await this.page.locator('//button[@name="login"]').click(); + } +} diff --git a/tests/pw/pages/frontend/my-orders/all-my-orders.page.ts b/tests/pw/pages/frontend/my-orders/all-my-orders.page.ts new file mode 100644 index 0000000000..981026719f --- /dev/null +++ b/tests/pw/pages/frontend/my-orders/all-my-orders.page.ts @@ -0,0 +1,7 @@ +import { BasePage } from '@pages/basePage'; + +export default class AllMyOrdersPage extends BasePage { + async clickOnViewButtonByOrderId(orderId: string) { + await this.page.locator(`//td[@class="order-number"]/a[contains(text(), "${orderId}")]/../following-sibling::td[5]/a`).click(); + } +} diff --git a/tests/pw/pages/frontend/my-orders/customer-order-details.page.ts b/tests/pw/pages/frontend/my-orders/customer-order-details.page.ts new file mode 100644 index 0000000000..5a03fc5ac7 --- /dev/null +++ b/tests/pw/pages/frontend/my-orders/customer-order-details.page.ts @@ -0,0 +1,15 @@ +import { BasePage } from '@pages/basePage'; + +export default class CustomerOrderDetailsPage extends BasePage { + trackingStatusByShipmentNumber(shipmentNumber: string) { + return this.page.locator(`//h4[@class="shippments-tracking-title"]/strong[text()="Shipment ${shipmentNumber} "]/../../div[1]/p/strong`); + } + + async markOrderAsReceived(shipmentNumber: string) { + await this.page.locator(`//h4[@class="shippments-tracking-title"]/strong[text()="Shipment ${shipmentNumber} "]/../../div[1]/strong[@class="customer-status"]`).click(); + } + + async clickOnDialogBoxOkButton() { + await this.page.locator('//div[@role="dialog"]/div[6]/button[text()="OK"]').click(); + } +} diff --git a/tests/pw/pages/frontend/navigation/main-menu.page.ts b/tests/pw/pages/frontend/navigation/main-menu.page.ts new file mode 100644 index 0000000000..ef9c2f5bb4 --- /dev/null +++ b/tests/pw/pages/frontend/navigation/main-menu.page.ts @@ -0,0 +1,7 @@ +import { BasePage } from '@pages/basePage'; + +export default class StorefrontMainMenu extends BasePage { + async clickOnCartContentLink() { + await this.page.locator('.cart-contents').click(); + } +} diff --git a/tests/pw/pages/frontend/shop/shop.page.ts b/tests/pw/pages/frontend/shop/shop.page.ts new file mode 100644 index 0000000000..a76fb4fa90 --- /dev/null +++ b/tests/pw/pages/frontend/shop/shop.page.ts @@ -0,0 +1,7 @@ +import { BasePage } from '@pages/basePage'; + +export default class ShopPage extends BasePage { + async clickOnProductWithTitle(productTitle: string) { + await this.page.locator('.woocommerce-loop-product__title').getByText(productTitle).click(); + } +} diff --git a/tests/pw/pages/frontend/shop/single-product.page.ts b/tests/pw/pages/frontend/shop/single-product.page.ts new file mode 100644 index 0000000000..de688d2ba3 --- /dev/null +++ b/tests/pw/pages/frontend/shop/single-product.page.ts @@ -0,0 +1,15 @@ +import { BasePage } from '@pages/basePage'; + +export default class SingleProductPage extends BasePage { + errorMessageElement() { + return this.page.locator('//ul[@class="woocommerce-error"]/li'); + } + + async enterQuantityValue(productTitle: string, quantityValue: string) { + await this.page.locator(`//div[@class="quantity"]/label[contains(text(), "${productTitle}")]/following-sibling::input`).fill(quantityValue); + } + + async clickOnAddToCartButton() { + await this.page.locator('.single_add_to_cart_button').click(); + } +} diff --git a/tests/pw/pages/frontend/vendor-dashboard/common/vendor-sidebar.page.ts b/tests/pw/pages/frontend/vendor-dashboard/common/vendor-sidebar.page.ts new file mode 100644 index 0000000000..ab286a5bcd --- /dev/null +++ b/tests/pw/pages/frontend/vendor-dashboard/common/vendor-sidebar.page.ts @@ -0,0 +1,19 @@ +import { BasePage } from '@pages/basePage'; + +export default class VendorDashboardSidebarPage extends BasePage { + sidebarMenu(title: string) { + return this.page.locator(`//li[contains(@class, "${title}")]/a`); + } + + async clickOnOrdersTab() { + await this.sidebarMenu('orders').click(); + } + + async clickOnProductsTab() { + await this.sidebarMenu('products').click(); + } + + async clickOnSettingsTab() { + await this.sidebarMenu('settings').click(); + } +} diff --git a/tests/pw/pages/frontend/vendor-dashboard/orders/vendor-all-orders.page.ts b/tests/pw/pages/frontend/vendor-dashboard/orders/vendor-all-orders.page.ts new file mode 100644 index 0000000000..4c06566545 --- /dev/null +++ b/tests/pw/pages/frontend/vendor-dashboard/orders/vendor-all-orders.page.ts @@ -0,0 +1,11 @@ +import { BasePage } from '@pages/basePage'; + +export default class VendorAllOrdersPage extends BasePage { + orderTitleById(orderId: string) { + return this.page.locator(`//td[@data-title="Order"]/a/strong[text()="Order ${orderId}"]`); + } + + async clickOnOrderById(orderId: string) { + await this.orderTitleById(orderId).click(); + } +} diff --git a/tests/pw/pages/frontend/vendor-dashboard/orders/vendor-edit-order.page.ts b/tests/pw/pages/frontend/vendor-dashboard/orders/vendor-edit-order.page.ts new file mode 100644 index 0000000000..c45fb59b73 --- /dev/null +++ b/tests/pw/pages/frontend/vendor-dashboard/orders/vendor-edit-order.page.ts @@ -0,0 +1,31 @@ +import { BasePage } from '@pages/basePage'; + +export default class VendorEditOrderPage extends BasePage { + async clickOnCreateNewShipmentButton() { + await this.page.locator('#create-tracking-status-action').click(); + } + + async clickOnShipmentItemCheckboxByIndex(itemNumber: string) { + await this.page.locator(`//form[@id="add-shipping-tracking-status-form"]/div/table/tbody[@id="order_line_items"]/tr[${itemNumber}]/td[1]/label/input`).click(); + } + + async selectShippingStatus(status: string) { + await this.page.locator('#shipment-status').selectOption(status); + } + + async selectShippingProvider(providerName: string) { + await this.page.locator('#shipping_status_provider').selectOption(providerName); + } + + async enterShippingDate(date: string) { + await this.page.locator('#shipped_status_date').fill(date); + } + + async enterShippingTrackingNumber(trackingNumber: string) { + await this.page.locator('#tracking_status_number').fill(trackingNumber); + } + + async clickOnCreateShipmentButton() { + await this.page.locator('#add-tracking-status-details').click(); + } +} diff --git a/tests/pw/pages/frontend/vendor-dashboard/products/product-add-edit.page.ts b/tests/pw/pages/frontend/vendor-dashboard/products/product-add-edit.page.ts new file mode 100644 index 0000000000..52c0913dc8 --- /dev/null +++ b/tests/pw/pages/frontend/vendor-dashboard/products/product-add-edit.page.ts @@ -0,0 +1,19 @@ +import { BasePage } from '@pages/basePage'; + +export default class VendorProductAddEditPage extends BasePage { + async enterSimpleProductMinQty(quantity: string) { + await this.page.locator('#min_quantity').fill(quantity); + } + + async enterSimpleProductMaxQty(quantity: string) { + await this.page.locator('#max_quantity').fill(quantity); + } + + async selectProductStatus(status: 'publish' | 'draft' | 'pending') { + await this.page.locator('#post_status').selectOption(status); + } + + async clickOnSaveProduct() { + await this.page.locator('#publish').click(); + } +} diff --git a/tests/pw/pages/frontend/vendor-dashboard/products/products-list.page.ts b/tests/pw/pages/frontend/vendor-dashboard/products/products-list.page.ts new file mode 100644 index 0000000000..254b935ad5 --- /dev/null +++ b/tests/pw/pages/frontend/vendor-dashboard/products/products-list.page.ts @@ -0,0 +1,11 @@ +import { BasePage } from '@pages/basePage'; + +export default class VendorProductListPage extends BasePage { + productTitle() { + return this.page.locator(`//td[@data-title="Name"]/strong/a`); + } + + async clickOnProductWithTitle(productTitle: string) { + await this.productTitle().getByText(productTitle).click(); + } +} diff --git a/tests/pw/pages/frontend/vendor-dashboard/settings/store/vendor-store.page.ts b/tests/pw/pages/frontend/vendor-dashboard/settings/store/vendor-store.page.ts new file mode 100644 index 0000000000..f66c269864 --- /dev/null +++ b/tests/pw/pages/frontend/vendor-dashboard/settings/store/vendor-store.page.ts @@ -0,0 +1,15 @@ +import { BasePage } from '@pages/basePage'; + +export default class VendorStoreSettingsPage extends BasePage { + async enterMinimumOrderAmount(amount: string) { + await this.page.locator('#min_amount_to_order').fill(amount); + } + + async enterMaximumOrderAmount(amount: string) { + await this.page.locator('#max_amount_to_order').fill(amount); + } + + async clickOnUpdateSettingsButton() { + await this.page.locator(`//input[@name="dokan_update_store_settings"]`).click(); + } +} diff --git a/tests/pw/pages/wp-admin/common/sidebar.page.ts b/tests/pw/pages/wp-admin/common/sidebar.page.ts new file mode 100644 index 0000000000..60e60f490e --- /dev/null +++ b/tests/pw/pages/wp-admin/common/sidebar.page.ts @@ -0,0 +1,15 @@ +import { BasePage } from '@pages/basePage'; + +export default class WpAdminSidebar extends BasePage { + sideMenu(title: string) { + return this.page.locator('.wp-menu-name').getByText(title); + } + + async clickOnProductsLink() { + await this.sideMenu('Products').click(); + } + + async clickOnDokanLink() { + await this.sideMenu('Dokan').click(); + } +} diff --git a/tests/pw/pages/wp-admin/dokan/settings/modules.page.ts b/tests/pw/pages/wp-admin/dokan/settings/modules.page.ts new file mode 100644 index 0000000000..ae8acf1915 --- /dev/null +++ b/tests/pw/pages/wp-admin/dokan/settings/modules.page.ts @@ -0,0 +1,19 @@ +import { BasePage } from '@pages/basePage'; + +export default class DokanModulesPage extends BasePage { + moduleTitle() { + return this.page.locator(`//div[@class="module-details"]/h3/a`); + } + + async searchFor(searchTerm: string) { + await this.page.locator('//div[@class="search-box"]/input').fill(searchTerm); + } + + async clickOnModuleToggleButton(moduleName: string) { + await this.page.locator(`//div[@class="module-details"]/h3/a[contains(text(), "${moduleName}")]/../../following-sibling::div/div[2]/label`).click(); + } + + async clickOnActiveModulesTab() { + await this.page.locator(`//div[@class="module-filter-left"]/ul/li[2]/a`).click(); + } +} diff --git a/tests/pw/pages/wp-admin/dokan/settings/shipping-status.page.ts b/tests/pw/pages/wp-admin/dokan/settings/shipping-status.page.ts new file mode 100644 index 0000000000..7c778d46f0 --- /dev/null +++ b/tests/pw/pages/wp-admin/dokan/settings/shipping-status.page.ts @@ -0,0 +1,33 @@ +import { BasePage } from '@pages/basePage'; + +export default class DokanShippingStatusPage extends BasePage { + async shippingStatusItem(status: string) { + const list = this.page.locator('//ul[@class="dokan-settings-repeatable-list"]/li').all(); + + let locator; + for (const item of await list) { + const text = await item.textContent(); + if (text?.includes(status)) { + locator = item; + } + } + + return locator; + } + + async clickOnShippingStatusTab() { + await this.page.locator('//div[@class="nav-title"][text()="Shipping Status"]').click(); + } + + async clickOnAllowShipmentTrackingCheckbox() { + await this.page.locator('(//p/../following-sibling::div/label/label)[1]').click(); + } + + async clickOnAllowMarkAsReceivedCheckbox() { + await this.page.locator('(//p/../following-sibling::div/label/label)[2]').click(); + } + + async clickOnSaveChangesButton() { + await this.page.locator('#submit').click(); + } +} diff --git a/tests/pw/pages/wp-admin/products/all-products.page.ts b/tests/pw/pages/wp-admin/products/all-products.page.ts new file mode 100644 index 0000000000..444882dea4 --- /dev/null +++ b/tests/pw/pages/wp-admin/products/all-products.page.ts @@ -0,0 +1,7 @@ +import { BasePage } from '@pages/basePage'; + +export default class AllProductsPage extends BasePage { + async clickOnProductTitleById(productId: string) { + await this.page.locator(`//tr[@id="post-${productId}"]/td[2]/strong/a`).click(); + } +} diff --git a/tests/pw/pages/wp-admin/products/edit-product.page.ts b/tests/pw/pages/wp-admin/products/edit-product.page.ts new file mode 100644 index 0000000000..59f8bdadde --- /dev/null +++ b/tests/pw/pages/wp-admin/products/edit-product.page.ts @@ -0,0 +1,7 @@ +import { BasePage } from '@pages/basePage'; + +export default class EditProductPage extends BasePage { + async clickOnPublishButton() { + await this.page.locator('#publish').click(); + } +} diff --git a/tests/pw/tests/e2e/order-min-max/min-max-01.spec.ts b/tests/pw/tests/e2e/order-min-max/min-max-01.spec.ts new file mode 100644 index 0000000000..39c4861257 --- /dev/null +++ b/tests/pw/tests/e2e/order-min-max/min-max-01.spec.ts @@ -0,0 +1,147 @@ +import test, { BrowserContext, expect, Page } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { payloads } from '@utils/payloads'; +import { data } from '@utils/testData'; + +import VendorDashboardSidebarPage from '@pages/frontend/vendor-dashboard/common/vendor-sidebar.page'; +import VendorProductListPage from '@pages/frontend/vendor-dashboard/products/products-list.page'; +import VendorProductAddEditPage from '@pages/frontend/vendor-dashboard/products/product-add-edit.page'; +import ShopPage from '@pages/frontend/shop/shop.page'; +import SingleProductPage from '@pages/frontend/shop/single-product.page'; +import VendorStoreSettingsPage from '@pages/frontend/vendor-dashboard/settings/store/vendor-store.page'; +import { faker } from '@faker-js/faker'; +import MyAccountAuthPage from '@pages/frontend/my-account/auth/my-account-auth.page'; + +let api: ApiUtils; +let productName: string; +let vendorId: string; +let storeName: string; +let storeSettingsPage: VendorStoreSettingsPage; + +let vendorDashboardSidebarPage: VendorDashboardSidebarPage; +let vendorProductListPage: VendorProductListPage; +let vendorProductAddEditPage: VendorProductAddEditPage; +let vendorMyAccountAuthPage: MyAccountAuthPage; +let vendorPage: Page; +let vendorEmail: string; + +let customerPage: Page; +let shopPage: ShopPage; +let singleProductPage: SingleProductPage; +let customerMyAccountAuthPage: MyAccountAuthPage; +let customerEmail: string; + +let vendorBrowserContext: BrowserContext; +let customerBrowserContext: BrowserContext; + +test.describe('Order Min-Max - Single Product Page', () => { + test.beforeEach(async ({ page, request, browser, baseURL }) => { + await page.goto(baseURL as string); + api = new ApiUtils(request); + + // create customer + const customer = await api.createCustomer(payloads.createCustomer(), payloads.adminAuth); + customerEmail = customer[0].email; + + // create vendor + const vendor = await api.createStore(payloads.createStore(), payloads.adminAuth); + vendorId = vendor[0].id; + vendorEmail = vendor[0].email; + storeName = vendor[0]['store_name']; + + // // create product + const productTitle = `Automation Simple Product ${vendorId}${faker.string.alpha(10)}`; + const product = await api.createProduct( + { + name: productTitle, + type: 'simple', + regular_price: '10', + status: 'publish', + post_author: `${vendorId}`, + categories: [{}], + description: '
test description
', + }, + payloads.adminAuth, + ); + + productName = product[0]['name']; + + // vendor + vendorBrowserContext = await browser.newContext(); + vendorPage = await vendorBrowserContext.newPage(); + vendorDashboardSidebarPage = new VendorDashboardSidebarPage(vendorPage); + vendorMyAccountAuthPage = new MyAccountAuthPage(vendorPage); + vendorProductListPage = new VendorProductListPage(vendorPage); + vendorProductAddEditPage = new VendorProductAddEditPage(vendorPage); + storeSettingsPage = new VendorStoreSettingsPage(vendorPage); + + // customer + customerBrowserContext = await browser.newContext(); + customerPage = await customerBrowserContext.newPage(); + customerMyAccountAuthPage = new MyAccountAuthPage(customerPage); + shopPage = new ShopPage(customerPage); + singleProductPage = new SingleProductPage(customerPage); + + await vendorPage.goto(data.subUrls.frontend.vDashboard.dashboard); + await vendorMyAccountAuthPage.enterUsername(vendorEmail); + await vendorMyAccountAuthPage.enterPassword(process.env.USER_PASSWORD); + await vendorMyAccountAuthPage.clickOnLoginButton(); + + await customerPage.goto(data.subUrls.frontend.myAccount); + await customerMyAccountAuthPage.enterUsername(customerEmail); + await customerMyAccountAuthPage.enterPassword(process.env.USER_PASSWORD); + await customerMyAccountAuthPage.clickOnLoginButton(); + }); + + test.afterEach(async () => { + await vendorBrowserContext.close(); + await customerBrowserContext.close(); + }); + + test('Adding more product than max quantity limit displays error in single product page', { tag: ['@admin'] }, async () => { + await vendorDashboardSidebarPage.clickOnProductsTab(); + await vendorProductListPage.clickOnProductWithTitle(productName); + + const maxQuantity = '2'; + + await vendorProductAddEditPage.enterSimpleProductMaxQty(maxQuantity); + await vendorProductAddEditPage.selectProductStatus('publish'); + await vendorProductAddEditPage.clickOnSaveProduct(); + + await customerPage.goto(data.subUrls.frontend.shop); + await shopPage.clickOnProductWithTitle(productName); + await singleProductPage.clickOnAddToCartButton(); + await singleProductPage.clickOnAddToCartButton(); + await singleProductPage.clickOnAddToCartButton(); + + const errorMessage = await singleProductPage.errorMessageElement().allInnerTexts(); + const expectedErrorMessage = `Maximum allowed quantity for ${productName} is ${maxQuantity}.`; + + expect(errorMessage[0]).toEqual(expectedErrorMessage); + }); + + test('Error displayed in single product page if added product exceeds maximum allowed amount', { tag: ['@admin'] }, async () => { + await vendorDashboardSidebarPage.goto(data.subUrls.frontend.vDashboard.products); + await vendorProductListPage.clickOnProductWithTitle(productName); + + await vendorProductAddEditPage.selectProductStatus('publish'); + await vendorProductAddEditPage.clickOnSaveProduct(); + + const maxAmount = '20'; + + await vendorDashboardSidebarPage.clickOnSettingsTab(); + await storeSettingsPage.enterMaximumOrderAmount(maxAmount); + await storeSettingsPage.clickOnUpdateSettingsButton(); + + await customerPage.goto(data.subUrls.frontend.shop); + await shopPage.clickOnProductWithTitle(productName); + await singleProductPage.clickOnAddToCartButton(); + await singleProductPage.clickOnAddToCartButton(); + await singleProductPage.clickOnAddToCartButton(); + + const errorMessage = await singleProductPage.errorMessageElement().allInnerTexts(); + const expectedErrorMessage = `Maximum allowed cart amount for ${storeName} is $${maxAmount}.00. You currently have $20.00 in cart.`; + + expect(errorMessage[0]).toEqual(expectedErrorMessage); + }); +}); diff --git a/tests/pw/tests/e2e/order-min-max/min-max-02.spec.ts b/tests/pw/tests/e2e/order-min-max/min-max-02.spec.ts new file mode 100644 index 0000000000..b5f34b5bcb --- /dev/null +++ b/tests/pw/tests/e2e/order-min-max/min-max-02.spec.ts @@ -0,0 +1,201 @@ +import test, { BrowserContext, expect, Page } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { payloads } from '@utils/payloads'; +import { data } from '@utils/testData'; + +import VendorDashboardSidebarPage from '@pages/frontend/vendor-dashboard/common/vendor-sidebar.page'; +import VendorProductListPage from '@pages/frontend/vendor-dashboard/products/products-list.page'; +import VendorProductAddEditPage from '@pages/frontend/vendor-dashboard/products/product-add-edit.page'; +import ShopPage from '@pages/frontend/shop/shop.page'; +import SingleProductPage from '@pages/frontend/shop/single-product.page'; +import VendorStoreSettingsPage from '@pages/frontend/vendor-dashboard/settings/store/vendor-store.page'; +import CartPage from '@pages/frontend/cart.page'; +import StorefrontMainMenu from '@pages/frontend/navigation/main-menu.page'; +import { faker } from '@faker-js/faker'; +import MyAccountAuthPage from '@pages/frontend/my-account/auth/my-account-auth.page'; + +let api: ApiUtils; +let productName: string; +let vendorId: string; +let storeName: string; +let storeSettingsPage: VendorStoreSettingsPage; + +let vendorDashboardSidebarPage: VendorDashboardSidebarPage; +let vendorProductListPage: VendorProductListPage; +let vendorProductAddEditPage: VendorProductAddEditPage; +let vendorMyAccountAuthPage: MyAccountAuthPage; +let vendorPage: Page; +let vendorEmail: string; + +let customerPage: Page; +let customerMyAccountAuthPage: MyAccountAuthPage; +let shopPage: ShopPage; +let singleProductPage: SingleProductPage; +let customerCartPage: CartPage; +let storefrontMainMenu: StorefrontMainMenu; +let customerEmail: string; + +let vendorBrowserContext: BrowserContext; +let customerBrowserContext: BrowserContext; + +test.describe('Order Min-Max - Cart Page', () => { + test.beforeEach(async ({ page, request, browser, baseURL }) => { + await page.goto(baseURL as string); + api = new ApiUtils(request); + + // create customer + const customer = await api.createCustomer(payloads.createCustomer(), payloads.adminAuth); + customerEmail = customer[0].email; + + // create vendor + const vendor = await api.createStore(payloads.createStore(), payloads.adminAuth); + vendorId = vendor[0].id; + vendorEmail = vendor[0].email; + storeName = vendor[0]['store_name']; + + // // create product + const title = `Automation Simple Product ${vendorId}${faker.string.alpha(10)}`; + const product = await api.createProduct( + { + name: title, + type: 'simple', + regular_price: '10', + status: 'publish', + post_author: `${vendorId}`, + categories: [{}], + description: 'test description
', + }, + payloads.adminAuth, + ); + + productName = product[0]['name']; + + // vendor + vendorBrowserContext = await browser.newContext(); + vendorPage = await vendorBrowserContext.newPage(); + + vendorDashboardSidebarPage = new VendorDashboardSidebarPage(vendorPage); + vendorProductListPage = new VendorProductListPage(vendorPage); + vendorProductAddEditPage = new VendorProductAddEditPage(vendorPage); + vendorMyAccountAuthPage = new MyAccountAuthPage(vendorPage); + storeSettingsPage = new VendorStoreSettingsPage(vendorPage); + + // customer + customerBrowserContext = await browser.newContext(); + customerPage = await customerBrowserContext.newPage(); + shopPage = new ShopPage(customerPage); + customerMyAccountAuthPage = new MyAccountAuthPage(customerPage); + singleProductPage = new SingleProductPage(customerPage); + customerCartPage = new CartPage(customerPage); + storefrontMainMenu = new StorefrontMainMenu(customerPage); + + await vendorPage.goto(data.subUrls.frontend.vDashboard.dashboard); + await vendorMyAccountAuthPage.enterUsername(vendorEmail); + await vendorMyAccountAuthPage.enterPassword(process.env.USER_PASSWORD); + await vendorMyAccountAuthPage.clickOnLoginButton(); + + await customerPage.goto(data.subUrls.frontend.myAccount); + await customerMyAccountAuthPage.enterUsername(customerEmail); + await customerMyAccountAuthPage.enterPassword(process.env.USER_PASSWORD); + await customerMyAccountAuthPage.clickOnLoginButton(); + }); + + test.afterEach(async () => { + await vendorBrowserContext.close(); + await customerBrowserContext.close(); + }); + + test('Product quantity should not be more than maximum limit', { tag: ['@admin'] }, async () => { + // vendor + await vendorDashboardSidebarPage.clickOnProductsTab(); + await vendorProductListPage.clickOnProductWithTitle(productName); + await vendorProductAddEditPage.enterSimpleProductMaxQty('4'); + await vendorProductAddEditPage.selectProductStatus('publish'); + await vendorProductAddEditPage.clickOnSaveProduct(); + + // customer + await customerPage.goto(data.subUrls.frontend.shop); + await shopPage.clickOnProductWithTitle(productName); + await singleProductPage.clickOnAddToCartButton(); + await customerPage.goto(data.subUrls.frontend.cart); + await customerCartPage.enterQuantityValue(productName, '5'); + await customerCartPage.clickOnUpdateCartButton(); + + const quantityErrorMessage = await customerCartPage.quantityErrorElement().textContent(); + const woocommerceError = await customerCartPage.woocommerceErrorMessage().textContent(); + + expect(quantityErrorMessage?.includes(`Maximum 4 allowed`)).toBeTruthy(); + expect(woocommerceError?.includes(`Maximum allowed quantity for ${productName} is 4.`)).toBeTruthy(); + }); + + test('Product quantity should not be less than minimum limit', { tag: ['@admin'] }, async () => { + // vendor + await vendorDashboardSidebarPage.clickOnProductsTab(); + await vendorProductListPage.clickOnProductWithTitle(productName); + await vendorProductAddEditPage.enterSimpleProductMinQty('3'); + await vendorProductAddEditPage.selectProductStatus('publish'); + await vendorProductAddEditPage.clickOnSaveProduct(); + + // customer + await customerPage.goto(data.subUrls.frontend.shop); + await shopPage.clickOnProductWithTitle(productName); + await singleProductPage.clickOnAddToCartButton(); + await customerPage.goto(data.subUrls.frontend.cart); + await customerCartPage.enterQuantityValue(productName, '2'); + await customerCartPage.clickOnUpdateCartButton(); + + const quantityErrorMessage = await customerCartPage.quantityErrorElement().textContent(); + const woocommerceError = await customerCartPage.woocommerceErrorMessage().textContent(); + + expect(quantityErrorMessage?.includes(`Minimum 3 required`)).toBeTruthy(); + expect(woocommerceError?.includes(`Minimum required quantity for ${productName} is 3.`)).toBeTruthy(); + }); + + test('Cart total should not be more than maximum amount limit', { tag: ['@admin'] }, async () => { + // vendor + await vendorDashboardSidebarPage.clickOnProductsTab(); + await vendorProductListPage.clickOnProductWithTitle(productName); + await vendorProductAddEditPage.selectProductStatus('publish'); + await vendorProductAddEditPage.clickOnSaveProduct(); + + await vendorDashboardSidebarPage.clickOnSettingsTab(); + await storeSettingsPage.enterMaximumOrderAmount('30'); + await storeSettingsPage.clickOnUpdateSettingsButton(); + + // customer + await customerPage.goto(data.subUrls.frontend.shop); + await shopPage.clickOnProductWithTitle(productName); + await singleProductPage.clickOnAddToCartButton(); + await customerPage.goto(data.subUrls.frontend.cart); + await customerCartPage.enterQuantityValue(productName, '4'); + await customerCartPage.clickOnUpdateCartButton(); + + const woocommerceError = await customerCartPage.woocommerceErrorMessage().textContent(); + + expect(woocommerceError?.trim()).toEqual(`Maximum allowed cart amount for ${storeName} is $30.00. You currently have $40.00 in cart.`); + }); + + test('Cart total should not be less than minimum amount limit', { tag: ['@admin'] }, async () => { + // vendor + await vendorDashboardSidebarPage.clickOnProductsTab(); + await vendorProductListPage.clickOnProductWithTitle(productName); + await vendorProductAddEditPage.selectProductStatus('publish'); + await vendorProductAddEditPage.clickOnSaveProduct(); + + await vendorDashboardSidebarPage.clickOnSettingsTab(); + await storeSettingsPage.enterMinimumOrderAmount('30'); + await storeSettingsPage.clickOnUpdateSettingsButton(); + + // customer + await customerPage.goto(data.subUrls.frontend.shop); + await shopPage.clickOnProductWithTitle(productName); + await singleProductPage.enterQuantityValue(productName, '2'); + await singleProductPage.clickOnAddToCartButton(); + await customerPage.goto(data.subUrls.frontend.cart); + await storefrontMainMenu.clickOnCartContentLink(); + + const woocommerceError = await customerCartPage.woocommerceErrorMessage().textContent(); + + expect(woocommerceError?.trim()).toEqual(`Minimum required cart amount for ${storeName} is $30.00. You currently have $20.00 in cart.`); + }); +});