From 0c90ac8955afd46c314ee57f9d517fc64be6a2c5 Mon Sep 17 00:00:00 2001 From: Yeasin Arafat <85940958+YeasinArafat1998@users.noreply.github.com> Date: Mon, 20 May 2024 16:05:20 +0600 Subject: [PATCH 1/8] Modified a grammatical error. (#2276) --- readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.txt b/readme.txt index 8b5f2a9288..d7908efb44 100644 --- a/readme.txt +++ b/readme.txt @@ -308,7 +308,7 @@ A. Not for the moment. We have plans to integrate with BuddyPress via an add-on A. Yes, Dokan is fully responsive. We take mobile first approach and it displays very well in mobile and tablet devices. We are using Twitter Bootstrap as a framework and it just works. = Q. Does it supports variable products? = -A. The **Pro** version does! You can seller normal products, downloadable products and variable products with your own attributes. +A. The **Pro** version does! You can sell normal products, downloadable products, and variable products with your own attributes. = Q. Can each vendor customize his store? = A. Right now we have options for only changing the store banner page. We are working on a better customizable seller store page. From 36d4ed8c2ea7f50d60c90275b48574771a6be181 Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Thu, 23 May 2024 12:57:24 +0600 Subject: [PATCH 2/8] refactor: replaced `apply_filters` with `do_action` where necessary (#2277) --- templates/store-header.php | 4 ++-- templates/store-lists-loop.php | 2 +- templates/vendor-store-info.php | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/templates/store-header.php b/templates/store-header.php index 78fd1dc896..d5a8727132 100644 --- a/templates/store-header.php +++ b/templates/store-header.php @@ -62,7 +62,7 @@ class="profile-info-img"> get_shop_name() ) && 'default' === $profile_layout ) { ?>

get_shop_name() ); ?> - +

@@ -71,7 +71,7 @@ class="profile-info-img"> get_shop_name() ) && 'default' !== $profile_layout ) { ?>

get_shop_name() ); ?> - +

diff --git a/templates/store-lists-loop.php b/templates/store-lists-loop.php index 1a2778bb96..5b943fb189 100644 --- a/templates/store-lists-loop.php +++ b/templates/store-lists-loop.php @@ -47,7 +47,7 @@
-

+

- +
From ebead224f742531bf06725e627a7a9f9b5ff5496 Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Thu, 23 May 2024 14:12:57 +0600 Subject: [PATCH 3/8] chore: Release Version 3.11.2 --- README.md | 10 +++++++--- dokan.php | 6 +++--- languages/dokan-lite.pot | 4 ++-- package-lock.json | 4 ++-- package.json | 2 +- readme.txt | 8 ++++++-- templates/whats-new.php | 12 ++++++++++++ 7 files changed, 33 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index dc20c1a859..ae587f569b 100644 --- a/README.md +++ b/README.md @@ -5,9 +5,9 @@ **Requires at least:** 6.4 **Tested up to:** 6.5.3 **WC requires at least:** 8.0.0 -**WC tested up to:** 8.8.3 +**WC tested up to:** 8.9.1 **Requires PHP:** 7.4 -**Stable tag:** 3.11.1 +**Stable tag:** 3.11.2 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -308,7 +308,7 @@ A. Not for the moment. We have plans to integrate with BuddyPress via an add-on A. Yes, Dokan is fully responsive. We take mobile first approach and it displays very well in mobile and tablet devices. We are using Twitter Bootstrap as a framework and it just works. ### Q. Does it supports variable products? ### -A. The **Pro** version does! You can seller normal products, downloadable products and variable products with your own attributes. +A. The **Pro** version does! You can sell normal products, downloadable products, and variable products with your own attributes. ### Q. Can each vendor customize his store? ### A. Right now we have options for only changing the store banner page. We are working on a better customizable seller store page. @@ -347,6 +347,10 @@ A. Just install and activate the PRO version without deleting the free plugin. A ## Changelog ## +### v3.11.2 ( May 27, 2024 ) ### + +- **update:** WooCommerce 8.9.1 Compatibility added. + ### v3.11.1 ( May 16, 2024 ) ### - **new:** Action hook `dokan_dashboard_sidebar_start` added. diff --git a/dokan.php b/dokan.php index b6af94480f..c58079e943 100755 --- a/dokan.php +++ b/dokan.php @@ -3,13 +3,13 @@ * Plugin Name: Dokan * Plugin URI: https://dokan.co/wordpress/ * Description: An e-commerce marketplace plugin for WordPress. Powered by WooCommerce and weDevs. - * Version: 3.11.1 + * Version: 3.11.2 * Author: weDevs * Author URI: https://dokan.co/ * Text Domain: dokan-lite * Requires Plugins: woocommerce * WC requires at least: 8.0.0 - * WC tested up to: 8.8.3 + * WC tested up to: 8.9.1 * Domain Path: /languages/ * License: GPL2 */ @@ -66,7 +66,7 @@ final class WeDevs_Dokan { * * @var string */ - public $version = '3.11.1'; + public $version = '3.11.2'; /** * Instance of self diff --git a/languages/dokan-lite.pot b/languages/dokan-lite.pot index c04b3ab5b6..69488c2a65 100644 --- a/languages/dokan-lite.pot +++ b/languages/dokan-lite.pot @@ -1,14 +1,14 @@ # Copyright (c) 2024 weDevs Pte. Ltd. All Rights Reserved. msgid "" msgstr "" -"Project-Id-Version: Dokan 3.11.1\n" +"Project-Id-Version: Dokan 3.11.2\n" "Report-Msgid-Bugs-To: https://dokan.co/contact/\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"POT-Creation-Date: 2024-05-16T07:51:11+00:00\n" +"POT-Creation-Date: 2024-05-23T08:02:36+00:00\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "X-Generator: WP-CLI 2.9.0\n" "X-Domain: dokan-lite\n" diff --git a/package-lock.json b/package-lock.json index 18b77788c9..af4a009224 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "dokan", - "version": "3.11.1", + "version": "3.11.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dokan", - "version": "3.11.1", + "version": "3.11.2", "license": "GPL", "devDependencies": { "@wordpress/scripts": "^26.18.0", diff --git a/package.json b/package.json index 80820dc7bf..228fa98c8d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "dokan", - "version": "3.11.1", + "version": "3.11.2", "description": "A WordPress marketplace plugin", "author": "weDevs", "license": "GPL", diff --git a/readme.txt b/readme.txt index d7908efb44..aa309b013e 100644 --- a/readme.txt +++ b/readme.txt @@ -5,9 +5,9 @@ Tags: WooCommerce multivendor marketplace, multivendor marketplace, multivendor, Requires at least: 6.4 Tested up to: 6.5.3 WC requires at least: 8.0.0 -WC tested up to: 8.8.3 +WC tested up to: 8.9.1 Requires PHP: 7.4 -Stable tag: 3.11.1 +Stable tag: 3.11.2 License: GPLv2 or later License URI: http://www.gnu.org/licenses/gpl-2.0.html @@ -347,6 +347,10 @@ A. Just install and activate the PRO version without deleting the free plugin. A == Changelog == += v3.11.2 ( May 27, 2024 ) = + +- **update:** WooCommerce 8.9.1 Compatibility added. + = v3.11.1 ( May 16, 2024 ) = - **new:** Action hook `dokan_dashboard_sidebar_start` added. diff --git a/templates/whats-new.php b/templates/whats-new.php index 18eb3dd7c7..6d3621e735 100644 --- a/templates/whats-new.php +++ b/templates/whats-new.php @@ -3,6 +3,18 @@ * When you are adding new version please follow this sequence for changes: New Feature, New, Improvement, Fix... */ $changelog = [ + [ + 'version' => 'Version 3.11.2', + 'released' => '2024-05-27', + 'changes' => [ + 'Improvement' => [ + [ + 'title' => 'WooCommerce 8.9.1 Compatibility added.', + 'description' => '', + ], + ], + ], + ], [ 'version' => 'Version 3.11.1', 'released' => '2024-05-16', From 76673cb733ca776738c0f2c8992dedd3ce4c84c3 Mon Sep 17 00:00:00 2001 From: shashwata Halder Date: Fri, 24 May 2024 14:58:10 +0600 Subject: [PATCH 4/8] add: vendor verification tests (#2280) * fix: Q&A test * remove: a Q&A locator * update: tests and feature map * add: added vendor verification api tests * add: add verification e2e tests * add: added e2e tests vendor verification * fix: fix setup wizard tests * skip: skip some tests * fix: schema issue * fix: lint & typo --- tests/pw/feature-map/feature-map.yml | 233 ++++---- tests/pw/pages/basePage.ts | 18 +- tests/pw/pages/loginPage.ts | 2 +- tests/pw/pages/privacyPolicyPage.ts | 2 +- tests/pw/pages/productQAPage.ts | 1 + tests/pw/pages/selectors.ts | 277 ++++----- tests/pw/pages/settingsPage.ts | 17 + tests/pw/pages/singleStorePage.ts | 5 +- tests/pw/pages/vendorDeliveryTimePage.ts | 4 +- tests/pw/pages/vendorPage.ts | 21 +- tests/pw/pages/vendorVerificationsPage.ts | 535 ++++++++++-------- tests/pw/pages/withdrawsPage.ts | 20 +- tests/pw/tests/api/vendorSubscription.spec.ts | 58 ++ tests/pw/tests/api/vendorVerification.spec.ts | 112 ++++ tests/pw/tests/e2e/_coverage.teardown.spec.ts | 2 +- tests/pw/tests/e2e/admin.spec.ts | 3 + ...minDashboard.spec.ts => dashboard.spec.ts} | 20 +- tests/pw/tests/e2e/privacyPolicy.spec.ts | 3 +- tests/pw/tests/e2e/refunds.spec.ts | 2 +- tests/pw/tests/e2e/reports.spec.ts | 19 +- .../pw/tests/e2e/requestForQuoteRules.spec.ts | 2 +- tests/pw/tests/e2e/reverseWithdraws.spec.ts | 4 +- tests/pw/tests/e2e/settings.spec.ts | 4 + tests/pw/tests/e2e/stores.spec.ts | 3 +- tests/pw/tests/e2e/vendorDashboard.spec.ts | 22 - tests/pw/tests/e2e/vendorDeliveryTime.spec.ts | 2 +- tests/pw/tests/e2e/vendorReports.spec.ts | 28 - .../pw/tests/e2e/vendorVerifications.spec.ts | 212 +++++-- tests/pw/tests/e2e/withdraws.spec.ts | 18 +- tests/pw/types/environment.d.ts | 3 +- tests/pw/utils/apiEndPoints.ts | 21 + tests/pw/utils/apiUtils.ts | 88 ++- tests/pw/utils/dbUtils.ts | 17 +- tests/pw/utils/interfaces.ts | 52 +- tests/pw/utils/payloads.ts | 34 ++ tests/pw/utils/schemas.ts | 128 ++++- tests/pw/utils/testData.ts | 72 ++- 37 files changed, 1427 insertions(+), 637 deletions(-) create mode 100644 tests/pw/tests/api/vendorSubscription.spec.ts create mode 100644 tests/pw/tests/api/vendorVerification.spec.ts rename tests/pw/tests/e2e/{adminDashboard.spec.ts => dashboard.spec.ts} (68%) delete mode 100644 tests/pw/tests/e2e/vendorDashboard.spec.ts delete mode 100644 tests/pw/tests/e2e/vendorReports.spec.ts diff --git a/tests/pw/feature-map/feature-map.yml b/tests/pw/feature-map/feature-map.yml index 6e9b327e68..4d3a3a15d0 100644 --- a/tests/pw/feature-map/feature-map.yml +++ b/tests/pw/feature-map/feature-map.yml @@ -1,4 +1,4 @@ -- page: 'plugin' +- page: 'plugins' features: admin: admin can install Dokan plugin [lite]: false @@ -42,8 +42,20 @@ admin: admin can login [lite]: true admin can logout [lite]: true -# -- page: 'customer' + +- page: 'Vendor' + features: + vendor: + vendor can register [lite]: true + vendor can register (address fields are enabled) [lite]: true + vendor can login [lite]: true + vendor can logout [lite]: true + vendor can setup setup-wizard [lite]: true + vendor can view account details menu page [lite]: true + vendor update account details [lite]: true + vendor can visit own Store [lite]: true + +- page: 'Customer' features: customer: customer can register [lite]: true @@ -56,14 +68,16 @@ customer can add product to cart [lite]: true customer can buy product [lite]: true customer can buy multi-vendor products [lite]: true -# -- page: 'Admin Dashboard' + +- page: 'Dashboard' features: admin: admin can view Dokan dashboard [lite]: true admin can evaluate dashboard at a glance values [lite]: true admin can add Dokan news subscriber [lite]: true -# + vendor: + vendor can view vendor dashboard [lite]: true + - page: 'Products' features: admin: @@ -101,10 +115,9 @@ vendor can add product wholesale options: true vendor can add product min-max options: false vendor can add product other options [lite]: true - vendor can add catalog mode [lite]: false vendor can duplicate product: true vendor can permanently delete product [lite]: true - # + - page: 'MyOrders' features: customer: @@ -114,7 +127,7 @@ customer can pay pending payment order [lite]: true customer can cancel order [lite]: true customer can order again [lite]: false -# + - page: 'Orders' features: vendor: @@ -133,7 +146,7 @@ vendor can add shipment to order: true vendor can add downloadable product permission to order [lite]: false vendor can perform bulk action on orders [lite]: true -# + - page: 'Payments' features: admin: @@ -153,7 +166,7 @@ vendor can disconnect bank payment method: true vendor can disconnect Skrill payment method: true vendor can disconnect custom payment method: true -# + - page: 'Shop' features: customer: @@ -164,7 +177,7 @@ customer can filter products by location: true customer can view products list on map: true customer can go to product details from shop [lite]: true -# + - page: 'Single Product' features: customer: @@ -176,7 +189,7 @@ customer can view more products [lite]: true customer can view related products [lite]: true customer can review product [lite]: true -# + - page: 'Single Store' features: customer: @@ -186,14 +199,14 @@ customer can sort products on single store [lite]: true customer can view store terms and conditions [lite]: false customer can share store: true -# + - page: 'Store Appearance' features: customer: store map is disabled on store sidebar [lite]: true store open-close time is disabled store sidebar [lite]: true vendor info is disabled on single store page [lite]: false -# + - page: 'Store List' features: customer: @@ -208,22 +221,24 @@ customer can filter open now stores: false customer can view stores on map: true customer can go to single store from store list [lite]: true -# + - page: 'Stores' features: admin: admin can view vendors menu page [lite]: true - admin can view vendor details: true - admin can email vendor: true - admin can add vendor [lite]: true + admin can filter vendors by pending status: false + admin can filter vendors by approved status: false admin can search vendors [lite]: true + admin can view vendor details: true admin can disable vendor's selling capability [lite]: true admin can enable vendor's selling capability [lite]: true + admin can email vendor: true + admin can add vendor [lite]: true admin can edit vendor info [lite]: true admin can view vendor products [lite]: true admin can view vendor orders [lite]: true - admin can perform vendor bulk actions [lite]: true -# + admin can perform bulk action on vendors [lite]: true + - page: 'Withdraw' features: admin: @@ -234,7 +249,7 @@ admin can filter withdrawal requests by vendor [lite]: true admin can filter withdrawal requests by payment methods [lite]: true admin can filter withdrawal requests by date: false - admin can clear filters: false + admin can clear withdrawal request filters: false admin can export withdrawal requests [lite]: true admin can add note to withdrawal request [lite]: true admin can approve withdrawal request [lite]: true @@ -249,43 +264,33 @@ vendor can cancel withdrawal request [lite]: true vendor can add auto withdraw disbursement schedule: true vendor can add default withdraw payment methods [lite]: true -# + - page: 'Reverse Withdrawal' features: admin: admin can view reverse withdrawal menu page [lite]: true - admin can filter reverse withdraws by store [lite]: false - admin can crete reverse withdraws [lite]: true + admin can filter reverse withdrawal by store [lite]: false + admin can filter reverse withdrawal by date [lite]: false + admin can clear reverse withdrawal filters: false + admin can add reverse withdrawal [lite]: true vendor: vendor can view reverse withdrawal menu page [lite]: true vendor can view reverse withdrawal notice [lite]: true vendor can view reverse withdrawal announcement [lite]: true vendor can filter reverse withdrawals by date [lite]: true vendor can pay reverse withdrawal balance [lite]: true -# -- page: 'Vendor' - features: - vendor: - vendor can register [lite]: true - vendor can register (address fields are enabled) [lite]: true - vendor can login [lite]: true - vendor can logout [lite]: true - vendor can setup setup-wizard [lite]: true - vendor can view account details menu page [lite]: true - vendor update account details [lite]: true - vendor can visit own Store [lite]: true -# -- page: 'Vendor Dashboard' - features: - vendor: - vendor can view vendor dashboard [lite]: true -# -- page: 'Vendor Reports' + +- page: 'Catalog Mode' features: + admin: + admin can set catalog settings [lite]: false vendor: - vendor can view reports menu page: true - vendor can export statement: true -# + vendor can set catalog settings [lite]: true + vendor can add catalog mode [lite]: false + vendor can hide product price in catalog mode [lite]: false + customer: + customer can view product in catalog mode [lite]: false + - page: 'Privacy Policy' features: admin: @@ -294,20 +299,20 @@ customer: customer can contact vendor [lite]: true customer can navigate to Dokan privacy policy [lite]: true -# + - page: 'Notice And Promotion' features: admin: admin can view Dokan notice [lite]: true admin can view Dokan promotion [lite]: true admin can view Dokan premium features promotions [lite]: true -# + - page: 'Help' features: admin: admin can view help menu page [lite]: true admin can view get help dropdown [lite]: true -# + - page: 'Vendor Settings' features: vendor: @@ -323,7 +328,6 @@ vendor can set terms and conditions settings [lite]: true vendor can set open-close settings [lite]: true vendor can set vacation settings: true - vendor can set catalog settings [lite]: true vendor can set discount settings: true vendor can set biography settings: true vendor can set store support settings: true @@ -332,7 +336,7 @@ vendor can set social profile settings: true vendor can set rma settings: true vendor can set store seo settings: true -# + - page: 'Setting' features: admin: @@ -347,7 +351,7 @@ admin can enable more products tab (general settings) [lite]: true admin can enable vendor selling (selling settings) [lite]: true admin can set order status change capability (selling settings) [lite]: true -# + - page: 'settings' features: admin: @@ -389,7 +393,7 @@ admin can import dummy data: false admin can clear dummy data: true admin can test distance matrix API: true -# + - page: 'coupons' features: admin: @@ -404,7 +408,7 @@ customer can view coupon on single store: true customer can apply coupon: true customer can buy product with coupon: true -# + - page: 'Refunds' features: admin: @@ -413,11 +417,11 @@ admin can search refund requests by vendor: true admin can approve refund request: true admin can cancel refund requests: true - admin can perform refund requests bulk actions: false + admin can perform bulk action on refund requests: true vendor: vendor can full refund: true vendor can partial refund: true -# + - page: 'Reports' features: admin: @@ -427,6 +431,9 @@ admin can export all logs: true admin can filter all logs by store name: true admin can filter all logs by order status: true + vendor: + vendor can view reports menu page: true + vendor can export statement: true - page: 'Store Categories' features: @@ -439,7 +446,7 @@ admin can delete store category: true vendor: vendor can update own store category: true -# + - page: 'Announcements' features: admin: @@ -455,13 +462,13 @@ vendor can view announcements menu page: true vendor can view announcement details: true vendor can delete announcement: true -# + - page: 'Email Verification' features: customer: user can see registration notice (2-step auth) while registering as customer: true user can see registration notice (2-step auth) while loggingIn: true -# + - page: 'Product Reviews' features: vendor: @@ -474,7 +481,7 @@ vendor can restore trashed product review: true vendor can permanently-delete product review: true vendor can perform bulk action on product reviews: false -# + - page: 'MenuManager' features: admin: @@ -486,7 +493,7 @@ admin can reorder menu: true admin can't reorder or toggle status of dashboard & store menu: true admin can reset menu manager settings: true -# + - page: 'License' features: admin: @@ -506,7 +513,7 @@ admin can activate module: true admin can perform bulk action on modules: true admin can change module view layout: true -# + - page: 'Auction Integration' features: admin: @@ -525,12 +532,12 @@ customer: customer can bid auction product: true customer can buy auction product with buy it now price: false -# + - page: 'Color Scheme Customizer' features: admin: admin can change predefine color scheme: false -# + - page: 'Delivery Time' features: vendor: @@ -538,7 +545,7 @@ vendor can view delivery time settings menu page: true vendor can set delivery time settings: true vendor can filter delivery time: true - vendor can change view style of delivery time calender: true + vendor can change view style of delivery time calendar: true customer: customer can buy product with delivery time: false customer can buy product with store pickup: false @@ -552,7 +559,7 @@ features: admin: no test is written for this feature: false -# + - page: 'Follow Store' features: vendor: @@ -562,37 +569,37 @@ customer can view followed vendors menu page: true customer can follow store on store listing: true customer can follow store on single store: true -# + - page: 'Geolocation' features: admin: no test is written for this feature: false -# + - page: 'Live Chat' features: admin: no test is written for this feature: false -# + - page: 'Live Search' features: admin: no test is written for this feature: false -# + - page: 'MangoPay' features: admin: no test is written for this feature: false -# + - page: 'Min Max Quantities' features: admin: no test is written for this feature: false -# + - page: 'PayPal Marketplace' features: admin: no test is written for this feature: false -# + - page: 'Product Addon' features: vendor: @@ -600,7 +607,7 @@ vendor can add addons: true vendor can edit addon: true vendor can delete addon: true -# + - page: 'Product Advertising' features: admin: @@ -623,7 +630,7 @@ customer can enquire product: true guest: guest customer can enquire product: true -# + - page: 'Product Q&A' features: admin: @@ -652,7 +659,7 @@ customer can post question: true guest: guest customer need to signin/signup post question: true -# + - page: 'Product Subscription' features: vendor: @@ -669,17 +676,17 @@ customer can change payment of subscription: false customer can renew subscription: false customer can buy product subscription: false -# + - page: 'Rank Math SEO' features: admin: no test is written for this feature: false -# + - page: 'Razorpay' features: admin: no test is written for this feature: false -# + - page: 'Report Abuse' features: admin: @@ -694,7 +701,7 @@ guest: guest customer can report product: true guest customer need to log-in to report product: true -# + - page: 'Request for Quotation' features: quote rules: @@ -705,7 +712,7 @@ admin can trash quote rule: true admin can restore quote rule: true admin can permanently delete quote rule: true - admin can perform quote rule bulk actions: false + admin can perform bulk action on quote rules: true quotes: admin: admin can view quotes menu page: true @@ -746,7 +753,7 @@ customer can view return request menu page: true customer can request warranty: true customer can send rma message: true -# + - page: 'Seller Badge' features: admin: @@ -767,17 +774,17 @@ vendor can view badge acquired congratulation popup message action: true vendor can search seller badge: true vendor can filter seller badges: true -# + - page: 'Seller Vacation' features: admin: no test is written for this feature: false -# + - page: 'ShipStation Integration' features: admin: no test is written for this feature: false -# + - page: 'Single Product Multiple Vendor (SPMV)' features: admin: @@ -815,7 +822,7 @@ customer can review store: true customer can edit store review: true customer can view own review: true -# + - page: 'Store Support' features: admin: @@ -858,22 +865,22 @@ customer can't send message to closed support ticket: true guest: guest customer need to login before asking for store support: true -# + - page: 'Stripe Connect' features: admin: no test is written for this feature: false -# + - page: 'Stripe Express' features: admin: no test is written for this feature: false -# + - page: 'Table Rate Shipping' features: admin: no test is written for this feature: false -# + - page: 'Vendor Analytics' features: vendor: @@ -887,7 +894,7 @@ vendor can export product as csv: true vendor can import product as xml: true vendor can import product as csv: true -# + - page: 'Vendor Staff Manager' features: vendor: @@ -896,21 +903,52 @@ vendor can edit staff: true vendor can manage staff permission: true vendor can delete staff: true -# + - page: 'Vendor Subscription' features: admin: no test is written for this feature: false -# + - page: 'Vendor Verification' features: admin: + admin can change verified icon: true + admin can add vendor verification method: true + admin can edit vendor verification method: true + admin can delete vendor verification method: true + admin can update verificaiton method status: true admin can view verifications menu page: true + admin can filter verification requests by pending status: true + admin can filter verification requests by approved status: true + admin can filter verification requests by rejected status: true + admin can filter verification requests by cancelled status: true + admin can filter verification requests by vendor: true + admin can filter verification requests by verification methods: true + admin can reset filter: true + admin can add note to verification request: true + admin can view verification request documents: true + admin can approve verification request: true + admin can reject verification request: true + admin can perform bulk action on verification requests: true + admin receive notification for verification request: false vendor: vendor can view verifications settings menu page: true - vendor can send id verification request: true - vendor can send address verification request: true - vendor can send company verification request: true + vendor can submit verification request: true + vendor can re-submit verification request: true + vendor can cancel verification request: true + vendor can view verification request documents: true + vendor can view verification request notes: true + vendor can view only required verificaiton method on setup wizard: true + vendor can submit verification request on setup wizard: true + vendor can re-submit verification request on setup wizard: true + vendor can cancel verification request on setup wizard: true + vendor can view verification request documents on setup wizard: true + vendor need all required method to be verified to get verification badge: false + vendor need to be verified only one method when no required method is exists: false + vendor address verification gets reset when he update address: false + customer: + customer can view verified badge: true + - page: 'Wholesale' features: admin: @@ -927,6 +965,7 @@ customer can request for become a wholesale customer: true customer can see wholesale price on shop archive: true customer can buy wholesale product: true + - page: 'WooCommerce Booking Integration' features: admin: diff --git a/tests/pw/pages/basePage.ts b/tests/pw/pages/basePage.ts index ef6dbfc209..dd57205977 100644 --- a/tests/pw/pages/basePage.ts +++ b/tests/pw/pages/basePage.ts @@ -55,7 +55,7 @@ export class BasePage { // goto subUrl async goto(subPath: string): Promise { - await this.page.goto(subPath, { waitUntil: 'domcontentloaded' }); + await this.page.goto(subPath, { waitUntil: 'networkidle' }); } // go forward @@ -73,6 +73,14 @@ export class BasePage { await this.page.reload(); } + // reload if visible + async reloadIfVisible(selector: string): Promise { + const isVisible = await this.isVisible(selector); + if (isVisible) { + await this.reload(); + } + } + // returns whether the current URL is expected isCurrentUrl(subPath: string): boolean { const url = new URL(this.getCurrentUrl()); @@ -345,7 +353,7 @@ export class BasePage { } } - // click if visible + // click if exists async clickIfExists(selector: string): Promise { const isExists = await this.isLocatorExists(selector); if (isExists) { @@ -462,6 +470,12 @@ export class BasePage { return this.page.locator(selector); } + // get element count + async getElementCount(selector: string): Promise { + return await this.countLocator(selector); + // return this.page.locator(selector).count(); + } + // get element text content async getElementText(selector: string): Promise { return await this.textContentOfLocator(selector); diff --git a/tests/pw/pages/loginPage.ts b/tests/pw/pages/loginPage.ts index c011c2b11e..f67f69cf38 100644 --- a/tests/pw/pages/loginPage.ts +++ b/tests/pw/pages/loginPage.ts @@ -80,7 +80,7 @@ export class LoginPage extends BasePage { await this.goIfNotThere(data.subUrls.backend.adminLogin); await this.hover(selector.backend.userMenu); await this.page.hover(selector.backend.logout); - await this.clickAndWaitForResponseAndLoadState(data.subUrls.backend.adminLogout, selector.backend.logout); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.backend.adminLogout, selector.backend.logout, 302); await this.toContainText(selector.backend.logoutSuccessMessage, 'You are now logged out.'); const loggedInUser = await this.getCurrentUser(); expect(loggedInUser).toBeUndefined(); diff --git a/tests/pw/pages/privacyPolicyPage.ts b/tests/pw/pages/privacyPolicyPage.ts index 33edbe2a27..8fabebbd30 100644 --- a/tests/pw/pages/privacyPolicyPage.ts +++ b/tests/pw/pages/privacyPolicyPage.ts @@ -28,7 +28,7 @@ export class PrivacyPolicy extends BasePage { await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); // ensure page suppose to open on new tab await this.toHaveAttribute(singleStoreCustomer.storeContactForm.privacyPolicyLink, 'target', '_blank'); - // force page to open on same tab + // force page to open on the same tab await this.setAttributeValue(singleStoreCustomer.storeContactForm.privacyPolicyLink, 'target', '_self'); await this.clickAndWaitForUrl(helpers.stringToRegex('privacy-policy'), singleStoreCustomer.storeContactForm.privacyPolicyLink); } diff --git a/tests/pw/pages/productQAPage.ts b/tests/pw/pages/productQAPage.ts index de3bd6ff56..c00fffe330 100644 --- a/tests/pw/pages/productQAPage.ts +++ b/tests/pw/pages/productQAPage.ts @@ -266,6 +266,7 @@ export class ProductQAPage extends BasePage { async postQuestion(productName: string, questionsAnswers: questionsAnswers, guest = false): Promise { await this.goToProductDetails(productName); await this.click(selector.customer.cSingleProduct.menus.questionsAnswers); + await this.focus(productQACustomer.searchInput); await this.clearAndType(productQACustomer.searchInput, '....'); if (guest) { await this.click(productQACustomer.loginPostQuestion); diff --git a/tests/pw/pages/selectors.ts b/tests/pw/pages/selectors.ts index a7a81370c5..2f69212693 100644 --- a/tests/pw/pages/selectors.ts +++ b/tests/pw/pages/selectors.ts @@ -297,6 +297,7 @@ export const selector = { pending: '//ul[@class="subsubsub"]//li//a[contains(text(),"Pending")]', approved: '//ul[@class="subsubsub"]//li//a[contains(text(),"Approved")]', cancelled: '//ul[@class="subsubsub"]//li//a[contains(text(),"Cancelled")]', + tabByStatus: (status: string) => `//ul[@class="subsubsub"]//li//a[contains(text(),"${status}")]`, }, // Bulk Actions @@ -308,7 +309,6 @@ export const selector = { // Filters filters: { - // filterByVendor: '//select[@id="filter-vendors"]/..//span[@class="select2-selection__arrow"]', filterByVendor: '//span[@id="select2-filter-vendors-container"]/..//span[@class="select2-selection__arrow"]', filterByPaymentMethods: '//span[@id="select2-filter-payment-methods-container"]/..//span[@class="select2-selection__arrow"]', filterInput: '.select2-search.select2-search--dropdown .select2-search__field', @@ -332,7 +332,10 @@ export const selector = { actionsColumn: 'thead th.actions', }, + statusColumnValue: (status: string) => `td.column.status .${status}`, // pending, approved, rejected, cancelled + numberOfRowsFound: '.tablenav.top .displaying-num', + currentNoOfRows: 'table tbody tr', noRowsFound: '//td[normalize-space()="No requests found."]', withdrawCell: (storeName: string) => `//td//a[contains(text(), '${storeName}')]/../..`, withdrawDelete: (storeName: string) => `//td//a[contains(text(), '${storeName}')]/../..//span[@class="trash"]//a`, @@ -1616,49 +1619,61 @@ export const selector = { // Verifications verifications: { - verificationRequestsText: '//h2[normalize-space()="Verification Requests"]', + verificationRequestsText: '//h1[normalize-space()="Verification Requests"]', // Nav Tabs navTabs: { pending: '//ul[@class="subsubsub"]//li//a[contains(text(),"Pending")]', approved: '//ul[@class="subsubsub"]//li//a[contains(text(),"Approved")]', rejected: '//ul[@class="subsubsub"]//li//a[contains(text(),"Rejected")]', + cancelled: '//ul[@class="subsubsub"]//li//a[contains(text(),"Cancelled")]', + tabByStatus: (status: string) => `//ul[@class="subsubsub"]//li//a[contains(text(),"${status}")]`, }, - // Table - table: { - verificationTable: '.verification-table', - storeNameColumn: '//thead//th[contains(text(),"Store Name")]', - photoIdColumn: '//thead//th[contains(text(),"Photo ID")]', - addressColumn: '//thead//th[contains(text(),"Address")]', - phoneNumberColumn: '//thead//th[contains(text(),"Phone Number")]', - companyColumn: '//thead//th[contains(text(),"Company")]', - }, - - vendorRow: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..`, - - idRequest: { - approveRequest: (storeName: string) => `(//a[normalize-space()="${storeName}"]/../../..//a[@data-status="approved"])[1]`, - rejectRequest: (storeName: string) => `(//a[normalize-space()="${storeName}"]/../../..//a[@data-status="rejected"])[1]`, - disapproveRequest: (storeName: string) => `(//a[normalize-space()="${storeName}"]/../../..//a[@data-status="disapproved"])[1]`, + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // approved, cancelled, rejected + applyAction: '//div[@class="tablenav top"]//button[normalize-space()="Apply"]', }, - addressRequest: { - approveRequest: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..//a[@data-type="address"][normalize-space()="Approve"]`, - rejectRequest: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..//a[@data-type="address"][normalize-space()="Reject"]`, - disapproveRequest: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..//a[@data-type="address"][normalize-space()="Disapprove"]`, - proofOfResidence: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..//a[normalize-space()="Proof of residence"]`, + // Filters + filters: { + filterByVendors: '(//select[@id="filter-vendors"]/..//span[@class="select2-selection__arrow"])[1]', + filterByMethods: '(//select[@id="filter-methods"]/..//span[@class="select2-selection__arrow"])[2]', + resetFilterByVendors: '(//select[@id="filter-vendors"]/..//button[@class="button"])[1]', + resetFilterByMethods: '(//select[@id="filter-methods"]/..//button[@class="button"])[1]', + reset: '//button[text()="×"]', + filterInput: '.select2-search.select2-search--dropdown .select2-search__field', + result: 'li.select2-results__option.select2-results__option--highlighted', }, - phoneRequest: { - // todo: + // Table + table: { + verificationTable: '.verification-requests table', + requestIdColumn: 'thead th.id', + methodColumn: 'thead th.method_title', + documentsColumn: 'thead th.documents', + statusColumn: 'thead th.status', + vendorColumn: 'thead th.seller', + noteColumn: 'thead th.note', + dateColumn: 'thead th.created', + actionsColumn: 'thead th.actions', }, + statusColumnValue: (status: string) => `td.column.status .${status}`, // pending, approved, rejected, cancelled - companyRequest: { - approveRequest: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..//a[@data-type="company_verification_files"][normalize-space()="Approve"]`, - rejectRequest: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..//a[@data-type="company_verification_files"][normalize-space()="Reject"]`, - disapproveRequest: (storeName: string) => `//a[normalize-space()="${storeName}"]/../../..//a[@data-type="company_verification_files"][normalize-space()="Disapprove"]`, - }, + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No requests found."]', + currentNoOfRows: 'table tbody tr', + vendorRequestFirstCell: '(//tbody//tr//td//strong)[1]', + verificationRequestCell: (requestId: string) => `//td//strong[contains(text(), '#${requestId}')]/..`, + verificationRequestDocument: (requestId: string) => `(//td//strong[contains(text(), '#${requestId}')]/../..//a[@target])[1]`, + verificationRequestApprove: (requestId: string) => `//td//strong[contains(text(), '#${requestId}')]/../..//button[@title='Approve Request']`, + verificationRequestReject: (requestId: string) => `//td//strong[contains(text(), '#${requestId}')]/../..//button[@title='Reject Request']`, + verificationRequestAddNote: (requestId: string) => `//td//strong[contains(text(), '#${requestId}')]/../..//button[@title='Add Note']`, + vendorRequestNoteModalClose: '.dokan-modal-content .modal-header button', + addNote: '.dokan-modal-content .modal-body textarea', + updateNote: '.dokan-modal-content .modal-footer button', }, // Advertising @@ -1860,7 +1875,7 @@ export const selector = { colors: '//div[@class="nav-title" and contains(text(),"Colors")]', liveSearch: '//div[@class="nav-title" and contains(text(),"Live Search")]', storeSupport: '//div[@class="nav-title" and contains(text(),"Store Support")]', - sellerVerification: '//div[@class="nav-title" and contains(text(),"Seller Verification")]', + vendorVerification: '//div[@class="nav-title" and contains(text(),"Vendor Verification")]', verificationSmsGateways: '//div[@class="nav-title" and contains(text(),"Verification SMS Gateways")]', emailVerification: '//div[@class="nav-title" and contains(text(),"Email Verification")]', socialApi: '//div[@class="nav-title" and contains(text(),"Social API")]', @@ -2122,21 +2137,56 @@ export const selector = { storeSupportSaveChanges: '#submit', }, - // Seller Verification - sellerVerifications: { - // Seller Verification - // Facebook - facebookAppId: '#dokan_verification\\[fb_app_id\\]', - facebookAppSecret: '#dokan_verification\\[fb_app_secret\\]', - // Twitter - consumerKey: '#dokan_verification\\[twitter_app_id\\]', - consumerSecret: '#dokan_verification\\[twitter_app_secret\\]', - // Google - googleClientId: '#dokan_verification\\[google_app_id\\]', - googleClientSecret: '#dokan_verification\\[google_app_secret\\]', - // Linkedin - linkedinClientId: '#dokan_verification\\[linkedin_app_id\\]', - linkedinClientSecret: '#dokan_verification\\[linkedin_app_secret\\]', + vendorVerification: { + verifiedIcon: (iconName: string) => `//label[@for='dokan_verification[verified_icon][${iconName}]']`, + verifiedIconByIcon: (iconName: string) => `//i[@class='${iconName}']//../..`, + verificationMethodRow: (methodName: string) => `//p[text()[normalize-space()='${methodName}']]/../../..`, + enableVerificationMethod: (methodName: string) => `//p[text()[normalize-space()='${methodName}']]/../../..//label[@class="switch tips"]`, + editVerificationMethod: (methodName: string) => `//p[text()[normalize-space()='${methodName}']]/../../..//button[contains(@class, 'rounded-full bg-violet')]`, + deleteVerificationMethod: (methodName: string) => `//p[text()[normalize-space()='${methodName}']]/../../..//button[contains(@class, 'rounded-full bg-red')]`, + + confirmDelete: '.swal2-confirm', + cancelDelete: '.swal2-cancel', + methodCreateSuccessMessage: '//div[text()="Created Successfully."]', + methodUpdateSuccessMessage: '//div[text()="Updated Successfully."]', + methodDeleteSuccessMessage: '//div[text()="Deleted Successfully."]', + + addNewVerification: { + addNewVerification: '//button[text()[normalize-space()="Add New"]]', + closeModal: '//button[text()[normalize-space()="×"]]', + label: 'input#label-text', + helpText: 'input#label-help', + required: 'input#field-required', + cancel: '//button[text()[normalize-space()="Cancel"]]', + create: '//span[text()[normalize-space()="Create"]]/..', + update: '//span[text()[normalize-space()="Update"]]', + }, + + // Social Connect + socialConnect: { + enableMehod: (methodName: string) => `//div[@class='${methodName} dokan-settings-field-type-social']//label[@class='switch tips']`, + settings: (methodName: string) => `//div[@class='${methodName} dokan-settings-field-type-social']//span[contains(@class,"active-social-expend-btn")]`, + + //todo: need to update all social connect locators + facebook: { + facebookAppId: '#dokan_verification\\[fb_app_id\\]', + facebookAppSecret: '#dokan_verification\\[fb_app_secret\\]', + }, + twitter: { + consumerKey: '#dokan_verification\\[twitter_app_id\\]', + consumerSecret: '#dokan_verification\\[twitter_app_secret\\]', + }, + google: { + googleClientId: '#dokan_verification\\[google_app_id\\]', + googleClientSecret: '#dokan_verification\\[google_app_secret\\]', + }, + linked: { + linkedinClientId: '#dokan_verification\\[linkedin_app_id\\]', + linkedinClientSecret: '#dokan_verification\\[linkedin_app_secret\\]', + }, + }, + + saveChanges: '#submit', }, // Verification Sms Gateways @@ -2379,12 +2429,12 @@ export const selector = { // Store vendorStoreURL: '#custom_store_url', - // shippingFeeRecipient: "#select2-shipping_fee_recipient-container", - // shippingFeeRecipientValues: ".select2-results ul li", - // taxFeeRecipient: "#select2-tax_fee_recipient-container", - // taxFeeRecipientValues: ".select2-results ul li", - // mapApiSource: "#select2-map_api_source-container", - // mapApiSourceValues: ".select2-results ul li", + // shippingFeeRecipient: '#select2-shipping_fee_recipient-container', + // shippingFeeRecipientValues: '.select2-results ul li', + // taxFeeRecipient: '#select2-tax_fee_recipient-container', + // taxFeeRecipientValues: '.select2-results ul li', + // mapApiSource: '#select2-map_api_source-container', + // mapApiSourceValues: '.select2-results ul li', shippingFeeRecipient: '#shipping_fee_recipient', taxFeeRecipient: '#tax_fee_recipient', mapApiSource: '#map_api_source', @@ -2392,8 +2442,8 @@ export const selector = { mapBoxAccessToken: '#mapbox_access_token', shareEssentialsOff: '.switch-label', sellingProductTypes: '#dokan_digital_product', - // sellingProductTypes: "#select2-dokan_digital_product-container", - // Values: ".select2-results ul li", + // sellingProductTypes: '#select2-dokan_digital_product-container', + // Values: '.select2-results ul li', continue: '//input[@value="Continue"]', skipThisStep: '//a[contains(text(),"Skip this step")]', @@ -2507,7 +2557,7 @@ export const selector = { // Shipping addShippingZone: '.page-title-action', zoneName: '#zone_name', - // zoneRegions: ".select2-search__field", + // zoneRegions: '.select2-search__field', zoneRegions: '#zone_locations', shippingZoneCell: (shippingZone: string) => `//a[contains(text(), '${shippingZone}')]/..`, editShippingZone: (shippingZone: string) => `//a[contains(text(), '${shippingZone}')]/..//div//a[contains(text(), 'Edit')]`, @@ -3297,6 +3347,10 @@ export const selector = { continuePaymentSetup: '.payment-continue-btn', skipTheStepPaymentSetup: '.payment-step-skip-btn', + //verification + + skipTheStepVerifications: '.payment-step-skip-btn', + // Last Step goToStoreDashboard: '.wc-setup-actions.step .button', returnToMarketplace: '.wc-return-to-dashboard', @@ -4252,7 +4306,7 @@ export const selector = { next: '.fc-next-button', }, - deliveryTimeCalender: 'div#delivery-time-calendar', + deliveryTimeCalendar: 'div#delivery-time-calendar', }, // Review @@ -4480,10 +4534,6 @@ export const selector = { answer: { answerDiv: '//div[normalize-space()="Answer"]/..', answerTitle: '//div[normalize-space()="Answer"]', - - visualButton: 'button#dokan-product-qa-answer-tmce', - textButton: 'button#dokan-product-qa-answer-html', - questionAnswerIframe: 'iframe#dokan-product-qa-answer_ifr', questionAnswerHtmlBody: '#tinymce', saveAnswer: 'button#dokan_product_qa_save_answer', @@ -5907,71 +5957,32 @@ export const selector = { verificationText: '.dokan-settings-content h1', visitStore: '//a[normalize-space()="Visit Store"]', - // Id Verification - id: { - idVerificationDiv: 'div#dokan_v_id', - idVerificationText: '//strong[normalize-space()="ID Verification"]', - - idPendingFeedback: 'div#dokan_v_id_feedback.dokan-alert-warning', - cancelIdVerificationRequest: 'button#dokan_v_id_cancel', - - idApproveFeedback: 'div#dokan_v_id_feedback.dokan-alert-success', - startIdVerification: '#dokan_v_id_click', - passport: '//input[@value="passport"]', - nationalIdCard: '//input[@value="national_id"]', - drivingLicense: '//input[@value="driving_license"]', - uploadPhoto: 'a.dokan-gravatar-drag', - previousUploadedPhoto: '//div[@class="gravatar-wrap"]//img[@class="dokan-gravatar-img"]', - removePreviousUploadedPhoto: '.dokan-close.dokan-remove-gravatar-image', - submitId: '#dokan_v_id_submit', - cancelSubmitId: '#dokan_v_id_cancel_form', - - idUpdateSuccessMessage: 'div#feedback.dokan-alert.dokan-alert-success', - }, - - // Address Verification - address: { - addressVerificationDiv: '//strong[normalize-space()="Address Verification"]/../..', - addressVerificationText: '//strong[normalize-space()="Address Verification"]', - - addressPendingFeedback: 'div#d_v_address_feedback.dokan-alert-warning', - cancelAddressVerificationRequest: 'button#dokan_v_address_cancel', - - addressApproveFeedback: 'div#d_v_address_feedback.dokan-alert-success', - startAddressVerification: '#dokan_v_address_click', - street: '#dokan_address\\[street_1\\]', - street2: '#dokan_address\\[street_2\\]', - city: '#dokan_address\\[city\\]', - postOrZipCode: '#dokan_address\\[zip\\]', - country: '#dokan_address_country', - state: '#dokan_address_state', - uploadResidenceProof: '#vendor-proof', - previousUploadedResidenceProof: '.vendor_img_container img', - removePreviousUploadedResidenceProof: '.dokan-close.dokan-remove-proof-image', - submitAddress: '#dokan_v_address_submit', - cancelSubmitAddress: '.dokan-form-group > #dokan_v_address_cancel', - - addressUpdateSuccessMessage: 'div#feedback.dokan-alert.dokan-alert-success', - }, - - // Company Verification - company: { - companyVerificationDiv: '//strong[normalize-space()="Company Verification"]/../..', - companyVerificationText: '//strong[normalize-space()="Company Verification"]', - - companyPendingFeedback: 'div#d_v_company_feedback.dokan-alert-warning', - cancelCompanyVerificationRequest: 'button#dokan_v_company_cancel', - - companyApproveFeedback: 'div#d_v_company_feedback.dokan-alert-success', - startCompanyVerification: '#dokan_v_company_click', - uploadedCompanyFileClose: '.dokan-btn.dokan-btn-danger', - uploadFiles: 'a.dokan-files-drag', - uploadedFileFirst: '(//a[@onclick="companyVerificationRemoveList(event)"])[1]', - cancelSelectedInfo: '.fa-times', - submitCompanyInfo: '#dokan_v_company_submit', - cancelSubmitCompanyInfo: '.dokan-w5 > #dokan_v_company_cancel', - - companyInfoUpdateSuccessMessage: 'div#feedback.dokan-alert.dokan-alert-success', + verificationMethodAllDiv: '.dokan-verification-content .dokan-panel', + requiredText: '//small[text()="(Required)"]', + firtstVerificationMethod: '(//div[@class="dokan-panel-heading"]//strong)[1]', + verificationMethodDiv: (methodName: string) => `//strong[text()='${methodName}']/../..`, + verificationMethodHelpText: (methodName: string) => `//strong[text()='${methodName}']/../..//p`, + startVerification: (methodName: string) => `//strong[text()='${methodName}']/../..//button[contains(@class,'dokan-vendor-verification-start')]`, + cancelVerification: (methodName: string) => `//strong[text()='${methodName}']/../..//button[contains(@class,'dokan-vendor-verification-cancel-request')]`, + uploadFiles: (methodName: string) => `//strong[text()='${methodName}']/../..//a[@data-uploader_button_text='Add File']`, + removeuploadedFile: (methodName: string) => `(//strong[text()='${methodName}']/../..//a[contains(@class,'dokan-btn-danger')])[1]`, + submit: (methodName: string) => `//strong[text()='${methodName}']/../..//input[contains(@class,'dokan_vendor_verification_submit')]`, + cancelSubmit: (methodName: string) => `//strong[text()='${methodName}']/../..//input[contains(@class,'dokan_vendor_verification_cancel')]`, + verificationStatus: (methodName: string, staus: string) => `//strong[text()='${methodName}']/../..//p//label[contains(@class,'${staus}')]`, + verificationRequestDocument: (methodName: string) => `(//strong[text()='${methodName}']/../..//div[@class='dokan-vendor-verification-file-item']//a)[1]`, + verificationRequestNote: (methodName: string) => `(//strong[text()='${methodName}']/../..//p[text()='Note:']/..//p)[2]`, + + confirmCancelRequest: '.swal2-confirm', + cancelPopup: '.swal2-cancel', + requestCreateSuccessMessage: '//div[text()="Verification Request Creation Successfully."]', + requestCancelSuccessMessage: '//div[text()="Verification Request Cancelled Successfully."]', + + noSocialProfileMessage: '//div[text()[normalize-space()="No Social App is configured by website Admin"]]', + socialProfile: { + connectFacebook: "//button[text()[normalize-space()='Connect Facebook']]", + connectGoogle: "//button[text()[normalize-space()='Connect Google']]", + connectLinkedin: "//button[text()[normalize-space()='Connect Linkedin']]", + connectTwitter: "//button[text()[normalize-space()='Connect Twitter']]", }, }, @@ -6335,14 +6346,14 @@ export const selector = { billingVatOrTaxNumber: '#billing_dokan_vat_number', billingNameOfBank: '#billing_dokan_bank_name', billingBankIban: '#billing_dokan_bank_iban', - // billingCountryOrRegion: "#select2-billing_country-container", + // billingCountryOrRegion: '#select2-billing_country-container', billingCountryOrRegion: '(//span[@class="select2-selection__arrow"])[1]', billingCountryOrRegionInput: '.select2-search.select2-search--dropdown .select2-search__field', billingCountryOrRegionValues: '.select2-results ul li', billingStreetAddress: '#billing_address_1', billingStreetAddress2: '#billing_address_2', billingTownCity: '#billing_city', - // billingState: "#select2-billing_state-container", + // billingState: '#select2-billing_state-container', billingState: '(//span[@class="select2-selection__arrow"])[2]', billingStateInput: '.select2-search.select2-search--dropdown .select2-search__field', billingStateValues: '.select2-results ul li', @@ -6360,14 +6371,14 @@ export const selector = { shippingFirstName: '#shipping_first_name', shippingLastName: '#shipping_last_name', shippingCompanyName: '#shipping_company', - // shippingCountryOrRegion: "#select2-shipping_country-container", + // shippingCountryOrRegion: '#select2-shipping_country-container', shippingCountryOrRegion: '(//span[@class="select2-selection__arrow"])[1]', shippingCountryOrRegionInput: '.select2-search.select2-search--dropdown .select2-search__field', shippingCountryOrRegionValues: '.select2-results ul li', shippingStreetAddress: '#shipping_address_1', shippingStreetAddress2: '#shipping_address_2', shippingTownCity: '#shipping_city', - // shippingState: "#select2-shipping_state-container", + // shippingState: '#select2-shipping_state-container', shippingState: '(//span[@class="select2-selection__arrow"])[2]', shippingStateInput: '.select2-search.select2-search--dropdown .select2-search__field', shippingStateValues: '.select2-results ul li', @@ -6897,6 +6908,8 @@ export const selector = { profileInfoHead: '.profile-info-head', profileImage: '.profile-img.profile-img-circle', storeName: '.profile-info-head .store-name', + verifiedIcon: '//div[@data-original-title="Verified"]', + verifiedIconByIcon: (icon: string) => `//div[@data-original-title="Verified"]//i[@class="${icon}"]`, profileInfo: '.profile-info', storeInfo: '.dokan-store-info', @@ -7275,7 +7288,7 @@ export const selector = { billingVatOrTaxNumber: '#billing_dokan_vat_number', billingNameOfBank: '#billing_dokan_bank_name', billingBankIban: '#billing_dokan_bank_iban', - // billingCountryOrRegion: "#select2-billing_country-container", + // billingCountryOrRegion: '#select2-billing_country-container', billingCountryOrRegion: '.select2-selection__arrow', billingCountryOrRegionValues: '.select2-results ul li', billingStreetAddress: '#billing_address_1', @@ -7294,14 +7307,14 @@ export const selector = { shippingFirstName: '#shipping_first_name', shippingLastName: '#shipping_last_name', shippingCompanyName: '#shipping_company', - // shippingCountryOrRegion: "#select2-shipping_country-container", + // shippingCountryOrRegion: '#select2-shipping_country-container', shippingCountryOrRegion: '.select2-selection__arrow', shippingCountryOrRegionValues: '.select2-results ul li', shippingStreetAddress: '#shipping_address_1', shippingStreetAddress2: '#shipping_address_2', shippingTownCity: '#shipping_city', - // shippingState: "#select2-shipping_state-container", + // shippingState: '#select2-shipping_state-container', shippingState: '.select2-selection__arrow', shippingStateValues: '.select2-results ul li', shippingZipCode: '#shipping_postcode', diff --git a/tests/pw/pages/settingsPage.ts b/tests/pw/pages/settingsPage.ts index 7faed34ee0..b65e241f37 100644 --- a/tests/pw/pages/settingsPage.ts +++ b/tests/pw/pages/settingsPage.ts @@ -300,6 +300,23 @@ export class SettingsPage extends AdminPage { await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, storeSupport.saveSuccessMessage); } + // Admin Set Dokan Vendor Verificaton Settings + async setDokanVendorVerificationSettings(vendorVerification: dokanSettings['vendorVerification']) { + await this.goToDokanSettings(); + await this.click(settingsAdmin.menus.vendorVerification); + + await this.click(settingsAdmin.vendorVerification.verifiedIcon(vendorVerification.verifiedIcons.userCheckSolid)); + const response = await this.enableSwitcherAndWaitForResponse( + data.subUrls.api.dokan.verificationMethods, + settingsAdmin.vendorVerification.enableVerificationMethod(vendorVerification.verificationMethods.nationalId), + ); + response && (await this.toBeVisible(settingsAdmin.vendorVerification.methodUpdateSuccessMessage)); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, settingsAdmin.vendorVerification.saveChanges); + await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, vendorVerification.saveSuccessMessage); + } + // Admin Set Dokan Email Verification Settings async setDokanEmailVerificationSettings(emailVerification: dokanSettings['emailVerification']) { await this.goToDokanSettings(); diff --git a/tests/pw/pages/singleStorePage.ts b/tests/pw/pages/singleStorePage.ts index f78d3952f5..758f970df7 100644 --- a/tests/pw/pages/singleStorePage.ts +++ b/tests/pw/pages/singleStorePage.ts @@ -22,7 +22,8 @@ export class SingleStorePage extends CustomerPage { await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); // store profile elements are visible - await this.multipleElementVisible(singleStoreCustomer.storeProfile); + const { verifiedIcon, verifiedIconByIcon, ...storeProfile } = singleStoreCustomer.storeProfile; + await this.multipleElementVisible(storeProfile); // store tab elements are visible if (!DOKAN_PRO) { @@ -92,7 +93,7 @@ export class SingleStorePage extends CustomerPage { await this.click(singleStoreCustomer.storeTabs.share); // ensure page suppose to open on new tab await this.toHaveAttribute(singleStoreCustomer.sharePlatForms[site as keyof typeof singleStoreCustomer.sharePlatForms], 'target', '_blank'); - // force page to open on same tab + // force page to open on the same tab await this.setAttributeValue(singleStoreCustomer.sharePlatForms[site as keyof typeof singleStoreCustomer.sharePlatForms], 'target', '_self'); await this.clickAndWaitForUrl(new RegExp('.*' + site + '.*'), singleStoreCustomer.sharePlatForms[site as keyof typeof singleStoreCustomer.sharePlatForms]); } diff --git a/tests/pw/pages/vendorDeliveryTimePage.ts b/tests/pw/pages/vendorDeliveryTimePage.ts index 773d006df8..73c61f1ab7 100644 --- a/tests/pw/pages/vendorDeliveryTimePage.ts +++ b/tests/pw/pages/vendorDeliveryTimePage.ts @@ -25,7 +25,7 @@ export class VendorDeliveryTimePage extends CustomerPage { await this.toBeVisible(deliveryTimeVendor.deliveryTimeAndStorePickup); // delivery time calendar is visible - await this.toBeVisible(deliveryTimeVendor.deliveryTimeCalender); + await this.toBeVisible(deliveryTimeVendor.deliveryTimeCalendar); // delivery time filter elements are visible await this.multipleElementVisible(deliveryTimeVendor.filter); @@ -90,7 +90,7 @@ export class VendorDeliveryTimePage extends CustomerPage { // todo: need order via delivery time; via api for assertion } - // update calender views + // update calendar views async updateCalendarView(value: string) { await this.goIfNotThere(data.subUrls.frontend.vDashboard.deliveryTime); diff --git a/tests/pw/pages/vendorPage.ts b/tests/pw/pages/vendorPage.ts index 1c53b525d5..2173ea66a4 100644 --- a/tests/pw/pages/vendorPage.ts +++ b/tests/pw/pages/vendorPage.ts @@ -14,6 +14,7 @@ const registrationVendor = selector.vendor.vRegistration; const setupWizardVendor = selector.vendor.vSetup; const productsVendor = selector.vendor.product; const ordersVendor = selector.vendor.orders; +const verificationsVendor = selector.vendor.vVerificationSettings; export class VendorPage extends BasePage { constructor(page: Page) { @@ -154,7 +155,7 @@ export class VendorPage extends BasePage { } await this.check(setupWizardVendor.email); - await this.click(setupWizardVendor.continueStoreSetup); + await this.clickAndWaitForLoadState(setupWizardVendor.continueStoreSetup); // payment @@ -174,7 +175,21 @@ export class VendorPage extends BasePage { await this.typeIfVisible(setupWizardVendor.customPayment, setupWizardData.customPayment); // skrill await this.typeIfVisible(setupWizardVendor.skrill, setupWizardData.skrill); - await this.click(setupWizardVendor.continuePaymentSetup); + await this.clickAndWaitForLoadState(setupWizardVendor.continuePaymentSetup); + + // verifications + if (DOKAN_PRO) { + const method = await this.getElementText(verificationsVendor.firtstVerificationMethod); + if (method) { + await this.click(verificationsVendor.startVerification(method)); + await this.click(verificationsVendor.uploadFiles(method)); + await this.uploadMedia(setupWizardData.file); + await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.submit(method)); + await this.toBeVisible(verificationsVendor.requestCreateSuccessMessage); + await this.toBeVisible(verificationsVendor.verificationStatus(method, 'pending')); + } + await this.click(setupWizardVendor.skipTheStepVerifications); + } await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.dashboard, setupWizardVendor.goToStoreDashboard); } else { await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.dashboard, setupWizardVendor.notRightNow); @@ -287,7 +302,7 @@ export class VendorPage extends BasePage { await this.goIfNotThere(data.subUrls.frontend.vDashboard.dashboard); // ensure page suppose to open on new tab await this.toHaveAttribute(selector.vendor.vDashboard.menus.visitStore, 'target', '_blank'); - // force page to open on same tab + // force page to open on the same tab await this.setAttributeValue(selector.vendor.vDashboard.menus.visitStore, 'target', '_self'); await this.click(selector.vendor.vDashboard.menus.visitStore); await expect(this.page).toHaveURL(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName)) + '/'); diff --git a/tests/pw/pages/vendorVerificationsPage.ts b/tests/pw/pages/vendorVerificationsPage.ts index 5a451f22bc..e3c9bf54ef 100644 --- a/tests/pw/pages/vendorVerificationsPage.ts +++ b/tests/pw/pages/vendorVerificationsPage.ts @@ -1,104 +1,226 @@ -import { Page } from '@playwright/test'; +import { Page, expect } from '@playwright/test'; import { AdminPage } from '@pages/adminPage'; +import { CustomerPage } from '@pages/customerPage'; import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; import { data } from '@utils/testData'; import { vendor } from '@utils/interfaces'; +import { dokanSettings, vendorSetupWizard } from '@utils/interfaces'; // selectors +const settingsAdmin = selector.admin.dokan.settings; const verificationsAdmin = selector.admin.dokan.verifications; const verificationsVendor = selector.vendor.vVerificationSettings; +const setupWizardVendor = selector.vendor.vSetup; +const singleStoreCustomer = selector.customer.cSingleStore; -export class vendorVerificationsPage extends AdminPage { +export class VendorVerificationsPage extends AdminPage { constructor(page: Page) { super(page); } - // verification requests + customerPage = new CustomerPage(this.page); - // verification requests render properly - async adminVerificationsRenderProperly() { - await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + // verification methods + + async changeVerifiedIcon(icon: string, storeName: string) { + await this.goToDokanSettings(); + await this.click(settingsAdmin.menus.vendorVerification); + + await this.click(settingsAdmin.vendorVerification.verifiedIconByIcon(icon)); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, settingsAdmin.vendorVerification.saveChanges); + await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, data.dokanSettings.vendorVerification.saveSuccessMessage); + + // single store page + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.toBeVisible(singleStoreCustomer.storeProfile.verifiedIconByIcon(icon)); + } + + // update verification method status + async updateVerificationMethodStatus(methodName: string, status: string) { + await this.goToDokanSettings(); + await this.reload(); + await this.click(settingsAdmin.menus.vendorVerification); + + const response = + status === 'enable' + ? await this.enableSwitcherAndWaitForResponse(data.subUrls.api.dokan.verificationMethods, settingsAdmin.vendorVerification.enableVerificationMethod(methodName)) + : await this.disableSwitcherAndWaitForResponse(data.subUrls.api.dokan.verificationMethods, settingsAdmin.vendorVerification.enableVerificationMethod(methodName)); + response && (await this.toBeVisible(settingsAdmin.vendorVerification.methodUpdateSuccessMessage)); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, settingsAdmin.vendorVerification.saveChanges); + await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, data.dokanSettings.vendorVerification.saveSuccessMessage); + } - // tools text is visible - await this.toBeVisible(verificationsAdmin.verificationRequestsText); + // updte verification method fields + async updateVerificationMethod(verificationMethod: dokanSettings['vendorVerification']['verificationMethodDetails']) { + await this.clearAndType(settingsAdmin.vendorVerification.addNewVerification.label, verificationMethod.title); + await this.clearAndType(settingsAdmin.vendorVerification.addNewVerification.helpText, verificationMethod.help_text); + verificationMethod.required && (await this.check(settingsAdmin.vendorVerification.addNewVerification.required)); + } + + // add Verificaton Method + async addVendoVerificationMethod(verificationMethod: dokanSettings['vendorVerification']['verificationMethodDetails']) { + await this.goToDokanSettings(); + await this.reload(); + await this.click(settingsAdmin.menus.vendorVerification); + + await this.click(settingsAdmin.vendorVerification.addNewVerification.addNewVerification); + await this.updateVerificationMethod(verificationMethod); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.verificationMethods, settingsAdmin.vendorVerification.addNewVerification.create, 201); + await this.toBeVisible(settingsAdmin.vendorVerification.methodCreateSuccessMessage); - // navTab elements are visible - await this.multipleElementVisible(verificationsAdmin.navTabs); + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, settingsAdmin.vendorVerification.saveChanges); + await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, data.dokanSettings.vendorVerification.saveSuccessMessage); + } - // verification table elements are visible - await this.multipleElementVisible(verificationsAdmin.table); + // edit Verificaton Method + async editVendoVerificationMethod(methodName: string, verificationMethod: dokanSettings['vendorVerification']['verificationMethodDetails']) { + await this.goToDokanSettings(); + await this.reload(); + await this.click(settingsAdmin.menus.vendorVerification); + + await this.hover(settingsAdmin.vendorVerification.verificationMethodRow(methodName)); + await this.click(settingsAdmin.vendorVerification.editVerificationMethod(methodName)); + await this.updateVerificationMethod(verificationMethod); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.verificationMethods, settingsAdmin.vendorVerification.addNewVerification.update); + await this.toBeVisible(settingsAdmin.vendorVerification.methodUpdateSuccessMessage); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, settingsAdmin.vendorVerification.saveChanges); + await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, data.dokanSettings.vendorVerification.saveSuccessMessage); } - // approve verification requests - async approveVerificationRequest(storeName: string, verificationType: string, action: string) { + // delete Verificaton Method + async deleteVendoVerificationMethod(methodName: string) { + await this.goToDokanSettings(); + await this.reload(); + await this.click(settingsAdmin.menus.vendorVerification); + + await this.hover(settingsAdmin.vendorVerification.verificationMethodRow(methodName)); + await this.click(settingsAdmin.vendorVerification.deleteVerificationMethod(methodName)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.verificationMethods, settingsAdmin.vendorVerification.confirmDelete, 204); + await this.toBeVisible(settingsAdmin.vendorVerification.methodDeleteSuccessMessage); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, settingsAdmin.vendorVerification.saveChanges); + await this.toContainText(settingsAdmin.dokanUpdateSuccessMessage, data.dokanSettings.vendorVerification.saveSuccessMessage); + } + + // verification requests + + // verification requests render properly + async adminVerificationsRenderProperly() { await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + await this.wait(1); //TODO: added to goto else clause need to resolve this - const verificationRequestIsExists = await this.isVisible(verificationsAdmin.vendorRow(storeName)); + const noVerificationRequests = await this.isVisible(verificationsAdmin.noRowsFound); - if (!verificationRequestIsExists) { - console.log('No pending verification request found!!'); - return; - } + if (noVerificationRequests) { + await this.toContainText(verificationsAdmin.noRowsFound, 'No requests found.'); + console.log('No verification request found'); + } else { + // verification requests text is visible + await this.toBeVisible(verificationsAdmin.verificationRequestsText); - await this.hover(verificationsAdmin.vendorRow(storeName)); + // navTab elements are visible + const { tabByStatus, ...navTabs } = verificationsAdmin.navTabs; + await this.multipleElementVisible(navTabs); - switch (verificationType) { - case 'id': - if (action === 'approve') { - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.idRequest.approveRequest(storeName)); - } else { - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.idRequest.rejectRequest(storeName)); - } - break; + // bulk action elements are visible + await this.multipleElementVisible(verificationsAdmin.bulkActions); - case 'address': - if (action === 'approve') { - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.addressRequest.approveRequest(storeName)); - } else { - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.addressRequest.rejectRequest(storeName)); - } + // filter elements are visible + const { filterInput, resetFilterByVendors, resetFilterByMethods, reset, result, ...filters } = verificationsAdmin.filters; + await this.multipleElementVisible(filters); - break; + // verification table elements are visible + await this.multipleElementVisible(verificationsAdmin.table); + } + } - case 'company': - if (action === 'approve') { - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.companyRequest.approveRequest(storeName)); - } else { - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.companyRequest.rejectRequest(storeName)); - } + // verification requests + async filterVerificationRequests(input: string, action: string): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + await this.reloadIfVisible(verificationsAdmin.filters.reset); + + switch (action) { + case 'by-status': { + await this.clickAndWaitForLoadState(verificationsAdmin.navTabs.tabByStatus(input)); + await this.wait(1); // todo: need to resolve this + const count = await this.getElementCount(verificationsAdmin.statusColumnValue(input.toLowerCase())); + await this.toHaveCount(verificationsAdmin.currentNoOfRows, count); + return; + } + + case 'by-vendor': + await this.click(verificationsAdmin.filters.filterByVendors); + break; + case 'by-verification-method': + await this.click(verificationsAdmin.filters.filterByMethods); break; default: break; } + await this.fill(verificationsAdmin.filters.filterInput, input); + await this.toContainText(verificationsAdmin.filters.result, input); + await this.pressAndWaitForResponse(data.subUrls.api.dokan.verifications, data.key.enter); + // todo: need to wait for focus event + //todo: need to update assertions + const count = (await this.getElementText(verificationsAdmin.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); } - // disapprove verification requests - async disapproveVerificationRequest(storeName: string, verificationType: string) { + // reset filter + async resetFilter() { await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.verifications, verificationsAdmin.filters.reset); + await this.notToBeVisible(verificationsAdmin.filters.reset); + } - await this.clickAndWaitForLoadState(verificationsAdmin.navTabs.approved); + // add note to verification request + async addNoteVerificationRequest(requestId: string, note: string): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + await this.reloadIfVisible(verificationsAdmin.filters.reset); - const verificationRequestIsExists = await this.isVisible(verificationsAdmin.vendorRow(storeName)); - if (!verificationRequestIsExists) { - console.log('No approved verification request found!!'); - return; - } + await this.click(verificationsAdmin.verificationRequestAddNote(requestId)); + await this.clearAndType(verificationsAdmin.addNote, note); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.verifications, verificationsAdmin.updateNote); + } - await this.hover(verificationsAdmin.vendorRow(storeName)); + // view verification request document + async viewVerificationRequestDocument(requestId: string): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + await this.reloadIfVisible(verificationsAdmin.filters.reset); + + // ensure link suppose to open on new tab + await this.toHaveAttribute(verificationsAdmin.verificationRequestDocument(requestId), 'target', '_blank'); + // force link to open on the same tab + await this.setAttributeValue(verificationsAdmin.verificationRequestDocument(requestId), 'target', '_self'); + const documentLink = (await this.getAttributeValue(verificationsAdmin.verificationRequestDocument(requestId), 'href')) as string; + await this.clickAndWaitForUrl(documentLink, verificationsAdmin.verificationRequestDocument(requestId)); + await this.toHaveAttribute('body img', 'src', documentLink); + } - switch (verificationType) { - case 'id': - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.idRequest.disapproveRequest(storeName)); - break; + // update verification request + async updateVerificationRequest(requestId: string, action: string): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + await this.reload(); + await this.reloadIfVisible(verificationsAdmin.filters.reset); - case 'address': - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.addressRequest.disapproveRequest(storeName)); + switch (action) { + case 'approve': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.verifications, verificationsAdmin.verificationRequestApprove(requestId)); break; - case 'company': - await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, verificationsAdmin.companyRequest.disapproveRequest(storeName)); + case 'reject': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.verifications, verificationsAdmin.verificationRequestReject(requestId)); break; default: @@ -106,10 +228,23 @@ export class vendorVerificationsPage extends AdminPage { } } + // verification request bulk action + async verificationRequestBulkAction(action: string): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + await this.reloadIfVisible(verificationsAdmin.filters.reset); + + // ensure row exists + await this.notToBeVisible(verificationsAdmin.noRowsFound); + + await this.click(verificationsAdmin.bulkActions.selectAll); + await this.selectByValue(verificationsAdmin.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.verifications, verificationsAdmin.bulkActions.applyAction); + } + // vendor // vendor verifications render properly - async vendorVerificationsSettingsRenderProperly() { + async vendorVerificationsSettingsRenderProperly(methodName: string) { await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); // verification text is visible @@ -118,209 +253,133 @@ export class vendorVerificationsPage extends AdminPage { // visit store link is visible await this.toBeVisible(verificationsVendor.visitStore); - // verification div and heading text + // verification method + await this.toBeVisible(verificationsVendor.verificationMethodDiv(methodName)); + await this.toBeVisible(verificationsVendor.startVerification(methodName)); - // id - await this.toBeVisible(verificationsVendor.id.idVerificationDiv); - await this.toBeVisible(verificationsVendor.id.idVerificationText); + await this.click(verificationsVendor.startVerification(methodName)); - // address - await this.toBeVisible(verificationsVendor.address.addressVerificationDiv); - await this.toBeVisible(verificationsVendor.address.addressVerificationText); - - // company - await this.toBeVisible(verificationsVendor.company.companyVerificationDiv); - await this.toBeVisible(verificationsVendor.company.companyVerificationText); - - // verification request is pending - - // id - const idRequestIsPending = await this.isVisible(verificationsVendor.id.idPendingFeedback); - if (idRequestIsPending) { - await this.toContainText(verificationsVendor.id.idPendingFeedback, 'Your ID verification request is pending'); - await this.toBeVisible(verificationsVendor.id.cancelIdVerificationRequest); - } - - // address - const addressRequestIsPending = await this.isVisible(verificationsVendor.address.addressPendingFeedback); - if (addressRequestIsPending) { - await this.toContainText(verificationsVendor.address.addressPendingFeedback, 'Your Address verification request is pending'); - await this.toBeVisible(verificationsVendor.address.cancelAddressVerificationRequest); - } - - // company - const companyRequestIsPending = await this.isVisible(verificationsVendor.company.companyPendingFeedback); - if (companyRequestIsPending) { - await this.toContainText(verificationsVendor.company.companyPendingFeedback, 'Your company verification request is pending'); - await this.toBeVisible(verificationsVendor.company.cancelCompanyVerificationRequest); - } - - // verification request is approved - - // id - const idRequestIsApproved = await this.isVisible(verificationsVendor.id.idApproveFeedback); - if (idRequestIsApproved) { - await this.toContainText(verificationsVendor.id.idApproveFeedback, 'Your ID verification request is approved'); - } - - // address - const addressRequestIsApproved = await this.isVisible(verificationsVendor.address.addressApproveFeedback); - if (addressRequestIsApproved) { - await this.toContainText(verificationsVendor.address.addressApproveFeedback, 'Your Address verification request is approved'); - await this.toBeVisible(verificationsVendor.address.startAddressVerification); - } + await this.toBeVisible(verificationsVendor.verificationMethodHelpText(methodName)); + await this.toBeVisible(verificationsVendor.uploadFiles(methodName)); + await this.toBeVisible(verificationsVendor.submit(methodName)); + await this.toBeVisible(verificationsVendor.cancelSubmit(methodName)); + } - // company - const companyRequestIsApproved = await this.isVisible(verificationsVendor.company.companyApproveFeedback); - if (companyRequestIsApproved) { - await this.toContainText(verificationsVendor.company.companyApproveFeedback, 'Your company verification request is approved'); - await this.toBeVisible(verificationsVendor.company.startCompanyVerification); + // vendor submit verification request + async submitVerificationRequest(verification: vendor['verification'], setupWizard = false): Promise { + if (!setupWizard) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + await this.reload(); //todo: need to resolve this + } else { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.setupWizard); + await this.click(setupWizardVendor.letsGo); + await this.completeAddressStep(data.vendorSetupWizard); + // await this.click(setupWizardVendor.skipTheStepStoreSetup); + await this.click(setupWizardVendor.skipTheStepPaymentSetup); } - // no verification request is submitted - - // id - if (!idRequestIsPending && !idRequestIsApproved) { - await this.toBeVisible(verificationsVendor.id.startIdVerification); - - await this.click(verificationsVendor.id.startIdVerification); + await this.click(verificationsVendor.startVerification(verification.method)); + await this.click(verificationsVendor.uploadFiles(verification.method)); + await this.uploadMedia(verification.file); + await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.submit(verification.method)); - await this.toBeVisible(verificationsVendor.id.passport); - await this.toBeVisible(verificationsVendor.id.nationalIdCard); - await this.toBeVisible(verificationsVendor.id.drivingLicense); - const previousUploadedPhotoIsVisible = await this.isVisible(verificationsVendor.id.previousUploadedPhoto); - previousUploadedPhotoIsVisible && (await this.toBeVisible(verificationsVendor.id.uploadPhoto)); - await this.toBeVisible(verificationsVendor.id.submitId); - await this.toBeVisible(verificationsVendor.id.cancelSubmitId); - } + await this.toBeVisible(verificationsVendor.requestCreateSuccessMessage); + await this.toBeVisible(verificationsVendor.verificationStatus(verification.method, 'pending')); + } - // address - if (!addressRequestIsPending && !addressRequestIsApproved) { - await this.toBeVisible(verificationsVendor.address.startAddressVerification); - - await this.click(verificationsVendor.address.startAddressVerification); - - await this.toBeVisible(verificationsVendor.address.street); - await this.toBeVisible(verificationsVendor.address.street2); - await this.toBeVisible(verificationsVendor.address.city); - await this.toBeVisible(verificationsVendor.address.postOrZipCode); - await this.toBeVisible(verificationsVendor.address.country); - const previousUploadedResidenceProofIsVisible = await this.isVisible(verificationsVendor.address.previousUploadedResidenceProof); - !previousUploadedResidenceProofIsVisible && (await this.toBeVisible(verificationsVendor.address.uploadResidenceProof)); - await this.toBeVisible(verificationsVendor.address.submitAddress); - await this.toBeVisible(verificationsVendor.address.cancelSubmitAddress); + // vendor cancel verification request + async cancelVerificationRequest(verificationMethod: string, setupWizard = false): Promise { + if (!setupWizard) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + await this.reload(); //todo: need to resolve this + } else { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.setupWizard); + await this.click(setupWizardVendor.letsGo); + await this.completeAddressStep(data.vendorSetupWizard); + // await this.click(setupWizardVendor.skipTheStepStoreSetup); + await this.click(setupWizardVendor.skipTheStepPaymentSetup); } - // company - if (!companyRequestIsPending && !companyRequestIsApproved) { - await this.toBeVisible(verificationsVendor.company.startCompanyVerification); - - await this.click(verificationsVendor.company.startCompanyVerification); - - await this.toBeVisible(verificationsVendor.company.uploadFiles); - await this.toBeVisible(verificationsVendor.company.submitCompanyInfo); - await this.toBeVisible(verificationsVendor.company.cancelSubmitCompanyInfo); - } + await this.click(verificationsVendor.cancelVerification(verificationMethod)); + await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.confirmCancelRequest); + await this.toBeVisible(verificationsVendor.requestCancelSuccessMessage); } - // vendor send id verification request - async sendIdVerificationRequest(verification: vendor['verification']): Promise { - await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); - - const idRequestIsApproved = await this.isVisible(verificationsVendor.id.idApproveFeedback); - if (idRequestIsApproved) { - return; - } - - // cancel previous verification request if any - const cancelRequestIsVisible = await this.isVisible(verificationsVendor.id.cancelIdVerificationRequest); - if (cancelRequestIsVisible) { - await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.id.cancelIdVerificationRequest); - await this.toContainText(verificationsVendor.id.idUpdateSuccessMessage, verification.idRequestSubmitCancel); + // vendor view verification request document + async vendorViewVerificationRequestDocument(methodName: string, setupWizard = false): Promise { + if (!setupWizard) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + } else { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.setupWizard); + await this.click(setupWizardVendor.letsGo); + await this.completeAddressStep(data.vendorSetupWizard); + // await this.click(setupWizardVendor.skipTheStepStoreSetup); + await this.click(setupWizardVendor.skipTheStepPaymentSetup); } - // id verification - await this.click(verificationsVendor.id.startIdVerification); - // await this.wait(0.5); // todo: resolve this - await this.waitForVisibleLocator(verificationsVendor.id.submitId); - - // remove previously uploaded image - const uploadPhotoBtnIsVisible = await this.isVisible(verificationsVendor.id.uploadPhoto); - if (!uploadPhotoBtnIsVisible) { - // await this.hover(verificationsVendor.id.previousUploadedPhoto); // todo: not working: playwright issue - // await this.click(verificationsVendor.id.removePreviousUploadedPhoto); + // ensure link suppose to open on new tab + await this.toHaveAttribute(verificationsVendor.verificationRequestDocument(methodName), 'target', '_blank'); + // force link to open on the same tab + await this.setAttributeValue(verificationsVendor.verificationRequestDocument(methodName), 'target', '_self'); + const documentLink = (await this.getAttributeValue(verificationsVendor.verificationRequestDocument(methodName), 'href')) as string; + await this.clickAndWaitForUrl(documentLink, verificationsVendor.verificationRequestDocument(methodName)); + await this.toHaveAttribute('body img', 'src', documentLink); + } - await this.setAttributeValue('.gravatar-wrap', 'class', 'gravatar-wrap dokan-hide'); - await this.setAttributeValue('.gravatar-button-area.dokan-hide', 'class', 'gravatar-button-area'); + // vendor view verification request notes + async viewVerificationRequestNote(methodName: string, note: string, setupWizard = false): Promise { + if (!setupWizard) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + } else { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.setupWizard); + await this.click(setupWizardVendor.letsGo); + await this.completeAddressStep(data.vendorSetupWizard); + // await this.click(setupWizardVendor.skipTheStepStoreSetup); + await this.click(setupWizardVendor.skipTheStepPaymentSetup); } - await this.click(verificationsVendor.id.uploadPhoto); - await this.uploadMedia(verification.file); - - await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.id.submitId); - await this.toContainText(verificationsVendor.id.idUpdateSuccessMessage, verification.idRequestSubmitSuccessMessage); + await this.toContainText(verificationsVendor.verificationRequestNote(methodName), note); } - // vendor send address verification request - async sendAddressVerificationRequest(verification: vendor['verification']): Promise { - await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + // vendor view required verification request + async viewRequiredVerificationMethod(requiredMethod: string, nonRequiredMethod: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.setupWizard); + await this.click(setupWizardVendor.letsGo); + await this.completeAddressStep(data.vendorSetupWizard); + // await this.click(setupWizardVendor.skipTheStepStoreSetup); + await this.click(setupWizardVendor.skipTheStepPaymentSetup); - // cancel previous verification request if any - const cancelRequestIsVisible = await this.isVisible(verificationsVendor.address.cancelAddressVerificationRequest); - if (cancelRequestIsVisible) { - await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.address.cancelAddressVerificationRequest); - await this.toContainText(verificationsVendor.address.addressUpdateSuccessMessage, verification.addressRequestSubmitCancel); - } + await this.toBeVisible(verificationsVendor.verificationMethodDiv(requiredMethod)); + await this.notToBeVisible(verificationsVendor.verificationMethodDiv(nonRequiredMethod)); - // address verification - await this.click(verificationsVendor.address.startAddressVerification); - await this.clearAndType(verificationsVendor.address.street, verification.street1); - await this.clearAndType(verificationsVendor.address.street2, verification.street2); - await this.clearAndType(verificationsVendor.address.city, verification.city); - await this.clearAndType(verificationsVendor.address.postOrZipCode, verification.zipCode); - await this.selectByValue(verificationsVendor.address.country, verification.country); - await this.selectByValue(verificationsVendor.address.state, verification.state); - - // remove previously uploaded image - const uploadProofBtnIsVisible = await this.isVisible(verificationsVendor.address.uploadResidenceProof); - if (!uploadProofBtnIsVisible) { - await this.removeAttribute('div.proof-button-area', 'style'); - await this.setAttributeValue('div.vendor_img_container', 'style', 'display: none;'); - } - - await this.click(verificationsVendor.address.uploadResidenceProof); - await this.uploadMedia(verification.file); - - await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.address.submitAddress); - await this.toContainText(verificationsVendor.address.addressUpdateSuccessMessage, verification.addressRequestSubmitSuccessMessage); + const count = await this.getElementCount(verificationsVendor.verificationMethodAllDiv); + await this.toHaveCount(verificationsVendor.requiredText, count); } - // vendor send company verification request - async sendCompanyVerificationRequest(verification: vendor['verification']): Promise { - await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); - - // cancel previous verification request if any - const cancelRequestIsVisible = await this.isVisible(verificationsVendor.company.cancelCompanyVerificationRequest); - if (cancelRequestIsVisible) { - await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.company.cancelCompanyVerificationRequest); - await this.toContainText(verificationsVendor.company.companyInfoUpdateSuccessMessage, verification.companyRequestSubmitCancel); - } + async completeAddressStep(setupWizardData: vendorSetupWizard) { + await this.clearAndType(setupWizardVendor.street1, setupWizardData.street1); + await this.clearAndType(setupWizardVendor.street2, setupWizardData.street2); + await this.clearAndType(setupWizardVendor.city, setupWizardData.city); + await this.clearAndType(setupWizardVendor.zipCode, setupWizardData.zipCode); + await this.click(setupWizardVendor.country); + await this.type(setupWizardVendor.countryInput, setupWizardData.country); + await this.toContainText(setupWizardVendor.highlightedResult, setupWizardData.country); + await this.press(data.key.enter); + await this.click(setupWizardVendor.state); + await this.type(setupWizardVendor.stateInput, setupWizardData.state); + await this.click(setupWizardVendor.continueStoreSetup); + } - // company verification - await this.click(verificationsVendor.company.startCompanyVerification); - // await this.wait(1); // todo: need to resolve this - await this.waitForVisibleLocator(verificationsVendor.company.submitCompanyInfo); + // customer - // remove previously uploaded company file - const UploadedCompanyFileIsVisible = await this.isVisible(verificationsVendor.company.uploadedFileFirst); - if (UploadedCompanyFileIsVisible) { - await this.click(verificationsVendor.company.uploadedFileFirst); - } - - await this.click(verificationsVendor.company.uploadFiles); - await this.uploadMedia(verification.file); + async viewVerifiedBadge(storeName: string) { + // store listing page + await this.goIfNotThere(data.subUrls.frontend.storeListing); + await this.customerPage.searchStore(storeName); + await this.toBeVisible(singleStoreCustomer.storeProfile.verifiedIcon); - await this.clickAndWaitForResponse(data.subUrls.ajax, verificationsVendor.company.submitCompanyInfo); - await this.toContainText(verificationsVendor.company.companyInfoUpdateSuccessMessage, verification.companyRequestSubmitSuccessMessage); + // single store page + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.toBeVisible(singleStoreCustomer.storeProfile.verifiedIcon); } } diff --git a/tests/pw/pages/withdrawsPage.ts b/tests/pw/pages/withdrawsPage.ts index 6924889a4d..40ec2491eb 100644 --- a/tests/pw/pages/withdrawsPage.ts +++ b/tests/pw/pages/withdrawsPage.ts @@ -22,11 +22,12 @@ export class WithdrawsPage extends AdminPage { async adminWithdrawsRenderProperly(): Promise { await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); - // withdraw text is visible + // withdraw text is visible await this.toBeVisible(withdrawsAdmin.withdrawText); - // nav tabs elements are visible - await this.multipleElementVisible(withdrawsAdmin.navTabs); + // navTab elements are visible + const { tabByStatus, ...navTabs } = withdrawsAdmin.navTabs; + await this.multipleElementVisible(navTabs); // bulk action elements are visible await this.multipleElementVisible(withdrawsAdmin.bulkActions); @@ -41,11 +42,18 @@ export class WithdrawsPage extends AdminPage { // filter withdraws async filterWithdraws(input: string, action: string): Promise { - await this.goto(data.subUrls.backend.dokan.withdraw); - // await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); + await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); await this.click(withdrawsAdmin.filters.clearFilter); switch (action) { + case 'by-status': { + await this.clickAndWaitForLoadState(withdrawsAdmin.navTabs.tabByStatus(input)); + await this.wait(1); // todo: need to resolve this + const count = await this.getElementCount(withdrawsAdmin.statusColumnValue(input.toLowerCase())); + await this.toHaveCount(withdrawsAdmin.currentNoOfRows, count); + return; + } + case 'by-vendor': await this.click(withdrawsAdmin.filters.filterByVendor); break; @@ -80,7 +88,7 @@ export class WithdrawsPage extends AdminPage { await this.clickAndWaitForResponse(data.subUrls.api.dokan.withdraws, withdrawsAdmin.updateNote); } - // add note to withdraw request + // update withdraw request async updateWithdrawRequest(vendorName: string, action: string): Promise { await this.filterWithdraws(vendorName, 'by-vendor'); diff --git a/tests/pw/tests/api/vendorSubscription.spec.ts b/tests/pw/tests/api/vendorSubscription.spec.ts new file mode 100644 index 0000000000..1376df5d67 --- /dev/null +++ b/tests/pw/tests/api/vendorSubscription.spec.ts @@ -0,0 +1,58 @@ +//COVERAGE_TAG: GET /dokan/v1/subscription +//COVERAGE_TAG: GET /dokan/v1/subscription/packages +//COVERAGE_TAG: GET /dokan/v1/subscription/nonrecurring-packages +//COVERAGE_TAG: GET /dokan/v1/subscription/vendor/(?P[\d]+) // TODO: might need to update method +//COVERAGE_TAG: GET /dokan/v1/subscription/(?P[\d]+) // TODO: might need to update method +//COVERAGE_TAG: PUT /dokan/v1/subscription/batch + +import { test, expect, request } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { schemas } from '@utils/schemas'; + +test.describe('vendor subscription api test', () => { + test.skip(true, 'not implemented all tests yet'); + let apiUtils: ApiUtils; + + test.beforeAll(async () => { + apiUtils = new ApiUtils(await request.newContext()); + }); + + test.afterAll(async () => { + await apiUtils.dispose(); + }); + + test('get all vendor subscriptions', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllVendorSubscriptions); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.admin.reportOverviewSchema); + }); + + test('get all vendor-subscription packages', { tag: ['@pro'] }, async () => { + // todo: need a subscription pack + const [response, responseBody] = await apiUtils.get(endPoints.getAllVendorSubscriptionPackages); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.admin.reportSummarySchema); + }); + + test('get all vendor-subscription non-recucrring packages', { tag: ['@pro'] }, async () => { + // todo: need non-recucrring subscription pack + const [response, responseBody] = await apiUtils.get(endPoints.getAllVendorSubscriptionNonRecurringPackages); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.admin.adminDashboardFeedSchema); + }); + + test('get vendor active subscription pack', { tag: ['@pro'] }, async () => { + // todo: need vendor with subscription pack + const vendorId = '1'; + const [response, responseBody] = await apiUtils.get(endPoints.getVendorActiveSubscriptionPack(vendorId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.admin.adminHelpSchema); + }); + + // todo: has two more endpoints +}); diff --git a/tests/pw/tests/api/vendorVerification.spec.ts b/tests/pw/tests/api/vendorVerification.spec.ts new file mode 100644 index 0000000000..0cc84bdf7f --- /dev/null +++ b/tests/pw/tests/api/vendorVerification.spec.ts @@ -0,0 +1,112 @@ +//COVERAGE_TAG: GET /dokan/v1/verification-methods +//COVERAGE_TAG: GET /dokan/v1/verification-methods/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/verification-methods +//COVERAGE_TAG: PUT /dokan/v1/verification-methods/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/verification-methods/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v1/verification-requests +//COVERAGE_TAG: GET /dokan/v1/verification-requests/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/verification-requests +//COVERAGE_TAG: PUT /dokan/v1/verification-requests/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/verification-requests/(?P[\d]+) + +import { test, expect, request } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; +import { data } from '@utils/testData'; + +const { VENDOR_ID } = process.env; + +test.describe('vendor verification api test', () => { + let apiUtils: ApiUtils; + let methodId: string; + let requestId: string; + let mediaId: string; + + test.beforeAll(async () => { + apiUtils = new ApiUtils(await request.newContext()); + [, methodId] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod()); + [, mediaId] = await apiUtils.uploadMedia(data.image.avatar, payloads.mimeTypes.png, payloads.adminAuth); + [, requestId] = await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }); + }); + + test.afterAll(async () => { + // await apiUtils.deleteAllVerificationMethods(); + await apiUtils.dispose(); + }); + + // verification methods + + test('get all verification methods', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllVerificationMethods); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationMethodsSchema); + }); + + test('get single verification method', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleVerificationMethod(methodId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationMethodSchema); + }); + + test('create a verification method', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createVerificationMethod, { data: payloads.createVerificationMethod() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationMethodSchema); + }); + + test('update a verification method', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateVerificationMethod(methodId), { data: payloads.updateVerificationMethod() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationMethodSchema); + }); + + test('delete a verification method', { tag: ['@pro'] }, async () => { + const [, methodId] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod()); + const [response] = await apiUtils.delete(endPoints.deleteVerificationMethod(methodId)); + expect(response.ok()).toBeTruthy(); + }); + + // verification requests + + test('get all verification requests', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllVerificationRequests); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationRequestsSchema); + }); + + test('get single verification request', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleVerificationRequest(requestId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationRequestSchema); + }); + + test('create a verification request', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createVerificationRequest, { data: { ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationRequestSchema); + }); + + test('update a verification request', { tag: ['@pro'] }, async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateVerificationRequest(requestId), { + data: { ...payloads.updateVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }, + }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.vendorVerificationSchema.verificationRequestSchema); + }); + + test('delete a verification request', { tag: ['@pro'] }, async () => { + const [, requestId] = await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }); + const [response] = await apiUtils.delete(endPoints.deleteVerificationRequest(requestId)); + expect(response.ok()).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/e2e/_coverage.teardown.spec.ts b/tests/pw/tests/e2e/_coverage.teardown.spec.ts index 44bcc10f1c..3b18da3ea8 100644 --- a/tests/pw/tests/e2e/_coverage.teardown.spec.ts +++ b/tests/pw/tests/e2e/_coverage.teardown.spec.ts @@ -20,7 +20,7 @@ teardown.describe('get e2e test coverage', () => { const testReport = 'playwright-report/e2e/summary-report/results.json'; teardown('get coverage', { tag: ['@lite'] }, async () => { - executed_tests = (helpers.readJson(testReport))?.tests; + executed_tests = helpers.readJson(testReport)?.tests; getCoverage(feature_map, outputFile); }); }); diff --git a/tests/pw/tests/e2e/admin.spec.ts b/tests/pw/tests/e2e/admin.spec.ts index e5062e6ea5..3bb349c7a4 100644 --- a/tests/pw/tests/e2e/admin.spec.ts +++ b/tests/pw/tests/e2e/admin.spec.ts @@ -4,6 +4,8 @@ import { TaxPage } from '@pages/taxPage'; import { ShippingPage } from '@pages/shippingPage'; import { data } from '@utils/testData'; +const { DOKAN_PRO } = process.env; + test.describe('Admin functionality test', () => { let taxPage: TaxPage; let shippingPage: ShippingPage; @@ -26,6 +28,7 @@ test.describe('Admin functionality test', () => { }); test('admin can logout', { tag: ['@lite', '@admin'] }, async ({ page }) => { + test.skip(DOKAN_PRO, 'skip on pro'); //todo: need to fix const loginPage = new LoginPage(page); await loginPage.adminLogin(data.admin); await loginPage.logoutBackend(); diff --git a/tests/pw/tests/e2e/adminDashboard.spec.ts b/tests/pw/tests/e2e/dashboard.spec.ts similarity index 68% rename from tests/pw/tests/e2e/adminDashboard.spec.ts rename to tests/pw/tests/e2e/dashboard.spec.ts index 575829beef..2760fc1c29 100644 --- a/tests/pw/tests/e2e/adminDashboard.spec.ts +++ b/tests/pw/tests/e2e/dashboard.spec.ts @@ -1,26 +1,36 @@ import { test, request, Page } from '@playwright/test'; import { AdminDashboardPage } from '@pages/adminDashboardPage'; +import { VendorDashboardPage } from '@pages/vendorDashboardPage'; import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -test.describe('Admin dashboard test', () => { +test.describe('Dashboard test', () => { let admin: AdminDashboardPage; - let aPage: Page; + let vendor: VendorDashboardPage; + let aPage: Page, vPage: Page; let apiUtils: ApiUtils; test.beforeAll(async ({ browser }) => { const adminContext = await browser.newContext(data.auth.adminAuth); aPage = await adminContext.newPage(); admin = new AdminDashboardPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorDashboardPage(vPage); + apiUtils = new ApiUtils(await request.newContext()); }); test.afterAll(async () => { await aPage.close(); + await vPage.close(); await apiUtils.dispose(); }); + // admin + test('admin can view Dokan dashboard', { tag: ['@lite', '@exploratory', '@admin'] }, async () => { await admin.adminDashboardRenderProperly(); }); @@ -33,4 +43,10 @@ test.describe('Admin dashboard test', () => { test('admin can add Dokan news subscriber', { tag: ['@lite', '@admin'] }, async () => { await admin.addDokanNewsSubscriber(data.user.userDetails); }); + + //vendor + + test('vendor can view vendor dashboard', { tag: ['@lite', '@exploratory', '@vendor'] }, async () => { + await vendor.vendorDashboardRenderProperly(); + }); }); diff --git a/tests/pw/tests/e2e/privacyPolicy.spec.ts b/tests/pw/tests/e2e/privacyPolicy.spec.ts index ad180a36e8..173829883a 100644 --- a/tests/pw/tests/e2e/privacyPolicy.spec.ts +++ b/tests/pw/tests/e2e/privacyPolicy.spec.ts @@ -38,7 +38,8 @@ test.describe.skip('Privacy Policy & Store Contact form test', () => { await customer.goToPrivacyPolicy(data.predefined.vendorStores.vendor1); }); - test('admin can disable privacy policy on store contact form', { tag: ['@lite', '@customer'] }, async () => { //todo: mighit need to update title form customer perspective + test('admin can disable privacy policy on store contact form', { tag: ['@lite', '@customer'] }, async () => { + //todo: mighit need to update title form customer perspective await dbUtils.setDokanSettings(dbData.dokan.optionName.privacyPolicy, { ...privacyPolicySettings, enable_privacy: 'off' }); await customer.disablePrivacyPolicy(data.predefined.vendorStores.vendor1); }); diff --git a/tests/pw/tests/e2e/refunds.spec.ts b/tests/pw/tests/e2e/refunds.spec.ts index 8d8876b08d..ab791a2eb8 100644 --- a/tests/pw/tests/e2e/refunds.spec.ts +++ b/tests/pw/tests/e2e/refunds.spec.ts @@ -58,7 +58,7 @@ test.describe('Refunds test', () => { await admin.updateRefundRequests(orderId, 'cancel'); }); - test.skip('admin can perform refund requests bulk actions', { tag: ['@pro', '@admin'] }, async () => { + test.skip('admin can perform bulk action on refund requests', { tag: ['@pro', '@admin'] }, async () => { const [, orderResponseBody, ,] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrder, data.order.orderStatus.processing, payloads.vendorAuth); await dbUtils.createRefundRequest(orderResponseBody); await admin.refundRequestsBulkAction('completed'); diff --git a/tests/pw/tests/e2e/reports.spec.ts b/tests/pw/tests/e2e/reports.spec.ts index ad9c85638c..fd3de427f6 100644 --- a/tests/pw/tests/e2e/reports.spec.ts +++ b/tests/pw/tests/e2e/reports.spec.ts @@ -1,5 +1,6 @@ import { test, request, Page } from '@playwright/test'; import { ReportsPage } from '@pages/reportsPage'; +import { VendorReportsPage } from '@pages/vendorReportsPage'; import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; @@ -8,7 +9,8 @@ const { PRODUCT_ID } = process.env; test.describe('Reports test', () => { let admin: ReportsPage; - let aPage: Page; + let vendor: VendorReportsPage; + let aPage: Page, vPage: Page; let apiUtils: ApiUtils; let orderId: string; @@ -17,12 +19,17 @@ test.describe('Reports test', () => { aPage = await adminContext.newPage(); admin = new ReportsPage(aPage); + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorReportsPage(vPage); + apiUtils = new ApiUtils(await request.newContext()); [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrder, data.order.orderStatus.completed, payloads.vendorAuth); }); test.afterAll(async () => { await aPage.close(); + await vPage.close(); await apiUtils.dispose(); }); @@ -53,4 +60,14 @@ test.describe('Reports test', () => { test('admin can filter all logs by order status', { tag: ['@pro', '@admin'] }, async () => { await admin.filterAllLogsByStatus('completed'); }); + + //vendor + + test('vendor can view reports menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => { + await vendor.vendorReportsRenderProperly(); + }); + + test('vendor can export statement', { tag: ['@pro', '@vendor'] }, async () => { + await vendor.exportStatement(); + }); }); diff --git a/tests/pw/tests/e2e/requestForQuoteRules.spec.ts b/tests/pw/tests/e2e/requestForQuoteRules.spec.ts index 4263aaf9b4..351f5d9267 100644 --- a/tests/pw/tests/e2e/requestForQuoteRules.spec.ts +++ b/tests/pw/tests/e2e/requestForQuoteRules.spec.ts @@ -57,7 +57,7 @@ test.describe('Request for quotation Rules test', () => { await admin.updateQuoteRule(quoteRuleTitle, 'permanently-delete'); }); - test.skip('admin can perform quote rule bulk actions', { tag: ['@pro', '@admin'] }, async () => { + test.skip('admin can perform bulk action on quote rules', { tag: ['@pro', '@admin'] }, async () => { // todo: might cause other tests to fail in parallel await admin.quoteRulesBulkAction('trash'); }); diff --git a/tests/pw/tests/e2e/reverseWithdraws.spec.ts b/tests/pw/tests/e2e/reverseWithdraws.spec.ts index 74d2b86591..ae70f13958 100644 --- a/tests/pw/tests/e2e/reverseWithdraws.spec.ts +++ b/tests/pw/tests/e2e/reverseWithdraws.spec.ts @@ -43,11 +43,11 @@ test.describe('Reverse withdraw test', () => { await admin.adminReverseWithdrawRenderProperly(); }); - test.skip('admin can filter reverse withdraws by store', { tag: ['@lite', '@admin'] }, async () => { + test.skip('admin can filter reverse withdrawal by store', { tag: ['@lite', '@admin'] }, async () => { await admin.filterReverseWithdraws(data.predefined.vendorStores.vendor2); }); - test('admin can crete reverse withdraws', { tag: ['@lite', '@admin'] }, async () => { + test('admin can add reverse withdrawal', { tag: ['@lite', '@admin'] }, async () => { await admin.addReverseWithdrawal({ ...data.reverseWithdraw, store: data.predefined.vendorStores.vendor2, product: productName }); }); diff --git a/tests/pw/tests/e2e/settings.spec.ts b/tests/pw/tests/e2e/settings.spec.ts index 7c47b68ecf..7c00a4edc7 100644 --- a/tests/pw/tests/e2e/settings.spec.ts +++ b/tests/pw/tests/e2e/settings.spec.ts @@ -73,6 +73,10 @@ test.describe('Settings test', () => { await admin.setDokanStoreSupportSettings(data.dokanSettings.storeSupport); }); + test('admin can set Dokan vendor verification settings', { tag: ['@pro', '@admin'] }, async () => { + await admin.setDokanVendorVerificationSettings(data.dokanSettings.vendorVerification); //todo: need to resolve + }); + test('admin can set Dokan email verification settings', { tag: ['@pro', '@admin'] }, async () => { await admin.setDokanEmailVerificationSettings(data.dokanSettings.emailVerification); // reset settings diff --git a/tests/pw/tests/e2e/stores.spec.ts b/tests/pw/tests/e2e/stores.spec.ts index ac007925dd..70c6b13ca2 100644 --- a/tests/pw/tests/e2e/stores.spec.ts +++ b/tests/pw/tests/e2e/stores.spec.ts @@ -47,6 +47,7 @@ test.describe('Stores test', () => { }); test("admin can disable vendor's selling capability", { tag: ['@lite', '@admin'] }, async () => { + //todo: might need to combine with enable const [, , storeName] = await apiUtils.createStore(payloads.createStore(), payloads.adminAuth); await admin.updateVendor(storeName, 'disable'); }); @@ -68,7 +69,7 @@ test.describe('Stores test', () => { await admin.viewVendor(data.predefined.vendorStores.vendor1, 'orders'); }); - test('admin can perform vendor bulk actions', { tag: ['@lite', '@admin'] }, async () => { + test('admin can perform bulk action on vendors', { tag: ['@lite', '@admin'] }, async () => { await admin.vendorBulkAction('approved'); }); }); diff --git a/tests/pw/tests/e2e/vendorDashboard.spec.ts b/tests/pw/tests/e2e/vendorDashboard.spec.ts deleted file mode 100644 index 550bd608ae..0000000000 --- a/tests/pw/tests/e2e/vendorDashboard.spec.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { test, Page } from '@playwright/test'; -import { VendorDashboardPage } from '@pages/vendorDashboardPage'; -import { data } from '@utils/testData'; - -test.describe('Vendor dashboard test', () => { - let vendor: VendorDashboardPage; - let vPage: Page; - - test.beforeAll(async ({ browser }) => { - const vendorContext = await browser.newContext(data.auth.vendorAuth); - vPage = await vendorContext.newPage(); - vendor = new VendorDashboardPage(vPage); - }); - - test.afterAll(async () => { - await vPage.close(); - }); - - test('vendor can view vendor dashboard', { tag: ['@lite', '@exploratory', '@vendor'] }, async () => { - await vendor.vendorDashboardRenderProperly(); - }); -}); diff --git a/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts b/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts index f857d37972..6039183134 100644 --- a/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts +++ b/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts @@ -42,7 +42,7 @@ test.describe('Vendor delivery time test', () => { await vendor.filterDeliveryTime('delivery'); }); - test('vendor can change view style of delivery time calender', { tag: ['@pro', '@vendor'] }, async () => { + test('vendor can change view style of delivery time calendar', { tag: ['@pro', '@vendor'] }, async () => { await vendor.updateCalendarView('week'); }); diff --git a/tests/pw/tests/e2e/vendorReports.spec.ts b/tests/pw/tests/e2e/vendorReports.spec.ts deleted file mode 100644 index c4d2059fe5..0000000000 --- a/tests/pw/tests/e2e/vendorReports.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { test, Page } from '@playwright/test'; -import { VendorReportsPage } from '@pages/vendorReportsPage'; -import { data } from '@utils/testData'; - -test.describe('Vendor reports test', () => { - let vendor: VendorReportsPage; - let vPage: Page; - - test.beforeAll(async ({ browser }) => { - const vendorContext = await browser.newContext(data.auth.vendorAuth); - vPage = await vendorContext.newPage(); - vendor = new VendorReportsPage(vPage); - }); - - test.afterAll(async () => { - await vPage.close(); - }); - - //vendor - - test('vendor can view reports menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => { - await vendor.vendorReportsRenderProperly(); - }); - - test('vendor can export statement', { tag: ['@pro', '@vendor'] }, async () => { - await vendor.exportStatement(); - }); -}); diff --git a/tests/pw/tests/e2e/vendorVerifications.spec.ts b/tests/pw/tests/e2e/vendorVerifications.spec.ts index 2ebe99aa19..a77cd93e01 100644 --- a/tests/pw/tests/e2e/vendorVerifications.spec.ts +++ b/tests/pw/tests/e2e/vendorVerifications.spec.ts @@ -1,76 +1,214 @@ -import { test, Page } from '@playwright/test'; -import { vendorVerificationsPage } from '@pages/vendorVerificationsPage'; +import { test, request, Page } from '@playwright/test'; +import { VendorVerificationsPage } from '@pages/vendorVerificationsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { payloads } from '@utils/payloads'; import { data } from '@utils/testData'; +const { VENDOR_ID, VENDOR2_ID } = process.env; + test.describe('Verifications test', () => { - let admin: vendorVerificationsPage; - let vendor: vendorVerificationsPage; - let aPage: Page, vPage: Page; + let admin: VendorVerificationsPage; + let vendor: VendorVerificationsPage; + let customer: VendorVerificationsPage; + let aPage: Page, vPage: Page, cPage: Page; + let apiUtils: ApiUtils; + let methodId: string; + let methodName: string; + let requestId: string; + let mediaId: string; test.beforeAll(async ({ browser }) => { const adminContext = await browser.newContext(data.auth.adminAuth); aPage = await adminContext.newPage(); - admin = new vendorVerificationsPage(aPage); + admin = new VendorVerificationsPage(aPage); const vendorContext = await browser.newContext(data.auth.vendorAuth); vPage = await vendorContext.newPage(); - vendor = new vendorVerificationsPage(vPage); + vendor = new VendorVerificationsPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new VendorVerificationsPage(cPage); + + apiUtils = new ApiUtils(await request.newContext()); + [, methodId, methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + [, mediaId] = await apiUtils.uploadMedia(data.image.avatar, payloads.mimeTypes.png, payloads.adminAuth); + [, requestId] = await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }, payloads.adminAuth); }); test.afterAll(async () => { + // await apiUtils.deleteAllVerificationMethods(payloads.adminAuth); + // await apiUtils.deleteAllVerificationRequests(payloads.adminAuth); await aPage.close(); await vPage.close(); + await cPage.close(); }); - // vendor + //admin - test('vendor can view verifications settings menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => { - await vendor.vendorVerificationsSettingsRenderProperly(); + // verification methods + + test('admin can change verified icon', { tag: ['@pro', '@admin'] }, async () => { + await dbUtils.createUserMeta(VENDOR2_ID, 'dokan_verification_status', 'approved'); + await admin.changeVerifiedIcon(data.dokanSettings.vendorVerification.verifiedIcons.byIcon.certificateSolid, data.predefined.vendorStores.vendor2); }); - test('vendor can send id verification request', { tag: ['@pro', '@vendor'] }, async () => { - await vendor.sendIdVerificationRequest(data.vendor.verification); + test('admin can add vendor verification method', { tag: ['@pro', '@admin'] }, async () => { + await admin.addVendoVerificationMethod(data.dokanSettings.vendorVerification.customMethod); }); - test('vendor can send address verification request', { tag: ['@pro', '@vendor'] }, async () => { - await vendor.sendAddressVerificationRequest(data.vendor.verification); + test('admin can edit vendor verification method', { tag: ['@pro', '@admin'] }, async () => { + const [, , methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await admin.editVendoVerificationMethod(methodName, data.dokanSettings.vendorVerification.updateMethod); }); - test('vendor can send company verification request', { tag: ['@pro', '@vendor'] }, async () => { - await vendor.sendCompanyVerificationRequest(data.vendor.verification); + test('admin can delete vendor verification method', { tag: ['@pro', '@admin'] }, async () => { + const [, , methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await admin.deleteVendoVerificationMethod(methodName); }); - // todo: remove dependency: admin tests depends on vendor tests + test('admin can update verificaiton method status', { tag: ['@pro', '@admin'] }, async () => { + const [, , methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await admin.updateVerificationMethodStatus(methodName, 'disable'); + }); - //admin + // verification requests test('admin can view verifications menu page', { tag: ['@pro', '@exploratory', '@admin'] }, async () => { await admin.adminVerificationsRenderProperly(); }); - // test('admin can approve ID verification request', { tag: ['@pro', '@admin'] }, async ( ) => { - // await admin.approveVerificationRequest(data.predefined.vendorInfo.username, 'id', 'approve'); - // }); + test('admin can filter verification requests by pending status', { tag: ['@pro', '@admin'] }, async () => { + await admin.filterVerificationRequests('Pending', 'by-status'); + }); + + test('admin can filter verification requests by approved status', { tag: ['@pro', '@admin'] }, async () => { + const [, methodId] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId], status: 'approved' }, payloads.adminAuth); + await admin.filterVerificationRequests('Approved', 'by-status'); + }); + + test('admin can filter verification requests by rejected status', { tag: ['@pro', '@admin'] }, async () => { + const [, methodId] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId], status: 'rejected' }, payloads.adminAuth); + await admin.filterVerificationRequests('Rejected', 'by-status'); + }); + + test('admin can filter verification requests by cancelled status', { tag: ['@pro', '@admin'] }, async () => { + const [, methodId] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId], status: 'cancelled' }, payloads.adminAuth); + await admin.filterVerificationRequests('Cancelled', 'by-status'); + }); + + test('admin can filter verification requests by vendor', { tag: ['@pro', '@admin'] }, async () => { + await admin.filterVerificationRequests(data.predefined.vendorStores.vendor1, 'by-vendor'); + }); + + test('admin can filter verification requests by verification methods', { tag: ['@pro', '@admin'] }, async () => { + await admin.filterVerificationRequests(methodName, 'by-verification-method'); + }); + + test('admin can reset filter', { tag: ['@pro', '@admin'] }, async () => { + await admin.filterVerificationRequests(data.predefined.vendorStores.vendor1, 'by-vendor'); + await admin.resetFilter(); + }); + + test('admin can add note to verification request', { tag: ['@pro', '@admin'] }, async () => { + await admin.addNoteVerificationRequest(requestId, 'test verification note'); + }); + + test('admin can view verification request documents', { tag: ['@pro', '@admin'] }, async () => { + await admin.viewVerificationRequestDocument(requestId); + }); + + test('admin can approve verification request', { tag: ['@pro', '@admin'] }, async () => { + const [, requestId] = await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }, payloads.adminAuth); + await admin.updateVerificationRequest(requestId, 'approve'); + }); + + test('admin can reject verification request', { tag: ['@pro', '@admin'] }, async () => { + const [, requestId] = await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }, payloads.adminAuth); + //todo: need to force goto or reload page, page is not reloading because of previous test are on the same page, and created data via api is not loading + await admin.updateVerificationRequest(requestId, 'reject'); + }); + + test('admin can perform bulk action on verification requests', { tag: ['@pro', '@admin'] }, async () => { + await admin.verificationRequestBulkAction('approved'); + }); + + // vendor + + test('vendor can view verifications settings menu page', { tag: ['@pro', '@exploratory', '@vendor'] }, async () => { + const [, , methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await vendor.vendorVerificationsSettingsRenderProperly(methodName); + }); + + test('vendor can submit verification request', { tag: ['@pro', '@vendor'] }, async () => { + const [, , methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await vendor.submitVerificationRequest({ ...data.vendor.verification, method: methodName }); + }); + + test('vendor can re-submit verification request', { tag: ['@pro', '@vendor'] }, async () => { + const [, methodId, methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId], status: 'rejected' }, payloads.adminAuth); + await vendor.submitVerificationRequest({ ...data.vendor.verification, method: methodName }); + }); + + test('vendor can cancel verification request', { tag: ['@pro', '@vendor'] }, async () => { + const [, methodId, methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }, payloads.adminAuth); + await vendor.cancelVerificationRequest(methodName); + }); + + test('vendor can view verification request documents', { tag: ['@pro', '@vendor'] }, async () => { + await vendor.vendorViewVerificationRequestDocument(methodName); + }); + + test('vendor can view verification request notes', { tag: ['@pro', '@vendor'] }, async () => { + const note = 'test verification note'; + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId], note: note }, payloads.adminAuth); + await vendor.viewVerificationRequestNote(methodName, note); + }); + + test('vendor can view only required verificaiton method on setup wizard', { tag: ['@pro', '@vendor'] }, async () => { + const [, , nonRequiredMethodName] = await apiUtils.createVerificationMethod({ ...payloads.createVerificationMethod(), required: false }, payloads.adminAuth); + await vendor.viewRequiredVerificationMethod(methodName, nonRequiredMethodName); + }); - // test('admin can approve address verification request', { tag: ['@pro', '@admin'] }, async ( ) => { - // await admin.approveVerificationRequest(data.predefined.vendorInfo.username, 'address', 'approve'); - // }); + test('vendor can submit verification request on setup wizard', { tag: ['@pro', '@vendor'] }, async () => { + const [, , methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await vendor.submitVerificationRequest({ ...data.vendor.verification, method: methodName }, true); + }); - // test('admin can approve company verification request', { tag: ['@pro', '@admin'] }, async ( ) => { - // await admin.approveVerificationRequest(data.predefined.vendorInfo.username, 'company', 'approve'); - // }); + test('vendor can re-submit verification request on setup wizard', { tag: ['@pro', '@vendor'] }, async () => { + const [, methodId, methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId], status: 'rejected' }, payloads.adminAuth); + await vendor.submitVerificationRequest({ ...data.vendor.verification, method: methodName }, true); + }); - // todo: admin can reject requests + test('vendor can cancel verification request on setup wizard', { tag: ['@pro', '@vendor'] }, async () => { + const [, methodId, methodName] = await apiUtils.createVerificationMethod(payloads.createVerificationMethod(), payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId] }, payloads.adminAuth); + await vendor.cancelVerificationRequest(methodName, true); + }); - // test('admin can disapprove approved ID verification request', { tag: ['@pro', '@admin'] }, async ( ) => { - // await admin.disapproveVerificationRequest(data.predefined.vendorInfo.username, 'id'); - // }); + test('vendor can view verification request documents on setup wizard', { tag: ['@pro', '@vendor'] }, async () => { + await vendor.vendorViewVerificationRequestDocument(methodName, true); + }); - // test('admin can disapprove approved address verification request', { tag: ['@pro', '@admin'] }, async ( ) => { - // await admin.disapproveVerificationRequest(data.predefined.vendorInfo.username, 'address'); - // }); + // customer - // test('admin can disapprove approved company verification request', { tag: ['@pro', '@admin'] }, async ( ) => { - // await admin.disapproveVerificationRequest(data.predefined.vendorInfo.username, 'company'); - // }); + test('customer can view verified badge', { tag: ['@pro', '@customer'] }, async () => { + await dbUtils.createUserMeta(VENDOR2_ID, 'dokan_verification_status', 'approved'); + await customer.viewVerifiedBadge(data.predefined.vendorStores.vendor2); + }); + + test.skip('admin receive notification for verification request', { tag: ['@pro', '@admin'] }, async () => {}); + test.skip('vendor need all required method to be verified to get verification badge', { tag: ['@pro', '@vendor'] }, async () => {}); + test.skip('vendor need to be verified only one method when no required method is exists', { tag: ['@pro', '@vendor'] }, async () => {}); + test.skip('vendor address verification gets reset when he update address', { tag: ['@pro', '@vendor'] }, async () => { + const [, methodId] = await apiUtils.getVerificationMethodId('address', payloads.adminAuth); + await apiUtils.createVerificationRequest({ ...payloads.createVerificationRequest(), vendor_id: VENDOR_ID, method_id: methodId, documents: [mediaId], status: 'approved' }, payloads.adminAuth); + }); }); diff --git a/tests/pw/tests/e2e/withdraws.spec.ts b/tests/pw/tests/e2e/withdraws.spec.ts index cef82c999e..9434059b7b 100644 --- a/tests/pw/tests/e2e/withdraws.spec.ts +++ b/tests/pw/tests/e2e/withdraws.spec.ts @@ -25,7 +25,7 @@ test.describe('Withdraw test', () => { apiUtils = new ApiUtils(await request.newContext()); [currentBalance, minimumWithdrawLimit] = await apiUtils.getMinimumWithdrawLimit(payloads.vendorAuth); - await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, line_items: [{ quantity: 10 }] }, 'wc-completed', payloads.vendorAuth); + await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, line_items: [{ quantity: 100 }] }, 'wc-completed', payloads.vendorAuth); await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }, payloads.vendorAuth); }); @@ -39,6 +39,22 @@ test.describe('Withdraw test', () => { await admin.adminWithdrawsRenderProperly(); }); + test('admin can filter withdrawal requests by pending status', { tag: ['@lite', '@admin'] }, async () => { + await admin.filterWithdraws('Pending', 'by-status'); + }); + + test.skip('admin can filter withdrawal requests by approved status', { tag: ['@lite', '@admin'] }, async () => { + // todo: create an approved withdraw + // await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit, user_id: VENDOR_ID, status: 'approved' }, payloads.adminAuth); + await admin.filterWithdraws('Approved', 'by-status'); + }); + + test.skip('admin can filter withdrawal requests by cancelled status', { tag: ['@lite', '@admin'] }, async () => { + // todo: create a cancelled withdraw + // await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit, user_id: VENDOR_ID, status: 'cancelled' }, payloads.adminAuth); + await admin.filterWithdraws('Cancelled', 'by-status'); + }); + test('admin can filter withdrawal requests by vendor', { tag: ['@lite', '@admin'] }, async () => { await admin.filterWithdraws(data.predefined.vendorStores.vendor1, 'by-vendor'); }); diff --git a/tests/pw/types/environment.d.ts b/tests/pw/types/environment.d.ts index 8cbc4a2d19..8cd9802d8e 100644 --- a/tests/pw/types/environment.d.ts +++ b/tests/pw/types/environment.d.ts @@ -21,7 +21,7 @@ declare global { GMAP: string; MAPBOX: string; LICENSE_KEY: string; - DOKAN_PRO: string; + DOKAN_PRO: boolean; SITE_PATH: string; BASE_URL: string; QUERY: string; @@ -44,6 +44,7 @@ declare global { API_TEST_RESULT: string; E2E_TEST_RESULT: string; API_COVERAGE: string; + E2E_COVERAGE: string; } } } diff --git a/tests/pw/utils/apiEndPoints.ts b/tests/pw/utils/apiEndPoints.ts index 15e6c8d1ea..ed57651180 100644 --- a/tests/pw/utils/apiEndPoints.ts +++ b/tests/pw/utils/apiEndPoints.ts @@ -282,6 +282,14 @@ export const endPoints = { getVendorStaffCapabilities: (staffId: string) => `${SERVER_URL}/dokan/v1/vendor-staff/${staffId}/capabilities`, updateVendorStaffCapabilities: (staffId: string) => `${SERVER_URL}/dokan/v1/vendor-staff/${staffId}/capabilities`, + // vendor subscriptions + getAllVendorSubscriptions: `${SERVER_URL}/dokan/v1/subscription`, + getAllVendorSubscriptionPackages: `${SERVER_URL}/dokan/v1/subscription/packages`, + getAllVendorSubscriptionNonRecurringPackages: `${SERVER_URL}/dokan/v1/subscription/nonrecurring-packages`, + getVendorActiveSubscriptionPack: (vendorId: string) => `${SERVER_URL}/dokan/v1/subscription/vendor/${vendorId}`, + updateVendorSubscription: (packId: string) => `${SERVER_URL}/wp-json/dokan/v1/subscription/${packId}`, + updateBatchVendorSubscriptions: `${SERVER_URL}/dokan/v1/subscription/batch`, // method: delete, read, unread + // v2 // rank math @@ -340,6 +348,19 @@ export const endPoints = { updateProductQuestionAnswer: (answerId: string) => `${SERVER_URL}/dokan/v1/product-answers/${answerId}`, deleteProductQuestionAnswer: (answerId: string) => `${SERVER_URL}/dokan/v1/product-answers/${answerId}`, + // vendor verification + getAllVerificationMethods: `${SERVER_URL}/dokan/v1/verification-methods`, + getSingleVerificationMethod: (methodId: string) => `${SERVER_URL}/dokan/v1/verification-methods/${methodId}`, + createVerificationMethod: `${SERVER_URL}/dokan/v1/verification-methods`, + updateVerificationMethod: (methodId: string) => `${SERVER_URL}/dokan/v1/verification-methods/${methodId}`, + deleteVerificationMethod: (methodId: string) => `${SERVER_URL}/dokan/v1/verification-methods/${methodId}`, + + getAllVerificationRequests: `${SERVER_URL}/dokan/v1/verification-requests`, + getSingleVerificationRequest: (requestId: string) => `${SERVER_URL}/dokan/v1/verification-requests/${requestId}`, + createVerificationRequest: `${SERVER_URL}/dokan/v1/verification-requests`, + updateVerificationRequest: (requestId: string) => `${SERVER_URL}/dokan/v1/verification-requests/${requestId}`, + deleteVerificationRequest: (requestId: string) => `${SERVER_URL}/dokan/v1/verification-requests/${requestId}`, + wc: { // coupons getAllCoupons: `${SERVER_URL}/wc/v3/coupons`, diff --git a/tests/pw/utils/apiUtils.ts b/tests/pw/utils/apiUtils.ts index 5f49ef5f4a..0a73de73cf 100644 --- a/tests/pw/utils/apiUtils.ts +++ b/tests/pw/utils/apiUtils.ts @@ -534,6 +534,12 @@ export class ApiUtils { return [responseBody, withdrawId]; } + // update withdraw + async updateWithdraw(withdrawId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.updateWithdraw(withdrawId), { data: payload, headers: auth }); + return responseBody; + } + // cancel withdraw async cancelWithdraw(withdrawId: string, auth?: auth): Promise { if (!withdrawId) { @@ -1254,7 +1260,7 @@ export class ApiUtils { } /** - * product questions answers + * product questions answers methods */ // get all product questions @@ -1296,6 +1302,86 @@ export class ApiUtils { return [responseBody, answerId]; } + /** + * vendor verification methods + */ + + // get verification methodId + async getVerificationMethodId(methodName: string, auth?: auth): Promise { + const allVerificationMethods = await this.getAllVerificationMethods(auth); + const methodId = allVerificationMethods.find((o: { title: string }) => o.title.toLowerCase() === methodName.toLowerCase())?.id; + return methodId; + } + + // get all verification methods + async getAllVerificationMethods(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllVerificationMethods, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // create verification method + async createVerificationMethod(payload: object, auth?: auth): Promise<[responseBody, string, string]> { + const [, responseBody] = await this.post(endPoints.createVerificationMethod, { data: payload, headers: auth }); + const methodId = String(responseBody?.id); + const methodTitle = String(responseBody?.title); + return [responseBody, methodId, methodTitle]; + } + + // get all verification requests + async getAllVerificationRequests(params = {}, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllVerificationRequests, { params: { ...params, per_page: 100 }, headers: auth }); + return responseBody; + } + + // create verification request + async createVerificationRequest(payload: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.createVerificationRequest, { data: payload, headers: auth }); + const requestId = String(responseBody?.id); + return [responseBody, requestId]; + } + + // update verification request + async updateVerificationRequest(requestId: string, payload: object, auth?: auth): Promise<[responseBody]> { + const [, responseBody] = await this.put(endPoints.updateVerificationRequest(requestId), { data: payload, headers: auth }); + return responseBody; + } + + // delete all verification methods + async deleteAllVerificationMethods(auth?: auth) { + const allVerificationMethods = await this.getAllVerificationMethods(auth); + if (!allVerificationMethods?.length) { + console.log('No verification method exists'); + return; + } + const allmethodIds = allVerificationMethods.map((o: { id: unknown }) => o.id); + for (const methodId of allmethodIds) { + await this.delete(endPoints.deleteVerificationMethod(methodId), { headers: auth }); + } + } + + // delete all verification methods + async deleteAllVerificationRequests(params = {}, auth?: auth) { + const allVerificationRequests = await this.getAllVerificationRequests(params, auth); + if (!allVerificationRequests?.length) { + console.log('No verification requests exists'); + return; + } + const allRequestIds = allVerificationRequests.map((o: { id: unknown }) => o.id); + for (const requestId of allRequestIds) { + await this.delete(endPoints.deleteVerificationRequest(requestId), { headers: auth }); + } + } + + /** + * vendor subscription methods + */ + + // get all vendor subscriptions + async getAllVendorSubscriptions(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllVendorSubscriptions, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + /** * wp api methods */ diff --git a/tests/pw/utils/dbUtils.ts b/tests/pw/utils/dbUtils.ts index 6c1271eba4..5a7100ed7f 100644 --- a/tests/pw/utils/dbUtils.ts +++ b/tests/pw/utils/dbUtils.ts @@ -44,9 +44,20 @@ export const dbUtils = { // update option table async updateWpOptionTable(optionName: string, optionValue: object | string, serializeData?: string): Promise { - const queryUpdate = serializeData - ? `UPDATE ${dbPrefix}_options SET option_value = '${serialize(optionValue)}' WHERE option_name = '${optionName}';` - : `UPDATE ${dbPrefix}_options SET option_value = '${optionValue}' WHERE option_name = '${optionName}';`; + optionValue = serializeData ? serialize(optionValue) : optionValue; + const queryUpdate = `UPDATE ${dbPrefix}_options SET option_value = '${optionValue}' WHERE option_name = '${optionName}';`; + const res = await dbUtils.dbQuery(queryUpdate); + // console.log(res); + return res; + }, + + // create user meta + async createUserMeta(userId: string, metaKey: string, metaValue: object | string, serializeData?: string): Promise { + metaValue = serializeData ? serialize(metaValue) : metaValue; + const metaExists = await dbUtils.dbQuery(`SELECT EXISTS (SELECT 1 FROM ${dbPrefix}_usermeta WHERE user_id = '${userId}' AND meta_key = '${metaKey}') AS row_exists;`); + const queryUpdate = metaExists[0].row_exists + ? `UPDATE ${dbPrefix}_usermeta SET meta_value = '${metaValue}' WHERE user_id = '${userId}' AND meta_key = '${metaKey}';` + : `INSERT INTO ${dbPrefix}_usermeta VALUES ( NULL, '${userId}', '${metaKey}', '${metaValue}');`; const res = await dbUtils.dbQuery(queryUpdate); // console.log(res); return res; diff --git a/tests/pw/utils/interfaces.ts b/tests/pw/utils/interfaces.ts index 475291b96a..11f5f99f6f 100644 --- a/tests/pw/utils/interfaces.ts +++ b/tests/pw/utils/interfaces.ts @@ -644,6 +644,7 @@ export interface vendorSetupWizard { bankSwiftCode: string; customPayment: string; skrill: string; + file: string; } // user @@ -947,19 +948,8 @@ export interface vendor { }; verification: { + method: string; file: string; - street1: string; - street2: string; - city: string; - zipCode: string; - country: string; - state: string; - idRequestSubmitSuccessMessage: string; - idRequestSubmitCancel: string; - addressRequestSubmitSuccessMessage: string; - addressRequestSubmitCancel: string; - companyRequestSubmitSuccessMessage: string; - companyRequestSubmitCancel: string; }; deliveryTime: { @@ -1566,6 +1556,44 @@ export interface dokanSettings { saveSuccessMessage: string; }; + // Vendor Verification + vendorVerification: { + verifiedIcons: { + circleSolid: string; + circleRegular: string; + solid: string; + doubleSolid: string; + squireRegular: string; + userCheckSolid: string; + certificateSolid: string; + + byIcon: { + circleSolid: string; + circleRegular: string; + solid: string; + doubleSolid: string; + squireRegular: string; + userCheckSolid: string; + certificateSolid: string; + }; + }; + + verificationMethods: { + nationalId: string; + drivingLicense: string; + address: string; + company: string; + }; + + verificationMethodDetails: { + title: string; + help_text: string; + required: boolean; + }; + + saveSuccessMessage: string; + }; + // Email verification emailVerification: { registrationNotice: string; diff --git a/tests/pw/utils/payloads.ts b/tests/pw/utils/payloads.ts index 726101ddc1..54b66e9656 100644 --- a/tests/pw/utils/payloads.ts +++ b/tests/pw/utils/payloads.ts @@ -3255,6 +3255,40 @@ export const payloads = { answer: 'test answer updated_' + faker.string.nanoid(10), }), + // vendor verification + + createVerificationMethod: () => ({ + title: 'test verification method_' + faker.string.nanoid(10), + help_text: 'test help-text', + status: true, + required: true, + kind: 'custom', // custom, address + }), + + updateVerificationMethod: () => ({ + title: 'test verification method updated_' + faker.string.nanoid(10), + help_text: 'test help-text updated', + status: false, + required: false, + kind: 'custom', // custom, address + }), + + createVerificationRequest: () => ({ + vendor_id: 0, + method_id: 0, + status: 'pending', + note: 'test-note', + documents: [], + }), + + updateVerificationRequest: () => ({ + vendor_id: 0, + method_id: 0, + status: 'approved', + note: 'test-note updated', + documents: [], + }), + // reverse withdrawal amountToPay: { diff --git a/tests/pw/utils/schemas.ts b/tests/pw/utils/schemas.ts index c1a0f6e320..3af804af91 100644 --- a/tests/pw/utils/schemas.ts +++ b/tests/pw/utils/schemas.ts @@ -71,17 +71,17 @@ const badgeCreateUpdateSchema = z.object({ // store settings const socialSchema = z.object({ - fb: z.string().url(), - youtube: z.string().url(), - twitter: z.string().url(), - linkedin: z.string().url(), - pinterest: z.string().url(), - instagram: z.string().url(), - flickr: z.string().url(), + fb: z.string().url().or(z.string().nullish()), + youtube: z.string().url().or(z.string().nullish()), + twitter: z.string().url().or(z.string().nullish()), + linkedin: z.string().url().or(z.string().nullish()), + pinterest: z.string().url().or(z.string().nullish()), + instagram: z.string().url().or(z.string().nullish()), + flickr: z.string().url().or(z.string().nullish()), }); const paypalSchema = z.object({ - email: z.string().email(), + email: z.string().email().or(z.string().nullish()), }); const bankSchema = z.object({ @@ -100,10 +100,10 @@ const skrillSchema = z.object({ }); const paymentSchema = z.object({ - paypal: paypalSchema, - bank: bankSchema, - stripe: z.boolean(), - skrill: skrillSchema, + paypal: paypalSchema.optional(), + bank: bankSchema.optional(), + stripe: z.boolean().optional(), + skrill: skrillSchema.optional(), }); const addressSchema = z.object({ @@ -215,16 +215,8 @@ const ratingSchema = z.object({ }); const linksSchema = z.object({ - self: z.array( - z.object({ - href: z.string().url(), - }), - ), - collection: z.array( - z.object({ - href: z.string().url(), - }), - ), + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), }); const storyCategorySchema = z.object({ @@ -372,6 +364,91 @@ const productQuestionAnswerSchema = z.object({ _links: linksSchema, }); +const verificationMethodSchema = z.object({ + id: z.number(), + title: z.string(), + help_text: z.string(), + status: z.boolean(), + required: z.boolean(), + kind: z.string(), + created_at: z.coerce.date(), + updated_at: z.coerce.date(), + _links: linksSchema, +}); + +const vendorSchema = z.object({ + store_name: z.string(), + social: socialSchema, + payment: paymentSchema.or(z.array(z.any())), + phone: z.string(), + show_email: z.string(), + address: addressSchema.or(z.array(z.any())), + location: z.string(), + banner: z.number(), + icon: z.number().or(z.string()), + gravatar: z.number(), + enable_tnc: z.string(), + store_tnc: z.string(), + show_min_order_discount: z.string(), + store_seo: z.unknown(), + dokan_store_time_enabled: z.string(), + dokan_store_open_notice: z.string(), + dokan_store_close_notice: z.string(), + find_address: z.string().nullish(), + dokan_category: z.string().nullish(), + sale_only_here: z.boolean(), + company_name: z.string(), + vat_number: z.string(), + company_id_number: z.string(), + bank_name: z.string(), + bank_iban: z.string(), + profile_completion: z.object({ + store_name: z.number(), + phone: z.number(), + next_todo: z.string(), + progress: z.number(), + progress_vals: z.object({ + closed_by_user: z.boolean().nullish(), + banner_val: z.number(), + profile_picture_val: z.number(), + store_name_val: z.number(), + address_val: z.number(), + phone_val: z.number(), + map_val: z.number().nullish(), + payment_method_val: z.number(), + social_val: z.object({ + fb: z.number(), + twitter: z.number(), + youtube: z.number(), + linkedin: z.number(), + }), + }), + }), +}); + +const verificationRequestSchema = z.object({ + id: z.number(), + vendor_id: z.number(), + method_id: z.number(), + status: z.string(), + status_title: z.string(), + documents: z.array(z.string().or(z.number())), + note: z.string(), + additional_info: z.array(z.unknown()), + checked_by: z.number(), + created_at: z.coerce.date(), + updated_at: z.coerce.date(), + vendor: vendorSchema, + method: verificationMethodSchema.omit({ _links: true }), + document_urls: z.record( + z.object({ + url: z.string().url(), + title: z.string(), + }), + ), + _links: linksSchema, +}); + export const schemas = { abuseReportsSchema: { abuseReportReasonsSchema: z.array( @@ -2039,4 +2116,11 @@ export const schemas = { productQuestionAnswerSchema: productQuestionAnswerSchema, productQuestionAnswersSchema: z.array(productQuestionAnswerSchema), }, + + vendorVerificationSchema: { + verificationMethodSchema: verificationMethodSchema, + verificationMethodsSchema: z.array(verificationMethodSchema), + verificationRequestSchema: verificationRequestSchema, + verificationRequestsSchema: z.array(verificationRequestSchema), + }, }; diff --git a/tests/pw/utils/testData.ts b/tests/pw/utils/testData.ts index 847b15bc09..4684b4ea02 100644 --- a/tests/pw/utils/testData.ts +++ b/tests/pw/utils/testData.ts @@ -765,6 +765,7 @@ export const data = { bankSwiftCode: faker.string.alphanumeric(10), customPayment: '1234567890', skrill: faker.internet.email(), + file: 'utils/sampleData/avatar.png', }, storeShare: { @@ -782,7 +783,7 @@ export const data = { backend: { login: 'wp-login.php', adminLogin: 'wp-admin', - adminLogout: 'wp-login.php?loggedout=true', + adminLogout: 'wp-login.php?action=logout', adminDashboard: 'wp-admin', user: 'wp-admin/user-edit.php', setupWP: 'wp-admin/install.php', @@ -821,7 +822,7 @@ export const data = { tools: 'wp-admin/admin.php?page=dokan#/tools', productQA: 'wp-admin/admin.php?page=dokan#/product-qa', questionDetails: (questionId: string) => `wp-admin/admin.php?page=dokan#/product-qa/${questionId}`, - verifications: 'wp-admin/admin.php?page=dokan-seller-verifications', + verifications: 'wp-admin/admin.php?page=dokan#/verifications?status=pending', productAdvertising: 'wp-admin/admin.php?page=dokan#/product-advertising', wholeSaleCustomer: 'wp-admin/admin.php?page=dokan#/wholesale-customer', help: 'wp-admin/admin.php?page=dokan#/help', @@ -986,6 +987,8 @@ export const data = { productQuestions: 'dokan/v1/product-questions', productQuestionsBulkActions: 'dokan/v1/product-questions/bulk_action', productAnswers: 'dokan/v1/product-answers', + verifications: '/dokan/v1/verification-requests', + verificationMethods: '/dokan/v1/verification-methods', }, wc: { @@ -1275,20 +1278,8 @@ export const data = { }, verification: { + method: 'National ID', file: 'utils/sampleData/avatar.png', - // file2: 'tests/e2e/utils/sampleData/avatar.png', - street1: 'abc street', - street2: 'xyz street', - city: 'New York', - zipCode: '10006', - country: 'US', - state: 'NY', - idRequestSubmitSuccessMessage: 'Your ID verification request is Sent and pending approval', - idRequestSubmitCancel: 'Your ID Verification request is cancelled', - addressRequestSubmitSuccessMessage: 'Your Address verification request is Sent and Pending approval', - addressRequestSubmitCancel: 'Your Address Verification request is cancelled', - companyRequestSubmitSuccessMessage: 'Your company verification request is sent and pending approval', - companyRequestSubmitCancel: 'Your company verification request is cancelled', }, toc: 'test Vendor terms and conditions', @@ -1943,6 +1934,57 @@ export const data = { saveSuccessMessage: 'Setting has been saved successfully.', }, + // Vendor Verification + vendorVerification: { + verifiedIcons: { + circleSolid: 'check_circle_solid', + circleRegular: 'check_circle_regular', + solid: 'check_solid', + doubleSolid: 'check_double_solid', + squireRegular: 'check_squire_regular', + userCheckSolid: 'user_check_solid', + certificateSolid: 'certificate_solid', + + byIcon: { + circleSolid: 'fas fa-check-circle', + circleRegular: 'far fa-check-circle', + solid: 'fas fa-check', + doubleSolid: 'fas fa-check-double', + squireRegular: 'fas fa-check-square', + userCheckSolid: 'fas fa-user-check', + certificateSolid: 'fas fa-certificate', + }, + }, + + verificationMethods: { + nationalId: 'National ID', + drivingLicense: 'Driving License', + address: 'Address', + company: 'Company', + }, + + customMethod: { + title: 'test verification method_' + faker.string.nanoid(10), + help_text: 'test help-text', + required: false, + }, + + updateMethod: { + title: 'test verification method updated_' + faker.string.nanoid(10), + help_text: 'test help-text updated', + required: true, + }, + + socialProfile: { + facebook: 'facebook_app_details', + twitter: 'twitter_app_details', + google: 'google_details', + linkedin: 'linkedin_details', + }, + + saveSuccessMessage: 'Setting has been saved successfully.', + }, + // Email verification emailVerification: { registrationNotice: 'Please check your email and complete email verification to login.', From 92b7c99a0dbda1260984680bd2bfa4b898a66763 Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Fri, 24 May 2024 16:44:15 +0600 Subject: [PATCH 5/8] refactor: change promo content (#2281) --- src/admin/components/ModuleUpgradePopup.vue | 57 ++++---- src/admin/components/UpgradeBanner.vue | 137 +++++++++++--------- 2 files changed, 109 insertions(+), 85 deletions(-) diff --git a/src/admin/components/ModuleUpgradePopup.vue b/src/admin/components/ModuleUpgradePopup.vue index b7c1a7851f..add89e26f1 100644 --- a/src/admin/components/ModuleUpgradePopup.vue +++ b/src/admin/components/ModuleUpgradePopup.vue @@ -41,48 +41,55 @@ {{ __( 'Upgrade to Pro', 'dokan-lite' ) }}
- - - - - - + + + + + + + + + + + + + + + + + - - - - - - - - - - + - - - - - + + + + + + - + - - + + - + + + + +
{{ __( 'Already upgraded?', 'dokan-lite' ) }} diff --git a/src/admin/components/UpgradeBanner.vue b/src/admin/components/UpgradeBanner.vue index 423e060075..a8bde302ee 100644 --- a/src/admin/components/UpgradeBanner.vue +++ b/src/admin/components/UpgradeBanner.vue @@ -1,105 +1,122 @@