diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index c3ba43e9e3..ba3c5a55b4 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -5,6 +5,7 @@ * [ ] My code is tested * [ ] My code passes the PHPCS tests * [ ] My code has proper inline documentation +* [ ] I've included related pull request(s) (optional) * [ ] I've included developer documentation (optional) * [ ] I've added proper labels to this pull request @@ -16,19 +17,42 @@ -Closes # . +### Related Pull Request(s) -### How to test the changes in this Pull Request: +* Full PR Link + + +### Closes + +* Closes # -1. -2. -3. +### How to test the changes in this Pull Request: + +* Steps or issue link ### Changelog entry -> Enter a summary of all changes on this Pull Request. This will appear in the changelog if accepted. +*Title* + +Detailed Description of the pull request. What was previous behaviour +and what will be changed in this PR. + + +### Before Changes + +Describe the issue before changes with screenshots(s). + + +### After Changes + +Describe the issue after changes with screenshot(s). + + +### Feature Video (optional) + +Link of detailed video if this PR is for a feature. ### PR Self Review Checklist: diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml new file mode 100644 index 0000000000..7c94cfa1db --- /dev/null +++ b/.github/workflows/e2e_tests.yml @@ -0,0 +1,208 @@ +name: End-to-End Tests Lite + +on: + schedule: + - cron: '0 8 * * *' + pull_request: + push: + branches: + - develop + workflow_dispatch: + +# Cancels all previous workflow runs for pull requests that have not completed. +concurrency: + # The concurrency group contains the workflow name and the branch name for pull requests or the commit hash for any other events. + group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }} + cancel-in-progress: true + +permissions: + checks: write + contents: read + issues: write + pull-requests: write + +env: + ADMIN: admin + ADMIN_PASSWORD: password + VENDOR: vendor1 + VENDOR2: vendor2 + CUSTOMER: customer1 + USER_PASSWORD: 01dokan01 + GMAP: ${{secrets.GMAP}} + BASE_URL: http://localhost:9999 + CI: true + FORCE_COLOR: 1 + DB_HOST_NAME: localhost + DB_USER_NAME: root + DB_USER_PASSWORD: password + DATABASE: tests-wordpress + DB_PREFIX: wp + PR_NUMBER: ${{ github.event.number }} + SHA: ${{ github.event.pull_request.head.sha }} + SYSTEM_INFO: ./tests/pw/systemInfo.json + API_TEST_RESULT: ./tests/pw/playwright-report/api/summary-report/results.json + E2E_TEST_RESULT: ./tests/pw/playwright-report/e2e/summary-report/results.json + +jobs: + tests: + name: e2e tests + runs-on: ubuntu-latest + # strategy: + # fail-fast: false + + steps: + - name: Checkout testing repo + uses: actions/checkout@v3 + + - name: Use desired version of NodeJS + if: success() + uses: actions/setup-node@v3 + with: + node-version: '16' + cache: 'npm' + + - name: Composer install and build (Dokan-lite) + if: success() + run: | + composer install --no-dev + composer dump-autoload -o + + - name: Npm install and build (Dokan-lite) + if: success() + run: | + npm ci + npm run build + + # Install test dependencies + - name: Install dependencies + if: success() + run: | + cd tests/pw + npm ci + + # Start wordpress environment + - name: Start WordPress Env + id: wp-env + if: success() + run: | + cd tests/pw + npm run start:env + + # Grab test db port + - name: Get Test DB PORT + id: db-port + if: success() + run: | + cd tests/pw + echo "DB_PORT=$(docker ps -f ancestor='mariadb' -f name='tests-mysql' --format='{{.Ports}}' | sed -E 's/.*:(.*)->.*/\1/')" >> $GITHUB_ENV + + # db port + - name: DB PORT + if: success() + run: | + cd tests/pw + echo "The value of test DB_PORT is ${{ env.DB_PORT }}" + echo "The value of test DB_PORT is ${{ env.GMAP }}" + + # Set permalink structure + - name: Set Permalink structure + if: success() + run: | + cd tests/pw + npm run wp-env run tests-cli wp rewrite structure /%postname%/ + + # Activate theme + - name: Activate theme:Storefront + if: success() + run: | + cd tests/pw + npm run wp-env run tests-cli wp theme activate storefront + + # Get Playwright version + - name: Get installed Playwright version + id: playwright-version + if: success() + run: | + cd tests/pw + echo "PLAYWRIGHT_VERSION=$(npm ls @playwright/test --json | jq --raw-output '.dependencies["@playwright/test"].version')" >> $GITHUB_ENV + + # Cache browser binaries, cache key is based on Playwright version and OS + - name: Cache playwright binaries + id: playwright-cache + if: success() + uses: actions/cache@v3 + with: + path: | + ~/.cache/ms-playwright + key: ${{ runner.os }}-playwright-${{ env.PLAYWRIGHT_VERSION }} + restore-keys: | + ${{ runner.os }}-playwright- + + # Install browser binaries & OS dependencies if cache missed + - name: Install Playwright browser binaries & OS dependencies + id: pw-install + if: success() && steps.playwright-cache.outputs.cache-hit != 'true' + run: | + cd tests/pw + npm run pw:browser-with-deps + + # Run e2e tests + - name: 🧪 Running the e2e tests + id: e2e-test + if: steps.pw-install.outcome == 'success' + timeout-minutes: 40 + run: | + cd tests/pw + npm run test:e2e:lite + + # Run API tests + - name: 🧪 Running the api tests + id: api-test + if: always() + timeout-minutes: 5 + run: | + cd tests/pw + npm run test:api:lite + + # Prepare test summary + - name: Prepare test summary + id: prepare-test-summary + uses: actions/github-script@v6 + if: always() + with: + result-encoding: string + script: | + const script = require("./tests/pw/utils/gitTestSummary.ts") + return await script({github, context, core}) + + # Find PR comment + - name: Find PR comment by github-actions[bot] + uses: peter-evans/find-comment@v2 + id: find-comment + if: github.event_name == 'pull_request' + with: + issue-number: ${{ github.event.pull_request.number }} + comment-author: 'github-actions[bot]' + body-includes: Tests Summary + + # Post test summary as PR comment + - name: Create or update PR comment + uses: peter-evans/create-or-update-comment@v2 + if: github.event_name == 'pull_request' + with: + comment-id: ${{ steps.find-comment.outputs.comment-id }} + issue-number: ${{ github.event.pull_request.number }} + body: ${{ steps.prepare-test-summary.outputs.result }} + edit-mode: replace + + # Upload artifacts + - name: Archive test artifacts (screenshots, HTML snapshots, Reports) + uses: actions/upload-artifact@v3 + if: always() + with: + name: test-artifact + path: | + tests/pw/playwright + tests/pw/playwright-report + if-no-files-found: ignore + retention-days: 30 diff --git a/README.md b/README.md index cdf3e5d462..4a085dc68c 100644 --- a/README.md +++ b/README.md @@ -3,11 +3,11 @@ **Donate Link:** http://tareq.co/donate/ **Tags:** WooCommerce multivendor marketplace, multi vendor marketplace, multi seller store, multi-vendor, multi seller, commissions, multivendor, marketplace, product vendors, woocommerce vendor, commission rate, e-commerce, woocommerce, ebay, ecommerce. **Requires at least:** 5.6 -**Tested up to:** 6.3.1 +**Tested up to:** 6.3.2 **WC requires at least:** 5.0.0 -**WC tested up to:** 8.1.1 +**WC tested up to:** 8.2.1 **Requires PHP:** 7.3 -**Stable tag:** 3.8.3 +**Stable tag:** 3.9.1 **License:** GPLv2 or later **License URI:** http://www.gnu.org/licenses/gpl-2.0.html @@ -338,6 +338,29 @@ A. Just install and activate the PRO version without deleting the free plugin. A ## Changelog ## +### v3.9.1 ( Oct 17, 2023 ) ### + +- **update:** Removed flaticon packages and replace used icons with fontAwesome icons. This will reduce the plugin zip size. +- **update:** Added a new settings to disable fontAwesome library +- **update:** Changed all the single date picker fields with daterange picker. This updates will keep the design consistent throughout the plugin. +- **fix:** [StoreOpenCloseTime] An issue where invalid store opening or closing times generate warning and fatal error on single store page. +- **fix:** [Email] Fixed an issue where the product edit link on email template redirects to the products listing instead of single product edit page +- **fix:** Fixed some responsive issue under vendor dashboard product edit page. +- **fix:** Fixed some responsive issue under vendor dashboard withdraw page. + +### v3.9.0 ( Oct 06, 2023 ) ### + +- **new:** Added two new hooks named `dokan_get_admin_report_data` and `dokan_get_overview_data` to extend Dokan reports functionality. +- **fix:** Resolved an issue where the `Tracking Number` button was still visible under the `Vendor Dashboard → Order Details → Order Note section` even after the `Shipment Tracking` feature was enabled by the admin. +- **fix:** [WidgetProductAttribute] Fixed an issue where the `Filter Products by Attribute` widget was not working for Multi-Word Attributes. +- **update:** Added a new filter named `dokan_get_store_url` to filter store URLs for a single store. +- **update:** Removed some redundant or not required settings from vendor store settings page, also rearranged some admin settings and added some settings under Admin dashboard. +Details: +1. Removed `Show Vendor Info` settings under the `WordPress Admin Dashboard → Dokan → Settings → Appearance` and added it back under the `WordPress Admin Dashboard → Dokan → Settings → General → Product Page Settings` section. +2. Removed the `More Products` setting under `Vendor Dashboard → Settings → Store Settings` and added it back as a new Admin setting under `WordPress Admin Dashboard → Dokan → Settings → General → Product Page Settings` section. Now, only the admin can control this setting. +3. Removed redundant `Store Products Per Page` setting under `Vendor Dashboard → Settings → Store Settings`. Since the admin already has this setting under `WordPress Admin Dashboard → Dokan → Settings → General`, this setting will be used from now on and only the admin can control this setting. +4. Removed redundant `Store Page Product Section` settings under `Vendor Dashboard → Settings → Store Page Product Section`. Now, only the admin can control these settings under Theme Customizer settings. + ### v3.8.3 ( Sep 26, 2023 ) ### - **update:** Added advanced filtering and CSV export feature for vendor withdraws under Admin Dashboard → Dokan → Withdraw menu. diff --git a/assets/css/style.css b/assets/css/style.css index 8e8df00031..cecbd53f2d 100644 --- a/assets/css/style.css +++ b/assets/css/style.css @@ -5643,6 +5643,30 @@ div.media-sidebar a.edit-attachment { text-align: right; border-top: 1px solid #eee; } +@media only screen and (max-width: 500px) { + .dokan-withdraw-content .dokan-withdraw-area .entry-content .dokan-panel .dokan-panel-body .dokan-panel-inner-container { + display: flex; + flex-direction: column; + } + .dokan-withdraw-content .dokan-withdraw-area .entry-content .dokan-panel .dokan-panel-body .dokan-panel-inner-container .dokan-w5 { + position: relative; + left: 0; + right: 100%; + top: 100%; + transform: none; + margin-top: 20px; + } + .dokan-withdraw-content .dokan-withdraw-area .entry-content .dokan-withdraw-status-filter-container .dokan-add-product-link a { + margin: 15px 0; + } + .dokan-withdraw-content .dokan-withdraw-area table.dokan-table-striped { + overflow: auto; + display: block; + } + .dokan-withdraw-content .dokan-withdraw-area table.dokan-table-striped tbody tr th { + width: 150px; + } +} .dokan-login-form-popup-wrapper { width: 430px !important; padding: 16px !important; @@ -6410,7 +6434,7 @@ p.vendor-customer-registration .radio:hover { .dokan-dashboard .dokan-dashboard-content { float: none; width: 100%; - padding: 20px; + padding: 20px 0; } .dokan-dashboard .dokan-dash-sidebar .dokan-table, .dokan-dashboard .dokan-dashboard-content .dokan-table { @@ -6471,21 +6495,35 @@ p.vendor-customer-registration .radio:hover { } .dokan-dashboard .dokan-product-listing .dokan-product-listing-area .dokan-product-date-filter { display: flex; + flex-flow: column wrap; justify-content: space-between; } .dokan-dashboard .dokan-product-listing .dokan-product-listing-area .dokan-product-date-filter .dokan-form-group { - margin-bottom: 0; + margin-bottom: 10px; } .dokan-dashboard .dokan-product-listing .dokan-product-listing-area .dokan-product-search-form { - margin-top: 15px; - width: 100%; + display: flex; + justify-content: space-between; + flex-flow: row-reverse nowrap; } .dokan-dashboard .dokan-product-listing .dokan-product-listing-area .dokan-product-search-form .dokan-form-group { margin-bottom: 0; margin-right: 0; + width: 73%; } - .dokan-dashboard .dokan-product-listing .dokan-product-listing-area #product-filter .dokan-form-group { - margin-top: 15px; + .dokan-dashboard .dokan-product-listing .dokan-product-listing-area .dokan-product-search-form .dokan-btn { + width: 25%; + } + .dokan-dashboard .dokan-product-listing .dokan-product-listing-area #dokan-bulk-action-selector { + width: 73%; + margin-right: 2%; + } + .dokan-dashboard .dokan-product-listing .dokan-product-listing-area #dokan-bulk-action-submit { + width: 25%; + margin-right: 0; + } + .dokan-dashboard .dokan-product-listing .dokan-product-listing-area #product-filter .dokan-btn { + width: 100%; } .dokan-dashboard .dokan-right, .dokan-dashboard .dokan-left { diff --git a/assets/font/flaticon/Flaticon.eot b/assets/font/flaticon/Flaticon.eot deleted file mode 100644 index b1fead4a11..0000000000 Binary files a/assets/font/flaticon/Flaticon.eot and /dev/null differ diff --git a/assets/font/flaticon/Flaticon.svg b/assets/font/flaticon/Flaticon.svg deleted file mode 100644 index 03de3ab432..0000000000 --- a/assets/font/flaticon/Flaticon.svg +++ /dev/null @@ -1,176 +0,0 @@ - - - - - -Created by FontForge 20160405 at Sat Mar 24 15:52:30 2018 - By Apache -Copyright (c) 2018, Apache - - - - - - - - - - - - - - - - - - - - - - diff --git a/assets/font/flaticon/Flaticon.ttf b/assets/font/flaticon/Flaticon.ttf deleted file mode 100644 index 63886f77df..0000000000 Binary files a/assets/font/flaticon/Flaticon.ttf and /dev/null differ diff --git a/assets/font/flaticon/Flaticon.woff b/assets/font/flaticon/Flaticon.woff deleted file mode 100644 index 963a644d7d..0000000000 Binary files a/assets/font/flaticon/Flaticon.woff and /dev/null differ diff --git a/assets/font/flaticon/flaticon.css b/assets/font/flaticon/flaticon.css deleted file mode 100644 index c070c349f3..0000000000 --- a/assets/font/flaticon/flaticon.css +++ /dev/null @@ -1,44 +0,0 @@ - /* - Flaticon icon font: Flaticon - Creation date: 24/03/2018 15:52 - */ - -@font-face { - font-family: "Flaticon"; - src: url("./Flaticon.eot"); - src: url("./Flaticon.eot?#iefix") format("embedded-opentype"), - url("./Flaticon.woff") format("woff"), - url("./Flaticon.ttf") format("truetype"), - url("./Flaticon.svg#Flaticon") format("svg"); - font-weight: normal; - font-style: normal; -} - -@media screen and (-webkit-min-device-pixel-ratio:0) { - @font-face { - font-family: "Flaticon"; - src: url("./Flaticon.svg#Flaticon") format("svg"); - } -} - -[class^="flaticon-"]:before, [class*=" flaticon-"]:before, -[class^="flaticon-"]:after, [class*=" flaticon-"]:after { - font-family: Flaticon; - font-size: 22px; - font-style: normal; -} - -.flaticon-flickr-website-logo-silhouette:before { content: "\f100"; } -.flaticon-skrill-pay-logo:before { content: "\f101"; } -.flaticon-money:before { content: "\f102"; } -.flaticon-stripe-logo:before { content: "\f103"; } -.flaticon-bank-building:before { content: "\f104"; } -.flaticon-paypal-logotype:before { content: "\f105"; } -.flaticon-pinterest-logo:before { content: "\f106"; } -.flaticon-linkedin-logo:before { content: "\f107"; } -.flaticon-instagram:before { content: "\f108"; } -.flaticon-google-plus:before { content: "\f109"; } -.flaticon-youtube:before { content: "\f10a"; } -.flaticon-whatsapp:before { content: "\f10b"; } -.flaticon-twitter-logo-silhouette:before { content: "\f10c"; } -.flaticon-facebook-logo:before { content: "\f10d"; } diff --git a/assets/js/dokan.js b/assets/js/dokan.js index f940c50793..996c818284 100644 --- a/assets/js/dokan.js +++ b/assets/js/dokan.js @@ -1 +1 @@ -(()=>{var e,t;jQuery((function(e){e(".tips").tooltip(),e("ul.order-status").on("click","a.dokan-edit-status",(function(t){return e(this).addClass("dokan-hide").closest("li").next("li").removeClass("dokan-hide"),!1})),e("ul.order-status").on("click","a.dokan-cancel-status",(function(t){return e(this).closest("li").addClass("dokan-hide").prev("li").find("a.dokan-edit-status").removeClass("dokan-hide"),!1})),e("form#dokan-order-status-form").on("submit",(function(t){t.preventDefault();var a=e(this),n=a.closest("li");n.block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}}),e.post(dokan.ajaxurl,a.serialize(),(function(e){if(n.unblock(),e.success){var t=n.prev();n.addClass("dokan-hide"),t.find("label").replaceWith(e.data),t.find("a.dokan-edit-status").removeClass("dokan-hide")}else dokan_sweetalert(e.data,{icon:"success"})}))})),e("form#add-order-note").on("submit",(function(t){if(t.preventDefault(),e("textarea#add-note-content").val())return e("#dokan-order-notes").block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}}),e.post(dokan.ajaxurl,e(this).serialize(),(function(t){e("ul.order_notes").prepend(t),e("#dokan-order-notes").unblock(),e("#add-note-content").val("")})),!1})),e("#dokan-order-notes").on("click","a.delete_note",(function(){var t=e(this).closest("li.note");e("#dokan-order-notes").block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}});var a={action:"dokan_delete_order_note",note_id:e(t).attr("rel"),security:e("#delete-note-security").val()};return e.post(dokan.ajaxurl,a,(function(a){e(t).remove(),e("#dokan-order-notes").unblock()})),!1})),e(".order_download_permissions").on("click","button.grant_access",(function(){var t=e(this),a=e("select.grant_access_id").val();if(a){e(".order_download_permissions").block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}});var n={action:"dokan_grant_access_to_download",product_ids:a,loop:e(".order_download_permissions .panel").length,order_id:t.data("order-id"),security:t.data("nonce")};return e.post(dokan.ajaxurl,n,(function(t){t?e("#accordion").append(t):dokan_sweetalert(dokan.i18n_download_access,{icon:"warning"}),e(".datepicker").datepicker(),e(".order_download_permissions").unblock()})),!1}})),e(".order_download_permissions").on("click","button.revoke_access",(async function(t){t.preventDefault();const a=await dokan_sweetalert(dokan.i18n_download_permission,{action:"confirm",icon:"warning"});if("undefined"!==a&&a.isConfirmed){var n=e(this),o=n.closest(".dokan-panel"),i=n.attr("rel").split(",")[0],r=n.attr("rel").split(",")[1];if(i>0){e(o).block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}});var d={action:"dokan_revoke_access_to_download",product_id:i,download_id:r,order_id:n.data("order-id"),permission_id:n.data("permission-id"),security:n.data("nonce")};e.post(dokan.ajaxurl,d,(function(t){e(o).fadeOut("300",(function(){e(o).remove()}))}))}else e(o).fadeOut("300",(function(){e(o).remove()}))}return!1}))})),e=jQuery,(t={init:function(){let t={d:"dd",D:"D",j:"d",l:"DD",F:"MM",m:"mm",M:"M",n:"m",o:"yy",Y:"yy",y:"y"},a=0,n="",o="";for(a=0;a0?e("#restock_refunded_items").closest("tr").show():(e("#restock_refunded_items").closest("tr").hide(),e(".woocommerce_order_items input.refund_order_item_qty").each((function(){e(this).val()>0&&e("#restock_refunded_items").closest("tr").show()}))),e(this).trigger("refund_quantity_changed")}}}).init(),e("#dokan-filter-customer").filter(":not(.enhanced)").each((function(){var t={allowClear:!!e(this).data("allow_clear"),placeholder:e(this).data("placeholder"),minimumInputLength:e(this).data("minimum_input_length")?e(this).data("minimum_input_length"):"1",escapeMarkup:function(e){return e},language:{errorLoading:function(){return dokan.i18n_searching},inputTooLong:function(e){var t=e.input.length-e.maximum;return 1===t?dokan.i18n_input_too_long_1:dokan.i18n_input_too_long_n.replace("%qty%",t)},inputTooShort:function(e){var t=e.minimum-e.input.length;return 1===t?dokan.i18n_input_too_short_1:dokan.i18n_input_too_short_n.replace("%qty%",t)},loadingMore:function(){return dokan.i18n_load_more},maximumSelected:function(e){return 1===e.maximum?dokan.i18n_selection_too_long_1:dokan.i18n_selection_too_long_n.replace("%qty%",e.maximum)},noResults:function(){return dokan.i18n_no_matches},searching:function(){return dokan.i18n_searching}},ajax:{url:dokan.ajaxurl,dataType:"json",delay:1e3,data:function(t){return{term:t.term,action:"dokan_json_search_vendor_customers",security:dokan.search_customer_nonce,exclude:e(this).data("exclude")}},processResults:function(t){var a=[];return t&&e.each(t,(function(e,t){a.push({id:e,text:t})})),{results:a}},cache:!0}};if(e(this).select2(t).addClass("enhanced"),e(this).data("sortable")){var a=e(this),n=e(this).next(".select2-container").find("ul.select2-selection__rendered");n.sortable({placeholder:"ui-state-highlight select2-selection__choice",forcePlaceholderSize:!0,items:"li:not(.select2-search__field)",tolerance:"pointer",stop:function(){e(n.find(".select2-selection__choice").get().reverse()).each((function(){var t=e(this).data("data").id,n=a.find('option[value="'+t+'"]')[0];a.prepend(n)}))}})}})),function(e){e("#variants-holder"),e("#product_image_gallery"),e("#product_images_container ul.product_images");var t,a,n={modal:!1,init:function(){product_type="simple",e(".product-edit-container").on("click",".dokan-section-heading",this.toggleProductSection),e(".product-edit-container").on("click","input[type=checkbox]#_downloadable",this.downloadable),e(".product-edit-container").on("click","a.sale-schedule",this.showDiscountSchedule),e("body, #dokan-product-images").on("click","a.add-product-images",this.gallery.addImages),e("body, #dokan-product-images").on("click","a.action-delete",this.gallery.deleteImage),this.gallery.sortable(),e("body, .product-edit-container").on("click","a.dokan-feat-image-btn",this.featuredImage.addImage),e("body, .product-edit-container").on("click","a.dokan-remove-feat-image",this.featuredImage.removeImage),e("body, #variable_product_options").on("click",".sale_schedule",this.saleSchedule),e("body, #variable_product_options").on("click",".cancel_sale_schedule",this.cancelSchedule),e(".product-edit-container").on("change","input[type=checkbox]#_manage_stock",this.showManageStock),e(".product-edit-container").on("click","a.upload_file_button",this.fileDownloadable),e("body").on("click","a.insert-file-row",(function(){return e(this).closest("table").find("tbody").append(e(this).data("row")),!1})),e("body").on("click","a.dokan-product-delete",(function(){return e(this).closest("tr").remove(),!1})),e("body").on("submit","form.dokan-product-edit-form",this.inputValidate),e(".dokan-product-listing").on("click","a.dokan-add-new-product",this.addProductPopup),this.loadSelect2(),this.bindProductTagDropdown(),this.attribute.sortable(),this.checkProductPostboxToggle(),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.dokan-product-toggle-attribute, .dokan-product-attribute-heading",this.attribute.toggleAttribute),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.add_new_attribute",this.attribute.addNewAttribute),e(".product-edit-container .dokan-product-attribute-wrapper").on("keyup","input.dokan-product-attribute-name",this.attribute.dynamicAttrNameChange),e(".dokan-product-attribute-wrapper ul.dokan-attribute-option-list").on("click","button.dokan-select-all-attributes",this.attribute.selectAllAttr),e(".dokan-product-attribute-wrapper ul.dokan-attribute-option-list").on("click","button.dokan-select-no-attributes",this.attribute.selectNoneAttr),e(".dokan-product-attribute-wrapper ul.dokan-attribute-option-list").on("click","button.dokan-add-new-attribute",this.attribute.addNewExtraAttr),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.dokan-product-remove-attribute",this.attribute.removeAttribute),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.dokan-save-attribute",this.attribute.saveAttribute),e("body").on("click",'.product-container-footer input[type="submit"]',this.createNewProduct),this.attribute.disbalePredefinedAttribute(),this.setCorrectProductId(),e("body").trigger("dokan-product-editor-loaded",this)},setCorrectProductId:function(){if(!e(".dokan-product-edit-form"))return;let t=e("#dokan_product_id").val();if(window.history.replaceState){let e=new URL(document.location),a=e.searchParams,n=a.get("product_id");if(""!==n&&"0"!==n)return;if(a.set("product_id",t),"edit"!==a.get("action"))return;e.search=a.toString();let o=e.toString(),i={product_id:t};window.history.replaceState(i,document.title,o)}},saleSchedule:function(){var t=e(this).closest(".dokan-product-field-content","div, table");return e(this).hide(),t.find(".cancel_sale_schedule").show(),t.find(".sale_price_dates_fields").show(),!1},cancelSchedule:function(){var t=e(this).closest(".dokan-product-field-content","div, table");return e(this).hide(),t.find(".sale_schedule").show(),t.find(".sale_price_dates_fields").hide(),t.find(".sale_price_dates_fields").find("input").val(""),!1},checkProductPostboxToggle:function(){var t=JSON.parse(localStorage.getItem("toggleClasses"));e.each(t,(function(t,a){var n=e("."+t.replace(/_/g,"-")),o=n.find(".dokan-section-content"),i=n.find("i.fa-sort-desc");a?(o.show(),i.removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),i.css("marginTop","9px")):(o.hide(),i.removeClass("fa-flip-vertical").addClass("fa-flip-horizointal"),i.css("marginTop","0px"))}))},toggleProductSection:function(t){t.preventDefault();var a=e(this);if(null!=JSON.parse(localStorage.getItem("toggleClasses")))var n=JSON.parse(localStorage.getItem("toggleClasses"));else n={};a.closest(".dokan-edit-row").find(".dokan-section-content").slideToggle(300,(function(){var t;e(this).is(":visible")?((t=a.find("i.fa-sort-desc")).removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),t.css("marginTop","9px"),n[a.data("togglehandler")]=!0):((t=a.find("i.fa-sort-desc")).removeClass("fa-flip-vertical").addClass("fa-flip-horizointal"),t.css("marginTop","0px"),n[a.data("togglehandler")]=!1),localStorage.setItem("toggleClasses",JSON.stringify(n))}))},loadSelect2:function(){e(".dokan-select2").select2({language:{noResults:function(){return dokan.i18n_no_result_found}}})},bindProductTagDropdown:function(){e(".product_tag_search").select2({allowClear:!1,tags:dokan.product_vendors_can_create_tags&&"on"===dokan.product_vendors_can_create_tags,createTag:function(t){var a=e.trim(t.term);return""===a?null:{id:a,text:a,newTag:!0}},insertTag:function(t,a){var n=!1;e.each(t,(function(t,o){e.trim(a.text).toUpperCase()==e.trim(o.text).toUpperCase()&&(n=!0)})),n||t.unshift(a)},minimumInputLength:2,maximumSelectionLength:void 0!==dokan.maximum_tags_select_length?dokan.maximum_tags_select_length:-1,ajax:{url:dokan.ajaxurl,dataType:"json",delay:250,data:function(e){return{q:e.term,action:"dokan_json_search_products_tags",security:dokan.search_products_tags_nonce,page:e.page||1}},processResults:function(t){var a=[];return t&&e.each(t,(function(e,t){a.push({id:t[0],text:t[1]})})),{results:a,pagination:{more:0!=a.length}}},cache:!0},language:{errorLoading:function(){return dokan.i18n_searching},inputTooLong:function(e){var t=e.input.length-e.maximum;return 1===t?dokan.i18n_input_too_long_1:dokan.i18n_input_too_long_n.replace("%qty%",t)},inputTooShort:function(e){var t=e.minimum-e.input.length;return 1===t?dokan.i18n_input_too_short_1:dokan.i18n_input_too_short_n.replace("%qty%",t)},loadingMore:function(){return dokan.i18n_load_more},maximumSelected:function(e){return 1===e.maximum?dokan.i18n_selection_too_long_1:dokan.i18n_selection_too_long_n.replace("%qty%",e.maximum)},noResults:function(){return dokan.i18n_no_matches},searching:function(){return dokan.i18n_searching}}})},addProductPopup:function(e){e.preventDefault(),n.openProductPopup()},openProductPopup:function(){const o=wp.template("dokan-add-new-product"),i=e("#dokan-add-product-popup");n.modal=i.iziModal({headerColor:dokan.modal_header_color,overlayColor:"rgba(0, 0, 0, 0.8)",width:690,top:32,onOpening:()=>{n.reRenderPopupElements()},onClosed:()=>{t=void 0,a=void 0,e('#dokan-add-new-product-popup input[name="_sale_price_dates_from"], #dokan-add-new-product-popup input[name="_sale_price_dates_to"]').datepicker("destroy")}}),n.modal.iziModal("setContent",o().trim()),n.modal.iziModal("open")},reRenderPopupElements:function(){n.loadSelect2(),n.bindProductTagDropdown(),e("#dokan-add-new-product-popup .sale_price_dates_fields input").daterangepicker({singleDatePicker:!0,showDropdowns:!1,autoApply:!0,parentEl:"#dokan-add-new-product-popup",opens:"left",autoUpdateInput:!1}).on("apply.daterangepicker",(function(t,a){e(this).val(a.startDate.format("YYYY-MM-DD"))})),e(".tips").tooltip(),n.gallery.sortable(),e("body").trigger("dokan-product-editor-popup-opened",n)},createNewProduct:function(t){t.preventDefault();var o=e(this),i=o.closest("form#dokan-add-new-product-form"),r=o.attr("data-btn_id");if(i.find("span.dokan-show-add-product-success").html(""),i.find("span.dokan-show-add-product-error").html(""),i.find("span.dokan-add-new-product-spinner").css("display","inline-block"),o.attr("disabled","disabled"),""==i.find('input[name="post_title"]').val())return e("span.dokan-show-add-product-error").html(dokan.product_title_required),o.removeAttr("disabled"),void i.find("span.dokan-add-new-product-spinner").css("display","none");if("-1"==i.find('select[name="product_cat"]').val())return e("span.dokan-show-add-product-error").html(dokan.product_category_required),o.removeAttr("disabled"),void i.find("span.dokan-add-new-product-spinner").css("display","none");var d={action:"dokan_create_new_product",postdata:i.serialize(),_wpnonce:dokan.nonce};n.modal.iziModal("startLoading"),e.post(dokan.ajaxurl,d,(function(t){t.success?(o.removeAttr("disabled"),"create_new"===r?(e("#dokan-add-product-popup").iziModal("close"),window.location.href=t.data):(a=void 0,e(".dokan-dashboard-product-listing-wrapper").load(window.location.href+" table.product-listing-table"),n.modal.iziModal("resetContent"),n.openProductPopup(),n.reRenderPopupElements(),e("span.dokan-show-add-product-success").html(dokan.product_created_response),setTimeout((function(){e("span.dokan-show-add-product-success").html("")}),3e3))):(o.removeAttr("disabled"),e("span.dokan-show-add-product-error").html(t.data)),i.find("span.dokan-add-new-product-spinner").css("display","none")})).always((function(){n.modal.iziModal("stopLoading")}))},attribute:{toggleAttribute:function(t){t.preventDefault();var a=e(this),n=a.closest("li").find(".dokan-product-attribute-item");return e(n).hasClass("dokan-hide")?(a.closest(".dokan-product-attribute-heading").css({borderBottom:"1px solid #e3e3e3"}),e(n).slideDown(200,(function(){a.find("i.fa").removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),e(this).removeClass("dokan-hide"),e(t.target).hasClass("dokan-product-attribute-heading")?e(t.target).hasClass("dokan-product-attribute-heading")&&a.find("a.dokan-product-toggle-attribute").css("top","12px"):e(t.target).closest("a").css("top","12px")}))):e(n).slideUp(200,(function(){e(this).addClass("dokan-hide"),a.find("i.fa").removeClass("fa-flip-vertical").addClass("fa-flip-horizointal"),e(t.target).hasClass("dokan-product-attribute-heading")?e(t.target).hasClass("dokan-product-attribute-heading")&&a.find("a.dokan-product-toggle-attribute").css("top","7px"):e(t.target).closest("a").css("top","7px"),a.closest(".dokan-product-attribute-heading").css({borderBottom:"none"})})),!1},sortable:function(){e(".dokan-product-attribute-wrapper ul").sortable({items:"li.product-attribute-list",cursor:"move",scrollSensitivity:40,forcePlaceholderSize:!0,forceHelperSize:!1,helper:"clone",opacity:.65,placeholder:"dokan-sortable-placeholder",start:function(e,t){t.item.css("background-color","#f6f6f6")},stop:function(e,t){t.item.removeAttr("style")},update:function(e,t){n.attribute.reArrangeAttribute()}})},dynamicAttrNameChange:function(t){t.preventDefault();var a=e(this),n=a.val();""==n?a.closest("li").find("strong").html(dokan.i18n_attribute_label):a.closest("li").find("strong").html(n)},selectAllAttr:function(t){return t.preventDefault(),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values option").attr("selected","selected"),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values").trigger("change"),!1},selectNoneAttr:function(t){return t.preventDefault(),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values option").removeAttr("selected"),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values").trigger("change"),!1},reArrangeAttribute:function(){e(".dokan-product-attribute-wrapper").find("ul.dokan-attribute-option-list").find("li.product-attribute-list").css("cursor","default").each((function(t){e(this).find(".attribute_position").val(t)}))},addNewExtraAttr:async function(t){t.preventDefault();var a=e(this).closest("li.product-attribute-list"),n=a.data("taxonomy"),o=(await dokan_sweetalert(dokan.new_attribute_prompt,{action:"prompt",input:"text"})).value;if(o){var i={action:"dokan_add_new_attribute",taxonomy:n,term:o,_wpnonce:dokan.nonce};e.post(dokan.ajaxurl,i,(function(e){e.error?dokan_sweetalert(e.error,{action:"alert",icon:"warning"}):e.slug&&(a.find("select.dokan_attribute_values").append('"),a.find("select.dokan_attribute_values").trigger("change"))}))}},addNewAttribute:function(t){t.preventDefault();var a=e(this),o=a.closest(".dokan-attribute-type").find("select#predefined_attribute"),i=o.val(),r=e("ul.dokan-attribute-option-list .product-attribute-list").length,d={action:"dokan_get_pre_attribute",taxonomy:i,i:r,_wpnonce:dokan.nonce};a.closest(".dokan-attribute-type").find("span.dokan-attribute-spinner").removeClass("dokan-hide"),e.post(dokan.ajaxurl,d,(function(t){if(t.success){var r=e(".dokan-product-attribute-wrapper").find("ul.dokan-attribute-option-list");if($html=e.parseHTML(t.data),e($html).find(".dokan-product-attribute-item").removeClass("dokan-hide"),e($html).find("i.fa.fa-sort-desc").removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),e($html).find("a.dokan-product-toggle-attribute").css("top","12px"),e($html).find(".dokan-product-attribute-heading").css({borderBottom:"1px solid #e3e3e3"}),r.append($html),n.loadSelect2(),n.bindProductTagDropdown(),n.attribute.reArrangeAttribute(),"variable"!==e("select#product_type").val()){let t=e("div.dokan-product-attribute-wrapper label.show_if_variable");for(let a of t){let t=e(a).find('input[type="checkbox"]');t.length>0&&t[0].getAttribute("name")?.startsWith("attribute_variation[")&&e(a).hide()}}}a.closest(".dokan-attribute-type").find("span.dokan-attribute-spinner").addClass("dokan-hide"),i&&(o.find('option[value="'+i+'"]').attr("disabled","disabled"),o.val(""))})).done((function(){e("select#product_type").trigger("change")}))},removeAttribute:async function(t){t.stopPropagation(),t.preventDefault();const a=await dokan_sweetalert(dokan.remove_attribute,{action:"confirm",icon:"warning"});if("undefined"!==a&&a.isConfirmed){var o=e(this).closest("li.product-attribute-list");o.fadeOut(300,(function(){o.is(".taxonomy")?(o.find("select, input[type=text]").val(""),e("select.dokan_attribute_taxonomy").find('option[value="'+o.data("taxonomy")+'"]').removeAttr("disabled")):(o.find("select, input[type=text]").val(""),o.hide()),n.attribute.reArrangeAttribute()}))}return!1},saveAttribute:function(t){t.preventDefault(),e(this);var a={post_id:e("#dokan-edit-product-id").val(),data:e("ul.dokan-attribute-option-list").find("input, select, textarea").serialize(),action:"dokan_save_attributes"};e(".dokan-product-attribute-wrapper").block({message:null,fadeIn:50,fadeOut:1e3,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,a,(function(t){e("#dokan-variable-product-options").load(window.location.toString()+" #dokan-variable-product-options-inner",(function(){e("#dokan-variable-product-options").trigger("reload"),e("select#product_type").trigger("change"),e(".dokan-product-attribute-wrapper").unblock()}))}))},disbalePredefinedAttribute:function(){e("ul.dokan-attribute-option-list li.product-attribute-list").each((function(t,a){"none"!==e(a).css("display")&&e(a).is(".taxonomy")&&e("select#predefined_attribute").find('option[value="'+e(a).data("taxonomy")+'"]').attr("disabled","disabled")}))}},inputValidate:function(t){return t.preventDefault(),""==e("#post_title").val().trim()?(e("#post_title").focus(),void e("div.dokan-product-title-alert").removeClass("dokan-hide")):(e("div.dokan-product-title-alert").hide(),-1==e("select.product_cat").val()?(e("select.product_cat").focus(),void e("div.dokan-product-cat-alert").removeClass("dokan-hide")):(e("div.dokan-product-cat-alert").hide(),e("input[type=submit]").attr("disabled","disabled"),void this.submit()))},downloadable:function(){e(this).prop("checked")?e(this).closest("aside").find(".dokan-side-body").removeClass("dokan-hide"):e(this).closest("aside").find(".dokan-side-body").addClass("dokan-hide")},showDiscountSchedule:function(t){t.preventDefault(),e(".sale-schedule-container").slideToggle("fast")},showManageStock:function(t){const a=e("#product_type").val();e(this).is(":checked")&&"external"!==a?e(".show_if_stock").slideDown("fast"):e(".show_if_stock").slideUp("fast"),"simple"===a&&(e(this).is(":checked")?e(".hide_if_stock_global").slideUp("fast"):e(".hide_if_stock_global").slideDown("fast"))},gallery:{addImages:function(a){a.preventDefault();var n=e(this),o=n.closest(".dokan-product-gallery").find("#product_images_container ul.product_images"),i=n.closest(".dokan-product-gallery").find("#product_image_gallery");t||(t=wp.media({title:dokan.i18n_choose_gallery,library:{type:"image"},button:{text:dokan.i18n_choose_gallery_btn_text},multiple:!0})).on("select",(function(){t.state().get("selection").map((function(t){t=t.toJSON(),attachment_ids=[],t.id&&"image"===t.type&&(e('
  • ×
  • ').insertBefore(o.find("li.add-image")),e("#product_images_container ul li.image").css("cursor","default").each((function(){var e=jQuery(this).attr("data-attachment_id");attachment_ids.push(e)})),i.val(attachment_ids.join(",")))}))})),t.open()},deleteImage:function(t){t.preventDefault();var a=e(this),n=(a.closest(".dokan-product-gallery").find("#product_images_container ul.product_images"),a.closest(".dokan-product-gallery").find("#product_image_gallery"));a.closest("li.image").remove();var o=[];return e("#product_images_container ul li.image").css("cursor","default").each((function(){var t=e(this).attr("data-attachment_id");o.push(t)})),n.val(o.join(",")),!1},sortable:function(){e("body").find("#product_images_container ul.product_images").sortable({items:"li.image",cursor:"move",scrollSensitivity:40,forcePlaceholderSize:!0,forceHelperSize:!1,helper:"clone",opacity:.65,placeholder:"dokan-sortable-placeholder",start:function(e,t){t.item.css("background-color","#f6f6f6")},stop:function(e,t){t.item.removeAttr("style")},update:function(t,a){var n=[];e("body").find("#product_images_container ul li.image").css("cursor","default").each((function(){var e=jQuery(this).attr("data-attachment_id");n.push(e)})),e("body").find("#product_image_gallery").val(n.join(","))}})}},featuredImage:{addImage:function(t){t.preventDefault();var n=e(this);a||(a=wp.media({title:dokan.i18n_choose_featured_img,library:{type:"image"},button:{text:dokan.i18n_choose_featured_img_btn_text}})).on("select",(function(){a.state().get("selection").map((function(e){if("image"===(e=e.toJSON()).type){n.siblings("input.dokan-feat-image-id").val(e.id);var t=n.closest(".instruction-inside"),a=t.siblings(".image-wrap");a.find("img").attr("src",e.url),a.find("img").removeAttr("srcset"),t.addClass("dokan-hide"),a.removeClass("dokan-hide")}}))})),a.open()},removeImage:function(t){t.preventDefault();var a=e(this).closest(".image-wrap"),n=a.siblings(".instruction-inside");n.find("input.dokan-feat-image-id").val("0"),a.addClass("dokan-hide"),n.removeClass("dokan-hide")}},fileDownloadable:function(t){t.preventDefault();var a,n=e(this);a||((a=wp.media({title:dokan.i18n_choose_file,button:{text:dokan.i18n_choose_file_btn_text},multiple:!0})).on("select",(function(){a.state().get("selection").map((function(e){e=e.toJSON(),n.closest("tr").find("input.wc_file_url, input.wc_variation_file_url").val(e.url)}))})),a.on("ready",(function(){a.uploader.options.uploader.params={type:"downloadable_product"}}))),a.open()}};e((function(){function t(){var t=e("#product_type").val(),a=e("input#_virtual:checked").length,n=e("input#_downloadable:checked").length;let o=e(".dokan-product-shipping-tax");var i=".hide_if_downloadable, .hide_if_virtual",r=".show_if_downloadable, .show_if_virtual";e.each(Object.keys(dokan.product_types),(function(e,t){i=i+", .hide_if_"+t,r=r+", .show_if_"+t})),e(i).show(),e(r).hide(),n&&e(".show_if_downloadable").show(),a&&e(".show_if_virtual").show(),e(".show_if_"+t).show(),n&&e(".hide_if_downloadable").hide(),a?(e(".hide_if_virtual").hide(),1===e(".dokan-product-shipping-tax .dokan-section-content").first().children().length?o.hide():(o.hasClass("hide_if_virtual")&&o.removeClass("hide_if_virtual"),o.show())):o.show(),e(".hide_if_"+t).hide(),e("input#_manage_stock").trigger("change")}n.init(),e("select#product_type").on("change",(function(){var a=e(this).val();"variable"===a&&(e("input#_manage_stock").trigger("change"),e("input#_downloadable").prop("checked",!1),e("input#_virtual").removeAttr("checked")),t(),e(document.body).trigger("dokan-product-type-change",a,e(this))})).trigger("change"),e(".product-edit-container").on("change","input#_downloadable, input#_virtual",(function(){t()})).trigger("change"),e("input#_downloadable").trigger("change"),e("input#_virtual").trigger("change"),e(".sale_price_dates_fields").each((function(){var t=e(this),a=!1,n=t.closest("div, table");t.find("input").each((function(){""!==e(this).val()&&(a=!0)})),a?(n.find(".sale_schedule").hide(),n.find(".sale_price_dates_fields").show()):(n.find(".sale_schedule").show(),n.find(".sale_price_dates_fields").hide())})),e(".product-edit-container").on("click",".sale_schedule",(function(){var t=e(this).closest(".product-edit-container, div.dokan-product-variation-itmes, table");return e(this).hide(),t.find(".cancel_sale_schedule").show(),t.find(".sale_price_dates_fields").show(),!1})),e(".product-edit-container").on("click",".cancel_sale_schedule",(function(){var t=e(".product-edit-container, div.dokan-product-variation-itmes, table");return e(this).hide(),t.find(".sale_schedule").show(),t.find(".sale_price_dates_fields").hide(),t.find(".sale_price_dates_fields").find("input").val(""),!1})),e("#dokan-product-title-area").on("click",".edit-slug",(function(){!function(){var t,a,n,o,i=0,r=e("#post_name"),d=r.val(),s=e("#sample-permalink"),l=s.html(),c=e("#sample-permalink a").html(),u=e("#edit-slug-buttons"),p=u.html(),m=e("#editable-post-name-full");for(m.find("img").replaceWith((function(){return this.alt})),m=m.html(),s.html(c),n=e("#editable-post-name"),o=n.html(),u.html(' "),u.children(".save").on("click",(function(){var t=n.children("input").val();t!=e("#editable-post-name-full").text()?e.post(ajaxurl,{action:"sample-permalink",post_id:e("#dokan-edit-product-id").val(),new_slug:t,new_title:e("#post_title").val(),samplepermalinknonce:e("#samplepermalinknonce").val()},(function(a){var n=e("#edit-slug-box");n.html(a),n.hasClass("hidden")&&n.fadeIn("fast",(function(){n.removeClass("hidden")})),u.html(p),s.html(l),r.val(t),e(".edit-slug").focus(),e("#editable-post-name-full-dokan").val(e("#editable-post-name-full").html())})):u.children(".cancel").trigger("click")})),u.children(".cancel").on("click",(function(){e("#view-post-btn").show(),n.html(o),u.html(p),s.html(l),r.val(d),e(".edit-slug").focus()})),t=0;tm.length/4?"":m,n.html('').children("input").on("keydown",(function(e){var t=e.which;13===t&&(e.preventDefault(),u.children(".save").trigger("click")),27===t&&u.children(".cancel").trigger("click")})).on("keyup",(function(){r.val(this.value)})).focus()}()})),e("#dokan-edit-product-id").val()&&e("#post_title").val()&&e("#samplepermalinknonce").val()&&e.post(ajaxurl,{action:"sample-permalink",post_id:e("#dokan-edit-product-id").val(),new_slug:e("#edited-post-name-dokan").val(),new_title:e("#post_title").val(),samplepermalinknonce:e("#samplepermalinknonce").val()},(function(t){e("#edit-slug-box").html(t)})),e(window).on("load",(function(){e("input#_virtual:checked").length&&t()}))}))}(jQuery),jQuery((function(e){function t(e,t,a){jQuery('
    '+a+"
    ").css({top:t-16,left:e+20}).appendTo("body").fadeIn(200)}wp.customize,e(".datepicker").datepicker({dateFormat:"yy-mm-dd"}),e(".dokan-table tbody").on("click",".toggle-row",(function(){e(this).closest("tr").toggleClass("is-expanded")})),e(".dokan-start-date").datepicker({defaultDate:"",dateFormat:"yy-mm-dd",numberOfMonths:1,onSelect:function(t){let a=new Date(t);a.setDate(a.getDate()+1),e(".dokan-end-date").datepicker("option",{minDate:a})}}),e(".dokan-end-date").datepicker({defaultDate:"",dateFormat:"yy-mm-dd",numberOfMonths:1,onSelect:function(t){let a=new Date(t);a.setDate(a.getDate()-1),e("dokan-start-date").datepicker("option",{maxDate:a})}}),e(".tips").tooltip();var a=null,n=null;jQuery(".chart-placeholder").on("plothover",(function(e,o,i){if(i){if((a!=i.dataIndex||n!=i.seriesIndex)&&(a=i.dataIndex,n=i.seriesIndex,jQuery(".chart-tooltip").remove(),i.series.points.show||i.series.enable_tooltip)){var r=i.series.data[i.dataIndex][1];tooltip_content="",i.series.prepend_label&&(tooltip_content=tooltip_content+i.series.label+": "),i.series.prepend_tooltip&&(tooltip_content+=i.series.prepend_tooltip),tooltip_content+=r,i.series.append_tooltip&&(tooltip_content+=i.series.append_tooltip),i.series.pie.show?t(o.pageX,o.pageY,tooltip_content):t(i.pageX,i.pageY,tooltip_content)}}else jQuery(".chart-tooltip").remove(),a=null}))})),function(e){e.validator.setDefaults({ignore:":hidden"});var t=function(t,a){e(a).closest(".dokan-form-group").addClass("has-error").append(t)},a=function(t,a){e(a).closest(".dokan-form-group").removeClass("has-error"),e(t).remove()},n=wp.customize,o='input[name="settings[bank][disconnect]"], input[name="settings[paypal][disconnect]"], input[name="settings[skrill][disconnect]"], input[name="settings[dokan_custom][disconnect]"]',i={init:function(){return e("a.dokan-banner-drag").on("click",this.imageUpload),e("a.dokan-remove-banner-image").on("click",this.removeBanner),e("a.dokan-pro-gravatar-drag").on("click",this.gragatarImageUpload),e("a.dokan-gravatar-drag").on("click",this.simpleImageUpload),e("a.dokan-remove-gravatar-image").on("click",this.removeGravatar),e(".dokan-update-setting-top-button").on("click",(function(){e("input[name='dokan_update_store_settings']").trigger("click")})),this.validateForm(this),e(".dokan_payment_disconnect_btn").on("click",(function(){var t=e(this).closest("form"),a=e("form#"+t.attr("id"));e(":input",t).not(":button, :submit, :reset, :hidden, :checkbox").val("").prop("selected",!1);var n=t.serializeArray().reduce((function(e,t){return e[t.name]=t.value,e}),{});n[e(this).attr("name")]="",n.form_id=t.attr("id"),n.action="dokan_settings",i.handleRequest(a,n,!0)})),!1},calculateImageSelectOptions:function(e,t){var a,o,i,r,d,s,l=parseInt(dokan.store_banner_dimension.width,10),c=parseInt(dokan.store_banner_dimension.height,10),u=!!parseInt(dokan.store_banner_dimension["flex-width"],10),p=!!parseInt(dokan.store_banner_dimension["flex-height"],10);return d=e.get("width"),r=e.get("height"),this.headerImage=new n.HeaderTool.ImageModel,this.headerImage.set({themeWidth:l,themeHeight:c,themeFlexWidth:u,themeFlexHeight:p,imageWidth:d,imageHeight:r}),t.set("canSkipCrop",!this.headerImage.shouldBeCropped()),(o=d)/(i=r)>(a=l/c)?l=(c=i)*a:c=(l=o)/a,s={handles:!0,keys:!0,instance:!0,persistent:!0,imageWidth:d,imageHeight:r,x1:0,y1:0,x2:l,y2:c},!1===p&&!1===u&&(s.aspectRatio=l+":"+c),!1===p&&(s.maxHeight=c),!1===u&&(s.maxWidth=l),s},onSelect:function(){this.frame.setState("cropper")},onCropped:function(e){var t=e.url,a=e.attachment_id,n=e.width,o=e.height;this.setImageFromURL(t,a,n,o)},onSkippedCrop:function(e){var t=e.get("url"),a=e.get("width"),n=e.get("height");this.setImageFromURL(t,e.id,a,n)},setImageFromURL:function(t,a,n,o){var i=!1;if(e(this.uploadBtn).hasClass("dokan-banner-drag"))(r=e(this.uploadBtn).closest(".dokan-banner")).find("input.dokan-file-field").val(a),r.find("img.dokan-banner-img").attr("src",t),e(this.uploadBtn).parent().siblings(".image-wrap",r).removeClass("dokan-hide"),e(this.uploadBtn).parent(".button-area").addClass("dokan-hide"),i=!0;else if(e(this.uploadBtn).hasClass("dokan-pro-gravatar-drag")){var r;(r=e(this.uploadBtn).closest(".dokan-gravatar")).find("input.dokan-file-field").val(a),r.find("img.dokan-gravatar-img").attr("src",t),i=!0,e(this.uploadBtn).parent().siblings(".gravatar-wrap",r).removeClass("dokan-hide"),e(this.uploadBtn).parent(".gravatar-button-area").addClass("dokan-hide")}!0===i&&(e(window).on("beforeunload",(function(){return dokan.dokan_banner_added_alert_msg})),e(document).ready((function(){e("#store-form").on("submit",(function(t){return e(window).off("beforeunload"),!0}))})))},removeImage:function(){n.HeaderTool.currentHeader.trigger("hide"),n.HeaderTool.CombinedList.trigger("control:removeImage")},imageUpload:function(e){e.preventDefault();var t=i;t.uploadBtn=this,t.frame=wp.media({multiple:!1,button:{text:dokan.selectAndCrop,close:!1},states:[new wp.media.controller.Library({title:dokan.chooseImage,library:wp.media.query({type:"image"}),multiple:!1,date:!1,priority:20,suggestedWidth:dokan.store_banner_dimension.width,suggestedHeight:dokan.store_banner_dimension.height}),new wp.media.controller.Cropper({suggestedWidth:5e3,imgSelectOptions:t.calculateImageSelectOptions})]}),t.frame.on("select",t.onSelect,t),t.frame.on("cropped",t.onCropped,t),t.frame.on("skippedcrop",t.onSkippedCrop,t),t.frame.open()},calculateImageSelectOptionsProfile:function(e,t){var a,o,i,r,d,s,l=150,c=150,u=!!parseInt(dokan.store_banner_dimension["flex-width"],10),p=!!parseInt(dokan.store_banner_dimension["flex-height"],10);return d=e.get("width"),r=e.get("height"),this.headerImage=new n.HeaderTool.ImageModel,this.headerImage.set({themeWidth:l,themeHeight:c,themeFlexWidth:u,themeFlexHeight:p,imageWidth:d,imageHeight:r}),t.set("canSkipCrop",!this.headerImage.shouldBeCropped()),(o=d)/(i=r)>(a=l/c)?l=(c=i)*a:c=(l=o)/a,s={handles:!0,keys:!0,instance:!0,persistent:!0,imageWidth:d,imageHeight:r,x1:0,y1:0,x2:l,y2:c},!1===p&&!1===u&&(s.aspectRatio=l+":"+c),!1===p&&(s.maxHeight=c),!1===u&&(s.maxWidth=l),s},simpleImageUpload:function(t){t.preventDefault();var a,n=e(this);a||(a=wp.media.frames.file_frame=wp.media({title:jQuery(this).data("uploader_title"),button:{text:jQuery(this).data("uploader_button_text")},multiple:!1})).on("select",(function(){var e=a.state().get("selection").first().toJSON(),t=n.closest(".dokan-gravatar");t.find("input.dokan-file-field").val(e.id),t.find("img.dokan-gravatar-img").attr("src",e.url),n.parent().siblings(".gravatar-wrap",t).removeClass("dokan-hide"),n.parent(".gravatar-button-area").addClass("dokan-hide")})),a.open()},gragatarImageUpload:function(e){e.preventDefault();var t=i;t.uploadBtn=this,t.frame=wp.media({multiple:!1,button:{text:dokan.selectAndCrop,close:!1},states:[new wp.media.controller.Library({title:dokan.chooseImage,library:wp.media.query({type:"image"}),multiple:!1,date:!1,priority:20,suggestedWidth:150,suggestedHeight:150}),new wp.media.controller.Cropper({imgSelectOptions:t.calculateImageSelectOptionsProfile})]}),t.frame.on("select",t.onSelect,t),t.frame.on("cropped",t.onCropped,t),t.frame.on("skippedcrop",t.onSkippedCrop,t),t.frame.open()},submitSettings:function(t){"undefined"!=typeof tinyMCE&&tinyMCE.triggerSave();var a=e("form#"+t),n=a.serialize()+"&action=dokan_settings&form_id="+t;i.handleRequest(a,n,!1)},handleRequest:function(t,a,n){n?t.find(".ajax_prev.disconnect").append(' '):t.find(".ajax_prev.save").append(' '),e(".dokan-update-setting-top-button span.dokan-loading").remove(),e(".dokan-update-setting-top-button").append(' '),e.post(dokan.ajaxurl,a,(function(a){t.find("span.dokan-loading").remove(),e(".dokan-update-setting-top-button span.dokan-loading").remove(),e("html,body").animate({scrollTop:e(".dokan-dashboard-header").offset().top}),a.success?(e(".dokan-ajax-response").html(e("
    ",{class:"dokan-alert dokan-alert-success",html:"

    "+a.data.msg+"

    "})),e(".dokan-ajax-response").append(a.data.progress),dokan&&dokan.storeProgressBar&&dokan.storeProgressBar.init(),o=o.replaceAll("input","button"),n?t.find(o).addClass("dokan-hide"):t.find(o).removeClass("dokan-hide")):e(".dokan-ajax-response").html(e("
    ",{class:"dokan-alert dokan-alert-danger",html:"

    "+a.data+"

    "}))}))},validateForm:function(n){e("form#settings-form, form#profile-form, form#store-form, form#payment-form").validate({submitHandler:function(e){n.submitSettings(e.getAttribute("id"))},errorElement:"span",errorClass:"error",errorPlacement:t,success:a,ignore:".select2-search__field, :hidden, .mapboxgl-ctrl-geocoder--input"})},removeBanner:function(t){t.preventDefault();var a=e(this).closest(".image-wrap"),n=a.siblings(".button-area");a.find("input.dokan-file-field").val("0"),a.addClass("dokan-hide"),n.removeClass("dokan-hide")},removeGravatar:function(t){t.preventDefault();var a=e(this).closest(".gravatar-wrap"),n=a.siblings(".gravatar-button-area");a.find("input.dokan-file-field").val("0"),a.addClass("dokan-hide"),n.removeClass("dokan-hide")}},r={init:function(){this.withdrawValidate(this)},withdrawValidate:function(n){e("form.withdraw").validate({errorElement:"span",errorClass:"error",errorPlacement:t,success:a})}},d={init:function(){this.validate(this)},validate:function(a){e("form#dokan-form-contact-seller").validate({errorPlacement:t,errorElement:"span",success:function(e,t){e.removeClass("error"),e.remove()},submitHandler:async function(t,a){a.preventDefault(),e(t).block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}}),await dokan_execute_recaptcha("form#dokan-form-contact-seller .dokan_recaptcha_token","dokan_contact_seller_recaptcha");var n=e(t).serialize();e.post(dokan.ajaxurl,n,(function(a){e(t).unblock(),void 0!==a.data&&e(t).find(".ajax-response").html(a.data),e(t).find("input[type=text], input[type=email], textarea, input[name=dokan_recaptcha_token]").val("").removeClass("valid")}))}})}};e((function(){i.init(),r.init(),d.init(),e(".dokan-form-horizontal").on("change","input[type=checkbox]#lbl_setting_minimum_quantity",(function(){var t=e(".show_if_needs_sw_discount");e(this).is(":checked")?(t.find('input[type="number"]').val(""),t.slideDown("slow")):t.slideUp("slow")}))}))}(jQuery),function(e){var t=DokanValidateMsg;t.maxlength=e.validator.format(t.maxlength_msg),t.minlength=e.validator.format(t.minlength_msg),t.rangelength=e.validator.format(t.rangelength_msg),t.range=e.validator.format(t.range_msg),t.max=e.validator.format(t.max_msg),t.min=e.validator.format(t.min_msg),e.validator.messages=t,e(document).on("click","#dokan_store_tnc_enable",(function(t){e(this).is(":checked")?e("#dokan_tnc_text").show():e("#dokan_tnc_text").hide()})).ready((function(t){e("#dokan_store_tnc_enable").is(":checked")?e("#dokan_tnc_text").show():e("#dokan_tnc_text").hide()}))}(jQuery),function(e){var t="undefined"!=typeof wp&&wp.customize&&wp.customize.selectiveRefresh;function a(){dokan.store_banner_dimension.width;var t=dokan.store_banner_dimension.height/dokan.store_banner_dimension.width*e("#dokan-content").width();e(".dokan-profile-frame-wrapper .profile-info-img.dummy-image").css({height:t})}a(),e(window).on("resize",(function(e){a()})),t&&wp.customize.selectiveRefresh.bind("partial-content-rendered",(function(e){console.log("placement",e),"store_header_template"===e.partial.id&&a()})),e(":input.dokan-product-search").filter(":not(.enhanced)").each((function(){var t={allowClear:!!e(this).data("allow_clear"),placeholder:e(this).data("placeholder"),minimumInputLength:e(this).data("minimum_input_length")?e(this).data("minimum_input_length"):"3",escapeMarkup:function(e){return e},language:{errorLoading:function(){return dokan.i18n_searching},inputTooLong:function(e){var t=e.input.length-e.maximum;return 1===t?dokan.i18n_input_too_long_1:dokan.i18n_input_too_long_n.replace("%qty%",t)},inputTooShort:function(e){var t=e.minimum-e.input.length;return 1===t?dokan.i18n_input_too_short_1:dokan.i18n_input_too_short_n.replace("%qty%",t)},loadingMore:function(){return dokan.i18n_load_more},maximumSelected:function(e){return 1===e.maximum?dokan.i18n_selection_too_long_1:dokan.i18n_selection_too_long_n.replace("%qty%",e.maximum)},noResults:function(){return dokan.i18n_no_matches},searching:function(){return dokan.i18n_searching}},ajax:{url:dokan.ajaxurl,dataType:"json",delay:250,data:function(t){return{term:t.term,action:e(this).data("action")||"dokan_json_search_products_and_variations",security:dokan.search_products_nonce,exclude:e(this).data("exclude"),user_ids:e(this).data("user_ids"),include:e(this).data("include"),limit:e(this).data("limit")}},processResults:function(t){var a=[];return t&&e.each(t,(function(e,t){a.push({id:e,text:t})})),{results:a}},cache:!0}};if(e(this).select2(t).addClass("enhanced"),e(this).data("sortable")){var a=e(this),n=e(this).next(".select2-container").find("ul.select2-selection__rendered");n.sortable({placeholder:"ui-state-highlight select2-selection__choice",forcePlaceholderSize:!0,items:"li:not(.select2-search__field)",tolerance:"pointer",stop:function(){e(n.find(".select2-selection__choice").get().reverse()).each((function(){var t=e(this).data("data").id,n=a.find('option[value="'+t+'"]')[0];a.prepend(n)}))}})}})),selected_items=[],e("#cb-select-all").on("change",(function(t){var a=e(this),n=e(".cb-select-items");a.is(":checked")?n.each((function(t,a){e(a).prop("checked","checked")})):n.each((function(t,a){e(a).prop("checked",""),selected_items.pop()}))}))}(jQuery),function(e){function t(t,a){const n=e(t.target).closest("li.has-submenu");n.find(".navigation-submenu").each(((t,o)=>{if(a)n.removeClass("submenu-hovered"),e(".dokan-dashboard-wrap").css("height",""),e(o).css("bottom",0),e(o).removeAttr("style");else{n.addClass("submenu-hovered");let t=n[0].getBoundingClientRect(),a=o.getBoundingClientRect(),i=e(".dokan-dashboard-wrap"),r=i[0].getBoundingClientRect(),d=Math.min(r.bottom,r.height);if(d0)e(o).css("bottom",0),a=o.getBoundingClientRect(),a.top<0&&(e(o).css("bottom","unset"),e(o).css("top",0));else{e(o).css("bottom",n);let t=e(".dokan-dash-sidebar")[0].getBoundingClientRect(),i=e(".entry-header")[0].getBoundingClientRect();a=o.getBoundingClientRect(),a.bottom>t.bottom?n+=a.bottom-t.bottom:a.bottom-i.bottom'+dokan[n]+"
    "),a.parent().find(".wc_error_tip").css("left",o.left+a.width()-a.width()/2-e(".wc_error_tip").width()/2).css("top",o.top+a.height()).fadeIn("100"))})).on("wc_remove_error_tip",(function(t,a,n){a.parent().find(".wc_error_tip."+n).fadeOut("100",(function(){e(this).remove()}))})).on("click",(function(){e(".wc_error_tip").fadeOut("100",(function(){e(this).remove()}))})).on("blur",".wc_input_decimal[type=text], .wc_input_price[type=text], .wc_input_country_iso[type=text]",(function(){e(".wc_error_tip").fadeOut("100",(function(){e(this).remove()}))})).on("change",".wc_input_price[type=text], .wc_input_decimal[type=text], .wc-order-totals #refund_amount[type=text]",(function(){var t,a,n=dokan.decimal_point;(e(this).is(".wc_input_price")||e(this).is("#refund_amount"))&&(n=dokan.mon_decimal_point),t=new RegExp("[^-0-9%\\"+n+"]+","gi"),a=new RegExp("\\"+n+"+","gi");var o=e(this).val(),i=o.replace(t,"").replace(a,n);o!==i&&e(this).val(i)})).on("keyup",".wc_input_price[type=text], .wc_input_decimal[type=text], .wc_input_country_iso[type=text], .wc-order-totals #refund_amount[type=text]",(function(){var t,a,n,o=!1;e(this).is(".wc_input_price")||e(this).is("#refund_amount")?(o=!0,t=new RegExp("[^-0-9%\\"+dokan.mon_decimal_point+"]+","gi"),n=new RegExp("[^\\"+dokan.mon_decimal_point+"]","gi"),a="i18n_mon_decimal_error"):e(this).is(".wc_input_country_iso")?(t=new RegExp("([^A-Z])+|(.){3,}","im"),a="i18n_country_iso_error"):(o=!0,t=new RegExp("[^-0-9%\\"+dokan.decimal_point+"]+","gi"),n=new RegExp("[^\\"+dokan.decimal_point+"]","gi"),a="i18n_decimal_error");var i=e(this).val(),r=i.replace(t,"");o&&1=parseFloat(window.accounting.unformat(t.val(),dokan.mon_decimal_point))&&e(this).val("")})).on("keyup","#_sale_price.wc_input_price[type=text], .wc_input_price[name^=variable_sale_price], #_subscription_sale_price.wc_input_price[type=text]",(function(){var t,a=e(this),n=e("#product_type");t=-1!==a.attr("name").indexOf("variable")?a.parents(".variable_pricing").find(".wc_input_price[name^=variable_regular_price]"):n.length&&"subscription"===n.find(":selected").val()?e("#_subscription_price"):e("#_regular_price"),parseFloat(window.accounting.unformat(a.val(),dokan.mon_decimal_point))>=parseFloat(window.accounting.unformat(t.val(),dokan.mon_decimal_point))?e(document.body).triggerHandler("wc_add_error_tip",[e(this),"i18n_sale_less_than_regular_error"]):e(document.body).triggerHandler("wc_remove_error_tip",[e(this),"i18n_sale_less_than_regular_error"])})).on("init_tooltips",(function(){e(".tips, .help_tip, .woocommerce-help-tip").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}),e(".column-wc_actions .wc-action-button").tipTip({fadeIn:50,fadeOut:50,delay:200}),e(".parent-tips").each((function(){e(this).closest("a, th").attr("data-tip",e(this).data("tip")).tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}).css("cursor","help")}))})),e("#dokan-navigation .dokan-dashboard-menu li.has-submenu:not(.active)").on("mouseover",(e=>{t(e)})).on("mouseout",(e=>{t(e,!0)}))}(jQuery),window.dokan_show_delete_prompt=async function(e,t){e.preventDefault();let a=await dokan_sweetalert(t,{action:"confirm",icon:"warning"});if(a.isConfirmed&&void 0!==e.target.href)window.location.href=e.target.href;else{if(!a.isConfirmed||void 0===e.target.dataset.url)return!1;window.location.href=e.target.dataset.url}},window.dokan_bulk_delete_prompt=async function(e,t,a,n){"delete"===jQuery(a).val()&&(e.preventDefault(),(await dokan_sweetalert(t,{action:"confirm",icon:"warning"})).isConfirmed&&jQuery(n).submit())},function(e){var t={query:{},form:null,cateItemStringArray:[],init:function(){e("#dokan-store-listing-filter-wrap .sort-by #stores_orderby").on("change",this.buildSortByQuery),e("#dokan-store-listing-filter-wrap .toggle-view span").on("click",this.toggleView),e("#dokan-store-listing-filter-wrap .dokan-store-list-filter-button, #dokan-store-listing-filter-wrap .dokan-icons, #dokan-store-listing-filter-form-wrap .apply-filter #cancel-filter-btn ").on("click",this.toggleForm),e("#dokan-store-listing-filter-form-wrap .store-search-input").on("change",this.buildSearchQuery),e("#dokan-store-listing-filter-form-wrap .apply-filter #apply-filter-btn").on("click",this.submitForm),this.maybeHideListView();const a=t;a.form=document.forms.dokan_store_lists_filter_form;const n=a.getLocal("dokan-layout");if(n){const t=e(".toggle-view span");a.setView(n,t)}const o=a.getParams();if(o.length){let t=!1;o.forEach((function(e){const n=Object.keys(e),i=Object.values(e);(!n.includes("stores_orderby")||o.length>1)&&(t=!0),a.setParams(n,i)})),t&&e("#dokan-store-listing-filter-form-wrap").slideToggle()}var i,r;e("#dokan-store-listing-filter-form-wrap").length&&e(".store-search-input").on("keypress",(function(t){if(13==t.which)return e("#dokan-store-listing-filter-form-wrap").submit(),!1})),e("body").on("click",(function(t){e(t.target).is("div#dokan-store-products-search-result li")||(e("#dokan-store-products-search-result").html(""),e("#dokan-store-products-search-result").removeClass("dokan-store-products-search-has-results"))})),e("body").on("keyup",".dokan-store-products-filter-search",(i=function(t){t.preventDefault();var a=e(this),n=a.val(),o=a.data("store_id");n&&(e(".dokan-store-products-filter-search").addClass("dokan-ajax-search-loader"),e("#dokan-store-products-search-result").removeClass("dokan-store-products-search-has-results"),e("#dokan-store-products-search-result").hide(),e("#dokan-store-products-search-result").html(""),jQuery.ajax({type:"post",dataType:"json",url:dokan.ajaxurl,data:{search_term:n,store_id:o,_wpnonce:dokan.store_product_search_nonce,action:"dokan_store_product_search_action"},success:function(t){e(".dokan-store-products-filter-search").removeClass("dokan-ajax-search-loader"),e("#dokan-store-products-search-result").show(),e("#dokan-store-products-search-result").addClass("dokan-store-products-search-has-results"),"success"==t.type?e("#dokan-store-products-search-result").html("
      "+t.data_list+"
    "):e("#dokan-store-products-search-result").html('
      '+t.data_list+"
    ")}}))},500,r=0,function(){var e=this,t=arguments;clearTimeout(r),r=setTimeout((function(){i.apply(e,t)}),500)}))},buildSortByQuery:function(e){const a=t;a.query.stores_orderby=e.target.value,a.submitForm(e)},toggleView:function(a){const n=t,o=e(a.target),i=o.parent().find("span"),r=o.data("view");n.setView(r,i),n.setLocal("dokan-layout",r)},setView:function(t,a){if(void 0===t||t.length<1||void 0===a||a.length<1)return;const n=e("#dokan-seller-listing-wrap");[...a].forEach((function(a){const o=e(a);t===o.data("view")?(o.addClass("active"),n.addClass(t)):(o.removeClass("active"),n.removeClass(o.data("view")))}))},toggleForm:function(t){t.preventDefault(),e("#dokan-store-listing-filter-form-wrap").slideToggle()},buildSearchQuery:function(e){e.target.value?t.query.dokan_seller_search=e.target.value:delete t.query.dokan_seller_search},submitForm:function(a){a.preventDefault(),t.query._store_filter_nonce&&delete t.query._store_filter_nonce,t.query._store_filter_nonce=e('input[name="_store_filter_nonce"]').first().val();const n=decodeURIComponent(e.param(t.query)),o="/page",i=window.location.pathname,r=i.includes(o)?i.substr(0,i.indexOf(o)):"";window.history.pushState(null,null,`${r}?${n}`),window.location.reload()},setLocal:function(e,t){window.localStorage.setItem(e,t)},getLocal:function(e){return window.localStorage.getItem(e)},setParams:function(a,n){const o=t,i=o.form?o.form.elements:"",r=document.forms.stores_sorting,d=r?r.elements:"";Object.values(d).forEach((function(t){t.name===a[0]&&e(t).val(n[0])})),Object.values(i).forEach((function(t){if(a.includes(t.name)&&("checkbox"===t.type?t.checked=!!["yes","true","1"].includes(n[0]):["text","search"].includes(t.type)&&(t.value=n[0])),a[0].includes("store_categories[")||a[0].includes("store_category[")){const t=n[0].split(" ").join("-"),a=e(`[data-slug=${t}]`);o.cateItemStringArray.includes(a.text().trim())||o.cateItemStringArray.push(a.text().trim()),a.addClass("dokan-btn-theme")}else if("rating"===a[0]){const t=n[0].split(" ").join("-");e(`[data-${a[0]}=${t}]`).addClass("active"),e(`[data-rating=${t}]`).parent().addClass("selected")}})),a.forEach((function(e,t){e.includes("[")||(o.query[e]=n[t])}))},getParams:function(){const e=new URLSearchParams(location.search),t=[];return e.forEach((function(e,a){t.push({[a]:e})})),t},maybeHideListView:function(){const a=t;window.matchMedia("(max-width: 767px)").matches&&"list-view"===a.getLocal("dokan-layout")&&a.setLocal("dokan-layout","grid-view"),e(window).on("resize",(function(){e(this).width()<767?(e("#dokan-seller-listing-wrap").removeClass("list-view"),e("#dokan-seller-listing-wrap").addClass("grid-view")):(e(".toggle-view.item span").last().removeClass("active"),e(".toggle-view.item span").first().addClass("active"))}))}};window.dokan&&(window.dokan.storeLists=t,window.dokan.storeLists.init())}(jQuery),(e=>{const t={init:()=>{e("#dokan-request-withdraw-button").on("click",(e=>{e.preventDefault(),t.openRequestWithdrawWindow()})),e(".dokan-withdraw-make-default-button").on("click",(e=>{e.preventDefault(),t.makeDefault(e)})),e("#dokan-withdraw-request-submit").on("click",(e=>{t.handleWithdrawRequest(e)})),e("#dokan-withdraw-display-schedule-popup").on("click",(e=>{t.opensScheduleWindow(e)})),e("#dokan-withdraw-schedule-request-submit").on("click",(e=>{t.handleScheduleChangeRequest(e)})),e("input[name='withdraw-schedule']").on("change",(e=>{t.handleScheduleChange(e)}))},openRequestWithdrawWindow:()=>{const a=wp.template("withdraw-request-popup"),n=e("#dokan-withdraw-request-popup").iziModal({width:690,overlayColor:"rgba(0, 0, 0, 0.8)",headerColor:dokan.modal_header_color});n.iziModal("setContent",a().trim()),n.iziModal("open"),t.init()},opensScheduleWindow:()=>{const a=wp.template("withdraw-schedule-popup"),n=e("#dokan-withdraw-schedule-popup").iziModal({width:690,overlayColor:"rgba(0, 0, 0, 0.8)",headerColor:dokan.modal_header_color});n.iziModal("setContent",a().trim()),n.iziModal("open"),t.init()},makeDefault:t=>{const a=e(t.target),n=e("#dokan-withdraw-payment-method-list");n.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,{action:"dokan_withdraw_handle_make_default_method",nonce:n.data("security"),method:a.data("method")},(e=>{e.success?(dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"success",showConfirmButton:!1,timer:2e3,timerProgressBar:!0}),n.unblock(),window.location.reload()):(dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"error",showConfirmButton:!1,timer:2e3,timerProgressBar:!0}),n.unblock())}))},handleWithdrawRequest:t=>{t.preventDefault();const a=e("input#withdraw-amount").val(),n=e("input#dokan_withdraw_nonce").val(),o=e("#withdraw-request-popup"),i=e("#withdraw-method").val();o.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,{action:"dokan_handle_withdraw_request",_handle_withdraw_request:n,amount:a,method:i},(async e=>{e.success?await dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"success",showConfirmButton:!1,timer:2e3,timerProgressBar:!0,didOpen:e=>{setTimeout((function(){o.unblock(),window.location.reload()}),2e3)}}):(dokan_sweetalert("",{icon:"error",html:e.data}),o.unblock())}))},handleScheduleChangeRequest:t=>{t.preventDefault();const a=e("input[name='withdraw-schedule']:checked").val(),n=e("#dokan-withdraw-schedule-request-submit").data("security"),o=e("#withdraw-schedule-popup"),i=e("#withdraw-remaining-amount").val(),r=e("#minimum-withdraw-amount").val(),d=e("#preferred-payment-method").val();o.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,{action:"dokan_handle_withdraw_schedule_change_request",nonce:n,schedule:a,reserve:i,minimum:r,method:d},(e=>{e.success?(dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"success",showConfirmButton:!1,timer:2e3,timerProgressBar:!0}),o.unblock(),window.location.reload()):(dokan_sweetalert("",{icon:"error",html:e.data}),o.unblock())}))},handleScheduleChange:t=>{const a=e(t.target).data("next-schedule");e("#dokan-withdraw-next-scheduled-date").html(a)}};e(document).ready((function(){t.init()}))})(jQuery)})(); \ No newline at end of file +(()=>{var e,t;jQuery((function(e){e(".tips").tooltip(),e("ul.order-status").on("click","a.dokan-edit-status",(function(t){return e(this).addClass("dokan-hide").closest("li").next("li").removeClass("dokan-hide"),!1})),e("ul.order-status").on("click","a.dokan-cancel-status",(function(t){return e(this).closest("li").addClass("dokan-hide").prev("li").find("a.dokan-edit-status").removeClass("dokan-hide"),!1})),e("form#dokan-order-status-form").on("submit",(function(t){t.preventDefault();var a=e(this),n=a.closest("li");n.block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}}),e.post(dokan.ajaxurl,a.serialize(),(function(e){if(n.unblock(),e.success){var t=n.prev();n.addClass("dokan-hide"),t.find("label").replaceWith(e.data),t.find("a.dokan-edit-status").removeClass("dokan-hide")}else dokan_sweetalert(e.data,{icon:"success"})}))})),e("form#add-order-note").on("submit",(function(t){if(t.preventDefault(),e("textarea#add-note-content").val())return e("#dokan-order-notes").block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}}),e.post(dokan.ajaxurl,e(this).serialize(),(function(t){e("ul.order_notes").prepend(t),e("#dokan-order-notes").unblock(),e("#add-note-content").val("")})),!1})),e("#dokan-order-notes").on("click","a.delete_note",(function(){var t=e(this).closest("li.note");e("#dokan-order-notes").block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}});var a={action:"dokan_delete_order_note",note_id:e(t).attr("rel"),security:e("#delete-note-security").val()};return e.post(dokan.ajaxurl,a,(function(a){e(t).remove(),e("#dokan-order-notes").unblock()})),!1})),e(".order_download_permissions").on("click","button.grant_access",(function(){var t=e(this),a=e("select.grant_access_id").val();if(a){e(".order_download_permissions").block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}});var n={action:"dokan_grant_access_to_download",product_ids:a,loop:e(".order_download_permissions .panel").length,order_id:t.data("order-id"),security:t.data("nonce")};return e.post(dokan.ajaxurl,n,(function(t){t?e("#accordion").append(t):dokan_sweetalert(dokan.i18n_download_access,{icon:"warning"}),e(".datepicker").datepicker(),e(".order_download_permissions").unblock()})),!1}})),e(".order_download_permissions").on("click","button.revoke_access",(async function(t){t.preventDefault();const a=await dokan_sweetalert(dokan.i18n_download_permission,{action:"confirm",icon:"warning"});if("undefined"!==a&&a.isConfirmed){var n=e(this),o=n.closest(".dokan-panel"),i=n.attr("rel").split(",")[0],r=n.attr("rel").split(",")[1];if(i>0){e(o).block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}});var d={action:"dokan_revoke_access_to_download",product_id:i,download_id:r,order_id:n.data("order-id"),permission_id:n.data("permission-id"),security:n.data("nonce")};e.post(dokan.ajaxurl,d,(function(t){e(o).fadeOut("300",(function(){e(o).remove()}))}))}else e(o).fadeOut("300",(function(){e(o).remove()}))}return!1}))})),e=jQuery,(t={init:function(){let t={d:"dd",D:"D",j:"d",l:"DD",F:"MM",m:"mm",M:"M",n:"m",o:"yy",Y:"yy",y:"y"},a=0,n="",o="";for(a=0;a0?e("#restock_refunded_items").closest("tr").show():(e("#restock_refunded_items").closest("tr").hide(),e(".woocommerce_order_items input.refund_order_item_qty").each((function(){e(this).val()>0&&e("#restock_refunded_items").closest("tr").show()}))),e(this).trigger("refund_quantity_changed")}}}).init(),e("#dokan-filter-customer").filter(":not(.enhanced)").each((function(){var t={allowClear:!!e(this).data("allow_clear"),placeholder:e(this).data("placeholder"),minimumInputLength:e(this).data("minimum_input_length")?e(this).data("minimum_input_length"):"1",escapeMarkup:function(e){return e},language:{errorLoading:function(){return dokan.i18n_searching},inputTooLong:function(e){var t=e.input.length-e.maximum;return 1===t?dokan.i18n_input_too_long_1:dokan.i18n_input_too_long_n.replace("%qty%",t)},inputTooShort:function(e){var t=e.minimum-e.input.length;return 1===t?dokan.i18n_input_too_short_1:dokan.i18n_input_too_short_n.replace("%qty%",t)},loadingMore:function(){return dokan.i18n_load_more},maximumSelected:function(e){return 1===e.maximum?dokan.i18n_selection_too_long_1:dokan.i18n_selection_too_long_n.replace("%qty%",e.maximum)},noResults:function(){return dokan.i18n_no_matches},searching:function(){return dokan.i18n_searching}},ajax:{url:dokan.ajaxurl,dataType:"json",delay:1e3,data:function(t){return{term:t.term,action:"dokan_json_search_vendor_customers",security:dokan.search_customer_nonce,exclude:e(this).data("exclude")}},processResults:function(t){var a=[];return t&&e.each(t,(function(e,t){a.push({id:e,text:t})})),{results:a}},cache:!0}};if(e(this).select2(t).addClass("enhanced"),e(this).data("sortable")){var a=e(this),n=e(this).next(".select2-container").find("ul.select2-selection__rendered");n.sortable({placeholder:"ui-state-highlight select2-selection__choice",forcePlaceholderSize:!0,items:"li:not(.select2-search__field)",tolerance:"pointer",stop:function(){e(n.find(".select2-selection__choice").get().reverse()).each((function(){var t=e(this).data("data").id,n=a.find('option[value="'+t+'"]')[0];a.prepend(n)}))}})}})),function(e){e("#variants-holder"),e("#product_image_gallery"),e("#product_images_container ul.product_images");var t,a,n={modal:!1,init:function(){product_type="simple",e(".product-edit-container").on("click",".dokan-section-heading",this.toggleProductSection),e(".product-edit-container").on("click","input[type=checkbox]#_downloadable",this.downloadable),e(".product-edit-container").on("click","a.sale-schedule",this.showDiscountSchedule),e("body, #dokan-product-images").on("click","a.add-product-images",this.gallery.addImages),e("body, #dokan-product-images").on("click","a.action-delete",this.gallery.deleteImage),this.gallery.sortable(),e("body, .product-edit-container").on("click","a.dokan-feat-image-btn",this.featuredImage.addImage),e("body, .product-edit-container").on("click","a.dokan-remove-feat-image",this.featuredImage.removeImage),e("body, #variable_product_options").on("click",".sale_schedule",this.saleSchedule),e("body, #variable_product_options").on("click",".cancel_sale_schedule",this.cancelSchedule),e(".product-edit-container").on("change","input[type=checkbox]#_manage_stock",this.showManageStock),e(".product-edit-container").on("click","a.upload_file_button",this.fileDownloadable),e("body").on("click","a.insert-file-row",(function(){return e(this).closest("table").find("tbody").append(e(this).data("row")),!1})),e("body").on("click","a.dokan-product-delete",(function(){return e(this).closest("tr").remove(),!1})),e("body").on("submit","form.dokan-product-edit-form",this.inputValidate),e(".dokan-product-listing").on("click","a.dokan-add-new-product",this.addProductPopup),this.loadSelect2(),this.bindProductTagDropdown(),this.attribute.sortable(),this.checkProductPostboxToggle(),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.dokan-product-toggle-attribute, .dokan-product-attribute-heading",this.attribute.toggleAttribute),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.add_new_attribute",this.attribute.addNewAttribute),e(".product-edit-container .dokan-product-attribute-wrapper").on("keyup","input.dokan-product-attribute-name",this.attribute.dynamicAttrNameChange),e(".dokan-product-attribute-wrapper ul.dokan-attribute-option-list").on("click","button.dokan-select-all-attributes",this.attribute.selectAllAttr),e(".dokan-product-attribute-wrapper ul.dokan-attribute-option-list").on("click","button.dokan-select-no-attributes",this.attribute.selectNoneAttr),e(".dokan-product-attribute-wrapper ul.dokan-attribute-option-list").on("click","button.dokan-add-new-attribute",this.attribute.addNewExtraAttr),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.dokan-product-remove-attribute",this.attribute.removeAttribute),e(".product-edit-container .dokan-product-attribute-wrapper").on("click","a.dokan-save-attribute",this.attribute.saveAttribute),e("body").on("click",'.product-container-footer input[type="submit"]',this.createNewProduct),this.attribute.disbalePredefinedAttribute(),this.setCorrectProductId(),e("body").trigger("dokan-product-editor-loaded",this)},setCorrectProductId:function(){if(!e(".dokan-product-edit-form"))return;let t=e("#dokan_product_id").val();if(window.history.replaceState){let e=new URL(document.location),a=e.searchParams,n=a.get("product_id");if(""!==n&&"0"!==n)return;if(a.set("product_id",t),"edit"!==a.get("action"))return;e.search=a.toString();let o=e.toString(),i={product_id:t};window.history.replaceState(i,document.title,o)}},saleSchedule:function(){var t=e(this).closest(".dokan-product-field-content","div, table");return e(this).hide(),t.find(".cancel_sale_schedule").show(),t.find(".sale_price_dates_fields").show(),!1},cancelSchedule:function(){var t=e(this).closest(".dokan-product-field-content","div, table");return e(this).hide(),t.find(".sale_schedule").show(),t.find(".sale_price_dates_fields").hide(),t.find(".sale_price_dates_fields").find("input").val(""),!1},checkProductPostboxToggle:function(){var t=JSON.parse(localStorage.getItem("toggleClasses"));e.each(t,(function(t,a){var n=e("."+t.replace(/_/g,"-")),o=n.find(".dokan-section-content"),i=n.find("i.fa-sort-desc");a?(o.show(),i.removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),i.css("marginTop","9px")):(o.hide(),i.removeClass("fa-flip-vertical").addClass("fa-flip-horizointal"),i.css("marginTop","0px"))}))},toggleProductSection:function(t){t.preventDefault();var a=e(this);if(null!=JSON.parse(localStorage.getItem("toggleClasses")))var n=JSON.parse(localStorage.getItem("toggleClasses"));else n={};a.closest(".dokan-edit-row").find(".dokan-section-content").slideToggle(300,(function(){var t;e(this).is(":visible")?((t=a.find("i.fa-sort-desc")).removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),t.css("marginTop","9px"),n[a.data("togglehandler")]=!0):((t=a.find("i.fa-sort-desc")).removeClass("fa-flip-vertical").addClass("fa-flip-horizointal"),t.css("marginTop","0px"),n[a.data("togglehandler")]=!1),localStorage.setItem("toggleClasses",JSON.stringify(n))}))},loadSelect2:function(){e(".dokan-select2").select2({language:{noResults:function(){return dokan.i18n_no_result_found}}})},bindProductTagDropdown:function(){e(".product_tag_search").select2({allowClear:!1,tags:dokan.product_vendors_can_create_tags&&"on"===dokan.product_vendors_can_create_tags,createTag:function(t){var a=e.trim(t.term);return""===a?null:{id:a,text:a,newTag:!0}},insertTag:function(t,a){var n=!1;e.each(t,(function(t,o){e.trim(a.text).toUpperCase()==e.trim(o.text).toUpperCase()&&(n=!0)})),n||t.unshift(a)},minimumInputLength:2,maximumSelectionLength:void 0!==dokan.maximum_tags_select_length?dokan.maximum_tags_select_length:-1,ajax:{url:dokan.ajaxurl,dataType:"json",delay:250,data:function(e){return{q:e.term,action:"dokan_json_search_products_tags",security:dokan.search_products_tags_nonce,page:e.page||1}},processResults:function(t){var a=[];return t&&e.each(t,(function(e,t){a.push({id:t[0],text:t[1]})})),{results:a,pagination:{more:0!=a.length}}},cache:!0},language:{errorLoading:function(){return dokan.i18n_searching},inputTooLong:function(e){var t=e.input.length-e.maximum;return 1===t?dokan.i18n_input_too_long_1:dokan.i18n_input_too_long_n.replace("%qty%",t)},inputTooShort:function(e){var t=e.minimum-e.input.length;return 1===t?dokan.i18n_input_too_short_1:dokan.i18n_input_too_short_n.replace("%qty%",t)},loadingMore:function(){return dokan.i18n_load_more},maximumSelected:function(e){return 1===e.maximum?dokan.i18n_selection_too_long_1:dokan.i18n_selection_too_long_n.replace("%qty%",e.maximum)},noResults:function(){return dokan.i18n_no_matches},searching:function(){return dokan.i18n_searching}}})},addProductPopup:function(e){e.preventDefault(),n.openProductPopup()},openProductPopup:function(){const o=wp.template("dokan-add-new-product"),i=e("#dokan-add-product-popup");n.modal=i.iziModal({headerColor:dokan.modal_header_color,overlayColor:"rgba(0, 0, 0, 0.8)",width:690,top:32,onOpening:()=>{n.reRenderPopupElements()},onClosed:()=>{t=void 0,a=void 0,e('#dokan-add-new-product-popup input[name="_sale_price_dates_from"], #dokan-add-new-product-popup input[name="_sale_price_dates_to"]').datepicker("destroy")}}),n.modal.iziModal("setContent",o().trim()),n.modal.iziModal("open")},reRenderPopupElements:function(){n.loadSelect2(),n.bindProductTagDropdown(),e("#dokan-add-new-product-popup .sale_price_dates_fields input").daterangepicker({singleDatePicker:!0,showDropdowns:!1,autoApply:!0,parentEl:"#dokan-add-new-product-popup",opens:"left",autoUpdateInput:!1}).on("apply.daterangepicker",(function(t,a){e(this).val(a.startDate.format("YYYY-MM-DD"))})),e(".tips").tooltip(),n.gallery.sortable(),e("body").trigger("dokan-product-editor-popup-opened",n)},createNewProduct:function(t){t.preventDefault();var o=e(this),i=o.closest("form#dokan-add-new-product-form"),r=o.attr("data-btn_id");if(i.find("span.dokan-show-add-product-success").html(""),i.find("span.dokan-show-add-product-error").html(""),i.find("span.dokan-add-new-product-spinner").css("display","inline-block"),o.attr("disabled","disabled"),""==i.find('input[name="post_title"]').val())return e("span.dokan-show-add-product-error").html(dokan.product_title_required),o.removeAttr("disabled"),void i.find("span.dokan-add-new-product-spinner").css("display","none");if("-1"==i.find('select[name="product_cat"]').val())return e("span.dokan-show-add-product-error").html(dokan.product_category_required),o.removeAttr("disabled"),void i.find("span.dokan-add-new-product-spinner").css("display","none");var d={action:"dokan_create_new_product",postdata:i.serialize(),_wpnonce:dokan.nonce};n.modal.iziModal("startLoading"),e.post(dokan.ajaxurl,d,(function(t){t.success?(o.removeAttr("disabled"),"create_new"===r?(e("#dokan-add-product-popup").iziModal("close"),window.location.href=t.data):(a=void 0,e(".dokan-dashboard-product-listing-wrapper").load(window.location.href+" table.product-listing-table"),n.modal.iziModal("resetContent"),n.openProductPopup(),n.reRenderPopupElements(),e("span.dokan-show-add-product-success").html(dokan.product_created_response),setTimeout((function(){e("span.dokan-show-add-product-success").html("")}),3e3))):(o.removeAttr("disabled"),e("span.dokan-show-add-product-error").html(t.data)),i.find("span.dokan-add-new-product-spinner").css("display","none")})).always((function(){n.modal.iziModal("stopLoading")}))},attribute:{toggleAttribute:function(t){t.preventDefault();var a=e(this),n=a.closest("li").find(".dokan-product-attribute-item");return e(n).hasClass("dokan-hide")?(a.closest(".dokan-product-attribute-heading").css({borderBottom:"1px solid #e3e3e3"}),e(n).slideDown(200,(function(){a.find("i.fa").removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),e(this).removeClass("dokan-hide"),e(t.target).hasClass("dokan-product-attribute-heading")?e(t.target).hasClass("dokan-product-attribute-heading")&&a.find("a.dokan-product-toggle-attribute").css("top","12px"):e(t.target).closest("a").css("top","12px")}))):e(n).slideUp(200,(function(){e(this).addClass("dokan-hide"),a.find("i.fa").removeClass("fa-flip-vertical").addClass("fa-flip-horizointal"),e(t.target).hasClass("dokan-product-attribute-heading")?e(t.target).hasClass("dokan-product-attribute-heading")&&a.find("a.dokan-product-toggle-attribute").css("top","7px"):e(t.target).closest("a").css("top","7px"),a.closest(".dokan-product-attribute-heading").css({borderBottom:"none"})})),!1},sortable:function(){e(".dokan-product-attribute-wrapper ul").sortable({items:"li.product-attribute-list",cursor:"move",scrollSensitivity:40,forcePlaceholderSize:!0,forceHelperSize:!1,helper:"clone",opacity:.65,placeholder:"dokan-sortable-placeholder",start:function(e,t){t.item.css("background-color","#f6f6f6")},stop:function(e,t){t.item.removeAttr("style")},update:function(e,t){n.attribute.reArrangeAttribute()}})},dynamicAttrNameChange:function(t){t.preventDefault();var a=e(this),n=a.val();""==n?a.closest("li").find("strong").html(dokan.i18n_attribute_label):a.closest("li").find("strong").html(n)},selectAllAttr:function(t){return t.preventDefault(),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values option").attr("selected","selected"),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values").trigger("change"),!1},selectNoneAttr:function(t){return t.preventDefault(),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values option").removeAttr("selected"),e(this).closest("li.product-attribute-list").find("select.dokan_attribute_values").trigger("change"),!1},reArrangeAttribute:function(){e(".dokan-product-attribute-wrapper").find("ul.dokan-attribute-option-list").find("li.product-attribute-list").css("cursor","default").each((function(t){e(this).find(".attribute_position").val(t)}))},addNewExtraAttr:async function(t){t.preventDefault();var a=e(this).closest("li.product-attribute-list"),n=a.data("taxonomy"),o=(await dokan_sweetalert(dokan.new_attribute_prompt,{action:"prompt",input:"text"})).value;if(o){var i={action:"dokan_add_new_attribute",taxonomy:n,term:o,_wpnonce:dokan.nonce};e.post(dokan.ajaxurl,i,(function(e){e.error?dokan_sweetalert(e.error,{action:"alert",icon:"warning"}):e.slug&&(a.find("select.dokan_attribute_values").append('"),a.find("select.dokan_attribute_values").trigger("change"))}))}},addNewAttribute:function(t){t.preventDefault();var a=e(this),o=a.closest(".dokan-attribute-type").find("select#predefined_attribute"),i=o.val(),r=e("ul.dokan-attribute-option-list .product-attribute-list").length,d={action:"dokan_get_pre_attribute",taxonomy:i,i:r,_wpnonce:dokan.nonce};a.closest(".dokan-attribute-type").find("span.dokan-attribute-spinner").removeClass("dokan-hide"),e.post(dokan.ajaxurl,d,(function(t){if(t.success){var r=e(".dokan-product-attribute-wrapper").find("ul.dokan-attribute-option-list");if($html=e.parseHTML(t.data),e($html).find(".dokan-product-attribute-item").removeClass("dokan-hide"),e($html).find("i.fa.fa-sort-desc").removeClass("fa-flip-horizointal").addClass("fa-flip-vertical"),e($html).find("a.dokan-product-toggle-attribute").css("top","12px"),e($html).find(".dokan-product-attribute-heading").css({borderBottom:"1px solid #e3e3e3"}),r.append($html),n.loadSelect2(),n.bindProductTagDropdown(),n.attribute.reArrangeAttribute(),"variable"!==e("select#product_type").val()){let t=e("div.dokan-product-attribute-wrapper label.show_if_variable");for(let a of t){let t=e(a).find('input[type="checkbox"]');t.length>0&&t[0].getAttribute("name")?.startsWith("attribute_variation[")&&e(a).hide()}}}a.closest(".dokan-attribute-type").find("span.dokan-attribute-spinner").addClass("dokan-hide"),i&&(o.find('option[value="'+i+'"]').attr("disabled","disabled"),o.val(""))})).done((function(){e("select#product_type").trigger("change")}))},removeAttribute:async function(t){t.stopPropagation(),t.preventDefault();const a=await dokan_sweetalert(dokan.remove_attribute,{action:"confirm",icon:"warning"});if("undefined"!==a&&a.isConfirmed){var o=e(this).closest("li.product-attribute-list");o.fadeOut(300,(function(){o.is(".taxonomy")?(o.find("select, input[type=text]").val(""),e("select.dokan_attribute_taxonomy").find('option[value="'+o.data("taxonomy")+'"]').removeAttr("disabled")):(o.find("select, input[type=text]").val(""),o.hide()),n.attribute.reArrangeAttribute()}))}return!1},saveAttribute:function(t){t.preventDefault(),e(this);var a={post_id:e("#dokan-edit-product-id").val(),data:e("ul.dokan-attribute-option-list").find("input, select, textarea").serialize(),action:"dokan_save_attributes"};e(".dokan-product-attribute-wrapper").block({message:null,fadeIn:50,fadeOut:1e3,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,a,(function(t){e("#dokan-variable-product-options").load(window.location.toString()+" #dokan-variable-product-options-inner",(function(){e("#dokan-variable-product-options").trigger("reload"),e("select#product_type").trigger("change"),e(".dokan-product-attribute-wrapper").unblock()}))}))},disbalePredefinedAttribute:function(){e("ul.dokan-attribute-option-list li.product-attribute-list").each((function(t,a){"none"!==e(a).css("display")&&e(a).is(".taxonomy")&&e("select#predefined_attribute").find('option[value="'+e(a).data("taxonomy")+'"]').attr("disabled","disabled")}))}},inputValidate:function(t){return t.preventDefault(),""==e("#post_title").val().trim()?(e("#post_title").focus(),void e("div.dokan-product-title-alert").removeClass("dokan-hide")):(e("div.dokan-product-title-alert").hide(),-1==e("select.product_cat").val()?(e("select.product_cat").focus(),void e("div.dokan-product-cat-alert").removeClass("dokan-hide")):(e("div.dokan-product-cat-alert").hide(),e("input[type=submit]").attr("disabled","disabled"),void this.submit()))},downloadable:function(){e(this).prop("checked")?e(this).closest("aside").find(".dokan-side-body").removeClass("dokan-hide"):e(this).closest("aside").find(".dokan-side-body").addClass("dokan-hide")},showDiscountSchedule:function(t){t.preventDefault(),e(".sale-schedule-container").slideToggle("fast")},showManageStock:function(t){const a=e("#product_type").val();e(this).is(":checked")&&"external"!==a?e(".show_if_stock").slideDown("fast"):e(".show_if_stock").slideUp("fast"),"simple"===a&&(e(this).is(":checked")?e(".hide_if_stock_global").slideUp("fast"):e(".hide_if_stock_global").slideDown("fast"))},gallery:{addImages:function(a){a.preventDefault();var n=e(this),o=n.closest(".dokan-product-gallery").find("#product_images_container ul.product_images"),i=n.closest(".dokan-product-gallery").find("#product_image_gallery");t||(t=wp.media({title:dokan.i18n_choose_gallery,library:{type:"image"},button:{text:dokan.i18n_choose_gallery_btn_text},multiple:!0})).on("select",(function(){t.state().get("selection").map((function(t){t=t.toJSON(),attachment_ids=[],t.id&&"image"===t.type&&(e('
  • ×
  • ').insertBefore(o.find("li.add-image")),e("#product_images_container ul li.image").css("cursor","default").each((function(){var e=jQuery(this).attr("data-attachment_id");attachment_ids.push(e)})),i.val(attachment_ids.join(",")))}))})),t.open()},deleteImage:function(t){t.preventDefault();var a=e(this),n=(a.closest(".dokan-product-gallery").find("#product_images_container ul.product_images"),a.closest(".dokan-product-gallery").find("#product_image_gallery"));a.closest("li.image").remove();var o=[];return e("#product_images_container ul li.image").css("cursor","default").each((function(){var t=e(this).attr("data-attachment_id");o.push(t)})),n.val(o.join(",")),!1},sortable:function(){e("body").find("#product_images_container ul.product_images").sortable({items:"li.image",cursor:"move",scrollSensitivity:40,forcePlaceholderSize:!0,forceHelperSize:!1,helper:"clone",opacity:.65,placeholder:"dokan-sortable-placeholder",start:function(e,t){t.item.css("background-color","#f6f6f6")},stop:function(e,t){t.item.removeAttr("style")},update:function(t,a){var n=[];e("body").find("#product_images_container ul li.image").css("cursor","default").each((function(){var e=jQuery(this).attr("data-attachment_id");n.push(e)})),e("body").find("#product_image_gallery").val(n.join(","))}})}},featuredImage:{addImage:function(t){t.preventDefault();var n=e(this);a||(a=wp.media({title:dokan.i18n_choose_featured_img,library:{type:"image"},button:{text:dokan.i18n_choose_featured_img_btn_text}})).on("select",(function(){a.state().get("selection").map((function(e){if("image"===(e=e.toJSON()).type){n.siblings("input.dokan-feat-image-id").val(e.id);var t=n.closest(".instruction-inside"),a=t.siblings(".image-wrap");a.find("img").attr("src",e.url),a.find("img").removeAttr("srcset"),t.addClass("dokan-hide"),a.removeClass("dokan-hide")}}))})),a.open()},removeImage:function(t){t.preventDefault();var a=e(this).closest(".image-wrap"),n=a.siblings(".instruction-inside");n.find("input.dokan-feat-image-id").val("0"),a.addClass("dokan-hide"),n.removeClass("dokan-hide")}},fileDownloadable:function(t){t.preventDefault();var a,n=e(this);a||((a=wp.media({title:dokan.i18n_choose_file,button:{text:dokan.i18n_choose_file_btn_text},multiple:!0})).on("select",(function(){a.state().get("selection").map((function(e){e=e.toJSON(),n.closest("tr").find("input.wc_file_url, input.wc_variation_file_url").val(e.url)}))})),a.on("ready",(function(){a.uploader.options.uploader.params={type:"downloadable_product"}}))),a.open()}};e((function(){function t(){var t=e("#product_type").val(),a=e("input#_virtual:checked").length,n=e("input#_downloadable:checked").length;let o=e(".dokan-product-shipping-tax");var i=".hide_if_downloadable, .hide_if_virtual",r=".show_if_downloadable, .show_if_virtual";e.each(Object.keys(dokan.product_types),(function(e,t){i=i+", .hide_if_"+t,r=r+", .show_if_"+t})),e(i).show(),e(r).hide(),n&&e(".show_if_downloadable").show(),a&&e(".show_if_virtual").show(),e(".show_if_"+t).show(),n&&e(".hide_if_downloadable").hide(),a?(e(".hide_if_virtual").hide(),1===e(".dokan-product-shipping-tax .dokan-section-content").first().children().length?o.hide():(o.hasClass("hide_if_virtual")&&o.removeClass("hide_if_virtual"),o.show())):o.show(),e(".hide_if_"+t).hide(),e("input#_manage_stock").trigger("change")}n.init(),e("select#product_type").on("change",(function(){var a=e(this).val();"variable"===a&&(e("input#_manage_stock").trigger("change"),e("input#_downloadable").prop("checked",!1),e("input#_virtual").removeAttr("checked")),t(),e(document.body).trigger("dokan-product-type-change",a,e(this))})).trigger("change"),e(".product-edit-container").on("change","input#_downloadable, input#_virtual",(function(){t()})).trigger("change"),e("input#_downloadable").trigger("change"),e("input#_virtual").trigger("change"),e(".sale_price_dates_fields").each((function(){var t=e(this),a=!1,n=t.closest("div, table");t.find("input").each((function(){""!==e(this).val()&&(a=!0)})),a?(n.find(".sale_schedule").hide(),n.find(".sale_price_dates_fields").show()):(n.find(".sale_schedule").show(),n.find(".sale_price_dates_fields").hide())})),e(".product-edit-container").on("click",".sale_schedule",(function(){var t=e(this).closest(".product-edit-container, div.dokan-product-variation-itmes, table");return e(this).hide(),t.find(".cancel_sale_schedule").show(),t.find(".sale_price_dates_fields").show(),!1})),e(".product-edit-container").on("click",".cancel_sale_schedule",(function(){var t=e(".product-edit-container, div.dokan-product-variation-itmes, table");return e(this).hide(),t.find(".sale_schedule").show(),t.find(".sale_price_dates_fields").hide(),t.find(".sale_price_dates_fields").find("input").val(""),!1})),e("#dokan-product-title-area").on("click",".edit-slug",(function(){!function(){var t,a,n,o,i=0,r=e("#post_name"),d=r.val(),s=e("#sample-permalink"),l=s.html(),c=e("#sample-permalink a").html(),u=e("#edit-slug-buttons"),p=u.html(),m=e("#editable-post-name-full");for(m.find("img").replaceWith((function(){return this.alt})),m=m.html(),s.html(c),n=e("#editable-post-name"),o=n.html(),u.html(' "),u.children(".save").on("click",(function(){var t=n.children("input").val();t!=e("#editable-post-name-full").text()?e.post(ajaxurl,{action:"sample-permalink",post_id:e("#dokan-edit-product-id").val(),new_slug:t,new_title:e("#post_title").val(),samplepermalinknonce:e("#samplepermalinknonce").val()},(function(a){var n=e("#edit-slug-box");n.html(a),n.hasClass("hidden")&&n.fadeIn("fast",(function(){n.removeClass("hidden")})),u.html(p),s.html(l),r.val(t),e(".edit-slug").focus(),e("#editable-post-name-full-dokan").val(e("#editable-post-name-full").html())})):u.children(".cancel").trigger("click")})),u.children(".cancel").on("click",(function(){e("#view-post-btn").show(),n.html(o),u.html(p),s.html(l),r.val(d),e(".edit-slug").focus()})),t=0;tm.length/4?"":m,n.html('').children("input").on("keydown",(function(e){var t=e.which;13===t&&(e.preventDefault(),u.children(".save").trigger("click")),27===t&&u.children(".cancel").trigger("click")})).on("keyup",(function(){r.val(this.value)})).focus()}()})),e("#dokan-edit-product-id").val()&&e("#post_title").val()&&e("#samplepermalinknonce").val()&&e.post(ajaxurl,{action:"sample-permalink",post_id:e("#dokan-edit-product-id").val(),new_slug:e("#edited-post-name-dokan").val(),new_title:e("#post_title").val(),samplepermalinknonce:e("#samplepermalinknonce").val()},(function(t){e("#edit-slug-box").html(t)})),e(window).on("load",(function(){e("input#_virtual:checked").length&&t()}))}))}(jQuery),jQuery((function(e){function t(e,t,a){jQuery('
    '+a+"
    ").css({top:t-16,left:e+20}).appendTo("body").fadeIn(200)}wp.customize,e(".datepicker").datepicker({dateFormat:"yy-mm-dd"}),e(".dokan-table tbody").on("click",".toggle-row",(function(){e(this).closest("tr").toggleClass("is-expanded")})),e(".dokan-start-date").datepicker({defaultDate:"",dateFormat:"yy-mm-dd",numberOfMonths:1,onSelect:function(t){let a=new Date(t);a.setDate(a.getDate()+1),e(".dokan-end-date").datepicker("option",{minDate:a})}}),e(".dokan-end-date").datepicker({defaultDate:"",dateFormat:"yy-mm-dd",numberOfMonths:1,onSelect:function(t){let a=new Date(t);a.setDate(a.getDate()-1),e("dokan-start-date").datepicker("option",{maxDate:a})}}),e(".tips").tooltip();var a=null,n=null;jQuery(".chart-placeholder").on("plothover",(function(e,o,i){if(i){if((a!=i.dataIndex||n!=i.seriesIndex)&&(a=i.dataIndex,n=i.seriesIndex,jQuery(".chart-tooltip").remove(),i.series.points.show||i.series.enable_tooltip)){var r=i.series.data[i.dataIndex][1];tooltip_content="",i.series.prepend_label&&(tooltip_content=tooltip_content+i.series.label+": "),i.series.prepend_tooltip&&(tooltip_content+=i.series.prepend_tooltip),tooltip_content+=r,i.series.append_tooltip&&(tooltip_content+=i.series.append_tooltip),i.series.pie.show?t(o.pageX,o.pageY,tooltip_content):t(i.pageX,i.pageY,tooltip_content)}}else jQuery(".chart-tooltip").remove(),a=null}))})),function(e){e.validator.setDefaults({ignore:":hidden"});var t=function(t,a){e(a).closest(".dokan-form-group").addClass("has-error").append(t)},a=function(t,a){e(a).closest(".dokan-form-group").removeClass("has-error"),e(t).remove()},n=wp.customize,o='input[name="settings[bank][disconnect]"], input[name="settings[paypal][disconnect]"], input[name="settings[skrill][disconnect]"], input[name="settings[dokan_custom][disconnect]"]',i={init:function(){return e("a.dokan-banner-drag").on("click",this.imageUpload),e("a.dokan-remove-banner-image").on("click",this.removeBanner),e("a.dokan-pro-gravatar-drag").on("click",this.gragatarImageUpload),e("a.dokan-gravatar-drag").on("click",this.simpleImageUpload),e("a.dokan-remove-gravatar-image").on("click",this.removeGravatar),e(".dokan-update-setting-top-button").on("click",(function(){e("input[name='dokan_update_store_settings']").trigger("click")})),this.validateForm(this),e(".dokan_payment_disconnect_btn").on("click",(function(){var t=e(this).closest("form"),a=e("form#"+t.attr("id"));e(":input",t).not(":button, :submit, :reset, :hidden, :checkbox").val("").prop("selected",!1);var n=t.serializeArray().reduce((function(e,t){return e[t.name]=t.value,e}),{});n[e(this).attr("name")]="",n.form_id=t.attr("id"),n.action="dokan_settings",i.handleRequest(a,n,!0)})),!1},calculateImageSelectOptions:function(e,t){var a,o,i,r,d,s,l=parseInt(dokan.store_banner_dimension.width,10),c=parseInt(dokan.store_banner_dimension.height,10),u=!!parseInt(dokan.store_banner_dimension["flex-width"],10),p=!!parseInt(dokan.store_banner_dimension["flex-height"],10);return d=e.get("width"),r=e.get("height"),this.headerImage=new n.HeaderTool.ImageModel,this.headerImage.set({themeWidth:l,themeHeight:c,themeFlexWidth:u,themeFlexHeight:p,imageWidth:d,imageHeight:r}),t.set("canSkipCrop",!this.headerImage.shouldBeCropped()),(o=d)/(i=r)>(a=l/c)?l=(c=i)*a:c=(l=o)/a,s={handles:!0,keys:!0,instance:!0,persistent:!0,imageWidth:d,imageHeight:r,x1:0,y1:0,x2:l,y2:c},!1===p&&!1===u&&(s.aspectRatio=l+":"+c),!1===p&&(s.maxHeight=c),!1===u&&(s.maxWidth=l),s},onSelect:function(){this.frame.setState("cropper")},onCropped:function(e){var t=e.url,a=e.attachment_id,n=e.width,o=e.height;this.setImageFromURL(t,a,n,o)},onSkippedCrop:function(e){var t=e.get("url"),a=e.get("width"),n=e.get("height");this.setImageFromURL(t,e.id,a,n)},setImageFromURL:function(t,a,n,o){var i=!1;if(e(this.uploadBtn).hasClass("dokan-banner-drag"))(r=e(this.uploadBtn).closest(".dokan-banner")).find("input.dokan-file-field").val(a),r.find("img.dokan-banner-img").attr("src",t),e(this.uploadBtn).parent().siblings(".image-wrap",r).removeClass("dokan-hide"),e(this.uploadBtn).parent(".button-area").addClass("dokan-hide"),i=!0;else if(e(this.uploadBtn).hasClass("dokan-pro-gravatar-drag")){var r;(r=e(this.uploadBtn).closest(".dokan-gravatar")).find("input.dokan-file-field").val(a),r.find("img.dokan-gravatar-img").attr("src",t),i=!0,e(this.uploadBtn).parent().siblings(".gravatar-wrap",r).removeClass("dokan-hide"),e(this.uploadBtn).parent(".gravatar-button-area").addClass("dokan-hide")}!0===i&&(e(window).on("beforeunload",(function(){return dokan.dokan_banner_added_alert_msg})),e(document).ready((function(){e("#store-form").on("submit",(function(t){return e(window).off("beforeunload"),!0}))})))},removeImage:function(){n.HeaderTool.currentHeader.trigger("hide"),n.HeaderTool.CombinedList.trigger("control:removeImage")},imageUpload:function(e){e.preventDefault();var t=i;t.uploadBtn=this,t.frame=wp.media({multiple:!1,button:{text:dokan.selectAndCrop,close:!1},states:[new wp.media.controller.Library({title:dokan.chooseImage,library:wp.media.query({type:"image"}),multiple:!1,date:!1,priority:20,suggestedWidth:dokan.store_banner_dimension.width,suggestedHeight:dokan.store_banner_dimension.height}),new wp.media.controller.Cropper({suggestedWidth:5e3,imgSelectOptions:t.calculateImageSelectOptions})]}),t.frame.on("select",t.onSelect,t),t.frame.on("cropped",t.onCropped,t),t.frame.on("skippedcrop",t.onSkippedCrop,t),t.frame.open()},calculateImageSelectOptionsProfile:function(e,t){var a,o,i,r,d,s,l=150,c=150,u=!!parseInt(dokan.store_banner_dimension["flex-width"],10),p=!!parseInt(dokan.store_banner_dimension["flex-height"],10);return d=e.get("width"),r=e.get("height"),this.headerImage=new n.HeaderTool.ImageModel,this.headerImage.set({themeWidth:l,themeHeight:c,themeFlexWidth:u,themeFlexHeight:p,imageWidth:d,imageHeight:r}),t.set("canSkipCrop",!this.headerImage.shouldBeCropped()),(o=d)/(i=r)>(a=l/c)?l=(c=i)*a:c=(l=o)/a,s={handles:!0,keys:!0,instance:!0,persistent:!0,imageWidth:d,imageHeight:r,x1:0,y1:0,x2:l,y2:c},!1===p&&!1===u&&(s.aspectRatio=l+":"+c),!1===p&&(s.maxHeight=c),!1===u&&(s.maxWidth=l),s},simpleImageUpload:function(t){t.preventDefault();var a,n=e(this);a||(a=wp.media.frames.file_frame=wp.media({title:jQuery(this).data("uploader_title"),button:{text:jQuery(this).data("uploader_button_text")},multiple:!1})).on("select",(function(){var e=a.state().get("selection").first().toJSON(),t=n.closest(".dokan-gravatar");t.find("input.dokan-file-field").val(e.id),t.find("img.dokan-gravatar-img").attr("src",e.url),n.parent().siblings(".gravatar-wrap",t).removeClass("dokan-hide"),n.parent(".gravatar-button-area").addClass("dokan-hide")})),a.open()},gragatarImageUpload:function(e){e.preventDefault();var t=i;t.uploadBtn=this,t.frame=wp.media({multiple:!1,button:{text:dokan.selectAndCrop,close:!1},states:[new wp.media.controller.Library({title:dokan.chooseImage,library:wp.media.query({type:"image"}),multiple:!1,date:!1,priority:20,suggestedWidth:150,suggestedHeight:150}),new wp.media.controller.Cropper({imgSelectOptions:t.calculateImageSelectOptionsProfile})]}),t.frame.on("select",t.onSelect,t),t.frame.on("cropped",t.onCropped,t),t.frame.on("skippedcrop",t.onSkippedCrop,t),t.frame.open()},submitSettings:function(t){"undefined"!=typeof tinyMCE&&tinyMCE.triggerSave();var a=e("form#"+t),n=a.serialize()+"&action=dokan_settings&form_id="+t;i.handleRequest(a,n,!1)},handleRequest:function(t,a,n){n?t.find(".ajax_prev.disconnect").append(' '):t.find(".ajax_prev.save").append(' '),e(".dokan-update-setting-top-button span.dokan-loading").remove(),e(".dokan-update-setting-top-button").append(' '),e.post(dokan.ajaxurl,a,(function(a){t.find("span.dokan-loading").remove(),e(".dokan-update-setting-top-button span.dokan-loading").remove(),e("html,body").animate({scrollTop:e(".dokan-dashboard-header").offset().top}),a.success?(e(".dokan-ajax-response").html(e("
    ",{class:"dokan-alert dokan-alert-success",html:"

    "+a.data.msg+"

    "})),e(".dokan-ajax-response").append(a.data.progress),dokan&&dokan.storeProgressBar&&dokan.storeProgressBar.init(),o=o.replaceAll("input","button"),n?t.find(o).addClass("dokan-hide"):t.find(o).removeClass("dokan-hide")):e(".dokan-ajax-response").html(e("
    ",{class:"dokan-alert dokan-alert-danger",html:"

    "+a.data+"

    "}))}))},validateForm:function(n){e("form#settings-form, form#profile-form, form#store-form, form#payment-form").validate({submitHandler:function(e){n.submitSettings(e.getAttribute("id"))},errorElement:"span",errorClass:"error",errorPlacement:t,success:a,ignore:".select2-search__field, :hidden, .mapboxgl-ctrl-geocoder--input"})},removeBanner:function(t){t.preventDefault();var a=e(this).closest(".image-wrap"),n=a.siblings(".button-area");a.find("input.dokan-file-field").val("0"),a.addClass("dokan-hide"),n.removeClass("dokan-hide")},removeGravatar:function(t){t.preventDefault();var a=e(this).closest(".gravatar-wrap"),n=a.siblings(".gravatar-button-area");a.find("input.dokan-file-field").val("0"),a.addClass("dokan-hide"),n.removeClass("dokan-hide")}},r={init:function(){this.withdrawValidate(this)},withdrawValidate:function(n){e("form.withdraw").validate({errorElement:"span",errorClass:"error",errorPlacement:t,success:a})}},d={init:function(){this.validate(this)},validate:function(a){e("form#dokan-form-contact-seller").validate({errorPlacement:t,errorElement:"span",success:function(e,t){e.removeClass("error"),e.remove()},submitHandler:async function(t,a){a.preventDefault(),e(t).block({message:null,overlayCSS:{background:"#fff url("+dokan.ajax_loader+") no-repeat center",opacity:.6}}),await dokan_execute_recaptcha("form#dokan-form-contact-seller .dokan_recaptcha_token","dokan_contact_seller_recaptcha");var n=e(t).serialize();e.post(dokan.ajaxurl,n,(function(a){e(t).unblock(),void 0!==a.data&&e(t).find(".ajax-response").html(a.data),e(t).find("input[type=text], input[type=email], textarea, input[name=dokan_recaptcha_token]").val("").removeClass("valid")}))}})}};e((function(){i.init(),r.init(),d.init(),e(".dokan-form-horizontal").on("change","input[type=checkbox]#lbl_setting_minimum_quantity",(function(){var t=e(".show_if_needs_sw_discount");e(this).is(":checked")?(t.find('input[type="number"]').val(""),t.slideDown("slow")):t.slideUp("slow")}))}))}(jQuery),function(e){var t=DokanValidateMsg;t.maxlength=e.validator.format(t.maxlength_msg),t.minlength=e.validator.format(t.minlength_msg),t.rangelength=e.validator.format(t.rangelength_msg),t.range=e.validator.format(t.range_msg),t.max=e.validator.format(t.max_msg),t.min=e.validator.format(t.min_msg),e.validator.messages=t,e(document).on("click","#dokan_store_tnc_enable",(function(t){e(this).is(":checked")?e("#dokan_tnc_text").show():e("#dokan_tnc_text").hide()})).ready((function(t){e("#dokan_store_tnc_enable").is(":checked")?e("#dokan_tnc_text").show():e("#dokan_tnc_text").hide()}))}(jQuery),function(e){var t="undefined"!=typeof wp&&wp.customize&&wp.customize.selectiveRefresh;function a(){dokan.store_banner_dimension.width;var t=dokan.store_banner_dimension.height/dokan.store_banner_dimension.width*e("#dokan-content").width();e(".dokan-profile-frame-wrapper .profile-info-img.dummy-image").css({height:t})}a(),e(window).on("resize",(function(e){a()})),t&&wp.customize.selectiveRefresh.bind("partial-content-rendered",(function(e){console.log("placement",e),"store_header_template"===e.partial.id&&a()})),e(":input.dokan-product-search").filter(":not(.enhanced)").each((function(){var t={allowClear:!!e(this).data("allow_clear"),placeholder:e(this).data("placeholder"),minimumInputLength:e(this).data("minimum_input_length")?e(this).data("minimum_input_length"):"3",escapeMarkup:function(e){return e},language:{errorLoading:function(){return dokan.i18n_searching},inputTooLong:function(e){var t=e.input.length-e.maximum;return 1===t?dokan.i18n_input_too_long_1:dokan.i18n_input_too_long_n.replace("%qty%",t)},inputTooShort:function(e){var t=e.minimum-e.input.length;return 1===t?dokan.i18n_input_too_short_1:dokan.i18n_input_too_short_n.replace("%qty%",t)},loadingMore:function(){return dokan.i18n_load_more},maximumSelected:function(e){return 1===e.maximum?dokan.i18n_selection_too_long_1:dokan.i18n_selection_too_long_n.replace("%qty%",e.maximum)},noResults:function(){return dokan.i18n_no_matches},searching:function(){return dokan.i18n_searching}},ajax:{url:dokan.ajaxurl,dataType:"json",delay:250,data:function(t){return{term:t.term,action:e(this).data("action")||"dokan_json_search_products_and_variations",security:dokan.search_products_nonce,exclude:e(this).data("exclude"),user_ids:e(this).data("user_ids"),include:e(this).data("include"),limit:e(this).data("limit")}},processResults:function(t){var a=[];return t&&e.each(t,(function(e,t){a.push({id:e,text:t})})),{results:a}},cache:!0}};if(e(this).select2(t).addClass("enhanced"),e(this).data("sortable")){var a=e(this),n=e(this).next(".select2-container").find("ul.select2-selection__rendered");n.sortable({placeholder:"ui-state-highlight select2-selection__choice",forcePlaceholderSize:!0,items:"li:not(.select2-search__field)",tolerance:"pointer",stop:function(){e(n.find(".select2-selection__choice").get().reverse()).each((function(){var t=e(this).data("data").id,n=a.find('option[value="'+t+'"]')[0];a.prepend(n)}))}})}})),selected_items=[],e("#cb-select-all").on("change",(function(t){var a=e(this),n=e(".cb-select-items");a.is(":checked")?n.each((function(t,a){e(a).prop("checked","checked")})):n.each((function(t,a){e(a).prop("checked",""),selected_items.pop()}))}))}(jQuery),function(e){function t(t,a){const n=e(t.target).closest("li.has-submenu");n.find(".navigation-submenu").each(((t,o)=>{if(a)n.removeClass("submenu-hovered"),e(".dokan-dashboard-wrap").css("height",""),e(o).css("bottom",0),e(o).removeAttr("style");else{n.addClass("submenu-hovered");let t=n[0].getBoundingClientRect(),a=o.getBoundingClientRect(),i=e(".dokan-dashboard-wrap"),r=i[0].getBoundingClientRect(),d=Math.min(r.bottom,r.height);if(d0)e(o).css("bottom",0),a=o.getBoundingClientRect(),a.top<0&&(e(o).css("bottom","unset"),e(o).css("top",0));else{e(o).css("bottom",n);let t=e(".dokan-dash-sidebar")[0].getBoundingClientRect(),i=e(".entry-header")[0].getBoundingClientRect();a=o.getBoundingClientRect(),a.bottom>t.bottom?n+=a.bottom-t.bottom:a.bottom-i.bottom'+dokan[n]+"
    "),a.parent().find(".wc_error_tip").css("left",o.left+a.width()-a.width()/2-e(".wc_error_tip").width()/2).css("top",o.top+a.height()).fadeIn("100"))})).on("wc_remove_error_tip",(function(t,a,n){a.parent().find(".wc_error_tip."+n).fadeOut("100",(function(){e(this).remove()}))})).on("click",(function(){e(".wc_error_tip").fadeOut("100",(function(){e(this).remove()}))})).on("blur",".wc_input_decimal[type=text], .wc_input_price[type=text], .wc_input_country_iso[type=text]",(function(){e(".wc_error_tip").fadeOut("100",(function(){e(this).remove()}))})).on("change",".wc_input_price[type=text], .wc_input_decimal[type=text], .wc-order-totals #refund_amount[type=text]",(function(){var t,a,n=dokan.decimal_point;(e(this).is(".wc_input_price")||e(this).is("#refund_amount"))&&(n=dokan.mon_decimal_point),t=new RegExp("[^-0-9%\\"+n+"]+","gi"),a=new RegExp("\\"+n+"+","gi");var o=e(this).val(),i=o.replace(t,"").replace(a,n);o!==i&&e(this).val(i)})).on("keyup",".wc_input_price[type=text], .wc_input_decimal[type=text], .wc_input_country_iso[type=text], .wc-order-totals #refund_amount[type=text]",(function(){var t,a,n,o=!1;e(this).is(".wc_input_price")||e(this).is("#refund_amount")?(o=!0,t=new RegExp("[^-0-9%\\"+dokan.mon_decimal_point+"]+","gi"),n=new RegExp("[^\\"+dokan.mon_decimal_point+"]","gi"),a="i18n_mon_decimal_error"):e(this).is(".wc_input_country_iso")?(t=new RegExp("([^A-Z])+|(.){3,}","im"),a="i18n_country_iso_error"):(o=!0,t=new RegExp("[^-0-9%\\"+dokan.decimal_point+"]+","gi"),n=new RegExp("[^\\"+dokan.decimal_point+"]","gi"),a="i18n_decimal_error");var i=e(this).val(),r=i.replace(t,"");o&&1=parseFloat(window.accounting.unformat(t.val(),dokan.mon_decimal_point))&&e(this).val("")})).on("keyup","#_sale_price.wc_input_price[type=text], .wc_input_price[name^=variable_sale_price], #_subscription_sale_price.wc_input_price[type=text]",(function(){var t,a=e(this),n=e("#product_type");t=-1!==a.attr("name").indexOf("variable")?a.parents(".variable_pricing").find(".wc_input_price[name^=variable_regular_price]"):n.length&&"subscription"===n.find(":selected").val()?e("#_subscription_price"):e("#_regular_price"),parseFloat(window.accounting.unformat(a.val(),dokan.mon_decimal_point))>=parseFloat(window.accounting.unformat(t.val(),dokan.mon_decimal_point))?e(document.body).triggerHandler("wc_add_error_tip",[e(this),"i18n_sale_less_than_regular_error"]):e(document.body).triggerHandler("wc_remove_error_tip",[e(this),"i18n_sale_less_than_regular_error"])})).on("init_tooltips",(function(){e(".tips, .help_tip, .woocommerce-help-tip").tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}),e(".column-wc_actions .wc-action-button").tipTip({fadeIn:50,fadeOut:50,delay:200}),e(".parent-tips").each((function(){e(this).closest("a, th").attr("data-tip",e(this).data("tip")).tipTip({attribute:"data-tip",fadeIn:50,fadeOut:50,delay:200}).css("cursor","help")}))})),e("#dokan-navigation .dokan-dashboard-menu li.has-submenu:not(.active)").on("mouseover",(e=>{t(e)})).on("mouseout",(e=>{t(e,!0)}))}(jQuery),window.dokan_show_delete_prompt=async function(e,t){e.preventDefault();let a=await dokan_sweetalert(t,{action:"confirm",icon:"warning"});if(a.isConfirmed&&void 0!==e.target.href)window.location.href=e.target.href;else{if(!a.isConfirmed||void 0===e.target.dataset.url)return!1;window.location.href=e.target.dataset.url}},window.dokan_bulk_delete_prompt=async function(e,t,a,n){"delete"===jQuery(a).val()&&(e.preventDefault(),(await dokan_sweetalert(t,{action:"confirm",icon:"warning"})).isConfirmed&&jQuery(n).submit())},function(e){var t={query:{},form:null,cateItemStringArray:[],init:function(){e("#dokan-store-listing-filter-wrap .sort-by #stores_orderby").on("change",this.buildSortByQuery),e("#dokan-store-listing-filter-wrap .toggle-view span").on("click",this.toggleView),e("#dokan-store-listing-filter-wrap .dokan-store-list-filter-button, #dokan-store-listing-filter-wrap .dokan-icons, #dokan-store-listing-filter-form-wrap .apply-filter #cancel-filter-btn ").on("click",this.toggleForm),e("#dokan-store-listing-filter-form-wrap .store-search-input").on("change",this.buildSearchQuery),e("#dokan-store-listing-filter-form-wrap .apply-filter #apply-filter-btn").on("click",this.submitForm),this.maybeHideListView();const a=t;a.form=document.forms.dokan_store_lists_filter_form;const n=a.getLocal("dokan-layout");if(n){const t=e(".toggle-view span");a.setView(n,t)}const o=a.getParams();if(o.length){let t=!1;o.forEach((function(e){const n=Object.keys(e),i=Object.values(e);(!n.includes("stores_orderby")||o.length>1)&&(t=!0),a.setParams(n,i)})),t&&e("#dokan-store-listing-filter-form-wrap").slideToggle()}var i,r;e("#dokan-store-listing-filter-form-wrap").length&&e(".store-search-input").on("keypress",(function(t){if(13==t.which)return e("#dokan-store-listing-filter-form-wrap").submit(),!1})),e("body").on("click",(function(t){e(t.target).is("div#dokan-store-products-search-result li")||(e("#dokan-store-products-search-result").html(""),e("#dokan-store-products-search-result").removeClass("dokan-store-products-search-has-results"))})),e("body").on("keyup",".dokan-store-products-filter-search",(i=function(t){t.preventDefault();var a=e(this),n=a.val(),o=a.data("store_id");n&&(e(".dokan-store-products-filter-search").addClass("dokan-ajax-search-loader"),e("#dokan-store-products-search-result").removeClass("dokan-store-products-search-has-results"),e("#dokan-store-products-search-result").hide(),e("#dokan-store-products-search-result").html(""),jQuery.ajax({type:"post",dataType:"json",url:dokan.ajaxurl,data:{search_term:n,store_id:o,_wpnonce:dokan.store_product_search_nonce,action:"dokan_store_product_search_action"},success:function(t){e(".dokan-store-products-filter-search").removeClass("dokan-ajax-search-loader"),e("#dokan-store-products-search-result").show(),e("#dokan-store-products-search-result").addClass("dokan-store-products-search-has-results"),"success"==t.type?e("#dokan-store-products-search-result").html("
      "+t.data_list+"
    "):e("#dokan-store-products-search-result").html('
      '+t.data_list+"
    ")}}))},500,r=0,function(){var e=this,t=arguments;clearTimeout(r),r=setTimeout((function(){i.apply(e,t)}),500)}))},buildSortByQuery:function(e){const a=t;a.query.stores_orderby=e.target.value,a.submitForm(e)},toggleView:function(a){const n=t,o=e(a.target),i=o.parent().find("span"),r=o.data("view");n.setView(r,i),n.setLocal("dokan-layout",r)},setView:function(t,a){if(void 0===t||t.length<1||void 0===a||a.length<1)return;const n=e("#dokan-seller-listing-wrap");[...a].forEach((function(a){const o=e(a);t===o.data("view")?(o.addClass("active"),n.addClass(t)):(o.removeClass("active"),n.removeClass(o.data("view")))}))},toggleForm:function(t){t.preventDefault(),e("#dokan-store-listing-filter-form-wrap").slideToggle()},buildSearchQuery:function(e){e.target.value?t.query.dokan_seller_search=e.target.value:delete t.query.dokan_seller_search},submitForm:function(a){a.preventDefault(),t.query._store_filter_nonce&&delete t.query._store_filter_nonce,t.query._store_filter_nonce=e('input[name="_store_filter_nonce"]').first().val();const n=decodeURIComponent(e.param(t.query)),o="/page",i=window.location.pathname,r=i.includes(o)?i.substr(0,i.indexOf(o)):"";window.history.pushState(null,null,`${r}?${n}`),window.location.reload()},setLocal:function(e,t){window.localStorage.setItem(e,t)},getLocal:function(e){return window.localStorage.getItem(e)},setParams:function(a,n){const o=t,i=o.form?o.form.elements:"",r=document.forms.stores_sorting,d=r?r.elements:"";Object.values(d).forEach((function(t){t.name===a[0]&&e(t).val(n[0])})),Object.values(i).forEach((function(t){if(a.includes(t.name)&&("checkbox"===t.type?t.checked=!!["yes","true","1"].includes(n[0]):["text","search"].includes(t.type)&&(t.value=n[0])),a[0].includes("store_categories[")||a[0].includes("store_category[")){const t=n[0].split(" ").join("-"),a=e(`[data-slug=${t}]`);o.cateItemStringArray.includes(a.text().trim())||o.cateItemStringArray.push(a.text().trim()),a.addClass("dokan-btn-theme")}else if("rating"===a[0]){const t=n[0].split(" ").join("-");e(`[data-${a[0]}=${t}]`).addClass("active"),e(`[data-rating=${t}]`).parent().addClass("selected")}})),a.forEach((function(e,t){e.includes("[")||(o.query[e]=n[t])}))},getParams:function(){const e=new URLSearchParams(location.search),t=[];return e.forEach((function(e,a){t.push({[a]:e})})),t},maybeHideListView:function(){const a=t;window.matchMedia("(max-width: 767px)").matches&&"list-view"===a.getLocal("dokan-layout")&&a.setLocal("dokan-layout","grid-view"),e(window).on("resize",(function(){e(this).width()<767?(e("#dokan-seller-listing-wrap").removeClass("list-view"),e("#dokan-seller-listing-wrap").addClass("grid-view")):(e(".toggle-view.item span").last().removeClass("active"),e(".toggle-view.item span").first().addClass("active"))}))}};window.dokan&&(window.dokan.storeLists=t,window.dokan.storeLists.init())}(jQuery),(e=>{const t={init:()=>{e("#dokan-request-withdraw-button").on("click",(e=>{e.preventDefault(),t.openRequestWithdrawWindow()})),e(".dokan-withdraw-make-default-button").on("click",(e=>{e.preventDefault(),t.makeDefault(e)})),e("#dokan-withdraw-request-submit").on("click",(e=>{t.handleWithdrawRequest(e)})),e("#dokan-withdraw-display-schedule-popup").on("click",(e=>{t.opensScheduleWindow(e)})),e("#dokan-withdraw-schedule-request-submit").on("click",(e=>{t.handleScheduleChangeRequest(e)})),e("input[name='withdraw-schedule']").on("change",(e=>{t.handleScheduleChange(e)}))},openRequestWithdrawWindow:()=>{const a=wp.template("withdraw-request-popup"),n=e("#dokan-withdraw-request-popup").iziModal({width:690,overlayColor:"rgba(0, 0, 0, 0.8)",headerColor:dokan.modal_header_color});n.iziModal("setContent",a().trim()),n.iziModal("open"),t.init()},opensScheduleWindow:()=>{const a=wp.template("withdraw-schedule-popup"),n=e("#dokan-withdraw-schedule-popup").iziModal({width:690,overlayColor:"rgba(0, 0, 0, 0.8)",headerColor:dokan.modal_header_color});n.iziModal("setContent",a().trim()),n.iziModal("open"),t.init()},makeDefault:t=>{const a=e(t.target),n=e("#dokan-withdraw-payment-method-list");n.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,{action:"dokan_withdraw_handle_make_default_method",nonce:n.data("security"),method:a.data("method")},(e=>{e.success?(dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"success",showConfirmButton:!1,timer:2e3,timerProgressBar:!0}),n.unblock(),window.location.reload()):(dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"error",showConfirmButton:!1,timer:2e3,timerProgressBar:!0}),n.unblock())}))},handleWithdrawRequest:t=>{t.preventDefault();const a=e("input#withdraw-amount").val(),n=e("input#dokan_withdraw_nonce").val(),o=e("#withdraw-request-popup"),i=e("#withdraw-method").val();o.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,{action:"dokan_handle_withdraw_request",_handle_withdraw_request:n,amount:a,method:i},(async e=>{e.success?await dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"success",showConfirmButton:!1,timer:2e3,timerProgressBar:!0,didOpen:e=>{setTimeout((function(){o.unblock(),window.location.reload()}),2e3)}}):(dokan_sweetalert("",{icon:"error",html:e.data}),o.unblock())}))},handleScheduleChangeRequest:t=>{t.preventDefault();const a=e("input[name='withdraw-schedule']:checked").val(),n=e("#dokan-withdraw-schedule-request-submit").data("security"),o=e("#withdraw-schedule-popup"),i=e("#withdraw-remaining-amount").val(),r=e("#minimum-withdraw-amount").val(),d=e("#preferred-payment-method").val();o.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),e.post(dokan.ajaxurl,{action:"dokan_handle_withdraw_schedule_change_request",nonce:n,schedule:a,reserve:i,minimum:r,method:d},(e=>{e.success?(dokan_sweetalert(e.data,{position:"bottom-end",toast:!0,icon:"success",showConfirmButton:!1,timer:2e3,timerProgressBar:!0}),o.unblock(),window.location.reload()):(dokan_sweetalert("",{icon:"error",html:e.data}),o.unblock())}))},handleScheduleChange:t=>{const a=e(t.target).data("next-schedule");e("#dokan-withdraw-next-scheduled-date").html(a)}};e(document).ready((function(){t.init()}))})(jQuery),function(e){!function(){let t={format:dokan_get_daterange_picker_format(),...dokan_helper.locale};e(".dokan-daterangepicker").daterangepicker({autoUpdateInput:!1,showDropdowns:!0,locale:t}),e(".dokan-daterangepicker").on("apply.daterangepicker",(function(a,n){e(this).val(n.startDate.format(t.format)+" - "+n.endDate.format(t.format)),e(this).siblings("input.dokan-daterangepicker-start-date").val(n.startDate.format("YYYY-MM-DD")),e(this).siblings("input.dokan-daterangepicker-end-date").val(n.endDate.format("YYYY-MM-DD"))})),e(".dokan-daterangepicker").on("cancel.daterangepicker",(function(t,a){e(this).data("clear")&&(e(this).val(""),e(this).siblings("input.dokan-daterangepicker-start-date").val(""),e(this).siblings("input.dokan-daterangepicker-end-date").val(""))}))}()}(jQuery)})(); \ No newline at end of file diff --git a/assets/js/helper.js b/assets/js/helper.js index 0a2adfa7f5..54ac3d310b 100644 --- a/assets/js/helper.js +++ b/assets/js/helper.js @@ -1 +1 @@ -!function(e,t){t.dokan_get_i18n_date_format=function(e=!0){if(!e)return dokan_helper.i18n_date_format;let t={d:"dd",D:"D",j:"d",l:"DD",F:"MM",m:"mm",M:"M",n:"m",o:"yy",Y:"yy",y:"y"},n=0,o="",r="";for(n=0;n=12?"pm":"am",m=i>=12?"PM":"AM",d=(e,t)=>e[t]?e[t]:t;convertTime=e=>((e=e.toString().match(/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/)||[e]).length>1&&((e=e.slice(1))[0]=+e[0]%12||12),e[0]),hour12=convertTime(`${a(i)}:${a(_)}`),replaceMent={hh:a(hour12),h:hour12,HH:a(i),H:i,g:hour12,MM:a(_),M:_,mm:a(_),m:_,i:a(_),ss:a(c),s:c,A:m,a:s};let l="",f="",h="";for(let e=0;e0&&(l+=d(replaceMent,f),f=""),e++,l+=t[e]):0===f.length?f=h:f!==h?(l+=d(replaceMent,f),f=h):f===h&&(f+=h);return l+=f.length?d(replaceMent,f):"",l},t.dokan_get_daterange_picker_format=function(e=dokan_helper.i18n_date_format){let t={d:"D",D:"DD",j:"D",l:"DD",F:"MMMM",m:"MM",M:"MM",n:"M",o:"YYYY",Y:"YYYY",y:"YY",g:"h",G:"H",h:"hh",H:"HH",i:"mm",s:"ss"},n=0,o="",r="";for(n=0;n=12?"pm":"am",l=i>=12?"PM":"AM",h=(e,t)=>e[t]?e[t]:t;convertTime=e=>((e=e.toString().match(/^([01]\d|2[0-3])(:)([0-5]\d)(:[0-5]\d)?$/)||[e]).length>1&&((e=e.slice(1))[0]=+e[0]%12||12),e[0]),hour12=convertTime(`${a(i)}:${a(s)}`),replaceMent={hh:a(hour12),h:hour12,HH:a(i),H:i,g:hour12,MM:a(s),M:s,mm:a(s),m:s,i:a(s),ss:a(c),s:c,A:l,a:d};let p="",m="",_="";for(let e=0;e0&&(p+=h(replaceMent,m),m=""),e++,p+=t[e]):0===m.length?m=_:m!==_?(p+=h(replaceMent,m),m=_):m===_&&(m+=_);return p+=m.length?h(replaceMent,m):"",p},t.dokan_get_daterange_picker_format=function(e=dokan_helper.i18n_date_format){let t={d:"D",D:"DD",j:"D",l:"DD",F:"MMMM",m:"MM",M:"MM",n:"M",o:"YYYY",Y:"YYYY",y:"YY",g:"h",G:"H",h:"hh",H:"HH",i:"mm",s:"ss"},n=0,o="",r="";for(n=0;n\n \n '),setTimeout((()=>{t.html(o)}),1e3))}};n(e).ready((function(){a.init()}))}(document,window,jQuery); \ No newline at end of file diff --git a/assets/js/reverse-withdrawal.js b/assets/js/reverse-withdrawal.js index 9924a2f596..f0afb2673d 100644 --- a/assets/js/reverse-withdrawal.js +++ b/assets/js/reverse-withdrawal.js @@ -1 +1 @@ -!function(e,t,a){const r={init(){this.init_datepicker(),e(".reverse-balance-section").on("click","#reverse_pay",r.add_to_cart)},init_datepicker(){let t={format:dokan_get_daterange_picker_format(),...dokan_helper.daterange_picker_local};e("#trn_date_filter").daterangepicker({autoUpdateInput:!1,locale:t},(function(a,r,n){e("#trn_date_filter").on("apply.daterangepicker",(function(a,r){e(this).val(r.startDate.format(t.format)+" - "+r.endDate.format(t.format))})),e("#trn_date_form_filter_alt").val(a.format("YYYY-MM-DD")),e("#trn_date_to_filter_alt").val(r.format("YYYY-MM-DD"))})),e("#trn_date_filter").on("cancel.daterangepicker",(function(t,a){e(this).val(""),e("#trn_date_form_filter_alt").val(""),e("#trn_date_to_filter_alt").val("")}))},add_to_cart(){e(this);let t=e("#reverse_pay_balance");r.disableProps();let n={price:t.val(),_reverse_withdrawal_nonce:dokan.reverse_withdrawal.nonce};wp.ajax.post("dokan_reverse_withdrawal_payment_to_cart",n).then((async e=>{let t={action:"confirm",title:dokan.reverse_withdrawal.on_success_title,icon:"success",showCloseButton:!1,showCancelButton:!1,focusConfirm:!0};await dokan_sweetalert(e.message,t).then((()=>{a.location.replace(dokan.reverse_withdrawal.checkout_url)}))})).fail((e=>{r.disableProps(!1);let t=dokan_handle_ajax_error(e);t&&dokan_sweetalert(t,{action:"error",title:dokan.reverse_withdrawal.on_error_title,icon:"error"})}))},disableProps(t=!0){e("#reverse_pay_balance").prop("disabled",t),e("#reverse_pay").prop("disabled",t)}};e((function(){r.init()}))}(jQuery,document,window); \ No newline at end of file +!function(e,a,r){const t={init(){e(".reverse-balance-section").on("click","#reverse_pay",t.add_to_cart)},add_to_cart(){e(this);let a=e("#reverse_pay_balance");t.disableProps();let o={price:a.val(),_reverse_withdrawal_nonce:dokan.reverse_withdrawal.nonce};wp.ajax.post("dokan_reverse_withdrawal_payment_to_cart",o).then((async e=>{let a={action:"confirm",title:dokan.reverse_withdrawal.on_success_title,icon:"success",showCloseButton:!1,showCancelButton:!1,focusConfirm:!0};await dokan_sweetalert(e.message,a).then((()=>{r.location.replace(dokan.reverse_withdrawal.checkout_url)}))})).fail((e=>{t.disableProps(!1);let a=dokan_handle_ajax_error(e);a&&dokan_sweetalert(a,{action:"error",title:dokan.reverse_withdrawal.on_error_title,icon:"error"})}))},disableProps(a=!0){e("#reverse_pay_balance").prop("disabled",a),e("#reverse_pay").prop("disabled",a)}};e((function(){t.init()}))}(jQuery,document,window); \ No newline at end of file diff --git a/assets/js/vue-admin.js b/assets/js/vue-admin.js index 532b04d0f9..ec8624314b 100644 --- a/assets/js/vue-admin.js +++ b/assets/js/vue-admin.js @@ -1,2 +1,2 @@ /*! For license information please see vue-admin.js.LICENSE.txt */ -(()=>{var e={3302:e=>{e.exports=function(e,t,a){return ta?a:e:et?t:e}},6850:e=>{function t(e,t,a){var s,n,i,r,o;function d(){var l=Date.now()-r;l=0?s=setTimeout(d,t-l):(s=null,a||(o=e.apply(i,n),i=n=null))}null==t&&(t=100);var l=function(){i=this,n=arguments,r=Date.now();var l=a&&!s;return s||(s=setTimeout(d,t)),l&&(o=e.apply(i,n),i=n=null),o};return l.clear=function(){s&&(clearTimeout(s),s=null)},l.flush=function(){s&&(o=e.apply(i,n),i=n=null,clearTimeout(s),s=null)},l}t.debounce=t,e.exports=t},8882:(e,t,a)=>{var s="Expected a function",n=NaN,i="[object Symbol]",r=/^\s+|\s+$/g,o=/^[-+]0x[0-9a-f]+$/i,d=/^0b[01]+$/i,l=/^0o[0-7]+$/i,u=parseInt,c="object"==typeof a.g&&a.g&&a.g.Object===Object&&a.g,_="object"==typeof self&&self&&self.Object===Object&&self,m=c||_||Function("return this")(),h=Object.prototype.toString,p=Math.max,f=Math.min,v=function(){return m.Date.now()};function g(e){var t=typeof e;return!!e&&("object"==t||"function"==t)}function y(e){if("number"==typeof e)return e;if(function(e){return"symbol"==typeof e||function(e){return!!e&&"object"==typeof e}(e)&&h.call(e)==i}(e))return n;if(g(e)){var t="function"==typeof e.valueOf?e.valueOf():e;e=g(t)?t+"":t}if("string"!=typeof e)return 0===e?e:+e;e=e.replace(r,"");var a=d.test(e);return a||l.test(e)?u(e.slice(2),a?2:8):o.test(e)?n:+e}e.exports=function(e,t,a){var n=!0,i=!0;if("function"!=typeof e)throw new TypeError(s);return g(a)&&(n="leading"in a?!!a.leading:n,i="trailing"in a?!!a.trailing:i),function(e,t,a){var n,i,r,o,d,l,u=0,c=!1,_=!1,m=!0;if("function"!=typeof e)throw new TypeError(s);function h(t){var a=n,s=i;return n=i=void 0,u=t,o=e.apply(s,a)}function k(e){var a=e-l;return void 0===l||a>=t||a<0||_&&e-u>=r}function M(){var e=v();if(k(e))return b(e);d=setTimeout(M,function(e){var a=t-(e-l);return _?f(a,r-(e-u)):a}(e))}function b(e){return d=void 0,m&&n?h(e):(n=i=void 0,o)}function L(){var e=v(),a=k(e);if(n=arguments,i=this,l=e,a){if(void 0===d)return function(e){return u=e,d=setTimeout(M,t),c?h(e):o}(l);if(_)return d=setTimeout(M,t),h(l)}return void 0===d&&(d=setTimeout(M,t)),o}return t=y(t)||0,g(a)&&(c=!!a.leading,r=(_="maxWait"in a)?p(y(a.maxWait)||0,t):r,m="trailing"in a?!!a.trailing:m),L.cancel=function(){void 0!==d&&clearTimeout(d),u=0,n=l=i=d=void 0},L.flush=function(){return void 0===d?o:b(v())},L}(e,t,{leading:n,maxWait:t,trailing:i})}},9127:function(e,t,a){!function(e){"use strict";e.defineLocale("af",{months:"Januarie_Februarie_Maart_April_Mei_Junie_Julie_Augustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mrt_Apr_Mei_Jun_Jul_Aug_Sep_Okt_Nov_Des".split("_"),weekdays:"Sondag_Maandag_Dinsdag_Woensdag_Donderdag_Vrydag_Saterdag".split("_"),weekdaysShort:"Son_Maa_Din_Woe_Don_Vry_Sat".split("_"),weekdaysMin:"So_Ma_Di_Wo_Do_Vr_Sa".split("_"),meridiemParse:/vm|nm/i,isPM:function(e){return/^nm$/i.test(e)},meridiem:function(e,t,a){return e<12?a?"vm":"VM":a?"nm":"NM"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Vandag om] LT",nextDay:"[Môre om] LT",nextWeek:"dddd [om] LT",lastDay:"[Gister om] LT",lastWeek:"[Laas] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oor %s",past:"%s gelede",s:"'n paar sekondes",ss:"%d sekondes",m:"'n minuut",mm:"%d minute",h:"'n uur",hh:"%d ure",d:"'n dag",dd:"%d dae",M:"'n maand",MM:"%d maande",y:"'n jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(a(421))},2633:function(e,t,a){!function(e){"use strict";var t=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},a={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},s=function(e){return function(s,n,i,r){var o=t(s),d=a[e][t(s)];return 2===o&&(d=d[n?0:1]),d.replace(/%d/i,s)}},n=["جانفي","فيفري","مارس","أفريل","ماي","جوان","جويلية","أوت","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar-dz",{months:n,monthsShort:n,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,a){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:s("s"),ss:s("s"),m:s("m"),mm:s("m"),h:s("h"),hh:s("h"),d:s("d"),dd:s("d"),M:s("M"),MM:s("M"),y:s("y"),yy:s("y")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:0,doy:4}})}(a(421))},3215:function(e,t,a){!function(e){"use strict";e.defineLocale("ar-kw",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإتنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اتنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:0,doy:12}})}(a(421))},6968:function(e,t,a){!function(e){"use strict";var t={1:"1",2:"2",3:"3",4:"4",5:"5",6:"6",7:"7",8:"8",9:"9",0:"0"},a=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},s={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},n=function(e){return function(t,n,i,r){var o=a(t),d=s[e][a(t)];return 2===o&&(d=d[n?0:1]),d.replace(/%d/i,t)}},i=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar-ly",{months:i,monthsShort:i,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,a){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:n("s"),ss:n("s"),m:n("m"),mm:n("m"),h:n("h"),hh:n("h"),d:n("d"),dd:n("d"),M:n("M"),MM:n("M"),y:n("y"),yy:n("y")},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(a(421))},2572:function(e,t,a){!function(e){"use strict";e.defineLocale("ar-ma",{months:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_ماي_يونيو_يوليوز_غشت_شتنبر_أكتوبر_نونبر_دجنبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"احد_اثنين_ثلاثاء_اربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})}(a(421))},8319:function(e,t,a){!function(e){"use strict";var t={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},a={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"};e.defineLocale("ar-sa",{months:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"يناير_فبراير_مارس_أبريل_مايو_يونيو_يوليو_أغسطس_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,a){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return a[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]})).replace(/,/g,"،")},week:{dow:0,doy:6}})}(a(421))},5629:function(e,t,a){!function(e){"use strict";e.defineLocale("ar-tn",{months:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),monthsShort:"جانفي_فيفري_مارس_أفريل_ماي_جوان_جويلية_أوت_سبتمبر_أكتوبر_نوفمبر_ديسمبر".split("_"),weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[اليوم على الساعة] LT",nextDay:"[غدا على الساعة] LT",nextWeek:"dddd [على الساعة] LT",lastDay:"[أمس على الساعة] LT",lastWeek:"dddd [على الساعة] LT",sameElse:"L"},relativeTime:{future:"في %s",past:"منذ %s",s:"ثوان",ss:"%d ثانية",m:"دقيقة",mm:"%d دقائق",h:"ساعة",hh:"%d ساعات",d:"يوم",dd:"%d أيام",M:"شهر",MM:"%d أشهر",y:"سنة",yy:"%d سنوات"},week:{dow:1,doy:4}})}(a(421))},7006:function(e,t,a){!function(e){"use strict";var t={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},a={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},s=function(e){return 0===e?0:1===e?1:2===e?2:e%100>=3&&e%100<=10?3:e%100>=11?4:5},n={s:["أقل من ثانية","ثانية واحدة",["ثانيتان","ثانيتين"],"%d ثوان","%d ثانية","%d ثانية"],m:["أقل من دقيقة","دقيقة واحدة",["دقيقتان","دقيقتين"],"%d دقائق","%d دقيقة","%d دقيقة"],h:["أقل من ساعة","ساعة واحدة",["ساعتان","ساعتين"],"%d ساعات","%d ساعة","%d ساعة"],d:["أقل من يوم","يوم واحد",["يومان","يومين"],"%d أيام","%d يومًا","%d يوم"],M:["أقل من شهر","شهر واحد",["شهران","شهرين"],"%d أشهر","%d شهرا","%d شهر"],y:["أقل من عام","عام واحد",["عامان","عامين"],"%d أعوام","%d عامًا","%d عام"]},i=function(e){return function(t,a,i,r){var o=s(t),d=n[e][s(t)];return 2===o&&(d=d[a?0:1]),d.replace(/%d/i,t)}},r=["يناير","فبراير","مارس","أبريل","مايو","يونيو","يوليو","أغسطس","سبتمبر","أكتوبر","نوفمبر","ديسمبر"];e.defineLocale("ar",{months:r,monthsShort:r,weekdays:"الأحد_الإثنين_الثلاثاء_الأربعاء_الخميس_الجمعة_السبت".split("_"),weekdaysShort:"أحد_إثنين_ثلاثاء_أربعاء_خميس_جمعة_سبت".split("_"),weekdaysMin:"ح_ن_ث_ر_خ_ج_س".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/‏M/‏YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/ص|م/,isPM:function(e){return"م"===e},meridiem:function(e,t,a){return e<12?"ص":"م"},calendar:{sameDay:"[اليوم عند الساعة] LT",nextDay:"[غدًا عند الساعة] LT",nextWeek:"dddd [عند الساعة] LT",lastDay:"[أمس عند الساعة] LT",lastWeek:"dddd [عند الساعة] LT",sameElse:"L"},relativeTime:{future:"بعد %s",past:"منذ %s",s:i("s"),ss:i("s"),m:i("m"),mm:i("m"),h:i("h"),hh:i("h"),d:i("d"),dd:i("d"),M:i("M"),MM:i("M"),y:i("y"),yy:i("y")},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return a[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(a(421))},6722:function(e,t,a){!function(e){"use strict";var t={1:"-inci",5:"-inci",8:"-inci",70:"-inci",80:"-inci",2:"-nci",7:"-nci",20:"-nci",50:"-nci",3:"-üncü",4:"-üncü",100:"-üncü",6:"-ncı",9:"-uncu",10:"-uncu",30:"-uncu",60:"-ıncı",90:"-ıncı"};e.defineLocale("az",{months:"yanvar_fevral_mart_aprel_may_iyun_iyul_avqust_sentyabr_oktyabr_noyabr_dekabr".split("_"),monthsShort:"yan_fev_mar_apr_may_iyn_iyl_avq_sen_okt_noy_dek".split("_"),weekdays:"Bazar_Bazar ertəsi_Çərşənbə axşamı_Çərşənbə_Cümə axşamı_Cümə_Şənbə".split("_"),weekdaysShort:"Baz_BzE_ÇAx_Çər_CAx_Cüm_Şən".split("_"),weekdaysMin:"Bz_BE_ÇA_Çə_CA_Cü_Şə".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[sabah saat] LT",nextWeek:"[gələn həftə] dddd [saat] LT",lastDay:"[dünən] LT",lastWeek:"[keçən həftə] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s əvvəl",s:"bir neçə saniyə",ss:"%d saniyə",m:"bir dəqiqə",mm:"%d dəqiqə",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",M:"bir ay",MM:"%d ay",y:"bir il",yy:"%d il"},meridiemParse:/gecə|səhər|gündüz|axşam/,isPM:function(e){return/^(gündüz|axşam)$/.test(e)},meridiem:function(e,t,a){return e<4?"gecə":e<12?"səhər":e<17?"gündüz":"axşam"},dayOfMonthOrdinalParse:/\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,ordinal:function(e){if(0===e)return e+"-ıncı";var a=e%10;return e+(t[a]||t[e%100-a]||t[e>=100?100:null])},week:{dow:1,doy:7}})}(a(421))},5958:function(e,t,a){!function(e){"use strict";function t(e,t,a){return"m"===a?t?"хвіліна":"хвіліну":"h"===a?t?"гадзіна":"гадзіну":e+" "+(s=+e,n={ss:t?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:t?"хвіліна_хвіліны_хвілін":"хвіліну_хвіліны_хвілін",hh:t?"гадзіна_гадзіны_гадзін":"гадзіну_гадзіны_гадзін",dd:"дзень_дні_дзён",MM:"месяц_месяцы_месяцаў",yy:"год_гады_гадоў"}[a].split("_"),s%10==1&&s%100!=11?n[0]:s%10>=2&&s%10<=4&&(s%100<10||s%100>=20)?n[1]:n[2]);var s,n}e.defineLocale("be",{months:{format:"студзеня_лютага_сакавіка_красавіка_траўня_чэрвеня_ліпеня_жніўня_верасня_кастрычніка_лістапада_снежня".split("_"),standalone:"студзень_люты_сакавік_красавік_травень_чэрвень_ліпень_жнівень_верасень_кастрычнік_лістапад_снежань".split("_")},monthsShort:"студ_лют_сак_крас_трав_чэрв_ліп_жнів_вер_каст_ліст_снеж".split("_"),weekdays:{format:"нядзелю_панядзелак_аўторак_сераду_чацвер_пятніцу_суботу".split("_"),standalone:"нядзеля_панядзелак_аўторак_серада_чацвер_пятніца_субота".split("_"),isFormat:/\[ ?[Ууў] ?(?:мінулую|наступную)? ?\] ?dddd/},weekdaysShort:"нд_пн_ат_ср_чц_пт_сб".split("_"),weekdaysMin:"нд_пн_ат_ср_чц_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., HH:mm",LLLL:"dddd, D MMMM YYYY г., HH:mm"},calendar:{sameDay:"[Сёння ў] LT",nextDay:"[Заўтра ў] LT",lastDay:"[Учора ў] LT",nextWeek:function(){return"[У] dddd [ў] LT"},lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return"[У мінулую] dddd [ў] LT";case 1:case 2:case 4:return"[У мінулы] dddd [ў] LT"}},sameElse:"L"},relativeTime:{future:"праз %s",past:"%s таму",s:"некалькі секунд",m:t,mm:t,h:t,hh:t,d:"дзень",dd:t,M:"месяц",MM:t,y:"год",yy:t},meridiemParse:/ночы|раніцы|дня|вечара/,isPM:function(e){return/^(дня|вечара)$/.test(e)},meridiem:function(e,t,a){return e<4?"ночы":e<12?"раніцы":e<17?"дня":"вечара"},dayOfMonthOrdinalParse:/\d{1,2}-(і|ы|га)/,ordinal:function(e,t){switch(t){case"M":case"d":case"DDD":case"w":case"W":return e%10!=2&&e%10!=3||e%100==12||e%100==13?e+"-ы":e+"-і";case"D":return e+"-га";default:return e}},week:{dow:1,doy:7}})}(a(421))},4921:function(e,t,a){!function(e){"use strict";e.defineLocale("bg",{months:"януари_февруари_март_април_май_юни_юли_август_септември_октомври_ноември_декември".split("_"),monthsShort:"яну_фев_мар_апр_май_юни_юли_авг_сеп_окт_ное_дек".split("_"),weekdays:"неделя_понеделник_вторник_сряда_четвъртък_петък_събота".split("_"),weekdaysShort:"нед_пон_вто_сря_чет_пет_съб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Днес в] LT",nextDay:"[Утре в] LT",nextWeek:"dddd [в] LT",lastDay:"[Вчера в] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Миналата] dddd [в] LT";case 1:case 2:case 4:case 5:return"[Миналия] dddd [в] LT"}},sameElse:"L"},relativeTime:{future:"след %s",past:"преди %s",s:"няколко секунди",ss:"%d секунди",m:"минута",mm:"%d минути",h:"час",hh:"%d часа",d:"ден",dd:"%d дена",w:"седмица",ww:"%d седмици",M:"месец",MM:"%d месеца",y:"година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var t=e%10,a=e%100;return 0===e?e+"-ев":0===a?e+"-ен":a>10&&a<20?e+"-ти":1===t?e+"-ви":2===t?e+"-ри":7===t||8===t?e+"-ми":e+"-ти"},week:{dow:1,doy:7}})}(a(421))},7293:function(e,t,a){!function(e){"use strict";e.defineLocale("bm",{months:"Zanwuyekalo_Fewuruyekalo_Marisikalo_Awirilikalo_Mɛkalo_Zuwɛnkalo_Zuluyekalo_Utikalo_Sɛtanburukalo_ɔkutɔburukalo_Nowanburukalo_Desanburukalo".split("_"),monthsShort:"Zan_Few_Mar_Awi_Mɛ_Zuw_Zul_Uti_Sɛt_ɔku_Now_Des".split("_"),weekdays:"Kari_Ntɛnɛn_Tarata_Araba_Alamisa_Juma_Sibiri".split("_"),weekdaysShort:"Kar_Ntɛ_Tar_Ara_Ala_Jum_Sib".split("_"),weekdaysMin:"Ka_Nt_Ta_Ar_Al_Ju_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"MMMM [tile] D [san] YYYY",LLL:"MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm",LLLL:"dddd MMMM [tile] D [san] YYYY [lɛrɛ] HH:mm"},calendar:{sameDay:"[Bi lɛrɛ] LT",nextDay:"[Sini lɛrɛ] LT",nextWeek:"dddd [don lɛrɛ] LT",lastDay:"[Kunu lɛrɛ] LT",lastWeek:"dddd [tɛmɛnen lɛrɛ] LT",sameElse:"L"},relativeTime:{future:"%s kɔnɔ",past:"a bɛ %s bɔ",s:"sanga dama dama",ss:"sekondi %d",m:"miniti kelen",mm:"miniti %d",h:"lɛrɛ kelen",hh:"lɛrɛ %d",d:"tile kelen",dd:"tile %d",M:"kalo kelen",MM:"kalo %d",y:"san kelen",yy:"san %d"},week:{dow:1,doy:4}})}(a(421))},9907:function(e,t,a){!function(e){"use strict";var t={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},a={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};e.defineLocale("bn-bd",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/রাত|ভোর|সকাল|দুপুর|বিকাল|সন্ধ্যা|রাত/,meridiemHour:function(e,t){return 12===e&&(e=0),"রাত"===t?e<4?e:e+12:"ভোর"===t||"সকাল"===t?e:"দুপুর"===t?e>=3?e:e+12:"বিকাল"===t||"সন্ধ্যা"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"রাত":e<6?"ভোর":e<12?"সকাল":e<15?"দুপুর":e<18?"বিকাল":e<20?"সন্ধ্যা":"রাত"},week:{dow:0,doy:6}})}(a(421))},2288:function(e,t,a){!function(e){"use strict";var t={1:"১",2:"২",3:"৩",4:"৪",5:"৫",6:"৬",7:"৭",8:"৮",9:"৯",0:"০"},a={"১":"1","২":"2","৩":"3","৪":"4","৫":"5","৬":"6","৭":"7","৮":"8","৯":"9","০":"0"};e.defineLocale("bn",{months:"জানুয়ারি_ফেব্রুয়ারি_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্টেম্বর_অক্টোবর_নভেম্বর_ডিসেম্বর".split("_"),monthsShort:"জানু_ফেব্রু_মার্চ_এপ্রিল_মে_জুন_জুলাই_আগস্ট_সেপ্ট_অক্টো_নভে_ডিসে".split("_"),weekdays:"রবিবার_সোমবার_মঙ্গলবার_বুধবার_বৃহস্পতিবার_শুক্রবার_শনিবার".split("_"),weekdaysShort:"রবি_সোম_মঙ্গল_বুধ_বৃহস্পতি_শুক্র_শনি".split("_"),weekdaysMin:"রবি_সোম_মঙ্গল_বুধ_বৃহ_শুক্র_শনি".split("_"),longDateFormat:{LT:"A h:mm সময়",LTS:"A h:mm:ss সময়",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm সময়",LLLL:"dddd, D MMMM YYYY, A h:mm সময়"},calendar:{sameDay:"[আজ] LT",nextDay:"[আগামীকাল] LT",nextWeek:"dddd, LT",lastDay:"[গতকাল] LT",lastWeek:"[গত] dddd, LT",sameElse:"L"},relativeTime:{future:"%s পরে",past:"%s আগে",s:"কয়েক সেকেন্ড",ss:"%d সেকেন্ড",m:"এক মিনিট",mm:"%d মিনিট",h:"এক ঘন্টা",hh:"%d ঘন্টা",d:"এক দিন",dd:"%d দিন",M:"এক মাস",MM:"%d মাস",y:"এক বছর",yy:"%d বছর"},preparse:function(e){return e.replace(/[১২৩৪৫৬৭৮৯০]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/রাত|সকাল|দুপুর|বিকাল|রাত/,meridiemHour:function(e,t){return 12===e&&(e=0),"রাত"===t&&e>=4||"দুপুর"===t&&e<5||"বিকাল"===t?e+12:e},meridiem:function(e,t,a){return e<4?"রাত":e<10?"সকাল":e<17?"দুপুর":e<20?"বিকাল":"রাত"},week:{dow:0,doy:6}})}(a(421))},2127:function(e,t,a){!function(e){"use strict";var t={1:"༡",2:"༢",3:"༣",4:"༤",5:"༥",6:"༦",7:"༧",8:"༨",9:"༩",0:"༠"},a={"༡":"1","༢":"2","༣":"3","༤":"4","༥":"5","༦":"6","༧":"7","༨":"8","༩":"9","༠":"0"};e.defineLocale("bo",{months:"ཟླ་བ་དང་པོ_ཟླ་བ་གཉིས་པ_ཟླ་བ་གསུམ་པ_ཟླ་བ་བཞི་པ_ཟླ་བ་ལྔ་པ_ཟླ་བ་དྲུག་པ_ཟླ་བ་བདུན་པ_ཟླ་བ་བརྒྱད་པ_ཟླ་བ་དགུ་པ_ཟླ་བ་བཅུ་པ_ཟླ་བ་བཅུ་གཅིག་པ_ཟླ་བ་བཅུ་གཉིས་པ".split("_"),monthsShort:"ཟླ་1_ཟླ་2_ཟླ་3_ཟླ་4_ཟླ་5_ཟླ་6_ཟླ་7_ཟླ་8_ཟླ་9_ཟླ་10_ཟླ་11_ཟླ་12".split("_"),monthsShortRegex:/^(ཟླ་\d{1,2})/,monthsParseExact:!0,weekdays:"གཟའ་ཉི་མ་_གཟའ་ཟླ་བ་_གཟའ་མིག་དམར་_གཟའ་ལྷག་པ་_གཟའ་ཕུར་བུ_གཟའ་པ་སངས་_གཟའ་སྤེན་པ་".split("_"),weekdaysShort:"ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་".split("_"),weekdaysMin:"ཉི_ཟླ_མིག_ལྷག_ཕུར_སངས_སྤེན".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[དི་རིང] LT",nextDay:"[སང་ཉིན] LT",nextWeek:"[བདུན་ཕྲག་རྗེས་མ], LT",lastDay:"[ཁ་སང] LT",lastWeek:"[བདུན་ཕྲག་མཐའ་མ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ལ་",past:"%s སྔན་ལ",s:"ལམ་སང",ss:"%d སྐར་ཆ།",m:"སྐར་མ་གཅིག",mm:"%d སྐར་མ",h:"ཆུ་ཚོད་གཅིག",hh:"%d ཆུ་ཚོད",d:"ཉིན་གཅིག",dd:"%d ཉིན་",M:"ཟླ་བ་གཅིག",MM:"%d ཟླ་བ",y:"ལོ་གཅིག",yy:"%d ལོ"},preparse:function(e){return e.replace(/[༡༢༣༤༥༦༧༨༩༠]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/མཚན་མོ|ཞོགས་ཀས|ཉིན་གུང|དགོང་དག|མཚན་མོ/,meridiemHour:function(e,t){return 12===e&&(e=0),"མཚན་མོ"===t&&e>=4||"ཉིན་གུང"===t&&e<5||"དགོང་དག"===t?e+12:e},meridiem:function(e,t,a){return e<4?"མཚན་མོ":e<10?"ཞོགས་ཀས":e<17?"ཉིན་གུང":e<20?"དགོང་དག":"མཚན་མོ"},week:{dow:0,doy:6}})}(a(421))},3922:function(e,t,a){!function(e){"use strict";function t(e,t,a){return e+" "+function(e,t){return 2===t?function(e){var t={m:"v",b:"v",d:"z"};return void 0===t[e.charAt(0)]?e:t[e.charAt(0)]+e.substring(1)}(e):e}({mm:"munutenn",MM:"miz",dd:"devezh"}[a],e)}function a(e){return e>9?a(e%10):e}var s=[/^gen/i,/^c[ʼ\']hwe/i,/^meu/i,/^ebr/i,/^mae/i,/^(mez|eve)/i,/^gou/i,/^eos/i,/^gwe/i,/^her/i,/^du/i,/^ker/i],n=/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu|gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,i=[/^Su/i,/^Lu/i,/^Me([^r]|$)/i,/^Mer/i,/^Ya/i,/^Gw/i,/^Sa/i];e.defineLocale("br",{months:"Genver_Cʼhwevrer_Meurzh_Ebrel_Mae_Mezheven_Gouere_Eost_Gwengolo_Here_Du_Kerzu".split("_"),monthsShort:"Gen_Cʼhwe_Meu_Ebr_Mae_Eve_Gou_Eos_Gwe_Her_Du_Ker".split("_"),weekdays:"Sul_Lun_Meurzh_Mercʼher_Yaou_Gwener_Sadorn".split("_"),weekdaysShort:"Sul_Lun_Meu_Mer_Yao_Gwe_Sad".split("_"),weekdaysMin:"Su_Lu_Me_Mer_Ya_Gw_Sa".split("_"),weekdaysParse:i,fullWeekdaysParse:[/^sul/i,/^lun/i,/^meurzh/i,/^merc[ʼ\']her/i,/^yaou/i,/^gwener/i,/^sadorn/i],shortWeekdaysParse:[/^Sul/i,/^Lun/i,/^Meu/i,/^Mer/i,/^Yao/i,/^Gwe/i,/^Sad/i],minWeekdaysParse:i,monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(genver|c[ʼ\']hwevrer|meurzh|ebrel|mae|mezheven|gouere|eost|gwengolo|here|du|kerzu)/i,monthsShortStrictRegex:/^(gen|c[ʼ\']hwe|meu|ebr|mae|eve|gou|eos|gwe|her|du|ker)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [a viz] MMMM YYYY",LLL:"D [a viz] MMMM YYYY HH:mm",LLLL:"dddd, D [a viz] MMMM YYYY HH:mm"},calendar:{sameDay:"[Hiziv da] LT",nextDay:"[Warcʼhoazh da] LT",nextWeek:"dddd [da] LT",lastDay:"[Decʼh da] LT",lastWeek:"dddd [paset da] LT",sameElse:"L"},relativeTime:{future:"a-benn %s",past:"%s ʼzo",s:"un nebeud segondennoù",ss:"%d eilenn",m:"ur vunutenn",mm:t,h:"un eur",hh:"%d eur",d:"un devezh",dd:t,M:"ur miz",MM:t,y:"ur bloaz",yy:function(e){switch(a(e)){case 1:case 3:case 4:case 5:case 9:return e+" bloaz";default:return e+" vloaz"}}},dayOfMonthOrdinalParse:/\d{1,2}(añ|vet)/,ordinal:function(e){return e+(1===e?"añ":"vet")},week:{dow:1,doy:4},meridiemParse:/a.m.|g.m./,isPM:function(e){return"g.m."===e},meridiem:function(e,t,a){return e<12?"a.m.":"g.m."}})}(a(421))},8932:function(e,t,a){!function(e){"use strict";function t(e,t,a){var s=e+" ";switch(a){case"ss":return s+(1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi");case"m":return t?"jedna minuta":"jedne minute";case"mm":return s+(1===e?"minuta":2===e||3===e||4===e?"minute":"minuta");case"h":return t?"jedan sat":"jednog sata";case"hh":return s+(1===e?"sat":2===e||3===e||4===e?"sata":"sati");case"dd":return s+(1===e?"dan":"dana");case"MM":return s+(1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci");case"yy":return s+(1===e?"godina":2===e||3===e||4===e?"godine":"godina")}}e.defineLocale("bs",{months:"januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:case 3:return"[prošlu] dddd [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:t,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(a(421))},3246:function(e,t,a){!function(e){"use strict";e.defineLocale("ca",{months:{standalone:"gener_febrer_març_abril_maig_juny_juliol_agost_setembre_octubre_novembre_desembre".split("_"),format:"de gener_de febrer_de març_d'abril_de maig_de juny_de juliol_d'agost_de setembre_d'octubre_de novembre_de desembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._març_abr._maig_juny_jul._ag._set._oct._nov._des.".split("_"),monthsParseExact:!0,weekdays:"diumenge_dilluns_dimarts_dimecres_dijous_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dt._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dt_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a les] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a les] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:function(){return"[avui a "+(1!==this.hours()?"les":"la")+"] LT"},nextDay:function(){return"[demà a "+(1!==this.hours()?"les":"la")+"] LT"},nextWeek:function(){return"dddd [a "+(1!==this.hours()?"les":"la")+"] LT"},lastDay:function(){return"[ahir a "+(1!==this.hours()?"les":"la")+"] LT"},lastWeek:function(){return"[el] dddd [passat a "+(1!==this.hours()?"les":"la")+"] LT"},sameElse:"L"},relativeTime:{future:"d'aquí %s",past:"fa %s",s:"uns segons",ss:"%d segons",m:"un minut",mm:"%d minuts",h:"una hora",hh:"%d hores",d:"un dia",dd:"%d dies",M:"un mes",MM:"%d mesos",y:"un any",yy:"%d anys"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,t){var a=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"è";return"w"!==t&&"W"!==t||(a="a"),e+a},week:{dow:1,doy:4}})}(a(421))},8208:function(e,t,a){!function(e){"use strict";var t={format:"leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec".split("_"),standalone:"ledna_února_března_dubna_května_června_července_srpna_září_října_listopadu_prosince".split("_")},a="led_úno_bře_dub_kvě_čvn_čvc_srp_zář_říj_lis_pro".split("_"),s=[/^led/i,/^úno/i,/^bře/i,/^dub/i,/^kvě/i,/^(čvn|červen$|června)/i,/^(čvc|červenec|července)/i,/^srp/i,/^zář/i,/^říj/i,/^lis/i,/^pro/i],n=/^(leden|únor|březen|duben|květen|červenec|července|červen|června|srpen|září|říjen|listopad|prosinec|led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i;function i(e){return e>1&&e<5&&1!=~~(e/10)}function r(e,t,a,s){var n=e+" ";switch(a){case"s":return t||s?"pár sekund":"pár sekundami";case"ss":return t||s?n+(i(e)?"sekundy":"sekund"):n+"sekundami";case"m":return t?"minuta":s?"minutu":"minutou";case"mm":return t||s?n+(i(e)?"minuty":"minut"):n+"minutami";case"h":return t?"hodina":s?"hodinu":"hodinou";case"hh":return t||s?n+(i(e)?"hodiny":"hodin"):n+"hodinami";case"d":return t||s?"den":"dnem";case"dd":return t||s?n+(i(e)?"dny":"dní"):n+"dny";case"M":return t||s?"měsíc":"měsícem";case"MM":return t||s?n+(i(e)?"měsíce":"měsíců"):n+"měsíci";case"y":return t||s?"rok":"rokem";case"yy":return t||s?n+(i(e)?"roky":"let"):n+"lety"}}e.defineLocale("cs",{months:t,monthsShort:a,monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(leden|ledna|února|únor|březen|března|duben|dubna|květen|května|červenec|července|červen|června|srpen|srpna|září|říjen|října|listopadu|listopad|prosinec|prosince)/i,monthsShortStrictRegex:/^(led|úno|bře|dub|kvě|čvn|čvc|srp|zář|říj|lis|pro)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"neděle_pondělí_úterý_středa_čtvrtek_pátek_sobota".split("_"),weekdaysShort:"ne_po_út_st_čt_pá_so".split("_"),weekdaysMin:"ne_po_út_st_čt_pá_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm",l:"D. M. YYYY"},calendar:{sameDay:"[dnes v] LT",nextDay:"[zítra v] LT",nextWeek:function(){switch(this.day()){case 0:return"[v neděli v] LT";case 1:case 2:return"[v] dddd [v] LT";case 3:return"[ve středu v] LT";case 4:return"[ve čtvrtek v] LT";case 5:return"[v pátek v] LT";case 6:return"[v sobotu v] LT"}},lastDay:"[včera v] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulou neděli v] LT";case 1:case 2:return"[minulé] dddd [v] LT";case 3:return"[minulou středu v] LT";case 4:case 5:return"[minulý] dddd [v] LT";case 6:return"[minulou sobotu v] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"před %s",s:r,ss:r,m:r,mm:r,h:r,hh:r,d:r,dd:r,M:r,MM:r,y:r,yy:r},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},6492:function(e,t,a){!function(e){"use strict";e.defineLocale("cv",{months:"кӑрлач_нарӑс_пуш_ака_май_ҫӗртме_утӑ_ҫурла_авӑн_юпа_чӳк_раштав".split("_"),monthsShort:"кӑр_нар_пуш_ака_май_ҫӗр_утӑ_ҫур_авн_юпа_чӳк_раш".split("_"),weekdays:"вырсарникун_тунтикун_ытларикун_юнкун_кӗҫнерникун_эрнекун_шӑматкун".split("_"),weekdaysShort:"выр_тун_ытл_юн_кӗҫ_эрн_шӑм".split("_"),weekdaysMin:"вр_тн_ыт_юн_кҫ_эр_шм".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ]",LLL:"YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm",LLLL:"dddd, YYYY [ҫулхи] MMMM [уйӑхӗн] D[-мӗшӗ], HH:mm"},calendar:{sameDay:"[Паян] LT [сехетре]",nextDay:"[Ыран] LT [сехетре]",lastDay:"[Ӗнер] LT [сехетре]",nextWeek:"[Ҫитес] dddd LT [сехетре]",lastWeek:"[Иртнӗ] dddd LT [сехетре]",sameElse:"L"},relativeTime:{future:function(e){return e+(/сехет$/i.exec(e)?"рен":/ҫул$/i.exec(e)?"тан":"ран")},past:"%s каялла",s:"пӗр-ик ҫеккунт",ss:"%d ҫеккунт",m:"пӗр минут",mm:"%d минут",h:"пӗр сехет",hh:"%d сехет",d:"пӗр кун",dd:"%d кун",M:"пӗр уйӑх",MM:"%d уйӑх",y:"пӗр ҫул",yy:"%d ҫул"},dayOfMonthOrdinalParse:/\d{1,2}-мӗш/,ordinal:"%d-мӗш",week:{dow:1,doy:7}})}(a(421))},1883:function(e,t,a){!function(e){"use strict";e.defineLocale("cy",{months:"Ionawr_Chwefror_Mawrth_Ebrill_Mai_Mehefin_Gorffennaf_Awst_Medi_Hydref_Tachwedd_Rhagfyr".split("_"),monthsShort:"Ion_Chwe_Maw_Ebr_Mai_Meh_Gor_Aws_Med_Hyd_Tach_Rhag".split("_"),weekdays:"Dydd Sul_Dydd Llun_Dydd Mawrth_Dydd Mercher_Dydd Iau_Dydd Gwener_Dydd Sadwrn".split("_"),weekdaysShort:"Sul_Llun_Maw_Mer_Iau_Gwe_Sad".split("_"),weekdaysMin:"Su_Ll_Ma_Me_Ia_Gw_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Heddiw am] LT",nextDay:"[Yfory am] LT",nextWeek:"dddd [am] LT",lastDay:"[Ddoe am] LT",lastWeek:"dddd [diwethaf am] LT",sameElse:"L"},relativeTime:{future:"mewn %s",past:"%s yn ôl",s:"ychydig eiliadau",ss:"%d eiliad",m:"munud",mm:"%d munud",h:"awr",hh:"%d awr",d:"diwrnod",dd:"%d diwrnod",M:"mis",MM:"%d mis",y:"blwyddyn",yy:"%d flynedd"},dayOfMonthOrdinalParse:/\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,ordinal:function(e){var t="";return e>20?t=40===e||50===e||60===e||80===e||100===e?"fed":"ain":e>0&&(t=["","af","il","ydd","ydd","ed","ed","ed","fed","fed","fed","eg","fed","eg","eg","fed","eg","eg","fed","eg","fed"][e]),e+t},week:{dow:1,doy:4}})}(a(421))},2285:function(e,t,a){!function(e){"use strict";e.defineLocale("da",{months:"januar_februar_marts_april_maj_juni_juli_august_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"søn_man_tir_ons_tor_fre_lør".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd [d.] D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"på dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[i] dddd[s kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"få sekunder",ss:"%d sekunder",m:"et minut",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dage",M:"en måned",MM:"%d måneder",y:"et år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},3082:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return t?n[a][0]:n[a][1]}e.defineLocale("de-at",{months:"Jänner_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jän._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:t,mm:"%d Minuten",h:t,hh:"%d Stunden",d:t,dd:t,w:t,ww:"%d Wochen",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},9076:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return t?n[a][0]:n[a][1]}e.defineLocale("de-ch",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:t,mm:"%d Minuten",h:t,hh:"%d Stunden",d:t,dd:t,w:t,ww:"%d Wochen",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},6454:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={m:["eine Minute","einer Minute"],h:["eine Stunde","einer Stunde"],d:["ein Tag","einem Tag"],dd:[e+" Tage",e+" Tagen"],w:["eine Woche","einer Woche"],M:["ein Monat","einem Monat"],MM:[e+" Monate",e+" Monaten"],y:["ein Jahr","einem Jahr"],yy:[e+" Jahre",e+" Jahren"]};return t?n[a][0]:n[a][1]}e.defineLocale("de",{months:"Januar_Februar_März_April_Mai_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Feb._März_Apr._Mai_Juni_Juli_Aug._Sep._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonntag_Montag_Dienstag_Mittwoch_Donnerstag_Freitag_Samstag".split("_"),weekdaysShort:"So._Mo._Di._Mi._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mo_Di_Mi_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY HH:mm",LLLL:"dddd, D. MMMM YYYY HH:mm"},calendar:{sameDay:"[heute um] LT [Uhr]",sameElse:"L",nextDay:"[morgen um] LT [Uhr]",nextWeek:"dddd [um] LT [Uhr]",lastDay:"[gestern um] LT [Uhr]",lastWeek:"[letzten] dddd [um] LT [Uhr]"},relativeTime:{future:"in %s",past:"vor %s",s:"ein paar Sekunden",ss:"%d Sekunden",m:t,mm:"%d Minuten",h:t,hh:"%d Stunden",d:t,dd:t,w:t,ww:"%d Wochen",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},9016:function(e,t,a){!function(e){"use strict";var t=["ޖެނުއަރީ","ފެބްރުއަރީ","މާރިޗު","އޭޕްރީލު","މޭ","ޖޫން","ޖުލައި","އޯގަސްޓު","ސެޕްޓެމްބަރު","އޮކްޓޯބަރު","ނޮވެމްބަރު","ޑިސެމްބަރު"],a=["އާދިއްތަ","ހޯމަ","އަންގާރަ","ބުދަ","ބުރާސްފަތި","ހުކުރު","ހޮނިހިރު"];e.defineLocale("dv",{months:t,monthsShort:t,weekdays:a,weekdaysShort:a,weekdaysMin:"އާދި_ހޯމަ_އަން_ބުދަ_ބުރާ_ހުކު_ހޮނި".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"D/M/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},meridiemParse:/މކ|މފ/,isPM:function(e){return"މފ"===e},meridiem:function(e,t,a){return e<12?"މކ":"މފ"},calendar:{sameDay:"[މިއަދު] LT",nextDay:"[މާދަމާ] LT",nextWeek:"dddd LT",lastDay:"[އިއްޔެ] LT",lastWeek:"[ފާއިތުވި] dddd LT",sameElse:"L"},relativeTime:{future:"ތެރޭގައި %s",past:"ކުރިން %s",s:"ސިކުންތުކޮޅެއް",ss:"d% ސިކުންތު",m:"މިނިޓެއް",mm:"މިނިޓު %d",h:"ގަޑިއިރެއް",hh:"ގަޑިއިރު %d",d:"ދުވަހެއް",dd:"ދުވަސް %d",M:"މަހެއް",MM:"މަސް %d",y:"އަހަރެއް",yy:"އަހަރު %d"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:7,doy:12}})}(a(421))},3093:function(e,t,a){!function(e){"use strict";e.defineLocale("el",{monthsNominativeEl:"Ιανουάριος_Φεβρουάριος_Μάρτιος_Απρίλιος_Μάιος_Ιούνιος_Ιούλιος_Αύγουστος_Σεπτέμβριος_Οκτώβριος_Νοέμβριος_Δεκέμβριος".split("_"),monthsGenitiveEl:"Ιανουαρίου_Φεβρουαρίου_Μαρτίου_Απριλίου_Μαΐου_Ιουνίου_Ιουλίου_Αυγούστου_Σεπτεμβρίου_Οκτωβρίου_Νοεμβρίου_Δεκεμβρίου".split("_"),months:function(e,t){return e?"string"==typeof t&&/D/.test(t.substring(0,t.indexOf("MMMM")))?this._monthsGenitiveEl[e.month()]:this._monthsNominativeEl[e.month()]:this._monthsNominativeEl},monthsShort:"Ιαν_Φεβ_Μαρ_Απρ_Μαϊ_Ιουν_Ιουλ_Αυγ_Σεπ_Οκτ_Νοε_Δεκ".split("_"),weekdays:"Κυριακή_Δευτέρα_Τρίτη_Τετάρτη_Πέμπτη_Παρασκευή_Σάββατο".split("_"),weekdaysShort:"Κυρ_Δευ_Τρι_Τετ_Πεμ_Παρ_Σαβ".split("_"),weekdaysMin:"Κυ_Δε_Τρ_Τε_Πε_Πα_Σα".split("_"),meridiem:function(e,t,a){return e>11?a?"μμ":"ΜΜ":a?"πμ":"ΠΜ"},isPM:function(e){return"μ"===(e+"").toLowerCase()[0]},meridiemParse:/[ΠΜ]\.?Μ?\.?/i,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendarEl:{sameDay:"[Σήμερα {}] LT",nextDay:"[Αύριο {}] LT",nextWeek:"dddd [{}] LT",lastDay:"[Χθες {}] LT",lastWeek:function(){return 6===this.day()?"[το προηγούμενο] dddd [{}] LT":"[την προηγούμενη] dddd [{}] LT"},sameElse:"L"},calendar:function(e,t){var a,s=this._calendarEl[e],n=t&&t.hours();return a=s,("undefined"!=typeof Function&&a instanceof Function||"[object Function]"===Object.prototype.toString.call(a))&&(s=s.apply(t)),s.replace("{}",n%12==1?"στη":"στις")},relativeTime:{future:"σε %s",past:"%s πριν",s:"λίγα δευτερόλεπτα",ss:"%d δευτερόλεπτα",m:"ένα λεπτό",mm:"%d λεπτά",h:"μία ώρα",hh:"%d ώρες",d:"μία μέρα",dd:"%d μέρες",M:"ένας μήνας",MM:"%d μήνες",y:"ένας χρόνος",yy:"%d χρόνια"},dayOfMonthOrdinalParse:/\d{1,2}η/,ordinal:"%dη",week:{dow:1,doy:4}})}(a(421))},5535:function(e,t,a){!function(e){"use strict";e.defineLocale("en-au",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:0,doy:4}})}(a(421))},2610:function(e,t,a){!function(e){"use strict";e.defineLocale("en-ca",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"YYYY-MM-DD",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}})}(a(421))},8386:function(e,t,a){!function(e){"use strict";e.defineLocale("en-gb",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(a(421))},5272:function(e,t,a){!function(e){"use strict";e.defineLocale("en-ie",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(a(421))},3563:function(e,t,a){!function(e){"use strict";e.defineLocale("en-il",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}})}(a(421))},8604:function(e,t,a){!function(e){"use strict";e.defineLocale("en-in",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:0,doy:6}})}(a(421))},2140:function(e,t,a){!function(e){"use strict";e.defineLocale("en-nz",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(a(421))},8217:function(e,t,a){!function(e){"use strict";e.defineLocale("en-sg",{months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),monthsShort:"Jan_Feb_Mar_Apr_May_Jun_Jul_Aug_Sep_Oct_Nov_Dec".split("_"),weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),weekdaysShort:"Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),weekdaysMin:"Su_Mo_Tu_We_Th_Fr_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(a(421))},9823:function(e,t,a){!function(e){"use strict";e.defineLocale("eo",{months:"januaro_februaro_marto_aprilo_majo_junio_julio_aŭgusto_septembro_oktobro_novembro_decembro".split("_"),monthsShort:"jan_feb_mart_apr_maj_jun_jul_aŭg_sept_okt_nov_dec".split("_"),weekdays:"dimanĉo_lundo_mardo_merkredo_ĵaŭdo_vendredo_sabato".split("_"),weekdaysShort:"dim_lun_mard_merk_ĵaŭ_ven_sab".split("_"),weekdaysMin:"di_lu_ma_me_ĵa_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"[la] D[-an de] MMMM, YYYY",LLL:"[la] D[-an de] MMMM, YYYY HH:mm",LLLL:"dddd[n], [la] D[-an de] MMMM, YYYY HH:mm",llll:"ddd, [la] D[-an de] MMM, YYYY HH:mm"},meridiemParse:/[ap]\.t\.m/i,isPM:function(e){return"p"===e.charAt(0).toLowerCase()},meridiem:function(e,t,a){return e>11?a?"p.t.m.":"P.T.M.":a?"a.t.m.":"A.T.M."},calendar:{sameDay:"[Hodiaŭ je] LT",nextDay:"[Morgaŭ je] LT",nextWeek:"dddd[n je] LT",lastDay:"[Hieraŭ je] LT",lastWeek:"[pasintan] dddd[n je] LT",sameElse:"L"},relativeTime:{future:"post %s",past:"antaŭ %s",s:"kelkaj sekundoj",ss:"%d sekundoj",m:"unu minuto",mm:"%d minutoj",h:"unu horo",hh:"%d horoj",d:"unu tago",dd:"%d tagoj",M:"unu monato",MM:"%d monatoj",y:"unu jaro",yy:"%d jaroj"},dayOfMonthOrdinalParse:/\d{1,2}a/,ordinal:"%da",week:{dow:1,doy:7}})}(a(421))},9546:function(e,t,a){!function(e){"use strict";var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),a="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-do",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?a[e.month()]:t[e.month()]:t},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(a(421))},9089:function(e,t,a){!function(e){"use strict";var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),a="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-mx",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?a[e.month()]:t[e.month()]:t},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:0,doy:4},invalidDate:"Fecha inválida"})}(a(421))},7781:function(e,t,a){!function(e){"use strict";var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),a="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es-us",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?a[e.month()]:t[e.month()]:t},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"MM/DD/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY h:mm A",LLLL:"dddd, D [de] MMMM [de] YYYY h:mm A"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:0,doy:6}})}(a(421))},312:function(e,t,a){!function(e){"use strict";var t="ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.".split("_"),a="ene_feb_mar_abr_may_jun_jul_ago_sep_oct_nov_dic".split("_"),s=[/^ene/i,/^feb/i,/^mar/i,/^abr/i,/^may/i,/^jun/i,/^jul/i,/^ago/i,/^sep/i,/^oct/i,/^nov/i,/^dic/i],n=/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre|ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i;e.defineLocale("es",{months:"enero_febrero_marzo_abril_mayo_junio_julio_agosto_septiembre_octubre_noviembre_diciembre".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?a[e.month()]:t[e.month()]:t},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(enero|febrero|marzo|abril|mayo|junio|julio|agosto|septiembre|octubre|noviembre|diciembre)/i,monthsShortStrictRegex:/^(ene\.?|feb\.?|mar\.?|abr\.?|may\.?|jun\.?|jul\.?|ago\.?|sep\.?|oct\.?|nov\.?|dic\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"domingo_lunes_martes_miércoles_jueves_viernes_sábado".split("_"),weekdaysShort:"dom._lun._mar._mié._jue._vie._sáb.".split("_"),weekdaysMin:"do_lu_ma_mi_ju_vi_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoy a la"+(1!==this.hours()?"s":"")+"] LT"},nextDay:function(){return"[mañana a la"+(1!==this.hours()?"s":"")+"] LT"},nextWeek:function(){return"dddd [a la"+(1!==this.hours()?"s":"")+"] LT"},lastDay:function(){return"[ayer a la"+(1!==this.hours()?"s":"")+"] LT"},lastWeek:function(){return"[el] dddd [pasado a la"+(1!==this.hours()?"s":"")+"] LT"},sameElse:"L"},relativeTime:{future:"en %s",past:"hace %s",s:"unos segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"una hora",hh:"%d horas",d:"un día",dd:"%d días",w:"una semana",ww:"%d semanas",M:"un mes",MM:"%d meses",y:"un año",yy:"%d años"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4},invalidDate:"Fecha inválida"})}(a(421))},8563:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={s:["mõne sekundi","mõni sekund","paar sekundit"],ss:[e+"sekundi",e+"sekundit"],m:["ühe minuti","üks minut"],mm:[e+" minuti",e+" minutit"],h:["ühe tunni","tund aega","üks tund"],hh:[e+" tunni",e+" tundi"],d:["ühe päeva","üks päev"],M:["kuu aja","kuu aega","üks kuu"],MM:[e+" kuu",e+" kuud"],y:["ühe aasta","aasta","üks aasta"],yy:[e+" aasta",e+" aastat"]};return t?n[a][2]?n[a][2]:n[a][1]:s?n[a][0]:n[a][1]}e.defineLocale("et",{months:"jaanuar_veebruar_märts_aprill_mai_juuni_juuli_august_september_oktoober_november_detsember".split("_"),monthsShort:"jaan_veebr_märts_apr_mai_juuni_juuli_aug_sept_okt_nov_dets".split("_"),weekdays:"pühapäev_esmaspäev_teisipäev_kolmapäev_neljapäev_reede_laupäev".split("_"),weekdaysShort:"P_E_T_K_N_R_L".split("_"),weekdaysMin:"P_E_T_K_N_R_L".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[Täna,] LT",nextDay:"[Homme,] LT",nextWeek:"[Järgmine] dddd LT",lastDay:"[Eile,] LT",lastWeek:"[Eelmine] dddd LT",sameElse:"L"},relativeTime:{future:"%s pärast",past:"%s tagasi",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:"%d päeva",M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},4003:function(e,t,a){!function(e){"use strict";e.defineLocale("eu",{months:"urtarrila_otsaila_martxoa_apirila_maiatza_ekaina_uztaila_abuztua_iraila_urria_azaroa_abendua".split("_"),monthsShort:"urt._ots._mar._api._mai._eka._uzt._abu._ira._urr._aza._abe.".split("_"),monthsParseExact:!0,weekdays:"igandea_astelehena_asteartea_asteazkena_osteguna_ostirala_larunbata".split("_"),weekdaysShort:"ig._al._ar._az._og._ol._lr.".split("_"),weekdaysMin:"ig_al_ar_az_og_ol_lr".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY[ko] MMMM[ren] D[a]",LLL:"YYYY[ko] MMMM[ren] D[a] HH:mm",LLLL:"dddd, YYYY[ko] MMMM[ren] D[a] HH:mm",l:"YYYY-M-D",ll:"YYYY[ko] MMM D[a]",lll:"YYYY[ko] MMM D[a] HH:mm",llll:"ddd, YYYY[ko] MMM D[a] HH:mm"},calendar:{sameDay:"[gaur] LT[etan]",nextDay:"[bihar] LT[etan]",nextWeek:"dddd LT[etan]",lastDay:"[atzo] LT[etan]",lastWeek:"[aurreko] dddd LT[etan]",sameElse:"L"},relativeTime:{future:"%s barru",past:"duela %s",s:"segundo batzuk",ss:"%d segundo",m:"minutu bat",mm:"%d minutu",h:"ordu bat",hh:"%d ordu",d:"egun bat",dd:"%d egun",M:"hilabete bat",MM:"%d hilabete",y:"urte bat",yy:"%d urte"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(a(421))},463:function(e,t,a){!function(e){"use strict";var t={1:"۱",2:"۲",3:"۳",4:"۴",5:"۵",6:"۶",7:"۷",8:"۸",9:"۹",0:"۰"},a={"۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","۰":"0"};e.defineLocale("fa",{months:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),monthsShort:"ژانویه_فوریه_مارس_آوریل_مه_ژوئن_ژوئیه_اوت_سپتامبر_اکتبر_نوامبر_دسامبر".split("_"),weekdays:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysShort:"یک‌شنبه_دوشنبه_سه‌شنبه_چهارشنبه_پنج‌شنبه_جمعه_شنبه".split("_"),weekdaysMin:"ی_د_س_چ_پ_ج_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/قبل از ظهر|بعد از ظهر/,isPM:function(e){return/بعد از ظهر/.test(e)},meridiem:function(e,t,a){return e<12?"قبل از ظهر":"بعد از ظهر"},calendar:{sameDay:"[امروز ساعت] LT",nextDay:"[فردا ساعت] LT",nextWeek:"dddd [ساعت] LT",lastDay:"[دیروز ساعت] LT",lastWeek:"dddd [پیش] [ساعت] LT",sameElse:"L"},relativeTime:{future:"در %s",past:"%s پیش",s:"چند ثانیه",ss:"%d ثانیه",m:"یک دقیقه",mm:"%d دقیقه",h:"یک ساعت",hh:"%d ساعت",d:"یک روز",dd:"%d روز",M:"یک ماه",MM:"%d ماه",y:"یک سال",yy:"%d سال"},preparse:function(e){return e.replace(/[۰-۹]/g,(function(e){return a[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]})).replace(/,/g,"،")},dayOfMonthOrdinalParse:/\d{1,2}م/,ordinal:"%dم",week:{dow:6,doy:12}})}(a(421))},8941:function(e,t,a){!function(e){"use strict";var t="nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän".split(" "),a=["nolla","yhden","kahden","kolmen","neljän","viiden","kuuden",t[7],t[8],t[9]];function s(e,s,n,i){var r="";switch(n){case"s":return i?"muutaman sekunnin":"muutama sekunti";case"ss":r=i?"sekunnin":"sekuntia";break;case"m":return i?"minuutin":"minuutti";case"mm":r=i?"minuutin":"minuuttia";break;case"h":return i?"tunnin":"tunti";case"hh":r=i?"tunnin":"tuntia";break;case"d":return i?"päivän":"päivä";case"dd":r=i?"päivän":"päivää";break;case"M":return i?"kuukauden":"kuukausi";case"MM":r=i?"kuukauden":"kuukautta";break;case"y":return i?"vuoden":"vuosi";case"yy":r=i?"vuoden":"vuotta"}return function(e,s){return e<10?s?a[e]:t[e]:e}(e,i)+" "+r}e.defineLocale("fi",{months:"tammikuu_helmikuu_maaliskuu_huhtikuu_toukokuu_kesäkuu_heinäkuu_elokuu_syyskuu_lokakuu_marraskuu_joulukuu".split("_"),monthsShort:"tammi_helmi_maalis_huhti_touko_kesä_heinä_elo_syys_loka_marras_joulu".split("_"),weekdays:"sunnuntai_maanantai_tiistai_keskiviikko_torstai_perjantai_lauantai".split("_"),weekdaysShort:"su_ma_ti_ke_to_pe_la".split("_"),weekdaysMin:"su_ma_ti_ke_to_pe_la".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"Do MMMM[ta] YYYY",LLL:"Do MMMM[ta] YYYY, [klo] HH.mm",LLLL:"dddd, Do MMMM[ta] YYYY, [klo] HH.mm",l:"D.M.YYYY",ll:"Do MMM YYYY",lll:"Do MMM YYYY, [klo] HH.mm",llll:"ddd, Do MMM YYYY, [klo] HH.mm"},calendar:{sameDay:"[tänään] [klo] LT",nextDay:"[huomenna] [klo] LT",nextWeek:"dddd [klo] LT",lastDay:"[eilen] [klo] LT",lastWeek:"[viime] dddd[na] [klo] LT",sameElse:"L"},relativeTime:{future:"%s päästä",past:"%s sitten",s,ss:s,m:s,mm:s,h:s,hh:s,d:s,dd:s,M:s,MM:s,y:s,yy:s},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},1742:function(e,t,a){!function(e){"use strict";e.defineLocale("fil",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(a(421))},6:function(e,t,a){!function(e){"use strict";e.defineLocale("fo",{months:"januar_februar_mars_apríl_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan_feb_mar_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_"),weekdays:"sunnudagur_mánadagur_týsdagur_mikudagur_hósdagur_fríggjadagur_leygardagur".split("_"),weekdaysShort:"sun_mán_týs_mik_hós_frí_ley".split("_"),weekdaysMin:"su_má_tý_mi_hó_fr_le".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D. MMMM, YYYY HH:mm"},calendar:{sameDay:"[Í dag kl.] LT",nextDay:"[Í morgin kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[Í gjár kl.] LT",lastWeek:"[síðstu] dddd [kl] LT",sameElse:"L"},relativeTime:{future:"um %s",past:"%s síðani",s:"fá sekund",ss:"%d sekundir",m:"ein minuttur",mm:"%d minuttir",h:"ein tími",hh:"%d tímar",d:"ein dagur",dd:"%d dagar",M:"ein mánaður",MM:"%d mánaðir",y:"eitt ár",yy:"%d ár"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},761:function(e,t,a){!function(e){"use strict";e.defineLocale("fr-ca",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,t){switch(t){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}}})}(a(421))},982:function(e,t,a){!function(e){"use strict";e.defineLocale("fr-ch",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsParseExact:!0,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|e)/,ordinal:function(e,t){switch(t){default:case"M":case"Q":case"D":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})}(a(421))},2346:function(e,t,a){!function(e){"use strict";var t=/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?|janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,a=[/^janv/i,/^févr/i,/^mars/i,/^avr/i,/^mai/i,/^juin/i,/^juil/i,/^août/i,/^sept/i,/^oct/i,/^nov/i,/^déc/i];e.defineLocale("fr",{months:"janvier_février_mars_avril_mai_juin_juillet_août_septembre_octobre_novembre_décembre".split("_"),monthsShort:"janv._févr._mars_avr._mai_juin_juil._août_sept._oct._nov._déc.".split("_"),monthsRegex:t,monthsShortRegex:t,monthsStrictRegex:/^(janvier|février|mars|avril|mai|juin|juillet|août|septembre|octobre|novembre|décembre)/i,monthsShortStrictRegex:/(janv\.?|févr\.?|mars|avr\.?|mai|juin|juil\.?|août|sept\.?|oct\.?|nov\.?|déc\.?)/i,monthsParse:a,longMonthsParse:a,shortMonthsParse:a,weekdays:"dimanche_lundi_mardi_mercredi_jeudi_vendredi_samedi".split("_"),weekdaysShort:"dim._lun._mar._mer._jeu._ven._sam.".split("_"),weekdaysMin:"di_lu_ma_me_je_ve_sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Aujourd’hui à] LT",nextDay:"[Demain à] LT",nextWeek:"dddd [à] LT",lastDay:"[Hier à] LT",lastWeek:"dddd [dernier à] LT",sameElse:"L"},relativeTime:{future:"dans %s",past:"il y a %s",s:"quelques secondes",ss:"%d secondes",m:"une minute",mm:"%d minutes",h:"une heure",hh:"%d heures",d:"un jour",dd:"%d jours",w:"une semaine",ww:"%d semaines",M:"un mois",MM:"%d mois",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(er|)/,ordinal:function(e,t){switch(t){case"D":return e+(1===e?"er":"");default:case"M":case"Q":case"DDD":case"d":return e+(1===e?"er":"e");case"w":case"W":return e+(1===e?"re":"e")}},week:{dow:1,doy:4}})}(a(421))},4934:function(e,t,a){!function(e){"use strict";var t="jan._feb._mrt._apr._mai_jun._jul._aug._sep._okt._nov._des.".split("_"),a="jan_feb_mrt_apr_mai_jun_jul_aug_sep_okt_nov_des".split("_");e.defineLocale("fy",{months:"jannewaris_febrewaris_maart_april_maaie_juny_july_augustus_septimber_oktober_novimber_desimber".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?a[e.month()]:t[e.month()]:t},monthsParseExact:!0,weekdays:"snein_moandei_tiisdei_woansdei_tongersdei_freed_sneon".split("_"),weekdaysShort:"si._mo._ti._wo._to._fr._so.".split("_"),weekdaysMin:"Si_Mo_Ti_Wo_To_Fr_So".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[hjoed om] LT",nextDay:"[moarn om] LT",nextWeek:"dddd [om] LT",lastDay:"[juster om] LT",lastWeek:"[ôfrûne] dddd [om] LT",sameElse:"L"},relativeTime:{future:"oer %s",past:"%s lyn",s:"in pear sekonden",ss:"%d sekonden",m:"ien minút",mm:"%d minuten",h:"ien oere",hh:"%d oeren",d:"ien dei",dd:"%d dagen",M:"ien moanne",MM:"%d moannen",y:"ien jier",yy:"%d jierren"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(a(421))},2670:function(e,t,a){!function(e){"use strict";e.defineLocale("ga",{months:["Eanáir","Feabhra","Márta","Aibreán","Bealtaine","Meitheamh","Iúil","Lúnasa","Meán Fómhair","Deireadh Fómhair","Samhain","Nollaig"],monthsShort:["Ean","Feabh","Márt","Aib","Beal","Meith","Iúil","Lún","M.F.","D.F.","Samh","Noll"],monthsParseExact:!0,weekdays:["Dé Domhnaigh","Dé Luain","Dé Máirt","Dé Céadaoin","Déardaoin","Dé hAoine","Dé Sathairn"],weekdaysShort:["Domh","Luan","Máirt","Céad","Déar","Aoine","Sath"],weekdaysMin:["Do","Lu","Má","Cé","Dé","A","Sa"],longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Inniu ag] LT",nextDay:"[Amárach ag] LT",nextWeek:"dddd [ag] LT",lastDay:"[Inné ag] LT",lastWeek:"dddd [seo caite] [ag] LT",sameElse:"L"},relativeTime:{future:"i %s",past:"%s ó shin",s:"cúpla soicind",ss:"%d soicind",m:"nóiméad",mm:"%d nóiméad",h:"uair an chloig",hh:"%d uair an chloig",d:"lá",dd:"%d lá",M:"mí",MM:"%d míonna",y:"bliain",yy:"%d bliain"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(a(421))},1733:function(e,t,a){!function(e){"use strict";e.defineLocale("gd",{months:["Am Faoilleach","An Gearran","Am Màrt","An Giblean","An Cèitean","An t-Ògmhios","An t-Iuchar","An Lùnastal","An t-Sultain","An Dàmhair","An t-Samhain","An Dùbhlachd"],monthsShort:["Faoi","Gear","Màrt","Gibl","Cèit","Ògmh","Iuch","Lùn","Sult","Dàmh","Samh","Dùbh"],monthsParseExact:!0,weekdays:["Didòmhnaich","Diluain","Dimàirt","Diciadain","Diardaoin","Dihaoine","Disathairne"],weekdaysShort:["Did","Dil","Dim","Dic","Dia","Dih","Dis"],weekdaysMin:["Dò","Lu","Mà","Ci","Ar","Ha","Sa"],longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[An-diugh aig] LT",nextDay:"[A-màireach aig] LT",nextWeek:"dddd [aig] LT",lastDay:"[An-dè aig] LT",lastWeek:"dddd [seo chaidh] [aig] LT",sameElse:"L"},relativeTime:{future:"ann an %s",past:"bho chionn %s",s:"beagan diogan",ss:"%d diogan",m:"mionaid",mm:"%d mionaidean",h:"uair",hh:"%d uairean",d:"latha",dd:"%d latha",M:"mìos",MM:"%d mìosan",y:"bliadhna",yy:"%d bliadhna"},dayOfMonthOrdinalParse:/\d{1,2}(d|na|mh)/,ordinal:function(e){return e+(1===e?"d":e%10==2?"na":"mh")},week:{dow:1,doy:4}})}(a(421))},2271:function(e,t,a){!function(e){"use strict";e.defineLocale("gl",{months:"xaneiro_febreiro_marzo_abril_maio_xuño_xullo_agosto_setembro_outubro_novembro_decembro".split("_"),monthsShort:"xan._feb._mar._abr._mai._xuñ._xul._ago._set._out._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"domingo_luns_martes_mércores_xoves_venres_sábado".split("_"),weekdaysShort:"dom._lun._mar._mér._xov._ven._sáb.".split("_"),weekdaysMin:"do_lu_ma_mé_xo_ve_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY H:mm",LLLL:"dddd, D [de] MMMM [de] YYYY H:mm"},calendar:{sameDay:function(){return"[hoxe "+(1!==this.hours()?"ás":"á")+"] LT"},nextDay:function(){return"[mañá "+(1!==this.hours()?"ás":"á")+"] LT"},nextWeek:function(){return"dddd ["+(1!==this.hours()?"ás":"a")+"] LT"},lastDay:function(){return"[onte "+(1!==this.hours()?"á":"a")+"] LT"},lastWeek:function(){return"[o] dddd [pasado "+(1!==this.hours()?"ás":"a")+"] LT"},sameElse:"L"},relativeTime:{future:function(e){return 0===e.indexOf("un")?"n"+e:"en "+e},past:"hai %s",s:"uns segundos",ss:"%d segundos",m:"un minuto",mm:"%d minutos",h:"unha hora",hh:"%d horas",d:"un día",dd:"%d días",M:"un mes",MM:"%d meses",y:"un ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(a(421))},5537:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={s:["थोडया सॅकंडांनी","थोडे सॅकंड"],ss:[e+" सॅकंडांनी",e+" सॅकंड"],m:["एका मिणटान","एक मिनूट"],mm:[e+" मिणटांनी",e+" मिणटां"],h:["एका वरान","एक वर"],hh:[e+" वरांनी",e+" वरां"],d:["एका दिसान","एक दीस"],dd:[e+" दिसांनी",e+" दीस"],M:["एका म्हयन्यान","एक म्हयनो"],MM:[e+" म्हयन्यानी",e+" म्हयने"],y:["एका वर्सान","एक वर्स"],yy:[e+" वर्सांनी",e+" वर्सां"]};return s?n[a][0]:n[a][1]}e.defineLocale("gom-deva",{months:{standalone:"जानेवारी_फेब्रुवारी_मार्च_एप्रील_मे_जून_जुलय_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),format:"जानेवारीच्या_फेब्रुवारीच्या_मार्चाच्या_एप्रीलाच्या_मेयाच्या_जूनाच्या_जुलयाच्या_ऑगस्टाच्या_सप्टेंबराच्या_ऑक्टोबराच्या_नोव्हेंबराच्या_डिसेंबराच्या".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"जाने._फेब्रु._मार्च_एप्री._मे_जून_जुल._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"आयतार_सोमार_मंगळार_बुधवार_बिरेस्तार_सुक्रार_शेनवार".split("_"),weekdaysShort:"आयत._सोम._मंगळ._बुध._ब्रेस्त._सुक्र._शेन.".split("_"),weekdaysMin:"आ_सो_मं_बु_ब्रे_सु_शे".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [वाजतां]",LTS:"A h:mm:ss [वाजतां]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [वाजतां]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [वाजतां]",llll:"ddd, D MMM YYYY, A h:mm [वाजतां]"},calendar:{sameDay:"[आयज] LT",nextDay:"[फाल्यां] LT",nextWeek:"[फुडलो] dddd[,] LT",lastDay:"[काल] LT",lastWeek:"[फाटलो] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s आदीं",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}(वेर)/,ordinal:function(e,t){return"D"===t?e+"वेर":e},week:{dow:0,doy:3},meridiemParse:/राती|सकाळीं|दनपारां|सांजे/,meridiemHour:function(e,t){return 12===e&&(e=0),"राती"===t?e<4?e:e+12:"सकाळीं"===t?e:"दनपारां"===t?e>12?e:e+12:"सांजे"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"राती":e<12?"सकाळीं":e<16?"दनपारां":e<20?"सांजे":"राती"}})}(a(421))},763:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={s:["thoddea sekondamni","thodde sekond"],ss:[e+" sekondamni",e+" sekond"],m:["eka mintan","ek minut"],mm:[e+" mintamni",e+" mintam"],h:["eka voran","ek vor"],hh:[e+" voramni",e+" voram"],d:["eka disan","ek dis"],dd:[e+" disamni",e+" dis"],M:["eka mhoinean","ek mhoino"],MM:[e+" mhoineamni",e+" mhoine"],y:["eka vorsan","ek voros"],yy:[e+" vorsamni",e+" vorsam"]};return s?n[a][0]:n[a][1]}e.defineLocale("gom-latn",{months:{standalone:"Janer_Febrer_Mars_Abril_Mai_Jun_Julai_Agost_Setembr_Otubr_Novembr_Dezembr".split("_"),format:"Janerachea_Febrerachea_Marsachea_Abrilachea_Maiachea_Junachea_Julaiachea_Agostachea_Setembrachea_Otubrachea_Novembrachea_Dezembrachea".split("_"),isFormat:/MMMM(\s)+D[oD]?/},monthsShort:"Jan._Feb._Mars_Abr._Mai_Jun_Jul._Ago._Set._Otu._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Aitar_Somar_Mongllar_Budhvar_Birestar_Sukrar_Son'var".split("_"),weekdaysShort:"Ait._Som._Mon._Bud._Bre._Suk._Son.".split("_"),weekdaysMin:"Ai_Sm_Mo_Bu_Br_Su_Sn".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"A h:mm [vazta]",LTS:"A h:mm:ss [vazta]",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY A h:mm [vazta]",LLLL:"dddd, MMMM Do, YYYY, A h:mm [vazta]",llll:"ddd, D MMM YYYY, A h:mm [vazta]"},calendar:{sameDay:"[Aiz] LT",nextDay:"[Faleam] LT",nextWeek:"[Fuddlo] dddd[,] LT",lastDay:"[Kal] LT",lastWeek:"[Fattlo] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%s",past:"%s adim",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}(er)/,ordinal:function(e,t){return"D"===t?e+"er":e},week:{dow:0,doy:3},meridiemParse:/rati|sokallim|donparam|sanje/,meridiemHour:function(e,t){return 12===e&&(e=0),"rati"===t?e<4?e:e+12:"sokallim"===t?e:"donparam"===t?e>12?e:e+12:"sanje"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"rati":e<12?"sokallim":e<16?"donparam":e<20?"sanje":"rati"}})}(a(421))},4125:function(e,t,a){!function(e){"use strict";var t={1:"૧",2:"૨",3:"૩",4:"૪",5:"૫",6:"૬",7:"૭",8:"૮",9:"૯",0:"૦"},a={"૧":"1","૨":"2","૩":"3","૪":"4","૫":"5","૬":"6","૭":"7","૮":"8","૯":"9","૦":"0"};e.defineLocale("gu",{months:"જાન્યુઆરી_ફેબ્રુઆરી_માર્ચ_એપ્રિલ_મે_જૂન_જુલાઈ_ઑગસ્ટ_સપ્ટેમ્બર_ઑક્ટ્બર_નવેમ્બર_ડિસેમ્બર".split("_"),monthsShort:"જાન્યુ._ફેબ્રુ._માર્ચ_એપ્રિ._મે_જૂન_જુલા._ઑગ._સપ્ટે._ઑક્ટ્._નવે._ડિસે.".split("_"),monthsParseExact:!0,weekdays:"રવિવાર_સોમવાર_મંગળવાર_બુધ્વાર_ગુરુવાર_શુક્રવાર_શનિવાર".split("_"),weekdaysShort:"રવિ_સોમ_મંગળ_બુધ્_ગુરુ_શુક્ર_શનિ".split("_"),weekdaysMin:"ર_સો_મં_બુ_ગુ_શુ_શ".split("_"),longDateFormat:{LT:"A h:mm વાગ્યે",LTS:"A h:mm:ss વાગ્યે",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm વાગ્યે",LLLL:"dddd, D MMMM YYYY, A h:mm વાગ્યે"},calendar:{sameDay:"[આજ] LT",nextDay:"[કાલે] LT",nextWeek:"dddd, LT",lastDay:"[ગઇકાલે] LT",lastWeek:"[પાછલા] dddd, LT",sameElse:"L"},relativeTime:{future:"%s મા",past:"%s પહેલા",s:"અમુક પળો",ss:"%d સેકંડ",m:"એક મિનિટ",mm:"%d મિનિટ",h:"એક કલાક",hh:"%d કલાક",d:"એક દિવસ",dd:"%d દિવસ",M:"એક મહિનો",MM:"%d મહિનો",y:"એક વર્ષ",yy:"%d વર્ષ"},preparse:function(e){return e.replace(/[૧૨૩૪૫૬૭૮૯૦]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/રાત|બપોર|સવાર|સાંજ/,meridiemHour:function(e,t){return 12===e&&(e=0),"રાત"===t?e<4?e:e+12:"સવાર"===t?e:"બપોર"===t?e>=10?e:e+12:"સાંજ"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"રાત":e<10?"સવાર":e<17?"બપોર":e<20?"સાંજ":"રાત"},week:{dow:0,doy:6}})}(a(421))},1651:function(e,t,a){!function(e){"use strict";e.defineLocale("he",{months:"ינואר_פברואר_מרץ_אפריל_מאי_יוני_יולי_אוגוסט_ספטמבר_אוקטובר_נובמבר_דצמבר".split("_"),monthsShort:"ינו׳_פבר׳_מרץ_אפר׳_מאי_יוני_יולי_אוג׳_ספט׳_אוק׳_נוב׳_דצמ׳".split("_"),weekdays:"ראשון_שני_שלישי_רביעי_חמישי_שישי_שבת".split("_"),weekdaysShort:"א׳_ב׳_ג׳_ד׳_ה׳_ו׳_ש׳".split("_"),weekdaysMin:"א_ב_ג_ד_ה_ו_ש".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [ב]MMMM YYYY",LLL:"D [ב]MMMM YYYY HH:mm",LLLL:"dddd, D [ב]MMMM YYYY HH:mm",l:"D/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[היום ב־]LT",nextDay:"[מחר ב־]LT",nextWeek:"dddd [בשעה] LT",lastDay:"[אתמול ב־]LT",lastWeek:"[ביום] dddd [האחרון בשעה] LT",sameElse:"L"},relativeTime:{future:"בעוד %s",past:"לפני %s",s:"מספר שניות",ss:"%d שניות",m:"דקה",mm:"%d דקות",h:"שעה",hh:function(e){return 2===e?"שעתיים":e+" שעות"},d:"יום",dd:function(e){return 2===e?"יומיים":e+" ימים"},M:"חודש",MM:function(e){return 2===e?"חודשיים":e+" חודשים"},y:"שנה",yy:function(e){return 2===e?"שנתיים":e%10==0&&10!==e?e+" שנה":e+" שנים"}},meridiemParse:/אחה"צ|לפנה"צ|אחרי הצהריים|לפני הצהריים|לפנות בוקר|בבוקר|בערב/i,isPM:function(e){return/^(אחה"צ|אחרי הצהריים|בערב)$/.test(e)},meridiem:function(e,t,a){return e<5?"לפנות בוקר":e<10?"בבוקר":e<12?a?'לפנה"צ':"לפני הצהריים":e<18?a?'אחה"צ':"אחרי הצהריים":"בערב"}})}(a(421))},8602:function(e,t,a){!function(e){"use strict";var t={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},a={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"},s=[/^जन/i,/^फ़र|फर/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सितं|सित/i,/^अक्टू/i,/^नव|नवं/i,/^दिसं|दिस/i];e.defineLocale("hi",{months:{format:"जनवरी_फ़रवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितम्बर_अक्टूबर_नवम्बर_दिसम्बर".split("_"),standalone:"जनवरी_फरवरी_मार्च_अप्रैल_मई_जून_जुलाई_अगस्त_सितंबर_अक्टूबर_नवंबर_दिसंबर".split("_")},monthsShort:"जन._फ़र._मार्च_अप्रै._मई_जून_जुल._अग._सित._अक्टू._नव._दिस.".split("_"),weekdays:"रविवार_सोमवार_मंगलवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगल_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm बजे",LTS:"A h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm बजे",LLLL:"dddd, D MMMM YYYY, A h:mm बजे"},monthsParse:s,longMonthsParse:s,shortMonthsParse:[/^जन/i,/^फ़र/i,/^मार्च/i,/^अप्रै/i,/^मई/i,/^जून/i,/^जुल/i,/^अग/i,/^सित/i,/^अक्टू/i,/^नव/i,/^दिस/i],monthsRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsShortRegex:/^(जनवरी|जन\.?|फ़रवरी|फरवरी|फ़र\.?|मार्च?|अप्रैल|अप्रै\.?|मई?|जून?|जुलाई|जुल\.?|अगस्त|अग\.?|सितम्बर|सितंबर|सित\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर|नव\.?|दिसम्बर|दिसंबर|दिस\.?)/i,monthsStrictRegex:/^(जनवरी?|फ़रवरी|फरवरी?|मार्च?|अप्रैल?|मई?|जून?|जुलाई?|अगस्त?|सितम्बर|सितंबर|सित?\.?|अक्टूबर|अक्टू\.?|नवम्बर|नवंबर?|दिसम्बर|दिसंबर?)/i,monthsShortStrictRegex:/^(जन\.?|फ़र\.?|मार्च?|अप्रै\.?|मई?|जून?|जुल\.?|अग\.?|सित\.?|अक्टू\.?|नव\.?|दिस\.?)/i,calendar:{sameDay:"[आज] LT",nextDay:"[कल] LT",nextWeek:"dddd, LT",lastDay:"[कल] LT",lastWeek:"[पिछले] dddd, LT",sameElse:"L"},relativeTime:{future:"%s में",past:"%s पहले",s:"कुछ ही क्षण",ss:"%d सेकंड",m:"एक मिनट",mm:"%d मिनट",h:"एक घंटा",hh:"%d घंटे",d:"एक दिन",dd:"%d दिन",M:"एक महीने",MM:"%d महीने",y:"एक वर्ष",yy:"%d वर्ष"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/रात|सुबह|दोपहर|शाम/,meridiemHour:function(e,t){return 12===e&&(e=0),"रात"===t?e<4?e:e+12:"सुबह"===t?e:"दोपहर"===t?e>=10?e:e+12:"शाम"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"रात":e<10?"सुबह":e<17?"दोपहर":e<20?"शाम":"रात"},week:{dow:0,doy:6}})}(a(421))},8641:function(e,t,a){!function(e){"use strict";function t(e,t,a){var s=e+" ";switch(a){case"ss":return s+(1===e?"sekunda":2===e||3===e||4===e?"sekunde":"sekundi");case"m":return t?"jedna minuta":"jedne minute";case"mm":return s+(1===e?"minuta":2===e||3===e||4===e?"minute":"minuta");case"h":return t?"jedan sat":"jednog sata";case"hh":return s+(1===e?"sat":2===e||3===e||4===e?"sata":"sati");case"dd":return s+(1===e?"dan":"dana");case"MM":return s+(1===e?"mjesec":2===e||3===e||4===e?"mjeseca":"mjeseci");case"yy":return s+(1===e?"godina":2===e||3===e||4===e?"godine":"godina")}}e.defineLocale("hr",{months:{format:"siječnja_veljače_ožujka_travnja_svibnja_lipnja_srpnja_kolovoza_rujna_listopada_studenoga_prosinca".split("_"),standalone:"siječanj_veljača_ožujak_travanj_svibanj_lipanj_srpanj_kolovoz_rujan_listopad_studeni_prosinac".split("_")},monthsShort:"sij._velj._ožu._tra._svi._lip._srp._kol._ruj._lis._stu._pro.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"Do MMMM YYYY",LLL:"Do MMMM YYYY H:mm",LLLL:"dddd, Do MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[jučer u] LT",lastWeek:function(){switch(this.day()){case 0:return"[prošlu] [nedjelju] [u] LT";case 3:return"[prošlu] [srijedu] [u] LT";case 6:return"[prošle] [subote] [u] LT";case 1:case 2:case 4:case 5:return"[prošli] dddd [u] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"par sekundi",ss:t,m:t,mm:t,h:t,hh:t,d:"dan",dd:t,M:"mjesec",MM:t,y:"godinu",yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(a(421))},3079:function(e,t,a){!function(e){"use strict";var t="vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton".split(" ");function a(e,t,a,s){var n=e;switch(a){case"s":return s||t?"néhány másodperc":"néhány másodperce";case"ss":return n+(s||t)?" másodperc":" másodperce";case"m":return"egy"+(s||t?" perc":" perce");case"mm":return n+(s||t?" perc":" perce");case"h":return"egy"+(s||t?" óra":" órája");case"hh":return n+(s||t?" óra":" órája");case"d":return"egy"+(s||t?" nap":" napja");case"dd":return n+(s||t?" nap":" napja");case"M":return"egy"+(s||t?" hónap":" hónapja");case"MM":return n+(s||t?" hónap":" hónapja");case"y":return"egy"+(s||t?" év":" éve");case"yy":return n+(s||t?" év":" éve")}return""}function s(e){return(e?"":"[múlt] ")+"["+t[this.day()]+"] LT[-kor]"}e.defineLocale("hu",{months:"január_február_március_április_május_június_július_augusztus_szeptember_október_november_december".split("_"),monthsShort:"jan._feb._márc._ápr._máj._jún._júl._aug._szept._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"vasárnap_hétfő_kedd_szerda_csütörtök_péntek_szombat".split("_"),weekdaysShort:"vas_hét_kedd_sze_csüt_pén_szo".split("_"),weekdaysMin:"v_h_k_sze_cs_p_szo".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY. MMMM D.",LLL:"YYYY. MMMM D. H:mm",LLLL:"YYYY. MMMM D., dddd H:mm"},meridiemParse:/de|du/i,isPM:function(e){return"u"===e.charAt(1).toLowerCase()},meridiem:function(e,t,a){return e<12?!0===a?"de":"DE":!0===a?"du":"DU"},calendar:{sameDay:"[ma] LT[-kor]",nextDay:"[holnap] LT[-kor]",nextWeek:function(){return s.call(this,!0)},lastDay:"[tegnap] LT[-kor]",lastWeek:function(){return s.call(this,!1)},sameElse:"L"},relativeTime:{future:"%s múlva",past:"%s",s:a,ss:a,m:a,mm:a,h:a,hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},443:function(e,t,a){!function(e){"use strict";e.defineLocale("hy-am",{months:{format:"հունվարի_փետրվարի_մարտի_ապրիլի_մայիսի_հունիսի_հուլիսի_օգոստոսի_սեպտեմբերի_հոկտեմբերի_նոյեմբերի_դեկտեմբերի".split("_"),standalone:"հունվար_փետրվար_մարտ_ապրիլ_մայիս_հունիս_հուլիս_օգոստոս_սեպտեմբեր_հոկտեմբեր_նոյեմբեր_դեկտեմբեր".split("_")},monthsShort:"հնվ_փտր_մրտ_ապր_մյս_հնս_հլս_օգս_սպտ_հկտ_նմբ_դկտ".split("_"),weekdays:"կիրակի_երկուշաբթի_երեքշաբթի_չորեքշաբթի_հինգշաբթի_ուրբաթ_շաբաթ".split("_"),weekdaysShort:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),weekdaysMin:"կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY թ.",LLL:"D MMMM YYYY թ., HH:mm",LLLL:"dddd, D MMMM YYYY թ., HH:mm"},calendar:{sameDay:"[այսօր] LT",nextDay:"[վաղը] LT",lastDay:"[երեկ] LT",nextWeek:function(){return"dddd [օրը ժամը] LT"},lastWeek:function(){return"[անցած] dddd [օրը ժամը] LT"},sameElse:"L"},relativeTime:{future:"%s հետո",past:"%s առաջ",s:"մի քանի վայրկյան",ss:"%d վայրկյան",m:"րոպե",mm:"%d րոպե",h:"ժամ",hh:"%d ժամ",d:"օր",dd:"%d օր",M:"ամիս",MM:"%d ամիս",y:"տարի",yy:"%d տարի"},meridiemParse:/գիշերվա|առավոտվա|ցերեկվա|երեկոյան/,isPM:function(e){return/^(ցերեկվա|երեկոյան)$/.test(e)},meridiem:function(e){return e<4?"գիշերվա":e<12?"առավոտվա":e<17?"ցերեկվա":"երեկոյան"},dayOfMonthOrdinalParse:/\d{1,2}|\d{1,2}-(ին|րդ)/,ordinal:function(e,t){switch(t){case"DDD":case"w":case"W":case"DDDo":return 1===e?e+"-ին":e+"-րդ";default:return e}},week:{dow:1,doy:7}})}(a(421))},8963:function(e,t,a){!function(e){"use strict";e.defineLocale("id",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_November_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Agt_Sep_Okt_Nov_Des".split("_"),weekdays:"Minggu_Senin_Selasa_Rabu_Kamis_Jumat_Sabtu".split("_"),weekdaysShort:"Min_Sen_Sel_Rab_Kam_Jum_Sab".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|siang|sore|malam/,meridiemHour:function(e,t){return 12===e&&(e=0),"pagi"===t?e:"siang"===t?e>=11?e:e+12:"sore"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,a){return e<11?"pagi":e<15?"siang":e<19?"sore":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Besok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kemarin pukul] LT",lastWeek:"dddd [lalu pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lalu",s:"beberapa detik",ss:"%d detik",m:"semenit",mm:"%d menit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:0,doy:6}})}(a(421))},1343:function(e,t,a){!function(e){"use strict";function t(e){return e%100==11||e%10!=1}function a(e,a,s,n){var i=e+" ";switch(s){case"s":return a||n?"nokkrar sekúndur":"nokkrum sekúndum";case"ss":return t(e)?i+(a||n?"sekúndur":"sekúndum"):i+"sekúnda";case"m":return a?"mínúta":"mínútu";case"mm":return t(e)?i+(a||n?"mínútur":"mínútum"):a?i+"mínúta":i+"mínútu";case"hh":return t(e)?i+(a||n?"klukkustundir":"klukkustundum"):i+"klukkustund";case"d":return a?"dagur":n?"dag":"degi";case"dd":return t(e)?a?i+"dagar":i+(n?"daga":"dögum"):a?i+"dagur":i+(n?"dag":"degi");case"M":return a?"mánuður":n?"mánuð":"mánuði";case"MM":return t(e)?a?i+"mánuðir":i+(n?"mánuði":"mánuðum"):a?i+"mánuður":i+(n?"mánuð":"mánuði");case"y":return a||n?"ár":"ári";case"yy":return t(e)?i+(a||n?"ár":"árum"):i+(a||n?"ár":"ári")}}e.defineLocale("is",{months:"janúar_febrúar_mars_apríl_maí_júní_júlí_ágúst_september_október_nóvember_desember".split("_"),monthsShort:"jan_feb_mar_apr_maí_jún_júl_ágú_sep_okt_nóv_des".split("_"),weekdays:"sunnudagur_mánudagur_þriðjudagur_miðvikudagur_fimmtudagur_föstudagur_laugardagur".split("_"),weekdaysShort:"sun_mán_þri_mið_fim_fös_lau".split("_"),weekdaysMin:"Su_Má_Þr_Mi_Fi_Fö_La".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd, D. MMMM YYYY [kl.] H:mm"},calendar:{sameDay:"[í dag kl.] LT",nextDay:"[á morgun kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[í gær kl.] LT",lastWeek:"[síðasta] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"eftir %s",past:"fyrir %s síðan",s:a,ss:a,m:a,mm:a,h:"klukkustund",hh:a,d:a,dd:a,M:a,MM:a,y:a,yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},3115:function(e,t,a){!function(e){"use strict";e.defineLocale("it-ch",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[Oggi alle] LT",nextDay:"[Domani alle] LT",nextWeek:"dddd [alle] LT",lastDay:"[Ieri alle] LT",lastWeek:function(){return 0===this.day()?"[la scorsa] dddd [alle] LT":"[lo scorso] dddd [alle] LT"},sameElse:"L"},relativeTime:{future:function(e){return(/^[0-9].+$/.test(e)?"tra":"in")+" "+e},past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(a(421))},8072:function(e,t,a){!function(e){"use strict";e.defineLocale("it",{months:"gennaio_febbraio_marzo_aprile_maggio_giugno_luglio_agosto_settembre_ottobre_novembre_dicembre".split("_"),monthsShort:"gen_feb_mar_apr_mag_giu_lug_ago_set_ott_nov_dic".split("_"),weekdays:"domenica_lunedì_martedì_mercoledì_giovedì_venerdì_sabato".split("_"),weekdaysShort:"dom_lun_mar_mer_gio_ven_sab".split("_"),weekdaysMin:"do_lu_ma_me_gi_ve_sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:function(){return"[Oggi a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextDay:function(){return"[Domani a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},nextWeek:function(){return"dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastDay:function(){return"[Ieri a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},lastWeek:function(){return 0===this.day()?"[La scorsa] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT":"[Lo scorso] dddd [a"+(this.hours()>1?"lle ":0===this.hours()?" ":"ll'")+"]LT"},sameElse:"L"},relativeTime:{future:"tra %s",past:"%s fa",s:"alcuni secondi",ss:"%d secondi",m:"un minuto",mm:"%d minuti",h:"un'ora",hh:"%d ore",d:"un giorno",dd:"%d giorni",w:"una settimana",ww:"%d settimane",M:"un mese",MM:"%d mesi",y:"un anno",yy:"%d anni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(a(421))},8183:function(e,t,a){!function(e){"use strict";e.defineLocale("ja",{eras:[{since:"2019-05-01",offset:1,name:"令和",narrow:"㋿",abbr:"R"},{since:"1989-01-08",until:"2019-04-30",offset:1,name:"平成",narrow:"㍻",abbr:"H"},{since:"1926-12-25",until:"1989-01-07",offset:1,name:"昭和",narrow:"㍼",abbr:"S"},{since:"1912-07-30",until:"1926-12-24",offset:1,name:"大正",narrow:"㍽",abbr:"T"},{since:"1873-01-01",until:"1912-07-29",offset:6,name:"明治",narrow:"㍾",abbr:"M"},{since:"0001-01-01",until:"1873-12-31",offset:1,name:"西暦",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"紀元前",narrow:"BC",abbr:"BC"}],eraYearOrdinalRegex:/(元|\d+)年/,eraYearOrdinalParse:function(e,t){return"元"===t[1]?1:parseInt(t[1]||e,10)},months:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"日曜日_月曜日_火曜日_水曜日_木曜日_金曜日_土曜日".split("_"),weekdaysShort:"日_月_火_水_木_金_土".split("_"),weekdaysMin:"日_月_火_水_木_金_土".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日 dddd HH:mm",l:"YYYY/MM/DD",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日(ddd) HH:mm"},meridiemParse:/午前|午後/i,isPM:function(e){return"午後"===e},meridiem:function(e,t,a){return e<12?"午前":"午後"},calendar:{sameDay:"[今日] LT",nextDay:"[明日] LT",nextWeek:function(e){return e.week()!==this.week()?"[来週]dddd LT":"dddd LT"},lastDay:"[昨日] LT",lastWeek:function(e){return this.week()!==e.week()?"[先週]dddd LT":"dddd LT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}日/,ordinal:function(e,t){switch(t){case"y":return 1===e?"元年":e+"年";case"d":case"D":case"DDD":return e+"日";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"数秒",ss:"%d秒",m:"1分",mm:"%d分",h:"1時間",hh:"%d時間",d:"1日",dd:"%d日",M:"1ヶ月",MM:"%dヶ月",y:"1年",yy:"%d年"}})}(a(421))},1064:function(e,t,a){!function(e){"use strict";e.defineLocale("jv",{months:"Januari_Februari_Maret_April_Mei_Juni_Juli_Agustus_September_Oktober_Nopember_Desember".split("_"),monthsShort:"Jan_Feb_Mar_Apr_Mei_Jun_Jul_Ags_Sep_Okt_Nop_Des".split("_"),weekdays:"Minggu_Senen_Seloso_Rebu_Kemis_Jemuwah_Septu".split("_"),weekdaysShort:"Min_Sen_Sel_Reb_Kem_Jem_Sep".split("_"),weekdaysMin:"Mg_Sn_Sl_Rb_Km_Jm_Sp".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/enjing|siyang|sonten|ndalu/,meridiemHour:function(e,t){return 12===e&&(e=0),"enjing"===t?e:"siyang"===t?e>=11?e:e+12:"sonten"===t||"ndalu"===t?e+12:void 0},meridiem:function(e,t,a){return e<11?"enjing":e<15?"siyang":e<19?"sonten":"ndalu"},calendar:{sameDay:"[Dinten puniko pukul] LT",nextDay:"[Mbenjang pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kala wingi pukul] LT",lastWeek:"dddd [kepengker pukul] LT",sameElse:"L"},relativeTime:{future:"wonten ing %s",past:"%s ingkang kepengker",s:"sawetawis detik",ss:"%d detik",m:"setunggal menit",mm:"%d menit",h:"setunggal jam",hh:"%d jam",d:"sedinten",dd:"%d dinten",M:"sewulan",MM:"%d wulan",y:"setaun",yy:"%d taun"},week:{dow:1,doy:7}})}(a(421))},1999:function(e,t,a){!function(e){"use strict";e.defineLocale("ka",{months:"იანვარი_თებერვალი_მარტი_აპრილი_მაისი_ივნისი_ივლისი_აგვისტო_სექტემბერი_ოქტომბერი_ნოემბერი_დეკემბერი".split("_"),monthsShort:"იან_თებ_მარ_აპრ_მაი_ივნ_ივლ_აგვ_სექ_ოქტ_ნოე_დეკ".split("_"),weekdays:{standalone:"კვირა_ორშაბათი_სამშაბათი_ოთხშაბათი_ხუთშაბათი_პარასკევი_შაბათი".split("_"),format:"კვირას_ორშაბათს_სამშაბათს_ოთხშაბათს_ხუთშაბათს_პარასკევს_შაბათს".split("_"),isFormat:/(წინა|შემდეგ)/},weekdaysShort:"კვი_ორშ_სამ_ოთხ_ხუთ_პარ_შაბ".split("_"),weekdaysMin:"კვ_ორ_სა_ოთ_ხუ_პა_შა".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[დღეს] LT[-ზე]",nextDay:"[ხვალ] LT[-ზე]",lastDay:"[გუშინ] LT[-ზე]",nextWeek:"[შემდეგ] dddd LT[-ზე]",lastWeek:"[წინა] dddd LT-ზე",sameElse:"L"},relativeTime:{future:function(e){return e.replace(/(წამ|წუთ|საათ|წელ|დღ|თვ)(ი|ე)/,(function(e,t,a){return"ი"===a?t+"ში":t+a+"ში"}))},past:function(e){return/(წამი|წუთი|საათი|დღე|თვე)/.test(e)?e.replace(/(ი|ე)$/,"ის წინ"):/წელი/.test(e)?e.replace(/წელი$/,"წლის წინ"):e},s:"რამდენიმე წამი",ss:"%d წამი",m:"წუთი",mm:"%d წუთი",h:"საათი",hh:"%d საათი",d:"დღე",dd:"%d დღე",M:"თვე",MM:"%d თვე",y:"წელი",yy:"%d წელი"},dayOfMonthOrdinalParse:/0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,ordinal:function(e){return 0===e?e:1===e?e+"-ლი":e<20||e<=100&&e%20==0||e%100==0?"მე-"+e:e+"-ე"},week:{dow:1,doy:7}})}(a(421))},9360:function(e,t,a){!function(e){"use strict";var t={0:"-ші",1:"-ші",2:"-ші",3:"-ші",4:"-ші",5:"-ші",6:"-шы",7:"-ші",8:"-ші",9:"-шы",10:"-шы",20:"-шы",30:"-шы",40:"-шы",50:"-ші",60:"-шы",70:"-ші",80:"-ші",90:"-шы",100:"-ші"};e.defineLocale("kk",{months:"қаңтар_ақпан_наурыз_сәуір_мамыр_маусым_шілде_тамыз_қыркүйек_қазан_қараша_желтоқсан".split("_"),monthsShort:"қаң_ақп_нау_сәу_мам_мау_шіл_там_қыр_қаз_қар_жел".split("_"),weekdays:"жексенбі_дүйсенбі_сейсенбі_сәрсенбі_бейсенбі_жұма_сенбі".split("_"),weekdaysShort:"жек_дүй_сей_сәр_бей_жұм_сен".split("_"),weekdaysMin:"жк_дй_сй_ср_бй_жм_сн".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгін сағат] LT",nextDay:"[Ертең сағат] LT",nextWeek:"dddd [сағат] LT",lastDay:"[Кеше сағат] LT",lastWeek:"[Өткен аптаның] dddd [сағат] LT",sameElse:"L"},relativeTime:{future:"%s ішінде",past:"%s бұрын",s:"бірнеше секунд",ss:"%d секунд",m:"бір минут",mm:"%d минут",h:"бір сағат",hh:"%d сағат",d:"бір күн",dd:"%d күн",M:"бір ай",MM:"%d ай",y:"бір жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(ші|шы)/,ordinal:function(e){return e+(t[e]||t[e%10]||t[e>=100?100:null])},week:{dow:1,doy:7}})}(a(421))},3667:function(e,t,a){!function(e){"use strict";var t={1:"១",2:"២",3:"៣",4:"៤",5:"៥",6:"៦",7:"៧",8:"៨",9:"៩",0:"០"},a={"១":"1","២":"2","៣":"3","៤":"4","៥":"5","៦":"6","៧":"7","៨":"8","៩":"9","០":"0"};e.defineLocale("km",{months:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),monthsShort:"មករា_កុម្ភៈ_មីនា_មេសា_ឧសភា_មិថុនា_កក្កដា_សីហា_កញ្ញា_តុលា_វិច្ឆិកា_ធ្នូ".split("_"),weekdays:"អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍".split("_"),weekdaysShort:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysMin:"អា_ច_អ_ព_ព្រ_សុ_ស".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ព្រឹក|ល្ងាច/,isPM:function(e){return"ល្ងាច"===e},meridiem:function(e,t,a){return e<12?"ព្រឹក":"ល្ងាច"},calendar:{sameDay:"[ថ្ងៃនេះ ម៉ោង] LT",nextDay:"[ស្អែក ម៉ោង] LT",nextWeek:"dddd [ម៉ោង] LT",lastDay:"[ម្សិលមិញ ម៉ោង] LT",lastWeek:"dddd [សប្តាហ៍មុន] [ម៉ោង] LT",sameElse:"L"},relativeTime:{future:"%sទៀត",past:"%sមុន",s:"ប៉ុន្មានវិនាទី",ss:"%d វិនាទី",m:"មួយនាទី",mm:"%d នាទី",h:"មួយម៉ោង",hh:"%d ម៉ោង",d:"មួយថ្ងៃ",dd:"%d ថ្ងៃ",M:"មួយខែ",MM:"%d ខែ",y:"មួយឆ្នាំ",yy:"%d ឆ្នាំ"},dayOfMonthOrdinalParse:/ទី\d{1,2}/,ordinal:"ទី%d",preparse:function(e){return e.replace(/[១២៣៤៥៦៧៨៩០]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},week:{dow:1,doy:4}})}(a(421))},1882:function(e,t,a){!function(e){"use strict";var t={1:"೧",2:"೨",3:"೩",4:"೪",5:"೫",6:"೬",7:"೭",8:"೮",9:"೯",0:"೦"},a={"೧":"1","೨":"2","೩":"3","೪":"4","೫":"5","೬":"6","೭":"7","೮":"8","೯":"9","೦":"0"};e.defineLocale("kn",{months:"ಜನವರಿ_ಫೆಬ್ರವರಿ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂಬರ್_ಅಕ್ಟೋಬರ್_ನವೆಂಬರ್_ಡಿಸೆಂಬರ್".split("_"),monthsShort:"ಜನ_ಫೆಬ್ರ_ಮಾರ್ಚ್_ಏಪ್ರಿಲ್_ಮೇ_ಜೂನ್_ಜುಲೈ_ಆಗಸ್ಟ್_ಸೆಪ್ಟೆಂ_ಅಕ್ಟೋ_ನವೆಂ_ಡಿಸೆಂ".split("_"),monthsParseExact:!0,weekdays:"ಭಾನುವಾರ_ಸೋಮವಾರ_ಮಂಗಳವಾರ_ಬುಧವಾರ_ಗುರುವಾರ_ಶುಕ್ರವಾರ_ಶನಿವಾರ".split("_"),weekdaysShort:"ಭಾನು_ಸೋಮ_ಮಂಗಳ_ಬುಧ_ಗುರು_ಶುಕ್ರ_ಶನಿ".split("_"),weekdaysMin:"ಭಾ_ಸೋ_ಮಂ_ಬು_ಗು_ಶು_ಶ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[ಇಂದು] LT",nextDay:"[ನಾಳೆ] LT",nextWeek:"dddd, LT",lastDay:"[ನಿನ್ನೆ] LT",lastWeek:"[ಕೊನೆಯ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ನಂತರ",past:"%s ಹಿಂದೆ",s:"ಕೆಲವು ಕ್ಷಣಗಳು",ss:"%d ಸೆಕೆಂಡುಗಳು",m:"ಒಂದು ನಿಮಿಷ",mm:"%d ನಿಮಿಷ",h:"ಒಂದು ಗಂಟೆ",hh:"%d ಗಂಟೆ",d:"ಒಂದು ದಿನ",dd:"%d ದಿನ",M:"ಒಂದು ತಿಂಗಳು",MM:"%d ತಿಂಗಳು",y:"ಒಂದು ವರ್ಷ",yy:"%d ವರ್ಷ"},preparse:function(e){return e.replace(/[೧೨೩೪೫೬೭೮೯೦]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/ರಾತ್ರಿ|ಬೆಳಿಗ್ಗೆ|ಮಧ್ಯಾಹ್ನ|ಸಂಜೆ/,meridiemHour:function(e,t){return 12===e&&(e=0),"ರಾತ್ರಿ"===t?e<4?e:e+12:"ಬೆಳಿಗ್ಗೆ"===t?e:"ಮಧ್ಯಾಹ್ನ"===t?e>=10?e:e+12:"ಸಂಜೆ"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"ರಾತ್ರಿ":e<10?"ಬೆಳಿಗ್ಗೆ":e<17?"ಮಧ್ಯಾಹ್ನ":e<20?"ಸಂಜೆ":"ರಾತ್ರಿ"},dayOfMonthOrdinalParse:/\d{1,2}(ನೇ)/,ordinal:function(e){return e+"ನೇ"},week:{dow:0,doy:6}})}(a(421))},2401:function(e,t,a){!function(e){"use strict";e.defineLocale("ko",{months:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),monthsShort:"1월_2월_3월_4월_5월_6월_7월_8월_9월_10월_11월_12월".split("_"),weekdays:"일요일_월요일_화요일_수요일_목요일_금요일_토요일".split("_"),weekdaysShort:"일_월_화_수_목_금_토".split("_"),weekdaysMin:"일_월_화_수_목_금_토".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"YYYY.MM.DD.",LL:"YYYY년 MMMM D일",LLL:"YYYY년 MMMM D일 A h:mm",LLLL:"YYYY년 MMMM D일 dddd A h:mm",l:"YYYY.MM.DD.",ll:"YYYY년 MMMM D일",lll:"YYYY년 MMMM D일 A h:mm",llll:"YYYY년 MMMM D일 dddd A h:mm"},calendar:{sameDay:"오늘 LT",nextDay:"내일 LT",nextWeek:"dddd LT",lastDay:"어제 LT",lastWeek:"지난주 dddd LT",sameElse:"L"},relativeTime:{future:"%s 후",past:"%s 전",s:"몇 초",ss:"%d초",m:"1분",mm:"%d분",h:"한 시간",hh:"%d시간",d:"하루",dd:"%d일",M:"한 달",MM:"%d달",y:"일 년",yy:"%d년"},dayOfMonthOrdinalParse:/\d{1,2}(일|월|주)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"일";case"M":return e+"월";case"w":case"W":return e+"주";default:return e}},meridiemParse:/오전|오후/,isPM:function(e){return"오후"===e},meridiem:function(e,t,a){return e<12?"오전":"오후"}})}(a(421))},2583:function(e,t,a){!function(e){"use strict";var t={1:"١",2:"٢",3:"٣",4:"٤",5:"٥",6:"٦",7:"٧",8:"٨",9:"٩",0:"٠"},a={"١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","٠":"0"},s=["کانونی دووەم","شوبات","ئازار","نیسان","ئایار","حوزەیران","تەمموز","ئاب","ئەیلوول","تشرینی یەكەم","تشرینی دووەم","كانونی یەکەم"];e.defineLocale("ku",{months:s,monthsShort:s,weekdays:"یه‌كشه‌ممه‌_دووشه‌ممه‌_سێشه‌ممه‌_چوارشه‌ممه‌_پێنجشه‌ممه‌_هه‌ینی_شه‌ممه‌".split("_"),weekdaysShort:"یه‌كشه‌م_دووشه‌م_سێشه‌م_چوارشه‌م_پێنجشه‌م_هه‌ینی_شه‌ممه‌".split("_"),weekdaysMin:"ی_د_س_چ_پ_ه_ش".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},meridiemParse:/ئێواره‌|به‌یانی/,isPM:function(e){return/ئێواره‌/.test(e)},meridiem:function(e,t,a){return e<12?"به‌یانی":"ئێواره‌"},calendar:{sameDay:"[ئه‌مرۆ كاتژمێر] LT",nextDay:"[به‌یانی كاتژمێر] LT",nextWeek:"dddd [كاتژمێر] LT",lastDay:"[دوێنێ كاتژمێر] LT",lastWeek:"dddd [كاتژمێر] LT",sameElse:"L"},relativeTime:{future:"له‌ %s",past:"%s",s:"چه‌ند چركه‌یه‌ك",ss:"چركه‌ %d",m:"یه‌ك خوله‌ك",mm:"%d خوله‌ك",h:"یه‌ك كاتژمێر",hh:"%d كاتژمێر",d:"یه‌ك ڕۆژ",dd:"%d ڕۆژ",M:"یه‌ك مانگ",MM:"%d مانگ",y:"یه‌ك ساڵ",yy:"%d ساڵ"},preparse:function(e){return e.replace(/[١٢٣٤٥٦٧٨٩٠]/g,(function(e){return a[e]})).replace(/،/g,",")},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]})).replace(/,/g,"،")},week:{dow:6,doy:12}})}(a(421))},6751:function(e,t,a){!function(e){"use strict";var t={0:"-чү",1:"-чи",2:"-чи",3:"-чү",4:"-чү",5:"-чи",6:"-чы",7:"-чи",8:"-чи",9:"-чу",10:"-чу",20:"-чы",30:"-чу",40:"-чы",50:"-чү",60:"-чы",70:"-чи",80:"-чи",90:"-чу",100:"-чү"};e.defineLocale("ky",{months:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_"),monthsShort:"янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек".split("_"),weekdays:"Жекшемби_Дүйшөмбү_Шейшемби_Шаршемби_Бейшемби_Жума_Ишемби".split("_"),weekdaysShort:"Жек_Дүй_Шей_Шар_Бей_Жум_Ише".split("_"),weekdaysMin:"Жк_Дй_Шй_Шр_Бй_Жм_Иш".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Бүгүн саат] LT",nextDay:"[Эртең саат] LT",nextWeek:"dddd [саат] LT",lastDay:"[Кечээ саат] LT",lastWeek:"[Өткөн аптанын] dddd [күнү] [саат] LT",sameElse:"L"},relativeTime:{future:"%s ичинде",past:"%s мурун",s:"бирнече секунд",ss:"%d секунд",m:"бир мүнөт",mm:"%d мүнөт",h:"бир саат",hh:"%d саат",d:"бир күн",dd:"%d күн",M:"бир ай",MM:"%d ай",y:"бир жыл",yy:"%d жыл"},dayOfMonthOrdinalParse:/\d{1,2}-(чи|чы|чү|чу)/,ordinal:function(e){return e+(t[e]||t[e%10]||t[e>=100?100:null])},week:{dow:1,doy:7}})}(a(421))},1193:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={m:["eng Minutt","enger Minutt"],h:["eng Stonn","enger Stonn"],d:["een Dag","engem Dag"],M:["ee Mount","engem Mount"],y:["ee Joer","engem Joer"]};return t?n[a][0]:n[a][1]}function a(e){if(e=parseInt(e,10),isNaN(e))return!1;if(e<0)return!0;if(e<10)return 4<=e&&e<=7;if(e<100){var t=e%10;return a(0===t?e/10:t)}if(e<1e4){for(;e>=10;)e/=10;return a(e)}return a(e/=1e3)}e.defineLocale("lb",{months:"Januar_Februar_Mäerz_Abrëll_Mee_Juni_Juli_August_September_Oktober_November_Dezember".split("_"),monthsShort:"Jan._Febr._Mrz._Abr._Mee_Jun._Jul._Aug._Sept._Okt._Nov._Dez.".split("_"),monthsParseExact:!0,weekdays:"Sonndeg_Méindeg_Dënschdeg_Mëttwoch_Donneschdeg_Freideg_Samschdeg".split("_"),weekdaysShort:"So._Mé._Dë._Më._Do._Fr._Sa.".split("_"),weekdaysMin:"So_Mé_Dë_Më_Do_Fr_Sa".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm [Auer]",LTS:"H:mm:ss [Auer]",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm [Auer]",LLLL:"dddd, D. MMMM YYYY H:mm [Auer]"},calendar:{sameDay:"[Haut um] LT",sameElse:"L",nextDay:"[Muer um] LT",nextWeek:"dddd [um] LT",lastDay:"[Gëschter um] LT",lastWeek:function(){switch(this.day()){case 2:case 4:return"[Leschten] dddd [um] LT";default:return"[Leschte] dddd [um] LT"}}},relativeTime:{future:function(e){return a(e.substr(0,e.indexOf(" ")))?"a "+e:"an "+e},past:function(e){return a(e.substr(0,e.indexOf(" ")))?"viru "+e:"virun "+e},s:"e puer Sekonnen",ss:"%d Sekonnen",m:t,mm:"%d Minutten",h:t,hh:"%d Stonnen",d:t,dd:"%d Deeg",M:t,MM:"%d Méint",y:t,yy:"%d Joer"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},769:function(e,t,a){!function(e){"use strict";e.defineLocale("lo",{months:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),monthsShort:"ມັງກອນ_ກຸມພາ_ມີນາ_ເມສາ_ພຶດສະພາ_ມິຖຸນາ_ກໍລະກົດ_ສິງຫາ_ກັນຍາ_ຕຸລາ_ພະຈິກ_ທັນວາ".split("_"),weekdays:"ອາທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysShort:"ທິດ_ຈັນ_ອັງຄານ_ພຸດ_ພະຫັດ_ສຸກ_ເສົາ".split("_"),weekdaysMin:"ທ_ຈ_ອຄ_ພ_ພຫ_ສກ_ສ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"ວັນdddd D MMMM YYYY HH:mm"},meridiemParse:/ຕອນເຊົ້າ|ຕອນແລງ/,isPM:function(e){return"ຕອນແລງ"===e},meridiem:function(e,t,a){return e<12?"ຕອນເຊົ້າ":"ຕອນແລງ"},calendar:{sameDay:"[ມື້ນີ້ເວລາ] LT",nextDay:"[ມື້ອື່ນເວລາ] LT",nextWeek:"[ວັນ]dddd[ໜ້າເວລາ] LT",lastDay:"[ມື້ວານນີ້ເວລາ] LT",lastWeek:"[ວັນ]dddd[ແລ້ວນີ້ເວລາ] LT",sameElse:"L"},relativeTime:{future:"ອີກ %s",past:"%sຜ່ານມາ",s:"ບໍ່ເທົ່າໃດວິນາທີ",ss:"%d ວິນາທີ",m:"1 ນາທີ",mm:"%d ນາທີ",h:"1 ຊົ່ວໂມງ",hh:"%d ຊົ່ວໂມງ",d:"1 ມື້",dd:"%d ມື້",M:"1 ເດືອນ",MM:"%d ເດືອນ",y:"1 ປີ",yy:"%d ປີ"},dayOfMonthOrdinalParse:/(ທີ່)\d{1,2}/,ordinal:function(e){return"ທີ່"+e}})}(a(421))},4409:function(e,t,a){!function(e){"use strict";var t={ss:"sekundė_sekundžių_sekundes",m:"minutė_minutės_minutę",mm:"minutės_minučių_minutes",h:"valanda_valandos_valandą",hh:"valandos_valandų_valandas",d:"diena_dienos_dieną",dd:"dienos_dienų_dienas",M:"mėnuo_mėnesio_mėnesį",MM:"mėnesiai_mėnesių_mėnesius",y:"metai_metų_metus",yy:"metai_metų_metus"};function a(e,t,a,s){return t?n(a)[0]:s?n(a)[1]:n(a)[2]}function s(e){return e%10==0||e>10&&e<20}function n(e){return t[e].split("_")}function i(e,t,i,r){var o=e+" ";return 1===e?o+a(0,t,i[0],r):t?o+(s(e)?n(i)[1]:n(i)[0]):r?o+n(i)[1]:o+(s(e)?n(i)[1]:n(i)[2])}e.defineLocale("lt",{months:{format:"sausio_vasario_kovo_balandžio_gegužės_birželio_liepos_rugpjūčio_rugsėjo_spalio_lapkričio_gruodžio".split("_"),standalone:"sausis_vasaris_kovas_balandis_gegužė_birželis_liepa_rugpjūtis_rugsėjis_spalis_lapkritis_gruodis".split("_"),isFormat:/D[oD]?(\[[^\[\]]*\]|\s)+MMMM?|MMMM?(\[[^\[\]]*\]|\s)+D[oD]?/},monthsShort:"sau_vas_kov_bal_geg_bir_lie_rgp_rgs_spa_lap_grd".split("_"),weekdays:{format:"sekmadienį_pirmadienį_antradienį_trečiadienį_ketvirtadienį_penktadienį_šeštadienį".split("_"),standalone:"sekmadienis_pirmadienis_antradienis_trečiadienis_ketvirtadienis_penktadienis_šeštadienis".split("_"),isFormat:/dddd HH:mm/},weekdaysShort:"Sek_Pir_Ant_Tre_Ket_Pen_Šeš".split("_"),weekdaysMin:"S_P_A_T_K_Pn_Š".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY [m.] MMMM D [d.]",LLL:"YYYY [m.] MMMM D [d.], HH:mm [val.]",LLLL:"YYYY [m.] MMMM D [d.], dddd, HH:mm [val.]",l:"YYYY-MM-DD",ll:"YYYY [m.] MMMM D [d.]",lll:"YYYY [m.] MMMM D [d.], HH:mm [val.]",llll:"YYYY [m.] MMMM D [d.], ddd, HH:mm [val.]"},calendar:{sameDay:"[Šiandien] LT",nextDay:"[Rytoj] LT",nextWeek:"dddd LT",lastDay:"[Vakar] LT",lastWeek:"[Praėjusį] dddd LT",sameElse:"L"},relativeTime:{future:"po %s",past:"prieš %s",s:function(e,t,a,s){return t?"kelios sekundės":s?"kelių sekundžių":"kelias sekundes"},ss:i,m:a,mm:i,h:a,hh:i,d:a,dd:i,M:a,MM:i,y:a,yy:i},dayOfMonthOrdinalParse:/\d{1,2}-oji/,ordinal:function(e){return e+"-oji"},week:{dow:1,doy:4}})}(a(421))},9262:function(e,t,a){!function(e){"use strict";var t={ss:"sekundes_sekundēm_sekunde_sekundes".split("_"),m:"minūtes_minūtēm_minūte_minūtes".split("_"),mm:"minūtes_minūtēm_minūte_minūtes".split("_"),h:"stundas_stundām_stunda_stundas".split("_"),hh:"stundas_stundām_stunda_stundas".split("_"),d:"dienas_dienām_diena_dienas".split("_"),dd:"dienas_dienām_diena_dienas".split("_"),M:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),MM:"mēneša_mēnešiem_mēnesis_mēneši".split("_"),y:"gada_gadiem_gads_gadi".split("_"),yy:"gada_gadiem_gads_gadi".split("_")};function a(e,t,a){return a?t%10==1&&t%100!=11?e[2]:e[3]:t%10==1&&t%100!=11?e[0]:e[1]}function s(e,s,n){return e+" "+a(t[n],e,s)}function n(e,s,n){return a(t[n],e,s)}e.defineLocale("lv",{months:"janvāris_februāris_marts_aprīlis_maijs_jūnijs_jūlijs_augusts_septembris_oktobris_novembris_decembris".split("_"),monthsShort:"jan_feb_mar_apr_mai_jūn_jūl_aug_sep_okt_nov_dec".split("_"),weekdays:"svētdiena_pirmdiena_otrdiena_trešdiena_ceturtdiena_piektdiena_sestdiena".split("_"),weekdaysShort:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysMin:"Sv_P_O_T_C_Pk_S".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY.",LL:"YYYY. [gada] D. MMMM",LLL:"YYYY. [gada] D. MMMM, HH:mm",LLLL:"YYYY. [gada] D. MMMM, dddd, HH:mm"},calendar:{sameDay:"[Šodien pulksten] LT",nextDay:"[Rīt pulksten] LT",nextWeek:"dddd [pulksten] LT",lastDay:"[Vakar pulksten] LT",lastWeek:"[Pagājušā] dddd [pulksten] LT",sameElse:"L"},relativeTime:{future:"pēc %s",past:"pirms %s",s:function(e,t){return t?"dažas sekundes":"dažām sekundēm"},ss:s,m:n,mm:s,h:n,hh:s,d:n,dd:s,M:n,MM:s,y:n,yy:s},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},7514:function(e,t,a){!function(e){"use strict";var t={words:{ss:["sekund","sekunda","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],dd:["dan","dana","dana"],MM:["mjesec","mjeseca","mjeseci"],yy:["godina","godine","godina"]},correctGrammaticalCase:function(e,t){return 1===e?t[0]:e>=2&&e<=4?t[1]:t[2]},translate:function(e,a,s){var n=t.words[s];return 1===s.length?a?n[0]:n[1]:e+" "+t.correctGrammaticalCase(e,n)}};e.defineLocale("me",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sri._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sjutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedjelju] [u] LT";case 3:return"[u] [srijedu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedjelje] [u] LT","[prošlog] [ponedjeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srijede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"prije %s",s:"nekoliko sekundi",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:"dan",dd:t.translate,M:"mjesec",MM:t.translate,y:"godinu",yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(a(421))},3434:function(e,t,a){!function(e){"use strict";e.defineLocale("mi",{months:"Kohi-tāte_Hui-tanguru_Poutū-te-rangi_Paenga-whāwhā_Haratua_Pipiri_Hōngoingoi_Here-turi-kōkā_Mahuru_Whiringa-ā-nuku_Whiringa-ā-rangi_Hakihea".split("_"),monthsShort:"Kohi_Hui_Pou_Pae_Hara_Pipi_Hōngoi_Here_Mahu_Whi-nu_Whi-ra_Haki".split("_"),monthsRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,3}/i,monthsShortStrictRegex:/(?:['a-z\u0101\u014D\u016B]+\-?){1,2}/i,weekdays:"Rātapu_Mane_Tūrei_Wenerei_Tāite_Paraire_Hātarei".split("_"),weekdaysShort:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),weekdaysMin:"Ta_Ma_Tū_We_Tāi_Pa_Hā".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [i] HH:mm",LLLL:"dddd, D MMMM YYYY [i] HH:mm"},calendar:{sameDay:"[i teie mahana, i] LT",nextDay:"[apopo i] LT",nextWeek:"dddd [i] LT",lastDay:"[inanahi i] LT",lastWeek:"dddd [whakamutunga i] LT",sameElse:"L"},relativeTime:{future:"i roto i %s",past:"%s i mua",s:"te hēkona ruarua",ss:"%d hēkona",m:"he meneti",mm:"%d meneti",h:"te haora",hh:"%d haora",d:"he ra",dd:"%d ra",M:"he marama",MM:"%d marama",y:"he tau",yy:"%d tau"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(a(421))},610:function(e,t,a){!function(e){"use strict";e.defineLocale("mk",{months:"јануари_февруари_март_април_мај_јуни_јули_август_септември_октомври_ноември_декември".split("_"),monthsShort:"јан_фев_мар_апр_мај_јун_јул_авг_сеп_окт_ное_дек".split("_"),weekdays:"недела_понеделник_вторник_среда_четврток_петок_сабота".split("_"),weekdaysShort:"нед_пон_вто_сре_чет_пет_саб".split("_"),weekdaysMin:"нe_пo_вт_ср_че_пе_сa".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[Денес во] LT",nextDay:"[Утре во] LT",nextWeek:"[Во] dddd [во] LT",lastDay:"[Вчера во] LT",lastWeek:function(){switch(this.day()){case 0:case 3:case 6:return"[Изминатата] dddd [во] LT";case 1:case 2:case 4:case 5:return"[Изминатиот] dddd [во] LT"}},sameElse:"L"},relativeTime:{future:"за %s",past:"пред %s",s:"неколку секунди",ss:"%d секунди",m:"една минута",mm:"%d минути",h:"еден час",hh:"%d часа",d:"еден ден",dd:"%d дена",M:"еден месец",MM:"%d месеци",y:"една година",yy:"%d години"},dayOfMonthOrdinalParse:/\d{1,2}-(ев|ен|ти|ви|ри|ми)/,ordinal:function(e){var t=e%10,a=e%100;return 0===e?e+"-ев":0===a?e+"-ен":a>10&&a<20?e+"-ти":1===t?e+"-ви":2===t?e+"-ри":7===t||8===t?e+"-ми":e+"-ти"},week:{dow:1,doy:7}})}(a(421))},1654:function(e,t,a){!function(e){"use strict";e.defineLocale("ml",{months:"ജനുവരി_ഫെബ്രുവരി_മാർച്ച്_ഏപ്രിൽ_മേയ്_ജൂൺ_ജൂലൈ_ഓഗസ്റ്റ്_സെപ്റ്റംബർ_ഒക്ടോബർ_നവംബർ_ഡിസംബർ".split("_"),monthsShort:"ജനു._ഫെബ്രു._മാർ._ഏപ്രി._മേയ്_ജൂൺ_ജൂലൈ._ഓഗ._സെപ്റ്റ._ഒക്ടോ._നവം._ഡിസം.".split("_"),monthsParseExact:!0,weekdays:"ഞായറാഴ്ച_തിങ്കളാഴ്ച_ചൊവ്വാഴ്ച_ബുധനാഴ്ച_വ്യാഴാഴ്ച_വെള്ളിയാഴ്ച_ശനിയാഴ്ച".split("_"),weekdaysShort:"ഞായർ_തിങ്കൾ_ചൊവ്വ_ബുധൻ_വ്യാഴം_വെള്ളി_ശനി".split("_"),weekdaysMin:"ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ".split("_"),longDateFormat:{LT:"A h:mm -നു",LTS:"A h:mm:ss -നു",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm -നു",LLLL:"dddd, D MMMM YYYY, A h:mm -നു"},calendar:{sameDay:"[ഇന്ന്] LT",nextDay:"[നാളെ] LT",nextWeek:"dddd, LT",lastDay:"[ഇന്നലെ] LT",lastWeek:"[കഴിഞ്ഞ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s കഴിഞ്ഞ്",past:"%s മുൻപ്",s:"അൽപ നിമിഷങ്ങൾ",ss:"%d സെക്കൻഡ്",m:"ഒരു മിനിറ്റ്",mm:"%d മിനിറ്റ്",h:"ഒരു മണിക്കൂർ",hh:"%d മണിക്കൂർ",d:"ഒരു ദിവസം",dd:"%d ദിവസം",M:"ഒരു മാസം",MM:"%d മാസം",y:"ഒരു വർഷം",yy:"%d വർഷം"},meridiemParse:/രാത്രി|രാവിലെ|ഉച്ച കഴിഞ്ഞ്|വൈകുന്നേരം|രാത്രി/i,meridiemHour:function(e,t){return 12===e&&(e=0),"രാത്രി"===t&&e>=4||"ഉച്ച കഴിഞ്ഞ്"===t||"വൈകുന്നേരം"===t?e+12:e},meridiem:function(e,t,a){return e<4?"രാത്രി":e<12?"രാവിലെ":e<17?"ഉച്ച കഴിഞ്ഞ്":e<20?"വൈകുന്നേരം":"രാത്രി"}})}(a(421))},6730:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){switch(a){case"s":return t?"хэдхэн секунд":"хэдхэн секундын";case"ss":return e+(t?" секунд":" секундын");case"m":case"mm":return e+(t?" минут":" минутын");case"h":case"hh":return e+(t?" цаг":" цагийн");case"d":case"dd":return e+(t?" өдөр":" өдрийн");case"M":case"MM":return e+(t?" сар":" сарын");case"y":case"yy":return e+(t?" жил":" жилийн");default:return e}}e.defineLocale("mn",{months:"Нэгдүгээр сар_Хоёрдугаар сар_Гуравдугаар сар_Дөрөвдүгээр сар_Тавдугаар сар_Зургадугаар сар_Долдугаар сар_Наймдугаар сар_Есдүгээр сар_Аравдугаар сар_Арван нэгдүгээр сар_Арван хоёрдугаар сар".split("_"),monthsShort:"1 сар_2 сар_3 сар_4 сар_5 сар_6 сар_7 сар_8 сар_9 сар_10 сар_11 сар_12 сар".split("_"),monthsParseExact:!0,weekdays:"Ням_Даваа_Мягмар_Лхагва_Пүрэв_Баасан_Бямба".split("_"),weekdaysShort:"Ням_Дав_Мяг_Лха_Пүр_Баа_Бям".split("_"),weekdaysMin:"Ня_Да_Мя_Лх_Пү_Ба_Бя".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY оны MMMMын D",LLL:"YYYY оны MMMMын D HH:mm",LLLL:"dddd, YYYY оны MMMMын D HH:mm"},meridiemParse:/ҮӨ|ҮХ/i,isPM:function(e){return"ҮХ"===e},meridiem:function(e,t,a){return e<12?"ҮӨ":"ҮХ"},calendar:{sameDay:"[Өнөөдөр] LT",nextDay:"[Маргааш] LT",nextWeek:"[Ирэх] dddd LT",lastDay:"[Өчигдөр] LT",lastWeek:"[Өнгөрсөн] dddd LT",sameElse:"L"},relativeTime:{future:"%s дараа",past:"%s өмнө",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2} өдөр/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+" өдөр";default:return e}}})}(a(421))},7196:function(e,t,a){!function(e){"use strict";var t={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},a={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};function s(e,t,a,s){var n="";if(t)switch(a){case"s":n="काही सेकंद";break;case"ss":n="%d सेकंद";break;case"m":n="एक मिनिट";break;case"mm":n="%d मिनिटे";break;case"h":n="एक तास";break;case"hh":n="%d तास";break;case"d":n="एक दिवस";break;case"dd":n="%d दिवस";break;case"M":n="एक महिना";break;case"MM":n="%d महिने";break;case"y":n="एक वर्ष";break;case"yy":n="%d वर्षे"}else switch(a){case"s":n="काही सेकंदां";break;case"ss":n="%d सेकंदां";break;case"m":n="एका मिनिटा";break;case"mm":n="%d मिनिटां";break;case"h":n="एका तासा";break;case"hh":n="%d तासां";break;case"d":n="एका दिवसा";break;case"dd":n="%d दिवसां";break;case"M":n="एका महिन्या";break;case"MM":n="%d महिन्यां";break;case"y":n="एका वर्षा";break;case"yy":n="%d वर्षां"}return n.replace(/%d/i,e)}e.defineLocale("mr",{months:"जानेवारी_फेब्रुवारी_मार्च_एप्रिल_मे_जून_जुलै_ऑगस्ट_सप्टेंबर_ऑक्टोबर_नोव्हेंबर_डिसेंबर".split("_"),monthsShort:"जाने._फेब्रु._मार्च._एप्रि._मे._जून._जुलै._ऑग._सप्टें._ऑक्टो._नोव्हें._डिसें.".split("_"),monthsParseExact:!0,weekdays:"रविवार_सोमवार_मंगळवार_बुधवार_गुरूवार_शुक्रवार_शनिवार".split("_"),weekdaysShort:"रवि_सोम_मंगळ_बुध_गुरू_शुक्र_शनि".split("_"),weekdaysMin:"र_सो_मं_बु_गु_शु_श".split("_"),longDateFormat:{LT:"A h:mm वाजता",LTS:"A h:mm:ss वाजता",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm वाजता",LLLL:"dddd, D MMMM YYYY, A h:mm वाजता"},calendar:{sameDay:"[आज] LT",nextDay:"[उद्या] LT",nextWeek:"dddd, LT",lastDay:"[काल] LT",lastWeek:"[मागील] dddd, LT",sameElse:"L"},relativeTime:{future:"%sमध्ये",past:"%sपूर्वी",s,ss:s,m:s,mm:s,h:s,hh:s,d:s,dd:s,M:s,MM:s,y:s,yy:s},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/पहाटे|सकाळी|दुपारी|सायंकाळी|रात्री/,meridiemHour:function(e,t){return 12===e&&(e=0),"पहाटे"===t||"सकाळी"===t?e:"दुपारी"===t||"सायंकाळी"===t||"रात्री"===t?e>=12?e:e+12:void 0},meridiem:function(e,t,a){return e>=0&&e<6?"पहाटे":e<12?"सकाळी":e<17?"दुपारी":e<20?"सायंकाळी":"रात्री"},week:{dow:0,doy:6}})}(a(421))},4750:function(e,t,a){!function(e){"use strict";e.defineLocale("ms-my",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,t){return 12===e&&(e=0),"pagi"===t?e:"tengahari"===t?e>=11?e:e+12:"petang"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,a){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(a(421))},487:function(e,t,a){!function(e){"use strict";e.defineLocale("ms",{months:"Januari_Februari_Mac_April_Mei_Jun_Julai_Ogos_September_Oktober_November_Disember".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ogs_Sep_Okt_Nov_Dis".split("_"),weekdays:"Ahad_Isnin_Selasa_Rabu_Khamis_Jumaat_Sabtu".split("_"),weekdaysShort:"Ahd_Isn_Sel_Rab_Kha_Jum_Sab".split("_"),weekdaysMin:"Ah_Is_Sl_Rb_Km_Jm_Sb".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [pukul] HH.mm",LLLL:"dddd, D MMMM YYYY [pukul] HH.mm"},meridiemParse:/pagi|tengahari|petang|malam/,meridiemHour:function(e,t){return 12===e&&(e=0),"pagi"===t?e:"tengahari"===t?e>=11?e:e+12:"petang"===t||"malam"===t?e+12:void 0},meridiem:function(e,t,a){return e<11?"pagi":e<15?"tengahari":e<19?"petang":"malam"},calendar:{sameDay:"[Hari ini pukul] LT",nextDay:"[Esok pukul] LT",nextWeek:"dddd [pukul] LT",lastDay:"[Kelmarin pukul] LT",lastWeek:"dddd [lepas pukul] LT",sameElse:"L"},relativeTime:{future:"dalam %s",past:"%s yang lepas",s:"beberapa saat",ss:"%d saat",m:"seminit",mm:"%d minit",h:"sejam",hh:"%d jam",d:"sehari",dd:"%d hari",M:"sebulan",MM:"%d bulan",y:"setahun",yy:"%d tahun"},week:{dow:1,doy:7}})}(a(421))},8856:function(e,t,a){!function(e){"use strict";e.defineLocale("mt",{months:"Jannar_Frar_Marzu_April_Mejju_Ġunju_Lulju_Awwissu_Settembru_Ottubru_Novembru_Diċembru".split("_"),monthsShort:"Jan_Fra_Mar_Apr_Mej_Ġun_Lul_Aww_Set_Ott_Nov_Diċ".split("_"),weekdays:"Il-Ħadd_It-Tnejn_It-Tlieta_L-Erbgħa_Il-Ħamis_Il-Ġimgħa_Is-Sibt".split("_"),weekdaysShort:"Ħad_Tne_Tli_Erb_Ħam_Ġim_Sib".split("_"),weekdaysMin:"Ħa_Tn_Tl_Er_Ħa_Ġi_Si".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Illum fil-]LT",nextDay:"[Għada fil-]LT",nextWeek:"dddd [fil-]LT",lastDay:"[Il-bieraħ fil-]LT",lastWeek:"dddd [li għadda] [fil-]LT",sameElse:"L"},relativeTime:{future:"f’ %s",past:"%s ilu",s:"ftit sekondi",ss:"%d sekondi",m:"minuta",mm:"%d minuti",h:"siegħa",hh:"%d siegħat",d:"ġurnata",dd:"%d ġranet",M:"xahar",MM:"%d xhur",y:"sena",yy:"%d sni"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(a(421))},1240:function(e,t,a){!function(e){"use strict";var t={1:"၁",2:"၂",3:"၃",4:"၄",5:"၅",6:"၆",7:"၇",8:"၈",9:"၉",0:"၀"},a={"၁":"1","၂":"2","၃":"3","၄":"4","၅":"5","၆":"6","၇":"7","၈":"8","၉":"9","၀":"0"};e.defineLocale("my",{months:"ဇန်နဝါရီ_ဖေဖော်ဝါရီ_မတ်_ဧပြီ_မေ_ဇွန်_ဇူလိုင်_သြဂုတ်_စက်တင်ဘာ_အောက်တိုဘာ_နိုဝင်ဘာ_ဒီဇင်ဘာ".split("_"),monthsShort:"ဇန်_ဖေ_မတ်_ပြီ_မေ_ဇွန်_လိုင်_သြ_စက်_အောက်_နို_ဒီ".split("_"),weekdays:"တနင်္ဂနွေ_တနင်္လာ_အင်္ဂါ_ဗုဒ္ဓဟူး_ကြာသပတေး_သောကြာ_စနေ".split("_"),weekdaysShort:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),weekdaysMin:"နွေ_လာ_ဂါ_ဟူး_ကြာ_သော_နေ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ယနေ.] LT [မှာ]",nextDay:"[မနက်ဖြန်] LT [မှာ]",nextWeek:"dddd LT [မှာ]",lastDay:"[မနေ.က] LT [မှာ]",lastWeek:"[ပြီးခဲ့သော] dddd LT [မှာ]",sameElse:"L"},relativeTime:{future:"လာမည့် %s မှာ",past:"လွန်ခဲ့သော %s က",s:"စက္ကန်.အနည်းငယ်",ss:"%d စက္ကန့်",m:"တစ်မိနစ်",mm:"%d မိနစ်",h:"တစ်နာရီ",hh:"%d နာရီ",d:"တစ်ရက်",dd:"%d ရက်",M:"တစ်လ",MM:"%d လ",y:"တစ်နှစ်",yy:"%d နှစ်"},preparse:function(e){return e.replace(/[၁၂၃၄၅၆၇၈၉၀]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},week:{dow:1,doy:4}})}(a(421))},2121:function(e,t,a){!function(e){"use strict";e.defineLocale("nb",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"søndag_mandag_tirsdag_onsdag_torsdag_fredag_lørdag".split("_"),weekdaysShort:"sø._ma._ti._on._to._fr._lø.".split("_"),weekdaysMin:"sø_ma_ti_on_to_fr_lø".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] HH:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[i dag kl.] LT",nextDay:"[i morgen kl.] LT",nextWeek:"dddd [kl.] LT",lastDay:"[i går kl.] LT",lastWeek:"[forrige] dddd [kl.] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s siden",s:"noen sekunder",ss:"%d sekunder",m:"ett minutt",mm:"%d minutter",h:"en time",hh:"%d timer",d:"en dag",dd:"%d dager",w:"en uke",ww:"%d uker",M:"en måned",MM:"%d måneder",y:"ett år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},9802:function(e,t,a){!function(e){"use strict";var t={1:"१",2:"२",3:"३",4:"४",5:"५",6:"६",7:"७",8:"८",9:"९",0:"०"},a={"१":"1","२":"2","३":"3","४":"4","५":"5","६":"6","७":"7","८":"8","९":"9","०":"0"};e.defineLocale("ne",{months:"जनवरी_फेब्रुवरी_मार्च_अप्रिल_मई_जुन_जुलाई_अगष्ट_सेप्टेम्बर_अक्टोबर_नोभेम्बर_डिसेम्बर".split("_"),monthsShort:"जन._फेब्रु._मार्च_अप्रि._मई_जुन_जुलाई._अग._सेप्ट._अक्टो._नोभे._डिसे.".split("_"),monthsParseExact:!0,weekdays:"आइतबार_सोमबार_मङ्गलबार_बुधबार_बिहिबार_शुक्रबार_शनिबार".split("_"),weekdaysShort:"आइत._सोम._मङ्गल._बुध._बिहि._शुक्र._शनि.".split("_"),weekdaysMin:"आ._सो._मं._बु._बि._शु._श.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"Aको h:mm बजे",LTS:"Aको h:mm:ss बजे",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, Aको h:mm बजे",LLLL:"dddd, D MMMM YYYY, Aको h:mm बजे"},preparse:function(e){return e.replace(/[१२३४५६७८९०]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/राति|बिहान|दिउँसो|साँझ/,meridiemHour:function(e,t){return 12===e&&(e=0),"राति"===t?e<4?e:e+12:"बिहान"===t?e:"दिउँसो"===t?e>=10?e:e+12:"साँझ"===t?e+12:void 0},meridiem:function(e,t,a){return e<3?"राति":e<12?"बिहान":e<16?"दिउँसो":e<20?"साँझ":"राति"},calendar:{sameDay:"[आज] LT",nextDay:"[भोलि] LT",nextWeek:"[आउँदो] dddd[,] LT",lastDay:"[हिजो] LT",lastWeek:"[गएको] dddd[,] LT",sameElse:"L"},relativeTime:{future:"%sमा",past:"%s अगाडि",s:"केही क्षण",ss:"%d सेकेण्ड",m:"एक मिनेट",mm:"%d मिनेट",h:"एक घण्टा",hh:"%d घण्टा",d:"एक दिन",dd:"%d दिन",M:"एक महिना",MM:"%d महिना",y:"एक बर्ष",yy:"%d बर्ष"},week:{dow:0,doy:6}})}(a(421))},3497:function(e,t,a){!function(e){"use strict";var t="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),a="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),s=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],n=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;e.defineLocale("nl-be",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?a[e.month()]:t[e.month()]:t},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(a(421))},737:function(e,t,a){!function(e){"use strict";var t="jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.".split("_"),a="jan_feb_mrt_apr_mei_jun_jul_aug_sep_okt_nov_dec".split("_"),s=[/^jan/i,/^feb/i,/^maart|mrt.?$/i,/^apr/i,/^mei$/i,/^jun[i.]?$/i,/^jul[i.]?$/i,/^aug/i,/^sep/i,/^okt/i,/^nov/i,/^dec/i],n=/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december|jan\.?|feb\.?|mrt\.?|apr\.?|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i;e.defineLocale("nl",{months:"januari_februari_maart_april_mei_juni_juli_augustus_september_oktober_november_december".split("_"),monthsShort:function(e,s){return e?/-MMM-/.test(s)?a[e.month()]:t[e.month()]:t},monthsRegex:n,monthsShortRegex:n,monthsStrictRegex:/^(januari|februari|maart|april|mei|ju[nl]i|augustus|september|oktober|november|december)/i,monthsShortStrictRegex:/^(jan\.?|feb\.?|mrt\.?|apr\.?|mei|ju[nl]\.?|aug\.?|sep\.?|okt\.?|nov\.?|dec\.?)/i,monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"zondag_maandag_dinsdag_woensdag_donderdag_vrijdag_zaterdag".split("_"),weekdaysShort:"zo._ma._di._wo._do._vr._za.".split("_"),weekdaysMin:"zo_ma_di_wo_do_vr_za".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD-MM-YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[vandaag om] LT",nextDay:"[morgen om] LT",nextWeek:"dddd [om] LT",lastDay:"[gisteren om] LT",lastWeek:"[afgelopen] dddd [om] LT",sameElse:"L"},relativeTime:{future:"over %s",past:"%s geleden",s:"een paar seconden",ss:"%d seconden",m:"één minuut",mm:"%d minuten",h:"één uur",hh:"%d uur",d:"één dag",dd:"%d dagen",w:"één week",ww:"%d weken",M:"één maand",MM:"%d maanden",y:"één jaar",yy:"%d jaar"},dayOfMonthOrdinalParse:/\d{1,2}(ste|de)/,ordinal:function(e){return e+(1===e||8===e||e>=20?"ste":"de")},week:{dow:1,doy:4}})}(a(421))},8153:function(e,t,a){!function(e){"use strict";e.defineLocale("nn",{months:"januar_februar_mars_april_mai_juni_juli_august_september_oktober_november_desember".split("_"),monthsShort:"jan._feb._mars_apr._mai_juni_juli_aug._sep._okt._nov._des.".split("_"),monthsParseExact:!0,weekdays:"sundag_måndag_tysdag_onsdag_torsdag_fredag_laurdag".split("_"),weekdaysShort:"su._må._ty._on._to._fr._lau.".split("_"),weekdaysMin:"su_må_ty_on_to_fr_la".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY [kl.] H:mm",LLLL:"dddd D. MMMM YYYY [kl.] HH:mm"},calendar:{sameDay:"[I dag klokka] LT",nextDay:"[I morgon klokka] LT",nextWeek:"dddd [klokka] LT",lastDay:"[I går klokka] LT",lastWeek:"[Føregåande] dddd [klokka] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"%s sidan",s:"nokre sekund",ss:"%d sekund",m:"eit minutt",mm:"%d minutt",h:"ein time",hh:"%d timar",d:"ein dag",dd:"%d dagar",w:"ei veke",ww:"%d veker",M:"ein månad",MM:"%d månader",y:"eit år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},5173:function(e,t,a){!function(e){"use strict";e.defineLocale("oc-lnc",{months:{standalone:"genièr_febrièr_març_abril_mai_junh_julhet_agost_setembre_octòbre_novembre_decembre".split("_"),format:"de genièr_de febrièr_de març_d'abril_de mai_de junh_de julhet_d'agost_de setembre_d'octòbre_de novembre_de decembre".split("_"),isFormat:/D[oD]?(\s)+MMMM/},monthsShort:"gen._febr._març_abr._mai_junh_julh._ago._set._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"dimenge_diluns_dimars_dimècres_dijòus_divendres_dissabte".split("_"),weekdaysShort:"dg._dl._dm._dc._dj._dv._ds.".split("_"),weekdaysMin:"dg_dl_dm_dc_dj_dv_ds".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [de] YYYY",ll:"D MMM YYYY",LLL:"D MMMM [de] YYYY [a] H:mm",lll:"D MMM YYYY, H:mm",LLLL:"dddd D MMMM [de] YYYY [a] H:mm",llll:"ddd D MMM YYYY, H:mm"},calendar:{sameDay:"[uèi a] LT",nextDay:"[deman a] LT",nextWeek:"dddd [a] LT",lastDay:"[ièr a] LT",lastWeek:"dddd [passat a] LT",sameElse:"L"},relativeTime:{future:"d'aquí %s",past:"fa %s",s:"unas segondas",ss:"%d segondas",m:"una minuta",mm:"%d minutas",h:"una ora",hh:"%d oras",d:"un jorn",dd:"%d jorns",M:"un mes",MM:"%d meses",y:"un an",yy:"%d ans"},dayOfMonthOrdinalParse:/\d{1,2}(r|n|t|è|a)/,ordinal:function(e,t){var a=1===e?"r":2===e?"n":3===e?"r":4===e?"t":"è";return"w"!==t&&"W"!==t||(a="a"),e+a},week:{dow:1,doy:4}})}(a(421))},499:function(e,t,a){!function(e){"use strict";var t={1:"੧",2:"੨",3:"੩",4:"੪",5:"੫",6:"੬",7:"੭",8:"੮",9:"੯",0:"੦"},a={"੧":"1","੨":"2","੩":"3","੪":"4","੫":"5","੬":"6","੭":"7","੮":"8","੯":"9","੦":"0"};e.defineLocale("pa-in",{months:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),monthsShort:"ਜਨਵਰੀ_ਫ਼ਰਵਰੀ_ਮਾਰਚ_ਅਪ੍ਰੈਲ_ਮਈ_ਜੂਨ_ਜੁਲਾਈ_ਅਗਸਤ_ਸਤੰਬਰ_ਅਕਤੂਬਰ_ਨਵੰਬਰ_ਦਸੰਬਰ".split("_"),weekdays:"ਐਤਵਾਰ_ਸੋਮਵਾਰ_ਮੰਗਲਵਾਰ_ਬੁਧਵਾਰ_ਵੀਰਵਾਰ_ਸ਼ੁੱਕਰਵਾਰ_ਸ਼ਨੀਚਰਵਾਰ".split("_"),weekdaysShort:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),weekdaysMin:"ਐਤ_ਸੋਮ_ਮੰਗਲ_ਬੁਧ_ਵੀਰ_ਸ਼ੁਕਰ_ਸ਼ਨੀ".split("_"),longDateFormat:{LT:"A h:mm ਵਜੇ",LTS:"A h:mm:ss ਵਜੇ",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm ਵਜੇ",LLLL:"dddd, D MMMM YYYY, A h:mm ਵਜੇ"},calendar:{sameDay:"[ਅਜ] LT",nextDay:"[ਕਲ] LT",nextWeek:"[ਅਗਲਾ] dddd, LT",lastDay:"[ਕਲ] LT",lastWeek:"[ਪਿਛਲੇ] dddd, LT",sameElse:"L"},relativeTime:{future:"%s ਵਿੱਚ",past:"%s ਪਿਛਲੇ",s:"ਕੁਝ ਸਕਿੰਟ",ss:"%d ਸਕਿੰਟ",m:"ਇਕ ਮਿੰਟ",mm:"%d ਮਿੰਟ",h:"ਇੱਕ ਘੰਟਾ",hh:"%d ਘੰਟੇ",d:"ਇੱਕ ਦਿਨ",dd:"%d ਦਿਨ",M:"ਇੱਕ ਮਹੀਨਾ",MM:"%d ਮਹੀਨੇ",y:"ਇੱਕ ਸਾਲ",yy:"%d ਸਾਲ"},preparse:function(e){return e.replace(/[੧੨੩੪੫੬੭੮੯੦]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/ਰਾਤ|ਸਵੇਰ|ਦੁਪਹਿਰ|ਸ਼ਾਮ/,meridiemHour:function(e,t){return 12===e&&(e=0),"ਰਾਤ"===t?e<4?e:e+12:"ਸਵੇਰ"===t?e:"ਦੁਪਹਿਰ"===t?e>=10?e:e+12:"ਸ਼ਾਮ"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"ਰਾਤ":e<10?"ਸਵੇਰ":e<17?"ਦੁਪਹਿਰ":e<20?"ਸ਼ਾਮ":"ਰਾਤ"},week:{dow:0,doy:6}})}(a(421))},3629:function(e,t,a){!function(e){"use strict";var t="styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień".split("_"),a="stycznia_lutego_marca_kwietnia_maja_czerwca_lipca_sierpnia_września_października_listopada_grudnia".split("_"),s=[/^sty/i,/^lut/i,/^mar/i,/^kwi/i,/^maj/i,/^cze/i,/^lip/i,/^sie/i,/^wrz/i,/^paź/i,/^lis/i,/^gru/i];function n(e){return e%10<5&&e%10>1&&~~(e/10)%10!=1}function i(e,t,a){var s=e+" ";switch(a){case"ss":return s+(n(e)?"sekundy":"sekund");case"m":return t?"minuta":"minutę";case"mm":return s+(n(e)?"minuty":"minut");case"h":return t?"godzina":"godzinę";case"hh":return s+(n(e)?"godziny":"godzin");case"ww":return s+(n(e)?"tygodnie":"tygodni");case"MM":return s+(n(e)?"miesiące":"miesięcy");case"yy":return s+(n(e)?"lata":"lat")}}e.defineLocale("pl",{months:function(e,s){return e?/D MMMM/.test(s)?a[e.month()]:t[e.month()]:t},monthsShort:"sty_lut_mar_kwi_maj_cze_lip_sie_wrz_paź_lis_gru".split("_"),monthsParse:s,longMonthsParse:s,shortMonthsParse:s,weekdays:"niedziela_poniedziałek_wtorek_środa_czwartek_piątek_sobota".split("_"),weekdaysShort:"ndz_pon_wt_śr_czw_pt_sob".split("_"),weekdaysMin:"Nd_Pn_Wt_Śr_Cz_Pt_So".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Dziś o] LT",nextDay:"[Jutro o] LT",nextWeek:function(){switch(this.day()){case 0:return"[W niedzielę o] LT";case 2:return"[We wtorek o] LT";case 3:return"[W środę o] LT";case 6:return"[W sobotę o] LT";default:return"[W] dddd [o] LT"}},lastDay:"[Wczoraj o] LT",lastWeek:function(){switch(this.day()){case 0:return"[W zeszłą niedzielę o] LT";case 3:return"[W zeszłą środę o] LT";case 6:return"[W zeszłą sobotę o] LT";default:return"[W zeszły] dddd [o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"%s temu",s:"kilka sekund",ss:i,m:i,mm:i,h:i,hh:i,d:"1 dzień",dd:"%d dni",w:"tydzień",ww:i,M:"miesiąc",MM:i,y:"rok",yy:i},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},3312:function(e,t,a){!function(e){"use strict";e.defineLocale("pt-br",{months:"janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"domingo_segunda-feira_terça-feira_quarta-feira_quinta-feira_sexta-feira_sábado".split("_"),weekdaysShort:"dom_seg_ter_qua_qui_sex_sáb".split("_"),weekdaysMin:"do_2ª_3ª_4ª_5ª_6ª_sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY [às] HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY [às] HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"poucos segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",invalidDate:"Data inválida"})}(a(421))},5702:function(e,t,a){!function(e){"use strict";e.defineLocale("pt",{months:"janeiro_fevereiro_março_abril_maio_junho_julho_agosto_setembro_outubro_novembro_dezembro".split("_"),monthsShort:"jan_fev_mar_abr_mai_jun_jul_ago_set_out_nov_dez".split("_"),weekdays:"Domingo_Segunda-feira_Terça-feira_Quarta-feira_Quinta-feira_Sexta-feira_Sábado".split("_"),weekdaysShort:"Dom_Seg_Ter_Qua_Qui_Sex_Sáb".split("_"),weekdaysMin:"Do_2ª_3ª_4ª_5ª_6ª_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D [de] MMMM [de] YYYY",LLL:"D [de] MMMM [de] YYYY HH:mm",LLLL:"dddd, D [de] MMMM [de] YYYY HH:mm"},calendar:{sameDay:"[Hoje às] LT",nextDay:"[Amanhã às] LT",nextWeek:"dddd [às] LT",lastDay:"[Ontem às] LT",lastWeek:function(){return 0===this.day()||6===this.day()?"[Último] dddd [às] LT":"[Última] dddd [às] LT"},sameElse:"L"},relativeTime:{future:"em %s",past:"há %s",s:"segundos",ss:"%d segundos",m:"um minuto",mm:"%d minutos",h:"uma hora",hh:"%d horas",d:"um dia",dd:"%d dias",w:"uma semana",ww:"%d semanas",M:"um mês",MM:"%d meses",y:"um ano",yy:"%d anos"},dayOfMonthOrdinalParse:/\d{1,2}º/,ordinal:"%dº",week:{dow:1,doy:4}})}(a(421))},719:function(e,t,a){!function(e){"use strict";function t(e,t,a){var s=" ";return(e%100>=20||e>=100&&e%100==0)&&(s=" de "),e+s+{ss:"secunde",mm:"minute",hh:"ore",dd:"zile",ww:"săptămâni",MM:"luni",yy:"ani"}[a]}e.defineLocale("ro",{months:"ianuarie_februarie_martie_aprilie_mai_iunie_iulie_august_septembrie_octombrie_noiembrie_decembrie".split("_"),monthsShort:"ian._feb._mart._apr._mai_iun._iul._aug._sept._oct._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"duminică_luni_marți_miercuri_joi_vineri_sâmbătă".split("_"),weekdaysShort:"Dum_Lun_Mar_Mie_Joi_Vin_Sâm".split("_"),weekdaysMin:"Du_Lu_Ma_Mi_Jo_Vi_Sâ".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY H:mm",LLLL:"dddd, D MMMM YYYY H:mm"},calendar:{sameDay:"[azi la] LT",nextDay:"[mâine la] LT",nextWeek:"dddd [la] LT",lastDay:"[ieri la] LT",lastWeek:"[fosta] dddd [la] LT",sameElse:"L"},relativeTime:{future:"peste %s",past:"%s în urmă",s:"câteva secunde",ss:t,m:"un minut",mm:t,h:"o oră",hh:t,d:"o zi",dd:t,w:"o săptămână",ww:t,M:"o lună",MM:t,y:"un an",yy:t},week:{dow:1,doy:7}})}(a(421))},3778:function(e,t,a){!function(e){"use strict";function t(e,t,a){return"m"===a?t?"минута":"минуту":e+" "+(s=+e,n={ss:t?"секунда_секунды_секунд":"секунду_секунды_секунд",mm:t?"минута_минуты_минут":"минуту_минуты_минут",hh:"час_часа_часов",dd:"день_дня_дней",ww:"неделя_недели_недель",MM:"месяц_месяца_месяцев",yy:"год_года_лет"}[a].split("_"),s%10==1&&s%100!=11?n[0]:s%10>=2&&s%10<=4&&(s%100<10||s%100>=20)?n[1]:n[2]);var s,n}var a=[/^янв/i,/^фев/i,/^мар/i,/^апр/i,/^ма[йя]/i,/^июн/i,/^июл/i,/^авг/i,/^сен/i,/^окт/i,/^ноя/i,/^дек/i];e.defineLocale("ru",{months:{format:"января_февраля_марта_апреля_мая_июня_июля_августа_сентября_октября_ноября_декабря".split("_"),standalone:"январь_февраль_март_апрель_май_июнь_июль_август_сентябрь_октябрь_ноябрь_декабрь".split("_")},monthsShort:{format:"янв._февр._мар._апр._мая_июня_июля_авг._сент._окт._нояб._дек.".split("_"),standalone:"янв._февр._март_апр._май_июнь_июль_авг._сент._окт._нояб._дек.".split("_")},weekdays:{standalone:"воскресенье_понедельник_вторник_среда_четверг_пятница_суббота".split("_"),format:"воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу".split("_"),isFormat:/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?] ?dddd/},weekdaysShort:"вс_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"вс_пн_вт_ср_чт_пт_сб".split("_"),monthsParse:a,longMonthsParse:a,shortMonthsParse:a,monthsRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsShortRegex:/^(январ[ья]|янв\.?|феврал[ья]|февр?\.?|марта?|мар\.?|апрел[ья]|апр\.?|ма[йя]|июн[ья]|июн\.?|июл[ья]|июл\.?|августа?|авг\.?|сентябр[ья]|сент?\.?|октябр[ья]|окт\.?|ноябр[ья]|нояб?\.?|декабр[ья]|дек\.?)/i,monthsStrictRegex:/^(январ[яь]|феврал[яь]|марта?|апрел[яь]|ма[яй]|июн[яь]|июл[яь]|августа?|сентябр[яь]|октябр[яь]|ноябр[яь]|декабр[яь])/i,monthsShortStrictRegex:/^(янв\.|февр?\.|мар[т.]|апр\.|ма[яй]|июн[ья.]|июл[ья.]|авг\.|сент?\.|окт\.|нояб?\.|дек\.)/i,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY г.",LLL:"D MMMM YYYY г., H:mm",LLLL:"dddd, D MMMM YYYY г., H:mm"},calendar:{sameDay:"[Сегодня, в] LT",nextDay:"[Завтра, в] LT",lastDay:"[Вчера, в] LT",nextWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В следующее] dddd, [в] LT";case 1:case 2:case 4:return"[В следующий] dddd, [в] LT";case 3:case 5:case 6:return"[В следующую] dddd, [в] LT"}},lastWeek:function(e){if(e.week()===this.week())return 2===this.day()?"[Во] dddd, [в] LT":"[В] dddd, [в] LT";switch(this.day()){case 0:return"[В прошлое] dddd, [в] LT";case 1:case 2:case 4:return"[В прошлый] dddd, [в] LT";case 3:case 5:case 6:return"[В прошлую] dddd, [в] LT"}},sameElse:"L"},relativeTime:{future:"через %s",past:"%s назад",s:"несколько секунд",ss:t,m:t,mm:t,h:"час",hh:t,d:"день",dd:t,w:"неделя",ww:t,M:"месяц",MM:t,y:"год",yy:t},meridiemParse:/ночи|утра|дня|вечера/i,isPM:function(e){return/^(дня|вечера)$/.test(e)},meridiem:function(e,t,a){return e<4?"ночи":e<12?"утра":e<17?"дня":"вечера"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го|я)/,ordinal:function(e,t){switch(t){case"M":case"d":case"DDD":return e+"-й";case"D":return e+"-го";case"w":case"W":return e+"-я";default:return e}},week:{dow:1,doy:4}})}(a(421))},5545:function(e,t,a){!function(e){"use strict";var t=["جنوري","فيبروري","مارچ","اپريل","مئي","جون","جولاءِ","آگسٽ","سيپٽمبر","آڪٽوبر","نومبر","ڊسمبر"],a=["آچر","سومر","اڱارو","اربع","خميس","جمع","ڇنڇر"];e.defineLocale("sd",{months:t,monthsShort:t,weekdays:a,weekdaysShort:a,weekdaysMin:a,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,t,a){return e<12?"صبح":"شام"},calendar:{sameDay:"[اڄ] LT",nextDay:"[سڀاڻي] LT",nextWeek:"dddd [اڳين هفتي تي] LT",lastDay:"[ڪالهه] LT",lastWeek:"[گزريل هفتي] dddd [تي] LT",sameElse:"L"},relativeTime:{future:"%s پوء",past:"%s اڳ",s:"چند سيڪنڊ",ss:"%d سيڪنڊ",m:"هڪ منٽ",mm:"%d منٽ",h:"هڪ ڪلاڪ",hh:"%d ڪلاڪ",d:"هڪ ڏينهن",dd:"%d ڏينهن",M:"هڪ مهينو",MM:"%d مهينا",y:"هڪ سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})}(a(421))},5811:function(e,t,a){!function(e){"use strict";e.defineLocale("se",{months:"ođđajagemánnu_guovvamánnu_njukčamánnu_cuoŋománnu_miessemánnu_geassemánnu_suoidnemánnu_borgemánnu_čakčamánnu_golggotmánnu_skábmamánnu_juovlamánnu".split("_"),monthsShort:"ođđj_guov_njuk_cuo_mies_geas_suoi_borg_čakč_golg_skáb_juov".split("_"),weekdays:"sotnabeaivi_vuossárga_maŋŋebárga_gaskavahkku_duorastat_bearjadat_lávvardat".split("_"),weekdaysShort:"sotn_vuos_maŋ_gask_duor_bear_láv".split("_"),weekdaysMin:"s_v_m_g_d_b_L".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"MMMM D. [b.] YYYY",LLL:"MMMM D. [b.] YYYY [ti.] HH:mm",LLLL:"dddd, MMMM D. [b.] YYYY [ti.] HH:mm"},calendar:{sameDay:"[otne ti] LT",nextDay:"[ihttin ti] LT",nextWeek:"dddd [ti] LT",lastDay:"[ikte ti] LT",lastWeek:"[ovddit] dddd [ti] LT",sameElse:"L"},relativeTime:{future:"%s geažes",past:"maŋit %s",s:"moadde sekunddat",ss:"%d sekunddat",m:"okta minuhta",mm:"%d minuhtat",h:"okta diimmu",hh:"%d diimmut",d:"okta beaivi",dd:"%d beaivvit",M:"okta mánnu",MM:"%d mánut",y:"okta jahki",yy:"%d jagit"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},2015:function(e,t,a){!function(e){"use strict";e.defineLocale("si",{months:"ජනවාරි_පෙබරවාරි_මාර්තු_අප්‍රේල්_මැයි_ජූනි_ජූලි_අගෝස්තු_සැප්තැම්බර්_ඔක්තෝබර්_නොවැම්බර්_දෙසැම්බර්".split("_"),monthsShort:"ජන_පෙබ_මාර්_අප්_මැයි_ජූනි_ජූලි_අගෝ_සැප්_ඔක්_නොවැ_දෙසැ".split("_"),weekdays:"ඉරිදා_සඳුදා_අඟහරුවාදා_බදාදා_බ්‍රහස්පතින්දා_සිකුරාදා_සෙනසුරාදා".split("_"),weekdaysShort:"ඉරි_සඳු_අඟ_බදා_බ්‍රහ_සිකු_සෙන".split("_"),weekdaysMin:"ඉ_ස_අ_බ_බ්‍ර_සි_සෙ".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"a h:mm",LTS:"a h:mm:ss",L:"YYYY/MM/DD",LL:"YYYY MMMM D",LLL:"YYYY MMMM D, a h:mm",LLLL:"YYYY MMMM D [වැනි] dddd, a h:mm:ss"},calendar:{sameDay:"[අද] LT[ට]",nextDay:"[හෙට] LT[ට]",nextWeek:"dddd LT[ට]",lastDay:"[ඊයේ] LT[ට]",lastWeek:"[පසුගිය] dddd LT[ට]",sameElse:"L"},relativeTime:{future:"%sකින්",past:"%sකට පෙර",s:"තත්පර කිහිපය",ss:"තත්පර %d",m:"මිනිත්තුව",mm:"මිනිත්තු %d",h:"පැය",hh:"පැය %d",d:"දිනය",dd:"දින %d",M:"මාසය",MM:"මාස %d",y:"වසර",yy:"වසර %d"},dayOfMonthOrdinalParse:/\d{1,2} වැනි/,ordinal:function(e){return e+" වැනි"},meridiemParse:/පෙර වරු|පස් වරු|පෙ.ව|ප.ව./,isPM:function(e){return"ප.ව."===e||"පස් වරු"===e},meridiem:function(e,t,a){return e>11?a?"ප.ව.":"පස් වරු":a?"පෙ.ව.":"පෙර වරු"}})}(a(421))},1587:function(e,t,a){!function(e){"use strict";var t="január_február_marec_apríl_máj_jún_júl_august_september_október_november_december".split("_"),a="jan_feb_mar_apr_máj_jún_júl_aug_sep_okt_nov_dec".split("_");function s(e){return e>1&&e<5}function n(e,t,a,n){var i=e+" ";switch(a){case"s":return t||n?"pár sekúnd":"pár sekundami";case"ss":return t||n?i+(s(e)?"sekundy":"sekúnd"):i+"sekundami";case"m":return t?"minúta":n?"minútu":"minútou";case"mm":return t||n?i+(s(e)?"minúty":"minút"):i+"minútami";case"h":return t?"hodina":n?"hodinu":"hodinou";case"hh":return t||n?i+(s(e)?"hodiny":"hodín"):i+"hodinami";case"d":return t||n?"deň":"dňom";case"dd":return t||n?i+(s(e)?"dni":"dní"):i+"dňami";case"M":return t||n?"mesiac":"mesiacom";case"MM":return t||n?i+(s(e)?"mesiace":"mesiacov"):i+"mesiacmi";case"y":return t||n?"rok":"rokom";case"yy":return t||n?i+(s(e)?"roky":"rokov"):i+"rokmi"}}e.defineLocale("sk",{months:t,monthsShort:a,weekdays:"nedeľa_pondelok_utorok_streda_štvrtok_piatok_sobota".split("_"),weekdaysShort:"ne_po_ut_st_št_pi_so".split("_"),weekdaysMin:"ne_po_ut_st_št_pi_so".split("_"),longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD.MM.YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd D. MMMM YYYY H:mm"},calendar:{sameDay:"[dnes o] LT",nextDay:"[zajtra o] LT",nextWeek:function(){switch(this.day()){case 0:return"[v nedeľu o] LT";case 1:case 2:return"[v] dddd [o] LT";case 3:return"[v stredu o] LT";case 4:return"[vo štvrtok o] LT";case 5:return"[v piatok o] LT";case 6:return"[v sobotu o] LT"}},lastDay:"[včera o] LT",lastWeek:function(){switch(this.day()){case 0:return"[minulú nedeľu o] LT";case 1:case 2:case 4:case 5:return"[minulý] dddd [o] LT";case 3:return"[minulú stredu o] LT";case 6:return"[minulú sobotu o] LT"}},sameElse:"L"},relativeTime:{future:"za %s",past:"pred %s",s:n,ss:n,m:n,mm:n,h:n,hh:n,d:n,dd:n,M:n,MM:n,y:n,yy:n},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},147:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n=e+" ";switch(a){case"s":return t||s?"nekaj sekund":"nekaj sekundami";case"ss":return n+(1===e?t?"sekundo":"sekundi":2===e?t||s?"sekundi":"sekundah":e<5?t||s?"sekunde":"sekundah":"sekund");case"m":return t?"ena minuta":"eno minuto";case"mm":return n+(1===e?t?"minuta":"minuto":2===e?t||s?"minuti":"minutama":e<5?t||s?"minute":"minutami":t||s?"minut":"minutami");case"h":return t?"ena ura":"eno uro";case"hh":return n+(1===e?t?"ura":"uro":2===e?t||s?"uri":"urama":e<5?t||s?"ure":"urami":t||s?"ur":"urami");case"d":return t||s?"en dan":"enim dnem";case"dd":return n+(1===e?t||s?"dan":"dnem":2===e?t||s?"dni":"dnevoma":t||s?"dni":"dnevi");case"M":return t||s?"en mesec":"enim mesecem";case"MM":return n+(1===e?t||s?"mesec":"mesecem":2===e?t||s?"meseca":"mesecema":e<5?t||s?"mesece":"meseci":t||s?"mesecev":"meseci");case"y":return t||s?"eno leto":"enim letom";case"yy":return n+(1===e?t||s?"leto":"letom":2===e?t||s?"leti":"letoma":e<5?t||s?"leta":"leti":t||s?"let":"leti")}}e.defineLocale("sl",{months:"januar_februar_marec_april_maj_junij_julij_avgust_september_oktober_november_december".split("_"),monthsShort:"jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljek_torek_sreda_četrtek_petek_sobota".split("_"),weekdaysShort:"ned._pon._tor._sre._čet._pet._sob.".split("_"),weekdaysMin:"ne_po_to_sr_če_pe_so".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD. MM. YYYY",LL:"D. MMMM YYYY",LLL:"D. MMMM YYYY H:mm",LLLL:"dddd, D. MMMM YYYY H:mm"},calendar:{sameDay:"[danes ob] LT",nextDay:"[jutri ob] LT",nextWeek:function(){switch(this.day()){case 0:return"[v] [nedeljo] [ob] LT";case 3:return"[v] [sredo] [ob] LT";case 6:return"[v] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[v] dddd [ob] LT"}},lastDay:"[včeraj ob] LT",lastWeek:function(){switch(this.day()){case 0:return"[prejšnjo] [nedeljo] [ob] LT";case 3:return"[prejšnjo] [sredo] [ob] LT";case 6:return"[prejšnjo] [soboto] [ob] LT";case 1:case 2:case 4:case 5:return"[prejšnji] dddd [ob] LT"}},sameElse:"L"},relativeTime:{future:"čez %s",past:"pred %s",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(a(421))},6821:function(e,t,a){!function(e){"use strict";e.defineLocale("sq",{months:"Janar_Shkurt_Mars_Prill_Maj_Qershor_Korrik_Gusht_Shtator_Tetor_Nëntor_Dhjetor".split("_"),monthsShort:"Jan_Shk_Mar_Pri_Maj_Qer_Kor_Gus_Sht_Tet_Nën_Dhj".split("_"),weekdays:"E Diel_E Hënë_E Martë_E Mërkurë_E Enjte_E Premte_E Shtunë".split("_"),weekdaysShort:"Die_Hën_Mar_Mër_Enj_Pre_Sht".split("_"),weekdaysMin:"D_H_Ma_Më_E_P_Sh".split("_"),weekdaysParseExact:!0,meridiemParse:/PD|MD/,isPM:function(e){return"M"===e.charAt(0)},meridiem:function(e,t,a){return e<12?"PD":"MD"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Sot në] LT",nextDay:"[Nesër në] LT",nextWeek:"dddd [në] LT",lastDay:"[Dje në] LT",lastWeek:"dddd [e kaluar në] LT",sameElse:"L"},relativeTime:{future:"në %s",past:"%s më parë",s:"disa sekonda",ss:"%d sekonda",m:"një minutë",mm:"%d minuta",h:"një orë",hh:"%d orë",d:"një ditë",dd:"%d ditë",M:"një muaj",MM:"%d muaj",y:"një vit",yy:"%d vite"},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},7792:function(e,t,a){!function(e){"use strict";var t={words:{ss:["секунда","секунде","секунди"],m:["један минут","једног минута"],mm:["минут","минута","минута"],h:["један сат","једног сата"],hh:["сат","сата","сати"],d:["један дан","једног дана"],dd:["дан","дана","дана"],M:["један месец","једног месеца"],MM:["месец","месеца","месеци"],y:["једну годину","једне године"],yy:["годину","године","година"]},correctGrammaticalCase:function(e,t){return e%10>=1&&e%10<=4&&(e%100<10||e%100>=20)?e%10==1?t[0]:t[1]:t[2]},translate:function(e,a,s,n){var i,r=t.words[s];return 1===s.length?"y"===s&&a?"једна година":n||a?r[0]:r[1]:(i=t.correctGrammaticalCase(e,r),"yy"===s&&a&&"годину"===i?e+" година":e+" "+i)}};e.defineLocale("sr-cyrl",{months:"јануар_фебруар_март_април_мај_јун_јул_август_септембар_октобар_новембар_децембар".split("_"),monthsShort:"јан._феб._мар._апр._мај_јун_јул_авг._сеп._окт._нов._дец.".split("_"),monthsParseExact:!0,weekdays:"недеља_понедељак_уторак_среда_четвртак_петак_субота".split("_"),weekdaysShort:"нед._пон._уто._сре._чет._пет._суб.".split("_"),weekdaysMin:"не_по_ут_ср_че_пе_су".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[данас у] LT",nextDay:"[сутра у] LT",nextWeek:function(){switch(this.day()){case 0:return"[у] [недељу] [у] LT";case 3:return"[у] [среду] [у] LT";case 6:return"[у] [суботу] [у] LT";case 1:case 2:case 4:case 5:return"[у] dddd [у] LT"}},lastDay:"[јуче у] LT",lastWeek:function(){return["[прошле] [недеље] [у] LT","[прошлог] [понедељка] [у] LT","[прошлог] [уторка] [у] LT","[прошле] [среде] [у] LT","[прошлог] [четвртка] [у] LT","[прошлог] [петка] [у] LT","[прошле] [суботе] [у] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"за %s",past:"пре %s",s:"неколико секунди",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:t.translate,dd:t.translate,M:t.translate,MM:t.translate,y:t.translate,yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(a(421))},3019:function(e,t,a){!function(e){"use strict";var t={words:{ss:["sekunda","sekunde","sekundi"],m:["jedan minut","jednog minuta"],mm:["minut","minuta","minuta"],h:["jedan sat","jednog sata"],hh:["sat","sata","sati"],d:["jedan dan","jednog dana"],dd:["dan","dana","dana"],M:["jedan mesec","jednog meseca"],MM:["mesec","meseca","meseci"],y:["jednu godinu","jedne godine"],yy:["godinu","godine","godina"]},correctGrammaticalCase:function(e,t){return e%10>=1&&e%10<=4&&(e%100<10||e%100>=20)?e%10==1?t[0]:t[1]:t[2]},translate:function(e,a,s,n){var i,r=t.words[s];return 1===s.length?"y"===s&&a?"jedna godina":n||a?r[0]:r[1]:(i=t.correctGrammaticalCase(e,r),"yy"===s&&a&&"godinu"===i?e+" godina":e+" "+i)}};e.defineLocale("sr",{months:"januar_februar_mart_april_maj_jun_jul_avgust_septembar_oktobar_novembar_decembar".split("_"),monthsShort:"jan._feb._mar._apr._maj_jun_jul_avg._sep._okt._nov._dec.".split("_"),monthsParseExact:!0,weekdays:"nedelja_ponedeljak_utorak_sreda_četvrtak_petak_subota".split("_"),weekdaysShort:"ned._pon._uto._sre._čet._pet._sub.".split("_"),weekdaysMin:"ne_po_ut_sr_če_pe_su".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"D. M. YYYY.",LL:"D. MMMM YYYY.",LLL:"D. MMMM YYYY. H:mm",LLLL:"dddd, D. MMMM YYYY. H:mm"},calendar:{sameDay:"[danas u] LT",nextDay:"[sutra u] LT",nextWeek:function(){switch(this.day()){case 0:return"[u] [nedelju] [u] LT";case 3:return"[u] [sredu] [u] LT";case 6:return"[u] [subotu] [u] LT";case 1:case 2:case 4:case 5:return"[u] dddd [u] LT"}},lastDay:"[juče u] LT",lastWeek:function(){return["[prošle] [nedelje] [u] LT","[prošlog] [ponedeljka] [u] LT","[prošlog] [utorka] [u] LT","[prošle] [srede] [u] LT","[prošlog] [četvrtka] [u] LT","[prošlog] [petka] [u] LT","[prošle] [subote] [u] LT"][this.day()]},sameElse:"L"},relativeTime:{future:"za %s",past:"pre %s",s:"nekoliko sekundi",ss:t.translate,m:t.translate,mm:t.translate,h:t.translate,hh:t.translate,d:t.translate,dd:t.translate,M:t.translate,MM:t.translate,y:t.translate,yy:t.translate},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:7}})}(a(421))},5078:function(e,t,a){!function(e){"use strict";e.defineLocale("ss",{months:"Bhimbidvwane_Indlovana_Indlov'lenkhulu_Mabasa_Inkhwekhweti_Inhlaba_Kholwane_Ingci_Inyoni_Imphala_Lweti_Ingongoni".split("_"),monthsShort:"Bhi_Ina_Inu_Mab_Ink_Inh_Kho_Igc_Iny_Imp_Lwe_Igo".split("_"),weekdays:"Lisontfo_Umsombuluko_Lesibili_Lesitsatfu_Lesine_Lesihlanu_Umgcibelo".split("_"),weekdaysShort:"Lis_Umb_Lsb_Les_Lsi_Lsh_Umg".split("_"),weekdaysMin:"Li_Us_Lb_Lt_Ls_Lh_Ug".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Namuhla nga] LT",nextDay:"[Kusasa nga] LT",nextWeek:"dddd [nga] LT",lastDay:"[Itolo nga] LT",lastWeek:"dddd [leliphelile] [nga] LT",sameElse:"L"},relativeTime:{future:"nga %s",past:"wenteka nga %s",s:"emizuzwana lomcane",ss:"%d mzuzwana",m:"umzuzu",mm:"%d emizuzu",h:"lihora",hh:"%d emahora",d:"lilanga",dd:"%d emalanga",M:"inyanga",MM:"%d tinyanga",y:"umnyaka",yy:"%d iminyaka"},meridiemParse:/ekuseni|emini|entsambama|ebusuku/,meridiem:function(e,t,a){return e<11?"ekuseni":e<15?"emini":e<19?"entsambama":"ebusuku"},meridiemHour:function(e,t){return 12===e&&(e=0),"ekuseni"===t?e:"emini"===t?e>=11?e:e+12:"entsambama"===t||"ebusuku"===t?0===e?0:e+12:void 0},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:"%d",week:{dow:1,doy:4}})}(a(421))},3593:function(e,t,a){!function(e){"use strict";e.defineLocale("sv",{months:"januari_februari_mars_april_maj_juni_juli_augusti_september_oktober_november_december".split("_"),monthsShort:"jan_feb_mar_apr_maj_jun_jul_aug_sep_okt_nov_dec".split("_"),weekdays:"söndag_måndag_tisdag_onsdag_torsdag_fredag_lördag".split("_"),weekdaysShort:"sön_mån_tis_ons_tor_fre_lör".split("_"),weekdaysMin:"sö_må_ti_on_to_fr_lö".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"D MMMM YYYY",LLL:"D MMMM YYYY [kl.] HH:mm",LLLL:"dddd D MMMM YYYY [kl.] HH:mm",lll:"D MMM YYYY HH:mm",llll:"ddd D MMM YYYY HH:mm"},calendar:{sameDay:"[Idag] LT",nextDay:"[Imorgon] LT",lastDay:"[Igår] LT",nextWeek:"[På] dddd LT",lastWeek:"[I] dddd[s] LT",sameElse:"L"},relativeTime:{future:"om %s",past:"för %s sedan",s:"några sekunder",ss:"%d sekunder",m:"en minut",mm:"%d minuter",h:"en timme",hh:"%d timmar",d:"en dag",dd:"%d dagar",M:"en månad",MM:"%d månader",y:"ett år",yy:"%d år"},dayOfMonthOrdinalParse:/\d{1,2}(\:e|\:a)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?":e":1===t||2===t?":a":":e")},week:{dow:1,doy:4}})}(a(421))},7655:function(e,t,a){!function(e){"use strict";e.defineLocale("sw",{months:"Januari_Februari_Machi_Aprili_Mei_Juni_Julai_Agosti_Septemba_Oktoba_Novemba_Desemba".split("_"),monthsShort:"Jan_Feb_Mac_Apr_Mei_Jun_Jul_Ago_Sep_Okt_Nov_Des".split("_"),weekdays:"Jumapili_Jumatatu_Jumanne_Jumatano_Alhamisi_Ijumaa_Jumamosi".split("_"),weekdaysShort:"Jpl_Jtat_Jnne_Jtan_Alh_Ijm_Jmos".split("_"),weekdaysMin:"J2_J3_J4_J5_Al_Ij_J1".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"hh:mm A",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[leo saa] LT",nextDay:"[kesho saa] LT",nextWeek:"[wiki ijayo] dddd [saat] LT",lastDay:"[jana] LT",lastWeek:"[wiki iliyopita] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s baadaye",past:"tokea %s",s:"hivi punde",ss:"sekunde %d",m:"dakika moja",mm:"dakika %d",h:"saa limoja",hh:"masaa %d",d:"siku moja",dd:"siku %d",M:"mwezi mmoja",MM:"miezi %d",y:"mwaka mmoja",yy:"miaka %d"},week:{dow:1,doy:7}})}(a(421))},1553:function(e,t,a){!function(e){"use strict";var t={1:"௧",2:"௨",3:"௩",4:"௪",5:"௫",6:"௬",7:"௭",8:"௮",9:"௯",0:"௦"},a={"௧":"1","௨":"2","௩":"3","௪":"4","௫":"5","௬":"6","௭":"7","௮":"8","௯":"9","௦":"0"};e.defineLocale("ta",{months:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),monthsShort:"ஜனவரி_பிப்ரவரி_மார்ச்_ஏப்ரல்_மே_ஜூன்_ஜூலை_ஆகஸ்ட்_செப்டெம்பர்_அக்டோபர்_நவம்பர்_டிசம்பர்".split("_"),weekdays:"ஞாயிற்றுக்கிழமை_திங்கட்கிழமை_செவ்வாய்கிழமை_புதன்கிழமை_வியாழக்கிழமை_வெள்ளிக்கிழமை_சனிக்கிழமை".split("_"),weekdaysShort:"ஞாயிறு_திங்கள்_செவ்வாய்_புதன்_வியாழன்_வெள்ளி_சனி".split("_"),weekdaysMin:"ஞா_தி_செ_பு_வி_வெ_ச".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, HH:mm",LLLL:"dddd, D MMMM YYYY, HH:mm"},calendar:{sameDay:"[இன்று] LT",nextDay:"[நாளை] LT",nextWeek:"dddd, LT",lastDay:"[நேற்று] LT",lastWeek:"[கடந்த வாரம்] dddd, LT",sameElse:"L"},relativeTime:{future:"%s இல்",past:"%s முன்",s:"ஒரு சில விநாடிகள்",ss:"%d விநாடிகள்",m:"ஒரு நிமிடம்",mm:"%d நிமிடங்கள்",h:"ஒரு மணி நேரம்",hh:"%d மணி நேரம்",d:"ஒரு நாள்",dd:"%d நாட்கள்",M:"ஒரு மாதம்",MM:"%d மாதங்கள்",y:"ஒரு வருடம்",yy:"%d ஆண்டுகள்"},dayOfMonthOrdinalParse:/\d{1,2}வது/,ordinal:function(e){return e+"வது"},preparse:function(e){return e.replace(/[௧௨௩௪௫௬௭௮௯௦]/g,(function(e){return a[e]}))},postformat:function(e){return e.replace(/\d/g,(function(e){return t[e]}))},meridiemParse:/யாமம்|வைகறை|காலை|நண்பகல்|எற்பாடு|மாலை/,meridiem:function(e,t,a){return e<2?" யாமம்":e<6?" வைகறை":e<10?" காலை":e<14?" நண்பகல்":e<18?" எற்பாடு":e<22?" மாலை":" யாமம்"},meridiemHour:function(e,t){return 12===e&&(e=0),"யாமம்"===t?e<2?e:e+12:"வைகறை"===t||"காலை"===t||"நண்பகல்"===t&&e>=10?e:e+12},week:{dow:0,doy:6}})}(a(421))},5967:function(e,t,a){!function(e){"use strict";e.defineLocale("te",{months:"జనవరి_ఫిబ్రవరి_మార్చి_ఏప్రిల్_మే_జూన్_జులై_ఆగస్టు_సెప్టెంబర్_అక్టోబర్_నవంబర్_డిసెంబర్".split("_"),monthsShort:"జన._ఫిబ్ర._మార్చి_ఏప్రి._మే_జూన్_జులై_ఆగ._సెప్._అక్టో._నవ._డిసె.".split("_"),monthsParseExact:!0,weekdays:"ఆదివారం_సోమవారం_మంగళవారం_బుధవారం_గురువారం_శుక్రవారం_శనివారం".split("_"),weekdaysShort:"ఆది_సోమ_మంగళ_బుధ_గురు_శుక్ర_శని".split("_"),weekdaysMin:"ఆ_సో_మం_బు_గు_శు_శ".split("_"),longDateFormat:{LT:"A h:mm",LTS:"A h:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY, A h:mm",LLLL:"dddd, D MMMM YYYY, A h:mm"},calendar:{sameDay:"[నేడు] LT",nextDay:"[రేపు] LT",nextWeek:"dddd, LT",lastDay:"[నిన్న] LT",lastWeek:"[గత] dddd, LT",sameElse:"L"},relativeTime:{future:"%s లో",past:"%s క్రితం",s:"కొన్ని క్షణాలు",ss:"%d సెకన్లు",m:"ఒక నిమిషం",mm:"%d నిమిషాలు",h:"ఒక గంట",hh:"%d గంటలు",d:"ఒక రోజు",dd:"%d రోజులు",M:"ఒక నెల",MM:"%d నెలలు",y:"ఒక సంవత్సరం",yy:"%d సంవత్సరాలు"},dayOfMonthOrdinalParse:/\d{1,2}వ/,ordinal:"%dవ",meridiemParse:/రాత్రి|ఉదయం|మధ్యాహ్నం|సాయంత్రం/,meridiemHour:function(e,t){return 12===e&&(e=0),"రాత్రి"===t?e<4?e:e+12:"ఉదయం"===t?e:"మధ్యాహ్నం"===t?e>=10?e:e+12:"సాయంత్రం"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"రాత్రి":e<10?"ఉదయం":e<17?"మధ్యాహ్నం":e<20?"సాయంత్రం":"రాత్రి"},week:{dow:0,doy:6}})}(a(421))},9236:function(e,t,a){!function(e){"use strict";e.defineLocale("tet",{months:"Janeiru_Fevereiru_Marsu_Abril_Maiu_Juñu_Jullu_Agustu_Setembru_Outubru_Novembru_Dezembru".split("_"),monthsShort:"Jan_Fev_Mar_Abr_Mai_Jun_Jul_Ago_Set_Out_Nov_Dez".split("_"),weekdays:"Domingu_Segunda_Tersa_Kuarta_Kinta_Sesta_Sabadu".split("_"),weekdaysShort:"Dom_Seg_Ters_Kua_Kint_Sest_Sab".split("_"),weekdaysMin:"Do_Seg_Te_Ku_Ki_Ses_Sa".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Ohin iha] LT",nextDay:"[Aban iha] LT",nextWeek:"dddd [iha] LT",lastDay:"[Horiseik iha] LT",lastWeek:"dddd [semana kotuk] [iha] LT",sameElse:"L"},relativeTime:{future:"iha %s",past:"%s liuba",s:"segundu balun",ss:"segundu %d",m:"minutu ida",mm:"minutu %d",h:"oras ida",hh:"oras %d",d:"loron ida",dd:"loron %d",M:"fulan ida",MM:"fulan %d",y:"tinan ida",yy:"tinan %d"},dayOfMonthOrdinalParse:/\d{1,2}(st|nd|rd|th)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(a(421))},2091:function(e,t,a){!function(e){"use strict";var t={0:"-ум",1:"-ум",2:"-юм",3:"-юм",4:"-ум",5:"-ум",6:"-ум",7:"-ум",8:"-ум",9:"-ум",10:"-ум",12:"-ум",13:"-ум",20:"-ум",30:"-юм",40:"-ум",50:"-ум",60:"-ум",70:"-ум",80:"-ум",90:"-ум",100:"-ум"};e.defineLocale("tg",{months:{format:"январи_феврали_марти_апрели_майи_июни_июли_августи_сентябри_октябри_ноябри_декабри".split("_"),standalone:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_")},monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"якшанбе_душанбе_сешанбе_чоршанбе_панҷшанбе_ҷумъа_шанбе".split("_"),weekdaysShort:"яшб_дшб_сшб_чшб_пшб_ҷум_шнб".split("_"),weekdaysMin:"яш_дш_сш_чш_пш_ҷм_шб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[Имрӯз соати] LT",nextDay:"[Фардо соати] LT",lastDay:"[Дирӯз соати] LT",nextWeek:"dddd[и] [ҳафтаи оянда соати] LT",lastWeek:"dddd[и] [ҳафтаи гузашта соати] LT",sameElse:"L"},relativeTime:{future:"баъди %s",past:"%s пеш",s:"якчанд сония",m:"як дақиқа",mm:"%d дақиқа",h:"як соат",hh:"%d соат",d:"як рӯз",dd:"%d рӯз",M:"як моҳ",MM:"%d моҳ",y:"як сол",yy:"%d сол"},meridiemParse:/шаб|субҳ|рӯз|бегоҳ/,meridiemHour:function(e,t){return 12===e&&(e=0),"шаб"===t?e<4?e:e+12:"субҳ"===t?e:"рӯз"===t?e>=11?e:e+12:"бегоҳ"===t?e+12:void 0},meridiem:function(e,t,a){return e<4?"шаб":e<11?"субҳ":e<16?"рӯз":e<19?"бегоҳ":"шаб"},dayOfMonthOrdinalParse:/\d{1,2}-(ум|юм)/,ordinal:function(e){return e+(t[e]||t[e%10]||t[e>=100?100:null])},week:{dow:1,doy:7}})}(a(421))},4141:function(e,t,a){!function(e){"use strict";e.defineLocale("th",{months:"มกราคม_กุมภาพันธ์_มีนาคม_เมษายน_พฤษภาคม_มิถุนายน_กรกฎาคม_สิงหาคม_กันยายน_ตุลาคม_พฤศจิกายน_ธันวาคม".split("_"),monthsShort:"ม.ค._ก.พ._มี.ค._เม.ย._พ.ค._มิ.ย._ก.ค._ส.ค._ก.ย._ต.ค._พ.ย._ธ.ค.".split("_"),monthsParseExact:!0,weekdays:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัสบดี_ศุกร์_เสาร์".split("_"),weekdaysShort:"อาทิตย์_จันทร์_อังคาร_พุธ_พฤหัส_ศุกร์_เสาร์".split("_"),weekdaysMin:"อา._จ._อ._พ._พฤ._ศ._ส.".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"H:mm",LTS:"H:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY เวลา H:mm",LLLL:"วันddddที่ D MMMM YYYY เวลา H:mm"},meridiemParse:/ก่อนเที่ยง|หลังเที่ยง/,isPM:function(e){return"หลังเที่ยง"===e},meridiem:function(e,t,a){return e<12?"ก่อนเที่ยง":"หลังเที่ยง"},calendar:{sameDay:"[วันนี้ เวลา] LT",nextDay:"[พรุ่งนี้ เวลา] LT",nextWeek:"dddd[หน้า เวลา] LT",lastDay:"[เมื่อวานนี้ เวลา] LT",lastWeek:"[วัน]dddd[ที่แล้ว เวลา] LT",sameElse:"L"},relativeTime:{future:"อีก %s",past:"%sที่แล้ว",s:"ไม่กี่วินาที",ss:"%d วินาที",m:"1 นาที",mm:"%d นาที",h:"1 ชั่วโมง",hh:"%d ชั่วโมง",d:"1 วัน",dd:"%d วัน",w:"1 สัปดาห์",ww:"%d สัปดาห์",M:"1 เดือน",MM:"%d เดือน",y:"1 ปี",yy:"%d ปี"}})}(a(421))},4204:function(e,t,a){!function(e){"use strict";var t={1:"'inji",5:"'inji",8:"'inji",70:"'inji",80:"'inji",2:"'nji",7:"'nji",20:"'nji",50:"'nji",3:"'ünji",4:"'ünji",100:"'ünji",6:"'njy",9:"'unjy",10:"'unjy",30:"'unjy",60:"'ynjy",90:"'ynjy"};e.defineLocale("tk",{months:"Ýanwar_Fewral_Mart_Aprel_Maý_Iýun_Iýul_Awgust_Sentýabr_Oktýabr_Noýabr_Dekabr".split("_"),monthsShort:"Ýan_Few_Mar_Apr_Maý_Iýn_Iýl_Awg_Sen_Okt_Noý_Dek".split("_"),weekdays:"Ýekşenbe_Duşenbe_Sişenbe_Çarşenbe_Penşenbe_Anna_Şenbe".split("_"),weekdaysShort:"Ýek_Duş_Siş_Çar_Pen_Ann_Şen".split("_"),weekdaysMin:"Ýk_Dş_Sş_Çr_Pn_An_Şn".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün sagat] LT",nextDay:"[ertir sagat] LT",nextWeek:"[indiki] dddd [sagat] LT",lastDay:"[düýn] LT",lastWeek:"[geçen] dddd [sagat] LT",sameElse:"L"},relativeTime:{future:"%s soň",past:"%s öň",s:"birnäçe sekunt",m:"bir minut",mm:"%d minut",h:"bir sagat",hh:"%d sagat",d:"bir gün",dd:"%d gün",M:"bir aý",MM:"%d aý",y:"bir ýyl",yy:"%d ýyl"},ordinal:function(e,a){switch(a){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'unjy";var s=e%10;return e+(t[s]||t[e%100-s]||t[e>=100?100:null])}},week:{dow:1,doy:7}})}(a(421))},8361:function(e,t,a){!function(e){"use strict";e.defineLocale("tl-ph",{months:"Enero_Pebrero_Marso_Abril_Mayo_Hunyo_Hulyo_Agosto_Setyembre_Oktubre_Nobyembre_Disyembre".split("_"),monthsShort:"Ene_Peb_Mar_Abr_May_Hun_Hul_Ago_Set_Okt_Nob_Dis".split("_"),weekdays:"Linggo_Lunes_Martes_Miyerkules_Huwebes_Biyernes_Sabado".split("_"),weekdaysShort:"Lin_Lun_Mar_Miy_Huw_Biy_Sab".split("_"),weekdaysMin:"Li_Lu_Ma_Mi_Hu_Bi_Sab".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"MM/D/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY HH:mm",LLLL:"dddd, MMMM DD, YYYY HH:mm"},calendar:{sameDay:"LT [ngayong araw]",nextDay:"[Bukas ng] LT",nextWeek:"LT [sa susunod na] dddd",lastDay:"LT [kahapon]",lastWeek:"LT [noong nakaraang] dddd",sameElse:"L"},relativeTime:{future:"sa loob ng %s",past:"%s ang nakalipas",s:"ilang segundo",ss:"%d segundo",m:"isang minuto",mm:"%d minuto",h:"isang oras",hh:"%d oras",d:"isang araw",dd:"%d araw",M:"isang buwan",MM:"%d buwan",y:"isang taon",yy:"%d taon"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(a(421))},9565:function(e,t,a){!function(e){"use strict";var t="pagh_wa’_cha’_wej_loS_vagh_jav_Soch_chorgh_Hut".split("_");function a(e,a,s,n){var i=function(e){var a=Math.floor(e%1e3/100),s=Math.floor(e%100/10),n=e%10,i="";return a>0&&(i+=t[a]+"vatlh"),s>0&&(i+=(""!==i?" ":"")+t[s]+"maH"),n>0&&(i+=(""!==i?" ":"")+t[n]),""===i?"pagh":i}(e);switch(s){case"ss":return i+" lup";case"mm":return i+" tup";case"hh":return i+" rep";case"dd":return i+" jaj";case"MM":return i+" jar";case"yy":return i+" DIS"}}e.defineLocale("tlh",{months:"tera’ jar wa’_tera’ jar cha’_tera’ jar wej_tera’ jar loS_tera’ jar vagh_tera’ jar jav_tera’ jar Soch_tera’ jar chorgh_tera’ jar Hut_tera’ jar wa’maH_tera’ jar wa’maH wa’_tera’ jar wa’maH cha’".split("_"),monthsShort:"jar wa’_jar cha’_jar wej_jar loS_jar vagh_jar jav_jar Soch_jar chorgh_jar Hut_jar wa’maH_jar wa’maH wa’_jar wa’maH cha’".split("_"),monthsParseExact:!0,weekdays:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysShort:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),weekdaysMin:"lojmItjaj_DaSjaj_povjaj_ghItlhjaj_loghjaj_buqjaj_ghInjaj".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[DaHjaj] LT",nextDay:"[wa’leS] LT",nextWeek:"LLL",lastDay:"[wa’Hu’] LT",lastWeek:"LLL",sameElse:"L"},relativeTime:{future:function(e){var t=e;return-1!==e.indexOf("jaj")?t.slice(0,-3)+"leS":-1!==e.indexOf("jar")?t.slice(0,-3)+"waQ":-1!==e.indexOf("DIS")?t.slice(0,-3)+"nem":t+" pIq"},past:function(e){var t=e;return-1!==e.indexOf("jaj")?t.slice(0,-3)+"Hu’":-1!==e.indexOf("jar")?t.slice(0,-3)+"wen":-1!==e.indexOf("DIS")?t.slice(0,-3)+"ben":t+" ret"},s:"puS lup",ss:a,m:"wa’ tup",mm:a,h:"wa’ rep",hh:a,d:"wa’ jaj",dd:a,M:"wa’ jar",MM:a,y:"wa’ DIS",yy:a},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},6075:function(e,t,a){!function(e){"use strict";var t={1:"'inci",5:"'inci",8:"'inci",70:"'inci",80:"'inci",2:"'nci",7:"'nci",20:"'nci",50:"'nci",3:"'üncü",4:"'üncü",100:"'üncü",6:"'ncı",9:"'uncu",10:"'uncu",30:"'uncu",60:"'ıncı",90:"'ıncı"};e.defineLocale("tr",{months:"Ocak_Şubat_Mart_Nisan_Mayıs_Haziran_Temmuz_Ağustos_Eylül_Ekim_Kasım_Aralık".split("_"),monthsShort:"Oca_Şub_Mar_Nis_May_Haz_Tem_Ağu_Eyl_Eki_Kas_Ara".split("_"),weekdays:"Pazar_Pazartesi_Salı_Çarşamba_Perşembe_Cuma_Cumartesi".split("_"),weekdaysShort:"Paz_Pzt_Sal_Çar_Per_Cum_Cmt".split("_"),weekdaysMin:"Pz_Pt_Sa_Ça_Pe_Cu_Ct".split("_"),meridiem:function(e,t,a){return e<12?a?"öö":"ÖÖ":a?"ös":"ÖS"},meridiemParse:/öö|ÖÖ|ös|ÖS/,isPM:function(e){return"ös"===e||"ÖS"===e},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[bugün saat] LT",nextDay:"[yarın saat] LT",nextWeek:"[gelecek] dddd [saat] LT",lastDay:"[dün] LT",lastWeek:"[geçen] dddd [saat] LT",sameElse:"L"},relativeTime:{future:"%s sonra",past:"%s önce",s:"birkaç saniye",ss:"%d saniye",m:"bir dakika",mm:"%d dakika",h:"bir saat",hh:"%d saat",d:"bir gün",dd:"%d gün",w:"bir hafta",ww:"%d hafta",M:"bir ay",MM:"%d ay",y:"bir yıl",yy:"%d yıl"},ordinal:function(e,a){switch(a){case"d":case"D":case"Do":case"DD":return e;default:if(0===e)return e+"'ıncı";var s=e%10;return e+(t[s]||t[e%100-s]||t[e>=100?100:null])}},week:{dow:1,doy:7}})}(a(421))},1637:function(e,t,a){!function(e){"use strict";function t(e,t,a,s){var n={s:["viensas secunds","'iensas secunds"],ss:[e+" secunds",e+" secunds"],m:["'n míut","'iens míut"],mm:[e+" míuts",e+" míuts"],h:["'n þora","'iensa þora"],hh:[e+" þoras",e+" þoras"],d:["'n ziua","'iensa ziua"],dd:[e+" ziuas",e+" ziuas"],M:["'n mes","'iens mes"],MM:[e+" mesen",e+" mesen"],y:["'n ar","'iens ar"],yy:[e+" ars",e+" ars"]};return s||t?n[a][0]:n[a][1]}e.defineLocale("tzl",{months:"Januar_Fevraglh_Març_Avrïu_Mai_Gün_Julia_Guscht_Setemvar_Listopäts_Noemvar_Zecemvar".split("_"),monthsShort:"Jan_Fev_Mar_Avr_Mai_Gün_Jul_Gus_Set_Lis_Noe_Zec".split("_"),weekdays:"Súladi_Lúneçi_Maitzi_Márcuri_Xhúadi_Viénerçi_Sáturi".split("_"),weekdaysShort:"Súl_Lún_Mai_Már_Xhú_Vié_Sát".split("_"),weekdaysMin:"Sú_Lú_Ma_Má_Xh_Vi_Sá".split("_"),longDateFormat:{LT:"HH.mm",LTS:"HH.mm.ss",L:"DD.MM.YYYY",LL:"D. MMMM [dallas] YYYY",LLL:"D. MMMM [dallas] YYYY HH.mm",LLLL:"dddd, [li] D. MMMM [dallas] YYYY HH.mm"},meridiemParse:/d\'o|d\'a/i,isPM:function(e){return"d'o"===e.toLowerCase()},meridiem:function(e,t,a){return e>11?a?"d'o":"D'O":a?"d'a":"D'A"},calendar:{sameDay:"[oxhi à] LT",nextDay:"[demà à] LT",nextWeek:"dddd [à] LT",lastDay:"[ieiri à] LT",lastWeek:"[sür el] dddd [lasteu à] LT",sameElse:"L"},relativeTime:{future:"osprei %s",past:"ja%s",s:t,ss:t,m:t,mm:t,h:t,hh:t,d:t,dd:t,M:t,MM:t,y:t,yy:t},dayOfMonthOrdinalParse:/\d{1,2}\./,ordinal:"%d.",week:{dow:1,doy:4}})}(a(421))},4943:function(e,t,a){!function(e){"use strict";e.defineLocale("tzm-latn",{months:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),monthsShort:"innayr_brˤayrˤ_marˤsˤ_ibrir_mayyw_ywnyw_ywlywz_ɣwšt_šwtanbir_ktˤwbrˤ_nwwanbir_dwjnbir".split("_"),weekdays:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysShort:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),weekdaysMin:"asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[asdkh g] LT",nextDay:"[aska g] LT",nextWeek:"dddd [g] LT",lastDay:"[assant g] LT",lastWeek:"dddd [g] LT",sameElse:"L"},relativeTime:{future:"dadkh s yan %s",past:"yan %s",s:"imik",ss:"%d imik",m:"minuḍ",mm:"%d minuḍ",h:"saɛa",hh:"%d tassaɛin",d:"ass",dd:"%d ossan",M:"ayowr",MM:"%d iyyirn",y:"asgas",yy:"%d isgasn"},week:{dow:6,doy:12}})}(a(421))},8231:function(e,t,a){!function(e){"use strict";e.defineLocale("tzm",{months:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),monthsShort:"ⵉⵏⵏⴰⵢⵔ_ⴱⵕⴰⵢⵕ_ⵎⴰⵕⵚ_ⵉⴱⵔⵉⵔ_ⵎⴰⵢⵢⵓ_ⵢⵓⵏⵢⵓ_ⵢⵓⵍⵢⵓⵣ_ⵖⵓⵛⵜ_ⵛⵓⵜⴰⵏⴱⵉⵔ_ⴽⵟⵓⴱⵕ_ⵏⵓⵡⴰⵏⴱⵉⵔ_ⴷⵓⵊⵏⴱⵉⵔ".split("_"),weekdays:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysShort:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),weekdaysMin:"ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd D MMMM YYYY HH:mm"},calendar:{sameDay:"[ⴰⵙⴷⵅ ⴴ] LT",nextDay:"[ⴰⵙⴽⴰ ⴴ] LT",nextWeek:"dddd [ⴴ] LT",lastDay:"[ⴰⵚⴰⵏⵜ ⴴ] LT",lastWeek:"dddd [ⴴ] LT",sameElse:"L"},relativeTime:{future:"ⴷⴰⴷⵅ ⵙ ⵢⴰⵏ %s",past:"ⵢⴰⵏ %s",s:"ⵉⵎⵉⴽ",ss:"%d ⵉⵎⵉⴽ",m:"ⵎⵉⵏⵓⴺ",mm:"%d ⵎⵉⵏⵓⴺ",h:"ⵙⴰⵄⴰ",hh:"%d ⵜⴰⵙⵙⴰⵄⵉⵏ",d:"ⴰⵙⵙ",dd:"%d oⵙⵙⴰⵏ",M:"ⴰⵢoⵓⵔ",MM:"%d ⵉⵢⵢⵉⵔⵏ",y:"ⴰⵙⴳⴰⵙ",yy:"%d ⵉⵙⴳⴰⵙⵏ"},week:{dow:6,doy:12}})}(a(421))},7822:function(e,t,a){!function(e){"use strict";e.defineLocale("ug-cn",{months:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),monthsShort:"يانۋار_فېۋرال_مارت_ئاپرېل_ماي_ئىيۇن_ئىيۇل_ئاۋغۇست_سېنتەبىر_ئۆكتەبىر_نويابىر_دېكابىر".split("_"),weekdays:"يەكشەنبە_دۈشەنبە_سەيشەنبە_چارشەنبە_پەيشەنبە_جۈمە_شەنبە".split("_"),weekdaysShort:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),weekdaysMin:"يە_دۈ_سە_چا_پە_جۈ_شە".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY-MM-DD",LL:"YYYY-يىلىM-ئاينىڭD-كۈنى",LLL:"YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm",LLLL:"dddd، YYYY-يىلىM-ئاينىڭD-كۈنى، HH:mm"},meridiemParse:/يېرىم كېچە|سەھەر|چۈشتىن بۇرۇن|چۈش|چۈشتىن كېيىن|كەچ/,meridiemHour:function(e,t){return 12===e&&(e=0),"يېرىم كېچە"===t||"سەھەر"===t||"چۈشتىن بۇرۇن"===t?e:"چۈشتىن كېيىن"===t||"كەچ"===t?e+12:e>=11?e:e+12},meridiem:function(e,t,a){var s=100*e+t;return s<600?"يېرىم كېچە":s<900?"سەھەر":s<1130?"چۈشتىن بۇرۇن":s<1230?"چۈش":s<1800?"چۈشتىن كېيىن":"كەچ"},calendar:{sameDay:"[بۈگۈن سائەت] LT",nextDay:"[ئەتە سائەت] LT",nextWeek:"[كېلەركى] dddd [سائەت] LT",lastDay:"[تۆنۈگۈن] LT",lastWeek:"[ئالدىنقى] dddd [سائەت] LT",sameElse:"L"},relativeTime:{future:"%s كېيىن",past:"%s بۇرۇن",s:"نەچچە سېكونت",ss:"%d سېكونت",m:"بىر مىنۇت",mm:"%d مىنۇت",h:"بىر سائەت",hh:"%d سائەت",d:"بىر كۈن",dd:"%d كۈن",M:"بىر ئاي",MM:"%d ئاي",y:"بىر يىل",yy:"%d يىل"},dayOfMonthOrdinalParse:/\d{1,2}(-كۈنى|-ئاي|-ھەپتە)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"-كۈنى";case"w":case"W":return e+"-ھەپتە";default:return e}},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:7}})}(a(421))},7263:function(e,t,a){!function(e){"use strict";function t(e,t,a){return"m"===a?t?"хвилина":"хвилину":"h"===a?t?"година":"годину":e+" "+(s=+e,n={ss:t?"секунда_секунди_секунд":"секунду_секунди_секунд",mm:t?"хвилина_хвилини_хвилин":"хвилину_хвилини_хвилин",hh:t?"година_години_годин":"годину_години_годин",dd:"день_дні_днів",MM:"місяць_місяці_місяців",yy:"рік_роки_років"}[a].split("_"),s%10==1&&s%100!=11?n[0]:s%10>=2&&s%10<=4&&(s%100<10||s%100>=20)?n[1]:n[2]);var s,n}function a(e){return function(){return e+"о"+(11===this.hours()?"б":"")+"] LT"}}e.defineLocale("uk",{months:{format:"січня_лютого_березня_квітня_травня_червня_липня_серпня_вересня_жовтня_листопада_грудня".split("_"),standalone:"січень_лютий_березень_квітень_травень_червень_липень_серпень_вересень_жовтень_листопад_грудень".split("_")},monthsShort:"січ_лют_бер_квіт_трав_черв_лип_серп_вер_жовт_лист_груд".split("_"),weekdays:function(e,t){var a={nominative:"неділя_понеділок_вівторок_середа_четвер_п’ятниця_субота".split("_"),accusative:"неділю_понеділок_вівторок_середу_четвер_п’ятницю_суботу".split("_"),genitive:"неділі_понеділка_вівторка_середи_четверга_п’ятниці_суботи".split("_")};return!0===e?a.nominative.slice(1,7).concat(a.nominative.slice(0,1)):e?a[/(\[[ВвУу]\]) ?dddd/.test(t)?"accusative":/\[?(?:минулої|наступної)? ?\] ?dddd/.test(t)?"genitive":"nominative"][e.day()]:a.nominative},weekdaysShort:"нд_пн_вт_ср_чт_пт_сб".split("_"),weekdaysMin:"нд_пн_вт_ср_чт_пт_сб".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD.MM.YYYY",LL:"D MMMM YYYY р.",LLL:"D MMMM YYYY р., HH:mm",LLLL:"dddd, D MMMM YYYY р., HH:mm"},calendar:{sameDay:a("[Сьогодні "),nextDay:a("[Завтра "),lastDay:a("[Вчора "),nextWeek:a("[У] dddd ["),lastWeek:function(){switch(this.day()){case 0:case 3:case 5:case 6:return a("[Минулої] dddd [").call(this);case 1:case 2:case 4:return a("[Минулого] dddd [").call(this)}},sameElse:"L"},relativeTime:{future:"за %s",past:"%s тому",s:"декілька секунд",ss:t,m:t,mm:t,h:"годину",hh:t,d:"день",dd:t,M:"місяць",MM:t,y:"рік",yy:t},meridiemParse:/ночі|ранку|дня|вечора/,isPM:function(e){return/^(дня|вечора)$/.test(e)},meridiem:function(e,t,a){return e<4?"ночі":e<12?"ранку":e<17?"дня":"вечора"},dayOfMonthOrdinalParse:/\d{1,2}-(й|го)/,ordinal:function(e,t){switch(t){case"M":case"d":case"DDD":case"w":case"W":return e+"-й";case"D":return e+"-го";default:return e}},week:{dow:1,doy:7}})}(a(421))},1769:function(e,t,a){!function(e){"use strict";var t=["جنوری","فروری","مارچ","اپریل","مئی","جون","جولائی","اگست","ستمبر","اکتوبر","نومبر","دسمبر"],a=["اتوار","پیر","منگل","بدھ","جمعرات","جمعہ","ہفتہ"];e.defineLocale("ur",{months:t,monthsShort:t,weekdays:a,weekdaysShort:a,weekdaysMin:a,longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd، D MMMM YYYY HH:mm"},meridiemParse:/صبح|شام/,isPM:function(e){return"شام"===e},meridiem:function(e,t,a){return e<12?"صبح":"شام"},calendar:{sameDay:"[آج بوقت] LT",nextDay:"[کل بوقت] LT",nextWeek:"dddd [بوقت] LT",lastDay:"[گذشتہ روز بوقت] LT",lastWeek:"[گذشتہ] dddd [بوقت] LT",sameElse:"L"},relativeTime:{future:"%s بعد",past:"%s قبل",s:"چند سیکنڈ",ss:"%d سیکنڈ",m:"ایک منٹ",mm:"%d منٹ",h:"ایک گھنٹہ",hh:"%d گھنٹے",d:"ایک دن",dd:"%d دن",M:"ایک ماہ",MM:"%d ماہ",y:"ایک سال",yy:"%d سال"},preparse:function(e){return e.replace(/،/g,",")},postformat:function(e){return e.replace(/,/g,"،")},week:{dow:1,doy:4}})}(a(421))},4725:function(e,t,a){!function(e){"use strict";e.defineLocale("uz-latn",{months:"Yanvar_Fevral_Mart_Aprel_May_Iyun_Iyul_Avgust_Sentabr_Oktabr_Noyabr_Dekabr".split("_"),monthsShort:"Yan_Fev_Mar_Apr_May_Iyun_Iyul_Avg_Sen_Okt_Noy_Dek".split("_"),weekdays:"Yakshanba_Dushanba_Seshanba_Chorshanba_Payshanba_Juma_Shanba".split("_"),weekdaysShort:"Yak_Dush_Sesh_Chor_Pay_Jum_Shan".split("_"),weekdaysMin:"Ya_Du_Se_Cho_Pa_Ju_Sha".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Bugun soat] LT [da]",nextDay:"[Ertaga] LT [da]",nextWeek:"dddd [kuni soat] LT [da]",lastDay:"[Kecha soat] LT [da]",lastWeek:"[O'tgan] dddd [kuni soat] LT [da]",sameElse:"L"},relativeTime:{future:"Yaqin %s ichida",past:"Bir necha %s oldin",s:"soniya",ss:"%d soniya",m:"bir daqiqa",mm:"%d daqiqa",h:"bir soat",hh:"%d soat",d:"bir kun",dd:"%d kun",M:"bir oy",MM:"%d oy",y:"bir yil",yy:"%d yil"},week:{dow:1,doy:7}})}(a(421))},9736:function(e,t,a){!function(e){"use strict";e.defineLocale("uz",{months:"январ_феврал_март_апрел_май_июн_июл_август_сентябр_октябр_ноябр_декабр".split("_"),monthsShort:"янв_фев_мар_апр_май_июн_июл_авг_сен_окт_ноя_дек".split("_"),weekdays:"Якшанба_Душанба_Сешанба_Чоршанба_Пайшанба_Жума_Шанба".split("_"),weekdaysShort:"Якш_Душ_Сеш_Чор_Пай_Жум_Шан".split("_"),weekdaysMin:"Як_Ду_Се_Чо_Па_Жу_Ша".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"D MMMM YYYY, dddd HH:mm"},calendar:{sameDay:"[Бугун соат] LT [да]",nextDay:"[Эртага] LT [да]",nextWeek:"dddd [куни соат] LT [да]",lastDay:"[Кеча соат] LT [да]",lastWeek:"[Утган] dddd [куни соат] LT [да]",sameElse:"L"},relativeTime:{future:"Якин %s ичида",past:"Бир неча %s олдин",s:"фурсат",ss:"%d фурсат",m:"бир дакика",mm:"%d дакика",h:"бир соат",hh:"%d соат",d:"бир кун",dd:"%d кун",M:"бир ой",MM:"%d ой",y:"бир йил",yy:"%d йил"},week:{dow:1,doy:7}})}(a(421))},9562:function(e,t,a){!function(e){"use strict";e.defineLocale("vi",{months:"tháng 1_tháng 2_tháng 3_tháng 4_tháng 5_tháng 6_tháng 7_tháng 8_tháng 9_tháng 10_tháng 11_tháng 12".split("_"),monthsShort:"Thg 01_Thg 02_Thg 03_Thg 04_Thg 05_Thg 06_Thg 07_Thg 08_Thg 09_Thg 10_Thg 11_Thg 12".split("_"),monthsParseExact:!0,weekdays:"chủ nhật_thứ hai_thứ ba_thứ tư_thứ năm_thứ sáu_thứ bảy".split("_"),weekdaysShort:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysMin:"CN_T2_T3_T4_T5_T6_T7".split("_"),weekdaysParseExact:!0,meridiemParse:/sa|ch/i,isPM:function(e){return/^ch$/i.test(e)},meridiem:function(e,t,a){return e<12?a?"sa":"SA":a?"ch":"CH"},longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"D MMMM [năm] YYYY",LLL:"D MMMM [năm] YYYY HH:mm",LLLL:"dddd, D MMMM [năm] YYYY HH:mm",l:"DD/M/YYYY",ll:"D MMM YYYY",lll:"D MMM YYYY HH:mm",llll:"ddd, D MMM YYYY HH:mm"},calendar:{sameDay:"[Hôm nay lúc] LT",nextDay:"[Ngày mai lúc] LT",nextWeek:"dddd [tuần tới lúc] LT",lastDay:"[Hôm qua lúc] LT",lastWeek:"dddd [tuần trước lúc] LT",sameElse:"L"},relativeTime:{future:"%s tới",past:"%s trước",s:"vài giây",ss:"%d giây",m:"một phút",mm:"%d phút",h:"một giờ",hh:"%d giờ",d:"một ngày",dd:"%d ngày",w:"một tuần",ww:"%d tuần",M:"một tháng",MM:"%d tháng",y:"một năm",yy:"%d năm"},dayOfMonthOrdinalParse:/\d{1,2}/,ordinal:function(e){return e},week:{dow:1,doy:4}})}(a(421))},7219:function(e,t,a){!function(e){"use strict";e.defineLocale("x-pseudo",{months:"J~áñúá~rý_F~ébrú~árý_~Márc~h_Áp~ríl_~Máý_~Júñé~_Júl~ý_Áú~gúst~_Sép~témb~ér_Ó~ctób~ér_Ñ~óvém~bér_~Décé~mbér".split("_"),monthsShort:"J~áñ_~Féb_~Már_~Ápr_~Máý_~Júñ_~Júl_~Áúg_~Sép_~Óct_~Ñóv_~Déc".split("_"),monthsParseExact:!0,weekdays:"S~úñdá~ý_Mó~ñdáý~_Túé~sdáý~_Wéd~ñésd~áý_T~húrs~dáý_~Fríd~áý_S~átúr~dáý".split("_"),weekdaysShort:"S~úñ_~Móñ_~Túé_~Wéd_~Thú_~Frí_~Sát".split("_"),weekdaysMin:"S~ú_Mó~_Tú_~Wé_T~h_Fr~_Sá".split("_"),weekdaysParseExact:!0,longDateFormat:{LT:"HH:mm",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY HH:mm",LLLL:"dddd, D MMMM YYYY HH:mm"},calendar:{sameDay:"[T~ódá~ý át] LT",nextDay:"[T~ómó~rró~w át] LT",nextWeek:"dddd [át] LT",lastDay:"[Ý~ést~érdá~ý át] LT",lastWeek:"[L~ást] dddd [át] LT",sameElse:"L"},relativeTime:{future:"í~ñ %s",past:"%s á~gó",s:"á ~féw ~sécó~ñds",ss:"%d s~écóñ~ds",m:"á ~míñ~úté",mm:"%d m~íñú~tés",h:"á~ñ hó~úr",hh:"%d h~óúrs",d:"á ~dáý",dd:"%d d~áýs",M:"á ~móñ~th",MM:"%d m~óñt~hs",y:"á ~ýéár",yy:"%d ý~éárs"},dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1==~~(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")},week:{dow:1,doy:4}})}(a(421))},6195:function(e,t,a){!function(e){"use strict";e.defineLocale("yo",{months:"Sẹ́rẹ́_Èrèlè_Ẹrẹ̀nà_Ìgbé_Èbibi_Òkùdu_Agẹmo_Ògún_Owewe_Ọ̀wàrà_Bélú_Ọ̀pẹ̀̀".split("_"),monthsShort:"Sẹ́r_Èrl_Ẹrn_Ìgb_Èbi_Òkù_Agẹ_Ògú_Owe_Ọ̀wà_Bél_Ọ̀pẹ̀̀".split("_"),weekdays:"Àìkú_Ajé_Ìsẹ́gun_Ọjọ́rú_Ọjọ́bọ_Ẹtì_Àbámẹ́ta".split("_"),weekdaysShort:"Àìk_Ajé_Ìsẹ́_Ọjr_Ọjb_Ẹtì_Àbá".split("_"),weekdaysMin:"Àì_Aj_Ìs_Ọr_Ọb_Ẹt_Àb".split("_"),longDateFormat:{LT:"h:mm A",LTS:"h:mm:ss A",L:"DD/MM/YYYY",LL:"D MMMM YYYY",LLL:"D MMMM YYYY h:mm A",LLLL:"dddd, D MMMM YYYY h:mm A"},calendar:{sameDay:"[Ònì ni] LT",nextDay:"[Ọ̀la ni] LT",nextWeek:"dddd [Ọsẹ̀ tón'bọ] [ni] LT",lastDay:"[Àna ni] LT",lastWeek:"dddd [Ọsẹ̀ tólọ́] [ni] LT",sameElse:"L"},relativeTime:{future:"ní %s",past:"%s kọjá",s:"ìsẹjú aayá die",ss:"aayá %d",m:"ìsẹjú kan",mm:"ìsẹjú %d",h:"wákati kan",hh:"wákati %d",d:"ọjọ́ kan",dd:"ọjọ́ %d",M:"osù kan",MM:"osù %d",y:"ọdún kan",yy:"ọdún %d"},dayOfMonthOrdinalParse:/ọjọ́\s\d{1,2}/,ordinal:"ọjọ́ %d",week:{dow:1,doy:4}})}(a(421))},7289:function(e,t,a){!function(e){"use strict";e.defineLocale("zh-cn",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"周日_周一_周二_周三_周四_周五_周六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日Ah点mm分",LLLL:"YYYY年M月D日ddddAh点mm分",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return 12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t?e:"下午"===t||"晚上"===t?e+12:e>=11?e:e+12},meridiem:function(e,t,a){var s=100*e+t;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:function(e){return e.week()!==this.week()?"[下]dddLT":"[本]dddLT"},lastDay:"[昨天]LT",lastWeek:function(e){return this.week()!==e.week()?"[上]dddLT":"[本]dddLT"},sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|周)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"周";default:return e}},relativeTime:{future:"%s后",past:"%s前",s:"几秒",ss:"%d 秒",m:"1 分钟",mm:"%d 分钟",h:"1 小时",hh:"%d 小时",d:"1 天",dd:"%d 天",w:"1 周",ww:"%d 周",M:"1 个月",MM:"%d 个月",y:"1 年",yy:"%d 年"},week:{dow:1,doy:4}})}(a(421))},1589:function(e,t,a){!function(e){"use strict";e.defineLocale("zh-hk",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return 12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t?e:"中午"===t?e>=11?e:e+12:"下午"===t||"晚上"===t?e+12:void 0},meridiem:function(e,t,a){var s=100*e+t;return s<600?"凌晨":s<900?"早上":s<1200?"上午":1200===s?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天]LT",nextDay:"[明天]LT",nextWeek:"[下]ddddLT",lastDay:"[昨天]LT",lastWeek:"[上]ddddLT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(a(421))},9708:function(e,t,a){!function(e){"use strict";e.defineLocale("zh-mo",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"DD/MM/YYYY",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"D/M/YYYY",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return 12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t?e:"中午"===t?e>=11?e:e+12:"下午"===t||"晚上"===t?e+12:void 0},meridiem:function(e,t,a){var s=100*e+t;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s內",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(a(421))},3384:function(e,t,a){!function(e){"use strict";e.defineLocale("zh-tw",{months:"一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月".split("_"),monthsShort:"1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月".split("_"),weekdays:"星期日_星期一_星期二_星期三_星期四_星期五_星期六".split("_"),weekdaysShort:"週日_週一_週二_週三_週四_週五_週六".split("_"),weekdaysMin:"日_一_二_三_四_五_六".split("_"),longDateFormat:{LT:"HH:mm",LTS:"HH:mm:ss",L:"YYYY/MM/DD",LL:"YYYY年M月D日",LLL:"YYYY年M月D日 HH:mm",LLLL:"YYYY年M月D日dddd HH:mm",l:"YYYY/M/D",ll:"YYYY年M月D日",lll:"YYYY年M月D日 HH:mm",llll:"YYYY年M月D日dddd HH:mm"},meridiemParse:/凌晨|早上|上午|中午|下午|晚上/,meridiemHour:function(e,t){return 12===e&&(e=0),"凌晨"===t||"早上"===t||"上午"===t?e:"中午"===t?e>=11?e:e+12:"下午"===t||"晚上"===t?e+12:void 0},meridiem:function(e,t,a){var s=100*e+t;return s<600?"凌晨":s<900?"早上":s<1130?"上午":s<1230?"中午":s<1800?"下午":"晚上"},calendar:{sameDay:"[今天] LT",nextDay:"[明天] LT",nextWeek:"[下]dddd LT",lastDay:"[昨天] LT",lastWeek:"[上]dddd LT",sameElse:"L"},dayOfMonthOrdinalParse:/\d{1,2}(日|月|週)/,ordinal:function(e,t){switch(t){case"d":case"D":case"DDD":return e+"日";case"M":return e+"月";case"w":case"W":return e+"週";default:return e}},relativeTime:{future:"%s後",past:"%s前",s:"幾秒",ss:"%d 秒",m:"1 分鐘",mm:"%d 分鐘",h:"1 小時",hh:"%d 小時",d:"1 天",dd:"%d 天",M:"1 個月",MM:"%d 個月",y:"1 年",yy:"%d 年"}})}(a(421))},421:function(e,t,a){(e=a.nmd(e)).exports=function(){"use strict";var t,s;function n(){return t.apply(null,arguments)}function i(e){return e instanceof Array||"[object Array]"===Object.prototype.toString.call(e)}function r(e){return null!=e&&"[object Object]"===Object.prototype.toString.call(e)}function o(e,t){return Object.prototype.hasOwnProperty.call(e,t)}function d(e){if(Object.getOwnPropertyNames)return 0===Object.getOwnPropertyNames(e).length;var t;for(t in e)if(o(e,t))return!1;return!0}function l(e){return void 0===e}function u(e){return"number"==typeof e||"[object Number]"===Object.prototype.toString.call(e)}function c(e){return e instanceof Date||"[object Date]"===Object.prototype.toString.call(e)}function _(e,t){var a,s=[],n=e.length;for(a=0;a>>0;for(t=0;t0)for(a=0;a=0?a?"+":"":"-")+Math.pow(10,Math.max(0,n)).toString().substr(1)+s}var P=/(\[[^\[]*\])|(\\)?([Hh]mm(ss)?|Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Qo?|N{1,5}|YYYYYY|YYYYY|YYYY|YY|y{2,4}|yo?|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|kk?|mm?|ss?|S{1,9}|x|X|zz?|ZZ?|.)/g,j=/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,O={},A={};function V(e,t,a,s){var n=s;"string"==typeof s&&(n=function(){return this[s]()}),e&&(A[e]=n),t&&(A[t[0]]=function(){return H(n.apply(this,arguments),t[1],t[2])}),a&&(A[a]=function(){return this.localeData().ordinal(n.apply(this,arguments),e)})}function E(e,t){return e.isValid()?(t=F(t,e.localeData()),O[t]=O[t]||function(e){var t,a,s,n=e.match(P);for(t=0,a=n.length;t=0&&j.test(e);)e=e.replace(j,s),j.lastIndex=0,a-=1;return e}var $={};function I(e,t){var a=e.toLowerCase();$[a]=$[a+"s"]=$[t]=e}function W(e){return"string"==typeof e?$[e]||$[e.toLowerCase()]:void 0}function N(e){var t,a,s={};for(a in e)o(e,a)&&(t=W(a))&&(s[t]=e[a]);return s}var R={};function U(e,t){R[e]=t}function z(e){return e%4==0&&e%100!=0||e%400==0}function B(e){return e<0?Math.ceil(e)||0:Math.floor(e)}function q(e){var t=+e,a=0;return 0!==t&&isFinite(t)&&(a=B(t)),a}function Z(e,t){return function(a){return null!=a?(G(this,e,a),n.updateOffset(this,t),this):J(this,e)}}function J(e,t){return e.isValid()?e._d["get"+(e._isUTC?"UTC":"")+t]():NaN}function G(e,t,a){e.isValid()&&!isNaN(a)&&("FullYear"===t&&z(e.year())&&1===e.month()&&29===e.date()?(a=q(a),e._d["set"+(e._isUTC?"UTC":"")+t](a,e.month(),He(a,e.month()))):e._d["set"+(e._isUTC?"UTC":"")+t](a))}var K,X=/\d/,Q=/\d\d/,ee=/\d{3}/,te=/\d{4}/,ae=/[+-]?\d{6}/,se=/\d\d?/,ne=/\d\d\d\d?/,ie=/\d\d\d\d\d\d?/,re=/\d{1,3}/,oe=/\d{1,4}/,de=/[+-]?\d{1,6}/,le=/\d+/,ue=/[+-]?\d+/,ce=/Z|[+-]\d\d:?\d\d/gi,_e=/Z|[+-]\d\d(?::?\d\d)?/gi,me=/[0-9]{0,256}['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFF07\uFF10-\uFFEF]{1,256}|[\u0600-\u06FF\/]{1,256}(\s*?[\u0600-\u06FF]{1,256}){1,2}/i;function he(e,t,a){K[e]=T(t)?t:function(e,s){return e&&a?a:t}}function pe(e,t){return o(K,e)?K[e](t._strict,t._locale):new RegExp(fe(e.replace("\\","").replace(/\\(\[)|\\(\])|\[([^\]\[]*)\]|\\(.)/g,(function(e,t,a,s,n){return t||a||s||n}))))}function fe(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}K={};var ve={};function ge(e,t){var a,s,n=t;for("string"==typeof e&&(e=[e]),u(t)&&(n=function(e,a){a[t]=q(e)}),s=e.length,a=0;a68?1900:2e3)};var Ne=Z("FullYear",!0);function Re(e,t,a,s,n,i,r){var o;return e<100&&e>=0?(o=new Date(e+400,t,a,s,n,i,r),isFinite(o.getFullYear())&&o.setFullYear(e)):o=new Date(e,t,a,s,n,i,r),o}function Ue(e){var t,a;return e<100&&e>=0?((a=Array.prototype.slice.call(arguments))[0]=e+400,t=new Date(Date.UTC.apply(null,a)),isFinite(t.getUTCFullYear())&&t.setUTCFullYear(e)):t=new Date(Date.UTC.apply(null,arguments)),t}function ze(e,t,a){var s=7+t-a;return-(7+Ue(e,0,s).getUTCDay()-t)%7+s-1}function Be(e,t,a,s,n){var i,r,o=1+7*(t-1)+(7+a-s)%7+ze(e,s,n);return o<=0?r=We(i=e-1)+o:o>We(e)?(i=e+1,r=o-We(e)):(i=e,r=o),{year:i,dayOfYear:r}}function qe(e,t,a){var s,n,i=ze(e.year(),t,a),r=Math.floor((e.dayOfYear()-i-1)/7)+1;return r<1?s=r+Ze(n=e.year()-1,t,a):r>Ze(e.year(),t,a)?(s=r-Ze(e.year(),t,a),n=e.year()+1):(n=e.year(),s=r),{week:s,year:n}}function Ze(e,t,a){var s=ze(e,t,a),n=ze(e+1,t,a);return(We(e)-s+n)/7}V("w",["ww",2],"wo","week"),V("W",["WW",2],"Wo","isoWeek"),I("week","w"),I("isoWeek","W"),U("week",5),U("isoWeek",5),he("w",se),he("ww",se,Q),he("W",se),he("WW",se,Q),ye(["w","ww","W","WW"],(function(e,t,a,s){t[s.substr(0,1)]=q(e)}));function Je(e,t){return e.slice(t,7).concat(e.slice(0,t))}V("d",0,"do","day"),V("dd",0,0,(function(e){return this.localeData().weekdaysMin(this,e)})),V("ddd",0,0,(function(e){return this.localeData().weekdaysShort(this,e)})),V("dddd",0,0,(function(e){return this.localeData().weekdays(this,e)})),V("e",0,0,"weekday"),V("E",0,0,"isoWeekday"),I("day","d"),I("weekday","e"),I("isoWeekday","E"),U("day",11),U("weekday",11),U("isoWeekday",11),he("d",se),he("e",se),he("E",se),he("dd",(function(e,t){return t.weekdaysMinRegex(e)})),he("ddd",(function(e,t){return t.weekdaysShortRegex(e)})),he("dddd",(function(e,t){return t.weekdaysRegex(e)})),ye(["dd","ddd","dddd"],(function(e,t,a,s){var n=a._locale.weekdaysParse(e,s,a._strict);null!=n?t.d=n:p(a).invalidWeekday=e})),ye(["d","e","E"],(function(e,t,a,s){t[s]=q(e)}));var Ge="Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),Ke="Sun_Mon_Tue_Wed_Thu_Fri_Sat".split("_"),Xe="Su_Mo_Tu_We_Th_Fr_Sa".split("_"),Qe=me,et=me,tt=me;function at(e,t,a){var s,n,i,r=e.toLocaleLowerCase();if(!this._weekdaysParse)for(this._weekdaysParse=[],this._shortWeekdaysParse=[],this._minWeekdaysParse=[],s=0;s<7;++s)i=h([2e3,1]).day(s),this._minWeekdaysParse[s]=this.weekdaysMin(i,"").toLocaleLowerCase(),this._shortWeekdaysParse[s]=this.weekdaysShort(i,"").toLocaleLowerCase(),this._weekdaysParse[s]=this.weekdays(i,"").toLocaleLowerCase();return a?"dddd"===t?-1!==(n=Me.call(this._weekdaysParse,r))?n:null:"ddd"===t?-1!==(n=Me.call(this._shortWeekdaysParse,r))?n:null:-1!==(n=Me.call(this._minWeekdaysParse,r))?n:null:"dddd"===t?-1!==(n=Me.call(this._weekdaysParse,r))||-1!==(n=Me.call(this._shortWeekdaysParse,r))||-1!==(n=Me.call(this._minWeekdaysParse,r))?n:null:"ddd"===t?-1!==(n=Me.call(this._shortWeekdaysParse,r))||-1!==(n=Me.call(this._weekdaysParse,r))||-1!==(n=Me.call(this._minWeekdaysParse,r))?n:null:-1!==(n=Me.call(this._minWeekdaysParse,r))||-1!==(n=Me.call(this._weekdaysParse,r))||-1!==(n=Me.call(this._shortWeekdaysParse,r))?n:null}function st(){function e(e,t){return t.length-e.length}var t,a,s,n,i,r=[],o=[],d=[],l=[];for(t=0;t<7;t++)a=h([2e3,1]).day(t),s=fe(this.weekdaysMin(a,"")),n=fe(this.weekdaysShort(a,"")),i=fe(this.weekdays(a,"")),r.push(s),o.push(n),d.push(i),l.push(s),l.push(n),l.push(i);r.sort(e),o.sort(e),d.sort(e),l.sort(e),this._weekdaysRegex=new RegExp("^("+l.join("|")+")","i"),this._weekdaysShortRegex=this._weekdaysRegex,this._weekdaysMinRegex=this._weekdaysRegex,this._weekdaysStrictRegex=new RegExp("^("+d.join("|")+")","i"),this._weekdaysShortStrictRegex=new RegExp("^("+o.join("|")+")","i"),this._weekdaysMinStrictRegex=new RegExp("^("+r.join("|")+")","i")}function nt(){return this.hours()%12||12}function it(e,t){V(e,0,0,(function(){return this.localeData().meridiem(this.hours(),this.minutes(),t)}))}function rt(e,t){return t._meridiemParse}V("H",["HH",2],0,"hour"),V("h",["hh",2],0,nt),V("k",["kk",2],0,(function(){return this.hours()||24})),V("hmm",0,0,(function(){return""+nt.apply(this)+H(this.minutes(),2)})),V("hmmss",0,0,(function(){return""+nt.apply(this)+H(this.minutes(),2)+H(this.seconds(),2)})),V("Hmm",0,0,(function(){return""+this.hours()+H(this.minutes(),2)})),V("Hmmss",0,0,(function(){return""+this.hours()+H(this.minutes(),2)+H(this.seconds(),2)})),it("a",!0),it("A",!1),I("hour","h"),U("hour",13),he("a",rt),he("A",rt),he("H",se),he("h",se),he("k",se),he("HH",se,Q),he("hh",se,Q),he("kk",se,Q),he("hmm",ne),he("hmmss",ie),he("Hmm",ne),he("Hmmss",ie),ge(["H","HH"],De),ge(["k","kk"],(function(e,t,a){var s=q(e);t[De]=24===s?0:s})),ge(["a","A"],(function(e,t,a){a._isPm=a._locale.isPM(e),a._meridiem=e})),ge(["h","hh"],(function(e,t,a){t[De]=q(e),p(a).bigHour=!0})),ge("hmm",(function(e,t,a){var s=e.length-2;t[De]=q(e.substr(0,s)),t[Ye]=q(e.substr(s)),p(a).bigHour=!0})),ge("hmmss",(function(e,t,a){var s=e.length-4,n=e.length-2;t[De]=q(e.substr(0,s)),t[Ye]=q(e.substr(s,2)),t[Ce]=q(e.substr(n)),p(a).bigHour=!0})),ge("Hmm",(function(e,t,a){var s=e.length-2;t[De]=q(e.substr(0,s)),t[Ye]=q(e.substr(s))})),ge("Hmmss",(function(e,t,a){var s=e.length-4,n=e.length-2;t[De]=q(e.substr(0,s)),t[Ye]=q(e.substr(s,2)),t[Ce]=q(e.substr(n))}));var ot=Z("Hours",!0);var dt,lt={calendar:{sameDay:"[Today at] LT",nextDay:"[Tomorrow at] LT",nextWeek:"dddd [at] LT",lastDay:"[Yesterday at] LT",lastWeek:"[Last] dddd [at] LT",sameElse:"L"},longDateFormat:{LTS:"h:mm:ss A",LT:"h:mm A",L:"MM/DD/YYYY",LL:"MMMM D, YYYY",LLL:"MMMM D, YYYY h:mm A",LLLL:"dddd, MMMM D, YYYY h:mm A"},invalidDate:"Invalid date",ordinal:"%d",dayOfMonthOrdinalParse:/\d{1,2}/,relativeTime:{future:"in %s",past:"%s ago",s:"a few seconds",ss:"%d seconds",m:"a minute",mm:"%d minutes",h:"an hour",hh:"%d hours",d:"a day",dd:"%d days",w:"a week",ww:"%d weeks",M:"a month",MM:"%d months",y:"a year",yy:"%d years"},months:Pe,monthsShort:je,week:{dow:0,doy:6},weekdays:Ge,weekdaysMin:Xe,weekdaysShort:Ke,meridiemParse:/[ap]\.?m?\.?/i},ut={},ct={};function _t(e,t){var a,s=Math.min(e.length,t.length);for(a=0;a0;){if(s=ht(n.slice(0,t).join("-")))return s;if(a&&a.length>=t&&_t(n,a)>=t-1)break;t--}i++}return dt}(e)}function gt(e){var t,a=e._a;return a&&-2===p(e).overflow&&(t=a[Le]<0||a[Le]>11?Le:a[we]<1||a[we]>He(a[be],a[Le])?we:a[De]<0||a[De]>24||24===a[De]&&(0!==a[Ye]||0!==a[Ce]||0!==a[Te])?De:a[Ye]<0||a[Ye]>59?Ye:a[Ce]<0||a[Ce]>59?Ce:a[Te]<0||a[Te]>999?Te:-1,p(e)._overflowDayOfYear&&(twe)&&(t=we),p(e)._overflowWeeks&&-1===t&&(t=Se),p(e)._overflowWeekday&&-1===t&&(t=xe),p(e).overflow=t),e}var yt=/^\s*((?:[+-]\d{6}|\d{4})-(?:\d\d-\d\d|W\d\d-\d|W\d\d|\d\d\d|\d\d))(?:(T| )(\d\d(?::\d\d(?::\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,kt=/^\s*((?:[+-]\d{6}|\d{4})(?:\d\d\d\d|W\d\d\d|W\d\d|\d\d\d|\d\d|))(?:(T| )(\d\d(?:\d\d(?:\d\d(?:[.,]\d+)?)?)?)([+-]\d\d(?::?\d\d)?|\s*Z)?)?$/,Mt=/Z|[+-]\d\d(?::?\d\d)?/,bt=[["YYYYYY-MM-DD",/[+-]\d{6}-\d\d-\d\d/],["YYYY-MM-DD",/\d{4}-\d\d-\d\d/],["GGGG-[W]WW-E",/\d{4}-W\d\d-\d/],["GGGG-[W]WW",/\d{4}-W\d\d/,!1],["YYYY-DDD",/\d{4}-\d{3}/],["YYYY-MM",/\d{4}-\d\d/,!1],["YYYYYYMMDD",/[+-]\d{10}/],["YYYYMMDD",/\d{8}/],["GGGG[W]WWE",/\d{4}W\d{3}/],["GGGG[W]WW",/\d{4}W\d{2}/,!1],["YYYYDDD",/\d{7}/],["YYYYMM",/\d{6}/,!1],["YYYY",/\d{4}/,!1]],Lt=[["HH:mm:ss.SSSS",/\d\d:\d\d:\d\d\.\d+/],["HH:mm:ss,SSSS",/\d\d:\d\d:\d\d,\d+/],["HH:mm:ss",/\d\d:\d\d:\d\d/],["HH:mm",/\d\d:\d\d/],["HHmmss.SSSS",/\d\d\d\d\d\d\.\d+/],["HHmmss,SSSS",/\d\d\d\d\d\d,\d+/],["HHmmss",/\d\d\d\d\d\d/],["HHmm",/\d\d\d\d/],["HH",/\d\d/]],wt=/^\/?Date\((-?\d+)/i,Dt=/^(?:(Mon|Tue|Wed|Thu|Fri|Sat|Sun),?\s)?(\d{1,2})\s(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)\s(\d{2,4})\s(\d\d):(\d\d)(?::(\d\d))?\s(?:(UT|GMT|[ECMP][SD]T)|([Zz])|([+-]\d{4}))$/,Yt={UT:0,GMT:0,EDT:-240,EST:-300,CDT:-300,CST:-360,MDT:-360,MST:-420,PDT:-420,PST:-480};function Ct(e){var t,a,s,n,i,r,o=e._i,d=yt.exec(o)||kt.exec(o),l=bt.length,u=Lt.length;if(d){for(p(e).iso=!0,t=0,a=l;t7)&&(d=!0)):(i=e._locale._week.dow,r=e._locale._week.doy,l=qe(At(),i,r),a=xt(t.gg,e._a[be],l.year),s=xt(t.w,l.week),null!=t.d?((n=t.d)<0||n>6)&&(d=!0):null!=t.e?(n=t.e+i,(t.e<0||t.e>6)&&(d=!0)):n=i),s<1||s>Ze(a,i,r)?p(e)._overflowWeeks=!0:null!=d?p(e)._overflowWeekday=!0:(o=Be(a,s,n,i,r),e._a[be]=o.year,e._dayOfYear=o.dayOfYear)}(e),null!=e._dayOfYear&&(r=xt(e._a[be],s[be]),(e._dayOfYear>We(r)||0===e._dayOfYear)&&(p(e)._overflowDayOfYear=!0),a=Ue(r,0,e._dayOfYear),e._a[Le]=a.getUTCMonth(),e._a[we]=a.getUTCDate()),t=0;t<3&&null==e._a[t];++t)e._a[t]=o[t]=s[t];for(;t<7;t++)e._a[t]=o[t]=null==e._a[t]?2===t?1:0:e._a[t];24===e._a[De]&&0===e._a[Ye]&&0===e._a[Ce]&&0===e._a[Te]&&(e._nextDay=!0,e._a[De]=0),e._d=(e._useUTC?Ue:Re).apply(null,o),i=e._useUTC?e._d.getUTCDay():e._d.getDay(),null!=e._tzm&&e._d.setUTCMinutes(e._d.getUTCMinutes()-e._tzm),e._nextDay&&(e._a[De]=24),e._w&&void 0!==e._w.d&&e._w.d!==i&&(p(e).weekdayMismatch=!0)}}function Pt(e){if(e._f!==n.ISO_8601)if(e._f!==n.RFC_2822){e._a=[],p(e).empty=!0;var t,a,s,i,r,o,d,l=""+e._i,u=l.length,c=0;for(d=(s=F(e._f,e._locale).match(P)||[]).length,t=0;t0&&p(e).unusedInput.push(r),l=l.slice(l.indexOf(a)+a.length),c+=a.length),A[i]?(a?p(e).empty=!1:p(e).unusedTokens.push(i),ke(i,a,e)):e._strict&&!a&&p(e).unusedTokens.push(i);p(e).charsLeftOver=u-c,l.length>0&&p(e).unusedInput.push(l),e._a[De]<=12&&!0===p(e).bigHour&&e._a[De]>0&&(p(e).bigHour=void 0),p(e).parsedDateParts=e._a.slice(0),p(e).meridiem=e._meridiem,e._a[De]=function(e,t,a){var s;return null==a?t:null!=e.meridiemHour?e.meridiemHour(t,a):null!=e.isPM?((s=e.isPM(a))&&t<12&&(t+=12),s||12!==t||(t=0),t):t}(e._locale,e._a[De],e._meridiem),null!==(o=p(e).era)&&(e._a[be]=e._locale.erasConvertYear(o,e._a[be])),Ht(e),gt(e)}else St(e);else Ct(e)}function jt(e){var t=e._i,a=e._f;return e._locale=e._locale||vt(e._l),null===t||void 0===a&&""===t?v({nullInput:!0}):("string"==typeof t&&(e._i=t=e._locale.preparse(t)),b(t)?new M(gt(t)):(c(t)?e._d=t:i(a)?function(e){var t,a,s,n,i,r,o=!1,d=e._f.length;if(0===d)return p(e).invalidFormat=!0,void(e._d=new Date(NaN));for(n=0;nthis?this:e:v()}));function Ft(e,t){var a,s;if(1===t.length&&i(t[0])&&(t=t[0]),!t.length)return At();for(a=t[0],s=1;s=0?new Date(e+400,t,a)-ma:new Date(e,t,a).valueOf()}function fa(e,t,a){return e<100&&e>=0?Date.UTC(e+400,t,a)-ma:Date.UTC(e,t,a)}function va(e,t){return t.erasAbbrRegex(e)}function ga(){var e,t,a=[],s=[],n=[],i=[],r=this.eras();for(e=0,t=r.length;e(i=Ze(e,s,n))&&(t=i),Ma.call(this,e,t,a,s,n))}function Ma(e,t,a,s,n){var i=Be(e,t,a,s,n),r=Ue(i.year,0,i.dayOfYear);return this.year(r.getUTCFullYear()),this.month(r.getUTCMonth()),this.date(r.getUTCDate()),this}V("N",0,0,"eraAbbr"),V("NN",0,0,"eraAbbr"),V("NNN",0,0,"eraAbbr"),V("NNNN",0,0,"eraName"),V("NNNNN",0,0,"eraNarrow"),V("y",["y",1],"yo","eraYear"),V("y",["yy",2],0,"eraYear"),V("y",["yyy",3],0,"eraYear"),V("y",["yyyy",4],0,"eraYear"),he("N",va),he("NN",va),he("NNN",va),he("NNNN",(function(e,t){return t.erasNameRegex(e)})),he("NNNNN",(function(e,t){return t.erasNarrowRegex(e)})),ge(["N","NN","NNN","NNNN","NNNNN"],(function(e,t,a,s){var n=a._locale.erasParse(e,s,a._strict);n?p(a).era=n:p(a).invalidEra=e})),he("y",le),he("yy",le),he("yyy",le),he("yyyy",le),he("yo",(function(e,t){return t._eraYearOrdinalRegex||le})),ge(["y","yy","yyy","yyyy"],be),ge(["yo"],(function(e,t,a,s){var n;a._locale._eraYearOrdinalRegex&&(n=e.match(a._locale._eraYearOrdinalRegex)),a._locale.eraYearOrdinalParse?t[be]=a._locale.eraYearOrdinalParse(e,n):t[be]=parseInt(e,10)})),V(0,["gg",2],0,(function(){return this.weekYear()%100})),V(0,["GG",2],0,(function(){return this.isoWeekYear()%100})),ya("gggg","weekYear"),ya("ggggg","weekYear"),ya("GGGG","isoWeekYear"),ya("GGGGG","isoWeekYear"),I("weekYear","gg"),I("isoWeekYear","GG"),U("weekYear",1),U("isoWeekYear",1),he("G",ue),he("g",ue),he("GG",se,Q),he("gg",se,Q),he("GGGG",oe,te),he("gggg",oe,te),he("GGGGG",de,ae),he("ggggg",de,ae),ye(["gggg","ggggg","GGGG","GGGGG"],(function(e,t,a,s){t[s.substr(0,2)]=q(e)})),ye(["gg","GG"],(function(e,t,a,s){t[s]=n.parseTwoDigitYear(e)})),V("Q",0,"Qo","quarter"),I("quarter","Q"),U("quarter",7),he("Q",X),ge("Q",(function(e,t){t[Le]=3*(q(e)-1)})),V("D",["DD",2],"Do","date"),I("date","D"),U("date",9),he("D",se),he("DD",se,Q),he("Do",(function(e,t){return e?t._dayOfMonthOrdinalParse||t._ordinalParse:t._dayOfMonthOrdinalParseLenient})),ge(["D","DD"],we),ge("Do",(function(e,t){t[we]=q(e.match(se)[0])}));var ba=Z("Date",!0);V("DDD",["DDDD",3],"DDDo","dayOfYear"),I("dayOfYear","DDD"),U("dayOfYear",4),he("DDD",re),he("DDDD",ee),ge(["DDD","DDDD"],(function(e,t,a){a._dayOfYear=q(e)})),V("m",["mm",2],0,"minute"),I("minute","m"),U("minute",14),he("m",se),he("mm",se,Q),ge(["m","mm"],Ye);var La=Z("Minutes",!1);V("s",["ss",2],0,"second"),I("second","s"),U("second",15),he("s",se),he("ss",se,Q),ge(["s","ss"],Ce);var wa,Da,Ya=Z("Seconds",!1);for(V("S",0,0,(function(){return~~(this.millisecond()/100)})),V(0,["SS",2],0,(function(){return~~(this.millisecond()/10)})),V(0,["SSS",3],0,"millisecond"),V(0,["SSSS",4],0,(function(){return 10*this.millisecond()})),V(0,["SSSSS",5],0,(function(){return 100*this.millisecond()})),V(0,["SSSSSS",6],0,(function(){return 1e3*this.millisecond()})),V(0,["SSSSSSS",7],0,(function(){return 1e4*this.millisecond()})),V(0,["SSSSSSSS",8],0,(function(){return 1e5*this.millisecond()})),V(0,["SSSSSSSSS",9],0,(function(){return 1e6*this.millisecond()})),I("millisecond","ms"),U("millisecond",16),he("S",re,X),he("SS",re,Q),he("SSS",re,ee),wa="SSSS";wa.length<=9;wa+="S")he(wa,le);function Ca(e,t){t[Te]=q(1e3*("0."+e))}for(wa="S";wa.length<=9;wa+="S")ge(wa,Ca);Da=Z("Milliseconds",!1),V("z",0,0,"zoneAbbr"),V("zz",0,0,"zoneName");var Ta=M.prototype;function Sa(e){return e}Ta.add=aa,Ta.calendar=function(e,t){1===arguments.length&&(arguments[0]?ia(arguments[0])?(e=arguments[0],t=void 0):function(e){var t,a=r(e)&&!d(e),s=!1,n=["sameDay","nextDay","lastDay","nextWeek","lastWeek","sameElse"];for(t=0;ta.valueOf():a.valueOf()9999?E(a,t?"YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYYYY-MM-DD[T]HH:mm:ss.SSSZ"):T(Date.prototype.toISOString)?t?this.toDate().toISOString():new Date(this.valueOf()+60*this.utcOffset()*1e3).toISOString().replace("Z",E(a,"Z")):E(a,t?"YYYY-MM-DD[T]HH:mm:ss.SSS[Z]":"YYYY-MM-DD[T]HH:mm:ss.SSSZ")},Ta.inspect=function(){if(!this.isValid())return"moment.invalid(/* "+this._i+" */)";var e,t,a,s="moment",n="";return this.isLocal()||(s=0===this.utcOffset()?"moment.utc":"moment.parseZone",n="Z"),e="["+s+'("]',t=0<=this.year()&&this.year()<=9999?"YYYY":"YYYYYY","-MM-DD[T]HH:mm:ss.SSS",a=n+'[")]',this.format(e+t+"-MM-DD[T]HH:mm:ss.SSS"+a)},"undefined"!=typeof Symbol&&null!=Symbol.for&&(Ta[Symbol.for("nodejs.util.inspect.custom")]=function(){return"Moment<"+this.format()+">"}),Ta.toJSON=function(){return this.isValid()?this.toISOString():null},Ta.toString=function(){return this.clone().locale("en").format("ddd MMM DD YYYY HH:mm:ss [GMT]ZZ")},Ta.unix=function(){return Math.floor(this.valueOf()/1e3)},Ta.valueOf=function(){return this._d.valueOf()-6e4*(this._offset||0)},Ta.creationData=function(){return{input:this._i,format:this._f,locale:this._locale,isUTC:this._isUTC,strict:this._strict}},Ta.eraName=function(){var e,t,a,s=this.localeData().eras();for(e=0,t=s.length;ethis.clone().month(0).utcOffset()||this.utcOffset()>this.clone().month(5).utcOffset()},Ta.isLocal=function(){return!!this.isValid()&&!this._isUTC},Ta.isUtcOffset=function(){return!!this.isValid()&&this._isUTC},Ta.isUtc=Zt,Ta.isUTC=Zt,Ta.zoneAbbr=function(){return this._isUTC?"UTC":""},Ta.zoneName=function(){return this._isUTC?"Coordinated Universal Time":""},Ta.dates=w("dates accessor is deprecated. Use date instead.",ba),Ta.months=w("months accessor is deprecated. Use month instead",$e),Ta.years=w("years accessor is deprecated. Use year instead",Ne),Ta.zone=w("moment().zone is deprecated, use moment().utcOffset instead. http://momentjs.com/guides/#/warnings/zone/",(function(e,t){return null!=e?("string"!=typeof e&&(e=-e),this.utcOffset(e,t),this):-this.utcOffset()})),Ta.isDSTShifted=w("isDSTShifted is deprecated. See http://momentjs.com/guides/#/warnings/dst-shifted/ for more information",(function(){if(!l(this._isDSTShifted))return this._isDSTShifted;var e,t={};return k(t,this),(t=jt(t))._a?(e=t._isUTC?h(t._a):At(t._a),this._isDSTShifted=this.isValid()&&function(e,t,a){var s,n=Math.min(e.length,t.length),i=Math.abs(e.length-t.length),r=0;for(s=0;s0):this._isDSTShifted=!1,this._isDSTShifted}));var xa=x.prototype;function Ha(e,t,a,s){var n=vt(),i=h().set(s,t);return n[a](i,e)}function Pa(e,t,a){if(u(e)&&(t=e,e=void 0),e=e||"",null!=t)return Ha(e,t,a,"month");var s,n=[];for(s=0;s<12;s++)n[s]=Ha(e,s,a,"month");return n}function ja(e,t,a,s){"boolean"==typeof e?(u(t)&&(a=t,t=void 0),t=t||""):(a=t=e,e=!1,u(t)&&(a=t,t=void 0),t=t||"");var n,i=vt(),r=e?i._week.dow:0,o=[];if(null!=a)return Ha(t,(a+r)%7,s,"day");for(n=0;n<7;n++)o[n]=Ha(t,(n+r)%7,s,"day");return o}xa.calendar=function(e,t,a){var s=this._calendar[e]||this._calendar.sameElse;return T(s)?s.call(t,a):s},xa.longDateFormat=function(e){var t=this._longDateFormat[e],a=this._longDateFormat[e.toUpperCase()];return t||!a?t:(this._longDateFormat[e]=a.match(P).map((function(e){return"MMMM"===e||"MM"===e||"DD"===e||"dddd"===e?e.slice(1):e})).join(""),this._longDateFormat[e])},xa.invalidDate=function(){return this._invalidDate},xa.ordinal=function(e){return this._ordinal.replace("%d",e)},xa.preparse=Sa,xa.postformat=Sa,xa.relativeTime=function(e,t,a,s){var n=this._relativeTime[a];return T(n)?n(e,t,a,s):n.replace(/%d/i,e)},xa.pastFuture=function(e,t){var a=this._relativeTime[e>0?"future":"past"];return T(a)?a(t):a.replace(/%s/i,t)},xa.set=function(e){var t,a;for(a in e)o(e,a)&&(T(t=e[a])?this[a]=t:this["_"+a]=t);this._config=e,this._dayOfMonthOrdinalParseLenient=new RegExp((this._dayOfMonthOrdinalParse.source||this._ordinalParse.source)+"|"+/\d{1,2}/.source)},xa.eras=function(e,t){var a,s,i,r=this._eras||vt("en")._eras;for(a=0,s=r.length;a=0)return d[s]},xa.erasConvertYear=function(e,t){var a=e.since<=e.until?1:-1;return void 0===t?n(e.since).year():n(e.since).year()+(t-e.offset)*a},xa.erasAbbrRegex=function(e){return o(this,"_erasAbbrRegex")||ga.call(this),e?this._erasAbbrRegex:this._erasRegex},xa.erasNameRegex=function(e){return o(this,"_erasNameRegex")||ga.call(this),e?this._erasNameRegex:this._erasRegex},xa.erasNarrowRegex=function(e){return o(this,"_erasNarrowRegex")||ga.call(this),e?this._erasNarrowRegex:this._erasRegex},xa.months=function(e,t){return e?i(this._months)?this._months[e.month()]:this._months[(this._months.isFormat||Oe).test(t)?"format":"standalone"][e.month()]:i(this._months)?this._months:this._months.standalone},xa.monthsShort=function(e,t){return e?i(this._monthsShort)?this._monthsShort[e.month()]:this._monthsShort[Oe.test(t)?"format":"standalone"][e.month()]:i(this._monthsShort)?this._monthsShort:this._monthsShort.standalone},xa.monthsParse=function(e,t,a){var s,n,i;if(this._monthsParseExact)return Ee.call(this,e,t,a);for(this._monthsParse||(this._monthsParse=[],this._longMonthsParse=[],this._shortMonthsParse=[]),s=0;s<12;s++){if(n=h([2e3,s]),a&&!this._longMonthsParse[s]&&(this._longMonthsParse[s]=new RegExp("^"+this.months(n,"").replace(".","")+"$","i"),this._shortMonthsParse[s]=new RegExp("^"+this.monthsShort(n,"").replace(".","")+"$","i")),a||this._monthsParse[s]||(i="^"+this.months(n,"")+"|^"+this.monthsShort(n,""),this._monthsParse[s]=new RegExp(i.replace(".",""),"i")),a&&"MMMM"===t&&this._longMonthsParse[s].test(e))return s;if(a&&"MMM"===t&&this._shortMonthsParse[s].test(e))return s;if(!a&&this._monthsParse[s].test(e))return s}},xa.monthsRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||Ie.call(this),e?this._monthsStrictRegex:this._monthsRegex):(o(this,"_monthsRegex")||(this._monthsRegex=Ve),this._monthsStrictRegex&&e?this._monthsStrictRegex:this._monthsRegex)},xa.monthsShortRegex=function(e){return this._monthsParseExact?(o(this,"_monthsRegex")||Ie.call(this),e?this._monthsShortStrictRegex:this._monthsShortRegex):(o(this,"_monthsShortRegex")||(this._monthsShortRegex=Ae),this._monthsShortStrictRegex&&e?this._monthsShortStrictRegex:this._monthsShortRegex)},xa.week=function(e){return qe(e,this._week.dow,this._week.doy).week},xa.firstDayOfYear=function(){return this._week.doy},xa.firstDayOfWeek=function(){return this._week.dow},xa.weekdays=function(e,t){var a=i(this._weekdays)?this._weekdays:this._weekdays[e&&!0!==e&&this._weekdays.isFormat.test(t)?"format":"standalone"];return!0===e?Je(a,this._week.dow):e?a[e.day()]:a},xa.weekdaysMin=function(e){return!0===e?Je(this._weekdaysMin,this._week.dow):e?this._weekdaysMin[e.day()]:this._weekdaysMin},xa.weekdaysShort=function(e){return!0===e?Je(this._weekdaysShort,this._week.dow):e?this._weekdaysShort[e.day()]:this._weekdaysShort},xa.weekdaysParse=function(e,t,a){var s,n,i;if(this._weekdaysParseExact)return at.call(this,e,t,a);for(this._weekdaysParse||(this._weekdaysParse=[],this._minWeekdaysParse=[],this._shortWeekdaysParse=[],this._fullWeekdaysParse=[]),s=0;s<7;s++){if(n=h([2e3,1]).day(s),a&&!this._fullWeekdaysParse[s]&&(this._fullWeekdaysParse[s]=new RegExp("^"+this.weekdays(n,"").replace(".","\\.?")+"$","i"),this._shortWeekdaysParse[s]=new RegExp("^"+this.weekdaysShort(n,"").replace(".","\\.?")+"$","i"),this._minWeekdaysParse[s]=new RegExp("^"+this.weekdaysMin(n,"").replace(".","\\.?")+"$","i")),this._weekdaysParse[s]||(i="^"+this.weekdays(n,"")+"|^"+this.weekdaysShort(n,"")+"|^"+this.weekdaysMin(n,""),this._weekdaysParse[s]=new RegExp(i.replace(".",""),"i")),a&&"dddd"===t&&this._fullWeekdaysParse[s].test(e))return s;if(a&&"ddd"===t&&this._shortWeekdaysParse[s].test(e))return s;if(a&&"dd"===t&&this._minWeekdaysParse[s].test(e))return s;if(!a&&this._weekdaysParse[s].test(e))return s}},xa.weekdaysRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||st.call(this),e?this._weekdaysStrictRegex:this._weekdaysRegex):(o(this,"_weekdaysRegex")||(this._weekdaysRegex=Qe),this._weekdaysStrictRegex&&e?this._weekdaysStrictRegex:this._weekdaysRegex)},xa.weekdaysShortRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||st.call(this),e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex):(o(this,"_weekdaysShortRegex")||(this._weekdaysShortRegex=et),this._weekdaysShortStrictRegex&&e?this._weekdaysShortStrictRegex:this._weekdaysShortRegex)},xa.weekdaysMinRegex=function(e){return this._weekdaysParseExact?(o(this,"_weekdaysRegex")||st.call(this),e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex):(o(this,"_weekdaysMinRegex")||(this._weekdaysMinRegex=tt),this._weekdaysMinStrictRegex&&e?this._weekdaysMinStrictRegex:this._weekdaysMinRegex)},xa.isPM=function(e){return"p"===(e+"").toLowerCase().charAt(0)},xa.meridiem=function(e,t,a){return e>11?a?"pm":"PM":a?"am":"AM"},pt("en",{eras:[{since:"0001-01-01",until:1/0,offset:1,name:"Anno Domini",narrow:"AD",abbr:"AD"},{since:"0000-12-31",until:-1/0,offset:1,name:"Before Christ",narrow:"BC",abbr:"BC"}],dayOfMonthOrdinalParse:/\d{1,2}(th|st|nd|rd)/,ordinal:function(e){var t=e%10;return e+(1===q(e%100/10)?"th":1===t?"st":2===t?"nd":3===t?"rd":"th")}}),n.lang=w("moment.lang is deprecated. Use moment.locale instead.",pt),n.langData=w("moment.langData is deprecated. Use moment.localeData instead.",vt);var Oa=Math.abs;function Aa(e,t,a,s){var n=Kt(t,a);return e._milliseconds+=s*n._milliseconds,e._days+=s*n._days,e._months+=s*n._months,e._bubble()}function Va(e){return e<0?Math.floor(e):Math.ceil(e)}function Ea(e){return 4800*e/146097}function Fa(e){return 146097*e/4800}function $a(e){return function(){return this.as(e)}}var Ia=$a("ms"),Wa=$a("s"),Na=$a("m"),Ra=$a("h"),Ua=$a("d"),za=$a("w"),Ba=$a("M"),qa=$a("Q"),Za=$a("y");function Ja(e){return function(){return this.isValid()?this._data[e]:NaN}}var Ga=Ja("milliseconds"),Ka=Ja("seconds"),Xa=Ja("minutes"),Qa=Ja("hours"),es=Ja("days"),ts=Ja("months"),as=Ja("years");var ss=Math.round,ns={ss:44,s:45,m:45,h:22,d:26,w:null,M:11};function is(e,t,a,s,n){return n.relativeTime(t||1,!!a,e,s)}var rs=Math.abs;function os(e){return(e>0)-(e<0)||+e}function ds(){if(!this.isValid())return this.localeData().invalidDate();var e,t,a,s,n,i,r,o,d=rs(this._milliseconds)/1e3,l=rs(this._days),u=rs(this._months),c=this.asSeconds();return c?(e=B(d/60),t=B(e/60),d%=60,e%=60,a=B(u/12),u%=12,s=d?d.toFixed(3).replace(/\.?0+$/,""):"",n=c<0?"-":"",i=os(this._months)!==os(c)?"-":"",r=os(this._days)!==os(c)?"-":"",o=os(this._milliseconds)!==os(c)?"-":"",n+"P"+(a?i+a+"Y":"")+(u?i+u+"M":"")+(l?r+l+"D":"")+(t||e||d?"T":"")+(t?o+t+"H":"")+(e?o+e+"M":"")+(d?o+s+"S":"")):"P0D"}var ls=It.prototype;return ls.isValid=function(){return this._isValid},ls.abs=function(){var e=this._data;return this._milliseconds=Oa(this._milliseconds),this._days=Oa(this._days),this._months=Oa(this._months),e.milliseconds=Oa(e.milliseconds),e.seconds=Oa(e.seconds),e.minutes=Oa(e.minutes),e.hours=Oa(e.hours),e.months=Oa(e.months),e.years=Oa(e.years),this},ls.add=function(e,t){return Aa(this,e,t,1)},ls.subtract=function(e,t){return Aa(this,e,t,-1)},ls.as=function(e){if(!this.isValid())return NaN;var t,a,s=this._milliseconds;if("month"===(e=W(e))||"quarter"===e||"year"===e)switch(t=this._days+s/864e5,a=this._months+Ea(t),e){case"month":return a;case"quarter":return a/3;case"year":return a/12}else switch(t=this._days+Math.round(Fa(this._months)),e){case"week":return t/7+s/6048e5;case"day":return t+s/864e5;case"hour":return 24*t+s/36e5;case"minute":return 1440*t+s/6e4;case"second":return 86400*t+s/1e3;case"millisecond":return Math.floor(864e5*t)+s;default:throw new Error("Unknown unit "+e)}},ls.asMilliseconds=Ia,ls.asSeconds=Wa,ls.asMinutes=Na,ls.asHours=Ra,ls.asDays=Ua,ls.asWeeks=za,ls.asMonths=Ba,ls.asQuarters=qa,ls.asYears=Za,ls.valueOf=function(){return this.isValid()?this._milliseconds+864e5*this._days+this._months%12*2592e6+31536e6*q(this._months/12):NaN},ls._bubble=function(){var e,t,a,s,n,i=this._milliseconds,r=this._days,o=this._months,d=this._data;return i>=0&&r>=0&&o>=0||i<=0&&r<=0&&o<=0||(i+=864e5*Va(Fa(o)+r),r=0,o=0),d.milliseconds=i%1e3,e=B(i/1e3),d.seconds=e%60,t=B(e/60),d.minutes=t%60,a=B(t/60),d.hours=a%24,r+=B(a/24),o+=n=B(Ea(r)),r-=Va(Fa(n)),s=B(o/12),o%=12,d.days=r,d.months=o,d.years=s,this},ls.clone=function(){return Kt(this)},ls.get=function(e){return e=W(e),this.isValid()?this[e+"s"]():NaN},ls.milliseconds=Ga,ls.seconds=Ka,ls.minutes=Xa,ls.hours=Qa,ls.days=es,ls.weeks=function(){return B(this.days()/7)},ls.months=ts,ls.years=as,ls.humanize=function(e,t){if(!this.isValid())return this.localeData().invalidDate();var a,s,n=!1,i=ns;return"object"==typeof e&&(t=e,e=!1),"boolean"==typeof e&&(n=e),"object"==typeof t&&(i=Object.assign({},ns,t),null!=t.s&&null==t.ss&&(i.ss=t.s-1)),s=function(e,t,a,s){var n=Kt(e).abs(),i=ss(n.as("s")),r=ss(n.as("m")),o=ss(n.as("h")),d=ss(n.as("d")),l=ss(n.as("M")),u=ss(n.as("w")),c=ss(n.as("y")),_=i<=a.ss&&["s",i]||i0,_[4]=s,is.apply(null,_)}(this,!n,i,a=this.localeData()),n&&(s=a.pastFuture(+this,s)),a.postformat(s)},ls.toISOString=ds,ls.toString=ds,ls.toJSON=ds,ls.locale=oa,ls.localeData=la,ls.toIsoString=w("toIsoString() is deprecated. Please use toISOString() instead (notice the capitals)",ds),ls.lang=da,V("X",0,0,"unix"),V("x",0,0,"valueOf"),he("x",ue),he("X",/[+-]?\d+(\.\d{1,3})?/),ge("X",(function(e,t,a){a._d=new Date(1e3*parseFloat(e))})),ge("x",(function(e,t,a){a._d=new Date(q(e))})),n.version="2.29.4",t=At,n.fn=Ta,n.min=function(){return Ft("isBefore",[].slice.call(arguments,0))},n.max=function(){return Ft("isAfter",[].slice.call(arguments,0))},n.now=function(){return Date.now?Date.now():+new Date},n.utc=h,n.unix=function(e){return At(1e3*e)},n.months=function(e,t){return Pa(e,t,"months")},n.isDate=c,n.locale=pt,n.invalid=v,n.duration=Kt,n.isMoment=b,n.weekdays=function(e,t,a){return ja(e,t,a,"weekdays")},n.parseZone=function(){return At.apply(null,arguments).parseZone()},n.localeData=vt,n.isDuration=Wt,n.monthsShort=function(e,t){return Pa(e,t,"monthsShort")},n.weekdaysMin=function(e,t,a){return ja(e,t,a,"weekdaysMin")},n.defineLocale=ft,n.updateLocale=function(e,t){if(null!=t){var a,s,n=lt;null!=ut[e]&&null!=ut[e].parentLocale?ut[e].set(S(ut[e]._config,t)):(null!=(s=ht(e))&&(n=s._config),t=S(n,t),null==s&&(t.abbr=e),(a=new x(t)).parentLocale=ut[e],ut[e]=a),pt(e)}else null!=ut[e]&&(null!=ut[e].parentLocale?(ut[e]=ut[e].parentLocale,e===pt()&&pt(e)):null!=ut[e]&&delete ut[e]);return ut[e]},n.locales=function(){return D(ut)},n.weekdaysShort=function(e,t,a){return ja(e,t,a,"weekdaysShort")},n.normalizeUnits=W,n.relativeTimeRounding=function(e){return void 0===e?ss:"function"==typeof e&&(ss=e,!0)},n.relativeTimeThreshold=function(e,t){return void 0!==ns[e]&&(void 0===t?ns[e]:(ns[e]=t,"s"===e&&(ns.ss=t-1),!0))},n.calendarFormat=function(e,t){var a=e.diff(t,"days",!0);return a<-6?"sameElse":a<-1?"lastWeek":a<0?"lastDay":a<1?"sameDay":a<2?"nextDay":a<7?"nextWeek":"sameElse"},n.prototype=Ta,n.HTML5_FMT={DATETIME_LOCAL:"YYYY-MM-DDTHH:mm",DATETIME_LOCAL_SECONDS:"YYYY-MM-DDTHH:mm:ss",DATETIME_LOCAL_MS:"YYYY-MM-DDTHH:mm:ss.SSS",DATE:"YYYY-MM-DD",TIME:"HH:mm",TIME_SECONDS:"HH:mm:ss",TIME_MS:"HH:mm:ss.SSS",WEEK:"GGGG-[W]WW",MONTH:"YYYY-MM"},n}()},3490:function(e,t){var a,s;a=function e(){"use strict";var t="undefined"!=typeof self?self:"undefined"!=typeof window?window:void 0!==t?t:{},a=!t.document&&!!t.postMessage,s=t.IS_PAPA_WORKER||!1,n={},i=0,r={parse:function(a,s){var o=(s=s||{}).dynamicTyping||!1;if(M(o)&&(s.dynamicTypingFunction=o,o={}),s.dynamicTyping=o,s.transform=!!M(s.transform)&&s.transform,s.worker&&r.WORKERS_SUPPORTED){var d=function(){if(!r.WORKERS_SUPPORTED)return!1;var a,s,o=(a=t.URL||t.webkitURL||null,s=e.toString(),r.BLOB_URL||(r.BLOB_URL=a.createObjectURL(new Blob(["var global = (function() { if (typeof self !== 'undefined') { return self; } if (typeof window !== 'undefined') { return window; } if (typeof global !== 'undefined') { return global; } return {}; })(); global.IS_PAPA_WORKER=true; ","(",s,")();"],{type:"text/javascript"})))),d=new t.Worker(o);return d.onmessage=f,d.id=i++,n[d.id]=d}();return d.userStep=s.step,d.userChunk=s.chunk,d.userComplete=s.complete,d.userError=s.error,s.step=M(s.step),s.chunk=M(s.chunk),s.complete=M(s.complete),s.error=M(s.error),delete s.worker,void d.postMessage({input:a,config:s,workerId:d.id})}var m=null;return r.NODE_STREAM_INPUT,"string"==typeof a?(a=function(e){return 65279===e.charCodeAt(0)?e.slice(1):e}(a),m=s.download?new l(s):new c(s)):!0===a.readable&&M(a.read)&&M(a.on)?m=new _(s):(t.File&&a instanceof File||a instanceof Object)&&(m=new u(s)),m.stream(a)},unparse:function(e,t){var a=!1,s=!0,n=",",i="\r\n",o='"',d=o+o,l=!1,u=null,c=!1;!function(){if("object"==typeof t){if("string"!=typeof t.delimiter||r.BAD_DELIMITERS.filter((function(e){return-1!==t.delimiter.indexOf(e)})).length||(n=t.delimiter),("boolean"==typeof t.quotes||"function"==typeof t.quotes||Array.isArray(t.quotes))&&(a=t.quotes),"boolean"!=typeof t.skipEmptyLines&&"string"!=typeof t.skipEmptyLines||(l=t.skipEmptyLines),"string"==typeof t.newline&&(i=t.newline),"string"==typeof t.quoteChar&&(o=t.quoteChar),"boolean"==typeof t.header&&(s=t.header),Array.isArray(t.columns)){if(0===t.columns.length)throw new Error("Option columns is empty");u=t.columns}void 0!==t.escapeChar&&(d=t.escapeChar+o),("boolean"==typeof t.escapeFormulae||t.escapeFormulae instanceof RegExp)&&(c=t.escapeFormulae instanceof RegExp?t.escapeFormulae:/^[=+\-@\t\r].*$/)}}();var _=new RegExp(h(o),"g");if("string"==typeof e&&(e=JSON.parse(e)),Array.isArray(e)){if(!e.length||Array.isArray(e[0]))return m(null,e,l);if("object"==typeof e[0])return m(u||Object.keys(e[0]),e,l)}else if("object"==typeof e)return"string"==typeof e.data&&(e.data=JSON.parse(e.data)),Array.isArray(e.data)&&(e.fields||(e.fields=e.meta&&e.meta.fields||u),e.fields||(e.fields=Array.isArray(e.data[0])?e.fields:"object"==typeof e.data[0]?Object.keys(e.data[0]):[]),Array.isArray(e.data[0])||"object"==typeof e.data[0]||(e.data=[e.data])),m(e.fields||[],e.data||[],l);throw new Error("Unable to serialize unrecognized input");function m(e,t,a){var r="";"string"==typeof e&&(e=JSON.parse(e)),"string"==typeof t&&(t=JSON.parse(t));var o=Array.isArray(e)&&0=this._config.preview;if(s)t.postMessage({results:o,workerId:r.WORKER_ID,finished:l});else if(M(this._config.chunk)&&!a){if(this._config.chunk(o,this._handle),this._handle.paused()||this._handle.aborted())return void(this._halted=!0);o=void 0,this._completeResults=void 0}return this._config.step||this._config.chunk||(this._completeResults.data=this._completeResults.data.concat(o.data),this._completeResults.errors=this._completeResults.errors.concat(o.errors),this._completeResults.meta=o.meta),this._completed||!l||!M(this._config.complete)||o&&o.meta.aborted||(this._config.complete(this._completeResults,this._input),this._completed=!0),l||o&&o.meta.paused||this._nextChunk(),o}this._halted=!0},this._sendError=function(e){M(this._config.error)?this._config.error(e):s&&this._config.error&&t.postMessage({workerId:r.WORKER_ID,error:e,finished:!1})}}function l(e){var t;(e=e||{}).chunkSize||(e.chunkSize=r.RemoteChunkSize),d.call(this,e),this._nextChunk=a?function(){this._readChunk(),this._chunkLoaded()}:function(){this._readChunk()},this.stream=function(e){this._input=e,this._nextChunk()},this._readChunk=function(){if(this._finished)this._chunkLoaded();else{if(t=new XMLHttpRequest,this._config.withCredentials&&(t.withCredentials=this._config.withCredentials),a||(t.onload=k(this._chunkLoaded,this),t.onerror=k(this._chunkError,this)),t.open(this._config.downloadRequestBody?"POST":"GET",this._input,!a),this._config.downloadRequestHeaders){var e=this._config.downloadRequestHeaders;for(var s in e)t.setRequestHeader(s,e[s])}if(this._config.chunkSize){var n=this._start+this._config.chunkSize-1;t.setRequestHeader("Range","bytes="+this._start+"-"+n)}try{t.send(this._config.downloadRequestBody)}catch(e){this._chunkError(e.message)}a&&0===t.status&&this._chunkError()}},this._chunkLoaded=function(){4===t.readyState&&(t.status<200||400<=t.status?this._chunkError():(this._start+=this._config.chunkSize?this._config.chunkSize:t.responseText.length,this._finished=!this._config.chunkSize||this._start>=function(e){var t=e.getResponseHeader("Content-Range");return null===t?-1:parseInt(t.substring(t.lastIndexOf("/")+1))}(t),this.parseChunk(t.responseText)))},this._chunkError=function(e){var a=t.statusText||e;this._sendError(new Error(a))}}function u(e){var t,a;(e=e||{}).chunkSize||(e.chunkSize=r.LocalChunkSize),d.call(this,e);var s="undefined"!=typeof FileReader;this.stream=function(e){this._input=e,a=e.slice||e.webkitSlice||e.mozSlice,s?((t=new FileReader).onload=k(this._chunkLoaded,this),t.onerror=k(this._chunkError,this)):t=new FileReaderSync,this._nextChunk()},this._nextChunk=function(){this._finished||this._config.preview&&!(this._rowCount=this._input.size,this.parseChunk(e.target.result)},this._chunkError=function(){this._sendError(t.error)}}function c(e){var t;d.call(this,e=e||{}),this.stream=function(e){return t=e,this._nextChunk()},this._nextChunk=function(){if(!this._finished){var e,a=this._config.chunkSize;return a?(e=t.substring(0,a),t=t.substring(a)):(e=t,t=""),this._finished=!t,this.parseChunk(e)}}}function _(e){d.call(this,e=e||{});var t=[],a=!0,s=!1;this.pause=function(){d.prototype.pause.apply(this,arguments),this._input.pause()},this.resume=function(){d.prototype.resume.apply(this,arguments),this._input.resume()},this.stream=function(e){this._input=e,this._input.on("data",this._streamData),this._input.on("end",this._streamEnd),this._input.on("error",this._streamError)},this._checkIsFinished=function(){s&&1===t.length&&(this._finished=!0)},this._nextChunk=function(){this._checkIsFinished(),t.length?this.parseChunk(t.shift()):a=!0},this._streamData=k((function(e){try{t.push("string"==typeof e?e:e.toString(this._config.encoding)),a&&(a=!1,this._checkIsFinished(),this.parseChunk(t.shift()))}catch(e){this._streamError(e)}}),this),this._streamError=k((function(e){this._streamCleanUp(),this._sendError(e)}),this),this._streamEnd=k((function(){this._streamCleanUp(),s=!0,this._streamData("")}),this),this._streamCleanUp=k((function(){this._input.removeListener("data",this._streamData),this._input.removeListener("end",this._streamEnd),this._input.removeListener("error",this._streamError)}),this)}function m(e){var t,a,s,n=Math.pow(2,53),i=-n,o=/^\s*-?(\d+\.?|\.\d+|\d+\.\d+)([eE][-+]?\d+)?\s*$/,d=/^((\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z))|(\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d([+-][0-2]\d:[0-5]\d|Z)))$/,l=this,u=0,c=0,_=!1,m=!1,f=[],v={data:[],errors:[],meta:{}};if(M(e.step)){var g=e.step;e.step=function(t){if(v=t,L())b();else{if(b(),0===v.data.length)return;u+=t.data.length,e.preview&&u>e.preview?a.abort():(v.data=v.data[0],g(v,l))}}}function k(t){return"greedy"===e.skipEmptyLines?""===t.join("").trim():1===t.length&&0===t[0].length}function b(){return v&&s&&(D("Delimiter","UndetectableDelimiter","Unable to auto-detect delimiting character; defaulted to '"+r.DefaultDelimiter+"'"),s=!1),e.skipEmptyLines&&(v.data=v.data.filter((function(e){return!k(e)}))),L()&&function(){if(v)if(Array.isArray(v.data[0])){for(var t=0;L()&&t=f.length?"__parsed_extra":f[s]),e.transform&&(r=e.transform(r,i)),r=w(i,r),"__parsed_extra"===i?(n[i]=n[i]||[],n[i].push(r)):n[i]=r}return e.header&&(s>f.length?D("FieldMismatch","TooManyFields","Too many fields: expected "+f.length+" fields but parsed "+s,c+a):s=s.length/2?"\r\n":"\r"}(n,d)),s=!1,e.delimiter)M(e.delimiter)&&(e.delimiter=e.delimiter(n),v.meta.delimiter=e.delimiter);else{var l=function(t,a,s,n,i){var o,d,l,u;i=i||[",","\t","|",";",r.RECORD_SEP,r.UNIT_SEP];for(var c=0;c=o)return B(!0)}else for($=u,u++;;){if(-1===($=r.indexOf(t,$+1)))return m||b.push({type:"Quotes",code:"MissingQuotes",message:"Quoted field unterminated",row:k.length,index:u}),U();if($===p-1)return U(r.substring(u,$).replace(F,t));if(t!==l||r[$+1]!==l){if(t===l||0===$||r[$-1]!==l){-1!==V&&V<$+1&&(V=r.indexOf(a,$+1)),-1!==E&&E<$+1&&(E=r.indexOf(s,$+1));var I=R(-1===E?V:Math.min(V,E));if(r.substr($+1+I,f)===a){L.push(r.substring(u,$).replace(F,t)),r[u=$+1+I+f]!==t&&($=r.indexOf(t,u)),V=r.indexOf(a,u),E=r.indexOf(s,u);break}var W=R(E);if(r.substring($+1+W,$+1+W+v)===s){if(L.push(r.substring(u,$).replace(F,t)),z($+1+W+v),V=r.indexOf(a,u),$=r.indexOf(t,u),y&&(q(),c))return B();if(o&&k.length>=o)return B(!0);break}b.push({type:"Quotes",code:"InvalidQuotes",message:"Trailing quote on quoted field is malformed",row:k.length,index:u}),$++}}else $++}return U();function N(e){k.push(e),w=u}function R(e){var t=0;if(-1!==e){var a=r.substring($+1,e);a&&""===a.trim()&&(t=a.length)}return t}function U(e){return m||(void 0===e&&(e=r.substring(u)),L.push(e),u=p,N(L),y&&q()),B()}function z(e){u=e,N(L),L=[],E=r.indexOf(s,u)}function B(e){return{data:k,errors:b,meta:{delimiter:a,linebreak:s,aborted:c,truncated:!!e,cursor:w+(_||0)}}}function q(){i(B()),k=[],b=[]}},this.abort=function(){c=!0},this.getCharIndex=function(){return u}}function f(e){var t=e.data,a=n[t.workerId],s=!1;if(t.error)a.userError(t.error,t.file);else if(t.results&&t.results.data){var i={abort:function(){s=!0,v(t.workerId,{data:[],errors:[],meta:{aborted:!0}})},pause:g,resume:g};if(M(a.userStep)){for(var r=0;r{var s,n,i;!function(r){"use strict";n=[a(5311)],s=function(e){var t,a=window.Slick||{};(t=0,a=function(a,s){var n,i=this;i.defaults={accessibility:!0,adaptiveHeight:!1,appendArrows:e(a),appendDots:e(a),arrows:!0,asNavFor:null,prevArrow:'',nextArrow:'',autoplay:!1,autoplaySpeed:3e3,centerMode:!1,centerPadding:"50px",cssEase:"ease",customPaging:function(t,a){return e('
    diff --git a/templates/whats-new.php b/templates/whats-new.php index deec9f7cf3..3ac7a1a601 100644 --- a/templates/whats-new.php +++ b/templates/whats-new.php @@ -3,6 +3,95 @@ * When you are adding new version please follow this sequence for changes: New Feature, New, Improvement, Fix... */ $changelog = [ + [ + 'version' => 'Version 3.9.1', + 'released' => '2023-10-17', + 'changes' => [ + 'New' => [ + [ + 'title' => '', + 'description' => '', + ], + [ + 'title' => '', + 'description' => '', + ], + ], + 'Improvement' => [ + [ + 'title' => 'Removed flaticon packages and replace used icons with fontAwesome icons. This will reduce the plugin zip size.', + 'description' => '', + ], + [ + 'title' => 'Added a new settings to disable fontAwesome library', + 'description' => '', + ], + [ + 'title' => 'Changed all the single date picker fields with daterange picker. This updates will keep the design consistent throughout the plugin.', + 'description' => '', + ], + ], + 'Fix' => [ + [ + 'title' => '[StoreOpenCloseTime] An issue where invalid store opening or closing times generate warning and fatal error on single store page.', + 'description' => '', + ], + [ + 'title' => '[Email] Fixed an issue where the product edit link on email template redirects to the products listing instead of single product edit page', + 'description' => '', + ], + [ + 'title' => 'Fixed some responsive issue under vendor dashboard product edit page.', + 'description' => '', + ], + [ + 'title' => 'Fixed some responsive issue under vendor dashboard withdraw page.', + 'description' => '', + ], + ], + ], + ], + [ + 'version' => 'Version 3.9.0', + 'released' => '2023-10-06', + 'changes' => [ + 'New' => [ + [ + 'title' => 'Added two new hooks named `dokan_get_admin_report_data` and `dokan_get_overview_data` to extend Dokan reports functionality.', + 'description' => '', + ], + [ + 'title' => '', + 'description' => '', + ], + ], + 'Improvement' => [ + [ + 'title' => 'Added a new filter named `dokan_get_store_url` to filter store URLs for a single store.', + 'description' => '', + ], + [ + 'title' => 'Removed some redundant or not required settings from vendor store settings page, also rearranged some admin settings and added some settings under Admin dashboard.', + 'description' => 'Details: +1. Removed `Show Vendor Info` settings under the `WordPress Admin Dashboard → Dokan → Settings → Appearance` and added it back under the `WordPress Admin Dashboard → Dokan → Settings → General → Product Page Settings` section. +2. Removed the `More Products` setting under `Vendor Dashboard → Settings → Store Settings` and added it back as a new Admin setting under `WordPress Admin Dashboard → Dokan → Settings → General → Product Page Settings` section. Now, only the admin can control this setting. +3. Removed redundant `Store Products Per Page` setting under `Vendor Dashboard → Settings → Store Settings`. Since the admin already has this setting under `WordPress Admin Dashboard → Dokan → Settings → General`, this setting will be used from now on and only the admin can control this setting. +4. Removed redundant `Store Page Product Section` settings under `Vendor Dashboard → Settings → Store Page Product Section`. Now, only the admin can control these settings under Theme Customizer settings. +', + ], + ], + 'Fix' => [ + [ + 'title' => 'Resolved an issue where the `Tracking Number` button was still visible under the `Vendor Dashboard → Order Details → Order Note section` even after the `Shipment Tracking` feature was enabled by the admin.', + 'description' => '', + ], + [ + 'title' => '[WidgetProductAttribute] Fixed an issue where the `Filter Products by Attribute` widget was not working for Multi-Word Attributes.', + 'description' => '', + ], + ], + ], + ], [ 'version' => 'Version 3.8.3', 'released' => '2023-09-26', @@ -29,7 +118,7 @@ 'description' => '', ], ], - 'Fix' => [ + 'Fix' => [ [ 'title' => '[Refund] Earlier, when refunding an order under the vendor dashboard, the tax amount decimal point rounding precision was inconsistent with WooCommerce. However, it has now been updated to be consistent with WooCommerce.', 'description' => '', @@ -70,7 +159,7 @@ 'description' => '', ], ], - 'Fix' => [ + 'Fix' => [ [ 'title' => 'Fixed an issue where orders can’t be filtered by vendor under Admin Dashboard → WooCommerce → Order lists page if HPOS feature is enabled', 'description' => '', diff --git a/tests/pw/.env.example b/tests/pw/.env.example new file mode 100644 index 0000000000..e2365e301f --- /dev/null +++ b/tests/pw/.env.example @@ -0,0 +1,24 @@ +# Plugin Configuration +ADMIN=John_Doe [Admin username] +ADMIN_PASSWORD=AdminPass123 [Password for the admin account] +VENDOR=David_Johnson [Vendor username] +VENDOR2=jhonathon_Smith [Vendor username] +CUSTOMER=Michael_Williams [Customer username] +USER_PASSWORD=Passw0rd123 [Password for all other users] +GMAP=ABCD1234EFGH5678 [Google Maps API key] +LICENSE_KEY=ABCD1234EFGH5678 [Dokan License key] +DOKAN_PRO=true [Dokan pro active status] + +# Playwright Configuration +BASE_URL=https://example.com [Base URL of the test site] +CI=true [CI/CD environment indicator] +SLOWMO=10 [Slow down test execution by provided seconds] [optional] +SETUP=true [Whether not to run setup tests before actual tests] [optional] + +# Database Configuration +DB_HOST_NAME=localhost [Database server hostname or IP address] +DB_USER_NAME=dbuser [Database username] +DB_USER_PASSWORD=dbpassword [Database user password] +DATABASE=mywpdb [Database name] +DB_PORT=3306 [Database connection port] +DB_PREFIX=wp [Prefix for database tables] \ No newline at end of file diff --git a/tests/pw/.eslintignore b/tests/pw/.eslintignore new file mode 100644 index 0000000000..c6bdf3d86b --- /dev/null +++ b/tests/pw/.eslintignore @@ -0,0 +1,23 @@ +# Playwright Specific +node_modules/ +playwright/ +playwright-report +test-results/ +summary.json +types/ + +# IDE - VSCode +.vscode/* + +# System Files +.DS_Store +Thumbs.db +{"mode":"full","isActive":false} + +# Docs files +*_spec3.json + + +# Custom files +TODO.ts +TODO.md \ No newline at end of file diff --git a/tests/pw/.eslintrc b/tests/pw/.eslintrc new file mode 100644 index 0000000000..52adaa832d --- /dev/null +++ b/tests/pw/.eslintrc @@ -0,0 +1,37 @@ +{ + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", // recommended, recommended-type-checked, strict, strict-type-checked + // "plugin:@typescript-eslint/recommended-type-checked", // for ts typed check + // "plugin:@typescript-eslint/stylistic", // stylistic, stylistic-type-checked + // "plugin:@typescript-eslint/stylistic-type-checked", // for ts typed check + "plugin:playwright/recommended", + "prettier" + ], + "plugins": ["@typescript-eslint"], + "parser": "@typescript-eslint/parser", + // for ts typed check + // "parserOptions": { + // "project": true, + // "tsconfigRootDir": "__dirname" + // }, + "root": true, + "rules": { + // eslint rules + "@typescript-eslint/no-var-requires": "off", + "@typescript-eslint/no-unused-vars": "off", + "@typescript-eslint/no-explicit-any": "off", + // playwright rules + "playwright/expect-expect": "off", + "playwright/no-skipped-test": "off", + "playwright/no-conditional-in-test": "off" + // custom rules + // "no-restricted-syntax": [ + // "error", + // { + // "selector": "CallExpression[callee.property.name='only']", + // "message": "test.only is not allowed." + // }, + // ], + } +} diff --git a/tests/pw/.gitignore b/tests/pw/.gitignore new file mode 100644 index 0000000000..a95068d139 --- /dev/null +++ b/tests/pw/.gitignore @@ -0,0 +1,200 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp +.cache + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + + +# Mac +# General +.DS_Store +.AppleDouble +.LSOverride +Desktop.ini + +# Icon must end with two \r +Icon + +# Thumbnails +._* +Thumbs.db + + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# custom files + +#vscode +.idea/ + +# mac +.Ds_ + +# playwright +playwright/ +test-results/ +playwright-report/ +playwright/.cache/ +storageState.json +adminStorageState.json +customerStorageState.json +vendorStorageState.json +systemInfo.json + +# vscode +.vscode/ + +# js config +jsconfig.json + +# packages & plugins +wp-content/ +artifacts/ +jest-stare/ +allure-results/ +allure-report/ +plugins/ +../../plugins/ +_test.spec.ts +_test.js +_auth.spec.ts + diff --git a/tests/pw/.htaccess b/tests/pw/.htaccess new file mode 100644 index 0000000000..8e5df81db7 --- /dev/null +++ b/tests/pw/.htaccess @@ -0,0 +1,14 @@ +# BEGIN WordPress +# The directives (lines) between "BEGIN WordPress" and "END WordPress" are +# dynamically generated, and should only be modified via WordPress filters. +# Any changes to the directives between these markers will be overwritten. + +RewriteEngine On +RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] +RewriteBase / +RewriteRule ^index\.php$ - [L] +RewriteCond %{REQUEST_FILENAME} !-f +RewriteCond %{REQUEST_FILENAME} !-d +RewriteRule . /index.php [L] + +# END WordPress \ No newline at end of file diff --git a/tests/pw/.prettierignore b/tests/pw/.prettierignore new file mode 100644 index 0000000000..94dd707335 --- /dev/null +++ b/tests/pw/.prettierignore @@ -0,0 +1,28 @@ +# Playwright Specific +node_modules/ +playwright/ +playwright-report +test-results/ +summary.json +types/ + +# IDE - VSCode +.vscode/* + +# System Files +.DS_Store +Thumbs.db +{"mode":"full","isActive":false} + +# Docs files +*_spec3.json + +# Custom files +TODO.ts +TODO.md + + +# Ignore all design files: +**/*.html +**/*.css +**/*.JSX \ No newline at end of file diff --git a/tests/pw/.prettierrc b/tests/pw/.prettierrc new file mode 100644 index 0000000000..f3f4204902 --- /dev/null +++ b/tests/pw/.prettierrc @@ -0,0 +1,10 @@ +{ + "printWidth": 220, + "tabWidth": 4, + "semi": true, + "singleQuote": true, + "quoteProps": "as-needed", + "trailingComma": "all", + "bracketSpacing": true, + "arrowParens": "avoid" +} diff --git a/tests/pw/.wp-env.json b/tests/pw/.wp-env.json new file mode 100644 index 0000000000..70dbce6752 --- /dev/null +++ b/tests/pw/.wp-env.json @@ -0,0 +1,26 @@ +{ + "env": { + "tests": { + "port": 9999, + "core": "https://wordpress.org/latest.zip", + "phpVersion": "7.4", + "plugins": [ + "https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip", + "../../", + "https://github.com/shashwatahalder01/TestUtils/raw/main/ba.zip" + ], + "themes": [ + "https://downloads.wordpress.org/theme/storefront.latest-stable.zip" + ], + "config": { + "WP_DEBUG": "true", + "SCRIPT_DEBUG": "true", + "WP_DEBUG_LOG": "true", + "WP_DEBUG_DISPLAY": "true" + }, + "mappings": { + ".htaccess": ".htaccess" + } + } + } +} diff --git a/tests/pw/.wp-env.override b/tests/pw/.wp-env.override new file mode 100644 index 0000000000..c988950818 --- /dev/null +++ b/tests/pw/.wp-env.override @@ -0,0 +1,16 @@ +{ + "env": { + "tests": { + "plugins": [ + "https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip", + "../../", + "../../../../", + "https://github.com/shashwatahalder01/TestUtils/raw/main/ba.zip", + "https://github.com/shashwatahalder01/TestUtils/raw/main/wa.zip", + "https://github.com/shashwatahalder01/TestUtils/raw/main/wb.zip", + "https://github.com/shashwatahalder01/TestUtils/raw/main/wps.zip", + "https://github.com/shashwatahalder01/TestUtils/raw/main/ws.zip" + ] + } + } +} \ No newline at end of file diff --git a/tests/pw/README.MD b/tests/pw/README.MD new file mode 100644 index 0000000000..b6b19021bd --- /dev/null +++ b/tests/pw/README.MD @@ -0,0 +1,281 @@ +# Dokan E2E-API Tests :test_tube: (Playwright :performing_arts:) + +### :fire: Automated E2E and API tests for Dokan plugin. :fire: + +
    + +## :bookmark: Table of contents + +- [Pre-requisites :pushpin:](#pre-requisites) + - [Install Node](#install-node) + - [Install NVM](#install-nvm) + - [Install Docker](#install-docker) + +
    + +- [Prep for tests :construction:](#prep-for-tests) + - [Install Dependencies](#install-dependencies) + - [Start Wordpress Environment](#start-wordpress-environment) + - [Create Env file](#create-env-file) + +
    + +- [Running tests :test_tube: ](#running-tests) + - [How to run test projects](#how-to-run-test-projects) + - [How to run tests](#how-to-run-tests) + - [How to skip tests](#how-to-skip-tests) + - [How to debug tests](#how-to-debug-tests) + - [How to serve reports](#how-to-serve-reports) + +
    + +- [Contributing to Dokan-e2e-api-test](#Contributing-to-dokan-e2e-api-test) + - [How to wright tests](#how-to-run-tests) + +
    + +## :pushpin: Pre-requisites + +#### :o: Install Node + + Follow instructions on the [Node site](https://nodejs.org/en/download/) to install Node. + +#### :o: Install NVM + + Follow instructions in the [NVM repository](https://github.com/nvm-sh/nvm) to install NVM. + +#### :o: Install Docker + + Follow instructions on the [Docker Desktop](https://docs.docker.com/docker-for-mac/install/) to install Docker. + +
    + +## :construction: Prep for tests + +Preparation for running tests involves conducting necessary tasks and arrangements to ensure a smooth and efficient testing process. This may include setting up the testing environment, configuring dependencies, initializing resources, and performing any required setup actions. + +
    + +### :o: Install Dependencies + +
    + +:radio_button: Go to project directory + + cd tests/pw + +
    + +:radio_button: Install dependencies + +``` +npm i +``` + +
    + +:radio_button: Install browser + +``` +npx playwright install chromium +``` + +
    + +### :o: Start Wordpress Environment + +
    + +:radio_button: Go to project directory + + cd tests/pw + +
    + +:radio_button: Start Environment + + npm run wp-env start + +
    + +### :o: Create Env file + +Environment (env) file is used for storing configuration settings and variables specific to the testing environment. It allows managing and customizing the testing environment settings easily without modifying the test code. It provides flexibility and enables seamless configuration changes between different testing environments, ensuring efficient and effective testing of the project. + +
    + +Create .env file according to .env.example file + +
    + +``` +# Plugin Configuration +ADMIN=John_Doe [Admin username] +ADMIN_PASSWORD=AdminPass123 [Password for the admin account] +VENDOR=David_Johnson [Vendor username] +VENDOR2=jhonathon_Smith [Vendor username] +CUSTOMER=Michael_Williams [Customer username] +USER_PASSWORD=Passw0rd123 [Password for all other users] +GMAP=ABCD1234EFGH5678 [Google Maps API key] +LICENSE_KEY=ABCD1234EFGH5678 [Dokan License key] +DOKAN_PRO=true [Dokan pro active status] + +# Playwright Configuration +BASE_URL=https://example.com [Base URL of the test site] +CI=true [CI/CD environment indicator] +SLOWMO=10 [Slow down test execution by provided seconds] [optional] +SETUP=true [Whether not to run setup tests before actual tests] [optional] + +# Database Configuration +DB_HOST_NAME=localhost [Database server hostname or IP address] +DB_USER_NAME=dbuser [Database username] +DB_USER_PASSWORD=dbpassword [Database user password] +DATABASE=mywpdb [Database name] +DB_PORT=3306 [Database connection port] +DB_PREFIX=wp [Prefix for database tables] +``` + +
    +
    + +## :test_tube: Running tests + +Running tests involves executing the predefined test cases or scripts to evaluate the functionality, performance, or other aspects of a system or software application. By running tests, potential issues, bugs, or errors can be identified, providing insights into the quality and behavior of the system under test. The results obtained from running tests contribute to validating the system's compliance with requirements, verifying expected outcomes, and supporting the overall quality assurance process. + +
    + +### :o: How to run test projects + +
    + +:radio_button: Run E2E test project Lite + + npx playwright test --project=e2e_tests --grep '@lite|@liteOnly' --config=e2e.config.ts + +
    + +:radio_button: Run API test project Lite + + npx playwright test --project=api_tests --grep '@lite|@liteOnly' --config=api.config.ts + +
    + +:radio_button: Run E2E test project Pro + + npx playwright test --project=e2e_tests --grep '@lite|@pro' --config=e2e.config.ts + +
    + +:radio_button: Run API test project Pro + + npx playwright test --project=api_tests --grep '@lite|@pro' --config=api.config.ts + +
    + +### :o: How to run tests + +
    + +:radio_button: Run all tests + + npx playwright test + +
    + +:radio_button: Run tests in UI Mode + + npx playwright test --ui + +
    + +:radio_button: Run a single test file + + npx playwright test customers.spec.ts + +
    + +:radio_button: Run a set of test files + + npx playwright test tests/products/ tests/customers/ + +
    + +:radio_button: Run files that have report or customer in the file name + + npx playwright test report customers + +
    + +:radio_button: Run the test with the title + + npx playwright test -g "customer add customer details" + +
    + +:radio_button: Run a single project + + npx playwright test --project=e2e_tests + +
    + +:radio_button: Run group of tests with certain tag + + npx playwright test --grep @pro + +
    + +:radio_button: Run multiple groups of tags + + npx playwright test --grep @lite | @pro + +
    + +:radio_button: Skip the tests with a certain tag: + + npx playwright test --grep-invert @pro + +
    + +:radio_button: Run tests on specific browser + + npx playwright test --project=chromium + +
    + +:radio_button: Run tests in headed mode + + npx playwright test --headed + +
    + +### :o: How to debug tests + +
    + +:radio_button: Run all tests with debug flag + + npx playwright test --debug + +
    + +:radio_button: Run a single test with debug flag + + npx playwright test customers.spec.ts --debug + +
    + +:radio_button: Debug start form specific test line number [where the test(.. is defined] + + npx playwright test customers.spec.ts:20 --debug + +
    + +### :o: How to serve reports + +
    + +:radio_button: Server test report + + npx playwright show-report + +## Contributing to playwright-api-test diff --git a/tests/pw/api.config.ts b/tests/pw/api.config.ts new file mode 100644 index 0000000000..8ce06c1df9 --- /dev/null +++ b/tests/pw/api.config.ts @@ -0,0 +1,63 @@ +import { defineConfig } from '@playwright/test'; +import 'dotenv/config'; + +export default defineConfig({ + testDir: './tests/api' /* test directory */, + outputDir: 'playwright/api/test-artifacts/' /* Folder for test artifacts such as screenshots, videos, traces, etc. */, + globalSetup: './global-setup' /* Path to the global setup file. This file will be required and run before all the tests. */, + globalTeardown: './global-teardown' /* Path to the global teardown file. This file will be required and run after all the tests. */, + globalTimeout: process.env.CI ? 20 * (60 * 1000) : 20 * (60 * 1000) /* Maximum time in milliseconds the whole test suite can run */, + maxFailures: process.env.CI ? 30 : 30 /* The maximum number of test failures for the whole test suite run. After reaching this number, testing will stop and exit with an error. */, + timeout: process.env.CI ? 5 * 1000 : 10 * 1000 /* Maximum time one test can run for. */, + expect: { + timeout: 5 * 1000 /* Maximum time expect() should wait for the condition to be met. For example in `await expect(locator).toHaveText();`*/, + } /* Configuration for the expect assertion library */, + preserveOutput: 'always' /* Whether to preserve test output in the testConfig.outputDir. Defaults to 'always'. */, + // fullyParallel : true, /* Run tests in files in parallel */ + // forbidOnly : !!process.env.CI, /* Fail the build on CI if you accidentally left testonly in the source code. */ + repeatEach: 1 /* The number of times to repeat each test, useful for debugging flaky tests. */, + retries: process.env.CI ? 1 : 0 /* The maximum number of retry attempts given to failed tests. */, + workers: process.env.CI ? 1 : 1 /* Opt out of parallel tests on CI. */, + reportSlowTests: { max: 3, threshold: 10 } /* Whether to report slow test files. Pass null to disable this feature. */, + reporter: process.env.CI + ? [ + ['html', { open: 'never', outputFolder: 'playwright-report/api/html/html-report-api' }], + ['junit', { outputFile: 'playwright-report/api/junit-report/api-results.xml' }], + ['list', { printSteps: true }], + ['./utils/summaryReporter.ts', { outputFile: 'playwright-report/api/summary-report/results.json' }], + ] + : [ + ['html', { open: 'never', outputFolder: 'playwright-report/api/html/html-report-api' }], + ['junit', { outputFile: 'playwright-report/api/junit-report/api-results.xml' }], + ['list', { printSteps: true }], + ['./utils/summaryReporter.ts', { outputFile: 'playwright-report/api/summary-report/results.json' }], + // ['allure-playwright', { detail: true, outputFolder: 'playwright-report/api/allure/allure-report', suiteTitle: false }], + ], + + use: { + baseURL: process.env.BASE_URL ? process.env.BASE_URL : 'http://localhost:9999' /* Base URL */, + ignoreHTTPSErrors: true /* Whether to ignore HTTPS errors during navigation. */, + /* api request headers */ + extraHTTPHeaders: { + Accept: '*/*', + Authorization: 'Basic ' + Buffer.from(process.env.ADMIN + ':' + process.env.ADMIN_PASSWORD).toString('base64'), + }, + }, + + projects: [ + // Api project + + // api_setup + { + name: 'api_setup', + testMatch: /.*\.setup\.ts/, + }, + + // api_tests + { + name: 'api_tests', + testMatch: /.*\.spec\.ts/, + // dependencies: process.env.SETUP ? [] : ['api_setup'] /* whether not to run setup tests before running actual tests */, + }, + ], +}); diff --git a/tests/pw/e2e.config.ts b/tests/pw/e2e.config.ts new file mode 100644 index 0000000000..48d8449108 --- /dev/null +++ b/tests/pw/e2e.config.ts @@ -0,0 +1,81 @@ +import { defineConfig, devices } from '@playwright/test'; +import 'dotenv/config'; + +export default defineConfig({ + testDir: './tests/e2e' /* test directory */, + outputDir: 'playwright/e2e/test-artifacts/' /* Folder for test artifacts such as screenshots, videos, traces, etc. */, + globalSetup: './global-setup' /* Path to the global setup file. This file will be required and run before all the tests. */, + globalTeardown: './global-teardown' /* Path to the global teardown file. This file will be required and run after all the tests. */, + globalTimeout: process.env.CI ? 40 * (60 * 1000) : 20 * (60 * 1000) /* Maximum time in milliseconds the whole test suite can run */, + maxFailures: process.env.CI ? 30 : 30 /* The maximum number of test failures for the whole test suite run. After reaching this number, testing will stop and exit with an error. */, + timeout: process.env.CI ? 40 * 1000 : 35 * 1000 /* Maximum time one test can run for. */, + expect: { + timeout: 10 * 1000 /* Maximum time expect() should wait for the condition to be met. For example in `await expect(locator).toHaveText();`*/, + } /* Configuration for the expect assertion library */, + preserveOutput: 'always' /* Whether to preserve test output in the testConfig.outputDir. Defaults to 'always'. */, + // fullyParallel : true, /* Run tests in files in parallel */ + // forbidOnly : !!process.env.CI, /* Fail the build on CI if you accidentally left test-only in the source code. */ + repeatEach: 1 /* The number of times to repeat each test, useful for debugging flaky tests. */, + retries: process.env.CI ? 1 : 0 /* The maximum number of retry attempts given to failed tests. */, + workers: process.env.CI ? 1 : 1 /* Opt out of parallel tests on CI. */, + reportSlowTests: { max: 3, threshold: 25 } /* Whether to report slow test files. Pass null to disable this feature. */, + reporter: process.env.CI + ? [ + ['html', { open: 'never', outputFolder: 'playwright-report/e2e/html/html-report-e2e' }], + ['junit', { outputFile: 'playwright-report/e2e/junit-report/e2e-results.xml' }], + ['list', { printSteps: true }], + ['./utils/summaryReporter.ts', { outputFile: 'playwright-report/e2e/summary-report/results.json' }], + ] + : [ + ['html', { open: 'never', outputFolder: 'playwright-report/e2e/html/html-report-e2e' }], + ['junit', { outputFile: 'playwright-report/e2e/junit-report/e2e-results.xml' }], + ['list', { printSteps: true }], + ['./utils/summaryReporter.ts', { outputFile: 'playwright-report/e2e/summary-report/results.json' }], + // ['allure-playwright', { detail: true, outputFolder: 'playwright-report/e2e/allure/allure-report', suiteTitle: false }] + ], + + use: { + ...devices['Desktop Chrome'], + acceptDownloads: true /* Whether to automatically download all the attachments. */, + actionTimeout: 15 * 1000 /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */, + navigationTimeout: 20 * 1000 /* Maximum time each navigation such as 'goto()' can take. */, + baseURL: process.env.BASE_URL ? process.env.BASE_URL : 'http://localhost:9999' /* Base URL */, + // browserName : 'chromium', /* Name of the browser that runs tests. */ + bypassCSP: true /* Toggles bypassing page's Content-Security-Policy. */, + // channel : 'chrome', /* Browser distribution channel. */ + // colorScheme : 'dark', /* Emulates 'prefers-colors-scheme' media feature, supported values are 'light', 'dark', 'no-preference' */ + headless: process.env.CI ? !!process.env.CI : false /* Whether to run tests on headless or non-headless mode */, + ignoreHTTPSErrors: true /* Whether to ignore HTTPS errors during navigation. */, + // trace : 'retain-on-failure', /* Record trace only when retrying a test for the first time. */ + trace: 'on-first-retry' /* Record trace only when retrying a test for the first time. */, + screenshot: 'only-on-failure' /* Capture screenshot after each test failure. */, + // video : 'retain-on-failure', /* Record video only when retrying a test for the first time. */ + video: 'on-first-retry' /* Record video only when retrying a test for the first time. */, + // viewport : { width: 1280, height: 720 }, /* Size of viewport */ + launchOptions: { slowMo: process.env.SLOWMO ? Number(process.env.SLOWMO) * 1000 : 0 /* whether to slow down test execution by provided seconds */ }, + }, + + projects: [ + // E2e project + + // e2e_setup + { + name: 'e2e_setup', + testMatch: /.*\.setup\.ts/, + }, + + // e2e_tests + { + name: 'e2e_tests', + testMatch: /.*\.spec\.ts/, + // dependencies: process.env.SETUP ? [] : ['e2e_setup'] /* whether not to run setup tests before running actual tests */, + }, + + // local site setup project + { + name: 'site_setup', + testMatch: /.*\.install\.ts/, + // globalSetup: '', + }, + ], +}); diff --git a/tests/pw/global-setup.ts b/tests/pw/global-setup.ts new file mode 100644 index 0000000000..b5d68c0a8d --- /dev/null +++ b/tests/pw/global-setup.ts @@ -0,0 +1,24 @@ +import { FullConfig, request } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; + +async function globalSetup(config: FullConfig) { + console.log('Global Setup running....'); + + // get site url structure + let serverUrl = config.projects[0]?.use.baseURL as string; + const apiUtils = new ApiUtils(await request.newContext({ ignoreHTTPSErrors: true })); + for (let i = 0; i < 3; i++) { + const headers = await apiUtils.getSiteHeaders(serverUrl); + if (headers.link) { + serverUrl = headers.link.includes('rest_route') ? serverUrl + '/?rest_route=' : serverUrl + '/wp-json'; + process.env.SERVER_URL = serverUrl; + break; + } + console.log('retrying...'); + } + console.log('ServerUrl:', process.env.SERVER_URL); + + console.log('Global Setup Finished!'); +} + +export default globalSetup; diff --git a/tests/pw/global-teardown.ts b/tests/pw/global-teardown.ts new file mode 100644 index 0000000000..a813d76d42 --- /dev/null +++ b/tests/pw/global-teardown.ts @@ -0,0 +1,21 @@ +import { request } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { helpers } from '@utils/helpers'; +import { payloads } from '@utils/payloads'; + +async function globalSetup() { + console.log('Global Teardown running....'); + + const systemInfo = 'systemInfo.json'; + + // get test environment info + if (!helpers.fileExists(systemInfo)) { + const apiUtils = new ApiUtils(await request.newContext({ ignoreHTTPSErrors: true })); + const [, summaryInfo] = await apiUtils.getSystemStatus(payloads.adminAuth); + helpers.writeFile(systemInfo, JSON.stringify(summaryInfo)); + } + + console.log('Global Teardown Finished!'); +} + +export default globalSetup; diff --git a/tests/pw/package-lock.json b/tests/pw/package-lock.json new file mode 100644 index 0000000000..41173c4dec --- /dev/null +++ b/tests/pw/package-lock.json @@ -0,0 +1,9949 @@ +{ + "name": "dokan_e2e_api_automation_playwright", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "dokan_e2e_api_automation_playwright", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "@faker-js/faker": "^8.0.2", + "@playwright/test": "^1.38.1", + "@wordpress/env": "^8.9.0", + "allure-playwright": "^2.7.0", + "dotenv": "^16.3.1", + "mysqlconnector": "^2.0.1", + "php-serialize": "^4.1.1", + "xml-js": "^1.6.11" + }, + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^6.6.0", + "@typescript-eslint/parser": "^6.6.0", + "eslint": "^8.49.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-playwright": "^0.16.0", + "npm-check-updates": "^16.13.3", + "prettier": "^3.0.3", + "typescript": "^5.2.2" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/js": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@faker-js/faker": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.0.2.tgz", + "integrity": "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/fakerjs" + } + ], + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0", + "npm": ">=6.14.13" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "dev": true, + "dependencies": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "dependencies": { + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "dev": true, + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@playwright/test": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", + "dependencies": { + "playwright": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "dependencies": { + "graceful-fs": "4.2.10" + }, + "engines": { + "node": ">=12.22.0" + } + }, + "node_modules/@pnpm/network.ca-file/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "dependencies": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", + "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.2.tgz", + "integrity": "sha512-vjwcYePJzM01Ha6oWWZ9gNcdIgnzyFxfqfWzph483DPJTH8Tb7f7bQRRll3CYVkyH56j0AgcPAcl6Vg95DPF+Q==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "tuf-js": "^1.1.7" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "dependencies": { + "defer-to-connect": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tufjs/canonical-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", + "dev": true, + "dependencies": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "dependencies": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "node_modules/@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, + "node_modules/@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "node_modules/@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" + }, + "node_modules/@types/responselike": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", + "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.6.0.tgz", + "integrity": "sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.6.0", + "@typescript-eslint/type-utils": "6.6.0", + "@typescript-eslint/utils": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.6.0.tgz", + "integrity": "sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.6.0", + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/typescript-estree": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.6.0.tgz", + "integrity": "sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.6.0.tgz", + "integrity": "sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.6.0", + "@typescript-eslint/utils": "6.6.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.6.0.tgz", + "integrity": "sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.6.0.tgz", + "integrity": "sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.6.0.tgz", + "integrity": "sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.6.0", + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/typescript-estree": "6.6.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.6.0.tgz", + "integrity": "sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.6.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@wordpress/env": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-8.9.0.tgz", + "integrity": "sha512-f3W1OMcUubZVC4OH9MTG2XE2OWwZH3Y2pKgrXSXP7rUiiCCIknotbUKtq7vF9uoUOB+f5kF2zGRRCJBu7n8PYg==", + "dependencies": { + "chalk": "^4.0.0", + "copy-dir": "^1.3.0", + "docker-compose": "^0.22.2", + "extract-zip": "^1.6.7", + "got": "^11.8.5", + "inquirer": "^7.1.0", + "js-yaml": "^3.13.1", + "ora": "^4.0.2", + "rimraf": "^3.0.2", + "simple-git": "^3.5.0", + "terminal-link": "^2.0.0", + "yargs": "^17.3.0" + }, + "bin": { + "wp-env": "bin/wp-env" + } + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/allure-js-commons": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-2.7.0.tgz", + "integrity": "sha512-pLXrTyBC4XQ+eH7sJEIOieAd4Rv32kElyQB8G5Ubvg2+fKsZIr0Hfy8qVZxwaHAQRlcOcvJ7OaY/UvICiky5MA==", + "dependencies": { + "properties": "^1.2.1", + "uuid": "^8.3.0" + } + }, + "node_modules/allure-playwright": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/allure-playwright/-/allure-playwright-2.7.0.tgz", + "integrity": "sha512-tMfSXcLPziv9pZu4QG3PqdmXSgMwinTJdcSNmzHwzAMpiG1tYoFj1Qj2Suq7nwe8SfkE6Ec0UWqr82r0VQzJ2A==", + "dependencies": { + "allure-js-commons": "2.7.0" + } + }, + "node_modules/ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "dependencies": { + "string-width": "^4.1.0" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-escapes/node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==", + "engines": { + "node": "*" + } + }, + "node_modules/boxen": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.0.tgz", + "integrity": "sha512-ScG8CDo8dj7McqCZ5hz4dIBp20xj4unQ2lXIDa7ff6RcZElCpuNzutdwzKVvRikfNjm7CFAlR3HJHcoHkDOExQ==", + "dev": true, + "dependencies": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/boxen/node_modules/chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/boxen/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/boxen/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/boxen/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/boxen/node_modules/type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/cacache": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", + "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==", + "engines": { + "node": ">=10.6.0" + } + }, + "node_modules/cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "dependencies": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "dependencies": { + "mimic-response": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "dependencies": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "node_modules/config-chain/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dev": true, + "dependencies": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/yeoman/configstore?sponsor=1" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/copy-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-1.3.0.tgz", + "integrity": "sha512-Q4+qBFnN4bwGwvtXXzbp4P/4iNk0MaiGAzvQ8OiMtlLjkIKjmNN689uVzShSM0908q7GoFHXIPx4zi75ocoaHw==" + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "dependencies": { + "type-fest": "^1.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/crypto-random-string/node_modules/type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decompress-response/node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "dependencies": { + "clone": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==", + "engines": { + "node": ">=10" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/docker-compose": { + "version": "0.22.2", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.22.2.tgz", + "integrity": "sha512-iXWb5+LiYmylIMFXvGTYsjI1F+Xyx78Jm/uj1dxwwZLbWkUdH6yOXY5Nr3RjbYX15EgbGJCq78d29CmWQQQMPg==", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "dependencies": { + "is-obj": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-playwright": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.16.0.tgz", + "integrity": "sha512-DcHpF0SLbNeh9MT4pMzUGuUSnJ7q5MWbP8sSEFIMS6j7Ggnduq8ghNlfhURgty4c1YFny7Ge9xYTO1FSAoV2Vw==", + "dev": true, + "peerDependencies": { + "eslint": ">=7", + "eslint-plugin-jest": ">=25" + }, + "peerDependenciesMeta": { + "eslint-plugin-jest": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "dependencies": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + } + }, + "node_modules/extract-zip/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/extract-zip/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/figures/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true, + "engines": { + "node": ">= 14.17" + } + }, + "node_modules/fp-and-or": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fp-and-or/-/fp-and-or-0.1.3.tgz", + "integrity": "sha512-wJaE62fLaB3jCYvY2ZHjZvmKK2iiLiiehX38rz5QZxtdN8fVPJDeZUiVvJrHStdTc+23LHlyZuSEKgFc0pxi2g==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", + "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", + "dev": true, + "dependencies": { + "minipass": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "10.2.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.7.tgz", + "integrity": "sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2", + "path-scurry": "^1.7.0" + }, + "bin": { + "glob": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minipass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", + "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "dependencies": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + }, + "engines": { + "node": ">=10.19.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "dependencies": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "dev": true, + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/jackspeak": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", + "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", + "dev": true, + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/json-parse-helpfulerror": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", + "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", + "dev": true, + "dependencies": { + "jju": "^1.1.0" + } + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonlines": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsonlines/-/jsonlines-0.1.1.tgz", + "integrity": "sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==", + "dev": true + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dev": true, + "dependencies": { + "package-json": "^8.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "dependencies": { + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/log-symbols/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-collect/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", + "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", + "dev": true, + "dependencies": { + "minipass": "^5.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "node_modules/mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "dependencies": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mysql/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/mysqlconnector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mysqlconnector/-/mysqlconnector-2.0.1.tgz", + "integrity": "sha512-yr00AuY4IpBIG0cIk1LrwJIUr+1LM2fnH13WFTHV6sTb4ATfI4/ZnEMy3Zb+dVii8TcUGZVbS+jM0wOv3GYupg==", + "dependencies": { + "mysql": "2.18.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-gyp": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", + "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^11.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^12.13 || ^14.13 || >=16" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "dependencies": { + "abbrev": "^1.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-check-updates": { + "version": "16.13.3", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.13.3.tgz", + "integrity": "sha512-l3FQtm+ZtDwqtK2r27vCuNdtnoDsXzk8D2WczvrAJy2bGPZJvRmuUa/Q9Gv+AbZV0IHSNJD2oHtQqUeqQRhEsw==", + "dev": true, + "dependencies": { + "chalk": "^5.3.0", + "cli-table3": "^0.6.3", + "commander": "^10.0.1", + "fast-memoize": "^2.5.2", + "find-up": "5.0.0", + "fp-and-or": "^0.1.3", + "get-stdin": "^8.0.0", + "globby": "^11.0.4", + "hosted-git-info": "^5.1.0", + "ini": "^4.1.1", + "js-yaml": "^4.1.0", + "json-parse-helpfulerror": "^1.0.3", + "jsonlines": "^0.1.1", + "lodash": "^4.17.21", + "make-fetch-happen": "^11.1.1", + "minimatch": "^9.0.3", + "p-map": "^4.0.0", + "pacote": "15.2.0", + "parse-github-url": "^1.0.2", + "progress": "^2.0.3", + "prompts-ncu": "^3.0.0", + "rc-config-loader": "^4.1.3", + "remote-git-tags": "^3.0.0", + "rimraf": "^5.0.1", + "semver": "^7.5.4", + "semver-utils": "^1.1.4", + "source-map-support": "^0.5.21", + "spawn-please": "^2.0.1", + "strip-json-comments": "^5.0.1", + "untildify": "^4.0.0", + "update-notifier": "^6.0.2" + }, + "bin": { + "ncu": "build/src/bin/cli.js", + "npm-check-updates": "build/src/bin/cli.js" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/npm-check-updates/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/npm-check-updates/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/npm-check-updates/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm-check-updates/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/npm-check-updates/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-check-updates/node_modules/rimraf": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", + "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", + "dev": true, + "dependencies": { + "glob": "^10.2.5" + }, + "bin": { + "rimraf": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm-check-updates/node_modules/strip-json-comments": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-install-checks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", + "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", + "dev": true, + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg/node_modules/hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "dependencies": { + "lru-cache": "^7.5.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "dependencies": { + "ignore-walk": "^6.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "dev": true, + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", + "dev": true, + "dependencies": { + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-4.1.1.tgz", + "integrity": "sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A==", + "dependencies": { + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.2.0", + "is-interactive": "^1.0.0", + "log-symbols": "^3.0.0", + "mute-stream": "0.0.8", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dev": true, + "dependencies": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/@sindresorhus/is": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.4.1.tgz", + "integrity": "sha512-axlrvsHlHlFmKKMEg4VyvMzFr93JWJj4eIfXY1STVuO2fsImCa7ncaiG5gC8HKOX590AW5RtRsC41/B+OfrSqw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/is?sponsor=1" + } + }, + "node_modules/package-json/node_modules/@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "dependencies": { + "defer-to-connect": "^2.0.1" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/package-json/node_modules/cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/package-json/node_modules/cacheable-request": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.10.tgz", + "integrity": "sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==", + "dev": true, + "dependencies": { + "@types/http-cache-semantics": "^4.0.1", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.2", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + } + }, + "node_modules/package-json/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "dependencies": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sindresorhus/got?sponsor=1" + } + }, + "node_modules/package-json/node_modules/http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "dependencies": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + }, + "engines": { + "node": ">=10.19.0" + } + }, + "node_modules/package-json/node_modules/lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/package-json/node_modules/p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true, + "engines": { + "node": ">=12.20" + } + }, + "node_modules/package-json/node_modules/responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "dependencies": { + "lowercase-keys": "^3.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pacote": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", + "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", + "dev": true, + "dependencies": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^5.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.3.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-github-url": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "dev": true, + "bin": { + "parse-github-url": "cli.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", + "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", + "dev": true, + "dependencies": { + "lru-cache": "^9.1.1", + "minipass": "^5.0.0 || ^6.0.2" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz", + "integrity": "sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==", + "dev": true, + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", + "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", + "dev": true, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" + }, + "node_modules/php-serialize": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/php-serialize/-/php-serialize-4.1.1.tgz", + "integrity": "sha512-7drCrSZdJ05UdG3hyYEIRW0XyKyUFkxa5A3dpIp3NTjUHpI080pkdBAvqaBtkA+kBkMeXX3XnaSnaLGJRz071A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "dependencies": { + "playwright-core": "1.38.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/prompts-ncu": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prompts-ncu/-/prompts-ncu-3.0.0.tgz", + "integrity": "sha512-qyz9UxZ5MlPKWVhWrCmSZ1ahm2GVYdjLb8og2sg0IPth1KRuhcggHGuijz0e41dkx35p1t1q3GRISGH7QGALFA==", + "dev": true, + "dependencies": { + "kleur": "^4.0.1", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/properties/-/properties-1.2.1.tgz", + "integrity": "sha512-qYNxyMj1JeW54i/EWEFsM1cVwxJbtgPp8+0Wg9XjNaK6VE/c4oRi6PNu5p7w1mNXEIQIjV5Wwn8v8Gz82/QzdQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dev": true, + "dependencies": { + "escape-goat": "^4.0.0" + }, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "dev": true, + "dependencies": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + } + }, + "node_modules/rc-config-loader/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/rc-config-loader/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/read-package-json": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "dev": true, + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "dependencies": { + "@pnpm/npm-conf": "^2.1.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "dependencies": { + "rc": "1.2.8" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/remote-git-tags": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", + "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "dependencies": { + "lowercase-keys": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/restore-cursor/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/rxjs/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/semver-utils": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/semver-utils/-/semver-utils-1.1.4.tgz", + "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==", + "dev": true + }, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", + "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sigstore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.7.0.tgz", + "integrity": "sha512-KP7QULhWdlu3hlp+jw2EvgWKlOGOY9McLj/jrchLjHNlNPK0KWIwF919cbmOp6QiKXLmPijR2qH/5KYWlbtG9Q==", + "dev": true, + "dependencies": { + "@sigstore/protobuf-specs": "^0.1.0", + "@sigstore/tuf": "^1.0.1", + "make-fetch-happen": "^11.0.1" + }, + "bin": { + "sigstore": "bin/sigstore.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/simple-git": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.20.0.tgz", + "integrity": "sha512-ozK8tl2hvLts8ijTs18iFruE+RoqmC/mqZhjs/+V7gS5W68JpJ3+FCTmLVqmR59MaUQ52MfGQuWsIqfsTbbJ0Q==", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spawn-please": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-2.0.1.tgz", + "integrity": "sha512-W+cFbZR2q2mMTfjz5ZGvhBAiX+e/zczFCNlbS9mxiSdYswBXwUuBUT+a0urH+xZZa8f/bs0mXHyZsZHR9hKogA==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "node_modules/sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ssri": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", + "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", + "dev": true, + "dependencies": { + "minipass": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "dependencies": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/tuf-js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", + "dev": true, + "dependencies": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "node_modules/typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "dependencies": { + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "dependencies": { + "crypto-random-string": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dev": true, + "dependencies": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/yeoman/update-notifier?sponsor=1" + } + }, + "node_modules/update-notifier/node_modules/chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "dependencies": { + "string-width": "^5.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/widest-line/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/widest-line/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/widest-line/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "node_modules/write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "dependencies": { + "sax": "^1.2.4" + }, + "bin": { + "xml-js": "bin/cli.js" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "dev": true, + "optional": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.0.tgz", + "integrity": "sha512-JylOEEzDiOryeUnFbQz+oViCXS0KsvR1mvHkoMiu5+UiBvy+RYX7tzlIIIEstF/gVa2tj9AQXk3dgnxv6KxhFg==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", + "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "@eslint/js": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", + "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", + "dev": true + }, + "@faker-js/faker": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.0.2.tgz", + "integrity": "sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==" + }, + "@humanwhocodes/config-array": { + "version": "0.11.11", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", + "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dev": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "requires": { + "debug": "^4.1.1" + } + }, + "@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-4.1.0.tgz", + "integrity": "sha512-9hwoB3gStVfa0N31ymBmrX+GuDGdVA/QWShZVqE0HK2Af+7QGGrCTbZia/SW0ImUTjTne7SP91qxDmtXvDHRPQ==", + "dev": true, + "requires": { + "@npmcli/promise-spawn": "^6.0.0", + "lru-cache": "^7.4.4", + "npm-pick-manifest": "^8.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^3.0.0" + }, + "dependencies": { + "which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dev": true, + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "dev": true + }, + "@npmcli/promise-spawn": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-6.0.2.tgz", + "integrity": "sha512-gGq0NJkIGSwdbUt4yhdF8ZrmkGKVz9vAdVzpOfnom+V8PLSmSOVhZwbNvZZS1EYcJN5hzzKBxmmVVAInM6HQLg==", + "dev": true, + "requires": { + "which": "^3.0.0" + }, + "dependencies": { + "which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@npmcli/run-script": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-6.0.2.tgz", + "integrity": "sha512-NCcr1uQo1k5U+SYlnIrbAh3cxy+OQT1VtqiAbxdymSlptbzBb62AjH2xXgjNCoP073hoa1CfCAcwoZ8k96C4nA==", + "dev": true, + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/promise-spawn": "^6.0.0", + "node-gyp": "^9.0.0", + "read-package-json-fast": "^3.0.0", + "which": "^3.0.0" + }, + "dependencies": { + "which": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-3.0.1.tgz", + "integrity": "sha512-XA1b62dzQzLfaEOSQFTCOd5KFf/1VSzZo7/7TUjnya6u0vGGKzU96UQBZTAThCb2j4/xjBAyii1OhRLJEivHvg==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "dev": true, + "optional": true + }, + "@playwright/test": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.38.1.tgz", + "integrity": "sha512-NqRp8XMwj3AK+zKLbZShl0r/9wKgzqI/527bkptKXomtuo+dOjU9NdMASQ8DNC9z9zLOMbG53T4eihYr3XR+BQ==", + "requires": { + "playwright": "1.38.1" + } + }, + "@pnpm/config.env-replace": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@pnpm/config.env-replace/-/config.env-replace-1.1.0.tgz", + "integrity": "sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==", + "dev": true + }, + "@pnpm/network.ca-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@pnpm/network.ca-file/-/network.ca-file-1.0.2.tgz", + "integrity": "sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==", + "dev": true, + "requires": { + "graceful-fs": "4.2.10" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + } + } + }, + "@pnpm/npm-conf": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/@pnpm/npm-conf/-/npm-conf-2.2.2.tgz", + "integrity": "sha512-UA91GwWPhFExt3IizW6bOeY/pQ0BkuNwKjk9iQW9KqxluGCrg4VenZ0/L+2Y0+ZOtme72EVvg6v0zo3AMQRCeA==", + "dev": true, + "requires": { + "@pnpm/config.env-replace": "^1.1.0", + "@pnpm/network.ca-file": "^1.0.1", + "config-chain": "^1.1.11" + } + }, + "@sigstore/protobuf-specs": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.1.0.tgz", + "integrity": "sha512-a31EnjuIDSX8IXBUib3cYLDRlPMU36AWX4xS8ysLaNu4ZzUesDiPt83pgrW2X1YLMe5L2HbDyaKK5BrL4cNKaQ==", + "dev": true + }, + "@sigstore/tuf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-1.0.2.tgz", + "integrity": "sha512-vjwcYePJzM01Ha6oWWZ9gNcdIgnzyFxfqfWzph483DPJTH8Tb7f7bQRRll3CYVkyH56j0AgcPAcl6Vg95DPF+Q==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.1.0", + "tuf-js": "^1.1.7" + } + }, + "@sindresorhus/is": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-4.6.0.tgz", + "integrity": "sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==" + }, + "@szmarczak/http-timer": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-4.0.6.tgz", + "integrity": "sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==", + "requires": { + "defer-to-connect": "^2.0.0" + } + }, + "@tootallnate/once": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", + "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", + "dev": true + }, + "@tufjs/canonical-json": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-1.0.0.tgz", + "integrity": "sha512-QTnf++uxunWvG2z3UFNzAoQPHxnSXOwtaI3iJ+AohhV+5vONuArPjJE7aPXPVXfXJsqrVbZBu9b81AJoSd09IQ==", + "dev": true + }, + "@tufjs/models": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-1.0.4.tgz", + "integrity": "sha512-qaGV9ltJP0EO25YfFUPhxRVK0evXFIAGicsVXuRim4Ed9cjPxYhNnNJ49SFmbeLgtxpslIkX317IgpfcHPVj/A==", + "dev": true, + "requires": { + "@tufjs/canonical-json": "1.0.0", + "minimatch": "^9.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@types/cacheable-request": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@types/cacheable-request/-/cacheable-request-6.0.3.tgz", + "integrity": "sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==", + "requires": { + "@types/http-cache-semantics": "*", + "@types/keyv": "^3.1.4", + "@types/node": "*", + "@types/responselike": "^1.0.0" + } + }, + "@types/http-cache-semantics": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.1.tgz", + "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" + }, + "@types/json-schema": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.12.tgz", + "integrity": "sha512-Hr5Jfhc9eYOQNPYO5WLDq/n4jqijdHNlDXjuAQkkt+mWdQR+XJToOHrsD4cPaMXpn6KO7y2+wM8AZEs8VpBLVA==", + "dev": true + }, + "@types/keyv": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@types/keyv/-/keyv-3.1.4.tgz", + "integrity": "sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==", + "requires": { + "@types/node": "*" + } + }, + "@types/node": { + "version": "20.8.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.2.tgz", + "integrity": "sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w==" + }, + "@types/responselike": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.1.tgz", + "integrity": "sha512-TiGnitEDxj2X0j+98Eqk5lv/Cij8oHd32bU4D/Yw6AOq7vvTk0gSD2GPj0G/HkvhMoVsdlhYF4yqqlyPBTM6Sg==", + "requires": { + "@types/node": "*" + } + }, + "@types/semver": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", + "integrity": "sha512-cJRQXpObxfNKkFAZbJl2yjWtJCqELQIdShsogr1d2MilP8dKD9TE/nEKHkJgUNHdGKCQaf9HbIynuV2csLGVLg==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.6.0.tgz", + "integrity": "sha512-CW9YDGTQnNYMIo5lMeuiIG08p4E0cXrXTbcZ2saT/ETE7dWUrNxlijsQeU04qAAKkILiLzdQz+cGFxCJjaZUmA==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.6.0", + "@typescript-eslint/type-utils": "6.6.0", + "@typescript-eslint/utils": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/parser": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.6.0.tgz", + "integrity": "sha512-setq5aJgUwtzGrhW177/i+DMLqBaJbdwGj2CPIVFFLE0NCliy5ujIdLHd2D1ysmlmsjdL2GWW+hR85neEfc12w==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "6.6.0", + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/typescript-estree": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.6.0.tgz", + "integrity": "sha512-pT08u5W/GT4KjPUmEtc2kSYvrH8x89cVzkA0Sy2aaOUIw6YxOIjA8ilwLr/1fLjOedX1QAuBpG9XggWqIIfERw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.6.0.tgz", + "integrity": "sha512-8m16fwAcEnQc69IpeDyokNO+D5spo0w1jepWWY2Q6y5ZKNuj5EhVQXjtVAeDDqvW6Yg7dhclbsz6rTtOvcwpHg==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "6.6.0", + "@typescript-eslint/utils": "6.6.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.6.0.tgz", + "integrity": "sha512-CB6QpJQ6BAHlJXdwUmiaXDBmTqIE2bzGTDLADgvqtHWuhfNP3rAOK7kAgRMAET5rDRr9Utt+qAzRBdu3AhR3sg==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.6.0.tgz", + "integrity": "sha512-hMcTQ6Al8MP2E6JKBAaSxSVw5bDhdmbCEhGW/V8QXkb9oNsFkA4SBuOMYVPxD3jbtQ4R/vSODBsr76R6fP3tbA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/visitor-keys": "6.6.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/utils": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.6.0.tgz", + "integrity": "sha512-mPHFoNa2bPIWWglWYdR0QfY9GN0CfvvXX1Sv6DlSTive3jlMTUy+an67//Gysc+0Me9pjitrq0LJp0nGtLgftw==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.6.0", + "@typescript-eslint/types": "6.6.0", + "@typescript-eslint/typescript-estree": "6.6.0", + "semver": "^7.5.4" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.6.0.tgz", + "integrity": "sha512-L61uJT26cMOfFQ+lMZKoJNbAEckLe539VhTxiGHrWl5XSKQgA0RTBZJW2HFPy5T0ZvPVSD93QsrTKDkfNwJGyQ==", + "dev": true, + "requires": { + "@typescript-eslint/types": "6.6.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "@wordpress/env": { + "version": "8.9.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-8.9.0.tgz", + "integrity": "sha512-f3W1OMcUubZVC4OH9MTG2XE2OWwZH3Y2pKgrXSXP7rUiiCCIknotbUKtq7vF9uoUOB+f5kF2zGRRCJBu7n8PYg==", + "requires": { + "chalk": "^4.0.0", + "copy-dir": "^1.3.0", + "docker-compose": "^0.22.2", + "extract-zip": "^1.6.7", + "got": "^11.8.5", + "inquirer": "^7.1.0", + "js-yaml": "^3.13.1", + "ora": "^4.0.2", + "rimraf": "^3.0.2", + "simple-git": "^3.5.0", + "terminal-link": "^2.0.0", + "yargs": "^17.3.0" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", + "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^2.0.0", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "allure-js-commons": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-2.7.0.tgz", + "integrity": "sha512-pLXrTyBC4XQ+eH7sJEIOieAd4Rv32kElyQB8G5Ubvg2+fKsZIr0Hfy8qVZxwaHAQRlcOcvJ7OaY/UvICiky5MA==", + "requires": { + "properties": "^1.2.1", + "uuid": "^8.3.0" + } + }, + "allure-playwright": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/allure-playwright/-/allure-playwright-2.7.0.tgz", + "integrity": "sha512-tMfSXcLPziv9pZu4QG3PqdmXSgMwinTJdcSNmzHwzAMpiG1tYoFj1Qj2Suq7nwe8SfkE6Ec0UWqr82r0VQzJ2A==", + "requires": { + "allure-js-commons": "2.7.0" + } + }, + "ansi-align": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", + "integrity": "sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==", + "dev": true, + "requires": { + "string-width": "^4.1.0" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + }, + "dependencies": { + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + } + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "bignumber.js": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.0.0.tgz", + "integrity": "sha512-t/OYhhJ2SD+YGBQcjY8GzzDHEk9f3nerxjtfa6tlMXfe7frs/WozhvCNoGvpM0P3bNf3Gq5ZRMlGr5f3r4/N8A==" + }, + "boxen": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-7.1.0.tgz", + "integrity": "sha512-ScG8CDo8dj7McqCZ5hz4dIBp20xj4unQ2lXIDa7ff6RcZElCpuNzutdwzKVvRikfNjm7CFAlR3HJHcoHkDOExQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.1", + "camelcase": "^7.0.1", + "chalk": "^5.2.0", + "cli-boxes": "^3.0.0", + "string-width": "^5.1.2", + "type-fest": "^2.13.0", + "widest-line": "^4.0.1", + "wrap-ansi": "^8.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "type-fest": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-2.19.0.tgz", + "integrity": "sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==", + "dev": true + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==" + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "requires": { + "semver": "^7.0.0" + } + }, + "cacache": { + "version": "17.1.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-17.1.3.tgz", + "integrity": "sha512-jAdjGxmPxZh0IipMdR7fK/4sDSrHMLUV0+GvVUsjwyGNKHsh79kW/otg+GkbXwl6Uzvy9wsvHOX4nUoWldeZMg==", + "dev": true, + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + } + }, + "cacheable-lookup": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-5.0.4.tgz", + "integrity": "sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==" + }, + "cacheable-request": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-7.0.4.tgz", + "integrity": "sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==", + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^4.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^6.0.1", + "responselike": "^2.0.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-7.0.1.tgz", + "integrity": "sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, + "cli-boxes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-3.0.0.tgz", + "integrity": "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==", + "dev": true + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.0.tgz", + "integrity": "sha512-4/aL9X3Wh0yiMQlE+eeRhWP6vclO3QRtw1JHKIT0FFUs5FjpFmESqtMvYZ0+lbzBw900b95mS0hohy+qn2VK/g==" + }, + "cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "dev": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "cli-width": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", + "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==" + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==" + }, + "clone-response": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.3.tgz", + "integrity": "sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==", + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "commander": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz", + "integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "config-chain": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.13.tgz", + "integrity": "sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + } + } + }, + "configstore": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-6.0.0.tgz", + "integrity": "sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==", + "dev": true, + "requires": { + "dot-prop": "^6.0.1", + "graceful-fs": "^4.2.6", + "unique-string": "^3.0.0", + "write-file-atomic": "^3.0.3", + "xdg-basedir": "^5.0.1" + } + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "copy-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/copy-dir/-/copy-dir-1.3.0.tgz", + "integrity": "sha512-Q4+qBFnN4bwGwvtXXzbp4P/4iNk0MaiGAzvQ8OiMtlLjkIKjmNN689uVzShSM0908q7GoFHXIPx4zi75ocoaHw==" + }, + "core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-random-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-4.0.0.tgz", + "integrity": "sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==", + "dev": true, + "requires": { + "type-fest": "^1.0.1" + }, + "dependencies": { + "type-fest": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-1.4.0.tgz", + "integrity": "sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==", + "dev": true + } + } + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "requires": { + "mimic-response": "^3.1.0" + }, + "dependencies": { + "mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" + } + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "defaults": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", + "integrity": "sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==", + "requires": { + "clone": "^1.0.2" + } + }, + "defer-to-connect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-2.0.1.tgz", + "integrity": "sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==" + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "docker-compose": { + "version": "0.22.2", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.22.2.tgz", + "integrity": "sha512-iXWb5+LiYmylIMFXvGTYsjI1F+Xyx78Jm/uj1dxwwZLbWkUdH6yOXY5Nr3RjbYX15EgbGJCq78d29CmWQQQMPg==" + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dot-prop": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-6.0.1.tgz", + "integrity": "sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-goat": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-4.0.0.tgz", + "integrity": "sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "8.49.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", + "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.2", + "@eslint/js": "8.49.0", + "@humanwhocodes/config-array": "^0.11.11", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "eslint-config-prettier": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.0.0.tgz", + "integrity": "sha512-IcJsTkJae2S35pRsRAwoCE+925rJJStOdkKnLVgtE+tEpqU0EVVM7OqrwxqgptKdX29NUwC82I5pXsGFIgSevw==", + "dev": true, + "requires": {} + }, + "eslint-plugin-playwright": { + "version": "0.16.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.16.0.tgz", + "integrity": "sha512-DcHpF0SLbNeh9MT4pMzUGuUSnJ7q5MWbP8sSEFIMS6j7Ggnduq8ghNlfhURgty4c1YFny7Ge9xYTO1FSAoV2Vw==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==", + "dev": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extract-zip": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", + "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "requires": { + "concat-stream": "^1.6.2", + "debug": "^2.6.9", + "mkdirp": "^0.5.4", + "yauzl": "^2.10.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-memoize": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/fast-memoize/-/fast-memoize-2.5.2.tgz", + "integrity": "sha512-Ue0LwpDYErFbmNnZSF0UH6eImUwDmogUO1jyE+JbN2gsQz/jICm1Ve7t9QT0rNSsfJt+Hs4/S3GnsDVjL4HVrw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + } + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, + "form-data-encoder": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz", + "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==", + "dev": true + }, + "fp-and-or": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/fp-and-or/-/fp-and-or-0.1.3.tgz", + "integrity": "sha512-wJaE62fLaB3jCYvY2ZHjZvmKK2iiLiiehX38rz5QZxtdN8fVPJDeZUiVvJrHStdTc+23LHlyZuSEKgFc0pxi2g==", + "dev": true + }, + "fs-minipass": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.2.tgz", + "integrity": "sha512-2GAfyfoaCDRrM6jaOS3UsBts8yJ55VioXdWcOL7dK9zdAuKT71+WBA4ifnNYqVjYv+4SsPxjK0JT4yIIn4cA/g==", + "dev": true, + "requires": { + "minipass": "^5.0.0" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + } + } + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-stdin": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-8.0.0.tgz", + "integrity": "sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg==", + "dev": true + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "requires": { + "pump": "^3.0.0" + } + }, + "glob": { + "version": "10.2.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.2.7.tgz", + "integrity": "sha512-jTKehsravOJo8IJxUGfZILnkvVJM/MOfHRs8QcXolVef2zNI9Tqyy5+SeuOAZd3upViEZQLyFpQhYiHLrMUNmA==", + "dev": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.0.3", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2", + "path-scurry": "^1.7.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.1.tgz", + "integrity": "sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "minipass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", + "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", + "dev": true + } + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "dev": true, + "requires": { + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "dev": true + } + } + }, + "globals": { + "version": "13.21.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", + "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "got": { + "version": "11.8.6", + "resolved": "https://registry.npmjs.org/got/-/got-11.8.6.tgz", + "integrity": "sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==", + "requires": { + "@sindresorhus/is": "^4.0.0", + "@szmarczak/http-timer": "^4.0.5", + "@types/cacheable-request": "^6.0.1", + "@types/responselike": "^1.0.0", + "cacheable-lookup": "^5.0.3", + "cacheable-request": "^7.0.2", + "decompress-response": "^6.0.0", + "http2-wrapper": "^1.0.0-beta.5.2", + "lowercase-keys": "^2.0.0", + "p-cancelable": "^2.0.0", + "responselike": "^2.0.0" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "has-yarn": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-3.0.0.tgz", + "integrity": "sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==", + "dev": true + }, + "hosted-git-info": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", + "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "http-proxy-agent": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", + "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", + "dev": true, + "requires": { + "@tootallnate/once": "2", + "agent-base": "6", + "debug": "4" + } + }, + "http2-wrapper": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-1.0.3.tgz", + "integrity": "sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==", + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.0.0" + } + }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "ignore-walk": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "dev": true, + "requires": { + "minimatch": "^9.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-lazy": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", + "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true + }, + "inquirer": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", + "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", + "requires": { + "ansi-escapes": "^4.2.1", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-width": "^3.0.0", + "external-editor": "^3.0.3", + "figures": "^3.0.0", + "lodash": "^4.17.19", + "mute-stream": "0.0.8", + "run-async": "^2.4.0", + "rxjs": "^6.6.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0", + "through": "^2.3.6" + } + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "dev": true, + "requires": { + "ci-info": "^3.2.0" + } + }, + "is-core-module": { + "version": "2.13.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", + "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "dev": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "is-npm": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-6.0.0.tgz", + "integrity": "sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "is-yarn-global": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.4.1.tgz", + "integrity": "sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "jackspeak": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.2.1.tgz", + "integrity": "sha512-MXbxovZ/Pm42f6cDIDkl3xpwv1AGwObKwfmjs2nQePiy85tP3fatofl3FC1aBsOtP/6fq5SbtgHwWcMsLP+bDw==", + "dev": true, + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "jju": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/jju/-/jju-1.4.0.tgz", + "integrity": "sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" + }, + "json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "dev": true + }, + "json-parse-helpfulerror": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/json-parse-helpfulerror/-/json-parse-helpfulerror-1.0.3.tgz", + "integrity": "sha512-XgP0FGR77+QhUxjXkwOMkC94k3WtqEBfcnjWqhRd82qTat4SWKRE+9kUnynz/shm3I4ea2+qISvTIeGTNU7kJg==", + "dev": true, + "requires": { + "jju": "^1.1.0" + } + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "jsonlines": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsonlines/-/jsonlines-0.1.1.tgz", + "integrity": "sha512-ekDrAGso79Cvf+dtm+mL8OBI2bmAOt3gssYs833De/C9NmIpWDWyUO4zPgB5x2/OhY366dkhgfPMYfwZF7yOZA==", + "dev": true + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true + }, + "keyv": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.2.tgz", + "integrity": "sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==", + "requires": { + "json-buffer": "3.0.1" + } + }, + "kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true + }, + "latest-version": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-7.0.0.tgz", + "integrity": "sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==", + "dev": true, + "requires": { + "package-json": "^8.1.0" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "log-symbols": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz", + "integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==", + "requires": { + "chalk": "^2.4.2" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==" + }, + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true + }, + "make-fetch-happen": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-11.1.1.tgz", + "integrity": "sha512-rLWS7GCSTcEujjVBs2YqG7Y4643u8ucvCJeSRqiLYhesrDuzeuFIk37xREzAsfQaqzl8b9rNCE4m6J8tvX4Q8w==", + "dev": true, + "requires": { + "agentkeepalive": "^4.2.1", + "cacache": "^17.0.0", + "http-cache-semantics": "^4.1.1", + "http-proxy-agent": "^5.0.0", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^7.7.1", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^7.0.0", + "ssri": "^10.0.0" + } + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "dev": true + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-fetch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.3.tgz", + "integrity": "sha512-n5ITsTkDqYkYJZjcRWzZt9qnZKCT7nKCosJhHoj7S7zD+BP4jVbWs+odsniw5TA3E0sLomhTKOKjF86wf11PuQ==", + "dev": true, + "requires": { + "encoding": "^0.1.13", + "minipass": "^5.0.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "requires": { + "minimist": "^1.2.6" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==" + }, + "mysql": { + "version": "2.18.1", + "resolved": "https://registry.npmjs.org/mysql/-/mysql-2.18.1.tgz", + "integrity": "sha512-Bca+gk2YWmqp2Uf6k5NFEurwY/0td0cpebAucFpY/3jhrwrVGuxU2uQFCHjU19SJfje0yQvi+rVWdq78hR5lig==", + "requires": { + "bignumber.js": "9.0.0", + "readable-stream": "2.3.7", + "safe-buffer": "5.1.2", + "sqlstring": "2.3.1" + }, + "dependencies": { + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + } + } + }, + "mysqlconnector": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mysqlconnector/-/mysqlconnector-2.0.1.tgz", + "integrity": "sha512-yr00AuY4IpBIG0cIk1LrwJIUr+1LM2fnH13WFTHV6sTb4ATfI4/ZnEMy3Zb+dVii8TcUGZVbS+jM0wOv3GYupg==", + "requires": { + "mysql": "2.18.1" + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true + }, + "node-gyp": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.4.0.tgz", + "integrity": "sha512-dMXsYP6gc9rRbejLXmTbVRYjAHw7ppswsKyMxuxJxxOHzluIO1rGp9TOQgjFJ+2MCqcOcQTOPB/8Xwhr+7s4Eg==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^11.0.3", + "nopt": "^6.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "nopt": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", + "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, + "requires": { + "abbrev": "^1.0.0" + } + }, + "normalize-package-data": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-5.0.0.tgz", + "integrity": "sha512-h9iPVIfrVZ9wVYQnxFgtw1ugSvGEMOlyPWWtm8BMJhnwyEL/FLbYbTY3V3PpjI/BUK67n9PEWDu6eHzu1fB15Q==", + "dev": true, + "requires": { + "hosted-git-info": "^6.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "dependencies": { + "hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + } + } + }, + "normalize-url": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz", + "integrity": "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==" + }, + "npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dev": true, + "requires": { + "npm-normalize-package-bin": "^3.0.0" + } + }, + "npm-check-updates": { + "version": "16.13.3", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.13.3.tgz", + "integrity": "sha512-l3FQtm+ZtDwqtK2r27vCuNdtnoDsXzk8D2WczvrAJy2bGPZJvRmuUa/Q9Gv+AbZV0IHSNJD2oHtQqUeqQRhEsw==", + "dev": true, + "requires": { + "chalk": "^5.3.0", + "cli-table3": "^0.6.3", + "commander": "^10.0.1", + "fast-memoize": "^2.5.2", + "find-up": "5.0.0", + "fp-and-or": "^0.1.3", + "get-stdin": "^8.0.0", + "globby": "^11.0.4", + "hosted-git-info": "^5.1.0", + "ini": "^4.1.1", + "js-yaml": "^4.1.0", + "json-parse-helpfulerror": "^1.0.3", + "jsonlines": "^0.1.1", + "lodash": "^4.17.21", + "make-fetch-happen": "^11.1.1", + "minimatch": "^9.0.3", + "p-map": "^4.0.0", + "pacote": "15.2.0", + "parse-github-url": "^1.0.2", + "progress": "^2.0.3", + "prompts-ncu": "^3.0.0", + "rc-config-loader": "^4.1.3", + "remote-git-tags": "^3.0.0", + "rimraf": "^5.0.1", + "semver": "^7.5.4", + "semver-utils": "^1.1.4", + "source-map-support": "^0.5.21", + "spawn-please": "^2.0.1", + "strip-json-comments": "^5.0.1", + "untildify": "^4.0.0", + "update-notifier": "^6.0.2" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "rimraf": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.1.tgz", + "integrity": "sha512-OfFZdwtd3lZ+XZzYP/6gTACubwFcHdLRqS9UX3UwpU2dnGQYkPFISRwvM3w9IiB2w7bW5qGo/uAwE4SmXXSKvg==", + "dev": true, + "requires": { + "glob": "^10.2.5" + } + }, + "strip-json-comments": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-5.0.1.tgz", + "integrity": "sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==", + "dev": true + } + } + }, + "npm-install-checks": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.1.1.tgz", + "integrity": "sha512-dH3GmQL4vsPtld59cOn8uY0iOqRmqKvV+DLGwNXV/Q7MDgD2QfOADWd/mFXcIE5LVhYYGjA3baz6W9JneqnuCw==", + "dev": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "dev": true + }, + "npm-package-arg": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-10.1.0.tgz", + "integrity": "sha512-uFyyCEmgBfZTtrKk/5xDfHp6+MdrqGotX/VoOyEEl3mBwiEE5FlBaePanazJSVMPT7vKepcjYBY2ztg9A3yPIA==", + "dev": true, + "requires": { + "hosted-git-info": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-6.1.1.tgz", + "integrity": "sha512-r0EI+HBMcXadMrugk0GCQ+6BQV39PiWAZVfq7oIckeGiN7sjRGyQxPdft3nQekFTCQbYxLBH+/axZMeH8UX6+w==", + "dev": true, + "requires": { + "lru-cache": "^7.5.1" + } + } + } + }, + "npm-packlist": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-7.0.4.tgz", + "integrity": "sha512-d6RGEuRrNS5/N84iglPivjaJPxhDbZmlbTwTDX2IbcRHG5bZCdtysYMhwiPvcF4GisXHGn7xsxv+GQ7T/02M5Q==", + "dev": true, + "requires": { + "ignore-walk": "^6.0.0" + } + }, + "npm-pick-manifest": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-8.0.1.tgz", + "integrity": "sha512-mRtvlBjTsJvfCCdmPtiu2bdlx8d/KXtF7yNXNWe7G0Z36qWA9Ny5zXsI2PfBZEv7SXgoxTmNaTzGSbbzDZChoA==", + "dev": true, + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^10.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "14.0.5", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-14.0.5.tgz", + "integrity": "sha512-kIDMIo4aBm6xg7jOttupWZamsZRkAqMqwqqbVXnUqstY5+tapvv6bkH/qMR76jdgV+YljEUCyWx3hRYMrJiAgA==", + "dev": true, + "requires": { + "make-fetch-happen": "^11.0.0", + "minipass": "^5.0.0", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^10.0.0", + "proc-log": "^3.0.0" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "ora": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-4.1.1.tgz", + "integrity": "sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A==", + "requires": { + "chalk": "^3.0.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.2.0", + "is-interactive": "^1.0.0", + "log-symbols": "^3.0.0", + "mute-stream": "0.0.8", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + } + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, + "p-cancelable": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-2.1.1.tgz", + "integrity": "sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==" + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "package-json": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-8.1.1.tgz", + "integrity": "sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==", + "dev": true, + "requires": { + "got": "^12.1.0", + "registry-auth-token": "^5.0.1", + "registry-url": "^6.0.0", + "semver": "^7.3.7" + }, + "dependencies": { + "@sindresorhus/is": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.4.1.tgz", + "integrity": "sha512-axlrvsHlHlFmKKMEg4VyvMzFr93JWJj4eIfXY1STVuO2fsImCa7ncaiG5gC8HKOX590AW5RtRsC41/B+OfrSqw==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-5.0.1.tgz", + "integrity": "sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==", + "dev": true, + "requires": { + "defer-to-connect": "^2.0.1" + } + }, + "cacheable-lookup": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", + "integrity": "sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==", + "dev": true + }, + "cacheable-request": { + "version": "10.2.10", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-10.2.10.tgz", + "integrity": "sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==", + "dev": true, + "requires": { + "@types/http-cache-semantics": "^4.0.1", + "get-stream": "^6.0.1", + "http-cache-semantics": "^4.1.1", + "keyv": "^4.5.2", + "mimic-response": "^4.0.0", + "normalize-url": "^8.0.0", + "responselike": "^3.0.0" + } + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "got": { + "version": "12.6.1", + "resolved": "https://registry.npmjs.org/got/-/got-12.6.1.tgz", + "integrity": "sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==", + "dev": true, + "requires": { + "@sindresorhus/is": "^5.2.0", + "@szmarczak/http-timer": "^5.0.1", + "cacheable-lookup": "^7.0.0", + "cacheable-request": "^10.2.8", + "decompress-response": "^6.0.0", + "form-data-encoder": "^2.1.2", + "get-stream": "^6.0.1", + "http2-wrapper": "^2.1.10", + "lowercase-keys": "^3.0.0", + "p-cancelable": "^3.0.0", + "responselike": "^3.0.0" + } + }, + "http2-wrapper": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/http2-wrapper/-/http2-wrapper-2.2.0.tgz", + "integrity": "sha512-kZB0wxMo0sh1PehyjJUWRFEd99KC5TLjZ2cULC4f9iqJBAmKQQXEICjxl5iPJRwP40dpeHFqqhm7tYCvODpqpQ==", + "dev": true, + "requires": { + "quick-lru": "^5.1.1", + "resolve-alpn": "^1.2.0" + } + }, + "lowercase-keys": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-3.0.0.tgz", + "integrity": "sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==", + "dev": true + }, + "mimic-response": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-4.0.0.tgz", + "integrity": "sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==", + "dev": true + }, + "normalize-url": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", + "integrity": "sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==", + "dev": true + }, + "p-cancelable": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz", + "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==", + "dev": true + }, + "responselike": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-3.0.0.tgz", + "integrity": "sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==", + "dev": true, + "requires": { + "lowercase-keys": "^3.0.0" + } + } + } + }, + "pacote": { + "version": "15.2.0", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-15.2.0.tgz", + "integrity": "sha512-rJVZeIwHTUta23sIZgEIM62WYwbmGbThdbnkt81ravBplQv+HjyroqnLRNH2+sLJHcGZmLRmhPwACqhfTcOmnA==", + "dev": true, + "requires": { + "@npmcli/git": "^4.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^6.0.1", + "@npmcli/run-script": "^6.0.0", + "cacache": "^17.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^5.0.0", + "npm-package-arg": "^10.0.0", + "npm-packlist": "^7.0.0", + "npm-pick-manifest": "^8.0.0", + "npm-registry-fetch": "^14.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^6.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^1.3.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-github-url": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-github-url/-/parse-github-url-1.0.2.tgz", + "integrity": "sha512-kgBf6avCbO3Cn6+RnzRGLkUsv4ZVqv/VfAYkRsyBcgkshNvVBkRn1FEZcW0Jb+npXQWm2vHPnnOqFteZxRRGNw==", + "dev": true + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-scurry": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.9.2.tgz", + "integrity": "sha512-qSDLy2aGFPm8i4rsbHd4MNyTcrzHFsLQykrtbuGRknZZCBBVXSv2tSCDN2Cg6Rt/GFRw8GoW9y9Ecw5rIPG1sg==", + "dev": true, + "requires": { + "lru-cache": "^9.1.1", + "minipass": "^5.0.0 || ^6.0.2" + }, + "dependencies": { + "lru-cache": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-9.1.2.tgz", + "integrity": "sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ==", + "dev": true + }, + "minipass": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-6.0.2.tgz", + "integrity": "sha512-MzWSV5nYVT7mVyWCwn2o7JH13w2TBRmmSqSRCKzTw+lmft9X4z+3wjvs06Tzijo5z4W/kahUCDpRXTF+ZrmF/w==", + "dev": true + } + } + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" + }, + "php-serialize": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/php-serialize/-/php-serialize-4.1.1.tgz", + "integrity": "sha512-7drCrSZdJ05UdG3hyYEIRW0XyKyUFkxa5A3dpIp3NTjUHpI080pkdBAvqaBtkA+kBkMeXX3XnaSnaLGJRz071A==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "playwright": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.38.1.tgz", + "integrity": "sha512-oRMSJmZrOu1FP5iu3UrCx8JEFRIMxLDM0c/3o4bpzU5Tz97BypefWf7TuTNPWeCe279TPal5RtPPZ+9lW/Qkow==", + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.38.1" + } + }, + "playwright-core": { + "version": "1.38.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.38.1.tgz", + "integrity": "sha512-tQqNFUKa3OfMf4b2jQ7aGLB8o9bS3bOY0yMEtldtC2+spf8QXG9zvXLTXUeRsoNuxEYMgLYR+NXfAa1rjKRcrg==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.3.tgz", + "integrity": "sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==", + "dev": true + }, + "proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "prompts-ncu": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prompts-ncu/-/prompts-ncu-3.0.0.tgz", + "integrity": "sha512-qyz9UxZ5MlPKWVhWrCmSZ1ahm2GVYdjLb8og2sg0IPth1KRuhcggHGuijz0e41dkx35p1t1q3GRISGH7QGALFA==", + "dev": true, + "requires": { + "kleur": "^4.0.1", + "sisteransi": "^1.0.5" + } + }, + "properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/properties/-/properties-1.2.1.tgz", + "integrity": "sha512-qYNxyMj1JeW54i/EWEFsM1cVwxJbtgPp8+0Wg9XjNaK6VE/c4oRi6PNu5p7w1mNXEIQIjV5Wwn8v8Gz82/QzdQ==" + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "pupa": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-3.1.0.tgz", + "integrity": "sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==", + "dev": true, + "requires": { + "escape-goat": "^4.0.0" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "quick-lru": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz", + "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==" + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true + } + } + }, + "rc-config-loader": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.3.tgz", + "integrity": "sha512-kD7FqML7l800i6pS6pvLyIE2ncbk9Du8Q0gp/4hMPhJU6ZxApkoLcGD8ZeqgiAlfwZ6BlETq6qqe+12DUL207w==", + "dev": true, + "requires": { + "debug": "^4.3.4", + "js-yaml": "^4.1.0", + "json5": "^2.2.2", + "require-from-string": "^2.0.2" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "read-package-json": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-6.0.4.tgz", + "integrity": "sha512-AEtWXYfopBj2z5N5PbkAOeNHRPUg5q+Nen7QLxV8M2zJq1ym6/lCz3fYNTCXe19puu2d06jfHhrP7v/S2PtMMw==", + "dev": true, + "requires": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^5.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dev": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "registry-auth-token": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-5.0.2.tgz", + "integrity": "sha512-o/3ikDxtXaA59BmZuZrJZDJv8NMDGSj+6j6XaeBmHw8eY1i1qd9+6H+LjVvQXx3HN6aRCGa1cUdJ9RaJZUugnQ==", + "dev": true, + "requires": { + "@pnpm/npm-conf": "^2.1.0" + } + }, + "registry-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-6.0.1.tgz", + "integrity": "sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==", + "dev": true, + "requires": { + "rc": "1.2.8" + } + }, + "remote-git-tags": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", + "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", + "dev": true + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "resolve-alpn": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/resolve-alpn/-/resolve-alpn-1.2.1.tgz", + "integrity": "sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==" + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "responselike": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-2.0.1.tgz", + "integrity": "sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==", + "requires": { + "lowercase-keys": "^2.0.0" + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + } + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + } + } + }, + "run-async": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", + "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "requires": { + "tslib": "^1.9.0" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" + } + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "semver-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-4.0.0.tgz", + "integrity": "sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==", + "dev": true, + "requires": { + "semver": "^7.3.5" + } + }, + "semver-utils": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/semver-utils/-/semver-utils-1.1.4.tgz", + "integrity": "sha512-EjnoLE5OGmDAVV/8YDoN5KiajNadjzIp9BAHOhYeQHt7j0UWxjmgsx4YD48wp4Ue1Qogq38F1GNUJNqF1kKKxA==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "signal-exit": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.0.2.tgz", + "integrity": "sha512-MY2/qGx4enyjprQnFaZsHib3Yadh3IXyV2C321GY0pjGfVBu4un0uDJkwgdxqO+Rdx8JMT8IfJIRwbYVz3Ob3Q==", + "dev": true + }, + "sigstore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-1.7.0.tgz", + "integrity": "sha512-KP7QULhWdlu3hlp+jw2EvgWKlOGOY9McLj/jrchLjHNlNPK0KWIwF919cbmOp6QiKXLmPijR2qH/5KYWlbtG9Q==", + "dev": true, + "requires": { + "@sigstore/protobuf-specs": "^0.1.0", + "@sigstore/tuf": "^1.0.1", + "make-fetch-happen": "^11.0.1" + } + }, + "simple-git": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.20.0.tgz", + "integrity": "sha512-ozK8tl2hvLts8ijTs18iFruE+RoqmC/mqZhjs/+V7gS5W68JpJ3+FCTmLVqmR59MaUQ52MfGQuWsIqfsTbbJ0Q==", + "requires": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.4" + } + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "spawn-please": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/spawn-please/-/spawn-please-2.0.1.tgz", + "integrity": "sha512-W+cFbZR2q2mMTfjz5ZGvhBAiX+e/zczFCNlbS9mxiSdYswBXwUuBUT+a0urH+xZZa8f/bs0mXHyZsZHR9hKogA==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3" + } + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" + }, + "sqlstring": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.1.tgz", + "integrity": "sha512-ooAzh/7dxIG5+uDik1z/Rd1vli0+38izZhGzSa34FwR7IbelPWCCKSNIl8jlL/F7ERvy8CB2jNeM1E9i9mXMAQ==" + }, + "ssri": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.4.tgz", + "integrity": "sha512-12+IR2CB2C28MMAw0Ncqwj5QbTcs0nGIhgJzYWzDkb21vWmfNI83KS4f3Ci6GI98WreIfG7o9UXp3C0qbpA8nQ==", + "dev": true, + "requires": { + "minipass": "^5.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + }, + "supports-hyperlinks": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", + "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "requires": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + } + }, + "tar": { + "version": "6.1.15", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.15.tgz", + "integrity": "sha512-/zKt9UyngnxIT/EAGYuxaMYgOIJiP81ab9ZfkILq4oNLPFX50qyYmu7jRj9qeXoxmJHjGlbH0+cm2uy1WCs10A==", + "dev": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "terminal-link": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", + "integrity": "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==", + "requires": { + "ansi-escapes": "^4.2.1", + "supports-hyperlinks": "^2.0.0" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "requires": {} + }, + "tuf-js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-1.1.7.tgz", + "integrity": "sha512-i3P9Kgw3ytjELUfpuKVDNBJvk4u5bXL6gskv572mcevPbSKCV3zt3djhmlEQ65yERjIbOSncy7U4cQJaB1CBCg==", + "dev": true, + "requires": { + "@tufjs/models": "1.0.4", + "debug": "^4.3.4", + "make-fetch-happen": "^11.1.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true + }, + "unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dev": true, + "requires": { + "unique-slug": "^4.0.0" + } + }, + "unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-string": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-3.0.0.tgz", + "integrity": "sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==", + "dev": true, + "requires": { + "crypto-random-string": "^4.0.0" + } + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true + }, + "update-notifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-6.0.2.tgz", + "integrity": "sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==", + "dev": true, + "requires": { + "boxen": "^7.0.0", + "chalk": "^5.0.1", + "configstore": "^6.0.0", + "has-yarn": "^3.0.0", + "import-lazy": "^4.0.0", + "is-ci": "^3.0.1", + "is-installed-globally": "^0.4.0", + "is-npm": "^6.0.0", + "is-yarn-global": "^0.4.0", + "latest-version": "^7.0.0", + "pupa": "^3.1.0", + "semver": "^7.3.7", + "semver-diff": "^4.0.0", + "xdg-basedir": "^5.1.0" + }, + "dependencies": { + "chalk": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", + "integrity": "sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==", + "dev": true + } + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dev": true, + "requires": { + "builtins": "^5.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==", + "requires": { + "defaults": "^1.0.3" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "widest-line": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-4.0.1.tgz", + "integrity": "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==", + "dev": true, + "requires": { + "string-width": "^5.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dev": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "dev": true + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dev": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + }, + "dependencies": { + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + } + } + }, + "xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true + }, + "xml-js": { + "version": "1.6.11", + "resolved": "https://registry.npmjs.org/xml-js/-/xml-js-1.6.11.tgz", + "integrity": "sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==", + "requires": { + "sax": "^1.2.4" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/tests/pw/package.json b/tests/pw/package.json new file mode 100644 index 0000000000..e036379ae9 --- /dev/null +++ b/tests/pw/package.json @@ -0,0 +1,71 @@ +{ + "name": "dokan_e2e_api_automation_playwright", + "version": "1.0.0", + "description": "dokan e2e & api endpoints test automation using playwright", + "main": "index.js", + "scripts": { + "nip": "npm install --omit=dev", + "nid": "npm install --include=dev", + "pw:chrome-only": "playwright install chromium", + "pw:browser-with-deps": "playwright install --with-deps chromium", + "pw:deps-only": "playwright install-deps chromium", + "test": "npx playwright test", + "test:site_setup": "npx playwright test --project=site_setup", + "test:api": "npx playwright test --project=api_tests --config=api.config.ts ", + "test:e2e": "npx playwright test --project=e2e_tests --config=e2e.config.ts ", + "test:e2e-i": "npx playwright test --project=e2e_tests --headed", + "test:e2e:lite": "npx playwright test --project=e2e_tests --grep '@lite|@liteOnly' --grep-invert @pro --config=e2e.config.ts ", + "test:api:lite": "npx playwright test --project=api_tests --grep '@lite|@liteOnly' --grep-invert @pro --config=api.config.ts ", + "test:e2e:lite:explo": "npx playwright test --project=e2e_tests --grep '(?=.*@lite)(?=.*@explo)' --config=e2e.config.ts ", + "test:api:pro": "npx playwright test --project=api_tests --grep '@lite|@pro' --grep-invert @liteOnly --config=api.config.ts ", + "test:e2e:pro": "npx playwright test --project=e2e_tests --grep '@lite|@pro' --grep-invert @liteOnly --config=e2e.config.ts ", + "test:e2e:explo": "npx playwright test --project=e2e_tests --grep @explo --config=e2e.config.ts ", + "test:grep": "npx playwright test --grep", + "test:debug": "npx playwright test --debug", + "test:codegen": "playwright codegen", + "test:report": "npx playwright show-report", + "test:trace": "npx playwright show-trace trace.zip", + "allure:generate": "allure generate playwright-report/allure-report -o allure-report --clean", + "allure:open": "allure open allure-report", + "start:env": "wp-env start", + "update:env": "wp-env start -- --update", + "stop:env": "wp-env stop", + "restart:env": "wp-env start", + "reset:db": "wp-env clean all && wp-env start", + "reset:env": "wp-env destroy && wp-env start", + "container:path": "wp-env install-path", + "activate:theme": "wp-env run tests-cli wp theme activate storefront", + "set:post-permalink": "wp-env run tests-cli wp rewrite structure /%postname%/", + "htaccess": "wp-env run tests-cli 'ls -la'", + "user-list": "wp-env run tests-cli 'wp user list'", + "wp-env": "wp-env", + "docker:testDbPort": "docker ps -f ancestor='mariadb' -f name='tests-mysql' --format='{{.Ports}}'", + "lint": "eslint .", + "lint:fix": "eslint . --fix", + "prettier": "prettier . --check", + "prettier:fix": "prettier . --write" + }, + "keywords": [], + "author": "", + "license": "ISC", + "devDependencies": { + "@typescript-eslint/eslint-plugin": "^6.6.0", + "@typescript-eslint/parser": "^6.6.0", + "eslint": "^8.49.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-playwright": "^0.16.0", + "npm-check-updates": "^16.13.3", + "prettier": "^3.0.3", + "typescript": "^5.2.2" + }, + "dependencies": { + "@faker-js/faker": "^8.0.2", + "@playwright/test": "^1.38.1", + "@wordpress/env": "^8.9.0", + "allure-playwright": "^2.7.0", + "dotenv": "^16.3.1", + "mysqlconnector": "^2.0.1", + "php-serialize": "^4.1.1", + "xml-js": "^1.6.11" + } +} diff --git a/tests/pw/pages/abuseReportsPage.ts b/tests/pw/pages/abuseReportsPage.ts new file mode 100644 index 0000000000..5d47627075 --- /dev/null +++ b/tests/pw/pages/abuseReportsPage.ts @@ -0,0 +1,110 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; +import { product } from '@utils/interfaces'; + +export class AbuseReportsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // abuse reports + + // abuse report render properly + async adminAbuseReportRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.abuseReports); + + // abuse reports text is visible + await this.toBeVisible(selector.admin.dokan.abuseReports.abuseReportsText); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.abuseReports.bulkActions); + + // filter elements are visible + const { filterInput, ...filters } = selector.admin.dokan.abuseReports.filters; + await this.multipleElementVisible(filters); + + // abuse report table elements are visible + await this.multipleElementVisible(selector.admin.dokan.abuseReports.table); + } + + // abuse report details + async abuseReportDetails() { + await this.goIfNotThere(data.subUrls.backend.dokan.abuseReports); + await this.click(selector.admin.dokan.abuseReports.abuseReportFirstCell); + + // abuse report modal elements are visible + await this.multipleElementVisible(selector.admin.dokan.abuseReports.abuseReportModal); + await this.click(selector.admin.dokan.abuseReports.abuseReportModal.closeModal); + } + + // filter abuse reports + async filterAbuseReports(input: string, action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.abuseReports); + + switch (action) { + case 'by-reason': + await this.selectByLabelAndWaitForResponse(data.subUrls.api.dokan.abuseReports, selector.admin.dokan.abuseReports.filters.filterByAbuseReason, input); + break; + + case 'by-product': + await this.click(selector.admin.dokan.abuseReports.filters.filterByProduct); + await this.typeAndWaitForResponse(data.subUrls.api.wc.wcProducts, selector.admin.dokan.abuseReports.filters.filterInput, input); + await this.pressAndWaitForResponse(data.subUrls.api.dokan.abuseReports, data.key.enter); + break; + + case 'by-vendor': + await this.click(selector.admin.dokan.abuseReports.filters.filterByVendors); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.abuseReports.filters.filterInput, input); + await this.pressAndWaitForResponse(data.subUrls.api.dokan.abuseReports, data.key.enter); + break; + + default: + break; + } + + const count = (await this.getElementText(selector.admin.dokan.abuseReports.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } + + // abuse report bulk action + async abuseReportBulkAction(action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.abuseReports); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.abuseReports.noRowsFound); + + await this.click(selector.admin.dokan.abuseReports.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.abuseReports.bulkActions.selectAction, action); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.abuseReports, selector.admin.dokan.abuseReports.bulkActions.applyAction); + } + + // customer report product + async reportProduct(productName: string, report: product['report']): Promise { + // await this.goToProductDetails(productName); + await this.goto(data.subUrls.frontend.productDetails(helpers.slugify(productName))); // for non logged user scenario, to load db changes + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleProduct.reportAbuse.reportAbuse); + // non logged user + const isNonLoggedUser = await this.isVisible(selector.customer.cSingleProduct.reportAbuse.nonLoggedUser.userName); + if (isNonLoggedUser) { + await this.clearAndType(selector.customer.cSingleProduct.reportAbuse.nonLoggedUser.userName, report.username); + await this.clearAndType(selector.customer.cSingleProduct.reportAbuse.nonLoggedUser.userPassword, report.password); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleProduct.reportAbuse.nonLoggedUser.login); + } + + await this.click(selector.customer.cSingleProduct.reportAbuse.reportReasonByName(report.reportReason)); + await this.clearAndType(selector.customer.cSingleProduct.reportAbuse.reportDescription, report.reportReasonDescription); + // is guest + const isGuest = await this.isVisible(selector.customer.cSingleProduct.reportAbuse.guestName); + if (isGuest) { + await this.clearAndType(selector.customer.cSingleProduct.reportAbuse.guestName, report.guestName()); + await this.clearAndType(selector.customer.cSingleProduct.reportAbuse.guestEmail, report.guestEmail()); + } + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleProduct.reportAbuse.reportSubmit); + await this.toContainText(selector.customer.cSingleProduct.reportAbuse.reportSubmitSuccessMessage, report.reportSubmitSuccessMessage); + // close popup + await this.click(selector.customer.cSingleProduct.reportAbuse.confirmReportSubmit); + } +} diff --git a/tests/pw/pages/adminDashboardPage.ts b/tests/pw/pages/adminDashboardPage.ts new file mode 100644 index 0000000000..24e4620490 --- /dev/null +++ b/tests/pw/pages/adminDashboardPage.ts @@ -0,0 +1,62 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; +import { user, adminDashboard } from '@utils/interfaces'; + +export class AdminDashboardPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // admin dashboard + + // admin dashboard render properly + async adminDashboardRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.dokan); + + // dashboard text is visible + await this.toBeVisible(selector.admin.dokan.dashboard.dashboardText); + + // header elements are visible + await this.multipleElementVisible(selector.admin.dokan.dashboard.header); + + // at a glance elements are visible + await this.multipleElementVisible(selector.admin.dokan.dashboard.atAGlance); + + // overview elements are visible + await this.multipleElementVisible(selector.admin.dokan.dashboard.overview); + + // dokan new update elements are visible + await this.multipleElementVisible(selector.admin.dokan.dashboard.dokanNewUpdates); + + // Subscribe box elements are visible + const { thankYouMessage, ...subscribeBox } = selector.admin.dokan.dashboard.subscribeBox; + await this.multipleElementVisible(subscribeBox); + } + + // at a glance value + async dokanAtAGlanceValueAccuracy(atAGlanceValues: adminDashboard['summary']) { + await this.goIfNotThere(data.subUrls.backend.dokan.dokan); + const netSales = (await this.getElementText(selector.admin.dokan.dashboard.atAGlance.netSalesThisMonth)) as string; + const commissionEarned = (await this.getElementText(selector.admin.dokan.dashboard.atAGlance.commissionEarned)) as string; + + expect(helpers.roundToTwo(helpers.price(netSales))).toBe(helpers.roundToTwo(atAGlanceValues.sales.this_month)); + expect(helpers.roundToTwo(helpers.price(commissionEarned))).toBe(helpers.roundToTwo(atAGlanceValues.earning.this_month)); + await this.toContainText(selector.admin.dokan.dashboard.atAGlance.signupThisMonth, atAGlanceValues.vendors.this_month + ' Vendor'); + await this.toContainText(selector.admin.dokan.dashboard.atAGlance.vendorAwaitingApproval, atAGlanceValues.vendors.inactive + ' Vendor'); + await this.toContainText(selector.admin.dokan.dashboard.atAGlance.productCreatedThisMonth, atAGlanceValues.products.this_month + ' Products'); + await this.toContainText(selector.admin.dokan.dashboard.atAGlance.withdrawAwaitingApproval, atAGlanceValues.withdraw.pending + ' Withdrawals'); + } + + // add dokan news subscriber + async addDokanNewsSubscriber(user: user['userDetails']) { + await this.goIfNotThere(data.subUrls.backend.dokan.dokan); + + await this.clearAndType(selector.admin.dokan.dashboard.subscribeBox.subscriberName, user.name()); + await this.clearAndType(selector.admin.dokan.dashboard.subscribeBox.subscriberEmail, user.email()); + await this.clickAndWaitForResponse(data.subUrls.backend.dokan.subscribe, selector.admin.dokan.dashboard.subscribeBox.subscribeButton, 302); + await this.toContainText(selector.admin.dokan.dashboard.subscribeBox.thankYouMessage, 'Thank you for subscribing!'); + } +} diff --git a/tests/pw/pages/adminPage.ts b/tests/pw/pages/adminPage.ts new file mode 100644 index 0000000000..3d87eaa723 --- /dev/null +++ b/tests/pw/pages/adminPage.ts @@ -0,0 +1,172 @@ +import { Page } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { payment, dokanSetupWizard, woocommerce } from '@utils/interfaces'; +import { helpers } from '@utils/helpers'; + +const { DOKAN_PRO } = process.env; + +export class AdminPage extends BasePage { + constructor(page: Page) { + super(page); + } + + // navigation + + async goToAdminDashboard() { + await this.goIfNotThere(data.subUrls.backend.adminDashboard); + } + + async goToDokanSettings() { + await this.goIfNotThere(data.subUrls.backend.dokan.settings); + } + + async goToWooCommerceSettings() { + await this.goIfNotThere(data.subUrls.backend.wc.settings); + } + + // Woocommerce Settings + + // Enable Password Field + async enablePasswordInputField(woocommerce: woocommerce) { + await this.goToWooCommerceSettings(); + await this.click(selector.admin.wooCommerce.settings.accounts); + await this.uncheck(selector.admin.wooCommerce.settings.automaticPasswordGeneration); + await this.click(selector.admin.wooCommerce.settings.accountSaveChanges); + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, woocommerce.saveSuccessMessage); + } + + // Admin Set Currency Options + async setCurrencyOptions(currency: payment['currency']) { + await this.goToWooCommerceSettings(); + + // Set Currency Options + await this.clearAndType(selector.admin.wooCommerce.settings.thousandSeparator, currency.currencyOptions.thousandSeparator); + await this.clearAndType(selector.admin.wooCommerce.settings.decimalSeparator, currency.currencyOptions.decimalSeparator); + await this.clearAndType(selector.admin.wooCommerce.settings.numberOfDecimals, currency.currencyOptions.numberOfDecimals); + await this.click(selector.admin.wooCommerce.settings.generalSaveChanges); + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, currency.saveSuccessMessage); + } + + // Admin Set Currency + async setCurrency(currency: string) { + await this.goToWooCommerceSettings(); + const currentCurrency = await this.getElementText(selector.admin.wooCommerce.settings.currency); + if (currentCurrency !== currency) { + await this.click(selector.admin.wooCommerce.settings.currency); + await this.clearAndType(selector.admin.wooCommerce.settings.currency, currency); + await this.press(data.key.enter); + await this.click(selector.admin.wooCommerce.settings.generalSaveChanges); + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, data.payment.currency.saveSuccessMessage); + } + } + + // get order details from allLog table + async getOrderDetails(orderNumber: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.allLogs); + + await this.clearAndType(selector.admin.dokan.reports.allLogs.search, orderNumber); + + const aOrderDetails = { + orderNumber: ((await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.orderId)) as string).split('#')[1], + store: await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.store), + orderTotal: helpers.price((await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.orderTotal)) as string), + vendorEarning: helpers.price((await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.vendorEarning)) as string), + commission: helpers.price((await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.commission)) as string), + gatewayFee: helpers.price((await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.gatewayFee)) as string), + shippingCost: helpers.price((await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.shippingCost)) as string), + tax: helpers.price((await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.tax)) as string), + orderStatus: await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.orderStatus), + orderDate: await this.getElementText(selector.admin.dokan.reports.allLogs.orderDetails.orderDate), + }; + + return aOrderDetails; + } + + // Get Total Admin Commission from Admin Dashboard + async getTotalAdminCommission() { + await this.goIfNotThere(data.subUrls.backend.dokan.dokan); + const totalAdminCommission = helpers.price((await this.getElementText(selector.admin.dokan.dashboard.atAGlance.commissionEarned)) as string); + return totalAdminCommission; + } + + // Dokan Setup Wizard + + // Admin Set Dokan Setup Wizard + async setDokanSetupWizard(dokanSetupWizard: dokanSetupWizard) { + // await this.hover(selector.admin.aDashboard.dokan) + // await this.click(selector.admin.dokan.toolsMenu) + // await this.click(selector.admin.dokan.tools.openSetupWizard) + + await this.goIfNotThere(data.subUrls.backend.dokan.setupWizard); + await this.click(selector.admin.dokan.dokanSetupWizard.letsGo); + + // Store + await this.clearAndType(selector.admin.dokan.dokanSetupWizard.vendorStoreURL, dokanSetupWizard.vendorStoreURL); + await this.selectByValue(selector.admin.dokan.dokanSetupWizard.shippingFeeRecipient, dokanSetupWizard.shippingFeeRecipient); + await this.selectByValue(selector.admin.dokan.dokanSetupWizard.taxFeeRecipient, dokanSetupWizard.taxFeeRecipient); + await this.selectByValue(selector.admin.dokan.dokanSetupWizard.mapApiSource, dokanSetupWizard.mapApiSource); + await this.clearAndType(selector.admin.dokan.dokanSetupWizard.googleMapApiKey, dokanSetupWizard.googleMapApiKey); + await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.shareEssentialsOff); + DOKAN_PRO && (await this.selectByValue(selector.admin.dokan.dokanSetupWizard.sellingProductTypes, dokanSetupWizard.sellingProductTypes)); + await this.click(selector.admin.dokan.dokanSetupWizard.continue); + // await this.click(selector.admin.dokan.dokanSetupWizard.skipThisStep) + + // Selling + await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.newVendorEnableSelling); + await this.selectByValue(selector.admin.dokan.dokanSetupWizard.commissionType, dokanSetupWizard.commissionType); + await this.clearAndType(selector.admin.dokan.dokanSetupWizard.adminCommission, dokanSetupWizard.adminCommission); + await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.orderStatusChange); + await this.click(selector.admin.dokan.dokanSetupWizard.continue); + // await this.click(selector.admin.dokan.dokanSetupWizard.skipThisStep) + + // Withdraw + await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.payPal); + await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.bankTransfer); + // await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.wirecard) + // await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.stripe) + DOKAN_PRO && (await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.custom)); + DOKAN_PRO && (await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.skrill)); + await this.clearAndType(selector.admin.dokan.dokanSetupWizard.minimumWithdrawLimit, dokanSetupWizard.minimumWithdrawLimit); + await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.orderStatusForWithdrawCompleted); + await this.enableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.orderStatusForWithdrawProcessing); + await this.click(selector.admin.dokan.dokanSetupWizard.continue); + + // Recommended + await this.disableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.wooCommerceConversionTracking); + await this.disableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.weMail); + await this.disableSwitcherSetupWizard(selector.admin.dokan.dokanSetupWizard.texty); + await this.click(selector.admin.dokan.dokanSetupWizard.continueRecommended); + + // Ready! + await this.click(selector.admin.dokan.dokanSetupWizard.visitDokanDashboard); + await this.toBeVisible(selector.admin.dokan.dashboard.dashboardText); + } + + // dokan notice & promotion + + // dokan notice + async dokanPromotion() { + await this.goto(data.subUrls.backend.dokan.dokan); + // dokan promotion elements are visible + const isPromotionVisible = await this.isVisible(selector.admin.dokan.promotion.promotion); + if (isPromotionVisible) { + await this.multipleElementVisible(selector.admin.dokan.promotion); + } else { + console.log('No promotion is ongoing'); + } + } + + // dokan notice + async dokanNotice() { + await this.goto(data.subUrls.backend.dokan.dokan); + + // dokan notice elements are visible + const isPromotionVisible = await this.isVisible(selector.admin.dokan.promotion.promotion); + isPromotionVisible ? await this.notToHaveCount(selector.admin.dokan.notice.noticeDiv1, 0) : await this.notToHaveCount(selector.admin.dokan.notice.noticeDiv, 0); + await this.notToHaveCount(selector.admin.dokan.notice.slider, 0); + await this.notToHaveCount(selector.admin.dokan.notice.sliderPrev, 0); + await this.notToHaveCount(selector.admin.dokan.notice.sliderNext, 0); + } +} diff --git a/tests/pw/pages/announcementsPage.ts b/tests/pw/pages/announcementsPage.ts new file mode 100644 index 0000000000..03942db0e7 --- /dev/null +++ b/tests/pw/pages/announcementsPage.ts @@ -0,0 +1,146 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { announcement } from '@utils/interfaces'; +import { helpers } from '@utils/helpers'; + +export class AnnouncementsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // announcements + + // announcements render properly + async adminAnnouncementsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.announcements); + + // announcement text is visible + await this.toBeVisible(selector.admin.dokan.announcements.announcementText); + + // and announcement is visible + await this.toBeVisible(selector.admin.dokan.announcements.addNewAnnouncement); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.announcements.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.announcements.bulkActions); + + // announcement table elements are visible + await this.multipleElementVisible(selector.admin.dokan.announcements.table); + + // add announcement fields are visible + await this.click(selector.admin.dokan.announcements.addNewAnnouncement); + const { contentHtmlBody, schedule, ...addAnnouncement } = selector.admin.dokan.announcements.addAnnouncement; + await this.multipleElementVisible(addAnnouncement); + await this.goBack(); + } + + // update announcement fields + async updateAnnouncementFields(announcement: announcement) { + await this.clearAndType(selector.admin.dokan.announcements.addAnnouncement.title, announcement.title); + await this.typeFrameSelector(selector.admin.dokan.announcements.addAnnouncement.contentIframe, selector.admin.dokan.announcements.addAnnouncement.contentHtmlBody, announcement.content); + await this.selectByValue(selector.admin.dokan.announcements.addAnnouncement.sendAnnouncementTo, announcement.receiver); + if (announcement.publishType === 'immediately') { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.addAnnouncement.publish); + await this.toBeVisible(selector.admin.dokan.announcements.announcementStatusPublished(announcement.title)); + } else { + await this.click(selector.admin.dokan.announcements.addAnnouncement.schedule.addSchedule); + await this.selectByNumber(selector.admin.dokan.announcements.addAnnouncement.schedule.month, announcement.scheduleDate.getMonth()); + await this.clearAndType(selector.admin.dokan.announcements.addAnnouncement.schedule.day, String(announcement.scheduleDate.getDate())); + await this.clearAndType(selector.admin.dokan.announcements.addAnnouncement.schedule.year, String(announcement.scheduleDate.getFullYear())); + await this.clearAndType(selector.admin.dokan.announcements.addAnnouncement.schedule.hour, String(announcement.scheduleDate.getHours())); + await this.clearAndType(selector.admin.dokan.announcements.addAnnouncement.schedule.minute, String(announcement.scheduleDate.getMinutes())); + await this.click(selector.admin.dokan.announcements.addAnnouncement.schedule.ok); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.addAnnouncement.publish); + await this.toBeVisible(selector.admin.dokan.announcements.announcementStatusScheduled(announcement.title)); + } + } + + // add announcement + async addAnnouncement(announcement: announcement) { + await this.goIfNotThere(data.subUrls.backend.dokan.announcements); + await this.click(selector.admin.dokan.announcements.addNewAnnouncement); + await this.updateAnnouncementFields(announcement); + } + + // edit announcement + async editAnnouncement(announcement: announcement) { + await this.goto(data.subUrls.backend.dokan.announcements); + await this.hover(selector.admin.dokan.announcements.announcementCell(announcement.title)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.announcementEdit(announcement.title)); + await this.updateAnnouncementFields(announcement); + } + + // update announcement + async updateAnnouncement(announcementTitle: string, action: string) { + await this.goto(data.subUrls.backend.dokan.announcements); + // await this.goIfNotThere(data.subUrls.backend.dokan.announcements); + + switch (action) { + case 'trash': + await this.hover(selector.admin.dokan.announcements.announcementCellPublished(announcementTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.announcementDelete(announcementTitle)); + break; + + case 'restore': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.navTabs.trash); + await this.hover(selector.admin.dokan.announcements.announcementCell(announcementTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.announcementRestore(announcementTitle)); + break; + + case 'permanently-delete': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.navTabs.trash); + await this.hover(selector.admin.dokan.announcements.announcementCell(announcementTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.announcementPermanentlyDelete(announcementTitle)); + break; + + default: + break; + } + } + + // announcement bulk action + async announcementBulkAction(action: string) { + await this.goto(data.subUrls.backend.dokan.announcements); + // await this.goIfNotThere(data.subUrls.backend.dokan.announcements); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.announcements.noRowsFound); + + await this.click(selector.admin.dokan.announcements.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.announcements.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.announcements, selector.admin.dokan.announcements.bulkActions.applyAction); + } + + // vendor + + // vendor announcements render properly + async vendorAnnouncementsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.announcements); + await this.notToHaveCount(selector.vendor.vAnnouncement.announcementDiv, 0); + await this.notToHaveCount(selector.vendor.vAnnouncement.announcementDate, 0); + await this.notToHaveCount(selector.vendor.vAnnouncement.announcementHeading, 0); + await this.notToHaveCount(selector.vendor.vAnnouncement.announcementContent, 0); + await this.notToHaveCount(selector.vendor.vAnnouncement.removeAnnouncement, 0); + } + + // vendor view announcement + async vendorViewAnnouncement(announcement: { title: string; content: string }) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.announcements); + await this.clickAndWaitForLoadState(selector.vendor.vAnnouncement.announcementLink(announcement.title)); + await this.toContainText(selector.vendor.vAnnouncement.announcement.title, announcement.title); + await this.toContainText(selector.vendor.vAnnouncement.announcement.content, helpers.stringBetweenTags(announcement.content)); + await this.toBeVisible(selector.vendor.vAnnouncement.announcement.date); + await this.toBeVisible(selector.vendor.vAnnouncement.announcement.backToAllNotice); + } + + // vendor delete announcement + async vendorDeleteAnnouncement(title: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.announcements); + await this.click(selector.vendor.vAnnouncement.deleteAnnouncement(title)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vAnnouncement.confirmDeleteAnnouncement); + } +} diff --git a/tests/pw/pages/basePage.ts b/tests/pw/pages/basePage.ts new file mode 100644 index 0000000000..a291e5b6c3 --- /dev/null +++ b/tests/pw/pages/basePage.ts @@ -0,0 +1,1531 @@ +/* eslint-disable playwright/no-element-handle */ +/* eslint-disable playwright/no-wait-for-timeout */ +/* eslint-disable playwright/no-page-pause */ +/* eslint-disable playwright/no-networkidle */ +/* eslint-disable playwright/no-force-option */ + +import { expect, Page, BrowserContext, Cookie, Request, Response, Locator, Frame, FrameLocator, JSHandle, ElementHandle } from '@playwright/test'; +import { data } from '@utils/testData'; + +// This Page Contains All Necessary Playwright Automation Methods + +export class BasePage { + readonly page: Page; + + constructor(page: Page) { + this.page = page; + } + + /** + * Page navigation methods + */ + + // wait for navigation to complete + async waitForNavigation(): Promise { + await this.page.waitForNavigation({ waitUntil: 'networkidle' }); + } + + // wait for request + async waitForRequest(url: string): Promise { + return await this.page.waitForRequest(url); + } + + // wait for Response + async waitForResponse(url: string): Promise { + return await this.page.waitForResponse(url); + } + + // wait for load state + async waitForLoadState(): Promise { + await this.page.waitForLoadState('networkidle'); + // await this.page.waitForLoadState( 'domcontentloaded'); + } + + // wait for load state + async waitForLoadState1(): Promise { + await this.page.waitForLoadState('domcontentloaded'); + } + + // wait for url to be loaded + async waitForUrl(url: string, options?: { timeout?: number | undefined; waitUntil?: 'networkidle' | 'load' | 'domcontentloaded' | 'commit' | undefined } | undefined): Promise { + await this.page.waitForURL(url, options); + // await this.page.waitForURL(url,{ waitUntil: 'networkidle' }); + } + + // goto subUrl + async goto(subPath: string): Promise { + await this.page.goto(subPath, { waitUntil: 'networkidle' }); + } + + // go forward + async goForward(): Promise { + await this.page.goForward(); + } + + // go back + async goBack(): Promise { + await this.page.goBack(); + } + + // reload page + async reload(): Promise { + await this.page.reload(); + } + + // returns whether the current URL is expected + isCurrentUrl(subPath: string): boolean { + const url = new URL(this.getCurrentUrl()); + const currentURL = url.href.replace(/[/]$/, ''); // added to remove last '/', + return currentURL === this.createUrl(subPath); + } + + // Create a New URL + createUrl(subPath: string): string { + // let url = new URL(process.env.BASE_URL) + // url.pathname = url.pathname + subPath + '/' + // return url.href + return process.env.BASE_URL + '/' + subPath; + } + + // goto subPath if not already there + async goIfNotThere(subPath: string): Promise { + if (!this.isCurrentUrl(subPath)) { + const url = this.createUrl(subPath); + await this.page.goto(url, { waitUntil: 'networkidle' }); + // await this.page.goto(url, { waitUntil: 'domcontentloaded' }); //don't work for backend + const currentUrl = this.getCurrentUrl(); + expect(currentUrl).toMatch(subPath); + } + } + + // goto subPath if about:blank is loaded + async goIfBlank(subPath: string): Promise { + const blankPage = await this.page.evaluate(() => window.location.href === 'about:blank'); + if (blankPage) { + await this.goto(subPath); + } + } + + /** + * current page methods + */ + + // get base url + getBaseUrl(): string { + const url = this.getCurrentUrl(); + return new URL(url).origin; + } + + // get current page url + getCurrentUrl(): string { + return this.page.url(); + } + + // get current page title + async getPageTitle(): Promise { + return await this.page.title(); + } + + // get full HTML contents of the current page + async getFullHtml(): Promise { + return await this.page.content(); + } + + // get the browser context that the page belongs to. + getPageContext(): BrowserContext { + return this.page.context(); + } + + // assign html markup to the current page + async setContent(html: string): Promise { + await this.page.setContent(html); + } + + // brings page to front (activates tab) + async bringToFront(): Promise { + await this.page.bringToFront(); + } + + // scroll to top + async scrollToTop(): Promise { + await this.page.keyboard.down(data.key.home); + // await this.page.evaluate(() => window.scroll(0, 0)); + await this.wait(1); + } + + // scroll to bottom + async scrollToBottom(): Promise { + await this.page.keyboard.down(data.key.end); + // await this.page.evaluate(() => window.scrollTo(0, document.body.scrollHeight)); + // await this.wait(0.5); + } + + /** + * click methods + */ + + // click on element + async click(selector: string): Promise { + await this.clickLocator(selector); + // await this.clickViaPage(selector); + } + + // click on element + async clickViaPage(selector: string): Promise { + await this.page.click(selector); + } + + // click on element by Running the js element.Click() method + async clickJs(selector: string): Promise { + const element = this.getElement(selector); + await element.click(); + } + + // click on element + async focusAndClick(selector: string): Promise { + await this.focus(selector); + await this.clickLocator(selector); + } + + // double click on element + async doubleClick(selector: string): Promise { + await this.page.dblclick(selector); + } + + // click & wait for navigation to complete + async clickAndWaitForNavigation(selector: string): Promise { + await Promise.all([this.page.waitForNavigation({ waitUntil: 'networkidle' }), this.page.locator(selector).click()]); + } + + // click & wait for load state to complete + async clickAndWaitForLoadState(selector: string): Promise { + await Promise.all([ + this.page.waitForLoadState('networkidle'), + // this.page.waitForLoadState( 'domcontentloaded' ), + this.page.locator(selector).click(), + ]); + } + + // click & wait for navigation to complete + async clickAndWaitForUrl(url: string | RegExp, selector: string): Promise { + await Promise.all([ + this.page.waitForURL(url, { waitUntil: 'networkidle' }), + // this.page.waitForURL(url, { waitUntil: 'domcontentloaded' }), + this.page.locator(selector).click(), + ]); + } + + // click & wait for request + async clickAndWaitForRequest(url: string, selector: string): Promise { + await Promise.all([this.page.waitForRequest(url), this.page.locator(selector).click()]); + } + + // click & wait for response + async clickLocatorAndWaitForResponse(subUrl: string, locator: Locator, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), locator.click()]); + return response; + } + + // click & wait for response + async clickAndWaitForResponse(subUrl: string, selector: string, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.locator(selector).click()]); + return response; + } + + // click & wait for response + async clickAndWaitForResponseAndLoadState(subUrl: string, selector: string, code = 200): Promise { + const [, response] = await Promise.all([this.page.waitForLoadState('networkidle'), this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.locator(selector).click()]); + expect(response.status()).toBe(code); + return response; + } + + // click & accept + async clickAndAccept(selector: string): Promise { + await Promise.all([this.acceptAlert(), this.page.locator(selector).click()]); + } + + // click & wait for response + async clickAndAcceptAndWaitForResponse(subUrl: string, selector: string, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.acceptAlert(), this.page.locator(selector).click()]); + return response; + } + + // click & wait for response + async clickAndAcceptAndWaitForResponseAndLoadState(subUrl: string, selector: string, code = 200): Promise { + const [response] = await Promise.all([ + this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), + this.acceptAlert(), + this.page.waitForLoadState('networkidle'), + this.page.locator(selector).click(), + ]); + return response; + } + + // type & wait for response + async typeViaPageAndWaitForResponse(subUrl: string, selector: string, text: string, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.type(selector, text, { delay: 100 })]); + return response; + } + + // type & wait for response + async typeAndWaitForResponse(subUrl: string, selector: string, text: string, code = 200): Promise { + const [response] = await Promise.all([ + this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), + // await this.page.type(selector, text), + this.clearAndFill(selector, text), + ]); + return response; + } + + // type & wait for response and LoadState + async typeAndWaitForResponseAndLoadState(subUrl: string, selector: string, text: string, code = 200): Promise { + const [response] = await Promise.all([ + this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), + // await this.page.type(selector, text), + this.page.waitForLoadState('networkidle'), + this.clearAndFill(selector, text), + ]); + return response; + } + + // type & wait for response and LoadState + async pressOnLocatorAndWaitForResponseAndLoadState(subUrl: string, selector: string, key: string, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.waitForLoadState('networkidle'), this.keyPressOnLocator(selector, key)]); + return response; + } + + // type & wait for load state + async pressAndWaitForLoadState(key: string): Promise { + await Promise.all([this.waitForLoadState(), this.press(key)]); + } + + // type & wait for response + async pressAndWaitForResponse(subUrl: string, key: string, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.press(key)]); + return response; + } + + // click & wait for event + async clickAndWaitForEvent(event: any, selector: string): Promise { + const [res] = await Promise.all([this.page.waitForEvent(event), this.page.locator(selector).click()]); + return res; + } + + // click & wait for download event + async clickAndWaitForDownload(selector: string): Promise { + await this.clickAndWaitForEvent('download', selector); + } + + // click if visible + async clickIfVisible(selector: string): Promise { + const isVisible = await this.isVisible(selector); + if (isVisible) { + await this.click(selector); + } + } + + // click and wait for response if visible + async clickAndWaitForResponseIfVisible(subUrl: string, selector: string): Promise { + const isVisible = await this.isVisible(selector); + if (isVisible) { + await this.clickAndWaitForResponse(subUrl, selector); + } + } + + // click if visible + async clickIfExists(selector: string): Promise { + const isExists = await this.isLocatorExists(selector); + if (isExists) { + await this.click(selector); + } + } + + // is locator exists + async isLocatorExists(selector: string): Promise { + return (await this.page.locator(selector).count()) ? true : false; + } + + // is element exists + async isElementExists(selector: string): Promise { + return (await this.page.$(selector).catch(() => null)) !== null; + } + + /** + * Keyboard methods + */ + + // press key + async press(key: string): Promise { + await this.page.keyboard.press(key); + } + + // press on selector [Focuses the element, and then uses keyboard press] + async pressOnSelector(selector: string, key: string): Promise { + await this.page.press(selector, key); + } + + /** + * selector methods + */ + + // wait for selector + async waitForSelector(selector: string): Promise { + await this.page.locator(selector).waitFor(); + // await this.page.waitForSelector(selector); + } + + // get locator + getLocator(selector: string): Locator { + return this.page.locator(selector); + } + + // get locators + async getLocators(selector: string): Promise { + return await this.page.locator(selector).all(); + // return this.page.locator(selector).elementHandles(); + // return this.page.$$(selector); + } + + // returns whether the element is visible + async isVisible(selector: string): Promise { + return await this.isVisibleLocator(selector); + // return await this.isVisibleViaPage(selector); + } + + // returns whether the element is visible + async isVisibleViaPage(selector: string): Promise { + return await this.page.isVisible(selector); + } + + // returns whether the element is hidden + async isHidden(selector: string): Promise { + return await this.page.isHidden(selector); + } + + // returns whether the element is enabled + async isEnabled(selector: string): Promise { + return await this.page.isEnabled(selector); + } + + // returns whether the element is editable + async isEditable(selector: string): Promise { + return await this.page.isEditable(selector); + } + + // returns whether the element is disabled + async isDisabled(selector: string): Promise { + return await this.isDisabledLocator(selector); + // return await this.page.isDisabled(selector); + } + + // returns whether the element is disabled + async isDisabledViaPage(selector: string): Promise { + return await this.page.isDisabled(selector); + } + + // returns whether the element is checked + async isChecked(selector: string): Promise { + return await this.page.isChecked(selector); + } + + // focus on selector + async focus(selector: string): Promise { + await this.page.focus(selector); + } + + // hover on selector + async hover(selector: string): Promise { + await this.page.locator(selector).hover(); + // await this.page.hover(selector); + await this.wait(0.2); + } + + // drag and drop + async dragAndDrop(source: string, target: string): Promise { + await this.page.dragAndDrop(source, target); + } + + // get element + getElement(selector: string): Locator { + return this.page.locator(selector); + } + + // get element text content + async getElementText(selector: string): Promise { + return await this.textContentOfLocator(selector); + // return await this.page.textContent(selector); + } + + // get element text if visible + async getElementTextIfVisible(selector: string): Promise { + const isVisible = await this.isVisible(selector); + if (isVisible) { + return await this.getElementText(selector); + } + } + + // get element text content + async getElementTextViaPage(selector: string): Promise { + return await this.page.textContent(selector); + } + + // get element has test or not + async hasText(selector: string, text: string): Promise { + const elementText = await this.textContentOfLocator(selector); + return elementText?.trim() === text ? true : false; + } + + // get element inner text + async getElementInnerText(selector: string): Promise { + return await this.page.innerText(selector); + } + + // get element inner html + async getElementInnerHtml(selector: string): Promise { + return await this.page.innerHTML(selector); + } + + // get element value [input, textarea, select] + async getElementValue(selector: string): Promise { + return await this.page.inputValue(selector); + } + + // get class attribute value + async getClassValue(selector: string): Promise { + return await this.page.getAttribute(selector, 'class'); + } + + // get element has class or not + async hasClass(selector: string, className: string): Promise { + const element = this.getElement(selector); + const hasClass = await element.evaluate((element, className) => element.classList.contains(className), className); + return hasClass; + } + + // get attribute value + async getAttributeValue(selector: string, attribute: string): Promise { + return await this.page.getAttribute(selector, attribute); + } + + // has attribute + async hasAttribute(selector: string, attribute: string): Promise { + const element = this.getElement(selector); + const hasAttribute = await element.evaluate((element, attribute) => element.hasAttribute(attribute), attribute); + return hasAttribute; + } + + // set attribute/class value + async setAttributeValue(selector: string, attribute: string, value: string): Promise { + const element = this.getElement(selector); + await element.evaluate((element, [attribute, value]) => element.setAttribute(attribute as string, value as string), [attribute, value]); + } + + // remove element attribute + async removeAttribute(selector: string, attribute: string): Promise { + const element = this.getElement(selector); + await element.evaluate((element, attribute) => element.removeAttribute(attribute), attribute); + } + + // get element property value: background color + async getElementBackgroundColor(selector: string): Promise { + const element = this.getElement(selector); + const value = await element.evaluate(element => window.getComputedStyle(element).getPropertyValue('background-color')); + // console.log(value) + return value; + } + + // get element property value: color + async getElementColor(selector: string): Promise { + const element = this.getElement(selector); + const value = await element.evaluate(element => window.getComputedStyle(element).getPropertyValue('color')); + // console.log(value) + return value; + } + + // has color + async hasColor(selector: string, color: string): Promise { + const elementColor = await this.getElementColor(selector); + // console.log(elementColor); + return elementColor === color ? true : false; + } + + // get pseudo element style + async getPseudoElementStyles(selector: string, pseudoElement: string, property: string): Promise { + const element = this.getElement(selector); + const value = await element.evaluate((element, [pseudoElement, property]) => window.getComputedStyle(element, '::' + pseudoElement).getPropertyValue(property as string), [pseudoElement, property]); + // console.log(value); + return value; + } + + // get multiple element texts + async getMultipleElementTexts(selector: string): Promise { + // const texts = await this.page.$$eval(selector, (elements) => elements.map((item) => item.textContent)); + const element = this.getElement(selector); + const allTexts = await element.allTextContents(); + // console.log(allTexts); + return allTexts; + } + + // get element bounding box + async getElementBoundingBox(selector: string): Promise { + const boundingBox = await this.page.locator(selector).boundingBox(); + return boundingBox; + } + + /** + * timeout methods + */ + + // change default maximum time(seconds) for all the methods + setDefaultNavigationTimeout(timeout: number): void { + this.page.setDefaultTimeout(timeout * 1000); + } + + // change default maximum navigation time(seconds) for all navigation methods [goto, goBack, goForward, ...] + setDefaultTimeout(timeout: number): void { + this.page.setDefaultTimeout(timeout * 1000); + } + + // waits for the given timeout in seconds + async wait(seconds: number): Promise { + await this.page.waitForTimeout(seconds * 1000); + } + + /** + * Input field methods + */ + + // clear input field + async clearInputField(selector: string): Promise { + await this.page.fill(selector, ''); + } + + // Or + async clearInputField1(selector: string): Promise { + const element = this.getElement(selector); + await element.click({ clickCount: 3 }); + await this.press('Backspace'); + } + + // Or + // async clearInputField2(selector): Promise { + // let element = await this.getElement(selector) + // await this.page.evaluate(element => element.value = '', element) + // } + + // clear input field and type + async clearAndType(selector: string, text: string): Promise { + await this.fill(selector, text); + // await this.clearAndTypeViaPage(selector, text); + } + + // clear input field and type + async clearAndTypeViaPage(selector: string, text: string): Promise { + await this.clearInputField1(selector); + await this.type(selector, text); + } + + // clear input field and type + async clearAndFill(selector: string, text: string): Promise { + await this.page.fill(selector, text); + } + + // type in input field + async type(selector: string, text: string): Promise { + await this.page.type(selector, text); + } + + // fill in input field + async fill(selector: string, text: string): Promise { + await this.page.fill(selector, text); + } + + // fill if visible + async fillIfVisible(selector: string, text: string): Promise { + const IsVisible = await this.isVisible(selector); + if (IsVisible) { + await this.clearAndFill(selector, text); + } + } + + // append in input filed + async append(selector: string, text: string): Promise { + await this.focus(selector); + await this.press('End'); + await this.page.type(selector, text); + } + + // check if visible + async typeIfVisible(selector: string, text: string): Promise { + const IsVisible = await this.isVisible(selector); + if (IsVisible) { + await this.clearAndFill(selector, text); + } + } + + // check/uncheck input fields [checkbox/radio] based on choice + async checkUncheck(selector: string, checked: boolean): Promise { + await this.page.setChecked(selector, checked); + } + + // check input fields [checkbox/radio] + async check1(selector: string): Promise { + await this.page.check(selector); + } + + // check input fields [checkbox/radio] + async check(selector: string): Promise { + await this.checkLocator(selector); + // await this.checkViaPage(selector); + } + + // check input fields [checkbox/radio] + async checkViaPage(selector: string): Promise { + await this.page.setChecked(selector, true); + } + + // uncheck input fields [checkbox/radio] + async uncheck(selector: string): Promise { + await this.page.uncheck(selector); + } + + // check if visible + async checkIfVisible(selector: string): Promise { + const IsVisible = await this.isVisible(selector); + if (IsVisible) { + await this.check(selector); + } + } + + /** + * Input field methods + */ + + // // select option by value/text/index + // async select(selector: string, choice: string, value: string | number): Promise { + // switch (choice) { + // case 'value': + // return await this.page.selectOption(selector, {value: value}) + // case 'label': + // return await this.page.selectOption(selector, {label: value}) + // case 'index': + // return await this.page.selectOption(selector, {index: value}) + // default: + // break + // } + // } + + // select by value + async selectByValue(selector: string, value: string): Promise { + return await this.page.selectOption(selector, { value }); + } + + // select by label + async selectByLabel(selector: string, value: string): Promise { + return await this.page.selectOption(selector, { label: value }); + } + + // select by number + async selectByNumber(selector: string, value: number | string): Promise { + return await this.page.selectOption(selector, { index: Number(value) }); + } + + // select by valid and wait for response + async selectByValueAndWaitForResponse(subUrl: string, selector: string, value: string, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.selectOption(selector, { value })]); + return response; + } + + // select by label and wait for response + async selectByLabelAndWaitForResponse(subUrl: string, selector: string, value: string, code = 200): Promise { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.selectOption(selector, { label: value })]); + return response; + } + + // set value based on select options text + // async selectByText(selectSelector: string, optionSelector: string, text: string): Promise { + // let optionValue = await this.page.$$eval(optionSelector, (options, text) => options.find(option => (option.innerText).toLowerCase() === text.toLowerCase())?.value, text) + // await this.selectByValue(selectSelector, optionValue); + // } + + /** + * Files & Media methods + */ + + // upload file + async uploadFile(selector: string, files: string | string[]): Promise { + // await this.page.setInputFiles(selector, files, { noWaitAfter: true }); + await this.page.setInputFiles(selector, files); + await this.wait(1.5); + } + + // upload file + async uploadBuffer(selector: string, filePath: string): Promise { + await this.page.setInputFiles(selector, { name: String(filePath.split('/').pop()), mimeType: 'image/' + filePath.split('.').pop(), buffer: Buffer.from(filePath) }); + } + + // upload files when input file element is missing + async uploadFileViaListener(selector: string, files: string | string[]): Promise { + this.page.on('filechooser', async fileChooser => { + await fileChooser.setFiles(files); + }); + await this.page.locator(selector).click(); // invokes the filechooser + } + + async uploadFileViaListener1(selector: string, files: string | string[]): Promise { + // Start waiting for file chooser before clicking. Note no await. + const fileChooserPromise = this.page.waitForEvent('filechooser'); // Note: no await on listener + await this.page.locator(selector).click(); // invokes the filechooser + const fileChooser = await fileChooserPromise; + await fileChooser.setFiles(files); + // or + // const [fileChooser] = await Promise.all([this.page.waitForEvent('filechooser'), this.page.locator(selector).click()]) + // await fileChooser.setFiles(files) + } + + // remove selected files to upload + async removeSelectedFileToUpload(selector: string, file: [] = []): Promise { + await this.page.setInputFiles(selector, file); + } + + // get screenshot + async getScreenshot(path: string, fullPage = false): Promise { + await this.page.screenshot({ path, fullPage }); + } + + // get screenshots as buffer + async getScreenshotBuffer(path: string): Promise { + const screenshot = await this.page.screenshot({ path }); + const buffer = screenshot.toString('base64'); + return buffer; + } + + // get screenshot + async getElementScreenshot(selector: string, path: string): Promise { + await this.page.locator(selector).screenshot({ path }); + } + + // generate a pdf of the page + async pdf(): Promise { + await this.page.pdf(); + } + + /** + * Frame [iframe] methods + */ + + // get all frames attached to the page + getAllFrames(): Frame[] { + return this.page.frames(); + } + + // get frame + getFrame(frame: string): Frame | null { + return this.page.frame(frame); + } + + // get child frames + getChildFrames(frame: string): Frame[] | null { + const parentFrame = this.page.frame(frame)!; + const childFrames = parentFrame.childFrames(); + return childFrames; + } + + // get frame + getFrameSelector(frame: string, frameSelector: string): FrameLocator { + return this.page.frameLocator(frame).locator(frameSelector); + } + + // click frame locator + async clickFrameSelector(frame: string, frameSelector: string): Promise { + const locator = this.page.frameLocator(frame).locator(frameSelector); + await locator.click(); + } + + // get frame + async typeFrameSelector(frame: string, frameSelector: string, text: string): Promise { + const locator = this.page.frameLocator(frame).locator(frameSelector); + await locator.fill(text); + // await locator.type(text); + } + + /** + * Locator methods [using playwright locator class] + */ + + // get locator all inner texts + async allInnerTextLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.allInnerTexts(); + } + + // get locator all text contents + async allTextContentsLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.allTextContents(); + } + + // get locator boundingBox + async boundingBoxLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.boundingBox(); + } + + // check locator + async checkLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.check({ force: true }); // forced is used to avoid "locator.check: Clicking the checkbox did not change its state" error + } + + // click locator + async clickLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.click(); + } + + // get locator count + async countLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.count(); + } + + // double click element + async dblclickLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.dblclick(); + } + + // dispatches event('click', 'dragstart',...) on the element + dispatchEvent(selector: string, event: string): void { + const locator = this.page.locator(selector); + locator.dispatchEvent(event); + } + + // drag locator to target locator + async dragToTargetLocator(sourceSelector: string, targetSelector: string): Promise { + const sourceLocator = this.page.locator(sourceSelector); + const targetLocator = this.page.locator(targetSelector); + await sourceLocator.dragTo(targetLocator); + } + + // resolves given locator to the first matching DOM element + async getElementHandle(selector: string): Promise> { + const locator = this.page.locator(selector); + return await locator.elementHandle(); + } + + // resolves given locator to all matching DOM elements + async getElementHandles(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.elementHandles(); + } + + // returns the return value of pageFunction + async evaluate(selector: string, pageFunction: string): Promise { + const locator = this.page.locator(selector); + await locator.evaluate(pageFunction); + } + + // returns the result of pageFunction invocation + async evaluateAll(selector: string, pageFunction: string): Promise { + const locator = this.page.locator(selector); + await locator.evaluateAll(pageFunction); + } + + // returns the return value of pageFunction as a JSHandle + // eslint-disable-next-line @typescript-eslint/ban-types + async evaluateHandle(selector: string, pageFunction: Function | string): Promise { + const locator = this.page.locator(selector); + return await locator.evaluateHandle(pageFunction); + } + + // fill input locator + async fillLocator(selector: string, text: string): Promise { + const locator = this.page.locator(selector); + await locator.fill(text); + } + + // filter locator through inner locator or text + filterLocator(selector: string, filterOptions: object): Locator { + const locator = this.page.locator(selector); + return locator.filter(filterOptions); + } + + // get first matching locator + firstLocator(selector: string): Locator { + const locator = this.page.locator(selector); + return locator.first(); + } + + // focus locator + async focusOnLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.focus(); + } + + // get frame locator + frameLocator(selector: string): FrameLocator { + const locator = this.page.locator(selector); + return locator.frameLocator(selector); + } + + // get locator attribute value + async getAttributeOfLocator(selector: string, attribute: string): Promise { + const locator = this.page.locator(selector); + return await locator.getAttribute(attribute); + } + + // highlight locator + async highlightLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.highlight(); + } + + // hover on locator + async hoverOnLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.hover(); + } + + // get locator inner html + async innerHTMLOfLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.innerHTML(); + } + + // get locator inner text + async innerTextOfLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.innerText(); + } + + // get locator input value + async inputValueOfLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.inputValue(); + } + + // returns whether the locator is checked + async isCheckedLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.isChecked(); + } + + // returns whether the locator is disabled + async isDisabledLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.isDisabled(); + } + + // returns whether the locator is editable + async isEditableLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.isEditable(); + } + + // returns whether the locator is enabled + async isEnabledLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.isEnabled(); + } + + // returns whether the locator is hidden + async isHiddenLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.isHidden(); + } + + // returns whether the locator is visible + async isVisibleLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.isVisible(); + } + + // get last matching locator + lastLocator(selector: string): Locator { + // todo: update all selector parameter to both selector or locator + const locator = this.page.locator(selector); + return locator.last(); + } + + // get child locator + locatorOfLocator(parentSelector: string, childSelector: string): Locator { + const locator = this.page.locator(parentSelector); + return locator.locator(childSelector); + } + + // get n-th matching locator + nthLocator(selector: string, index: number): Locator { + const locator = this.page.locator(selector); + return locator.nth(index); + } + + // get the page locator belongs to + pageOfLocator(selector: string): Page { + const locator = this.page.locator(selector); + return locator.page(); + } + + // key press on locator + async keyPressOnLocator(selector: string, key: string): Promise { + const locator = this.page.locator(selector); + await locator.press(key); + } + + // take locator screenshot + async screenshotOfLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.screenshot(); + } + + // scroll locator into view if needed + async scrollIntoViewLocator(selector: string, options?: { timeout?: number }): Promise { + const locator = this.page.locator(selector); + await locator.scrollIntoViewIfNeeded(options); + } + + // select from select option through value, option, index + async selectOptionOfLocator(selector: string, values: string): Promise { + const locator = this.page.locator(selector); + return await locator.selectOption(values); + } + + // select all locator's text content + async selectTextOfLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.selectText(); + } + + // check/uncheck locator + async setCheckedLocator(selector: string, checked: boolean): Promise { + const locator = this.page.locator(selector); + await locator.setChecked(checked); + } + + // upload file + async setInputFilesLocator(selector: string, file: string): Promise { + const locator = this.page.locator(selector); + await locator.setInputFiles(file); + } + + // tap on locator + async tapOnLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.tap(); + } + + // get locator text content + async textContentOfLocator(selector: string): Promise { + const locator = this.page.locator(selector); + return await locator.textContent(); + } + + // type on input locator + async typeOnLocator(selector: string, text: string): Promise { + const locator = this.page.locator(selector); + await locator.type(text); + } + + // uncheck locator + async uncheckLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.uncheck(); + } + + // wait for locator + async waitForLocator(selector: string, option: { state?: 'visible' | 'attached' | 'detached' | 'hidden' | undefined; timeout?: number | undefined } | undefined): Promise { + const locator = this.page.locator(selector); + await locator.waitFor(option); + } + + // wait for locator to be visible + async waitForVisibleLocator(selector: string): Promise { + const locator = this.page.locator(selector); + await locator.waitFor({ state: 'visible' }); + } + + /** + * Dialog methods + */ + + // accept alert + acceptAlert(): void { + this.page.once('dialog', dialog => { + // page.once is used avoid future alerts to be accepted + dialog.accept(); + }); + } + + // dismiss alert + dismissAlert(): void { + this.page.once('dialog', dialog => { + // page.once is used avoid future alerts to be dismissed + dialog.dismiss(); + }); + } + + // type on prompt box/alert + fillAlert(value: string): void { + this.page.once('dialog', dialog => { + // page.once is used avoid future prompts to be filled + dialog.accept(value); + }); + } + + // get default prompt value. Otherwise, returns empty string. + // getDefaultPromptValue(): string { + // let value: string; + // this.page.on('dialog', (dialog) => { + // value = dialog.defaultValue(); + // }); + // return value; + // } + + // get dialog's type [alert, beforeunload, confirm or prompt] + // async getDialogType(): Promise { + // let type: string; + // this.page.on('dialog', (dialog) => { + // type = dialog.type(); + // }); + // return type; + // } + + // get dialog's message + // async getDialogMessage(): Promise { + // let message: string; + // this.page.on('dialog', (dialog) => { + // message = dialog.message(); + // }); + // return message; + // } + + /** + * Cookies methods + */ + + // get cookies + async getCookies(): Promise { + return await this.page.context().cookies(); + } + + // add cookies + async addCookies( + browserContext: BrowserContext, + cookies: { + name: string; + value: string; + url?: string | undefined; + domain?: string | undefined; + path?: string | undefined; + expires?: number | undefined; + httpOnly?: boolean | undefined; + secure?: boolean | undefined; + sameSite?: 'Strict' | 'Lax' | 'None' | undefined; + }[], + ): Promise { + await browserContext.addCookies(cookies); + } + + // get cookies + async clearCookies(): Promise { + await this.page.context().clearCookies(); + } + + // get wp current user + async getCurrentUser(): Promise { + const cookies = await this.getCookies(); + const cookie = cookies.find(c => { + let _c$name: string; + return !!(c !== null && c !== void 0 && (_c$name = c.name) !== null && _c$name !== void 0 && _c$name.startsWith('wordpress_logged_in_')); + }); + if (!(cookie !== null && cookie !== void 0 && cookie.value)) { + return; + } + return decodeURIComponent(cookie.value).split('|')[0]; + } + + /** + * dropdown methods + */ + + // set dropdown option span dropdown + async setDropdownOptionSpan(selector: string, value: string): Promise { + const elements = await this.page.$$(selector); + for (const element of elements) { + const text = element.evaluate(element => element.textContent, element); + // console.log(text) + if (value.toLowerCase() == text?.trim().toLowerCase()) { + // console.log(text) + await element.click(); + } + } + } + + /** + * Debug methods + */ + + // pauses script execution + async pause(): Promise { + await this.page.pause(); + } + + /** + * page methods + */ + + // get all pages + getAllPages(): Page[] { + return this.page.context().pages(); + } + + /** + * Extra methods + */ + + // multiple elements to be checked + async multipleElementCheck(selectors: any) { + for (const selector in selectors) { + await this.check(selectors[selector]); + } + } + + // multiple elements to be visible + async multipleElementVisible(selectors: any) { + for (const selector in selectors) { + await this.toBeVisible(selectors[selector]); + } + } + + /** + * Assertion methods + */ + + // assert any element to be visible + async toBeVisibleAnyOfThem(selectors: string[]) { + // todo: extend nd improve this method + const res = []; + for (const selector of selectors) { + res.push(await this.isVisible(selector)); + } + const result = res.includes(true); + expect(result).toBeTruthy(); + } + + // assert element to be visible + async toBeVisible(selector: string) { + await expect(this.page.locator(selector)).toBeVisible(); + } + + // assert element to contain text + async toContainText(selector: string, text: string) { + await expect(this.page.locator(selector)).toContainText(text); + } + + // assert element to have count + async toHaveCount(selector: string, count: number) { + await expect(this.page.locator(selector)).toHaveCount(count); + } + + // assert element to have value + async toHaveValue(selector: string, value: string) { + await expect(this.page.locator(selector)).toHaveValue(value); + } + + // assert element to have attribute + async toHaveAttribute(selector: string, attribute: string, value: string) { + await expect(this.page.locator(selector)).toHaveAttribute(attribute, value); + } + + // assert element to have class + async toHaveClass(selector: string, className: string) { + await expect(this.page.locator(selector)).toHaveClass(className); + } + + // assert element not to be visible + async notToBeVisible(selector: string) { + await expect(this.page.locator(selector)).toBeHidden(); + } + + // assert element not to contain text + async notToContainText(selector: string, text: string) { + await expect(this.page.locator(selector)).not.toContainText(text); + } + + // assert element not to have count + async notToHaveCount(selector: string, count: number) { + await expect(this.page.locator(selector)).not.toHaveCount(count); + } + + // assert element not to have value + async notToHaveValue(selector: string, value: string) { + await expect(this.page.locator(selector)).not.toHaveValue(value); + } + + // assert element not to have attribute + async notToHaveAttribute(selector: string, attribute: string, value: string) { + await expect(this.page.locator(selector)).not.toHaveAttribute(attribute, value); + } + + // assert element not to have class + async notToHaveClass(selector: string, className: string) { + await expect(this.page.locator(selector)).not.toHaveClass(className); + } + + /** + * custom methods + */ + + // dokan select2 + async select2ByText(selectSelector: string, optionSelector: string, text: string): Promise { + await this.click(selectSelector); + await this.typeAndWaitForResponse(data.subUrls.ajax, optionSelector, text); + await this.toContainText('.select2-results__option.select2-results__option--highlighted', text); + await this.press('Enter'); + } + + // dokan select2 multi-selector + async select2ByTextMultiSelector(selectSelector: string, optionSelector: string, text: string): Promise { + const isExists = await this.isLocatorExists(`//li[@class="select2-selection__choice" and @title="${text}"]`); + if (!isExists) { + await this.click(selectSelector); + await this.typeAndWaitForResponse(data.subUrls.ajax, optionSelector, text); + await this.toContainText('.select2-results__option.select2-results__option--highlighted', text); + await this.press('Enter'); + } + } + + // admin enable switcher , if enabled then Skip : admin settings switcher + async enableSwitcher(selector: string): Promise { + /^(\/\/|\(\/\/)/.test(selector) ? (selector += '//span') : (selector += ' span'); + const value = await this.getElementBackgroundColor(selector); + if (!value.includes('rgb(0, 144, 255)')) { + await this.click(selector); + } + } + + // admin disable switcher , if disabled then skip : admin settings switcher + async disableSwitcher(selector: string): Promise { + /^(\/\/|\(\/\/)/.test(selector) ? (selector += '//span') : (selector += ' span'); + const value = await this.getElementBackgroundColor(selector); + if (value.includes('rgb(0, 144, 255)')) { + await this.click(selector); + } + } + + // admin enable switcher , if enabled then Skip : admin settings switcher + async enableSwitcherAndWaitForResponse(subUrl: string, selector: string, code = 200): Promise { + /^(\/\/|\(\/\/)/.test(selector) ? (selector += '//span') : (selector += ' span'); + const value = await this.getElementBackgroundColor(selector); + if (!value.includes('rgb(0, 144, 255)')) { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.locator(selector).click()]); + return response; + } + return ''; + } + + // admin disable switcher , if disabled then skip : admin settings switcher + async disableSwitcherAndWaitForResponse(subUrl: string, selector: string, code = 200): Promise { + /^(\/\/|\(\/\/)/.test(selector) ? (selector += '//span') : (selector += ' span'); + const value = await this.getElementBackgroundColor(selector); + if (value.includes('rgb(0, 144, 255)')) { + const [response] = await Promise.all([this.page.waitForResponse(resp => resp.url().includes(subUrl) && resp.status() === code), this.page.locator(selector).click()]); + return response; + } + return ''; + } + + // enable switch or checkbox: dokan setup wizard + async enableSwitcherSetupWizard(selector: string): Promise { + const value = await this.getPseudoElementStyles(selector, 'before', 'background-color'); + // rgb(251, 203, 196) for switcher & rgb(242, 98, 77) for checkbox + if (!value.includes('rgb(251, 203, 196)') && !value.includes('rgb(242, 98, 77)')) { + if (selector.includes('withdraw_methods')) selector += '/..'; + await this.click(selector); + } + } + + // disable switch or checkbox: dokan setup wizard + async disableSwitcherSetupWizard(selector: string): Promise { + const value = await this.getPseudoElementStyles(selector, 'before', 'background-color'); + // rgb(251, 203, 196) for switcher & rgb(242, 98, 77) for checkbox + if (value.includes('rgb(251, 203, 196)') || value.includes('rgb(242, 98, 77)')) { + if (selector.includes('withdraw_methods')) selector += '/..'; + await this.click(selector); + } + } + + // admin enable switcher , if enabled then Skip : vendor dashboard disbursements + async enableSwitcherDisbursement(selector: string): Promise { + /^(\/\/|\(\/\/)/.test(selector) ? (selector += '//span') : (selector += ' span'); + const value = await this.getElementBackgroundColor(selector); + if (!value.includes('rgb(33, 150, 243)')) { + await this.click(selector); + } + } + + // enable switch or checkbox: vendor dashboard delivery time + async enableSwitcherDeliveryTime(selector: string): Promise { + const value = await this.hasClass((selector += '//div[contains(@class,"minitoggle")]'), 'active'); + if (!value) { + await this.click(selector); + } + } + + // admin Enable payment methods via Slider + async enablePaymentMethod(selector: string): Promise { + const classValueBefore = await this.getClassValue(selector); + if (classValueBefore?.includes('woocommerce-input-toggle--disabled')) { + await this.click(selector); + } + const classValueAfter = await this.getClassValue(selector); + expect(classValueAfter).toContain('woocommerce-input-toggle--enabled'); + } + + // Check Multiple Elements with Same Selector/Class/Xpath + async checkMultiple(selector: string): Promise { + for (const element of await this.page.locator(selector).all()) { + const isCheckBoxChecked = await element.isChecked(); + if (!isCheckBoxChecked) { + await element.click(); + } + } + } + + // delete element if exist (only first will delete) : dokan rma,report abuse, company verifications // todo: delete all + async deleteIfExists(selector: string): Promise { + const elementExists = await this.isVisible(selector); + if (elementExists) { + const element = this.getElement(selector); + await element.click(); + } + } + + // upload file + async wpUploadFile(filePath: string | string[]) { + // wp image upload + const wpUploadFiles = '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[@id="menu-item-upload"]'; + const uploadedMedia = '.attachment-preview'; + const selectFiles = '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[@class="browser button button-hero"]'; + const select = '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[contains(@class, "media-button-select")]'; + const crop = '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[contains(@class, "media-button-insert")]'; + const uploadedMediaIsVisible = await this.isVisible(uploadedMedia); + if (uploadedMediaIsVisible) { + await this.click(wpUploadFiles); + } else { + await this.uploadFile(selectFiles, filePath); + await this.click(select); + await this.clickIfVisible(crop); + } + } + + // Remove Previous Uploaded media If Exists + async removePreviouslyUploadedImage(previousUploadedImageSelector: string, removePreviousUploadedImageSelector: string) { + const previousUploadedImageIsVisible = await this.isVisible(previousUploadedImageSelector); + if (previousUploadedImageIsVisible) { + await this.hover(previousUploadedImageSelector); + await this.click(removePreviousUploadedImageSelector); + await this.wait(2); + } + } +} diff --git a/tests/pw/pages/couponsPage.ts b/tests/pw/pages/couponsPage.ts new file mode 100644 index 0000000000..ed3b126787 --- /dev/null +++ b/tests/pw/pages/couponsPage.ts @@ -0,0 +1,114 @@ +import { Page } 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 { coupon } from '@utils/interfaces'; + +export class CouponsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + customerPage = new CustomerPage(this.page); + + // add marketplace coupon + async addMarketplaceCoupon(coupon: coupon) { + await this.goIfNotThere(data.subUrls.backend.wc.coupons); + + await this.clickAndWaitForResponse(data.subUrls.backend.wc.addCoupon, selector.admin.marketing.addCoupon); + await this.clearAndType(selector.admin.marketing.addNewCoupon.couponCode, coupon.title); + await this.clearAndType(selector.admin.marketing.addNewCoupon.couponDescription, coupon.description); + await this.selectByValue(selector.admin.marketing.addNewCoupon.discountType, coupon.discountType); + await this.clearAndType(selector.admin.marketing.addNewCoupon.couponAmount, coupon.amount()); + + await this.click(selector.admin.marketing.addNewCoupon.vendorLimits); + await this.check(selector.admin.marketing.addNewCoupon.enableForAllVendors); + await this.check(selector.admin.marketing.addNewCoupon.showOnStores); + await this.check(selector.admin.marketing.addNewCoupon.notifyVendors); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.marketing.addNewCoupon.publish); + await this.toContainText(selector.admin.marketing.addNewCoupon.publishSuccessMessage, 'Coupon updated.'); + } + + // vendor coupons render properly + async vendorCouponsRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.coupons); + + // coupon text is visible + await this.toBeVisible(selector.vendor.vCoupon.couponText); + + // add new coupon is visible + await this.toBeVisible(selector.vendor.vCoupon.addNewCoupon); + + // coupon menus are visible + await this.multipleElementVisible(selector.vendor.vCoupon.menus); + + // table elements are visible + await this.multipleElementVisible(selector.vendor.vCoupon.table); + } + + // vendor view marketplace coupon + async viewMarketPlaceCoupon(marketplaceCoupon: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.coupons); + await this.click(selector.vendor.vCoupon.menus.marketplaceCoupons); + await this.toBeVisible(selector.vendor.vCoupon.marketPlaceCoupon.marketPlaceCoupon); + marketplaceCoupon && (await this.toBeVisible(selector.vendor.vCoupon.marketPlaceCoupon.couponCell(marketplaceCoupon))); + } + + // update coupon fields + async updateCouponFields(coupon: coupon) { + await this.clearAndType(selector.vendor.vCoupon.couponTitle, coupon.title); + await this.clearAndType(selector.vendor.vCoupon.description, coupon.description); + await this.selectByValue(selector.vendor.vCoupon.discountType, coupon.discountType); + await this.clearAndType(selector.vendor.vCoupon.amount, coupon.amount()); + await this.click(selector.vendor.vCoupon.selectAll); + await this.check(selector.vendor.vCoupon.applyForNewProducts); + await this.check(selector.vendor.vCoupon.showOnStore); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.coupons, selector.vendor.vCoupon.createCoupon, 302); + } + + // vendor add coupon + async addCoupon(coupon: coupon) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.coupons); + await this.click(selector.vendor.vCoupon.addNewCoupon); + await this.updateCouponFields(coupon); + } + + // vendor edit coupon + async editCoupon(coupon: coupon) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.coupons); + await this.clickAndWaitForLoadState(selector.vendor.vCoupon.couponLink(coupon.title)); + await this.updateCouponFields(coupon); + await this.toContainText(selector.vendor.vCoupon.dokanMessage, selector.vendor.vCoupon.couponUpdateSuccessMessage); + } + + // vendor edit coupon + async deleteCoupon(couponCode: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.coupons); + await this.hover(selector.vendor.vCoupon.couponCell(couponCode)); + await this.clickAndAccept(selector.vendor.vCoupon.couponDelete(couponCode)); + await this.toContainText(selector.vendor.vCoupon.dokanMessage, 'Coupon has been deleted successfully!'); + } + + // customer + + // single store coupon + async viewStoreCoupon(storeName: string, couponCode: string) { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.toBeVisible(selector.customer.cSingleStore.storeCoupon.coupon(couponCode)); + } + + // apply coupon + async applyCoupon(productName: string, couponCode: string) { + await this.customerPage.addProductToCart(productName, 'single-product'); + await this.customerPage.applyCoupon(couponCode); + } + + // buy product with coupon + async buyProductWithCoupon(productName: string, couponCode: string) { + await this.customerPage.addProductToCart(productName, 'single-product'); + await this.customerPage.applyCoupon(couponCode); + await this.customerPage.placeOrder(); + } +} diff --git a/tests/pw/pages/customerPage.ts b/tests/pw/pages/customerPage.ts new file mode 100644 index 0000000000..215f7ee6c7 --- /dev/null +++ b/tests/pw/pages/customerPage.ts @@ -0,0 +1,538 @@ +import { Page, expect } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { LoginPage } from '@pages/loginPage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; +import { customer, paymentDetails } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class CustomerPage extends BasePage { + constructor(page: Page) { + super(page); + } + + loginPage = new LoginPage(this.page); + + // navigation + + async goToMyAccount(): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + } + + async goToCart(): Promise { + await this.goIfNotThere(data.subUrls.frontend.cart); + } + + async goToCheckout(): Promise { + await this.goIfNotThere(data.subUrls.frontend.checkout); + } + + async goToShop(): Promise { + await this.goIfNotThere(data.subUrls.frontend.shop); + } + + async goToStoreList(): Promise { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + } + + async goToProductDetails(productName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.productDetails(helpers.slugify(productName))); + } + + async goToOrderDetails(orderNumber: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.orderDetails(orderNumber)); + } + + // go to cart from shop page + async goToCartFromShop(): Promise { + await this.clickAndWaitForUrl(helpers.stringToRegex(data.subUrls.frontend.cart), selector.customer.cShop.productCard.viewCart); + } + + // go to cart from product details page + async goToCartFromSingleProductPage(): Promise { + await this.clickAndWaitForUrl(helpers.stringToRegex(data.subUrls.frontend.cart), selector.customer.cSingleProduct.productDetails.viewCart); + } + + // got to checkout from cart + async goToCheckoutFromCart(): Promise { + await this.clickAndWaitForUrl(helpers.stringToRegex(data.subUrls.frontend.checkout), selector.customer.cCart.proceedToCheckout); + } + + // customer details + + // customer register + async customerRegister(customerInfo: customer['customerInfo']): Promise { + const username = (customerInfo.firstName() + customerInfo.lastName()).replace("'", ''); + await this.goToMyAccount(); + const regIsVisible = await this.isVisible(selector.customer.cRegistration.regEmail); + !regIsVisible && (await this.loginPage.logout()); + await this.clearAndType(selector.customer.cRegistration.regEmail, username + data.customer.customerInfo.emailDomain); + await this.clearAndType(selector.customer.cRegistration.regPassword, customerInfo.password); + await this.click(selector.customer.cRegistration.regAsCustomer); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.myAccount, selector.customer.cRegistration.register, 302); + const registrationErrorIsVisible = await this.isVisible(selector.customer.cWooSelector.wooCommerceError); + if (registrationErrorIsVisible) { + const hasError = await this.hasText(selector.customer.cWooSelector.wooCommerceError, data.customer.registration.registrationErrorMessage); + if (hasError) { + console.log('User already exists!!'); + return; + } + } + const loggedInUser = await this.getCurrentUser(); + expect(loggedInUser).toBe(username.toLowerCase()); + } + + // customer become vendor + async customerBecomeVendor(customerInfo: customer['customerInfo']): Promise { + const firstName = customerInfo.firstName(); + + await this.goIfNotThere(data.subUrls.frontend.myAccount); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.accountMigration, selector.customer.cDashboard.becomeVendor); + // vendor registration form + await this.clearAndType(selector.customer.cDashboard.firstName, firstName); + await this.clearAndType(selector.customer.cDashboard.lastName, customerInfo.lastName()); + await this.clearAndType(selector.customer.cDashboard.shopName, customerInfo.shopName()); + await this.click(selector.customer.cDashboard.shopUrl); + await this.clearAndType(selector.customer.cDashboard.phone, customerInfo.phone); + + if (DOKAN_PRO) { + await this.clearAndType(selector.customer.cDashboard.companyName, customerInfo.companyName); + await this.clearAndType(selector.customer.cDashboard.companyId, customerInfo.companyId); + await this.clearAndType(selector.customer.cDashboard.vatNumber, customerInfo.vatNumber); + await this.clearAndType(selector.customer.cDashboard.bankName, customerInfo.bankName); + await this.clearAndType(selector.customer.cDashboard.bankIban, customerInfo.bankIban); + } + + await this.clickIfVisible(selector.customer.cDashboard.termsAndConditions); + const subscriptionPackIsVisible = await this.isVisible(selector.customer.cDashboard.subscriptionPack); + subscriptionPackIsVisible && (await this.selectByLabel(selector.vendor.vRegistration.subscriptionPack, data.predefined.vendorSubscription.nonRecurring)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.becomeVendor, selector.customer.cDashboard.becomeAVendor, 302); + subscriptionPackIsVisible && (await this.placeOrder('bank', false, true, false)); + + // skip vendor setup wizard + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.dashboard, selector.vendor.vSetup.notRightNow); + await this.toBeVisible(selector.vendor.vDashboard.menus.dashboard); + } + + // customer add customer details + async addCustomerDetails(customer: customer): Promise { + await this.goIfNotThere(data.subUrls.frontend.editAccountCustomer); + await this.clearAndType(selector.customer.cAccountDetails.firstName, customer.username); + await this.clearAndType(selector.customer.cAccountDetails.lastName, customer.lastname); + await this.clearAndType(selector.customer.cAccountDetails.displayName, customer.username); + await this.clearAndType(selector.customer.cAccountDetails.email, customer.username + customer.customerInfo.emailDomain); + // await this.updatePassword(customer.customerInfo.password, customer.customerInfo.password1); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.editAccountCustomer, selector.customer.cAccountDetails.saveChanges, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.customer.account.updateSuccessMessage); + + // cleanup: reset password + // await this.updatePassword(customer.customerInfo.password1, customer.customerInfo.password, true); + } + + // customer update password + async updatePassword(currentPassword: string, newPassword: string, saveChanges = false): Promise { + await this.clearAndType(selector.customer.cAccountDetails.currentPassword, currentPassword); + await this.clearAndType(selector.customer.cAccountDetails.NewPassword, newPassword); + await this.clearAndType(selector.customer.cAccountDetails.confirmNewPassword, newPassword); + if (saveChanges) { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.editAccountCustomer, selector.customer.cAccountDetails.saveChanges); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.customer.account.updateSuccessMessage); + } + } + + // update billing fields + async updateBillingFields(billingInfo: customer['customerInfo']['billing']) { + await this.clearAndType(selector.customer.cAddress.billing.billingFirstName, billingInfo.firstName); + await this.clearAndType(selector.customer.cAddress.billing.billingLastName, billingInfo.lastName); + await this.clearAndType(selector.customer.cAddress.billing.billingCompanyName, billingInfo.companyName); + if (DOKAN_PRO) { + await this.clearAndType(selector.customer.cAddress.billing.billingCompanyID, billingInfo.companyId); + await this.clearAndType(selector.customer.cAddress.billing.billingVatOrTaxNumber, billingInfo.vatNumber); + await this.clearAndType(selector.customer.cAddress.billing.billingNameOfBank, billingInfo.bankName); + await this.clearAndType(selector.customer.cAddress.billing.billingBankIban, billingInfo.bankIban); + } + await this.click(selector.customer.cAddress.billing.billingCountryOrRegion); + await this.clearAndType(selector.customer.cAddress.billing.billingCountryOrRegionInput, billingInfo.country); + await this.press(data.key.enter); + await this.clearAndType(selector.customer.cAddress.billing.billingStreetAddress, billingInfo.street1); + await this.clearAndType(selector.customer.cAddress.billing.billingStreetAddress2, billingInfo.street2); + await this.clearAndType(selector.customer.cAddress.billing.billingTownCity, billingInfo.city); + await this.focus(selector.customer.cAddress.billing.billingZipCode); + await this.click(selector.customer.cAddress.billing.billingState); + await this.clearAndType(selector.customer.cAddress.billing.billingStateInput, billingInfo.state); + await this.press(data.key.enter); + await this.clearAndType(selector.customer.cAddress.billing.billingZipCode, billingInfo.zipCode); + await this.clearAndType(selector.customer.cAddress.billing.billingPhone, billingInfo.phone); + await this.clearAndType(selector.customer.cAddress.billing.billingEmailAddress, billingInfo.email); + } + + // update shipping fields + async updateShippingFields(shippingInfo: customer['customerInfo']['shipping']): Promise { + await this.clearAndType(selector.customer.cAddress.shipping.shippingFirstName, shippingInfo.firstName); + await this.clearAndType(selector.customer.cAddress.shipping.shippingLastName, shippingInfo.lastName); + await this.clearAndType(selector.customer.cAddress.shipping.shippingCompanyName, shippingInfo.companyName); + await this.click(selector.customer.cAddress.shipping.shippingCountryOrRegion); + await this.clearAndType(selector.customer.cAddress.shipping.shippingCountryOrRegionInput, shippingInfo.country); + await this.press(data.key.enter); + await this.clearAndType(selector.customer.cAddress.shipping.shippingStreetAddress, shippingInfo.street1); + await this.clearAndType(selector.customer.cAddress.shipping.shippingStreetAddress2, shippingInfo.street2); + await this.clearAndType(selector.customer.cAddress.shipping.shippingTownCity, shippingInfo.city); + await this.focus(selector.customer.cAddress.shipping.shippingZipCode); + await this.click(selector.customer.cAddress.shipping.shippingState); + await this.clearAndType(selector.customer.cAddress.shipping.shippingStateInput, shippingInfo.state); + await this.press(data.key.enter); + await this.clearAndType(selector.customer.cAddress.shipping.shippingZipCode, shippingInfo.zipCode); + } + + // customer add billing address + async addBillingAddress(billingInfo: customer['customerInfo']['billing']): Promise { + await this.goIfNotThere(data.subUrls.frontend.billingAddress); + await this.updateBillingFields(billingInfo); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.billingAddress, selector.customer.cAddress.billing.billingSaveAddress, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.customer.address.addressChangeSuccessMessage); + } + + // customer add shipping address + async addShippingAddress(shippingInfo: customer['customerInfo']['shipping']): Promise { + await this.goIfNotThere(data.subUrls.frontend.shippingAddress); + await this.updateShippingFields(shippingInfo); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.shippingAddress, selector.customer.cAddress.shipping.shippingSaveAddress, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.customer.address.addressChangeSuccessMessage); + } + + // customer functionality + + // add product to cart from shop page + async addProductToCartFromShop(productName: string): Promise { + await this.searchProduct(productName); + await this.clickAndWaitForResponse(data.subUrls.frontend.addToCart, selector.customer.cShop.productCard.addToCart); + await this.toBeVisible(selector.customer.cShop.productCard.viewCart); + } + + // add product to cart from product details page + async addProductToCartFromSingleProductPage(productName: string, quantity?: string): Promise { + await this.goToProductDetails(productName); + const addonIsVisible = await this.isVisible(selector.customer.cSingleProduct.productAddon.addOnSelect); + addonIsVisible && this.selectByNumber(selector.customer.cSingleProduct.productAddon.addOnSelect, 1); + quantity && (await this.clearAndType(selector.customer.cSingleProduct.productDetails.quantity, String(quantity))); + await this.clickAndWaitForResponse(data.subUrls.frontend.productCustomerPage, selector.customer.cSingleProduct.productDetails.addToCart); + if (!quantity) { + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, `“${productName}” has been added to your cart.`); + } else { + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, `${quantity} × “${productName}” have been added to your cart.`); + } + } + + // add product to cart + async addProductToCart(productName: string, from: string, clearCart = true, quantity?: string) { + // clear cart + clearCart && (await this.clearCart()); + switch (from) { + case 'shop': + await this.addProductToCartFromShop(productName); + break; + case 'single-product': + await this.addProductToCartFromSingleProductPage(productName, quantity); + break; + default: + break; + } + } + + // check whether product is on cart + async productIsOnCart(productName: string): Promise { + await this.goToCart(); + await this.toBeVisible(selector.customer.cCart.cartItem(productName)); + } + + // clear cart + async clearCart(): Promise { + await this.goToCart(); + const cartProductIsVisible = await this.isVisible(selector.customer.cCart.firstProductCrossIcon); + if (cartProductIsVisible) { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.cart, selector.customer.cCart.firstProductCrossIcon); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'removed. Undo?'); + await this.clearCart(); + } else { + await this.toContainText(selector.customer.cCart.cartEmptyMessage, 'Your cart is currently empty.'); + } + } + + // Update product quantity from cart + async updateProductQuantityOnCart(productName: string, quantity: string): Promise { + await this.goToCart(); + await this.clearAndType(selector.customer.cCart.quantity(productName), quantity); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.cart, selector.customer.cCart.updateCart); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'Cart updated.'); + await this.toHaveValue(selector.customer.cCart.quantity(productName), quantity); + } + + // apply coupon + async applyCoupon(couponTitle: string): Promise { + await this.goToCart(); + const couponIsApplied = await this.isVisible(selector.customer.cCart.removeCoupon(couponTitle)); + if (couponIsApplied) { + await this.clickAndWaitForResponse(data.subUrls.frontend.removeCoupon, selector.customer.cCart.removeCoupon(couponTitle)); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'Coupon has been removed.'); + } + await this.clearAndType(selector.customer.cCart.couponCode, couponTitle); + await this.clickAndWaitForResponse(data.subUrls.frontend.applyCoupon, selector.customer.cCart.applyCoupon); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'Coupon code applied successfully.'); + } + + // add billing address in checkout + async addBillingAddressInCheckout(billingInfo: customer['customerInfo']['billing']): Promise { + await this.updateBillingFields(billingInfo); + } + + // add shipping address in checkout + async addShippingAddressInCheckout(shippingInfo: customer['customerInfo']['shipping']): Promise { + await this.clickAndWaitForResponse(data.subUrls.frontend.shippingAddressCheckout, selector.customer.cCheckout.shippingAddress.shipToADifferentAddress); + await this.updateShippingFields(shippingInfo); + } + + // place order + async placeOrder(paymentMethod = 'bank', getOrderDetails = false, billingAddress = false, shippingAddress = false): Promise { + await this.goToCheckout(); + billingAddress && (await this.addBillingAddressInCheckout(data.customer.customerInfo.billing)); + shippingAddress && (await this.addShippingAddressInCheckout(data.customer.customerInfo.shipping)); + + switch (paymentMethod) { + case 'bank': + await this.click(selector.customer.cCheckout.directBankTransfer); + break; + + case 'check': + await this.click(selector.customer.cCheckout.checkPayments); + break; + + case 'cod': + await this.click(selector.customer.cCheckout.cashOnDelivery); + break; + + case 'stripe': + await this.payWithStripe(data.paymentDetails.strip); + break; + + case 'stripeExpress': + await this.payWithStripeExpress(data.paymentDetails.stripExpress); + break; + + default: + break; + } + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.orderReceived, selector.customer.cCheckout.placeOrder); + await this.toBeVisible(selector.customer.cOrderReceived.orderReceivedSuccessMessage); + + const ifMultiVendorOrder = await this.isVisible(selector.customer.cOrderReceived.orderDetails.subOrders.subOrders); + if (ifMultiVendorOrder) { + await this.multipleElementVisible(selector.customer.cOrderReceived.orderDetails.subOrders); + } + + if (getOrderDetails) { + return await this.getOrderDetailsAfterPlaceOrder(); + } + + return (await this.getElementText(selector.customer.cOrderReceived.orderDetails.orderNumber)) as string; // remove after solving api issue in -> return request before all + } + + // place order + async paymentOrder(paymentMethod = 'bank'): Promise { + switch (paymentMethod) { + case 'bank': + await this.click(selector.customer.cCheckout.directBankTransfer); + break; + + case 'check': + await this.click(selector.customer.cCheckout.checkPayments); + break; + + case 'cod': + await this.click(selector.customer.cCheckout.cashOnDelivery); + break; + + case 'stripe': + await this.payWithStripe(data.paymentDetails.strip); + break; + + case 'stripeExpress': + await this.payWithStripeExpress(data.paymentDetails.stripExpress); + break; + + default: + break; + } + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.orderReceived, selector.customer.cCheckout.placeOrder); + await this.toBeVisible(selector.customer.cOrderReceived.orderReceivedSuccessMessage); + return (await this.getElementText(selector.customer.cOrderReceived.orderDetails.orderNumber)) as string; // remove after solving api issue in -> return request before all + } + + // buy product + async buyProduct(productName: string, couponCode: string, applyCoupon = false, getOrderDetails = false, paymentMethod = 'bank'): Promise { + await this.addProductToCart(productName, 'single-product'); + applyCoupon && (await this.applyCoupon(couponCode)); + return await this.placeOrder(paymentMethod, getOrderDetails); + } + + // pay with stripe connect + async payWithStripe(cardInfo: paymentDetails['strip']): Promise { + await this.click(selector.customer.cCheckout.stripeConnect); + const savedTestCardIsVisible = await this.isVisible(selector.customer.cPayWithStripe.savedTestCard4242); + if (!savedTestCardIsVisible) { + await this.typeFrameSelector(selector.customer.cPayWithStripe.stripeConnectIframe, selector.customer.cPayWithStripe.cardNumber, cardInfo.cardNumber); + await this.typeFrameSelector(selector.customer.cPayWithStripe.stripeConnectIframe, selector.customer.cPayWithStripe.expDate, cardInfo.expiryDate); + await this.typeFrameSelector(selector.customer.cPayWithStripe.stripeConnectIframe, selector.customer.cPayWithStripe.cvc, cardInfo.cvc); + await this.click(selector.customer.cPayWithStripe.savePaymentInformation); + } else { + await this.click(selector.customer.cPayWithStripe.savedTestCard4242); + } + } + + // pay with stripe express + async payWithStripeExpress(paymentDetails: paymentDetails['stripExpress']): Promise { + const paymentMethod = paymentDetails.paymentMethod; + const cardInfo = paymentDetails.cardInfo; + await this.click(selector.customer.cCheckout.stripeExpress); + const savedTestCardIsVisible = await this.isVisible(selector.customer.cPayWithStripeExpress.savedTestCard4242); + if (!savedTestCardIsVisible) { + switch (paymentMethod) { + case 'card': + await this.clickFrameSelector(selector.customer.cPayWithStripeExpress.stripeExpressIframe, selector.customer.cPayWithStripeExpress.creditCard); + await this.typeFrameSelector(selector.customer.cPayWithStripeExpress.stripeExpressIframe, selector.customer.cPayWithStripeExpress.cardNumber, cardInfo.cardNumber); + await this.typeFrameSelector(selector.customer.cPayWithStripeExpress.stripeExpressIframe, selector.customer.cPayWithStripeExpress.expDate, cardInfo.expiryDate); + await this.typeFrameSelector(selector.customer.cPayWithStripeExpress.stripeExpressIframe, selector.customer.cPayWithStripeExpress.cvc, cardInfo.cvc); + await this.click(selector.customer.cPayWithStripeExpress.savePaymentInformation); + break; + + case 'gPay': + await this.clickFrameSelector(selector.customer.cPayWithStripeExpress.stripeExpressIframe, selector.customer.cPayWithStripeExpress.gPay); + return; + + case 'iDeal': + await this.clickFrameSelector(selector.customer.cPayWithStripeExpress.stripeExpressIframe, selector.customer.cPayWithStripeExpress.iDeal); + break; + + default: + break; + } + } else { + await this.click(selector.customer.cPayWithStripeExpress.savedTestCard4242); + } + } + + // get order details after purchase + async getOrderDetailsAfterPlaceOrder(): Promise { + const orderDetails = { + orderNumber: '', + subtotal: 0, + shippingCost: 0, + shippingMethod: '', + tax: 0, + paymentMethod: '', + orderTotal: 0, + }; + + orderDetails.orderNumber = (await this.getElementText(selector.customer.cOrderReceived.orderDetails.orderNumber)) as string; + orderDetails.subtotal = helpers.price((await this.getElementText(selector.customer.cOrderReceived.orderDetails.subTotal)) as string); + + const shippingIsVisible = await this.isVisible(selector.customer.cOrderReceived.orderDetails.shippingCost); + if (shippingIsVisible) { + orderDetails.shippingMethod = ((await this.getElementText(selector.customer.cOrderReceived.orderDetails.shippingMethod)) as string).replace('via ', ''); + orderDetails.shippingCost = helpers.price((await this.getElementText(selector.customer.cOrderReceived.orderDetails.shippingCost)) as string); + } + const taxIsVisible = await this.isVisible(selector.customer.cOrderReceived.orderDetails.tax); + if (taxIsVisible) { + orderDetails.tax = helpers.price((await this.getElementText(selector.customer.cOrderReceived.orderDetails.tax)) as string); + } + + orderDetails.paymentMethod = (await this.getElementText(selector.customer.cOrderReceived.orderDetails.orderPaymentMethod)) as string; + orderDetails.orderTotal = helpers.price((await this.getElementText(selector.customer.cOrderReceived.orderDetails.orderTotal)) as string); + + return orderDetails; + } + + // get order details + async getOrderDetails(orderNumber: string): Promise { + await this.goToOrderDetails(orderNumber); + + const orderDetails = { + orderNumber: '', + orderDate: '', + orderStatus: '', + subtotal: 0, + shippingCost: 0, + shippingMethod: '', + tax: 0, + orderDiscount: 0, + quantityDiscount: 0, + discount: 0, + paymentMethod: '', + orderTotal: 0, + }; + + orderDetails.orderNumber = (await this.getElementText(selector.customer.cOrders.orderDetails.orderNumber)) as string; + orderDetails.orderDate = (await this.getElementText(selector.customer.cOrders.orderDetails.orderDate)) as string; + orderDetails.orderStatus = (await this.getElementText(selector.customer.cOrders.orderDetails.orderStatus)) as string; + orderDetails.subtotal = helpers.price((await this.getElementText(selector.customer.cOrders.orderDetails.subTotal)) as string); + + const shippingIsVisible = await this.isVisible(selector.customer.cOrders.orderDetails.shippingCost); + if (shippingIsVisible) { + orderDetails.shippingCost = helpers.price((await this.getElementText(selector.customer.cOrders.orderDetails.shippingCost)) as string); + orderDetails.shippingMethod = ((await this.getElementText(selector.customer.cOrders.orderDetails.shippingMethod)) as string).replace('via ', ''); + } + + const taxIsVisible = await this.isVisible(selector.customer.cOrders.orderDetails.tax); + if (taxIsVisible) { + orderDetails.tax = helpers.price((await this.getElementText(selector.customer.cOrders.orderDetails.tax)) as string); + } + + const orderDiscount = await this.isVisible(selector.customer.cOrders.orderDetails.orderDiscount); + if (orderDiscount) { + orderDetails.orderDiscount = helpers.price((await this.getElementText(selector.customer.cOrders.orderDetails.orderDiscount)) as string); + } + + const quantityDiscount = await this.isVisible(selector.customer.cOrders.orderDetails.quantityDiscount); + if (quantityDiscount) { + orderDetails.quantityDiscount = helpers.price((await this.getElementText(selector.customer.cOrders.orderDetails.quantityDiscount)) as string); + } + + const discount = await this.isVisible(selector.customer.cOrders.orderDetails.discount); + if (discount) { + orderDetails.discount = helpers.price((await this.getElementText(selector.customer.cOrders.orderDetails.discount)) as string); + } + + orderDetails.paymentMethod = (await this.getElementText(selector.customer.cOrders.orderDetails.paymentMethod)) as string; + orderDetails.orderTotal = helpers.price((await this.getElementText(selector.customer.cOrders.orderDetails.orderTotal)) as string); + + console.log(orderDetails); + return orderDetails; + } + + // search product + async searchProduct(productName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.shop); + if (!DOKAN_PRO) { + // search on lite + await this.clearAndType(selector.customer.cShop.searchProductLite, productName); + await this.pressAndWaitForLoadState(data.key.enter); + await this.toContainText(selector.customer.cSingleProduct.productDetails.productTitle, productName); + } else { + await this.clearAndType(selector.customer.cShop.filters.searchProduct, productName); + await this.clickAndWaitForLoadState(selector.customer.cShop.filters.search); + await this.toContainText(selector.customer.cShop.productCard.productTitle, productName); + } + } + + // search store + async searchStore(storeName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + await this.click(selector.customer.cStoreList.filters.filterButton); + await this.clearAndType(selector.customer.cStoreList.filters.filterDetails.searchVendor, storeName); + await this.clickAndWaitForResponse(data.subUrls.frontend.storeListing, selector.customer.cStoreList.filters.filterDetails.apply); + await this.toBeVisible(selector.customer.cStoreList.visitStore(storeName)); + } +} diff --git a/tests/pw/pages/emailVerificationsPage.ts b/tests/pw/pages/emailVerificationsPage.ts new file mode 100644 index 0000000000..c7782f1eb3 --- /dev/null +++ b/tests/pw/pages/emailVerificationsPage.ts @@ -0,0 +1,29 @@ +import { Page } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class EmailVerificationsPage extends BasePage { + constructor(page: Page) { + super(page); + } + + async register(user: { username: string; password: string }): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + + await this.clearAndType(selector.customer.cRegistration.regEmail, user.username); + await this.clearAndType(selector.customer.cRegistration.regPassword, user.password); + await this.click(selector.customer.cRegistration.regAsCustomer); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.myAccount, selector.customer.cRegistration.register, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.dokanSettings.emailVerification.loginNotice); + } + + async login(user: { username: string; password: string }): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + + await this.clearAndType(selector.frontend.username, user.username); + await this.clearAndType(selector.frontend.userPassword, user.password); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.myAccount, selector.frontend.logIn, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.dokanSettings.emailVerification.loginNotice); + } +} diff --git a/tests/pw/pages/followStorePage.ts b/tests/pw/pages/followStorePage.ts new file mode 100644 index 0000000000..59a1d9b908 --- /dev/null +++ b/tests/pw/pages/followStorePage.ts @@ -0,0 +1,81 @@ +import { Page } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; + +export class FollowStorePage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // vendor Followers + + // vendor followers render properly + async vendorFollowersRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.followers); + + // Store followers text is visible + await this.toBeVisible(selector.vendor.vFollowers.storeFollowersText); + + // vendor followers table elements are visible + await this.multipleElementVisible(selector.vendor.vFollowers.table); + } + + // vendor followers render properly + async vendorViewFollowers() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.followers); + await this.notToHaveCount(selector.vendor.vFollowers.numberOfRowsFound, 0); + } + + // customer + + async customerFollowedVendorsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vendors); + + const noVendorsFound = await this.isVisible(selector.customer.cVendors.noVendorFound); + if (noVendorsFound) { + await this.toContainText(selector.customer.cVendors.noVendorFound, 'No vendor found!'); + return; + } + + await this.notToHaveCount(selector.customer.cVendors.storeCard.storeCardDiv, 0); + } + + // follow vendor + async followStore(storeName: string, followLocation: string): Promise { + let currentFollowStatus: boolean; + + switch (followLocation) { + // store listing page + case 'storeListing': + await this.searchStore(storeName); + currentFollowStatus = await this.hasText(selector.customer.cStoreList.currentFollowStatus(storeName), 'Following'); + // unfollow if not already + if (currentFollowStatus) { + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cStoreList.followUnFollowStore(storeName)); + await this.toContainText(selector.customer.cStoreList.currentFollowStatus(storeName), 'Follow'); + } + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cStoreList.followUnFollowStore(storeName)); + await this.toContainText(selector.customer.cStoreList.currentFollowStatus(storeName), 'Following'); + break; + + // single store page + case 'singleStore': + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + currentFollowStatus = await this.hasText(selector.customer.cStoreList.currentFollowStatusSingleStore, 'Following'); + + // unfollow if not already + if (currentFollowStatus) { + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cStoreList.followUnFollowStoreSingleStore); + await this.toContainText(selector.customer.cStoreList.currentFollowStatusSingleStore, 'Follow'); + } + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cStoreList.followUnFollowStoreSingleStore); + await this.toContainText(selector.customer.cStoreList.currentFollowStatusSingleStore, 'Following'); + break; + + default: + break; + } + } +} diff --git a/tests/pw/pages/helpPage.ts b/tests/pw/pages/helpPage.ts new file mode 100644 index 0000000000..ce91156dfe --- /dev/null +++ b/tests/pw/pages/helpPage.ts @@ -0,0 +1,42 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class HelpPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // help + + // help render properly + async adminHelpRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.help); + + // help text is visible + await this.toBeVisible(selector.admin.dokan.help.helpText); + + // basics elements are visible + await this.multipleElementVisible(selector.admin.dokan.help.basics); + + // payment And Shipping elements are visible + await this.multipleElementVisible(selector.admin.dokan.help.paymentAndShipping); + + // vendor related questions elements are visible + await this.multipleElementVisible(selector.admin.dokan.help.vendorRelatedQuestions); + + // miscellaneous elements are visible + await this.multipleElementVisible(selector.admin.dokan.help.miscellaneous); + } + + // get help + async adminGetHelpDropdownRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.help); + + await this.hover(selector.admin.dokan.dashboard.header.getHelpMenu); + + // get help drop down list elements are visible + await this.multipleElementVisible(selector.admin.dokan.dashboard.getHelp); + } +} diff --git a/tests/pw/pages/licensePage.ts b/tests/pw/pages/licensePage.ts new file mode 100644 index 0000000000..6ba1af7c47 --- /dev/null +++ b/tests/pw/pages/licensePage.ts @@ -0,0 +1,35 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class LicensePage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // license + + // license render properly + async adminLicenseRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.license); + + // license settings text is visible + await this.toBeVisible(selector.admin.dokan.license.licenseText); + + // license section elements are visible + await this.multipleElementVisible(selector.admin.dokan.license.activateSection); + } + + // activate license + async activateLicense(key: string, type = 'correct') { + await this.goIfNotThere(data.subUrls.backend.dokan.license); + await this.clearAndType(selector.admin.dokan.license.activateSection.licenseKeyInput, key); + await this.clickAndWaitForResponse(data.subUrls.backend.dokan.license, selector.admin.dokan.license.activateSection.activateLicense); + if (type === 'correct') { + // todo: add valid key scenario + } else { + await this.toContainText(selector.admin.dokan.license.errorNotice, 'Invalid License Key'); + } + } +} diff --git a/tests/pw/pages/localSetupPage.ts b/tests/pw/pages/localSetupPage.ts new file mode 100644 index 0000000000..c755bbf3fd --- /dev/null +++ b/tests/pw/pages/localSetupPage.ts @@ -0,0 +1,42 @@ +import { Page } from '@playwright/test'; +import { WpPage } from '@pages/wpPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { installWp } from '@utils/interfaces'; + +export class LocalSetupPage extends WpPage { + constructor(page: Page) { + super(page); + } + + // local site setup + + // setup wordpress + async setupWp(siteData: installWp) { + await this.goto(data.subUrls.backend.setupWP); + const alreadyInstalledIsVisible = await this.isVisible(selector.backend.alreadyInstalled); + if (alreadyInstalledIsVisible) { + return; + } + await this.clickAndWaitForLoadState(selector.backend.languageContinue); + const letsGoIsVisible = await this.isVisible(selector.backend.letsGo); + + if (letsGoIsVisible) { + await this.clickAndWaitForLoadState(selector.backend.letsGo); + await this.fill(selector.backend.dbName, siteData.dbName); + await this.fill(selector.backend.dbUserName, siteData.dbUserName); + await this.fill(selector.backend.dbPassword, siteData.dbPassword); + await this.fill(selector.backend.dbHost, siteData.dbHost); + await this.fill(selector.backend.dbTablePrefix, siteData.dbTablePrefix); + await this.clickAndWaitForLoadState(selector.backend.submit); + await this.clickAndWaitForLoadState(selector.backend.runTheInstallation); + } else { + await this.fill(selector.backend.siteTitle, siteData.siteTitle); + await this.fill(selector.backend.adminUserName, siteData.adminUserName); + await this.fill(selector.backend.adminPassword, siteData.adminPassword); + await this.fill(selector.backend.adminEmail, siteData.adminEmail); + await this.clickAndWaitForLoadState(selector.backend.installWp); + await this.clickAndWaitForLoadState(selector.backend.successLoginIn); + } + } +} diff --git a/tests/pw/pages/loginPage.ts b/tests/pw/pages/loginPage.ts new file mode 100644 index 0000000000..2c54f3a6c1 --- /dev/null +++ b/tests/pw/pages/loginPage.ts @@ -0,0 +1,93 @@ +import { Page, expect } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { data, user } from '@utils/testData'; +import { selector } from '@pages/selectors'; + +export class LoginPage extends BasePage { + constructor(page: Page) { + super(page); + } + + // user login + async login(user: user, storageState?: string): Promise { + await this.loginFronted(user, storageState); + } + + // user loginFronted + async loginFronted(user: user, storageState?: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + const currentUser = await this.getCurrentUser(); + + // skip if user is already logged in + if (user.username === currentUser) { + return; + } + + // logout if other user is already logged in + else if (user.username !== currentUser && currentUser !== undefined) { + // TODO : got undefined for using storage.json + // else if ((user.username !== currentUser) || (currentUser === undefined)) { + await this.logoutFrontend(); + } + + // login user + await this.clearAndType(selector.frontend.username, user.username); + await this.clearAndType(selector.frontend.userPassword, user.password); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.myAccount, selector.frontend.logIn, 302); + if (storageState) { + await this.page.context().storageState({ path: storageState }); + } + const loggedInUser = await this.getCurrentUser(); + expect(loggedInUser).toBe(user.username); + } + + // user loginBackend + async loginBackend(user: user, url: string = data.subUrls.backend.login, storageState?: string): Promise { + await this.goIfNotThere(url); + const emailField = await this.isVisible(selector.backend.email); + if (emailField) { + await this.clearAndType(selector.backend.email, user.username); + await this.clearAndType(selector.backend.password, user.password); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.backend.login, selector.backend.login, 302); + if (storageState) { + await this.page.context().storageState({ path: storageState }); + } + const loggedInUser = await this.getCurrentUser(); + expect(loggedInUser).toBe(user.username); + } + } + + // user logout + async logout(): Promise { + await this.logoutFrontend(); + } + + // user logoutFrontend + async logoutFrontend(): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + await this.clickAndWaitForLoadState(selector.frontend.customerLogout); + const loggedInUser = await this.getCurrentUser(); + expect(loggedInUser).toBeUndefined(); + } + + // admin login + async adminLogin(user: user, storageState?: string) { + await this.loginBackend(user, data.subUrls.backend.adminLogin, storageState); + } + + // admin logout + async logoutBackend(): Promise { + await this.hover(selector.backend.userMenu); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.backend.adminLogout, selector.backend.logout, 302); + const loggedInUser = await this.getCurrentUser(); + expect(loggedInUser).toBeUndefined(); + } + + // switch user + async switchUser(user: user): Promise { + const currentUser = await this.getCurrentUser(); + if (currentUser !== user.username) { + await this.loginBackend(user); + } + } +} diff --git a/tests/pw/pages/modulesPage.ts b/tests/pw/pages/modulesPage.ts new file mode 100644 index 0000000000..d63faeda35 --- /dev/null +++ b/tests/pw/pages/modulesPage.ts @@ -0,0 +1,123 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class ModulesPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // modules + + // modules render properly + async adminModulesRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.modules); + + // modules text is visible + await this.toBeVisible(selector.admin.dokan.modules.pro.moduleText); + + // module plan elements are visible + await this.multipleElementVisible(selector.admin.dokan.modules.pro.modulePlan); + + // navTab elements are visible + await this.multipleElementVisible(selector.admin.dokan.modules.pro.navTabs); + + // module filter is visible + await this.toBeVisible(selector.admin.dokan.modules.pro.moduleFilter); + + // modules search is visible + await this.toBeVisible(selector.admin.dokan.modules.pro.searchBox); + + // modules view mode switcher is visible + await this.toBeVisible(selector.admin.dokan.modules.pro.moduleViewMode); + + // module cards and card details are visible + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCard, 39); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleIcon, 39); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCheckbox, 39); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleName, 39); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleDescription, 39); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleActivationSwitch, 39); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleDocs, 38); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleVideos, 17); + + // module category tags are visible + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.productManagement, 13); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.integration, 6); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.uiUx, 2); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.shipping, 3); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.storeManagement, 10); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.payment, 7); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.orderManagement, 2); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.vendorManagement, 1); + } + + // search module + async searchModule(moduleName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.modules); + await this.clickIfVisible(selector.admin.dokan.modules.pro.clearFilter); + await this.clearAndType(selector.admin.dokan.modules.pro.searchBox, moduleName); + await this.toBeVisible(selector.admin.dokan.modules.pro.moduleCardByName(moduleName)); + } + + // filter modules + async filterModules(category: string) { + await this.goto(data.subUrls.backend.dokan.modules); + + await this.hover(selector.admin.dokan.modules.pro.moduleFilter); + await this.click(selector.admin.dokan.modules.pro.moduleFilterCheckBox(category)); + const numOfModules = await this.countLocator(selector.admin.dokan.modules.pro.moduleCard); + const numOfCategoryTag = await this.countLocator(selector.admin.dokan.modules.pro.moduleCategoryTag(category)); + expect(numOfModules).toBe(numOfCategoryTag); + } + + // activate deactivate module + async activateDeactivateModule(moduleName: string) { + await this.searchModule(moduleName); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.modules, selector.admin.dokan.modules.pro.moduleActivationSwitch); + } + + // modules bulk action + async moduleBulkAction(action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.modules); + + await this.click(selector.admin.dokan.modules.pro.firstModuleCheckbox); + await this.click(selector.admin.dokan.modules.pro.selectAllBulkAction); + switch (action) { + case 'activate': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.modules, selector.admin.dokan.modules.pro.activeAll); + break; + + case 'deactivate': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.modules, selector.admin.dokan.modules.pro.deActivateAll); + break; + + default: + break; + } + } + + // module view layout + async moduleViewLayout(style: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.modules); + const currentStyle = await this.getClassValue(selector.admin.dokan.modules.pro.currentLayout); + if (!currentStyle?.includes(style)) { + await this.click(selector.admin.dokan.modules.pro.moduleViewMode); + await this.toHaveClass(selector.admin.dokan.modules.pro.currentLayout, style); + } + } + + // inactive module exists + async inActiveModuleExists() { + await this.goIfNotThere(data.subUrls.backend.dokan.modules); + await this.click(selector.admin.dokan.modules.pro.navTabs.inActive); + const noModulesMessage = await this.isVisible(selector.admin.dokan.modules.pro.noModulesFound); + if (noModulesMessage) { + await this.toContainText(selector.admin.dokan.modules.pro.noModulesFound, data.modules.noModuleMessage); + } else { + const inActiveModuleNames = await this.getMultipleElementTexts(selector.admin.dokan.modules.pro.moduleName); + throw new Error('Inactive modules: ' + inActiveModuleNames); + } + } +} diff --git a/tests/pw/pages/myOrdersPage.ts b/tests/pw/pages/myOrdersPage.ts new file mode 100644 index 0000000000..20152639a9 --- /dev/null +++ b/tests/pw/pages/myOrdersPage.ts @@ -0,0 +1,77 @@ +import { Page } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +const { DOKAN_PRO } = process.env; + +export class MyOrdersPage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // my orders + + // my orders render properly + async myOrdersRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.myOrders); + + const noOrders = await this.isVisible(selector.customer.cMyOrders.noOrdersFound); + + if (noOrders) { + await this.toContainText(selector.customer.cMyOrders.noOrdersFound, 'No orders found!'); + console.log('No orders found on my order page'); + } else { + // my orders text is visible + await this.toBeVisible(selector.customer.cMyOrders.myOrdersText); + + // recent orders text is visible + await this.toBeVisible(selector.customer.cMyOrders.recentOrdersText); + + // my orders table elements are visible + await this.multipleElementVisible(selector.customer.cMyOrders.table); + } + } + + // view order details + async viewOrderDetails(orderId: string) { + await this.goIfNotThere(data.subUrls.frontend.orderDetails(orderId)); + + // order details are visible + await this.multipleElementVisible(selector.customer.cOrderDetails.orderDetails); + + // customer details are visible + await this.multipleElementVisible(selector.customer.cOrderDetails.customerDetails); + + DOKAN_PRO && (await this.toBeVisible(selector.customer.cOrderDetails.getSupport)); + } + + // view order note + async viewOrderNote(orderNumber: string, orderNote: string) { + await this.goIfNotThere(data.subUrls.frontend.orderDetails(orderNumber)); + await this.toBeVisible(selector.customer.cOrderDetails.orderUpdates.orderNote(orderNote)); + } + + // pay pending order + async payPendingOrder(orderId: string, paymentMethod = 'bank') { + await this.goIfNotThere(data.subUrls.frontend.myOrders); + await this.clickAndWaitForResponse(data.subUrls.frontend.orderPay, selector.customer.cMyOrders.orderPay(orderId)); + await this.paymentOrder(paymentMethod); + } + + // cancel order + async cancelPendingOrder(orderId: string) { + await this.goIfNotThere(data.subUrls.frontend.myOrders); + await this.clickAndWaitForResponse(data.subUrls.frontend.orderCancel, selector.customer.cMyOrders.orderCancel(orderId), 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceInfo, 'Your order was cancelled.'); + } + + // order again + async orderAgain(orderId: string, paymentMethod = 'bank') { + await this.goIfNotThere(data.subUrls.frontend.orderDetails(orderId)); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.frontend.orderAgain, selector.customer.cOrderDetails.orderAgain, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'The cart has been filled with the items from your previous order.'); + await this.goToCheckoutFromCart(); + await this.paymentOrder(paymentMethod); + } +} diff --git a/tests/pw/pages/ordersPage.ts b/tests/pw/pages/ordersPage.ts new file mode 100644 index 0000000000..44636d5486 --- /dev/null +++ b/tests/pw/pages/ordersPage.ts @@ -0,0 +1,254 @@ +import { Page, expect } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { orderNote, orderTrackingDetails, orderShipmentDetails, date } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class OrdersPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // orders + + // orders render properly + async vendorOrdersRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.orders); + + // order nav menus are visible + await this.multipleElementVisible(selector.vendor.orders.menus); + + // export elements are visible + await this.multipleElementVisible(selector.vendor.orders.export); + + // order filters elements are visible + const { filterByCustomer, filterByDate, ...filters } = selector.vendor.orders.filters; + await this.toBeVisible(selector.vendor.orders.filters.filterByCustomer.dropDown); + await this.toBeVisible(selector.vendor.orders.filters.filterByDate.dateRangeInput); + await this.multipleElementVisible(filters); + + // order search elements are visible + await this.multipleElementVisible(selector.vendor.orders.search); + + // bulk action elements are visible + await this.multipleElementVisible(selector.vendor.orders.bulkActions); + + // table elements are visible + const { shipmentColumn, ...table } = selector.vendor.orders.table; + await this.multipleElementVisible(table); + DOKAN_PRO && (await this.toBeVisible(shipmentColumn)); + } + + // export orders + async exportOrders(type: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.orders); + + switch (type) { + case 'all': + // await this.clickAndAcceptAndWaitForResponse(data.subUrls.frontend.vDashboard.orders, selector.vendor.orders.export.exportAll ); + await this.clickAndWaitForDownload(selector.vendor.orders.export.exportAll); + break; + + case 'filtered': + // await this.clickAndAcceptAndWaitForResponse(data.subUrls.frontend.vDashboard.orders, selector.vendor.orders.export.exportFiltered ); + await this.clickAndWaitForDownload(selector.vendor.orders.export.exportFiltered); + break; + + default: + break; + } + } + + // search order + async searchOrder(orderNumber: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.orders); + + await this.clearAndType(selector.vendor.orders.search.searchInput, orderNumber); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.orders, selector.vendor.orders.search.searchBtn); + await this.toBeVisible(selector.vendor.orders.orderLink(orderNumber)); + await this.toHaveCount(selector.vendor.orders.numberOfRowsFound, 1); + } + + // filter orders + async filterOrders(filterBy: string, inputValue: string | date['dateRange']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.orders); + + switch (filterBy) { + case 'by-customer': + await this.click(selector.vendor.orders.filters.filterByCustomer.dropDown); + await this.typeAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.filters.filterByCustomer.input, inputValue as string); + await this.click(selector.vendor.orders.filters.filterByCustomer.searchedResult); + break; + + case 'by-date': + if (typeof inputValue !== 'string') { + await this.setAttributeValue(selector.vendor.orders.filters.filterByDate.dateRangeInput, 'value', helpers.dateFormatFYJ(inputValue.startDate) + ' - ' + helpers.dateFormatFYJ(inputValue.endDate)); + await this.setAttributeValue(selector.vendor.orders.filters.filterByDate.startDateInput, 'value', inputValue.startDate); + await this.setAttributeValue(selector.vendor.orders.filters.filterByDate.endDateInput, 'value', inputValue.endDate); + } + break; + + default: + break; + } + + await this.clickAndWaitForLoadState(selector.vendor.orders.filters.filter); + await this.notToHaveCount(selector.vendor.orders.numberOfRowsFound, 0); + } + + // go to order details + async goToOrderDetails(orderNumber: string): Promise { + await this.searchOrder(orderNumber); + await this.clickAndWaitForLoadState(selector.vendor.orders.view(orderNumber)); + await this.toContainText(selector.vendor.orders.orderDetails.orderNumber, orderNumber); + } + + // view order details + async viewOrderDetails(orderNumber: string): Promise { + await this.goToOrderDetails(orderNumber); + + // order details elements are visible + await this.toBeVisible(selector.vendor.orders.orderDetails.orderNumber); + await this.toBeVisible(selector.vendor.orders.orderDetails.orderDate); + DOKAN_PRO ? await this.toBeVisible(selector.vendor.orders.orderDetails.orderTotal) : await this.toBeVisible(selector.vendor.orders.orderDetails.total); + // todo: add more fields to assert + + // general details elements are visible + await this.multipleElementVisible(selector.vendor.orders.generalDetails); + + await this.click(selector.vendor.orders.status.edit); + + // status elements are visible + const { selectedOrderStatus, edit, ...status } = selector.vendor.orders.status; + await this.multipleElementVisible(status); + + // order note elements are visible + await this.multipleElementVisible(selector.vendor.orders.orderNote); + + if (DOKAN_PRO) { + await this.click(selector.vendor.orders.shipment.createNewShipment); + // shipment elements are visible + const { createNewShipment, shipmentOrderItem, shipmentOrderItemQty, ...shipment } = selector.vendor.orders.shipment; + await this.multipleElementVisible(shipment); + } else { + await this.click(selector.vendor.orders.trackingDetails.addTrackingNumber); + // tracking detail elements are visible + const { addTrackingNumber, ...trackingDetails } = selector.vendor.orders.trackingDetails; + await this.multipleElementVisible(trackingDetails); + } + + // downloadable product elements are visible + const { revokeAccess, confirmAction, cancelAction, ...downloadableProductPermission } = selector.vendor.orders.downloadableProductPermission; + await this.multipleElementVisible(downloadableProductPermission); + } + + // update order status on table + async updateOrderStatusOnTable(orderNumber: string, status: string): Promise { + await this.searchOrder(orderNumber); + switch (status) { + case 'processing': + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.processing(orderNumber), 302); + await this.notToBeVisible(selector.vendor.orders.processing(orderNumber)); + break; + + case 'complete': + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.complete(orderNumber), 302); + await this.notToBeVisible(selector.vendor.orders.complete(orderNumber)); + break; + + default: + break; + } + } + + // update order status + async updateOrderStatus(orderNumber: string, status: string): Promise { + await this.goToOrderDetails(orderNumber); + await this.click(selector.vendor.orders.status.edit); + await this.selectByValue(selector.vendor.orders.status.orderStatus, status); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.status.updateOrderStatus); + const currentStatus = await this.getElementText(selector.vendor.orders.status.currentOrderStatus); + expect(currentStatus?.toLowerCase()).toBe(status.split('-').pop()); + // expect(currentOrderStatus?.toLowerCase()).toMatch((orderStatus.replace(/(^wc)|(\W)/g, '')).toLowerCase()); + } + + // add order note + async addOrderNote(orderNumber: string, orderNote: orderNote): Promise { + await this.goToOrderDetails(orderNumber); + await this.clearAndType(selector.vendor.orders.orderNote.orderNoteInput, orderNote.note); + await this.selectByLabel(selector.vendor.orders.orderNote.orderNoteType, orderNote.noteType); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.orderNote.addNote); + } + + // add tracking details + async addTrackingDetails(orderNumber: string, orderTrackingDetails: orderTrackingDetails): Promise { + await this.goToOrderDetails(orderNumber); + await this.click(selector.vendor.orders.trackingDetails.addTrackingNumber); + await this.clearAndType(selector.vendor.orders.trackingDetails.shippingProvider, orderTrackingDetails.shippingProvider); + await this.clearAndType(selector.vendor.orders.trackingDetails.trackingNumber, orderTrackingDetails.trackingNumber); + await this.setAttributeValue(selector.vendor.orders.trackingDetails.dateShipped, 'value', helpers.dateFormatFYJ(orderTrackingDetails.dateShipped)); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.trackingDetails.addTrackingDetails); + } + + // add shipment + async addShipment(orderNumber: string, shipmentDetails: orderShipmentDetails): Promise { + await this.goToOrderDetails(orderNumber); + await this.click(selector.vendor.orders.shipment.createNewShipment); + await this.click(selector.vendor.orders.shipment.shipmentOrderItem(shipmentDetails.shipmentOrderItem)); + await this.clearAndType(selector.vendor.orders.shipment.shipmentOrderItemQty(shipmentDetails.shipmentOrderItem), shipmentDetails.shipmentOrderItemQty); + await this.selectByValue(selector.vendor.orders.shipment.shippingStatus, shipmentDetails.shippingStatus); + await this.selectByValue(selector.vendor.orders.shipment.shippingProvider, shipmentDetails.shippingProvider); + await this.setAttributeValue(selector.vendor.orders.shipment.dateShipped, 'value', helpers.dateFormatFYJ(shipmentDetails.dateShipped)); + await this.clearAndType(selector.vendor.orders.shipment.trackingNumber, shipmentDetails.shippingProvider); + await this.clearAndType(selector.vendor.orders.shipment.comments, shipmentDetails.trackingNumber); + await this.click(selector.vendor.orders.shipment.notifyCustomer); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.shipment.createShipment); + // todo: add more assertion, success message, or short shipment description div + // todo: also assert on my order details or add new test + } + + // todo: update shipment test, shipment updates timeline + + // add Downloadable Product + async addDownloadableProduct(orderNumber: string, downloadableProductName: string): Promise { + await this.goToOrderDetails(orderNumber); + await this.clearAndType(selector.vendor.orders.downloadableProductPermission.downloadableProductInput, downloadableProductName); + await this.press(data.key.enter); + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.orders.downloadableProductPermission.grantAccess); // todo: need to fix + } + + // add Downloadable Product + async removeDownloadableProduct(orderNumber: string, downloadableProductName: string): Promise { + await this.addDownloadableProduct(orderNumber, downloadableProductName); // todo: do it via api + await this.click(selector.vendor.orders.downloadableProductPermission.revokeAccess); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.orders.downloadableProductPermission.confirmAction); + } + + // order bulk action + async orderBulkAction(action: string, orderNumber?: string): Promise { + orderNumber ? await this.searchOrder(orderNumber) : await this.goIfNotThere(data.subUrls.frontend.vDashboard.orders); + + await this.click(selector.vendor.orders.bulkActions.selectAll); + switch (action) { + case 'onhold': + await this.selectByValue(selector.vendor.orders.bulkActions.selectAction, 'wc-on-hold'); + break; + + case 'processing': + await this.selectByValue(selector.vendor.orders.bulkActions.selectAction, 'wc-processing'); + break; + + case 'completed': + await this.selectByValue(selector.vendor.orders.bulkActions.selectAction, 'wc-completed'); + break; + + default: + break; + } + + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.orders, selector.vendor.orders.bulkActions.applyAction); + } +} diff --git a/tests/pw/pages/paymentsPage.ts b/tests/pw/pages/paymentsPage.ts new file mode 100644 index 0000000000..26eda396c4 --- /dev/null +++ b/tests/pw/pages/paymentsPage.ts @@ -0,0 +1,361 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { payment, vendor } from '@utils/interfaces'; + +export class PaymentsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // Payment Methods + + // Admin Setup Basic Payment Methods + async setupBasicPaymentMethods(payment: payment) { + await this.goToWooCommerceSettings(); + + await this.click(selector.admin.wooCommerce.settings.payments); + // Bank Transfer + await this.enablePaymentMethod(selector.admin.wooCommerce.settings.enableDirectBankTransfer); + // Payments + await this.enablePaymentMethod(selector.admin.wooCommerce.settings.enableCheckPayments); + // Cash on Delivery + await this.enablePaymentMethod(selector.admin.wooCommerce.settings.enableCashOnDelivery); + + await this.click(selector.admin.wooCommerce.settings.paymentMethodsSaveChanges); + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, payment.saveSuccessMessage); + } + + // Admin Setup Stripe + async setupStripeConnect(payment: payment) { + await this.goToWooCommerceSettings(); + + await this.setCurrency(payment.currency.dollar); + + await this.click(selector.admin.wooCommerce.settings.payments); + await this.click(selector.admin.wooCommerce.settings.setupDokanStripeConnect); + // Setup Strip Connect + await this.check(selector.admin.wooCommerce.settings.stripe.enableDisableStripe); + await this.clearAndType(selector.admin.wooCommerce.settings.stripe.title, payment.stripeConnect.title); + await this.clearAndType(selector.admin.wooCommerce.settings.stripe.description, payment.stripeConnect.description); + await this.check(selector.admin.wooCommerce.settings.stripe.nonConnectedSellers); + await this.check(selector.admin.wooCommerce.settings.stripe.displayNoticeToConnectSeller); + await this.clearAndType(selector.admin.wooCommerce.settings.stripe.displayNoticeInterval, payment.stripeConnect.displayNoticeInterval); + await this.check(selector.admin.wooCommerce.settings.stripe.threeDSecureAndSca); + await this.check(selector.admin.wooCommerce.settings.stripe.sellerPaysTheProcessingFeeIn3DsMode); + await this.check(selector.admin.wooCommerce.settings.stripe.testMode); + await this.check(selector.admin.wooCommerce.settings.stripe.stripeCheckout); + await this.click(selector.admin.wooCommerce.settings.stripe.stripeCheckoutLocale); + await this.type(selector.admin.wooCommerce.settings.stripe.stripeCheckoutLocale, payment.stripeConnect.stripeCheckoutLocale); + await this.press(data.key.enter); + await this.check(selector.admin.wooCommerce.settings.stripe.savedCards); + // Test Credentials + await this.clearAndType(selector.admin.wooCommerce.settings.stripe.testPublishableKey, payment.stripeConnect.testPublishableKey); + await this.clearAndType(selector.admin.wooCommerce.settings.stripe.testSecretKey, payment.stripeConnect.testSecretKey); + await this.clearAndType(selector.admin.wooCommerce.settings.stripe.testClientId, payment.stripeConnect.testClientId); + await this.click(selector.admin.wooCommerce.settings.stripe.stripeSaveChanges); + + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, payment.saveSuccessMessage); + } + + // Admin Setup Dokan Paypal Marketplace + async setupPaypalMarketPlace(payment: payment) { + await this.goToWooCommerceSettings(); + + await this.setCurrency(payment.currency.dollar); + + await this.click(selector.admin.wooCommerce.settings.payments); + await this.click(selector.admin.wooCommerce.settings.setupDokanPayPalMarketplace); + // Setup Paypal Marketplace + await this.check(selector.admin.wooCommerce.settings.paypalMarketPlace.enableDisablePayPalMarketplace); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.title, payment.paypalMarketPlace.title); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.description, payment.paypalMarketPlace.description); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.payPalMerchantId, payment.paypalMarketPlace.payPalMerchantId); + // API Credentials + await this.check(selector.admin.wooCommerce.settings.paypalMarketPlace.payPalSandbox); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.sandboxClientId, payment.paypalMarketPlace.sandboxClientId); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.sandBoxClientSecret, payment.paypalMarketPlace.sandBoxClientSecret); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.payPalPartnerAttributionId, payment.paypalMarketPlace.payPalPartnerAttributionId); + await this.click(selector.admin.wooCommerce.settings.paypalMarketPlace.disbursementMode); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.paypalMarketPlace.disbursementModeValues, payment.paypalMarketPlace.disbursementMode); + await this.click(selector.admin.wooCommerce.settings.paypalMarketPlace.paymentButtonType); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.paypalMarketPlace.paymentButtonTypeValues, payment.paypalMarketPlace.paymentButtonType); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.marketplaceLogo, (await this.getBaseUrl()) + payment.paypalMarketPlace.marketplaceLogoPath); + await this.check(selector.admin.wooCommerce.settings.paypalMarketPlace.displayNoticeToConnectSeller); + await this.check(selector.admin.wooCommerce.settings.paypalMarketPlace.sendAnnouncementToConnectSeller); + await this.clearAndType(selector.admin.wooCommerce.settings.paypalMarketPlace.sendAnnouncementInterval, payment.paypalMarketPlace.announcementInterval); + await this.click(selector.admin.wooCommerce.settings.paypalMarketPlace.paypalMarketPlaceSaveChanges); + + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, payment.saveSuccessMessage); + } + + // Admin Setup Mangopay + async setupMangoPay(payment: payment) { + await this.goToWooCommerceSettings(); + + await this.setCurrency(payment.currency.euro); + + await this.click(selector.admin.wooCommerce.settings.payments); + await this.click(selector.admin.wooCommerce.settings.setupDokanMangoPay); + // Setup Mangopay + await this.check(selector.admin.wooCommerce.settings.dokanMangoPay.enableDisableMangoPayPayment); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanMangoPay.title, payment.mangoPay.title); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanMangoPay.description, payment.mangoPay.description); + // API Credentials + await this.check(selector.admin.wooCommerce.settings.dokanMangoPay.mangoPaySandbox); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanMangoPay.sandboxClientId, payment.mangoPay.sandboxClientId); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanMangoPay.sandBoxApiKey, payment.mangoPay.sandBoxApiKey); + // Payment Options + await this.click(selector.admin.wooCommerce.settings.dokanMangoPay.chooseAvailableCreditCards); + await this.type(selector.admin.wooCommerce.settings.dokanMangoPay.chooseAvailableCreditCards, 'CB/Visa/Mastercard'); + await this.press(data.key.enter); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.dokanMangoPay.chooseAvailableCreditCardsValues, payment.mangoPay.availableCreditCards); + await this.click(selector.admin.wooCommerce.settings.dokanMangoPay.chooseAvailableDirectPaymentServices); + await this.type(selector.admin.wooCommerce.settings.dokanMangoPay.chooseAvailableDirectPaymentServices, 'Sofort*'); + await this.press(data.key.enter); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.dokanMangoPay.chooseAvailableDirectPaymentServicesValues, payment.mangoPay.availableDirectPaymentServices); + await this.check(selector.admin.wooCommerce.settings.dokanMangoPay.savedCards); + // Fund Transfers and Payouts + await this.click(selector.admin.wooCommerce.settings.dokanMangoPay.transferFunds); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.dokanMangoPay.transferFundsValues, payment.mangoPay.transferFunds); + await this.check(selector.admin.wooCommerce.settings.dokanMangoPay.payoutMode); + // Types and Requirements of Vendors + await this.click(selector.admin.wooCommerce.settings.dokanMangoPay.typeOfVendors); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.dokanMangoPay.typeOfVendorsValues, payment.mangoPay.typeOfVendors); + await this.click(selector.admin.wooCommerce.settings.dokanMangoPay.businessRequirement); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.dokanMangoPay.businessRequirementValues, payment.mangoPay.businessRequirement); + // Advanced Settings + await this.check(selector.admin.wooCommerce.settings.dokanMangoPay.displayNoticeToNonConnectedSellers); + await this.check(selector.admin.wooCommerce.settings.dokanMangoPay.sendAnnouncementToNonConnectedSellers); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanMangoPay.announcementInterval, payment.mangoPay.announcementInterval); + await this.click(selector.admin.wooCommerce.settings.dokanMangoPay.dokanMangopaySaveChanges); + + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, payment.saveSuccessMessage); + } + + // Admin Setup Razorpay + async setupRazorpay(payment: payment) { + await this.goToWooCommerceSettings(); + + await this.setCurrency(payment.currency.rupee); + + await this.click(selector.admin.wooCommerce.settings.payments); + await this.click(selector.admin.wooCommerce.settings.setupDokanRazorpay); + // Setup Razorpay + await this.check(selector.admin.wooCommerce.settings.dokanRazorpay.enableDisableDokanRazorpay); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanRazorpay.title, payment.razorPay.title); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanRazorpay.description, payment.razorPay.description); + // API Credentials + await this.check(selector.admin.wooCommerce.settings.dokanRazorpay.razorpaySandbox); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanRazorpay.testKeyId, payment.razorPay.testKeyId); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanRazorpay.testKeySecret, payment.razorPay.testKeySecret); + await this.click(selector.admin.wooCommerce.settings.dokanRazorpay.disbursementMode); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.dokanRazorpay.disbursementModeValues, payment.razorPay.disbursementMode); + await this.check(selector.admin.wooCommerce.settings.dokanRazorpay.sellerPaysTheProcessingFee); + await this.check(selector.admin.wooCommerce.settings.dokanRazorpay.displayNoticeToConnectSeller); + await this.check(selector.admin.wooCommerce.settings.dokanRazorpay.sendAnnouncementToConnectSeller); + await this.clearAndType(selector.admin.wooCommerce.settings.dokanRazorpay.sendAnnouncementInterval, payment.razorPay.announcementInterval); + await this.click(selector.admin.wooCommerce.settings.dokanRazorpay.dokanRazorpaySaveChanges); + + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, payment.saveSuccessMessage); + } + + // Admin Setup Stripe Express + async setupStripeExpress(payment: payment) { + await this.goToWooCommerceSettings(); + + await this.setCurrency(payment.currency.dollar); + + await this.click(selector.admin.wooCommerce.settings.payments); + await this.click(selector.admin.wooCommerce.settings.setupDokanStripeExpress); + + // Stripe Express + await this.check(selector.admin.wooCommerce.settings.stripeExpress.enableOrDisableStripeExpress); + await this.clearAndType(selector.admin.wooCommerce.settings.stripeExpress.title, payment.stripeExpress.title); + await this.clearAndType(selector.admin.wooCommerce.settings.stripeExpress.description, payment.stripeExpress.description); + // API Credentials + await this.check(selector.admin.wooCommerce.settings.stripeExpress.testMode); + await this.clearAndType(selector.admin.wooCommerce.settings.stripeExpress.testPublishableKey, payment.stripeExpress.testPublishableKey); + await this.clearAndType(selector.admin.wooCommerce.settings.stripeExpress.testSecretKey, payment.stripeExpress.testSecretKey); + await this.clearAndType(selector.admin.wooCommerce.settings.stripeExpress.testWebhookSecret, payment.stripeExpress.testWebhookSecret); + // Payment and Disbursement + await this.click(selector.admin.wooCommerce.settings.stripeExpress.choosePaymentMethods); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.stripeExpress.choosePaymentMethodsValues, payment.stripeExpress.paymentMethods.card); + await this.click(selector.admin.wooCommerce.settings.stripeExpress.choosePaymentMethods); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.stripeExpress.choosePaymentMethodsValues, payment.stripeExpress.paymentMethods.ideal); + await this.check(selector.admin.wooCommerce.settings.stripeExpress.takeProcessingFeesFromSellers); + await this.check(selector.admin.wooCommerce.settings.stripeExpress.savedCards); + await this.check(selector.admin.wooCommerce.settings.stripeExpress.capturePaymentsManually); + await this.click(selector.admin.wooCommerce.settings.stripeExpress.disburseFunds); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.stripeExpress.disbursementModeValues, payment.stripeExpress.disbursementMode); + await this.clearAndType(selector.admin.wooCommerce.settings.stripeExpress.customerBankStatement, payment.stripeExpress.customerBankStatement); + // Payment Request Options (Apple Pay/Google Pay) + await this.check(selector.admin.wooCommerce.settings.stripeExpress.paymentRequestButtons); + await this.selectByValue(selector.admin.wooCommerce.settings.stripeExpress.buttonType, payment.stripeExpress.paymentRequestButtonType); + await this.selectByValue(selector.admin.wooCommerce.settings.stripeExpress.buttonTheme, payment.stripeExpress.paymentRequestButtonTheme); + await this.click(selector.admin.wooCommerce.settings.stripeExpress.buttonLocations); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.stripeExpress.buttonLocationsValues, payment.stripeExpress.paymentRequestButtonLocation.product); + await this.click(selector.admin.wooCommerce.settings.stripeExpress.buttonLocations); + await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.stripeExpress.buttonLocationsValues, payment.stripeExpress.paymentRequestButtonLocation.cart); + // Advanced Settings + await this.check(selector.admin.wooCommerce.settings.stripeExpress.displayNoticeToNonConnectedSellers); + await this.check(selector.admin.wooCommerce.settings.stripeExpress.sendAnnouncementToNonConnectedSellers); + await this.clearAndType(selector.admin.wooCommerce.settings.stripeExpress.announcementInterval, payment.stripeExpress.announcementInterval); + await this.click(selector.admin.wooCommerce.settings.stripeExpress.stripeExpressSaveChanges); + + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, payment.saveSuccessMessage); + } + + // vendor + + // payment settings render properly + async vendorPaymentSettingsRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsPayment); + + // paymentMethod text is visible + await this.toBeVisible(selector.vendor.vPaymentSettings.paymentMethodText); + + // paymentMethods summary div is visible + await this.toBeVisible(selector.vendor.vPaymentSettings.paymentMethods.paymentMethodsDiv); + // paymentMethods dropdown is visible + await this.toBeVisible(selector.vendor.vPaymentSettings.paymentMethods.addPaymentMethodDropDown); + + await this.notToHaveCount(selector.vendor.vPaymentSettings.paymentMethods.noOfPaymentMethods, 0); + } + + // vendor set basic payment settings + async setBasicPaymentSettings(payment: vendor['payment']): Promise { + await this.setBasicPayment({ ...data.vendor.payment, methodName: 'paypal' }); + await this.setBankTransfer(payment); + await this.setBasicPayment({ ...data.vendor.payment, methodName: 'skrill' }); + await this.setBasicPayment({ ...data.vendor.payment, methodName: 'custom' }); + } + + // set basic payment method [paypal, skrill, custom ] + async setBasicPayment(paymentMethod: vendor['payment']): Promise { + switch (paymentMethod.methodName) { + case 'paypal': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.paypal); + break; + + case 'skrill': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.skrill); + break; + + case 'custom': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.customPayment); + break; + + default: + break; + } + + await this.clearAndType(selector.vendor.vPaymentSettings.paymentEmail, paymentMethod.email()); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vPaymentSettings.updateSettings); + await this.toContainText(selector.vendor.vPaymentSettings.updateSettingsSuccessMessage, paymentMethod.saveSuccessMessage); + } + + // bank transfer payment settings + async setBankTransfer(paymentMethod: vendor['payment']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.bankTransfer); + + await this.clickIfVisible(selector.vendor.vPaymentSettings.disconnectAccount); + await this.clearAndType(selector.vendor.vPaymentSettings.bankAccountName, paymentMethod.bankAccountName); + await this.selectByValue(selector.vendor.vPaymentSettings.bankAccountType, paymentMethod.bankAccountType); + await this.clearAndType(selector.vendor.vPaymentSettings.bankAccountNumber, paymentMethod.bankAccountNumber); + await this.clearAndType(selector.vendor.vPaymentSettings.bankRoutingNumber, paymentMethod.bankRoutingNumber); + await this.clearAndType(selector.vendor.vPaymentSettings.bankName, paymentMethod.bankName); + await this.clearAndType(selector.vendor.vPaymentSettings.bankAddress, paymentMethod.bankAddress); + await this.clearAndType(selector.vendor.vPaymentSettings.bankIban, paymentMethod.bankIban); + await this.clearAndType(selector.vendor.vPaymentSettings.bankSwiftCode, paymentMethod.bankSwiftCode); + await this.check(selector.vendor.vSetup.declaration); + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vPaymentSettings.addAccount); + await this.toContainText(selector.vendor.vPaymentSettings.updateSettingsSuccessMessage, paymentMethod.saveSuccessMessage); + } + + // disconnect basic payment method [paypal, skrill, custom ] + async disconnectBasicPayment(paymentMethod: vendor['payment']): Promise { + switch (paymentMethod.methodName) { + case 'paypal': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.paypal); + break; + + case 'bank': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.bankTransfer); + break; + + case 'skrill': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.skrill); + break; + + case 'custom': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.customPayment); + break; + + default: + break; + } + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vPaymentSettings.disconnectPayment); + await this.toContainText(selector.vendor.vPaymentSettings.updateSettingsSuccessMessage, paymentMethod.saveSuccessMessage); + } + + // // paypal payment settings + // async setPaypal(paymentMethod: vendor['payment']): Promise { + // await this.goIfNotThere(data.subUrls.frontend.vDashboard.paypal); + // await this.clearAndType(selector.vendor.vPaymentSettings.paypal, paymentMethod.email()); + // await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vPaymentSettings.updateSettings); + // await this.toContainText(selector.vendor.vPaymentSettings.updateSettingsSuccessMessage, paymentMethod.saveSuccessMessage); + // } + + // // skrill Payment Settings + // async setSkrill(paymentMethod: vendor['payment']): Promise { + + // await this.clearAndType(selector.vendor.vPaymentSettings.skrill, paymentMethod.email()); + // await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vPaymentSettings.updateSettings); + // await this.toContainText(selector.vendor.vPaymentSettings.updateSettingsSuccessMessage, paymentMethod.saveSuccessMessage); + // } + + // // custom payment settings + // async setCustom(paymentMethod: vendor['payment']): Promise { + + // await this.clearAndType(selector.vendor.vPaymentSettings.customPayment, paymentMethod.email()); + // await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vPaymentSettings.updateSettings); + // await this.toContainText(selector.vendor.vPaymentSettings.updateSettingsSuccessMessage, paymentMethod.saveSuccessMessage); + // } + + // // stripe payment settings + // async setStripe(email): Promise { + // // Stripe + // await this.click(selector.vendor.vPaymentSettings.ConnectWithStripe); + // } + + // // paypal marketPlace payment settings + // async setPaypalMarketPlace(email): Promise { + // // paypal Marketplace + // await this.clearAndType(selector.vendor.vPaymentSettings.paypalMarketplace, paypalMarketplace); + // await this.click(selector.vendor.vPaymentSettings.paypalMarketplaceSignUp); + // } + + // // razorpay payment settings + // async setRazorpay(razorpay): Promise { + // // razorpay + // await this.click(selector.vendor.vPaymentSettings.rzSignup); + // // existing account info + // await this.click(selector.vendor.vPaymentSettings.rzIHaveAlreadyAnAccount); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzAccountId, rzAccountId); + // await this.click(selector.vendor.vPaymentSettings.rzConnectExistingAccount); + // //new account info + // await this.clearAndType(selector.vendor.vPaymentSettings.rzAccountName, rzAccountName); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzAccountEmail, rzAccountEmail); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzYourCompanyName, rzYourCompanyName); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzYourCompanyType, rzYourCompanyType); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzBankAccountName, rzBankAccountName); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzBankAccountNumber, rzBankAccountNumber); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzBankIfscCode, rzBankIfscCode); + // await this.clearAndType(selector.vendor.vPaymentSettings.rzBankAccountType, rzBankAccountType); + // await this.click(selector.vendor.vPaymentSettings.rzConnectAccount); + // } +} diff --git a/tests/pw/pages/proPromoPage.ts b/tests/pw/pages/proPromoPage.ts new file mode 100644 index 0000000000..c150c6d2b7 --- /dev/null +++ b/tests/pw/pages/proPromoPage.ts @@ -0,0 +1,42 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class ProPromoPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // dokan pro promo + async dokanProPromo() { + // dokan promo banner + await this.goIfNotThere(data.subUrls.backend.dokan.dokan); + + // promo banner elements are visible + await this.multipleElementVisible(selector.admin.dokan.promoBanner); + + // dokan lite modules + await this.goIfNotThere(data.subUrls.backend.dokan.liteModules); + + // pro upgrade popup elements are visible + await this.multipleElementVisible(selector.admin.dokan.modules.lite.popup); + + // module cards are visible + await this.click(selector.admin.dokan.modules.lite.popup.closeDokanUpgradePopup); + await this.toBeVisible(selector.admin.dokan.modules.lite.moduleText); + await this.toHaveCount(selector.admin.dokan.modules.lite.moduleCard, 27); + + // dokan pro features menu + await this.goIfNotThere(data.subUrls.backend.dokan.proFeatures); + + // dokan pro feature sections are visible + await this.multipleElementVisible(selector.admin.dokan.proFeatures); + + // dokan settings pro advertisement + await this.goToDokanSettings(); + + // settings pro advertisement banner elements are visible + await this.multipleElementVisible(selector.admin.dokan.settings.proAdvertisementBanner); + } +} diff --git a/tests/pw/pages/productAddonsPage.ts b/tests/pw/pages/productAddonsPage.ts new file mode 100644 index 0000000000..a71d8bc8a3 --- /dev/null +++ b/tests/pw/pages/productAddonsPage.ts @@ -0,0 +1,91 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { vendor } from '@utils/interfaces'; + +export class ProductAddonsPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // product addons render properly + async vendorProductAddonsSettingsRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsAddon); + + // product addon text is visible + await this.toBeVisible(selector.vendor.vAddonSettings.productAddonsText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vAddonSettings.visitStore); + + // create new addon text is visible + await this.toBeVisible(selector.vendor.vAddonSettings.createNewAddon); + + // create new text is visible + await this.toBeVisible(selector.vendor.vAddonSettings.createNew); + + // product addon table elements are visible + await this.multipleElementVisible(selector.vendor.vAddonSettings.table); + + await this.click(selector.vendor.vAddonSettings.createNewAddon); + await this.click(selector.vendor.vAddonSettings.addon.addField); + await this.check(selector.vendor.vAddonSettings.addon.enableDescription); + + // product addon fields elements are visible + const { addonFieldsRow, addonUpdateSuccessMessage, ...addonFields } = selector.vendor.vAddonSettings.addon; + await this.multipleElementVisible(addonFields); + + await this.clickAndWaitForLoadState(selector.vendor.vAddonSettings.backToAddonLists); + } + + // update addon fields + async updateAddonFields(addon: vendor['addon'], add = true) { + await this.clearAndType(selector.vendor.vAddonSettings.addon.name, addon.name); + await this.clearAndType(selector.vendor.vAddonSettings.addon.priority, addon.priority); + + // skipped category + // await this.click(selector.vendor.vAddonSettings.addon.productCategories); + // await this.clearAndType(selector.vendor.vAddonSettings.addon.productCategories, addon.category); + // await this.press(data.key.enter); + + add ? await this.click(selector.vendor.vAddonSettings.addon.addField) : await this.click(selector.vendor.vAddonSettings.addon.addonFieldsRow('Add-on Title')); + + await this.selectByValue(selector.vendor.vAddonSettings.addon.type, addon.type); + await this.selectByValue(selector.vendor.vAddonSettings.addon.displayAs, addon.displayAs); + await this.clearAndType(selector.vendor.vAddonSettings.addon.titleRequired, addon.titleRequired); + await this.selectByValue(selector.vendor.vAddonSettings.addon.formatTitle, addon.formatTitle); + await this.check(selector.vendor.vAddonSettings.addon.enableDescription); + await this.clearAndType(selector.vendor.vAddonSettings.addon.addDescription, addon.addDescription); + // await this.click(selector.vendor.vAddonSettings.addon.requiredField); + await this.clearAndType(selector.vendor.vAddonSettings.addon.enterAnOption, addon.enterAnOption); + await this.selectByValue(selector.vendor.vAddonSettings.addon.optionPriceType, addon.optionPriceType); + await this.clearAndType(selector.vendor.vAddonSettings.addon.optionPriceInput, addon.optionPriceInput); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.settingsAddon, selector.vendor.vAddonSettings.addon.publishOrUpdate); + await this.toContainText(selector.vendor.vAddonSettings.addon.addonUpdateSuccessMessage, addon.saveSuccessMessage); + } + + // add addon + async addAddon(addon: vendor['addon']) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsAddon); + await this.click(selector.vendor.vAddonSettings.createNewAddon); + await this.updateAddonFields(addon); + } + + // edit addon + async editAddon(addon: vendor['addon']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsAddon); + await this.hover(selector.vendor.vAddonSettings.addonRow(addon.name)); + await this.clickAndWaitForLoadState(selector.vendor.vAddonSettings.editAddon(addon.name)); + await this.updateAddonFields(addon, false); + } + + // delete addon + async deleteAddon(addon: vendor['addon']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsAddon); + await this.hover(selector.vendor.vAddonSettings.addonRow(addon.name)); + await this.clickAndWaitForLoadState(selector.vendor.vAddonSettings.deleteAddon(addon.name)); + await this.toContainText(selector.vendor.vAddonSettings.addon.addonUpdateSuccessMessage, addon.deleteSuccessMessage); + } +} diff --git a/tests/pw/pages/productAdvertisingPage.ts b/tests/pw/pages/productAdvertisingPage.ts new file mode 100644 index 0000000000..40765115bb --- /dev/null +++ b/tests/pw/pages/productAdvertisingPage.ts @@ -0,0 +1,157 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { productAdvertisement } from '@utils/interfaces'; + +export class ProductAdvertisingPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // product advertising + + // regenerate product advertisement payment product + async recreateProductAdvertisementPaymentViaSettingsSave() { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.productAdvertising); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.dokan.settings.productAdvertising.productAdvertisingSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, 'Setting has been saved successfully.'); + } + + // product advertising render properly + async adminProductAdvertisingRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.productAdvertising); + + // product advertising text is visible + await this.toBeVisible(selector.admin.dokan.productAdvertising.productAdvertisingText); + + // add new Advertisement is visible + await this.toBeVisible(selector.admin.dokan.productAdvertising.addNewProductAdvertising); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.productAdvertising.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.productAdvertising.bulkActions); + + // filter elements are visible + const { filterByStoreInput, filterByCreatedVia, ...filters } = selector.admin.dokan.productAdvertising.filters; + await this.multipleElementVisible(filters); + + // product advertising search is visible + await this.toBeVisible(selector.admin.dokan.productAdvertising.search); + + // product advertising table elements are visible + await this.multipleElementVisible(selector.admin.dokan.productAdvertising.table); + + // product advertising modal elements are visible + await this.click(selector.admin.dokan.productAdvertising.addNewProductAdvertising); + await this.toBeVisible(selector.admin.dokan.productAdvertising.addNewAdvertisement.selectStoreDropdown); + await this.toBeVisible(selector.admin.dokan.productAdvertising.addNewAdvertisement.selectProductDropdown); + await this.click(selector.admin.dokan.productAdvertising.addNewAdvertisement.closeModal); + } + + // add new product advertisement + async addNewProductAdvertisement(advertising: productAdvertisement) { + await this.goIfNotThere(data.subUrls.backend.dokan.productAdvertising); + + await this.click(selector.admin.dokan.productAdvertising.addNewProductAdvertising); + + await this.click(selector.admin.dokan.productAdvertising.addNewAdvertisement.selectStoreDropdown); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.productAdvertising.addNewAdvertisement.selectStoreInput, advertising.advertisedProductStore); + await this.toContainText(selector.admin.dokan.productAdvertising.addNewAdvertisement.selectedStore, advertising.advertisedProductStore); + await this.press(data.key.enter); + + await this.click(selector.admin.dokan.productAdvertising.addNewAdvertisement.selectProductDropdown); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.products, selector.admin.dokan.productAdvertising.addNewAdvertisement.selectProductInput, advertising.advertisedProduct); + await this.toContainText(selector.admin.dokan.productAdvertising.addNewAdvertisement.selectedProduct, advertising.advertisedProduct); + await this.press(data.key.enter); + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.addNewAdvertisement.addNew); + await this.click(selector.admin.dokan.productAdvertising.actionSuccessful); + + // close modal + await this.click(selector.admin.dokan.productAdvertising.addNewAdvertisement.closeModal); + } + + // search advertised product + async searchAdvertisedProduct(productOrOrder: string | number) { + await this.goIfNotThere(data.subUrls.backend.dokan.productAdvertising); + + await this.clearInputField(selector.admin.dokan.productAdvertising.search); + + await this.typeAndWaitForResponseAndLoadState(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.search, String(productOrOrder)); + if (typeof productOrOrder != 'number') { + await this.toBeVisible(selector.admin.dokan.productAdvertising.advertisedProductCell(productOrOrder)); + } else { + await this.toBeVisible(selector.admin.dokan.productAdvertising.advertisedProductOrderIdCell(productOrOrder)); + } + } + + // filter advertised product + async filterAdvertisedProduct(input: string, action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.productAdvertising); + + switch (action) { + case 'by-store': + await this.click(selector.admin.dokan.productAdvertising.filters.allStoresDropdown); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.filters.filterByStoreInput, input); + await this.pressAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, data.key.enter); + break; + + case 'by-creation': + await this.click(selector.admin.dokan.productAdvertising.filters.createdViaDropdown); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.filters.filterByCreatedVia(input)); + break; + + default: + break; + } + + const count = (await this.getElementText(selector.admin.dokan.productAdvertising.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + + // clear filter + await this.clickAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.filters.clearFilter); + } + + // update advertised product + async updateAdvertisedProduct(productName: string, action: string) { + await this.searchAdvertisedProduct(productName); + + await this.hover(selector.admin.dokan.productAdvertising.advertisedProductCell(productName)); + switch (action) { + case 'expire': + await this.click(selector.admin.dokan.productAdvertising.advertisedProductExpire(productName)); + break; + + case 'delete': + await this.click(selector.admin.dokan.productAdvertising.advertisedProductDelete(productName)); + break; + + default: + break; + } + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.confirmAction); + await this.click(selector.admin.dokan.productAdvertising.actionSuccessful); + + // refresh table by clicking filter + await this.clickAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.filters.clearFilter); + } + + // product advertising bulk action + async productAdvertisingBulkAction(action: string, productName?: string) { + productName ? await this.searchAdvertisedProduct(productName) : await this.goIfNotThere(data.subUrls.backend.dokan.productAdvertising); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.productAdvertising.noRowsFound); + + await this.click(selector.admin.dokan.productAdvertising.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.productAdvertising.bulkActions.selectAction, action); + await this.click(selector.admin.dokan.productAdvertising.bulkActions.applyAction); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.productAdvertising, selector.admin.dokan.productAdvertising.confirmAction); + await this.click(selector.admin.dokan.productAdvertising.actionSuccessful); + } +} diff --git a/tests/pw/pages/productEnquiryPage.ts b/tests/pw/pages/productEnquiryPage.ts new file mode 100644 index 0000000000..80e033537f --- /dev/null +++ b/tests/pw/pages/productEnquiryPage.ts @@ -0,0 +1,27 @@ +import { Page } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { product } from '@utils/interfaces'; + +export class ProductEnquiryPage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // product enquiry + + // enquire product + async enquireProduct(productName: string, enquiry: product['enquiry']): Promise { + await this.goToProductDetails(productName); + await this.click(selector.customer.cSingleProduct.menus.productEnquiry); + const isGuest = await this.isVisible(selector.customer.cSingleProduct.productEnquiry.guest.guestName); + if (isGuest) { + await this.clearAndType(selector.customer.cSingleProduct.productEnquiry.guest.guestName, enquiry.guestName()); + await this.clearAndType(selector.customer.cSingleProduct.productEnquiry.guest.guestEmail, enquiry.guestEmail()); + } + await this.clearAndType(selector.customer.cSingleProduct.productEnquiry.enquiryMessage, enquiry.enquiryDetails); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleProduct.productEnquiry.submitEnquiry); + await this.toContainText(selector.customer.cSingleProduct.productEnquiry.submitEnquirySuccessMessage, enquiry.enquirySubmitSuccessMessage); + } +} diff --git a/tests/pw/pages/productReviewsPage.ts b/tests/pw/pages/productReviewsPage.ts new file mode 100644 index 0000000000..996adef1fe --- /dev/null +++ b/tests/pw/pages/productReviewsPage.ts @@ -0,0 +1,96 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class ProductReviewsPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // vendor product review render properly + async vendorProductReviewsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reviews); + + // settings text is visible + await this.toBeVisible(selector.vendor.vReviews.reviewsText); + + // product review menu elements are visible + await this.multipleElementVisible(selector.vendor.vReviews.menus); + + // product review bulk action elements are visible + await this.multipleElementVisible(selector.vendor.vReviews.bulkActions); + + // product review table elements are visible + await this.multipleElementVisible(selector.vendor.vReviews.table); + + const noReviewsFound = await this.isVisible(selector.vendor.vReviews.noReviewsFound); + if (noReviewsFound) { + return; + } + + await this.notToHaveCount(selector.vendor.vReviews.numberOfRowsFound, 0); + } + + // view product review + async viewProductReview(reviewMessage: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reviews); + await this.clickAndWaitForLoadState(selector.vendor.vReviews.reviewLink(reviewMessage)); + await this.toBeVisible(selector.vendor.vReviews.reviewDetails.reviewMessageByMessage(reviewMessage)); + } + + // update product review status + async updateProductReview(action: string, reviewMessage: string) { + await this.goto(data.subUrls.frontend.vDashboard.reviews); + + switch (action) { + case 'unApprove': + await this.hover(selector.vendor.vReviews.reviewMessageCell(reviewMessage)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReviews.unApproveReview(reviewMessage)); + break; + + case 'spam': + await this.hover(selector.vendor.vReviews.reviewMessageCell(reviewMessage)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReviews.spamReview(reviewMessage)); + break; + + case 'trash': + await this.hover(selector.vendor.vReviews.reviewMessageCell(reviewMessage)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReviews.trashReview(reviewMessage)); + break; + + case 'approve': + await this.clickAndWaitForLoadState(selector.vendor.vReviews.menus.pending); + await this.hover(selector.vendor.vReviews.reviewMessageCell(reviewMessage)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReviews.approveReview(reviewMessage)); + break; + + case 'restore': + await this.clickAndWaitForLoadState(selector.vendor.vReviews.menus.trash); + await this.hover(selector.vendor.vReviews.reviewMessageCell(reviewMessage)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReviews.restoreReview(reviewMessage)); + break; + + case 'permanently-delete': + await this.clickAndWaitForLoadState(selector.vendor.vReviews.menus.trash); + await this.hover(selector.vendor.vReviews.reviewMessageCell(reviewMessage)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReviews.permanentlyDeleteReview(reviewMessage)); + break; + + default: + break; + } + } + + // product review bulk action + async productReviewsBulkActions(action: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reviews); + + // ensure row exists + await this.notToBeVisible(selector.vendor.vReviews.noReviewsFound); + + await this.click(selector.vendor.vReviews.bulkActions.selectAll); + await this.selectByValue(selector.vendor.vReviews.bulkActions.selectAction, action); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.reviews, selector.vendor.vReviews.bulkActions.applyAction); + } +} diff --git a/tests/pw/pages/productsPage.ts b/tests/pw/pages/productsPage.ts new file mode 100644 index 0000000000..293fa96c1d --- /dev/null +++ b/tests/pw/pages/productsPage.ts @@ -0,0 +1,589 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +// import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { product, vendor } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class ProductsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // admin add product category + async addCategory(categoryName: string) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewCategories); + await this.fill(selector.admin.products.category.name, categoryName); + await this.fill(selector.admin.products.category.slug, categoryName); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.products.category.addNewCategory); + await this.toBeVisible(selector.admin.products.category.categoryCell(categoryName)); + } + + // admin add product attribute + async addAttribute(attribute: product['attribute']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewAttributes); + await this.fill(selector.admin.products.attribute.name, attribute.attributeName); + await this.fill(selector.admin.products.attribute.slug, attribute.attributeName); + await this.clickAndWaitForResponse(data.subUrls.backend.wc.addNewAttributes, selector.admin.products.attribute.addAttribute); + await this.toBeVisible(selector.admin.products.attribute.attributeCell(attribute.attributeName)); + await this.clickAndWaitForResponse(data.subUrls.backend.wc.taxonomy, selector.admin.products.attribute.configureTerms(attribute.attributeName)); + + // add new term + for (const attributeTerm of attribute.attributeTerms) { + await this.fill(selector.admin.products.attribute.attributeTerm, attributeTerm); + await this.fill(selector.admin.products.attribute.attributeTermSlug, attributeTerm); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.products.attribute.addAttributeTerm); + await this.toBeVisible(selector.admin.products.attribute.attributeTermCell(attributeTerm)); + } + } + + // admin add simple product + async addSimpleProduct(product: product['simple']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // product basic info + await this.type(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + await this.click(selector.admin.products.product.general); + await this.type(selector.admin.products.product.regularPrice, product.regularPrice()); + await this.click(selector.admin.products.product.category(product.category)); + + // stock status + if (product.stockStatus) { + await this.click(selector.admin.products.product.inventory); + await this.selectByValue(selector.admin.products.product.stockStatus, data.product.stockStatus.outOfStock); + } + + // vendor Store Name + await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + await this.scrollToTop(); + + switch (product.status) { + case 'publish': + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.products.product.publish); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + break; + + case 'draft': + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.saveDraft, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.draftUpdateSuccessMessage); + break; + + case 'pending': + await this.click(selector.admin.products.product.editStatus); + await this.selectByValue(selector.admin.products.product.status, data.product.status.pending); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.saveDraft, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.pendingProductUpdateSuccessMessage); + break; + + default: + break; + } + } + + // admin add variable product + async addVariableProduct(product: product['variable']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // name + await this.type(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + + // add attributes + await this.click(selector.admin.products.product.attributes); + + if (await this.isVisibleLocator(selector.admin.products.product.customProductAttribute)) { + await this.selectByValue(selector.admin.products.product.customProductAttribute, `pa_${product.attribute}`); + await this.click(selector.admin.products.product.addAttribute); + } else { + await this.clickAndWaitForResponse(data.subUrls.backend.wc.searchAttribute, selector.admin.products.product.addExistingAttribute); + await this.typeAndWaitForResponse(data.subUrls.backend.wc.term, selector.admin.products.product.addExistingAttributeInput, product.attribute); + await this.pressAndWaitForResponse(data.subUrls.ajax, data.key.enter); + } + + await this.clickAndWaitForResponse(data.subUrls.backend.wc.taxonomyTerms, selector.admin.products.product.selectAll); + await this.check(selector.admin.products.product.usedForVariations); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.products.product.saveAttributes); + + // add variations + await this.click(selector.admin.products.product.variations); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.admin.products.product.generateVariations); + this.fillAlert('100'); + await this.selectByValue(selector.admin.products.product.addVariations, product.variations.variableRegularPrice); + + // category + await this.click(selector.admin.products.product.category(product.category)); + + // Vendor Store Name + await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + await this.scrollToTop(); + + // Publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + } + + // Admin Add Simple Subscription Product + async addSimpleSubscription(product: product['simpleSubscription']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // Name + await this.type(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + await this.click(selector.admin.products.product.general); + await this.type(selector.admin.products.product.subscriptionPrice, product.subscriptionPrice()); + await this.selectByValue(selector.admin.products.product.subscriptionPeriodInterval, product.subscriptionPeriodInterval); + await this.selectByValue(selector.admin.products.product.subscriptionPeriod, product.subscriptionPeriod); + await this.selectByValue(selector.admin.products.product.expireAfter, product.expireAfter); + await this.type(selector.admin.products.product.subscriptionTrialLength, product.subscriptionTrialLength); + await this.selectByValue(selector.admin.products.product.subscriptionTrialPeriod, product.subscriptionTrialPeriod); + + // Category + await this.click(selector.admin.products.product.category(product.category)); + + // Vendor Store Name + await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + await this.scrollToTop(); + + // Publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + } + + // admin add variable product + async addVariableSubscription(product: product['variableSubscription']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // name + await this.type(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + + // add attributes + await this.click(selector.admin.products.product.attributes); + + if (await this.isVisibleLocator(selector.admin.products.product.customProductAttribute)) { + await this.selectByValue(selector.admin.products.product.customProductAttribute, `pa_${product.attribute}`); + await this.click(selector.admin.products.product.addAttribute); + } else { + await this.clickAndWaitForResponse(data.subUrls.backend.wc.searchAttribute, selector.admin.products.product.addExistingAttribute); + await this.typeAndWaitForResponse(data.subUrls.backend.wc.term, selector.admin.products.product.addExistingAttributeInput, product.attribute); + await this.pressAndWaitForResponse(data.subUrls.ajax, data.key.enter); + } + + await this.clickAndWaitForResponse(data.subUrls.backend.wc.taxonomyTerms, selector.admin.products.product.selectAll); + await this.check(selector.admin.products.product.usedForVariations); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.products.product.saveAttributes); + // await this.wait(2); + + // add variations + await this.click(selector.admin.products.product.variations); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.admin.products.product.generateVariations); + this.fillAlert('100'); + await this.selectByValue(selector.admin.products.product.addVariations, product.variations.variableRegularPrice); + + // category + await this.click(selector.admin.products.product.category(product.category)); + + // Vendor Store Name + await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + await this.scrollToTop(); + + // Publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + } + + // Admin Add External Product + async addExternalProduct(product: product['external']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // Name + await this.type(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + await this.click(selector.admin.products.product.general); + await this.type(selector.admin.products.product.productUrl, this.getBaseUrl() + product.productUrl); + await this.type(selector.admin.products.product.buttonText, product.buttonText); + await this.type(selector.admin.products.product.regularPrice, product.regularPrice()); + + // Category + await this.click(selector.admin.products.product.category(product.category)); + + // Vendor Store Name + await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + await this.scrollToTop(); + + // Publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + } + + // Admin Add Dokan Subscription Product + async addDokanSubscription(product: product['vendorSubscription']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // Name + await this.type(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + await this.click(selector.admin.products.product.general); + await this.type(selector.admin.products.product.regularPrice, product.regularPrice()); + + // Category + await this.click(selector.admin.products.product.category(product.category)); + + // Subscription Details + await this.type(selector.admin.products.product.numberOfProducts, product.numberOfProducts); + await this.type(selector.admin.products.product.packValidity, product.packValidity); + await this.type(selector.admin.products.product.advertisementSlot, product.advertisementSlot); + await this.type(selector.admin.products.product.expireAfterDays, product.expireAfterDays); + await this.click(selector.admin.products.product.recurringPayment); + + // // Vendor Store Name + // await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + // await this.scrollToTop(); + + // Publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + } + + // vendor + + // products render properly + async vendorProductsRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + + // product nav menus are visible + const { draft, pendingReview, ...menus } = selector.vendor.product.menus; + await this.multipleElementVisible(menus); + + // add new product is visible + await this.toBeVisible(selector.vendor.product.create.addNewProduct); + + // import export is visible + DOKAN_PRO && (await this.multipleElementVisible(selector.vendor.product.importExport)); + + // product filters elements are visible + const { filterByType, filterByOther, ...filters } = selector.vendor.product.filters; + await this.multipleElementVisible(filters); + DOKAN_PRO && (await this.toBeVisible(filterByType)); + DOKAN_PRO && (await this.toBeVisible(filterByOther)); + + // product search elements are visible + await this.multipleElementVisible(selector.vendor.product.search); + + // bulk action elements are visible + await this.multipleElementVisible(selector.vendor.product.bulkActions); + + // table elements are visible + const { productAdvertisementColumn, ...table } = selector.vendor.product.table; + await this.multipleElementVisible(table); + } + + // products + + // vendor add product + async addProduct(product: product['simple'] | product['variable'] | product['simpleSubscription'] | product['external']): Promise { + const productName = product.productName(); + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + await this.clickAndWaitForLoadState(selector.vendor.product.create.addNewProduct); + await this.clearAndType(selector.vendor.product.edit.title, productName); + } + + // vendor add simple product + async vendorAddSimpleProduct(product: product['simple'] | product['variable'] | product['simpleSubscription'] | product['external'], productPopup = false): Promise { + const productName = product.productName(); + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + if (productPopup) { + await this.click(selector.vendor.product.create.addNewProduct); + await this.waitForVisibleLocator(selector.vendor.product.create.productName); + await this.clearAndType(selector.vendor.product.create.productName, productName); + await this.clearAndType(selector.vendor.product.create.productPrice, product.regularPrice()); + // await this.addProductCategory(product.category); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.product.create.createProduct); + const createdProduct = await this.getElementValue(selector.vendor.product.edit.title); + expect(createdProduct.toLowerCase()).toBe(productName.toLowerCase()); + } else { + await this.clickAndWaitForLoadState(selector.vendor.product.create.addNewProduct); + await this.clearAndType(selector.vendor.product.edit.title, productName); + await this.clearAndType(selector.vendor.product.edit.price, product.regularPrice()); + // await this.addProductCategory(product.category); + + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.dokanMessage, 'The product has been saved successfully. '); + } + } + + // vendor add variable product + async vendorAddVariableProduct(product: product['variable'], productPopup = false): Promise { + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + + // edit product + await this.selectByValue(selector.vendor.product.edit.productType, product.productType); + // add variation + await this.selectByValue(selector.vendor.product.attribute.customProductAttribute, `pa_${product.attribute}`); + await this.click(selector.vendor.product.attribute.addAttribute); + await this.click(selector.vendor.product.attribute.selectAll); + await this.click(selector.vendor.product.attribute.usedForVariations); + await this.click(selector.vendor.product.attribute.saveAttributes); + await this.selectByValue(selector.vendor.product.attribute.addVariations, product.variations.linkAllVariation); + await this.click(selector.vendor.product.attribute.go); + await this.click(selector.vendor.product.attribute.confirmGo); + await this.click(selector.vendor.product.attribute.okSuccessAlertGo); + await this.selectByValue(selector.vendor.product.attribute.addVariations, product.variations.variableRegularPrice); + await this.click(selector.vendor.product.attribute.go); + await this.type(selector.vendor.product.attribute.variationPrice, product.regularPrice()); + await this.click(selector.vendor.product.attribute.okVariationPrice); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // vendor add simple subscription product + async vendorAddSimpleSubscription(product: product['simpleSubscription'], productPopup = false): Promise { + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + // edit product + await this.selectByValue(selector.vendor.product.edit.productType, product.productType); + await this.type(selector.vendor.product.edit.subscriptionPrice, product.subscriptionPrice()); + await this.selectByValue(selector.vendor.product.edit.subscriptionPeriodInterval, product.subscriptionPeriodInterval); + await this.selectByValue(selector.vendor.product.edit.subscriptionPeriod, product.subscriptionPeriod); + await this.selectByValue(selector.vendor.product.edit.expireAfter, product.expireAfter); + await this.type(selector.vendor.product.edit.subscriptionTrialLength, product.subscriptionTrialLength); + await this.selectByValue(selector.vendor.product.edit.subscriptionTrialPeriod, product.subscriptionTrialPeriod); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // vendor add variable subscription product + async vendorAddVariableSubscription(product: product['variableSubscription'], productPopup = false): Promise { + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + // edit product + await this.selectByValue(selector.vendor.product.edit.productType, product.productType); + // add variation + await this.selectByValue(selector.vendor.product.attribute.customProductAttribute, `pa_${product.attribute}`); + await this.click(selector.vendor.product.attribute.addAttribute); + await this.click(selector.vendor.product.attribute.selectAll); + await this.click(selector.vendor.product.attribute.usedForVariations); + await this.click(selector.vendor.product.attribute.saveAttributes); + await this.selectByValue(selector.vendor.product.attribute.addVariations, product.variations.linkAllVariation); + await this.click(selector.vendor.product.attribute.go); + await this.click(selector.vendor.product.attribute.confirmGo); + await this.click(selector.vendor.product.attribute.okSuccessAlertGo); + await this.selectByValue(selector.vendor.product.attribute.addVariations, product.variations.variableRegularPrice); + await this.click(selector.vendor.product.attribute.go); + await this.type(selector.vendor.product.attribute.variationPrice, product.regularPrice()); + await this.click(selector.vendor.product.attribute.okVariationPrice); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // vendor add external product + async vendorAddExternalProduct(product: product['external'], productPopup = false): Promise { + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + // edit product + await this.selectByValue(selector.vendor.product.edit.productType, product.productType); + await this.type(selector.vendor.product.edit.productUrl, this.getBaseUrl() + product.productUrl); + await this.type(selector.vendor.product.edit.buttonText, product.buttonText); + await this.clearAndType(selector.vendor.product.edit.price, product.regularPrice()); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // go to product edit + async goToProductEdit(productName: string): Promise { + await this.searchProduct(productName); + await this.hover(selector.vendor.product.productCell(productName)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.editProduct(productName)); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + } + + // vendor add product category + async addProductCategory(category: string): Promise { + const productPopup = await this.isVisible(selector.vendor.product.create.productPopup); + productPopup ? await this.click(selector.vendor.product.category.productCategoryModalOnProductPopup) : await this.click(selector.vendor.product.category.productCategoryModal); + await this.waitForVisibleLocator(selector.vendor.product.category.productCategorySearchInput); + await this.type(selector.vendor.product.category.productCategorySearchInput, category); + await this.toContainText(selector.vendor.product.category.searchedResultText, category); + await this.click(selector.vendor.product.category.productCategorySearchResult); + await this.click(selector.vendor.product.category.productCategoryDone); + + const categoryAlreadySelectedPopup = await this.isVisible(selector.vendor.product.category.productCategoryAlreadySelectedPopup); + if (categoryAlreadySelectedPopup) { + await this.click(selector.vendor.product.category.productCategoryAlreadySelectedPopup); + await this.click(selector.vendor.product.category.productCategoryModalClose); + } + // todo: add multiple category selection + } + + // vendor add product category on product edit + async vendorAddProductCategory(productName: string, category: string): Promise { + await this.goToProductEdit(productName); + await this.addProductCategory(category); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, 'Success! The product has been saved successfully.'); + } + + // export product + async exportProducts(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + await this.clickAndWaitForLoadState(selector.vendor.product.importExport.export); + await this.clickAndWaitForDownload(selector.vendor.vTools.export.csv.generateCsv); + } + + // search product vendor dashboard + async searchProduct(productName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + + await this.clearAndType(selector.vendor.product.search.searchInput, productName); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.products, selector.vendor.product.search.searchBtn); + await this.toBeVisible(selector.vendor.product.productLink(productName)); + } + + // filter products + async filterProducts(filterBy: string, value: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + + switch (filterBy) { + case 'by-date': + await this.selectByNumber(selector.vendor.product.filters.filterByDate, value); + break; + + case 'by-category': + await this.selectByLabel(selector.vendor.product.filters.filterByCategory, value); + break; + + case 'by-type': + await this.selectByValue(selector.vendor.product.filters.filterByType, value); + break; + + case 'by-other': + await this.selectByValue(selector.vendor.product.filters.filterByOther, value); + break; + + default: + break; + } + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.filters.filter); + await this.notToHaveCount(selector.vendor.product.numberOfRowsFound, 0); + } + + // view product + async viewProduct(productName: string): Promise { + await this.searchProduct(productName); + await this.hover(selector.vendor.product.productCell(productName)); + await this.clickAndWaitForLoadState(selector.vendor.product.view(productName)); + await expect(this.page).toHaveURL(data.subUrls.frontend.productDetails(helpers.slugify(productName)) + '/'); + const { quantity, addToCart, viewCart, ...productDetails } = selector.customer.cSingleProduct.productDetails; + await this.multipleElementVisible(productDetails); + } + + // vendor can't buy own product + async cantBuyOwnProduct(productName: string) { + await this.goIfNotThere(data.subUrls.frontend.productDetails(helpers.slugify(productName))); + await this.notToBeVisible(selector.customer.cSingleProduct.productDetails.quantity); + await this.notToBeVisible(selector.customer.cSingleProduct.productDetails.addToCart); + } + + // edit product + async editProduct(product: product['simple']): Promise { + await this.goToProductEdit(product.editProduct); + + await this.clearAndType(selector.vendor.product.edit.title, product.editProduct); // don't update name below test needs same product + await this.clearAndType(selector.vendor.product.edit.price, product.regularPrice()); + // todo: add more fields + + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.dokanMessage, 'The product has been saved successfully. '); + } + + // product edit + + // add product quantity discount + async addProductQuantityDiscount(productName: string, quantityDiscount: vendor['vendorInfo']['quantityDiscount']): Promise { + await this.goToProductEdit(productName); + await this.check(selector.vendor.product.discount.enableBulkDiscount); // todo: need to fix + await this.clearAndType(selector.vendor.product.discount.lotMinimumQuantity, quantityDiscount.minimumQuantity); + await this.clearAndType(selector.vendor.product.discount.lotDiscountInPercentage, quantityDiscount.discountPercentage); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + } + + // vendor add product rma settings + async addProductRmaSettings(productName: string, rma: vendor['rma']): Promise { + await this.goToProductEdit(productName); + await this.check(selector.vendor.product.rma.overrideYourDefaultRmaSettingsForThisProduct); + await this.clearAndType(selector.vendor.product.rma.label, rma.label); + await this.selectByValue(selector.vendor.product.rma.type, rma.type); + await this.selectByValue(selector.vendor.product.rma.length, rma.rmaLength); + // todo: add rma as addon + if (rma.rmaLength === 'limited') { + await this.clearAndType(selector.vendor.product.rma.lengthValue, rma.lengthValue); + await this.selectByValue(selector.vendor.product.rma.lengthDuration, rma.lengthDuration); + } + const refundReasonIsVisible = await this.isVisible(selector.vendor.product.rma.refundReasonsFirst); + if (refundReasonIsVisible) { + await this.checkMultiple(selector.vendor.product.rma.refundReasons); + } + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + } + + // quick edit product + async quickEditProduct(product: product['simple']): Promise { + await this.searchProduct(product.editProduct); + await this.hover(selector.vendor.product.productCell(product.editProduct)); + await this.click(selector.vendor.product.quickEdit(product.editProduct)); + + await this.clearAndType(selector.vendor.product.quickEditProduct.title, product.editProduct); + // todo: add more fields + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.product.quickEditProduct.update); + } + + // duplicate product + async duplicateProduct(productName: string): Promise { + await this.searchProduct(productName); + await this.hover(selector.vendor.product.productCell(productName)); + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.duplicate(productName)); + await this.toContainText(selector.vendor.product.dokanSuccessMessage, 'Product succesfully duplicated'); + } + + // permanently delete product + async permanentlyDeleteProduct(productName: string): Promise { + await this.searchProduct(productName); + await this.hover(selector.vendor.product.productCell(productName)); + await this.click(selector.vendor.product.permanentlyDelete(productName)); + await this.clickAndWaitForLoadState(selector.vendor.product.confirmAction); + await this.toContainText(selector.vendor.product.dokanSuccessMessage, 'Product successfully deleted'); + } + + // product bulk action + async productBulkAction(action: string, productName?: string): Promise { + productName ? await this.searchProduct(productName) : await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + + await this.click(selector.vendor.product.bulkActions.selectAll); + switch (action) { + case 'edit': + await this.selectByValue(selector.vendor.product.bulkActions.selectAction, 'edit'); + // todo: + break; + + case 'permanently-delete': + await this.selectByValue(selector.vendor.product.bulkActions.selectAction, 'permanently-delete'); + break; + + case 'publish': + await this.selectByValue(selector.vendor.product.bulkActions.selectAction, 'publish'); + break; + + default: + break; + } + + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.bulkActions.applyAction); + } +} diff --git a/tests/pw/pages/refundsPage.ts b/tests/pw/pages/refundsPage.ts new file mode 100644 index 0000000000..ee10cfcd97 --- /dev/null +++ b/tests/pw/pages/refundsPage.ts @@ -0,0 +1,142 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; + +export class RefundsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // refunds + + // refunds render properly + async adminRefundRequestsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.refunds); + + // refund request text is visible + await this.toBeVisible(selector.admin.dokan.refunds.refundRequestsText); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.refunds.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.refunds.bulkActions); + + // refund request search is visible + await this.toBeVisible(selector.admin.dokan.refunds.search); + + // refund table elements are visible + await this.multipleElementVisible(selector.admin.dokan.refunds.table); + } + + // search refund request + async searchRefundRequests(orderOrStore: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.refunds); + + await this.clearInputField(selector.admin.dokan.refunds.search); + + await this.typeAndWaitForResponse(data.subUrls.api.dokan.refunds, selector.admin.dokan.refunds.search, String(orderOrStore)); + const count = (await this.getElementText(selector.admin.dokan.refunds.numberOfRowsFound))?.split(' ')[0]; + if (!isNaN(Number(orderOrStore))) { + await this.toBeVisible(selector.admin.dokan.refunds.refundCell(orderOrStore)); + expect(Number(count)).toBe(1); + } else { + expect(Number(count)).toBeGreaterThan(0); + } + } + + // update refund request + async updateRefundRequests(orderNumber: string, action: string) { + await this.searchRefundRequests(orderNumber); + + await this.hover(selector.admin.dokan.refunds.refundCell(orderNumber)); + switch (action) { + case 'approve': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.refunds, selector.admin.dokan.refunds.approveRefund(orderNumber)); + break; + + case 'cancel': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.refunds, selector.admin.dokan.refunds.cancelRefund(orderNumber)); + break; + + default: + break; + } + } + + // refund request bulk action + async refundRequestsBulkAction(action: string) { + await this.goto(data.subUrls.backend.dokan.refunds); + // await this.goIfNotThere(data.subUrls.backend.dokan.refunds); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.refunds.noRowsFound); + + await this.click(selector.admin.dokan.refunds.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.refunds.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.refunds, selector.admin.dokan.refunds.bulkActions.applyAction); + } + + // vendor + + // search order + async searchOrder(orderNumber: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.orders); + + await this.clearAndType(selector.vendor.orders.search.searchInput, orderNumber); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.orders, selector.vendor.orders.search.searchBtn); + await this.toBeVisible(selector.vendor.orders.orderLink(orderNumber)); + } + + // go to order details + async goToOrderDetails(orderNumber: string): Promise { + await this.searchOrder(orderNumber); + await this.clickAndWaitForLoadState(selector.vendor.orders.view(orderNumber)); + await this.toContainText(selector.vendor.orders.orderDetails.orderNumber, orderNumber); + } + + // vendor refund order + async refundOrder(orderNumber: string, productName: string, partialRefund = false): Promise { + await this.goToOrderDetails(orderNumber); + + // request refund + await this.click(selector.vendor.orders.refund.requestRefund); + const productQuantity = ((await this.getElementText(selector.vendor.orders.refund.productQuantity(productName))) as string).trim(); + const productCost = helpers.price((await this.getElementText(selector.vendor.orders.refund.productCost(productName))) as string); + const productTax = helpers.price((await this.getElementText(selector.vendor.orders.refund.productTax(productName))) as string); + + let shippingCost = 0; + let shippingTax = 0; + const isShipping = await this.isVisible(selector.vendor.orders.refund.shippingCost); + if (isShipping) { + shippingCost = helpers.price((await this.getElementText(selector.vendor.orders.refund.shippingCost)) as string); + shippingTax = helpers.price((await this.getElementText(selector.vendor.orders.refund.shippingTax)) as string); + } + await this.clearAndType(selector.vendor.orders.refund.refundProductQuantity(productName), productQuantity); + await this.click(selector.vendor.orders.refund.refundDiv); + if (partialRefund) { + await this.clearAndType(selector.vendor.orders.refund.refundProductCostAmount(productName), helpers.priceString(helpers.roundToTwo(productCost / 2), 'ES')); // todo: price style is fixed, make it dynamic + await this.clearAndType(selector.vendor.orders.refund.refundProductTaxAmount(productName), helpers.priceString(helpers.roundToTwo(productTax / 2), 'ES')); + if (isShipping) { + await this.clearAndType(selector.vendor.orders.refund.refundShippingAmount, helpers.priceString(helpers.roundToTwo(shippingCost / 2), 'ES')); + await this.clearAndType(selector.vendor.orders.refund.refundShippingTaxAmount, helpers.priceString(helpers.roundToTwo(shippingTax / 2), 'ES')); + } + } else { + await this.clearAndType(selector.vendor.orders.refund.refundProductCostAmount(productName), helpers.priceString(productCost, 'ES')); + await this.clearAndType(selector.vendor.orders.refund.refundProductTaxAmount(productName), helpers.priceString(productTax, 'ES')); + if (isShipping) { + await this.clearAndType(selector.vendor.orders.refund.refundShippingAmount, helpers.priceString(shippingCost, 'ES')); + await this.clearAndType(selector.vendor.orders.refund.refundShippingTaxAmount, helpers.priceString(shippingTax, 'ES')); + } + } + + await this.clearAndType(selector.vendor.orders.refund.refundReason, 'Defective product'); + await this.click(selector.vendor.orders.refund.refundManually); + await this.click(selector.vendor.orders.refund.confirmRefund); + + await this.toContainText(selector.vendor.orders.refund.refundRequestSuccessMessage, 'Refund request submitted.'); + await this.click(selector.vendor.orders.refund.refundRequestSuccessMessageOk); + } +} diff --git a/tests/pw/pages/reportsPage.ts b/tests/pw/pages/reportsPage.ts new file mode 100644 index 0000000000..f3ac432a3b --- /dev/null +++ b/tests/pw/pages/reportsPage.ts @@ -0,0 +1,104 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class ReportsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // reports + + // reports render properly + async adminReportsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.reports); + + // report Menus are visible + await this.multipleElementVisible(selector.admin.dokan.reports.menus); + + // filter Menus are visible + await this.multipleElementVisible(selector.admin.dokan.reports.reports.filterMenus); + + // calendar input is visible + await this.multipleElementVisible(selector.admin.dokan.reports.reports.calendar); + + // show button is visible + await this.toBeVisible(selector.admin.dokan.reports.reports.show); + + // at a glance elements are visible + await this.multipleElementVisible(selector.admin.dokan.reports.reports.atAGlance); + + // overview elements are visible + await this.multipleElementVisible(selector.admin.dokan.reports.reports.overview); + } + + // all logs + + // all logs render properly + async adminAllLogsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.allLogs); + + // report Menus are visible + await this.multipleElementVisible(selector.admin.dokan.reports.menus); + + // filter elements are visible + const { filterByStoreInput, filterByStatusInput, searchedResult, ...filters } = selector.admin.dokan.reports.allLogs.filters; + await this.multipleElementVisible(filters); + + // search is visible + await this.toBeVisible(selector.admin.dokan.reports.allLogs.search); + + // export log is visible + await this.toBeVisible(selector.admin.dokan.reports.allLogs.exportLogs); + + // all logs table elements are visible + await this.multipleElementVisible(selector.admin.dokan.reports.allLogs.table); + } + + // search all logs + async searchAllLogs(orderId: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.allLogs); + + await this.clearInputField(selector.admin.dokan.reports.allLogs.search); + await this.typeViaPageAndWaitForResponse(data.subUrls.api.dokan.logs, selector.admin.dokan.reports.allLogs.search, orderId); + await this.toBeVisible(selector.admin.dokan.reports.allLogs.orderIdCell(orderId)); + const count = (await this.getElementText(selector.admin.dokan.reports.allLogs.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBe(1); + // await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.logs, selector.admin.dokan.reports.allLogs.filters.clear); + } + + // export all logs + async exportAllLogs(orderId?: string) { + orderId && (await this.searchAllLogs(orderId)); + await this.clickAndWaitForDownload(selector.admin.dokan.reports.allLogs.exportLogs); + } + + // filter all logs by store + async filterAllLogsByStore(storeName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.allLogs); + + await this.click(selector.admin.dokan.reports.allLogs.filters.filterByStore); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.reports.allLogs.filters.filterByStoreInput, storeName); + await this.press(data.key.arrowDown); + // await this.toContainText(selector.admin.dokan.reports.allLogs.filters.searchedResult, (storeName)); + await this.pressAndWaitForResponse(data.subUrls.api.dokan.logs, data.key.enter); + + const count = (await this.getElementText(selector.admin.dokan.reports.allLogs.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + // await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.logs, selector.admin.dokan.reports.allLogs.filters.clear); + } + + // filter all logs by status + async filterAllLogsByStatus(orderStatus: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.allLogs); + + await this.click(selector.admin.dokan.reports.allLogs.filters.filterByStatus); // todo: add multiselect option + await this.type(selector.admin.dokan.reports.allLogs.filters.filterByStatusInput, orderStatus); + // await this.toContainText(selector.admin.dokan.reports.allLogs.filters.searchedResult, (orderStatus)); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.logs, selector.admin.dokan.reports.allLogs.filters.searchedResult); + const count = (await this.getElementText(selector.admin.dokan.reports.allLogs.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + // await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.logs, selector.admin.dokan.reports.allLogs.filters.clear); + } +} diff --git a/tests/pw/pages/requestForQuotationsPage.ts b/tests/pw/pages/requestForQuotationsPage.ts new file mode 100644 index 0000000000..2b66eb303a --- /dev/null +++ b/tests/pw/pages/requestForQuotationsPage.ts @@ -0,0 +1,460 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { CustomerPage } from '@pages/customerPage'; +import { MyOrdersPage } from '@pages/myOrdersPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { requestForQuotation } from '@utils/interfaces'; + +export class RequestForQuotationsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + customerPage = new CustomerPage(this.page); + customerMyOrders = new MyOrdersPage(this.page); + + // request for quote + + // quote rules + + // quote rules render properly + async adminQuoteRulesRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuoteRules); + + // request for quote menus are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.menus); + + // quote rules text is visible + await this.toBeVisible(selector.admin.dokan.requestForQuotation.quoteRules.quoteRulesText); + + // new quote rules is visible + await this.toBeVisible(selector.admin.dokan.requestForQuotation.quoteRules.newQuoteRule); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.quoteRules.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.quoteRules.bulkActions); + + // quote rules table elements are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.quoteRules.table); + } + + // update quote rule files + async updateQuoteRuleFields(rule: requestForQuotation['quoteRule']) { + await this.clearAndType(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.ruleTitle, rule.title); + await this.check(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.applyQuoteFor(rule.userRole)); + + // products + await this.click(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.applyOnAllProducts); + // await this.click(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.selectProductsDropDown); + // await this.typeAndWaitForResponse(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.selectProductsInput, rule.product); + // await this.press(data.key.enter); + + // category + // await this.check(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.selectCategories(rule.category)); + + await this.selectByValue(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.hidePrice, rule.hidePrice); + await this.clearAndType(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.hidePriceText, rule.hidePriceText); + await this.selectByValue(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.hideAddToCartButton, rule.hideAddToCartButton); + await this.clearAndType(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.customButtonLabel, rule.customButtonLabel); + + // priority + await this.clearAndType(selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.priorityOrder, rule.order); + + // publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.addNewQuoteRule.publishRule); + } + + // add quote rule + async addQuoteRule(rule: requestForQuotation['quoteRule']) { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuoteRules); + + await Promise.all([ + this.page.waitForResponse(resp => resp.url().includes(data.subUrls.api.dokan.quotes) && resp.status() === 200), + this.page.waitForResponse(resp => resp.url().includes(data.subUrls.api.dokan.products) && resp.status() === 200), + this.page.locator(selector.admin.dokan.requestForQuotation.quoteRules.newQuoteRule).click(), + ]); + + await this.updateQuoteRuleFields(rule); + } + + // edit quote rule + async editQuoteRule(rule: requestForQuotation['quoteRule']) { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuoteRules); + // await this.goto(data.subUrls.backend.dokan.requestForQuoteRules); + + await this.hover(selector.admin.dokan.requestForQuotation.quoteRules.quoteRulesCell(rule.title)); + + await Promise.all([ + this.page.waitForResponse(resp => resp.url().includes(data.subUrls.api.dokan.quotes) && resp.status() === 200), + this.page.waitForResponse(resp => resp.url().includes(data.subUrls.api.dokan.products) && resp.status() === 200), + this.page.locator(selector.admin.dokan.requestForQuotation.quoteRules.quoteRulesEdit(rule.title)).click(), + ]); + + await this.updateQuoteRuleFields(rule); + } + + // update quote rule + async updateQuoteRule(quoteTitle: string, action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuoteRules); + // await this.goto(data.subUrls.backend.dokan.requestForQuoteRules); + + switch (action) { + case 'trash': + await this.hover(selector.admin.dokan.requestForQuotation.quoteRules.quoteRulesCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.quoteRulesTrash(quoteTitle)); + break; + + case 'permanently-delete': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.navTabs.trash); + await this.hover(selector.admin.dokan.requestForQuotation.quoteRules.trashedQuoteRulesCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.quoteRulesPermanentlyDelete(quoteTitle)); + break; + + case 'restore': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.navTabs.trash); + await this.hover(selector.admin.dokan.requestForQuotation.quoteRules.trashedQuoteRulesCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.quoteRulesRestore(quoteTitle)); + break; + + default: + break; + } + } + + // quote rules bulk action + async quoteRulesBulkAction(action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuoteRules); + // await this.goto(data.subUrls.backend.dokan.requestForQuoteRules); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.requestForQuotation.quoteRules.noRowsFound); + + await this.check(selector.admin.dokan.requestForQuotation.quoteRules.bulkActions.selectAll); + + // only to remove flakiness // todo: need diff soln and make generic , don't work need custom soln + // const isDisabled = await this.hasAttribute(selector.admin.dokan.requestForQuotation.quoteRules.bulkActions.applyAction, 'disabled'); + // if(isDisabled){ + // await this.uncheck(selector.admin.dokan.requestForQuotation.quoteRules.bulkActions.selectAll); + // await this.check(selector.admin.dokan.requestForQuotation.quoteRules.bulkActions.selectAll); + // } + + await this.selectByValue(selector.admin.dokan.requestForQuotation.quoteRules.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quoteRules, selector.admin.dokan.requestForQuotation.quoteRules.bulkActions.applyAction); + } + + // quotes + + // quotes render properly + async adminQuotesRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuote); + + // request for quote menus are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.menus); + + // quotes text is visible + await this.toBeVisible(selector.admin.dokan.requestForQuotation.quotesList.quotesText); + + // new quote is visible + await this.toBeVisible(selector.admin.dokan.requestForQuotation.quotesList.newQuote); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.quotesList.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.quotesList.bulkActions); + + // quotes table elements are visible + await this.multipleElementVisible(selector.admin.dokan.requestForQuotation.quotesList.table); + } + + // update quote fields + async updateQuoteFields(quote: requestForQuotation['quote'], action = 'create') { + await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.quoteTitle, quote.title); + + // customer information + await this.click(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.quoteUserDropDown); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.quoteUserInput, quote.user); + await this.press(data.key.enter); + // await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.fullName, quote.fullName); + // await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.email, quote.email); + await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.companyName, quote.companyName); + await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.phoneNumber, quote.phoneNumber); + + // quote product + if (action === 'create') { + await this.click(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.addProducts); + + await this.click(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.quoteProductDropDown); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.products, selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.quoteProductInput, quote.product); + await this.press(data.key.enter); + + await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.quoteProductQuantity, quote.quantity); + await this.click(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.addToQuote); + } + + await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.offerPrice, quote.offerPrice); + await this.clearAndType(selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.offerProductQuantity, quote.offerProductQuantity); + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.addNewQuote.publishQuote); + } + + // add quote + async addQuote(quote: requestForQuotation['quote']) { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuote); + await this.click(selector.admin.dokan.requestForQuotation.quotesList.newQuote); + await this.updateQuoteFields(quote, 'create'); + } + + // edit quote + async editQuote(quote: requestForQuotation['quote']) { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuote); + + await this.hover(selector.admin.dokan.requestForQuotation.quotesList.quoteCell(quote.title)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.quoteEdit(quote.title)); + await this.updateQuoteFields(quote, 'update'); + } + + // update quote + async updateQuote(quoteTitle: string, action: string) { + await this.goto(data.subUrls.backend.dokan.requestForQuote); + // await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuote); + + switch (action) { + case 'trash': + await this.hover(selector.admin.dokan.requestForQuotation.quotesList.quoteCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.quoteTrash(quoteTitle)); + break; + + case 'permanently-delete': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.navTabs.trash); + await this.hover(selector.admin.dokan.requestForQuotation.quotesList.quoteCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.quotePermanentlyDelete(quoteTitle)); + break; + + case 'restore': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.navTabs.trash); + await this.hover(selector.admin.dokan.requestForQuotation.quotesList.quoteCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.quoteRestore(quoteTitle)); + break; + + default: + break; + } + } + + // approve quote + async approveQuote(quoteTitle: string) { + await this.goto(data.subUrls.backend.dokan.requestForQuote); + // await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuote); + await this.hover(selector.admin.dokan.requestForQuotation.quotesList.quoteCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.quoteEdit(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.approveQuote); + } + + // convert quote to order + async convertQuoteToOrder(quoteTitle: string) { + // await this.approveQuote(quoteTitle); + await this.goto(data.subUrls.backend.dokan.requestForQuote); + // await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuote); + await this.hover(selector.admin.dokan.requestForQuotation.quotesList.quoteCell(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.quoteEdit(quoteTitle)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.convertToOrder); + } + + // quotes bulk action + async quotesBulkAction(action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.requestForQuote); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.requestForQuotation.quotesList.noRowsFound); + + await this.click(selector.admin.dokan.requestForQuotation.quotesList.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.requestForQuotation.quotesList.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.quotes, selector.admin.dokan.requestForQuotation.quotesList.bulkActions.applyAction); + } + + // vendor + + // vendor request quotes render properly + async vendorRequestQuotesRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.requestQuotes); + + // request quotes text is visible + await this.toBeVisible(selector.vendor.vRequestQuotes.requestQuotesText); + + const noQuoteRequests = await this.isVisible(selector.vendor.vRequestQuotes.noQuoteMessage); + + if (noQuoteRequests) { + // go to shop is visible + await this.toBeVisible(selector.vendor.vRequestQuotes.goToShop); + } else { + // request quote table elements are visible + await this.multipleElementVisible(selector.vendor.vRequestQuotes.table); + } + } + + // vendor view request quote details + async vendorViewQuoteDetails(quoteTitle: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.requestQuotes); + await this.clickAndWaitForLoadState(selector.vendor.vRequestQuotes.viewQuoteDetails(quoteTitle)); + + // quote basic details elements are visible + await this.multipleElementVisible(selector.vendor.vRequestQuotes.quoteDetails.basicDetails); + + // quote item details elements are visible + await this.toBeVisible(selector.vendor.vRequestQuotes.quoteDetails.quoteItemDetails.quoteDetailsText); + await this.multipleElementVisible(selector.vendor.vRequestQuotes.quoteDetails.quoteItemDetails.table); + + // quote total details elements are visible + await this.multipleElementVisible(selector.vendor.vRequestQuotes.quoteDetails.quoteTotals); + + // update quote is visible + await this.toBeVisible(selector.vendor.vRequestQuotes.quoteDetails.updateQuote); + await this.toBeVisibleAnyOfThem([selector.vendor.vRequestQuotes.quoteDetails.approveThisQuote, selector.vendor.vRequestQuotes.quoteDetails.convertToOrder]); + } + + // update quote + async vendorUpdateQuoteRequest(quoteId: string, quote: requestForQuotation['userQuote']) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.quoteDetails(quoteId)); + await this.clearAndType(selector.vendor.vRequestQuotes.quoteDetails.offeredPriceInput(quote.productName), quote.offeredPrice); + await this.clearAndType(selector.vendor.vRequestQuotes.quoteDetails.quantityInput(quote.productName), quote.quantity); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.quoteDetails(quoteId), selector.vendor.vRequestQuotes.quoteDetails.updateQuote); + await this.toContainText(selector.vendor.vRequestQuotes.quoteDetails.message, 'Your quote has been successfully updated.'); + } + + // approve quote + async vendorApproveQuoteRequest(quoteId: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.quoteDetails(quoteId)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.quoteDetails(quoteId), selector.vendor.vRequestQuotes.quoteDetails.approveThisQuote); + await this.toContainText(selector.vendor.vRequestQuotes.quoteDetails.message, 'Your quote has been successfully updated.'); + } + + // convert quote to order + async vendorConvertQuoteToOrder(quoteId: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.quoteDetails(quoteId)); + const needApproval = await this.isVisible(selector.vendor.vRequestQuotes.quoteDetails.approveThisQuote); + needApproval && (await this.vendorApproveQuoteRequest(quoteId)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.quoteDetails(quoteId), selector.vendor.vRequestQuotes.quoteDetails.convertToOrder); + await this.toContainText(selector.vendor.vRequestQuotes.quoteDetails.message, `Your Quote# ${quoteId} has been converted to Order#`); + } + + // customer + + // customer request for quote render properly + async requestForQuoteRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.requestForQuote); + + await this.toBeVisible(selector.customer.cRequestForQuote.requestForQuote.requestForQuoteText); + + const noQuote = await this.isVisible(selector.customer.cRequestForQuote.requestForQuote.noQuotesFound); + + if (noQuote) { + await this.toContainText(selector.customer.cRequestForQuote.requestForQuote.noQuotesFound, 'Your quote is currently empty.'); + console.log('No quotes found on request for quote page'); + await this.toBeVisible(selector.customer.cRequestForQuote.requestForQuote.returnToShop); + } else { + // quote item table details elements are visible + await this.multipleElementVisible(selector.customer.cRequestForQuote.requestForQuote.quoteItemDetails.table); + + // quote total details elements are visible + await this.multipleElementVisible(selector.customer.cRequestForQuote.requestForQuote.quoteTotals); + + // update quote is visible + await this.toBeVisible(selector.customer.cRequestForQuote.requestForQuote.updateQuote); + } + } + + // requested quotes render properly + async requestedQuotesRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.requestedQuote); + + // request quotes text is visible + await this.toBeVisible(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteText); + + const noQuoteRequests = await this.isVisible(selector.customer.cRequestForQuote.requestedQuote.noQuoteMessage); + + if (noQuoteRequests) { + // go to shop is visible + await this.toBeVisible(selector.customer.cRequestForQuote.requestedQuote.goToShop); + } else { + // request quote table elements are visible + await this.multipleElementVisible(selector.customer.cRequestForQuote.requestedQuote.table); + + // pagination is visible + // await this.toBeVisible(selector.customer.cRequestForQuote.requestedQuote.pagination); + } + } + + // customer view requested quote details + async customerViewRequestedQuoteDetails(quoteTitle: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.requestedQuote); + + await this.clickAndWaitForLoadState(selector.customer.cRequestForQuote.requestedQuote.viewQuoteDetails(quoteTitle)); + + // quote basic details elements are visible + await this.multipleElementVisible(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.basicDetails); + + // quote item details elements are visible + await this.toBeVisible(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.quoteItemDetails.quoteDetailsText); + await this.multipleElementVisible(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.quoteItemDetails.table); + + // quote total details elements are visible + await this.multipleElementVisible(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.quoteTotals); + + // update quote is visible + await this.toBeVisible(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.updateQuote); + } + + // customer update requested quote + async customerUpdateRequestedQuote(quoteId: string, quote: requestForQuotation['userQuote']) { + await this.goIfNotThere(data.subUrls.frontend.quoteDetails(quoteId)); + await this.clearAndType(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.offeredPriceInput(quote.productName), quote.offeredPrice); + await this.clearAndType(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.quantityInput(quote.productName), quote.quantity); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.quoteDetails(quoteId), selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.updateQuote); + await this.toContainText(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.message, 'Your quote has been successfully updated.'); + } + + // customer pay converted quote + async payConvertedQuote(quoteId: string) { + await this.goto(data.subUrls.frontend.quoteDetails(quoteId)); + await this.clickAndWaitForLoadState(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.viewOrder); + await this.toBeVisible(selector.customer.cRequestForQuote.orderDetails.quoteNoteOnOrderDetails); + const orderId = (await this.getElementText(selector.customer.cOrderDetails.orderDetails.orderNumber)) as string; + await this.customerMyOrders.payPendingOrder(orderId, 'bank'); + } + + // customer quote product + async customerQuoteProduct(quote: requestForQuotation['userQuote'], guest?: requestForQuotation['guest']): Promise { + await this.customerPage.goToProductDetails(quote.productName); + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cRequestForQuote.singleProductDetails.addToQuote); + const viewQuoteIsVisible = await this.isVisible(selector.customer.cRequestForQuote.singleProductDetails.viewQuote); + if (viewQuoteIsVisible) { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.requestForQuote, selector.customer.cRequestForQuote.singleProductDetails.viewQuote); + } else { + await this.goIfNotThere(data.subUrls.frontend.requestForQuote); + } + await this.clearAndType(selector.customer.cRequestForQuote.requestForQuote.offeredPriceInput(quote.productName), quote.offeredPrice); + await this.clearAndType(selector.customer.cRequestForQuote.requestForQuote.quantityInput(quote.productName), quote.quantity); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.customer.cRequestForQuote.requestForQuote.updateQuote); + await this.toContainText(selector.customer.cRequestForQuote.requestForQuote.message, 'Quote updated'); + + if (guest) { + await this.clearAndType(selector.customer.cRequestForQuote.requestForQuote.guest.fullName, guest.fullName); + await this.clearAndType(selector.customer.cRequestForQuote.requestForQuote.guest.email, guest.email); + await this.clearAndType(selector.customer.cRequestForQuote.requestForQuote.guest.companyName, guest.companyName); + await this.clearAndType(selector.customer.cRequestForQuote.requestForQuote.guest.phoneNumber, guest.phoneNumber); + } + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.requestForQuote, selector.customer.cRequestForQuote.requestForQuote.placeQuote, 302); + await this.toBeVisible(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.requestedQuoteText); + + if (!guest) { + const quoteId = (await this.getElementText(selector.customer.cRequestForQuote.requestedQuote.requestedQuoteDetails.basicDetails.quoteNumberValue))?.trim() as string; + return quoteId; + } + } +} diff --git a/tests/pw/pages/reverseWithdrawsPage.ts b/tests/pw/pages/reverseWithdrawsPage.ts new file mode 100644 index 0000000000..b7aaf1b598 --- /dev/null +++ b/tests/pw/pages/reverseWithdrawsPage.ts @@ -0,0 +1,152 @@ +import { Page } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { reverseWithdraw, date } from '@utils/interfaces'; + +export class ReverseWithdrawsPage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // reverse withdraw + + // regenerate reverse withdrawal payment product + async reCreateReverseWithdrawalPaymentViaSettingsSave() { + await this.goIfNotThere(data.subUrls.backend.dokan.settings); + + await this.click(selector.admin.dokan.settings.menus.reverseWithdrawal); + await this.clickAndWaitForLoadState(selector.admin.dokan.settings.reverseWithdraw.reverseWithdrawSaveChanges); + } + + // reverse withdraw render properly + async adminReverseWithdrawRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.reverseWithdraws); + + // reverse withdraw text is visible + await this.toBeVisible(selector.admin.dokan.reverseWithdraw.reverseWithdrawText); + + // add new reverse withdrawal is visible + await this.toBeVisible(selector.admin.dokan.reverseWithdraw.addNewReverseWithdrawal); + + // fact cards elements are visible + await this.multipleElementVisible(selector.admin.dokan.reverseWithdraw.reverseWithdrawFactCards); + + // filter elements are visible + const { filterInput, clearFilter, filteredResult, ...filters } = selector.admin.dokan.reverseWithdraw.filters; + await this.multipleElementVisible(filters); + + // reverse withdraw table elements are visible + await this.multipleElementVisible(selector.admin.dokan.reverseWithdraw.table); + } + + // filter reverse withdraws + async filterReverseWithdraws(vendorName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.reverseWithdraws); + + await this.clickIfVisible(selector.admin.dokan.reverseWithdraw.filters.clearFilter); + + await this.click(selector.admin.dokan.reverseWithdraw.filters.filterByStore); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.reverseWithdraws, selector.admin.dokan.reverseWithdraw.filters.filterInput, vendorName); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.reverseWithdraws, selector.admin.dokan.reverseWithdraw.filters.filteredResult(vendorName)); + await this.toBeVisible(selector.admin.dokan.reverseWithdraw.reverseWithdrawCell(vendorName)); + } + + // add new reverse withdrawal + async addReverseWithdrawal(reverseWithdrawal: reverseWithdraw) { + await this.goIfNotThere(data.subUrls.backend.dokan.reverseWithdraws); + + await this.click(selector.admin.dokan.reverseWithdraw.addNewReverseWithdrawal); + + await this.click(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.selectVendorDropdown); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.selectVendorInput, reverseWithdrawal.store); + await this.click(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.selectOption(reverseWithdrawal.store)); + + // await this.toContainText(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.searchedResult, reverseWithdrawal.store); + // await this.press(data.key.arrowDown); + // await this.press(data.key.enter); + + await this.click(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.transactionType(reverseWithdrawal.transactionType)); + + await this.click(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.selectProductDropdown); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.products, selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.selectProductInput, reverseWithdrawal.product); + await this.click(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.selectOption(reverseWithdrawal.product)); + // await this.toContainText(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.searchedResult, reverseWithdrawal.product); + // await this.press(data.key.enter); + + await this.click(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.withdrawalBalanceType(reverseWithdrawal.withdrawalBalanceType)); + + await this.clearAndType(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.reverseWithdrawalAmount, reverseWithdrawal.amount); + await this.clearAndType(selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.note, reverseWithdrawal.note); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.reverseWithdraws, selector.admin.dokan.reverseWithdraw.addReverseWithdrawal.save); + } + + // vendor + + // reverse withdrawal render properly + async vendorReverseWithdrawalRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reverseWithdrawal); + + // reverse withdrawal text is visible + await this.toBeVisible(selector.vendor.vReverseWithdrawal.reverseWithdrawalText); + + // reverse balance section elements are visible + await this.multipleElementVisible(selector.vendor.vReverseWithdrawal.reverseBalanceSection); + + // filter elements are visible + await this.toBeVisible(selector.vendor.vReverseWithdrawal.filters.dateRangeInput); + await this.toBeVisible(selector.vendor.vReverseWithdrawal.filters.filter); + + // reverse withdrawal table elements are visible + await this.multipleElementVisible(selector.vendor.vReverseWithdrawal.table); + + // opening balance row is visible + await this.toBeVisible(selector.vendor.vReverseWithdrawal.openingBalanceRow); + } + + // reverse withdraw notice render properly + async vendorViewReverseWithdrawalNotice() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reverseWithdrawal); + + await this.toBeVisible(selector.vendor.vReverseWithdrawal.reverseWithdrawalNotice.noticeText); + // const noticeText = await this.getElementText(selector.vendor.vReverseWithdrawal.reverseWithdrawalNotice.noticeText); + + // expect(noticeText).toContain('Your products add to cart will be hidden. Hence users will not be able to purchase any of your products.'); + // expect(noticeText).toContain('Withdraw menu will be hidden. Hence you will not be able to make any withdraw request from your account.'); + // expect(noticeText).toContain('Your account will be disabled for selling. Hence you will no longer be able to sell any products.'); + + // expect(noticeText).toContain('Your products add to cart button has been temporarily hidden. Hence users are not able to purchase any of your products'); + // expect(noticeText).toContain('Withdraw menu has been temporarily hidden. Hence you are not able to make any withdrawal requests from your account.'); + // expect(noticeText).toContain('Kindly pay your due to start selling again.'); + } + + // view reverse withdraw announcement + async vendorViewReverseWithdrawalAnnouncement() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.announcements); + await this.clickAndWaitForLoadState(selector.vendor.vAnnouncement.firstAnnouncementLink('You have a reverse withdrawal balance of')); + await this.toContainText(selector.vendor.vAnnouncement.announcement.title, 'You have a reverse withdrawal balance of'); + } + + // filter reverse withdraws + async vendorFilterReverseWithdrawals(inputValue: date['dateRange']) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reverseWithdrawal); + + await this.setAttributeValue(selector.vendor.vReverseWithdrawal.filters.dateRangeInput, 'value', helpers.dateFormatFYJ(inputValue.startDate) + ' - ' + helpers.dateFormatFYJ(inputValue.endDate)); + await this.setAttributeValue(selector.vendor.vReverseWithdrawal.filters.startDateInput, 'value', inputValue.startDate); + await this.setAttributeValue(selector.vendor.vReverseWithdrawal.filters.endDateInput, 'value', inputValue.endDate); + await this.clickAndWaitForLoadState(selector.vendor.vReverseWithdrawal.filters.filter); + await this.notToHaveCount(selector.vendor.vReverseWithdrawal.numberOfRowsFound, 3); + } + + // pay reverse pay balance + async vendorPayReversePayBalance() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reverseWithdrawal); + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReverseWithdrawal.payNow); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.checkout, selector.vendor.vReverseWithdrawal.confirmAction); + const orderId = await this.paymentOrder(); + return orderId; + } +} diff --git a/tests/pw/pages/selectors.ts b/tests/pw/pages/selectors.ts new file mode 100644 index 0000000000..751eefd7c1 --- /dev/null +++ b/tests/pw/pages/selectors.ts @@ -0,0 +1,7220 @@ +import { helpers } from '@utils/helpers'; + +export const selector = { + // Login + + // Selectors + frontend: { + // Fronted Menus + home: '//a[contains(text(),"Home")]', + cart: '//a[contains(text(),"Cart")]', + checkout: '//a[contains(text(),"Checkout")]', + dashboard: '//a[contains(text(),"Dashboard")]', + myAccount: '//a[contains(text(),"My account")]', + myOrders: '//a[contains(text(),"My Orders")]', + samplePage: '//a[contains(text(),"Sample Page")]', + shop: '//a[contains(text(),"Shop")]', + storeList: '//a[contains(text(),"Store List")]', + + // Go to Vendor Dashboard + goToVendorDashboard: '.dokan-btn.dokan-btn-theme.vendor-dashboard', + + // User Login + username: '#username', + userPassword: '#password', + rememberMe: '#rememberme', + logIn: '//button[@value="Log in"]', + lostPassword: '.woocommerce-LostPassword > a', + + // User Logout + customerLogout: '.woocommerce-MyAccount-navigation-link--customer-logout > a', + vendorLogout: '.fa-power-off', + + // User Forget Password + resetPasswordEmail: '#user_login', + resetPasswordBtn: '.woocommerce-Button.button', + }, + + backend: { + // setup + alreadyInstalled: '//h1[contains(text(), "Already Installed")]', + languageContinue: '#language-continue', + letsGo: '//a[contains(text(), "go!")]', + // db setup + dbName: '#dbname', + dbUserName: '#uname', + dbPassword: '#pwd', + dbHost: '#dbhost', + dbTablePrefix: '#prefix', + submit: '.step input', + runTheInstallation: '.step a', + // site info + siteTitle: '#weblog_title', + adminUserName: '#user_login', + adminPassword: '#pass1', + adminEmail: '#admin_email', + searchEngineVisibility: '#blog_public', + installWp: '#submit', + successLoginIn: '.step a', + + // Admin Login + email: '#user_login', + password: '#user_pass', + rememberMe: '#rememberme', + login: '#wp-submit', + dashboardMenu: '.wp-first-item > .wp-menu-name', + dashboardText: '.wrap h1', + // Admin Logout + userMenu: '#wp-admin-bar-my-account', + logout: '#wp-admin-bar-logout a', + // Logout Message + logoutSuccessMessage: '#login p', + // Login Error + loginError: '#login_error', + }, + + wpMedia: { + // Wp Image Upload + wpUploadFiles: '#menu-item-upload', + uploadedMedia: 'div.attachment-preview', + uploadedMediaFirst: '(//div[contains(@class,"attachment-preview")])[1]', + selectFiles: '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[@class="browser button button-hero"]', + selectFilesInput: '//div[@class="supports-drag-drop" and @style="position: relative;"]//input[@type="file"]', + selectUploadedMedia: '(//h2[contains(text(),"Media list")]/..//ul//li)[1]', + select: '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[contains(@class, "media-button-select")]', + }, + + // Admin + + admin: { + // Admin Dashboard + aDashboard: { + // Dashboard Menus + dashboard: '.wp-first-item .wp-menu-name', + posts: '.menu-icon-post .wp-menu-name', + media: '.menu-icon-media .wp-menu-name', + pages: '.menu-icon-page .wp-menu-name', + comments: '.menu-icon-comments .wp-menu-name', + emailLog: '.toplevel_page_email-log .wp-menu-name', + dokanMenu: '#toplevel_page_dokan', + dokan: '#toplevel_page_dokan .wp-menu-name', + wooCommerce: '.toplevel_page_woocommerce .wp-menu-name', + products: '.menu-icon-product .wp-menu-name', + bookings: '.menu-icon-wc_booking .wp-menu-name', + analytics: '.toplevel_page_wc-admin\\&path\\=\\/analytics\\/overview .wp-menu-name', + marketing: '.toplevel_page_woocommerce-marketing .wp-menu-name', + elementor: '.toplevel_page_elementor .wp-menu-name', + templates: '.menu-icon-elementor_library .wp-menu-name', + appearance: '.menu-icon-appearance .wp-menu-name', + plugins: '.menu-icon-plugins .wp-menu-name', + users: '.menu-icon-users .wp-menu-name', + tools: '.menu-icon-tools .wp-menu-name', + settings: '.menu-icon-settings .wp-menu-name', + locoTranslate: '.toplevel_page_loco .wp-menu-name', + // Collapse Menu + collapseMenu: '#collapse-button', + }, + + // Dashboard + dashboard: { + // Menus + home: '//li[@id="menu-dashboard"]//a[contains(text(),"Home")]', + updates: '//li[@id="menu-dashboard"]//a[contains(text(),"Updates ")]', + }, + // Posts + posts: { + // Menus + allPosts: '//li[@id="menu-posts"]//a[contains(text(),"All Posts")]', + addNew: '//li[@id="menu-posts"]//a[contains(text(),"Add New")]', + categories: '//li[@id="menu-posts"]//a[contains(text(),"Categories")]', + tags: '//li[@id="menu-posts"]//a[contains(text(),"Tags")]', + }, + // Media + media: { + // Menus + library: '//li[@id="menu-media"]//a[contains(text(),"Library")]', + addNew: '//li[@id="menu-media"]//a[contains(text(),"Add New")]', + }, + // Pages + pages: { + // Menus + allPages: '//li[@id="menu-pages"]//a[contains(text(),"All Pages")]', + addNew: '//li[@id="menu-pages"]//a[contains(text(),"Add New")]', + }, + // Comments + comments: { + // Nav Tabs + all: '//li[@class="all"]', + mine: '//li[@class="mine"]', + pending: '//li[@class="moderated"]', + approved: '//li[@class="approved"]', + spam: '//li[@class="spam"]', + trash: '//li[@class="trash"]', + }, + // EmailLog + emailLog: { + // Menus + viewLogs: '//li[@id="toplevel_page_email-log"]//a[contains(text(),"View Logs")]', + settings: '//li[@id="toplevel_page_email-log"]//a[contains(text(),"Settings")]', + addOns: '//li[@id="toplevel_page_email-log"]//a[contains(text(),"Add-ons")]', + systemInfo: '//li[@id="toplevel_page_email-log"]//a[contains(text(),"System Info")]', + }, + // Dokan + dokan: { + // Dokan Menus + menus: { + dashboard: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Dashboard"]', + withdraw: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Withdraw"]', + vendors: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Vendors"]', + abuseReports: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Abuse Reports"]', + storeReviews: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Store Reviews"]', + storeSupport: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Store Support"]', + announcements: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Announcements"]', + refunds: '//li[contains(@class,"toplevel_page_dokan")]//a[contains(text(),"Refunds")]', + reports: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Reports"]', + modules: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Modules"]', + proFeature: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="PRO Features"]', + tools: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Tools"]', + verifications: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Verifications"]', + advertising: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Advertising"]', + wholesaleCustomer: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Wholesale Customer"]', + help: '//li[contains(@class,"toplevel_page_dokan")]//span[text()="Help"]/..', + settings: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="Settings"]', + license: '//li[contains(@class,"toplevel_page_dokan")]//a[text()="License"]', + }, + + // dokan promotion + promotion: { + promotion: '.dokan-notice-slides .dokan-promotion', + joinTheSale: '//a[contains(text(),"Join the Sale! →")]', + }, + + // dokan notice + notice: { + noticeDiv: '.dokan-admin-notices', + noticeDiv1: '.dokan-admin-notice.dokan-alert', + closeNotice: '.close-notice', + slider: '.slide-notice', + sliderPrev: '.slide-notice .prev', + sliderNext: '.slide-notice .next', + }, + + // promo banner + promoBanner: { + promoBanner: '.dokan-promo-banner', + bannerThumbnail: '.dokan-promo-banner .thumbnail', + promoContent: '.dokan-promo-banner .content', + upgradeToPremium: '.btn-upgrade', + closePromoBanner: '.close-banner', + }, + + // Dashboard + dashboard: { + // admin header + header: { + dokanLogo: '.dokan-admin-header-logo', + getHelpMenu: '.dokan-admin-header-menu .menu-icon', + }, + + getHelp: { + whatsNew: '//div[@class="list-item"]//a[normalize-space()="What’s New"]', + getSupport: '//div[@class="list-item"]//a[normalize-space()="Get Support"]', + community: '//div[@class="list-item"]//a[normalize-space()="Community"]', + documentation: '//div[@class="list-item"]//a[normalize-space()="Documentation"]', + faq: '//div[@class="list-item"]//a[normalize-space()="FAQ"]', + basicAndFundamental: '//div[@class="list-item"]//a[normalize-space()="Basic & Fundamental"]', + requestAFeature: '//div[@class="list-item"]//a[normalize-space()="Request a Feature"]', + runSetupWizard: '//div[@class="list-item"]//a[normalize-space()="Run Setup Wizard"]', + importDummyData: '//div[@class="list-item"]//a[normalize-space()="Import dummy data"]', + }, + + // Dashboard Text + dashboardText: '.dokan-dashboard h1', + + // At a Glance + atAGlance: { + atAGlance: '.postbox.dokan-postbox.dokan-status', + collapsibleButton: '.dokan-status .handle-actions button', + netSalesThisMonth: '.sale strong', + commissionEarned: '.commission strong div', + signupThisMonth: '.vendor strong', + vendorAwaitingApproval: '.approval strong', + productCreatedThisMonth: '.product strong', + withdrawAwaitingApproval: '.withdraw strong', + }, + + // Overview + overview: { + overview: '.postbox.dokan-postbox.overview-chart', + collapsibleButton: '.overview-chart .handle-actions button', + chart: '#line-chart', + }, + + // Dokan new Updates + dokanNewUpdates: { + dokanNewUpdates: '//div[@class="postbox dokan-postbox"]', + collapsibleButton: '//div[@class="postbox dokan-postbox"]//div[@class="postbox-header"]//button', + newUpdatesList: '.rss-widget ul', + }, + + // SubscribeBox + subscribeBox: { + subscribeBox: '.subscribe-box', + subscriberName: '//input[@placeholder="Your Name"]', + subscriberEmail: '//input[@placeholder="Your Email Address"]', + subscribeButton: '//button[normalize-space()="Subscribe"]', + thankYouMessage: '.thank-you', + }, + }, + + // Withdraw + withdraw: { + withdrawText: '.withdraw-requests h1', + + // Nav Tabs + navTabs: { + 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")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // approved, cancelled, delete, paypal + applyAction: '.tablenav.top .button.action', + }, + + // 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', + clearFilter: 'a#clear-all-filtering', + result: 'li.select2-results__option.select2-results__option--highlighted', + }, + + // Logs + exportWithdraws: 'a#export-all-logs', + + // Table + table: { + withdrawTable: '.wp-list-table', + vendorColumn: 'thead th.seller', + amountColumn: 'thead th.amount', + statusColumn: 'thead th.status', + methodColumn: 'thead th.method_title', + detailsColumn: 'thead th.method_details', + noteColumn: 'thead th.note', + dateColumn: 'thead th.created', + actionsColumn: 'thead th.actions', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + 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`, + withdrawCancel: (storeName: string) => `//td//a[contains(text(), '${storeName}')]/../..//span[@class="cancel"]//a`, + withdrawApprove: (storeName: string) => `//td//a[contains(text(), '${storeName}')]/../../..//button[@title='Approve Request']`, + withdrawAddNote: (storeName: string) => `//td//a[contains(text(), '${storeName}')]/../../..//button[@title='Add Note']`, + withdrawNoteModalClose: '.dokan-modal-content .modal-header button', + addNote: '.dokan-modal-content .modal-body textarea', + updateNote: '.dokan-modal-content .modal-footer button', + }, + + // Reverse Withdraw + reverseWithdraw: { + reverseWithdrawText: '.dokan-reverse-withdrawal h1', + + addNewReverseWithdrawal: '.dokan-reverse-withdrawal button.page-title-action', + + // Fact Cards + reverseWithdrawFactCards: { + totalCollectedCard: '//p[normalize-space()="Total Collected"]/../..', + totalCollected: '//p[normalize-space()="Total Collected"]/../..//h3', + remainingBalanceCard: '//p[normalize-space()="Remaining Balance"]/../..', + remainingBalance: '//p[normalize-space()="Remaining Balance"]/../..//h3', + TotalTransactionsCard: '//p[normalize-space()="Total Transactions"]/../..', + TotalTransactions: '//p[normalize-space()="Total Transactions"]/../..//h3', + TotalVendorsCard: '//p[normalize-space()="Total Vendors"]/../..', + TotalVendors: '//p[normalize-space()="Total Vendors"]/../..//h3', + }, + + // Filters + filters: { + filterByStore: '.multiselect__select', + filterInput: '.multiselect__input', + clearFilter: '//button[normalize-space()="Clear"]', + filteredResult: (storeName: string) => `//span[contains(text(), '${storeName}')]/..`, + }, + + // Table + table: { + revereWithdrawTable: '#dokan_reverse_withdrawal_list_table table', + storesColumn: 'thead th.store_name', + balanceColumn: 'thead th.balance', + lastPaymentDateColumn: 'thead th.last_payment_date', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No transaction found."]', + reverseWithdrawCell: (storeName: string) => `//td//a[contains(text(), '${storeName}')]/../..`, + + addReverseWithdrawal: { + closeModal: '.modal-close.modal-close-link', + selectVendorDropdown: '//span[normalize-space()="Search vendor"]/../..//div[@class="multiselect__select"]', + selectVendorInput: '//input[@placeholder="Search vendor"]', + transactionType: (type: string) => `//input[@value="${type}"]/..`, // manual_product, manual_order, other + selectProductDropdown: '//span[normalize-space()="Search product"]/../..//div[@class="multiselect__select"]', + selectProductInput: '//input[@placeholder="Search product"]', + selectOrderDropdown: '//span[normalize-space()="Search order"]/../..//div[@class="multiselect__select"]', + selectOrderInput: '//input[@placeholder="Search order"]', + selectOption: (value: string) => `//div[@class="dokan-modal"]//li//span[contains(text(), "${value}")]/..`, + searchedResult: 'span.multiselect__option.multiselect__option--highlight', + withdrawalBalanceType: (type: string) => `//input[@value="${type}"]/..`, // debit, credit + reverseWithdrawalAmount: 'input.regular-text.wc_input_decimal', + note: '//textarea[@placeholder="Write reverse withdrawal note"]', + save: 'button.dokan-rw-footer-btn', + }, + }, + + // Vendors + vendors: { + vendorsText: '.vendor-list h1', + addNewVendor: '//button[contains(text(), "Add New")]', + storeCategories: '//a[normalize-space()="Store Categories"]', + + // Nav Tabs + navTabs: { + cancelled: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + approved: '//ul[@class="subsubsub"]//li//a[contains(text(),"Approved")]', + pending: '//ul[@class="subsubsub"]//li//a[contains(text(),"Pending")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // approved, cancelled, delete, paypal + applyAction: '.tablenav.top .button.action', + }, + + // Filters + filters: { + filterByBadges: '#badge_name', + clearFilter: '//select[@id="badge_name"]/..//button', + }, + + search: '#post-search-input', + + // Table + table: { + vendorTable: '.vendor-list table', + storeColumn: 'thead th.store_name', + emailColumn: 'thead th.email', + categoryColumn: 'thead th.categories', + phoneColumn: 'thead th.phone', + RegisteredColumn: 'thead th.registered', + StatusColumn: 'thead th.enabled', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No vendors found."]', + vendorViewDetails: (username: string) => `//td//a[contains(text(), '${username}')]`, + vendorRow: (username: string) => `//td//a[contains(text(), '${username}')]/../../..`, + vendorCell: (username: string) => `//td//a[contains(text(), '${username}')]/../..`, + vendorEdit: (username: string) => `//td//a[contains(text(), '${username}')]/../..//span[@class="edit"]//a`, + vendorProducts: (username: string) => `//td//a[contains(text(), '${username}')]/../..//span[@class="products"]//a`, + vendorOrders: (username: string) => `//td//a[contains(text(), '${username}')]/../..//span[@class="orders"]//a`, + statusSlider: (username: string) => `//td//a[contains(text(), '${username}')]/../../..//label[@class='switch tips']`, + + // Add New Vendors + + newVendor: { + // Menus + accountInfo: '//div[@class="tab-link"]//a[contains(text(), "Account Info")]', + address: '//div[@class="tab-link"]//a[contains(text(), "Address")]', + paymentOptions: '//div[@class="tab-link"]//a[contains(text(), "Payment Options")]', + addNewVendorCloseModal: '.modal-close', + next: '.button.button-primary', + + // Account Info + + vendorPicture: '.profile-image .dokan-upload-image', + banner: '.banner-image .dokan-upload-image button', + firstName: '#first-name', + lastName: '#last-name', + storeName: '#store-name', + storeUrl: '#user-nicename', + phoneNumber: '#store-phone', + email: '#store-email', + username: '#user-login', + generatePassword: '.button.button-secondary', + password: '#store-password', + companyName: '#company-name', + companyIdEuidNumber: '#company-id-number', + vatOrTaxNumber: '#vat-tax-number', + nameOfBank: '#dokan-bank-name', + bankIban: '#dokan-bank-iban', + // Address + street1: '#street-1', + street2: '#street-2', + city: '#city', + zip: '#zip', + // country: '.multiselect__single', + country: '//label[@for="country"]/..//div[@class="multiselect__select"]', + countryInput: '#country', + state: '//label[@for="state"]/..//div[@class="multiselect__select"]', + stateInput: '#state', + // Payment Options + accountName: '#account-name', + accountNumber: '#account-number', + bankName: '#bank-name', + bankAddress: '#bank-address', + routingNumber: '#routing-number', + iban: '#iban', + swift: '#swift', + payPalEmail: '#paypal-email', + enableSelling: '//span[contains(text(),"Enable Selling")]/..//span[@class="slider round"]', + publishProductDirectly: '//span[contains(text(), "Publish Product Directly")]/..//span[@class="slider round"]', + makeVendorFeature: '//span[contains(text(), "Make Vendor Featured")]/..//span[@class="slider round"]', + createVendor: '.button.button-primary.button-hero', + }, + + // Sweet Alert + createAnother: '.swal2-confirm', // Sweet Alert Confirm + editVendorInfo: '.swal2-cancel', // Sweet Alert Cancel + closeSweetAlert: '.swal2-close', // Sweet Alert Close + sweetAlertTitle: '#swal2-title', // sweet alert title + + vendorDetails: { + profileInfo: { + profileInfoDiv: 'div.profile-info', + profileImage: '.profile-info .profile-icon img', + featuredVendor: 'span[title="Featured Vendor"]', + + storeName: '.profile-info .store-name', + storeRating: '.profile-info .star-rating', + storeCategory: '.profile-info .store-categoy-names', + storeAddress: '.profile-info .address', + phone: '.profile-info .phone', + + sendEmail: '.profile-info .message', + sellingStatus: '.profile-info .status', + }, + + sendEmail: { + closeModal: '.modal-close.modal-close-link', + replyTo: 'input#replyto', + subject: 'input#subject', + message: 'textarea#message', + sendEmail: '.modal-footer button', + }, + + profileBanner: { + profileBanner: 'div.profile-banner', + visitStore: 'div.action-links a.visit-store ', + editStore: 'div.action-links a.router-link-active', + }, + + vendorSummary: { + vendorSummarySection: 'section.vendor-summary', + + // badges + badgesAcquired: { + badgesAcquired: 'div.seller-badge-list-card', + noBadgesAvailable: '.no-badge-available', + badgesGallery: '.myGallery', + }, + + // products-revenue + productRevenue: { + productRevenueSection: '.vendor-summary div.products-revenue', + + products: { + products: 'div.products-revenue .stat-summary.products', + productCount: 'ul.counts li.products .count', + soldItemCount: 'ul.counts li.items .count', + visitorsCount: 'ul.counts li.visitors .count', + }, + + revenue: { + revenue: 'div.products-revenue .revenue', + ordersCount: 'ul.counts li.orders .count', + grossSales: 'ul.counts li.gross .count', + totalEarning: 'ul.counts li.earning .count', + }, + + others: { + others: 'div.products-revenue .others', + commissionRate: 'ul.counts li.commision .count', + balance: 'ul.counts li.balance .count', + reviewsCount: 'ul.counts li.reviews .count', + }, + }, + + // vendor info + vendorInfo: { + registeredSection: 'li.registered', + registeredDate: 'li.registered .date', + + socialProfilesSection: 'li.social-profiles', + socialProfilesList: 'li.social-profiles .profiles', + + paymentsSection: 'li.payments', + paymentMethods: 'li.payments .payment-methods', + + publishStatusSection: 'li.publishing', + }, + }, + }, + + // Edit Vendor + editVendor: { + editVendorIcon: '.dashicons-edit', + changeStorePhoto: '.profile-icon .dokan-upload-image img', + changeStoreBanner: '.profile-banner .dokan-upload-image img', + + // Account Info + firstName: '#first-name', + lastName: '#last-name', + storeName: '#store-name', + phoneNumber: '#store-phone', + email: '#store-email', + companyName: '#company-name', + companyIdEuidNumber: '#company-id-number', + vatOrTaxNumber: '#vat-tax-number', + nameOfBank: '#dokan-bank-name', + bankIban: '#dokan-bank-iban', + + // Address + street1: '#street-1', + street2: '#street-2', + city: '#city', + zipCode: '#zip', + country: '//input[@id="country"]/../..//div[@class="multiselect__select"]', + countryInput: '#country', + state: '//input[@id="state"]/../..//div[@class="multiselect__select"]', + stateInput: '#state', + + // Social Options + facebook: '#facebook', + flickr: '#flickr', + twitter: '#twitter', + youtube: '#youtube', + linkedin: '#linkedin', + pinterest: '//label[@id="pinterest"]/..//input', + instagram: '#instagram', + + // Payment Options + accountName: '#account-name', + accountNumber: '#account-number', + bankName: '#bank-name', + accountType: '#account-type', // personal, business + bankAddress: '#bank-address', + routingNumber: '#routing-number', + iban: '#iban', + swift: '#swift', + payPalEmail: '#paypal-email', + AdminCommissionType: '//label[@for="commission-type"]/..//span[@class="multiselect__single"]', + AdminCommissionFlat: '.wc_input_price', + AdminCommissionPercentage: '.wc_input_decimal', + + enableSelling: '//span[contains(text(), "Enable Selling")]/..//label[@class="switch tips"]', + publishProductDirectly: '//span[contains(text(), "Publish Product Directly")]/..//label[@class="switch tips"]', + makeVendorFeature: '//span[contains(text(), "Make Vendor Featured")]/..//label[@class="switch tips"]', + + // Vendor Subscription + AssignSubscriptionPack: '.multiselect--active > .multiselect__tags', + + // Edit Options + cancelEdit: '//div[contains(@class, "action-links footer")]//button[contains(text(),"Cancel")]', + saveChanges: '//div[contains(@class, "action-links footer")]//button[contains(text(),"Save Changes")]', + cancelEditOnTop: '//div[contains(@class, "profile-banner")]//button[contains(text(),"Cancel")]', + saveChangesOnTop: '//div[contains(@class, "profile-banner")]//button[contains(text(),"Save Changes")]', + confirmSaveChanges: 'button.swal2-confirm', + }, + + storeCategory: { + addNewCategory: { + name: '#tag-name', + slug: '#tag-slug', + description: '#tag-description', + addNewCategory: '#submit', + }, + + editCategory: { + name: '#name', + slug: '#slug', + description: '#description', + update: 'button[type="submit"]', + }, + + search: '//input[@placeholder="Search Categories"]', + + // Table + table: { + vendorTable: '#dokan-store-categories table', + nameColumn: 'thead th.name', + descriptionColumn: 'thead th.description', + slugColumn: 'thead th.slug', + countColumn: 'thead th.count', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No category found"]', + storeCategoryCell: (title: string) => `//td//a[contains(text(), '${title}')]/../..`, + storeCategoryEdit: (title: string) => `//td//a[contains(text(), '${title}')]/../..//span[@class='edit']//a`, + storeCategoryDelete: (title: string) => `//td//a[contains(text(), '${title}')]/../..//span[@class='delete']//a`, + storeCategorySetDefault: (title: string) => `//td//a[contains(text(), '${title}')]/../..//span[@class='set_as_default']//a`, + }, + }, + + // Abuse Reports + abuseReports: { + abuseReportsText: 'h1.wp-heading-inline', + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // delete + applyAction: '.tablenav.top .button.action', + }, + + // Filters + filters: { + filterByAbuseReason: '(//select[@id="filter-products"]/..//select)[1]', + filterByProduct: '(//span[@class="select2-selection__arrow"])[1]', + filterByVendors: '(//span[@class="select2-selection__arrow"])[2]', + filterInput: '.select2-search.select2-search--dropdown .select2-search__field', + }, + + // Table + table: { + abuseReportsTable: '.wp-list-table', + reasonColumn: 'thead th.reason', + productColumn: 'thead th.product', + vendorColumn: 'thead th.vendor', + reportedByColumn: 'thead th.reported_by', + reportedAtColumn: 'thead th.reported_at', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No items found."]', + abuseReportCell: (input: string) => `//a[contains(text(), '${input}')]/../..`, // abuse-reason, product-name, vendor-name + abuseReportFirstCell: '(//a[@href="#view-report"])[1]', + + abuseReportModal: { + modalTitle: '.modal-header h1', + closeModal: '.modal-close', + reportedProduct: '//strong[normalize-space()="Reported Product:"]', + reason: '//strong[normalize-space()="Reason:"]', + description: '//strong[normalize-space()="Description:"]', + reportedBy: '//strong[normalize-space()="Reported by:"]', + reportedAt: '//strong[normalize-space()="Reported At:"]', + productVendor: '//strong[normalize-space()="Product Vendor:"]', + }, + }, + + // Store Reviews + storeReviews: { + storeReviewsText: '.dokan-store-reviews h1', + + // Nav Tabs + navTabs: { + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + trash: '//ul[@class="subsubsub"]//li//a[contains(text(),"Trash")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // trash + applyAction: '.tablenav.top .button.action', + }, + + // Filters + filters: { + filterByVendor: '.select2-selection__arrow', + filterInput: '.select2-search.select2-search--dropdown .select2-search__field', + filterClear: '.select2-selection__clear', + }, + + // Table + table: { + storeReviewsTable: '.dokan-store-reviews table', + titleColumn: 'thead th.title', + contentColumn: 'thead th.content', + customerColumn: 'thead th.customer', + vendorColumn: 'thead th.vendor', + ratingColumn: 'thead th.rating', + dateColumn: 'thead th.created_at', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No reviews found."]', + storeReviewCell: (title: string) => `//td//a[contains(text(), '${title}')]/../..`, + storeReviewFirstCell: '(//td[@class="column title"]//a[@href="#"]/../..)[1]', + storeReviewFirstLink: '(//td[@class="column title"]//a[@href="#"])[1]', + storeReviewEdit: '(//a[normalize-space()="Edit"])[1]', + storeReviewDelete: '(//a[normalize-space()="Trash"])[1]', + storeReviewRestore: '(//a[normalize-space()="Restore"])[1]', + storeReviewPermanentlyDelete: '(//a[normalize-space()="Permanent Delete"])[1]', + + editReview: { + editReviewText: '//h1[normalize-space()="Edit Review"]', + modalClose: 'button.modal-close.modal-close-link', + ratings: '(//div[@class="modal-body"]//div[@class="vue-star-rating"] )[1]', + rating: (star: string) => `(//span[@class='vue-star-rating-pointer vue-star-rating-star'])[${star}]`, + title: '#store-review-title', + content: '#store-review-content', + update: 'input[value="Update Review"]', + }, + }, + + // Store Support + storeSupport: { + storeSupportText: '.admin-store-support-tickets h1', + + unreadTicketCount: 'span.pending-count.dokan-unread-ticket-count-badge-in-list', + + // Nav Tabs + navTabs: { + open: '//ul[@class="subsubsub"]//li//a[contains(text(),"Open")]', + closed: '//ul[@class="subsubsub"]//li//a[contains(text(),"Closed")]', + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // close + applyAction: '.tablenav.top .button.action', + }, + + // Filters + filters: { + filterByVendors: '//select[@id="filter-vendors"]/..//span[@class="select2-selection__arrow"]', + filterByCustomers: '//select[@id="filter-customers"]/..//span[@class="select2-selection__arrow"]', + filterInput: '.select2-search.select2-search--dropdown .select2-search__field', + filterButton: '//button[normalize-space()="Filter"]', + result: 'li.select2-results__option.select2-results__option--highlighted', + }, + + searchTicket: '#post-search-input', + + // Table + table: { + storeSupportTable: '.admin-store-support-tickets table', + topicColumn: 'thead th.ID', + titleColumn: 'thead th.post_title', + vendorColumn: 'thead th.vendor_name', + customerColumn: 'thead th.customer_name', + statusColumn: 'thead th.post_status', + dateColumn: 'thead th.ticket_date', + actionColumn: 'thead th.action', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No tickets found."]', + supportTicketCell: (ticketId: string) => `//strong[contains(text(), '#${ticketId}')]/../..`, + supportTicketFirstCell: '(//td[@class="column ID"]//a)[1]', + supportTicketLink: (ticketId: string) => `//strong[contains(text(), '#${ticketId}')]/..`, + + supportTicketDetails: { + backToTickets: '//span[@class="back-to-tickets"]//../..//a', + + ticketTitle: '//span[contains(@class,"dokan-chat-title") and not(contains(@class,"dokan-chat-status"))]', + chatStatus: 'div.dokan-chat-status-box span.dokan-chat-status', + chatBox: 'div.dokan-chat-box-container', + + chatAuthor: 'select#sender', // admin, vendor + chatReply: 'textarea.dokan-chat-replay', + sendReply: 'button.dokan-send-replay', + + ticketSummary: { + summaryDiv: 'div.dokan-chat-summary-holder', + summaryHeading: 'span.dokan-chat-summary', + summaryArrow: 'span.dokan-summary-arrow', + + ticketId: 'div.dokan-summary-info.ticket-id', + vendorInfo: 'div.dokan-summary-info.dokan-vendor-info', + customerInfo: 'div.dokan-summary-info.dokan-customer-info', + messageCount: 'div.dokan-summary-info.conversation', + createdAt: '//div[normalize-space()="Created At:"]/..//div[@class="dokan-summary-info created-at"]', + emailNotification: '.dokan-summary-info label.switch.tips', + closeTicket: 'button.dokan-close-ticket', + reopenTicket: 'button.dokan-reopen-ticket', + }, + }, + }, + + // Request for quotation + requestForQuotation: { + menus: { + quoteList: '//a[normalize-space()="Quotes List"]', + quoteRules: '//a[normalize-space()="Quote Rules"]', + }, + + quotesList: { + quotesText: '.dokan-quote-wrapper h1', + + newQuote: '.page-title-action', + + // Nav Tabs + navTabs: { + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + pending: '//ul[@class="subsubsub"]//li//a[contains(text(),"Pending")]', + draft: '//ul[@class="subsubsub"]//li//a[contains(text(),"Draft")]', + converted: '//ul[@class="subsubsub"]//li//a[contains(text(),"Converted")]', + approved: '//ul[@class="subsubsub"]//li//a[contains(text(),"Approved")]', + trash: '//ul[@class="subsubsub"]//li//a[contains(text(),"Trash")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // trash + applyAction: '.tablenav.top .button.action', + }, + + // Table + table: { + quotesTable: '.dokan-quote-wrapper table', + quoteColumn: 'thead th.sl', + quoteTitleColumn: 'thead th.title', + customerEmailColumn: 'thead th.customer_email', + quoteStatusColumn: 'thead th.status', + dateColumn: 'thead th.created_at', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No quote found."]', + quoteCell: (title: string) => `//strong[contains(text(),'${title}')]/../..//td[@class='column sl']`, + quoteEdit: (title: string) => `//strong[contains(text(),'${title}')]/../..//td[@class='column sl']//span[@class="edit"]`, + quoteTrash: (title: string) => `//strong[contains(text(),'${title}')]/../..//td[@class='column sl']//span[@class="trash"]`, + quotePermanentlyDelete: (title: string) => `//strong[contains(text(),'${title}')]/../..//span[@class="delete"]`, + quoteRestore: (title: string) => `//strong[contains(text(),'${title}')]/../..//span[@class="restore"]`, + + approveQuote: 'input[value="Approve Quote"]', + convertToOrder: 'input[value="Convert to Order"]', + + addNewQuote: { + goBack: '//a[normalize-space()="Go Back"]', + + // title + quoteTitle: '#title', + + // customer information + quoteUserDropDown: '.multiselect__select', + quoteUserInput: '.multiselect__input', + fullName: 'input[name="name_field"]', + email: 'input[name="email_field"]', + companyName: 'input[placeholder="Company Name"]', + phoneNumber: 'input[name="phone_field"]', + + // quote details + addProducts: 'input[value="Add product(s)"]', + quoteProductDropDown: '.dokan-modal .multiselect__select', + quoteProductInput: '.dokan-modal .multiselect__input', + quoteProductQuantity: '#quantity', + addToQuote: 'input[value="Add to quote"]', + offerPrice: '#offer_price', + offerProductQuantity: '#offer_product_quantity', + deleteQuoteProduct: '.dashicons.dashicons-no', + + offerPriceByProductName: (product: string) => `//a[normalize-space()="${product}"]/../../..//input[@id="offer_price"]`, + offerProductQuantityByProductName: (product: string) => `//a[normalize-space()="${product}"]/../../..//input[@id="offer_product_quantity"]`, + deleteQuoteProductByProductName: (product: string) => `//a[normalize-space()="${product}"]/../../..//span[@class="dashicons dashicons-no"]`, + + // publish + saveQuoteAsDraft: 'input[value="Save as Draft"]', + publishQuote: 'input[value="Publish"]', + }, + }, + + quoteRules: { + quoteRulesText: '.dokan-announcement-wrapper h1', + + newQuoteRule: '.page-title-action', + + // Nav Tabs + navTabs: { + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + published: '//ul[@class="subsubsub"]//li//a[contains(text(),"Published")]', + draft: '//ul[@class="subsubsub"]//li//a[contains(text(),"Draft")]', + trash: '//ul[@class="subsubsub"]//li//a[contains(text(),"Trash")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // trash + applyAction: '.tablenav.top .button.action', + }, + + // Table + table: { + quoteRulesTable: '.dokan-announcement-wrapper table', + titleColumn: 'thead th.rule_name', + userRolesColumn: 'thead th.selected_user_role', + hidePriceColumn: 'thead th.hide_price', + buttonTextColumn: 'thead th.button_text', + rulePriorityColumn: 'thead th.rule_priority', + ruleStatusColumn: 'thead th.status', + dateColumn: 'thead th.created_at', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No quote found."]', + quoteRulesCell: (title: string) => `//a[contains(text(),'${title}')]/../..`, + trashedQuoteRulesCell: (title: string) => `//strong[contains(text(),'${title}')]/../..`, + quoteRulesEdit: (title: string) => `//a[contains(text(),'${title}')]/../..//span[@class="edit"]`, + quoteRulesTrash: (title: string) => `//a[contains(text(),'${title}')]/../..//span[@class="trash"]`, + quoteRulesPermanentlyDelete: (title: string) => `//strong[contains(text(),'${title}')]/../..//span[@class="delete"]`, + quoteRulesRestore: (title: string) => `//strong[contains(text(),'${title}')]/../..//span[@class="restore"]`, + + addNewQuoteRule: { + goBack: '//a[normalize-space()="Go Back"]', + + // title + ruleTitle: '#title', + + // rule settings + applyQuoteFor: (role: string) => `#${role}`, + applyQuoteFor1: (role: string) => `//label[normalize-space()="${role}"]/..//input`, + applyOnAllProducts: '#apply_on_all_product', + selectProductsDropDown: '.multiselect__select', + selectProductsInput: '.multiselect__input', + selectCategories: (category: string) => `//span[normalize-space()="${category}"]/..//input`, + hidePrice: '#announcement_sender_type', // 1, 0 + hidePriceText: '//th[normalize-space()="Hide Price Text"]/..//input', + hideAddToCartButton: 'select[name="hide_cart_button"]', // replace, keep_and_add_new + customButtonLabel: '//th[normalize-space()="Custom Button Label"]/..//input', + + // rule priority + priorityOrder: '//span[normalize-space()="Rule priority"]/../../..//input', + + // publish + saveRuleAsDraft: 'input[value="Save as Draft"]', + publishRule: 'input[value="Publish"]', + }, + }, + }, + + // Seller Badge + sellerBadge: { + sellerBadgeText: '.seller-badge-list h1', + createBadge: '//a[normalize-space()="+ Create Badge"]', + + // Nav Tabs + navTabs: { + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + published: '//ul[@class="subsubsub"]//li//a[contains(text(),"Published")]', + draft: '//ul[@class="subsubsub"]//li//a[contains(text(),"Draft")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // delete + applyAction: '.tablenav.top .button.action', + }, + + search: '#post-search-input', + + // Table + table: { + sellerBadgeTable: '.seller-badge-list table', + badgesNameColumn: 'thead th.badge_name', + badgeEventColumn: 'thead th.event_type', + noOfVendorsColumn: 'thead th.vendor_count', + statusColumn: 'thead th.badge_status', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No badges found."]', + sellerBadgeRow: (name: string) => `//a[contains(text(),'${name}')]/../../..`, + sellerBadgeCell: (name: string) => `//a[contains(text(),'${name}')]/../..`, + sellerBadgeLevel: (name: string) => `//a[contains(text(),'${name}')]/../../..//span[@class="level_count"]//strong`, + sellerBadgeEdit: (name: string) => `//a[contains(text(),'${name}')]/../..//div[@class="row-actions"]//span[@class="edit"]//a`, + sellerBadgePreview: (name: string) => `//a[contains(text(),'${name}')]/../..//div[@class="row-actions"]//span[@class="view"]//a`, + sellerBadgeVendors: (name: string) => `//a[contains(text(),'${name}')]/../..//div[@class="row-actions"]//span[@class="show_vendors"]//a`, + sellerBadgePublish: (name: string) => `//a[contains(text(),'${name}')]/../..//div[@class="row-actions"]//span[@class="publish"]//a`, + sellerBadgeDraft: (name: string) => `//a[contains(text(),'${name}')]/../..//div[@class="row-actions"]//span[@class="draft"]//a`, + sellerBadgeDelete: (name: string) => `//a[contains(text(),'${name}')]/../..//div[@class="row-actions"]//span[@class="delete"]//a`, + + confirmAction: '.swal2-actions .swal2-confirm', + cancelAction: '.swal2-actions .swal2-cancel', + successMessage: '.swal2-actions .swal2-confirm', + + previewBadgeDetails: { + modal: '.seller-badge-modal-content', + + modalHeader: { + modalImage: '.modal-header .modal-img', + modalTitle: '.modal-header .modal-title', + modalClose: '.modal-header .modal-close', + }, + + levelBox: '.modal-level-box', + }, + + badgeDetails: { + // badge event + badgeEvents: { + badgeEventBox: 'div.badge__event-box', + badgeEventDropdown: '.seller-badge-event-dropdown', + badgeEvent: (name: string) => `//h3[normalize-space()="${name}"]/../..`, + badgePublishedStatus: (name: string) => `//h3[normalize-space()="${name}"]/..//i[contains(@class, "published")]`, + badgeName: 'input#title', + }, + + // badge condition & level + badgeCondition: { + badgeConditionBox: 'div.badge__condition-box', + badgeLevel: 'span.badge-level', + startingLevelValue: '//span[normalize-space()="Level 1"]/..//input', + levelInputValue: (value: string) => `//span[normalize-space()="Level ${value}"]/..//input`, + addBadgeLevel: 'div.dokan-logical-container button', + removeBadgeLevel: '(//i[@class="remove-level"])[2]', + verifiedSellerMethod: '//option[normalize-space()="Select a method"]/..', + disabledVerifiedSellerMethod: '//select//option[@disabled="disabled"]', + verifiedSellerMethod1: (number: number) => `(//option[normalize-space()="Select a method"]/..)[${number}]`, + trendingProductPeriod: '.dokan-logical-container select', + trendingProductTopBestSellingProduct: '.dokan-logical-container input', + }, + + // badge photo + badgePhoto: { + uploadBadgeImage: '//div[@class="dokan-upload-image-container"]//img', + badgePhotoReset: '//a[normalize-space()="restore default."]', + }, + + // badge status + badgeStatus: { + badgeStatus: 'select#status', + create: '//button[normalize-space()="Create"]', + update: '//button[normalize-space()="Update"]', + goBack: '//button[normalize-space()="Go Back"]', + }, + + confirmBadgeUpdate: '.swal2-actions .swal2-confirm', + badgeAddedSuccessfully: '.swal2-actions .swal2-confirm', + }, + }, + + // Announcements + announcements: { + announcementText: '.dokan-announcement-wrapper h1', + + addNewAnnouncement: '//a[normalize-space()="Add Announcement"]', + + // Nav Tabs + navTabs: { + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + published: '//ul[@class="subsubsub"]//li//a[contains(text(),"Published")]', + pending: '//ul[@class="subsubsub"]//li//a[contains(text(),"Pending")]', + scheduled: '//ul[@class="subsubsub"]//li//a[contains(text(),"Scheduled")]', + draft: '//ul[@class="subsubsub"]//li//a[contains(text(),"Draft")]', + trash: '//ul[@class="subsubsub"]//li//a[contains(text(),"Trash")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // trash + applyAction: '.tablenav.top .button.action', + }, + + // Table + table: { + announcementTable: '.dokan-announcement-wrapper table', + titleColumn: 'thead th.title', + contentColumn: 'thead th.content', + sentToColumn: 'thead th.send_to', + statusColumn: 'thead th.status', + dateColumn: 'thead th.created_at', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No announcement found."]', + announcementCell: (title: string) => `//a[contains(text(),'${title}')]/../..`, + announcementCellPublished: (title: string) => `//strong[contains(text(),'${title}')]/../..`, + announcementStatusPublished: (title: string) => `//strong[contains(text(),'${title}')]/../..//td[@class="column status"]//span[@class="publish"]`, + announcementStatusScheduled: (title: string) => `//a[contains(text(),'${title}')]/../../..//td[@class="column status"]//span[@class="future"]`, + announcementEdit: (title: string) => `//a[contains(text(),'${title}')]/../..//span[@class="edit"]`, + announcementDelete: (title: string) => `//strong[contains(text(),'${title}')]/../..//span[@class="trash"]`, + announcementPermanentlyDelete: (title: string) => `//a[contains(text(),'${title}')]/../..//span[@class="delete"]`, + announcementRestore: (title: string) => `//a[contains(text(),'${title}')]/../..//span[@class="restore"]`, + + // add announcement + addAnnouncement: { + title: '#titlediv input', + contentIframe: '#postdivrich iframe', + contentHtmlBody: '#tinymce', + sendAnnouncementTo: '#announcement_sender_type', // all_seller, selected_seller, enabled_seller, disabled_seller, featured_seller + saveAsDraft: '.draft-btn', + publish: '.publish-btn', + + schedule: { + addSchedule: 'span#timestamp a', + month: 'fieldset#timestampdiv label select', + day: 'input#jj', + year: 'input#aa', + hour: 'input#hh', + minute: 'input#mm', + ok: '//button[normalize-space()="Ok"]', + cancel: '//button[normalize-space()="Cancel"]', + }, + }, + }, + + // Refunds + refunds: { + refundRequestsText: '.dokan-refund-wrapper h1', + + // Nav Tabs + navTabs: { + 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")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // completed, cancelled + applyAction: '.tablenav.top .button.action', + }, + + // Search Refund + search: '#post-search-input', + + // Table + table: { + refundRequestTable: '.dokan-refund-wrapper table', + orderIdColumn: 'thead th.order_id', + vendorColumn: 'thead th.vendor', + refundAmountColumn: 'thead th.amount', + refundReasonColumn: 'thead th.reason', + paymentGatewayColumn: 'thead th.method', + dateColumn: 'thead th.date', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No request found."]', + refundCell: (orderNumber: string) => `//strong[contains(text(),'#${orderNumber}')]/../..`, + approveRefund: (orderNumber: string) => `//strong[contains(text(),'#${orderNumber}')]/../..//span[@class='completed']`, + cancelRefund: (orderNumber: string) => `//strong[contains(text(),'#${orderNumber}')]/../..//span[@class='cancelled']`, + }, + + // Reports + reports: { + // Menus + menus: { + reports: '//a[contains(@class, "nav-tab") and contains(text(),"Reports")]', + allLogs: '//a[contains(@class, "nav-tab") and contains(text(),"All Logs")]', + }, + // Reports + + reports: { + // At a Glance + atAGlance: { + atAGlance: '.postbox.dokan-postbox.dokan-status', + collapsibleButton: '.dokan-status .handle-actions button', + netSalesThisMonth: '.sale strong', + commissionEarned: '.commission strong div', + signupThisMonth: '.vendor strong', + vendorAwaitingApproval: '.approval strong', + productCreatedThisMonth: '.product strong', + withdrawAwaitingApproval: '.withdraw strong', + }, + + // Overview + overview: { + overview: '.postbox.dokan-postbox.overview-chart', + collapsibleButton: '.overview-chart .handle-actions button', + chart: '#line-chart', + }, + + // filterMenus + + filterMenus: { + byDay: '//ul[contains(@class, "dokan-report-sub")]//a[contains(text(),"By Day")]', + byYear: '//ul[contains(@class, "dokan-report-sub")]//a[contains(text(),"By Year")]', + byVendor: '//ul[contains(@class, "dokan-report-sub")]//a[contains(text(),"By Vendor")]', + }, + + filters: { + // By Year + filterByYearNumber: '.dokan-input', + // By Vendor + filterByStoreName: '.multiselect__tags', + filterByStoreNameInput: 'multiselect__input', + }, + + // calendar + calendar: { + dateFrom: '(//form[@class="form-inline report-filter"]//input[@class="dokan-input hasDatepicker"])[1]', + dateTo: '(//form[@class="form-inline report-filter"]//input[@class="dokan-input hasDatepicker"])[2]', + }, + + // show + show: '//button[normalize-space()="Show"]', + }, + + // All Logs + + allLogs: { + // Filter + filters: { + filterByStore: '//span[@id="select2-filter-vendors-container"]/..//span[@class="select2-selection__arrow"]', + filterByStoreInput: '//input[@class="select2-search__field" and @aria-owns="select2-filter-vendors-results"]', + // filterByStoreValues: '.select2-results ul li', + filterByStatus: '//span[@class="select2-selection select2-selection--multiple"]', + filterByStatusInput: '//input[@class="select2-search__field" and @placeholder="Filter by status"]', + searchedResult: '.select2-results__option.select2-results__option--highlighted', + // filterByStatusValues: '.select2-results ul li', + filterByDate: '.form-control', + clear: '//a[contains(text(),"Clear")]', + }, + + // Search + search: '#post-search-input', + + // Logs + exportLogs: '#export-all-logs', + + table: { + allLogsTable: '.reports-page table', + orderIdColumn: 'thead th.order_id', + storeColumn: 'thead th.vendor_id', + orderTotalColumn: 'thead th.order_total', + vendorEarningColumn: 'thead th.vendor_earning', + commissionColumn: 'thead th.commission', + gatewayFeeColumn: 'thead th.dokan_gateway_fee', + shippingColumn: 'thead th.shipping_total', + shippingTaxColumn: 'thead th.shipping_total_tax', + productTaxColumn: 'thead th.tax_total', + statusColumn: 'thead th.status', + DateColumn: 'thead th.date', + }, + + // Order Details + numberOfRowsFound: '.tablenav.top .displaying-num', + orderIdRow: (orderNumber: string) => `//a[normalize-space()='#${orderNumber}']/..//..`, + orderIdCell: (orderNumber: string) => `//a[normalize-space()='#${orderNumber}']/..`, + orderIdOrderTotal: (orderNumber: string) => `//a[normalize-space()='#${orderNumber}']/..//..//td[@class="column order_total"]//div`, + + orderDetails: { + orderId: '.column.order_id > a', + store: '.column.vendor_id > a', + orderTotal: '.column.order_total > div', + vendorEarning: '.column.vendor_earning > div', + commission: '.column.commission > div', + gatewayFee: '.column.dokan_gateway_fee > div', + shippingCost: '.column.shipping_total > div', + tax: '.column.tax_total > div', + orderStatus: 'td.column.status', + orderDate: 'td.column.date ', + }, + }, + }, + + // Modules + modules: { + lite: { + moduleText: '#lite-modules h1', + + // dokan upgrade popup + popup: { + dokanUpgradePopup: '#dokan-upgrade-popup', + closeDokanUpgradePopup: '#dokan-upgrade-popup .close', + upgradeToProText: '.upgrade-text', + upgradeToPro: '.upgrade-button', + proCard: '.promo-card', + alreadyUpdated: '.already-updated', + }, + + // modules + moduleCard: '.plugin-card', + }, + + pro: { + moduleText: '.dokan-modules-wrap h1', + + // module plan + modulePlan: { + planName: '.plan-name', + upgradePlan: '.module-plan .upgrade-plan', + }, + + // Nav Tabs + navTabs: { + myModules: '//li//a[contains(text(),"My Modules")]', + active: '//li//a[contains(text(),"Active")]', + inActive: '//li//a[contains(text(),"Inactive")]', + }, + + // filter + moduleFilter: '.module-category-filter', + moduleFilterCheckBox: (category: string) => `//label[contains(text(),"${category}")]/..//input`, + clearFilter: '//a[normalize-space()="Clear filter"]', + moduleCategoryTag: (category: string) => `//span[normalize-space()="${category}"]`, + moduleCategoryTypes: { + productManagement: '.product-management', + integration: '.integration', + uiUx: '.ui-ux', + shipping: '.shipping', + storeManagement: '.store-management', + payment: '.payment', + orderManagement: '.order-management', + vendorManagement: '.vendor-management', + }, + + // Search Box + searchBox: '.search-box input', + clearSearch: '.search-box svg', + + // view mode + currentLayout: '.my-modules', + moduleViewMode: '.module-view-mode', + + // module card + moduleCard: '.module-card', + moduleCardByName: (moduleName: string) => `//a[normalize-space()="${moduleName}"]/../../..`, + moduleIcon: '.module-icon', + moduleCheckbox: '.module-checkbox input', + moduleName: '.module-details a', + moduleDescription: '.module-details p', + moduleCategory: '.module-details span', + moduleActivationSwitch: '.switch.tips span', + moduleDocs: '//a[normalize-space()="Docs"]', + moduleVideos: '//a[normalize-space()="Video"]', + + // All Module Activation + firstModuleCheckbox: '(//div[@class="module-checkbox"]//input)[1]', + selectAllBulkAction: '.bulk-actions li input', + activeAll: '.activate', + deActivateAll: '.deactivate', + cancelBulkAction: '.cancel', + + // No Modules Message + noModulesFound: '.not-found h5', + }, + }, + + // pro features + proFeatures: { + dokanProFeatures: '.dokan-pro-features', + + // header section + headerSection: '.header-section', + + // vender capabilities + vendorCapabilitiesBanner: '.vendor-capabilities-banner', + checkOutAllVendorFunctionalities: '//a[normalize-space()="Check Out All Vendor Functionalities"]', + + // service section + serviceSection: '.service-section', + serviceList: '.service-section .service-list', + andManyMore: '//a[normalize-space()="And Many More"]', + + // compare section + comparisonSection: '.comparison-section', + comparisonBoxDokanLite: '.comparison-section .compare-box.dokan-lite', + comparisonBoxDokanPro: '.comparison-section .compare-box.dokan-pro', + + // pricing section + pricingSection: '.pricing-section', + pricingTable: '.pricing-section .pricing-wrapper', + + // payment section + paymentSection: '.payment-section', + guaranteeSection: '.payment-section .guarantee-section', + paymentOptions: '.payment-section .payment-area', + + // testimonial section + testimonialSection: '.testimonial-section', + testimonials: '.testimonial-section .testimonial-wrapper', + + // cta section + ctaSection: '.cta-section', + upgradeToPro: '//a[normalize-space()="Upgrade to Pro"]', + }, + + // Tools + tools: { + toolsText: '.tools-page h1', + + // Page Installation + pageInstallation: { + pageInstallation: '//span[normalize-space()="Page Installation"]/../../..', + collapsibleButton: '//span[normalize-space()="Page Installation"]/../../..//button', + allPagesCreated: '//a[normalize-space()="All Pages Created"]', + }, + + // Regenerate Order Sync Tab + regenerateOrderSyncTable: { + regenerateOrderSyncTable: '//span[normalize-space()="Regenerate Order Sync Table"]/../../..', + collapsibleButton: '//span[normalize-space()="Regenerate Order Sync Table"]/../../..//button', + reBuild: '//a[normalize-space()="Re-build"]', + }, + + // Check for Duplicate Orders + checkForDuplicateOrders: { + checkForDuplicateOrders: '//span[normalize-space()="Check for Duplicate Orders"]/../../..', + collapsibleButton: '//span[normalize-space()="Check for Duplicate Orders"]/../../..//button', + checkOrders: '//a[normalize-space()="Check Orders"]', + }, + + // Dokan Setup Wizard + dokanSetupWizard: { + dokanSetupWizard: '//span[normalize-space()="Dokan Setup Wizard"]/../../..', + collapsibleButton: '//span[normalize-space()="Dokan Setup Wizard"]/../../..//button', + openSetupWizard: '//a[normalize-space()="Open Setup Wizard"]', + }, + + // regenerate Variable Product Variations Author Ids + regenerateVariableProductVariationsAuthorIds: { + regenerateVariableProductVariationsAuthorIds: '//span[normalize-space()="Regenerate Variable Product Variations Author IDs"]/../../..', + collapsibleButton: '//span[normalize-space()="Regenerate Variable Product Variations Author IDs"]/../../..//button', + regenerate: '//a[normalize-space()="Regenerate"]', + }, + + // Import Dummy Data + importDummyData: { + importDummyData: '//span[normalize-space()="Import Dummy Data"]/../../..', + collapsibleButton: '//span[normalize-space()="Import Dummy Data"]/../../..//button', + import: '//span[normalize-space()="Import Dummy Data"]/../../..//a', + }, + + // Test Distance Matrix API (Google MAP) + testDistanceMatrixApi: { + testDistanceMatrixApi: '//span[normalize-space()="Test Distance Matrix API (Google MAP)"]/../../..', + collapsibleButton: '//span[normalize-space()="Test Distance Matrix API (Google MAP)"]/../../..//button[@class="handlediv"]', + address1: '#address1', + address2: '#address2', + getDistance: '//button[normalize-space()="Get Distance"]', + enabledSuccess: '//div[@class="formatted-message success"]', + }, + }, + + // Verifications + verifications: { + verificationRequestsText: '//h2[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")]', + }, + + // 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]`, + }, + + 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"]`, + }, + + phoneRequest: { + // todo: + }, + + 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"]`, + }, + }, + + // Advertising + productAdvertising: { + productAdvertisingText: '.product-advertisement-list h1', + + addNewProductAdvertising: '//button[normalize-space()="Add New Advertisement"]', + + // Nav Tabs + navTabs: { + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + active: '//ul[@class="subsubsub"]//li//a[contains(text(),"Active")]', + expired: '//ul[@class="subsubsub"]//li//a[contains(text(),"Expired")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // delete + applyAction: '//div[@class="tablenav top"]//button[normalize-space()="Apply"]', + }, + + // Filters + filters: { + allStoresDropdown: '//input[@placeholder="Filter by store"]/../..//div[@class="multiselect__select"]', + createdViaDropdown: '(//div[@class="multiselect__select"])[2]', + filterByStoreInput: 'input[placeholder="Filter by store"]', + filterByCreatedVia: (createdVia: string) => `//li[@class="multiselect__element"]//span[contains(@class,"multiselect__option")]//span[contains(text(), "${createdVia}")]`, + clearFilter: '//button[normalize-space()="Clear"]', + // todo: add date-range filter locator + }, + + // Search + search: '#post-search-input', + + // Table + table: { + productAdvertisingTable: '#product_advertisement_list_table table', + productNameColumn: 'thead th.product_title', + storeNameColumn: 'thead th.store', + createdViaColumn: 'thead th.created_via', + orderIdColumn: 'thead th.order_id', + costColumn: 'thead th.price', + expiresColumn: 'thead th.expires_at', + dateColumn: 'thead th.added', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No advertisement found."]', + advertisedProductCell: (productName: string) => `//a[normalize-space()="${productName}"]/../..`, + advertisedProductOrderIdCell: (orderNumber: number) => `//a[normalize-space()="${orderNumber}"]/../..`, + advertisedProductExpire: (productName: string) => `//a[normalize-space()="${productName}"]/../..//span[@class="expire"]`, + advertisedProductDelete: (productName: string) => `//a[normalize-space()="${productName}"]/../..//span[@class="delete"]`, + + confirmAction: '.swal2-actions .swal2-confirm', // todo: merge this type of locators + actionSuccessful: '.swal2-actions .swal2-confirm', // todo: merge this type of locators + + addNewAdvertisement: { + closeModal: '.modal-header button', + selectStoreDropdown: '//label[normalize-space()="Select Store"]/..//div[@class="multiselect__select"]', + selectStoreInput: '#filter-vendors', + selectedStore: '//label[normalize-space()="Select Store"]/..//span[@class="multiselect__option multiselect__option--highlight"]//span', + selectProductDropdown: '//label[normalize-space()="Select Product"]/..//div[@class="multiselect__select"]', + selectProductInput: '#filter-products', + selectedProduct: '//label[normalize-space()="Select Product"]/..//span[@class="multiselect__option multiselect__option--highlight"]//span', + addReverseWithdrawalEntry: '#reverse-withdrawal-entry', + addNew: '.modal-footer button', + }, + }, + + // Wholesale Customer + wholesaleCustomer: { + wholesaleCustomerText: '.wholesale-customer-list h1', + + // Nav Tabs + navTabs: { + all: '//ul[@class="subsubsub"]//li//a[contains(text(),"All")]', + active: '//ul[@class="subsubsub"]//li//a[contains(text(),"Active")]', + deActive: '//ul[@class="subsubsub"]//li//a[contains(text(),"Deactive")]', + }, + + // Bulk Actions + bulkActions: { + selectAll: 'thead .manage-column input', + selectAction: '.tablenav.top #bulk-action-selector-top', // activate, deactivate + applyAction: '.tablenav.top .button.action', + }, + + search: '#post-search-input', + + // Table + table: { + wholesaleCustomerTable: '.wholesale-customer-list table', + nameColumn: 'thead th.full_name', + emailColumn: 'thead th.email', + usernameColumn: 'thead th.username', + rolesColumn: 'thead th.role', + registeredColumn: 'thead th.registered', + statusColumn: 'thead th.wholesale_status', + }, + + numberOfRowsFound: '.tablenav.top .displaying-num', + noRowsFound: '//td[normalize-space()="No customers found."]', + wholesaleCustomerCell: (username: string) => `//td[contains(text(), '${username}')]/..//td[@class='column full_name']`, + wholesaleCustomerEdit: (username: string) => `//td[contains(text(), '${username}')]/..//td[@class='column full_name']//span[@class='edit']//a`, + wholesaleCustomerOrders: (username: string) => `//td[contains(text(), '${username}')]/..//td[@class='column full_name']//span[@class='orders']//a`, + wholesaleCustomerRemove: (username: string) => `//td[contains(text(), '${username}')]/..//td[@class='column full_name']//span[@class='delete']//a`, + statusSlider: (username: string) => `//td[contains(text(), '${username}')]/..//label[@class='switch tips']`, + enableStatusUpdateSuccessMessage: '.notification-content', + }, + + // Help + help: { + helpText: '.dokan-help-page h1', + + // basics + basics: { + basics: '//span[contains(text(), "Basics")]/../../..', + collapsibleButton: '//span[contains(text(), "Basics")]/../../..//button', + basicsList: '//span[contains(text(), "Basics")]/../../..//ul', + }, + + // payment And Shipping + paymentAndShipping: { + paymentAndShipping: '//span[contains(text(), "Payment and Shipping")]/../../..', + collapsibleButton: '//span[contains(text(), "Payment and Shipping")]/../../..//button', + paymentAndShippingList: '//span[contains(text(), "Basics")]/../../..//ul', + }, + + // vendor related questions + vendorRelatedQuestions: { + vendorRelatedQuestions: '//span[contains(text(), "Vendor Related Questions")]/../../..', + collapsibleButton: '//span[contains(text(), "Vendor Related Questions")]/../../..//button', + vendorRelatedQuestionsList: '//span[contains(text(), "Basics")]/../../..//ul', + }, + + // miscellaneous + miscellaneous: { + miscellaneous: '//span[contains(text(), "Miscellaneous")]/../../..', + collapsibleButton: '//span[contains(text(), "Miscellaneous")]/../../..//button', + miscellaneousList: '//span[contains(text(), "Miscellaneous")]/../../..//button', + }, + }, + + spmv: { + spmvDiv: '#dokan-spmv-products-admin', + searchVendor: '#dokan-spmv-products-admin input.select2-search__field', + searchedResult: (storeName: string) => `//div[contains(text(),"${storeName}") and @class="dokan-spmv-vendor-dropdown-results__title"]`, + highlightedResult: '.select2-results__option.select2-results__option--highlighted', + assignVendor: '#dokan-spmv-products-admin-assign-vendors-btn', + unassignVendor: (storeName: string) => `//span[normalize-space()="${storeName}"]/../..//span[@class="delete-product"]`, + }, + + // Dokan Settings + settings: { + // settings pro advertisement + proAdvertisementBanner: { + settingsBanner: '#dokan-settings-banner', + upgradeToPro: '//a[normalize-space()="Upgrade to Pro"]', + checkOutAllVendorFunctionalities: '//a[normalize-space()="Check Out All Vendor Functionalities"]', + }, + + settingsText: '.dokan-settings h1', + + sections: { + settingsMenuSection: '.nab-section', + settingsMenuDetailsSection: '.nab-section', + }, + + header: { + settingsHeader: '.settings-header', + settingsTitle: '.settings-title', + settingsContent: '.settings-content', + settingsDocumentation: '.settings-document-button', + }, + + fields: '.dokan-settings-fields', + + saveChanges: '.submit', + + search: { + searchBox: '.search-box', + input: '#dokan-admin-search', + close: '.search-box span.dashicons', + }, + + backToTop: '.back-to-top.tips', + + // Setting Menus + menus: { + general: '//div[@class="nav-title" and contains(text(),"General")]', + sellingOptions: '//div[@class="nav-title" and contains(text(),"Selling Options")]', + withdrawOptions: '//div[@class="nav-title" and contains(text(),"Withdraw Options")]', + reverseWithdrawal: '//div[@class="nav-title" and contains(text(),"Reverse Withdrawal")]', + pageSettings: '//div[@class="nav-title" and contains(text(),"Page Settings")]', + appearance: '//div[@class="nav-title" and contains(text(),"Appearance")]', + privacyPolicy: '//div[@class="nav-title" and contains(text(),"Privacy Policy")]', + 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")]', + 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")]', + shippingStatus: '//div[@class="nav-title" and contains(text(),"Shipping Status")]', + quote: '//div[@class="nav-title" and contains(text(),"Quote Settings")]', + liveChat: '//div[@class="nav-title" and contains(text(),"Live Chat")]', + rma: '//div[@class="nav-title" and contains(text(),"RMA")]', + wholesale: '//div[@class="nav-title" and contains(text(),"Wholesale")]', + euComplianceFields: '//div[@class="nav-title" and contains(text(),"EU Compliance Fields")]', + deliveryTime: '//div[@class="nav-title" and contains(text(),"Delivery Time")]', + productAdvertising: '//div[@class="nav-title" and contains(text(),"Product Advertising")]', + geolocation: '//div[@class="nav-title" and contains(text(),"Geolocation")]', + productReportAbuse: '//div[@class="nav-title" and contains(text(),"Product Report Abuse")]', + singleProductMultiVendor: '//div[@class="nav-title" and contains(text(),"Single Product MultiVendor")]', + vendorSubscription: '//div[@class="nav-title" and contains(text(),"Vendor Subscription")]', + vendorAnalytics: '//div[@class="nav-title" and contains(text(),"Vendor Analytics")]', + }, + + // General + general: { + // Site settings + adminAreaAccess: '.admin_access .switch', + + vendorStoreUrl: '#dokan_general\\[custom_store_url\\]', // todo: for CSS selector [ ] needs escaped with double back slash \\ + vendorSetupWizardLogo: '#dokan_general\\[setup_wizard_logo_url\\]', + disableWelcomeWizard: '#dokan_general\\[disable_welcome_wizard\\]', + setupWizardMessageIframe: 'iframe', + setupWizardMessageHtmlBody: '#tinymce', + sellingProductTypes: (type: string) => `//label[@for='dokan_general[global_digital_mode][${type}]']`, + logShipStationApiRequest: '#dokan_general\\[enable_shipstation_logging\\]', + dataClear: '#dokan_general\\[data_clear_on_uninstall\\]', + confirmDataClear: '.swal2-confirm', + cancelDataClear: '.swal2-cancel', + + // Vendor Store settings + storeTermsAndConditions: '.seller_enable_terms_and_conditions .switch', + storeProductPerPage: '#dokan_general\\[store_products_per_page\\]', + enableTermsAndCondition: '.enable_tc_on_reg .switch', + enableSingSellerMode: '#dokan_general\\[enable_single_seller_mode\\]', + storCategory: (category: string) => `//label[@for='dokan_general[store_category_type][${category}]']`, + + // product page settings + showVendorInfo: '.show_vendor_info .switch', + enableMoreProductsTab: '.enabled_more_products_tab .switch', + + generalSaveChanges: '#submit', + }, + + // Selling + selling: { + // Commission + commissionType: '#dokan_selling\\[commission_type\\]', + adminCommission: '#dokan_selling\\[admin_percentage\\]', + shippingFeeRecipient: (feeReceiver: string) => `//label[@for='dokan_selling[shipping_fee_recipient][${feeReceiver}]']`, + productTaxFeeRecipient: (feeReceiver: string) => `//label[@for='dokan_selling[tax_fee_recipient][${feeReceiver}]']`, + shippingTaxFeeRecipient: (feeReceiver: string) => `//label[@for='dokan_selling[shipping_tax_fee_recipient][${feeReceiver}]']`, + processRefundViaAPI: '#dokan_selling\\[automatic_process_api_refund\\]', + + // Vendor Capability + enableSelling: '.new_seller_enable_selling .switch', + onePageProductCreate: '.one_step_product_create .switch', + disableProductPopup: '.disable_product_popup .switch', + orderStatusChange: '.order_status_change .switch', + selectAnyCategory: '.dokan_any_category_selection .switch', + newProductStatus: (status: string) => `//label[@for='dokan_selling[product_status][${status}]']`, + duplicateProduct: '.vendor_duplicate_product .switch', + editedProductStatus: '.edited_product_status .switch', + productMailNotification: '.product_add_mail .switch', + productCategorySelection: (category: string) => `//label[@for='dokan_selling[product_category_style][${category}]']`, + vendorsCanCreateTags: '.product_vendors_can_create_tags .switch', + orderDiscount: '//div[contains(text(),"Order Discount")]//label[@class="switch tips"]', + productDiscount: '//div[contains(text(),"Product Discount")]//label[@class="switch tips"]', + + hideCustomerInfo: '.hide_customer_info .switch', + vendorProductReviewStatusChange: '.seller_review_manage .switch', + guestProductEnquiry: '.enable_guest_user_enquiry .switch', + newVendorEnableAuction: '.new_seller_enable_auction .switch', + enableMinMaxQuantities: '.enable_min_max_quantity .switch', + enableMinMaxAmount: '.enable_min_max_amount .switch', + disableShipping: '.disable_shipping_tab .switch', + sellingOptionsSaveChanges: '#submit', + }, + + // Withdraw + withdraw: { + // Withdraw Options + withdrawMethodsPaypal: '//div[normalize-space(text())="PayPal"]', + withdrawMethodsBankTransfer: '//div[contains(text()," Bank Transfer")]//label', + withdrawMethodsWireCard: '//div[contains(text(),"Wirecard")]//label', + withdrawMethodsPaypalMarketplace: '#dokan_withdraw\\[withdraw_methods\\]\\[dokan-paypal-marketplace\\]', + withdrawMethodsDokanCustom: '//div[contains(text(),"Custom")]//label', + withdrawMethodsRazorpay: '#dokan_withdraw\\[withdraw_methods\\]\\[dokan_razorpay\\]', + withdrawMethodsMangoPay: '#dokan_withdraw\\[withdraw_methods\\]\\[dokan_mangopay\\]', + withdrawMethodsStripe: '//div[contains(text(),"Stripe")]//label', + withdrawMethodsStripeExpress: '#dokan_withdraw\\[withdraw_methods\\]\\[dokan_stripe_express\\]', + withdrawMethodsSkrill: '//div[contains(text(),"Skrill")]//label', + customMethodName: '#dokan_withdraw\\[withdraw_method_name\\]', + customMethodType: '#dokan_withdraw\\[withdraw_method_type\\]', + minimumWithdrawAmount: '#dokan_withdraw\\[withdraw_limit\\]', + orderStatusForWithdrawCompleted: '//div[contains(text(),"Completed")]//label', + orderStatusForWithdrawProcessing: '//div[contains(text(),"Processing")]//label', + orderStatusForWithdrawOnHold: '//div[contains(text(),"On-hold")]//label', + excludeCodPayments: '.exclude_cod_payment .switch', + withdrawThreshold: '#dokan_withdraw\\[withdraw_date_limit\\]', + hideWithdrawOption: '.hide_withdraw_option .switch', + // Disbursement Schedule Settings + withdrawDisbursementManual: '//div[contains(text(),"Manual Withdraw")]//label', + withdrawDisbursementAuto: '//div[contains(text(),"Schedule Disbursement")]//label', + disburseMentQuarterlySchedule: '//div[contains(text(),"Quarterly")]//label', + disburseMentMonthlySchedule: '//div[contains(text(),"Monthly")]//label', + disburseMentBiweeklySchedule: '//div[contains(text(),"Biweekly (Twice Per Month)")]//label', + disburseMentWeeklySchedule: '//div[contains(text(),"Weekly")]//label', + quarterlyScheduleMonth: 'select[name="dokan_withdraw[quarterly_schedule][month]"]', + quarterlyScheduleWeek: 'select[name="dokan_withdraw[quarterly_schedule][week]"]', + quarterlyScheduleDay: 'select[name="dokan_withdraw[quarterly_schedule][days]"]', + monthlyScheduleWeek: 'select[name="dokan_withdraw[monthly_schedule][week]"]', + monthlyScheduleDay: 'select[name="dokan_withdraw[monthly_schedule][days]"]', + biweeklyScheduleWeek: 'select[name="dokan_withdraw[biweekly_schedule][week]"]', + biweeklyScheduleDay: 'select[name="dokan_withdraw[biweekly_schedule][days]"]', + weeklyScheduleDay: 'select[name="dokan_withdraw[weekly_schedule]"]', + withdrawSaveChanges: '#submit', + }, + + // Reverse Withdraw Settings + reverseWithdraw: { + // Reverse Withdraw Settings + enableReverseWithdrawal: '.enabled.dokan-settings-field-type-switcher .switch', + enableReverseWithdrawalForThisGateway: '.payment_gateways.dokan-settings-field-type-multicheck .switch', + billingType: '#dokan_reverse_withdrawal\\[billing_type\\]', + monthlyBillingDate: '#dokan_reverse_withdrawal\\[monthly_billing_day\\]', + reverseBalanceThreshold: '#dokan_reverse_withdrawal\\[reverse_balance_threshold\\]', + gracePeriod: '#dokan_reverse_withdrawal\\[due_period\\]', + disableAddToCartButton: '//div[contains(text(),"Disable Add to Cart Button")]//label', + hideWithdrawMenu: '//div[contains(text(),"Hide Withdraw Menu")]//label', + MakeVendorStatusInactive: '//div[contains(text(),"Make Vendor Status Inactive")]//label', + displayNoticeDuringGracePeriod: '.display_notice.dokan-settings-field-type-switcher .switch', + sendAnnouncement: '.send_announcement.dokan-settings-field-type-switcher .switch', + reverseWithdrawSaveChanges: '#submit', + }, + + // Pages + page: { + // Page Settings + dashboard: '#dokan_pages\\[dashboard\\]', + myOrders: '#dokan_pages\\[my_orders\\]', + storeListing: '#dokan_pages\\[store_listing\\]', + termsAndConditions: '#dokan_pages\\[reg_tc_page\\]', + pageSaveChanges: '#submit', + }, + + // Appearance + appearance: { + // Appearance + showMapOnStorePage: '.store_map .switch', + mapApiSourceGoogleMaps: '//div[@class="map_api_source dokan-settings-field-type-radio"] //label[@for="dokan_appearance[map_api_source][google_maps]"]', + mapApiSourceMapBox: '//div[@class="map_api_source dokan-settings-field-type-radio"] //label[@for="dokan_appearance[map_api_source][mapbox]"]', + googleMapApiKey: '#dokan_appearance\\[gmap_api_key\\]', + mapBoxAccessToken: '#dokan_appearance\\[mapbox_access_token\\]', + googleReCAPTCHA: '.recaptcha_validation_label .dashicons', + googleReCAPTCHAValidationSiteKey: '//h3[contains(text()," Site Key")]//..//..//input', + googleReCAPTCHAValidationSecretKey: '//h3[contains(text(),"Secret Key")]//..//..//input]', + showContactFormOnStorePage: '.contact_seller .switch', + storeHeaderTemplate1: '.radio-image:nth-child(1) .button', + storeHeaderTemplate2: '.radio-image:nth-child(2) .button', + storeHeaderTemplate3: '.radio-image:nth-child(3) .button', + storeHeaderTemplate4: '.radio-image:nth-child(4) .button', + storeBannerWidth: '#dokan_appearance\\[store_banner_width\\]', + storeBannerHeight: '#dokan_appearance\\[store_banner_height\\]', + storeOpeningClosingTimeWidget: '.store_open_close .switch', + enableStoreSidebarFromTheme: '.enable_theme_store_sidebar .switch', + + hideVendorInfoEmailAddress: '//div[contains(text(),"Email Address")]//label[@class="switch tips"]', + hideVendorInfoPhoneNumber: '//div[contains(text(),"Phone Number")]//label[@class="switch tips"]', + hideVendorInfoStoreAddress: '//div[contains(text(),"Store Address")]//label[@class="switch tips"]', + appearanceSaveChanges: '#submit', + }, + + // Privacy Policy + privacyPolicy: { + // Privacy Policy + enablePrivacyPolicy: '.enable_privacy .switch', + privacyPage: '#dokan_privacy\\[privacy_page\\]', + privacyPolicyIframe: 'iframe', + privacyPolicyHtmlBody: '#tinymce', + privacyPolicySaveChanges: '#submit', + }, + + // Colors + colors: { + predefineColorPalette: '//h3[normalize-space()="Pre-defined Color Palette"]/../..', + customColorPalette: '//h3[normalize-space()="Custom Color Palette"]/../..', + + colorPalette: { + default: '#default', + petalParty: '//input[@id="petal party"]', + pinky: '#pinky', + ocean: '#ocean', + sweety: '#sweety', + summerSplash: '//input[@id="summer splash"]', + tree: '#tree', + }, + + customColors: { + // todo: need to update all locators + buttonTextColor: '.btn_text span', + buttonBackgroundColor: '.btn_primary span', + buttonBorderColor: '.btn_primary_border span', + buttonHoverTextColor: '.btn_hover_text span', + buttonHoverColor: '.btn_hover span', + buttonHoverBorderColor: '.btn_hover_border span', + dashboardNavigationText: '.dash_nav_text span', + dashboardNavigationActiveMenu: '.dash_active_link span', + dashboardNavigationBackground: '.dash_nav_bg span', + dashboardMenuBorder: '.dash_nav_border span', + }, + + colorsSaveChanges: '#submit', + }, + + // Live Search + liveSearch: { + liveSearchOptions: '#dokan_live_search_setting\\[live_search_option\\]', + liveSearchSaveChanges: '#submit', + }, + + // Store Support + storeSupport: { + // Store Support + displayOnOrderDetails: '.enabled_for_customer_order .switch', + displayOnSingleProductPage: '#dokan_store_support_setting\\[store_support_product_page\\]', + supportButtonLabel: '#dokan_store_support_setting\\[support_button_label\\]', + supportTicketEmailNotification: '.dokan_admin_email_notification .switch', + 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\\]', + }, + + // Verification Sms Gateways + verificationSmsGateway: { + // Verification Sms Gateways + senderName: '#dokan_verification_sms_gateways\\[sender_name\\]', + smsText: '#dokan_verification_sms_gateways\\[sms_text\\]', + smsSentSuccess: '#dokan_verification_sms_gateways\\[sms_sent_msg\\]', + smsSentError: '#dokan_verification_sms_gateways\\[sms_sent_error\\]', + activeGateway: '#dokan_verification_sms_gateways\\[active_gateway\\]', + // Nexmo + apiKey: '#dokan_verification_sms_gateways\\[nexmo_username\\]', + apiSecret: '#dokan_verification_sms_gateways\\[nexmo_pass\\]', + }, + + // Email Verification + emailVerification: { + // Email Verification + enableEmailVerification: '//label[@for="dokan_email_verification[enabled]"]//label[@class="switch tips"]', + registrationNotice: 'textarea#dokan_email_verification\\[registration_notice\\]', + loginNotice: 'textarea#dokan_email_verification\\[login_notice\\]', + emailVerificationSaveChanges: '#submit', + }, + + // Social API + socialApi: { + enableSocialLogin: '#dokan_social_api\\[enabled\\]', + }, + + // Shipping Status + shippingStatus: { + allowShipmentTracking: 'label[for="dokan_shipping_status_setting[enabled]"] label', + + // Shipping Providers + shippingProviders: { + australiaPost: '//input[@value="sp-australia-post"]/..', + canadaPost: '//input[@value="sp-canada-post"]/..', + cityLink: '//input[@value="sp-city-link"]/..', + }, + + customShippingStatusInput: 'input.regular-text', + customShippingStatusAdd: 'a.dokan-repetable-add-item-btn', + + shippingStatusSaveChanges: '#submit', + }, + + // Quote + quote: { + // Configuration + enableQuoteForOutOfStockProducts: 'label[for="dokan_quote_settings[enable_out_of_stock]"] label.switch', + enableAjaxAddToQuote: 'label[for="dokan_quote_settings[enable_ajax_add_to_quote]"] label.switch', + redirectToQuotePage: 'label[for="dokan_quote_settings[redirect_to_quote_page]"] label.switch', + + // Quote Attributes Settings + decreaseOfferedPrice: 'input#dokan_quote_settings\\[decrease_offered_price\\]', + enableConvertToOrder: 'label[for="dokan_quote_settings[enable_convert_to_order]"] label.switch', + enableQuoteConverterDisplay: 'label[for="dokan_quote_settings[enable_quote_converter_display]"] label.switch', + + quoteSaveChanges: '#submit', + }, + + // Live Chat + liveChat: { + enableLiveChat: '#dokan_live_chat\\[enable\\]', + chatProviderFacebookMessenger: '#dokan_live_chat\\[provider\\]\\[messenger\\]', + chatProviderTalkJs: '#dokan_live_chat\\[provider\\]\\[talkjs\\]', + chatProviderTawkTo: '#dokan_live_chat\\[provider\\]\\[tawkto\\]', + chatProviderWhatsApp: '#dokan_live_chat\\[provider\\]\\[whatsapp\\]', + + // Fb + messengerColor: '.button > span', + + // Talkjs + talkJsAppId: '#dokan_live_chat\\[app_id\\]', + talkJsAppSecret: '#dokan_live_chat\\[app_secret\\]', + + // Whatsapp + openingPattern: '#dokan_live_chat\\[wa_opening_method\\]', + preFilledMessage: '#dokan_live_chat\\[wa_pre_filled_message\\]', + + // Chat Button + chatButtonOnVendorPage: '#dokan_live_chat\\[chat_button_seller_page\\]', + chatButtonOnProductPage: '#dokan_live_chat\\[chat_button_product_page\\]', + liveChatSaveChanges: '#submit', + }, + + // Rma + rma: { + orderStatus: '#dokan_rma\\[rma_order_status\\]', + enableRefundRequests: '.rma_enable_refund_request .switch', + enableCouponRequests: '.rma_enable_coupon_request .switch', + reasonsForRmaSingle: (reason: string) => `//li[contains(text(),'${reason}')]//span[@class="dashicons dashicons-no-alt remove-item"]`, + reasonsForRma: '.remove-item', + reasonsForRmaInput: '.regular-text', + reasonsForRmaAdd: '.dokan-repetable-add-item-btn', + refundPolicyIframe: 'iframe', + refundPolicyHtmlBody: '#tinymce', + rmaSaveChanges: '#submit', + }, + + // Wholesale + wholesale: { + whoCanSeeWholesalePrice: (type: string) => `//div[@class='wholesale_price_display dokan-settings-field-type-radio'] //label[@for='dokan_wholesale[wholesale_price_display][${type}]']`, + showWholesalePriceOnShopArchive: '.display_price_in_shop_archieve .switch', + needApprovalForCustomer: '.need_approval_for_wholesale_customer .switch', + wholesaleSaveChanges: '#submit', + }, + + // Eu Compliance Fields + euCompliance: { + vendorExtraFieldsCompanyName: '//input[@value="dokan_company_name"]//..', + vendorExtraFieldsCompanyIdOrEuidNumber: '//input[@value="dokan_company_id_number"]//..', + vendorExtraFieldsVatOrTaxNumber: '//input[@value="dokan_vat_number"]//..', + vendorExtraFieldsNameOfBank: '//input[@value="dokan_bank_name"]//..', + vendorExtraFieldsBankIban: '//input[@value="dokan_bank_iban"]//..', + displayInVendorRegistrationForm: '.vendor_registration .switch', + customerExtraFieldsCompanyIdOrEuidNumber: '//input[@value="billing_dokan_company_id_number"]//..', + customerExtraFieldsVatOrTaxNumber: '//input[@value="billing_dokan_vat_number"]//..', + customerExtraFieldsNameOfBank: '//input[@value="billing_dokan_bank_name"]//..', + customerExtraFieldsBankIban: '//input[@value="billing_dokan_bank_iban"]//..', + enableGermanizedSupportForVendors: '.enabled_germanized .switch', + vendorsWillBeAbleToOverrideInvoiceNumber: '.override_invoice_number .switch', + euComplianceFieldsSaveChanges: '#submit', + }, + + // Delivery Time + deliveryTime: { + allowVendorSettings: '.allow_vendor_override_settings .switch', + homeDelivery: '//div[contains(text(), "Home Delivery")]//label[@class="switch tips"]', + storePickup: '//div[contains(text(), "Store Pickup")]//label[@class="switch tips"]', + deliveryDateLabel: '#dokan_delivery_time\\[delivery_date_label\\]', + deliveryBlockedBuffer: '#dokan_delivery_time\\[preorder_date\\]', + timeSlot: '#dokan_delivery_time\\[time_slot_minutes\\]', + orderPerSlot: '#dokan_delivery_time\\[order_per_slot\\]', + deliveryBoxInfo: '#dokan_delivery_time\\[delivery_box_info\\]', + requireDeliveryDateAndTime: '.selection_required .switch', + deliveryDay: (day: string) => `//h3[contains(text(), '${day}')]/../..//label[@class='switch tips']`, + openingTime: (day: string) => `//input[@id="dokan_delivery_time[delivery_day_${day.toLowerCase()}][opening_time]"]/..`, + openingTimeDatePicker: (time: string) => `(//li[contains(text(),'${time}')])[2]`, + closingTime: (day: string) => `//input[@id="dokan_delivery_time[delivery_day_${day.toLowerCase()}][closing_time]"]/..`, + closingTimeDatePicker: (time: string) => `(//li[contains(text(),'${time}')])[1]`, + fullDay: 'li.fullDayClock', + deliveryTimeSaveChanges: '#submit', + }, + + // Product Advertising + productAdvertising: { + noOfAvailableSlot: '#dokan_product_advertisement\\[total_available_slot\\]', + expireAfterDays: '#dokan_product_advertisement\\[expire_after_days\\]', + vendorCanPurchaseAdvertisement: '.per_product_enabled .switch', + advertisementCost: '#dokan_product_advertisement\\[cost\\]', + enableAdvertisementInSubscription: '.vendor_subscription_enabled .switch', + markAdvertisedProductAsFeatured: '.featured .switch', + displayAdvertisedProductOnTop: '.catalog_priority .switch', + outOfStockVisibility: '.hide_out_of_stock_items .switch', + productAdvertisingSaveChanges: '#submit', + }, + + // Geolocation + geolocation: { + locationMapPosition: (position: string) => `//label[@for='dokan_geolocation[show_locations_map][${position}]']`, + showMap: (type: string) => `//label[@for='dokan_geolocation[show_location_map_pages][${type}]']`, + showFiltersBeforeLocationMap: '.show_filters_before_locations_map .switch', + productLocationTab: '.show_product_location_in_wc_tab .switch', + radiusSearchUnit: (unit: string) => `//label[@for='dokan_geolocation[distance_unit][${unit}]']`, + radiusSearchMinimumDistance: '#dokan_geolocation\\[distance_min\\]', + radiusSearchMaximumDistance: '#dokan_geolocation\\[distance_max\\]', + mapZoomLevel: '#dokan_geolocation\\[map_zoom\\]', + defaultLocation: '.search-address', + mapResultFirst: '(//div[contains(@class,"pac-container")]//div[@class="pac-item"])[1]', + geolocationSaveChanges: '#submit', + }, + + // Product Report Abuse + productReportAbuse: { + reportedBy: '#dokan_report_abuse\\[reported_by_logged_in_users_only\\]', + reasonsForAbuseReportList: '.dokan-settings-repeatable-list li', + reasonsForAbuseReportSingle: (reason: string) => `//li[contains(text(),'${reason}')]//span[@class="dashicons dashicons-no-alt remove-item"]`, + reasonsForAbuseReportInput: '.regular-text', + reasonsForAbuseReportAdd: '.dokan-repetable-add-item-btn', + productReportAbuseSaveChanges: '#submit', + }, + + // Single Product Multi Vendor + spmv: { + enableSingleProductMultipleVendor: '.enable_pricing .switch', + sellItemButtonText: '#dokan_spmv\\[sell_item_btn\\]', + availableVendorDisplayAreaTitle: '#dokan_spmv\\[available_vendor_list_title\\]', + availableVendorSectionDisplayPosition: '#dokan_spmv\\[available_vendor_list_position\\]', + showSpmvProducts: '#dokan_spmv\\[show_order\\]', + singleProductMultiVendorSaveChanges: '#submit', + }, + + // Vendor Subscription + vendorSubscriptions: { + subscription: '#dokan_product_subscription\\[subscription_pack\\]', + enableProductSubscription: '.enable_pricing .switch', + enableSubscriptionInRegistrationForm: '.enable_subscription_pack_in_reg .switch', + enableEmailNotification: '.notify_by_email .switch', + noOfDays: '#dokan_product_subscription\\[no_of_days_before_mail\\]', + productStatus: '#dokan_product_subscription\\[product_status_after_end\\]', + cancellingEmailSubject: '#dokan_product_subscription\\[cancelling_email_subject\\]', + cancellingEmailBody: '#dokan_product_subscription\\[cancelling_email_body\\]', + alertEmailSubject: '#dokan_product_subscription\\[alert_email_subject\\]', + alertEmailBody: '#dokan_product_subscription\\[alert_email_body\\]', + vendorSubscriptionSaveChanges: '#submit', + }, + + // Vendor Analytics + vendorAnalytics: { + vendorAnalyticsSaveChanges: '#submit', + }, + + // Update Settings + dokanUpdateSuccessMessage: '#setting-message_updated > p > strong', + }, + + // License + license: { + licenseText: '.appsero-license-settings-wrapper h1', + + activateSection: { + licenseSection: '.appsero-license-settings.appsero-license-section', + licenseKeyInput: '.license-input-fields .license-input-key input', + activateLicense: '//button[contains(text(),"Activate License")]', + }, + errorNotice: '.notice-error.appsero-license-section', + }, + + // Dokan Setup Wizard + dokanSetupWizard: { + letsGo: '.button-primary', + notWrightNow: '//a[contains(text(),"Not right now")]', + + // 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: '#shipping_fee_recipient', + taxFeeRecipient: '#tax_fee_recipient', + mapApiSource: '#map_api_source', + googleMapApiKey: '#gmap_api_key', + mapBoxAccessToken: '#mapbox_access_token', + shareEssentialsOff: '.switch-label', + sellingProductTypes: '#dokan_digital_product', + // sellingProductTypes: "#select2-dokan_digital_product-container", + // Values: ".select2-results ul li", + continue: '//input[@value="Continue"]', + skipThisStep: '//a[contains(text(),"Skip this step")]', + + // Selling + newVendorEnableSelling: '//label[@for="new_seller_enable_selling" and @class="switch-label"]', + commissionType: '.commission_type.wc-enhanced-select', + commissionTypeValues: '.select2-results ul li', + adminCommission: '#admin_percentage', + orderStatusChange: '//label[@for="order_status_change" and @class="switch-label"]', + + // Withdraw + payPal: '//label[@for="withdraw_methods[paypal]" and @class="switch-label"]', + bankTransfer: '//label[@for="withdraw_methods[bank]" and @class="switch-label"]', + wireCard: '//label[@for="withdraw_methods[dokan-moip-connect]" and @class="switch-label"]', + stripe: '//label[@for="withdraw_methods[dokan-stripe-connect]" and @class="switch-label"]', + custom: '//label[@for="withdraw_methods[dokan_custom]" and @class="switch-label"]', + skrill: '//label[@for="withdraw_methods[skrill]" and @class="switch-label"]', + minimumWithdrawLimit: '#withdraw_limit', + orderStatusForWithdrawCompleted: '//label[@for="withdraw_order_status[wc-completed]"]', + orderStatusForWithdrawProcessing: '//label[@for="withdraw_order_status[wc-processing]"]', + + // Recommended + wooCommerceConversionTracking: '//label[@for="dokan_recommended_wc_conversion_tracking"]', + weMail: '//label[@for="dokan_recommended_wemail"]', + texty: '//label[@for="dokan_recommended_texty"]', + continueRecommended: '.button-primary', + + // Ready! + visitDokanDashboard: '//a[contains(text(),"Visit Dokan Dashboard")]', + moreSettings: '//a[contains(text(),"More Settings")]', + ReturnToTheWordPressDashboard: '.wc-return-to-dashboard', + }, + + // Dummy data + dummyData: { + runTheImporter: '.dokan-import-continue-btn', + importComplete: '//p[normalize-space()="Import complete!"]', + viewVendors: '//a[normalize-space()="View vendors"]', + viewProducts: '//a[normalize-space()="View products"]', + clearDummyData: '.cancel-btn.dokan-import-continue-btn', + confirmClearDummyData: '.swal2-actions .swal2-confirm', + }, + }, + + // Woocommerce + wooCommerce: { + // Woocommerce Menu + settingsMenu: '//li[contains(@class,"toplevel_page_woocommerce")]//a[text()="Settings"]', + + // Woocommerce Settings + settings: { + // Settings Menu + general: '//a[contains(@class,"nav-tab") and text()="General"]', + products: '//a[contains(@class,"nav-tab") and text()="Products"]', + tax: '//a[contains(@class,"nav-tab") and text()="Tax"]', + shipping: '//a[contains(@class,"nav-tab") and text()="Shipping"]', + payments: '//a[contains(@class,"nav-tab") and text()="Payments"]', + accounts: '//a[contains(text(),"Accounts & Privacy")]', + + // General + // Store Address + addressLine1: '#woocommerce_store_address', + addressLine2: '#woocommerce_store_address_2', + city: '#woocommerce_store_city', + countryOrState: '#select2-woocommerce_default_country-g1-container', + PostcodeOrZip: '#woocommerce_store_postcode', + // General Options + sellingLocation: '#select2-woocommerce_allowed_countries-container', + shippingLocation: '#select2-woocommerce_ship_to_countries-container', + defaultCustomerLocation: '#select2-woocommerce_default_customer_address-container', + enableTaxes: '#woocommerce_calc_taxes', + enableShipping: '#select2-woocommerce_ship_to_countries-container', + enableShippingValues: '.select2-results ul li', + enableCoupon: '#woocommerce_enable_coupons', + calculateCouponDiscountsSequentially: '#woocommerce_calc_discounts_sequentially', + // Currency Options + currency: '#select2-woocommerce_currency-container', + currencyPosition: '#select2-woocommerce_currency_pos-container', + currencyPositionValues: '.select2-results ul li', + thousandSeparator: '#woocommerce_price_thousand_sep', + decimalSeparator: '#woocommerce_price_decimal_sep', + numberOfDecimals: '#woocommerce_price_num_decimals', + generalSaveChanges: '.woocommerce-save-button', + + // Tax + // Tax Menus + taxOptions: '//ul[@class="subsubsub"]//a[contains(text(),"Tax options")]', + standardRates: '//ul[@class="subsubsub"]//a[contains(text(),"Standard rates")]', + reducedRateRates: '//ul[@class="subsubsub"]//a[contains(text(),"Reduced rate rates")]', + zeroRateRates: '//ul[@class="subsubsub"]//a[contains(text(),"Zero rate rates")]', + + // Tax Options + pricesEnteredWithTaxPricesInclusiveOfTax: '//label[contains(text(),"Yes, I will enter prices inclusive of tax")]//input[@name="woocommerce_prices_include_tax"]', + pricesEnteredWithTaxPricesExclusiveOfTax: '//label[contains(text(),"No, I will enter prices exclusive of tax")]//input[@name="woocommerce_prices_include_tax"]', + calculateTaxBasedOn: '#select2-woocommerce_tax_based_on-container', + shippingTaxClass: '#select2-woocommerce_shipping_tax_class-container', + rounding: '#woocommerce_tax_round_at_subtotal', + additionalTaxClasses: '#woocommerce_tax_classes', + displayPricesInTheShop: '#select2-woocommerce_tax_display_shop-container', + displayPricesDuringCartAndCheckout: '#select2-woocommerce_tax_display_cart-container', + priceDisplaySuffix: '#woocommerce_price_display_suffix', + displayTaxTotals: '#select2-woocommerce_tax_total_display-container', + taxSaveChanges: '.woocommerce-save-button', + + // Add Tax + taxTable: '.wc_tax_rates', + insertRow: '.plus', + taxRate: '.rate input', + taxRateSaveChanges: '.woocommerce-save-button', + + // Shipping + addShippingZone: '.page-title-action', + zoneName: '#zone_name', + // 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')]`, + deleteShippingZone: (shippingZone: string) => `//a[contains(text(), '${shippingZone}')]/..//div//a[contains(text(), 'Delete')]`, + addShippingMethods: '.wc-shipping-zone-add-method', + shippingMethod: '.wc-shipping-zone-method-selector select', + addShippingMethod: '#btn-ok', + shippingMethodCell: (shippingMethodName: string) => `//a[contains(text(),'${shippingMethodName}')]/..`, + editShippingMethod: (shippingMethodName: string) => `//a[contains(text(),'${shippingMethodName}')]/..//div//a[contains(text(), 'Edit')]`, + deleteShippingMethod: (shippingMethodName: string) => `//a[contains(text(),'${shippingMethodName}')]/..//div//a[contains(text(), 'Delete')]`, + + // Edit Shipping Methods + // Flat Rate + flatRateMethodTitle: '#woocommerce_flat_rate_title', + flatRateTaxStatus: '#woocommerce_flat_rate_tax_status', + flatRateCost: '#woocommerce_flat_rate_cost', + // Free Shipping + freeShippingTitle: '#woocommerce_free_shipping_title', + freeShippingRequires: '#woocommerce_free_shipping_requires', + freeShippingMinimumOrderAmount: '#woocommerce_free_shipping_min_amount', + freeShippingCouponsDiscounts: '#woocommerce_free_shipping_ignore_discounts', + // Local Pickup + localPickupTitle: '#woocommerce_local_pickup_title', + localPickupTaxStatus: '#woocommerce_local_pickup_tax_status', + localPickupCost: '#woocommerce_local_pickup_cost', + // Dokan Table Rate Shipping + dokanTableRateShippingMethodTitle: '#woocommerce_dokan_table_rate_shipping_title', + // Dokan Distance Rate Shipping + dokanDistanceRateShippingMethodTitle: '#woocommerce_dokan_distance_rate_shipping_title', + // Vendor Shipping + vendorShippingMethodTitle: '#woocommerce_dokan_vendor_shipping_title', + vendorShippingTaxStatus: '#woocommerce_dokan_vendor_shipping_tax_status', + + // Shipping Method save Changes + shippingMethodSaveChanges: '#btn-ok', + // Shipping Zone save Changes + shippingZoneSaveChanges: '.button.wc-shipping-zone-method-save', + + // Payments + // Enable Methods + enableDirectBankTransfer: '//a[contains(text(),"Direct bank transfer")]/../..//span', + enableCheckPayments: '//a[contains(text(),"Check payments")]/../..//span', + enableCashOnDelivery: '//a[contains(text(),"Cash on delivery")]/../..//span', + enableDokanWireCardConnect: '//a[contains(text(),"Dokan Wirecard Connect")]/../..//td[@class="status"]//span', + enableDokanPayPalAdaptivePayments: '//a[contains(text(),"Dokan PayPal Adaptive Payments")]/../..//td[@class="status"]//span', + enableDokanPayPalMarketplace: '//a[contains(text(),"Dokan PayPal Marketplace")]/../..//td[@class="status"]//span', + enableDokanStripeConnect: '//a[contains(text(),"Dokan Stripe Connect")]/../..//td[@class="status"]//span', + enableDokanMangoPay: '//a[contains(text(),"Dokan MangoPay")]/../..//td[@class="status"]//span', + enableDokanRazorpay: '//a[contains(text(),"Dokan Razorpay")]/../..//td[@class="status"]//span', + enableDokanStripeExpress: '//a[contains(text(),"Dokan Stripe Express")]/../..//td[@class="status"]//span', + // Setup or Manage Payment Methods + setupDirectBankTransfer: '//a[contains(text(),"Direct bank transfer")]/../..//td[@class="action"]//a', + setupCheckPayments: '//a[contains(text(),"Check payments")]/../..//td[@class="action"]//a', + setupCashOnDelivery: '//a[contains(text(),"Cash on delivery")]/../..//td[@class="action"]//a', + setupDokanWireCardConnect: '//a[contains(text(),"Dokan Wirecard Connect")]/../..//td[@class="action"]//a', + setupDokanPayPalAdaptivePayments: '//a[contains(text(),"Dokan PayPal Adaptive Payments")]/../..//td[@class="action"]//a', + setupDokanPayPalMarketplace: '//a[contains(text(),"Dokan PayPal Marketplace")]/../..//td[@class="action"]//a', + setupDokanStripeConnect: '//a[contains(text(),"Dokan Stripe Connect")]/../..//td[@class="action"]//a', + setupDokanMangoPay: '//a[contains(text(),"Dokan MangoPay")]/../..//td[@class="action"]//a', + setupDokanRazorpay: '//a[contains(text(),"Dokan Razorpay")]/../..//td[@class="action"]//a', + setupDokanStripeExpress: '//a[contains(text(),"Dokan Stripe Express")]/../..//td[@class="action"]//a', + paymentMethodsSaveChanges: '.woocommerce-save-button', + + // Stripe + stripe: { + // Stripe Connect + enableDisableStripe: '#woocommerce_dokan-stripe-connect_enabled', + title: '#woocommerce_dokan-stripe-connect_title', + description: '#woocommerce_dokan-stripe-connect_description', + nonConnectedSellers: '#woocommerce_dokan-stripe-connect_allow_non_connected_sellers', + displayNoticeToConnectSeller: '#woocommerce_dokan-stripe-connect_display_notice_to_non_connected_sellers', + displayNoticeInterval: '#woocommerce_dokan-stripe-connect_display_notice_interval', + threeDSecureAndSca: '#woocommerce_dokan-stripe-connect_enable_3d_secure', + sellerPaysTheProcessingFeeIn3DsMode: '#woocommerce_dokan-stripe-connect_seller_pays_the_processing_fee', + testMode: '#woocommerce_dokan-stripe-connect_testmode', + stripeCheckout: '#woocommerce_dokan-stripe-connect_stripe_checkout', + stripeCheckoutLocale: '#select2-woocommerce_dokan-stripe-connect_stripe_checkout_locale-container', + checkoutImage: '#woocommerce_dokan-stripe-connect_stripe_checkout_image', + checkoutButtonLabel: '#woocommerce_dokan-stripe-connect_stripe_checkout_label', + savedCards: '#woocommerce_dokan-stripe-connect_saved_cards', + // Test Credentials + testPublishableKey: '#woocommerce_dokan-stripe-connect_test_publishable_key', + testSecretKey: '#woocommerce_dokan-stripe-connect_test_secret_key', + testClientId: '#woocommerce_dokan-stripe-connect_test_client_id', + stripeSaveChanges: '.woocommerce-save-button', + }, + + // Paypal Marketplace + paypalMarketPlace: { + enableDisablePayPalMarketplace: '#woocommerce_dokan_paypal_marketplace_enabled', + title: '#woocommerce_dokan_paypal_marketplace_title', + description: '#woocommerce_dokan_paypal_marketplace_description', + payPalMerchantId: '#woocommerce_dokan_paypal_marketplace_partner_id', + // API Credentials + payPalSandbox: '#woocommerce_dokan_paypal_marketplace_test_mode', + sandboxClientId: '#woocommerce_dokan_paypal_marketplace_test_app_user', + sandBoxClientSecret: '#woocommerce_dokan_paypal_marketplace_test_app_pass', + payPalPartnerAttributionId: '#woocommerce_dokan_paypal_marketplace_bn_code', + disbursementMode: '#select2-woocommerce_dokan_paypal_marketplace_disbursement_mode-container', + disbursementModeValues: '.select2-results ul li', + paymentButtonType: '#select2-woocommerce_dokan_paypal_marketplace_button_type-container', + paymentButtonTypeValues: '.select2-results ul li', + allowUnbrandedCreditCard: '#woocommerce_dokan_paypal_marketplace_ucc_mode', + marketplaceLogo: '#woocommerce_dokan_paypal_marketplace_marketplace_logo', + displayNoticeToConnectSeller: '#woocommerce_dokan_paypal_marketplace_display_notice_on_vendor_dashboard', + sendAnnouncementToConnectSeller: '#woocommerce_dokan_paypal_marketplace_display_notice_to_non_connected_sellers', + sendAnnouncementInterval: '#woocommerce_dokan_paypal_marketplace_display_notice_interval', + paypalMarketPlaceSaveChanges: '.woocommerce-save-button', + }, + + // Dokan Mangopay + dokanMangoPay: { + enableDisableMangoPayPayment: '#woocommerce_dokan_mangopay_enabled', + title: '#woocommerce_dokan_mangopay_title', + description: '#woocommerce_dokan_mangopay_description', + // API Credentials + mangoPaySandbox: '#woocommerce_dokan_mangopay_sandbox_mode', + sandboxClientId: '#woocommerce_dokan_mangopay_sandbox_client_id', + sandBoxApiKey: '#woocommerce_dokan_mangopay_sandbox_api_key', + // Payment Options + chooseAvailableCreditCards: '//label[contains(text(),"Choose Available Credit Cards ")]/../..//input[@class="select2-search__field"]', + chooseAvailableCreditCardsValues: '.select2-results ul li', + chooseAvailableDirectPaymentServices: '//label[contains(text(),"Choose Available Direct Payment Services")]/../..//input[@class="select2-search__field"]', + chooseAvailableDirectPaymentServicesValues: '.select2-results ul li', + savedCards: '#woocommerce_dokan_mangopay_saved_cards', + threeDs2: '#woocommerce_dokan_mangopay_disabled_3DS2', + // Fund Transfers and Payouts + transferFunds: '#select2-woocommerce_dokan_mangopay_disburse_mode-container', + transferFundsValues: '.select2-results ul li', + payoutMode: '#woocommerce_dokan_mangopay_instant_payout', + // Types and Requirements of Vendors + typeOfVendors: '#select2-woocommerce_dokan_mangopay_default_vendor_status-container', + typeOfVendorsValues: '.select2-results ul li', + businessRequirement: '#select2-woocommerce_dokan_mangopay_default_business_type-container', + businessRequirementValues: '.select2-results ul li', + // Advanced Settings + displayNoticeToNonConnectedSellers: '#woocommerce_dokan_mangopay_notice_on_vendor_dashboard', + sendAnnouncementToNonConnectedSellers: '#woocommerce_dokan_mangopay_announcement_to_sellers', + announcementInterval: '#woocommerce_dokan_mangopay_notice_interval', + dokanMangopaySaveChanges: '.woocommerce-save-button', + }, + + dokanRazorpay: { + enableDisableDokanRazorpay: '#woocommerce_dokan_razorpay_enabled', + title: '#woocommerce_dokan_razorpay_title', + description: '#woocommerce_dokan_razorpay_description', + // API Credentials + razorpaySandbox: '#woocommerce_dokan_razorpay_test_mode', + testKeyId: '#woocommerce_dokan_razorpay_test_key_id', + testKeySecret: '#woocommerce_dokan_razorpay_test_key_secret', + disbursementMode: '#select2-woocommerce_dokan_razorpay_disbursement_mode-container', + disbursementModeValues: '.select2-results ul li', + sellerPaysTheProcessingFee: '#woocommerce_dokan_razorpay_seller_pays_the_processing_fee', + displayNoticeToConnectSeller: '#woocommerce_dokan_razorpay_display_notice_on_vendor_dashboard', + sendAnnouncementToConnectSeller: '#woocommerce_dokan_razorpay_display_notice_to_non_connected_sellers', + sendAnnouncementInterval: '#woocommerce_dokan_razorpay_display_notice_interval', + dokanRazorpaySaveChanges: '.woocommerce-save-button', + }, + + stripeExpress: { + // Stripe Express + enableOrDisableStripeExpress: '#woocommerce_dokan_stripe_express_enabled', + title: '#woocommerce_dokan_stripe_express_title', + description: '#woocommerce_dokan_stripe_express_description', + // API Credentials + testMode: '#woocommerce_dokan_stripe_express_testmode', + testPublishableKey: '#woocommerce_dokan_stripe_express_test_publishable_key', + testSecretKey: '#woocommerce_dokan_stripe_express_test_secret_key', + testWebhookSecret: '#woocommerce_dokan_stripe_express_test_webhook_key', + // Payment and Disbursement + choosePaymentMethods: '//select[@id="woocommerce_dokan_stripe_express_enabled_payment_methods"]/..//span[@class="select2-selection select2-selection--multiple"]', + choosePaymentMethodsValues: '.select2-results ul li', + takeProcessingFeesFromSellers: '#woocommerce_dokan_stripe_express_sellers_pay_processing_fee', + savedCards: '#woocommerce_dokan_stripe_express_saved_cards', + capturePaymentsManually: '#woocommerce_dokan_stripe_express_capture', + disburseFunds: '#select2-woocommerce_dokan_stripe_express_disburse_mode-container', + disbursementModeValues: '.select2-results ul li', + customerBankStatement: '#woocommerce_dokan_stripe_express_statement_descriptor', + // Payment Request Options (Apple Pay / Google Pay) + paymentRequestButtons: '#woocommerce_dokan_stripe_express_payment_request', + buttonType: '#woocommerce_dokan_stripe_express_payment_request_button_type', + buttonTheme: '#woocommerce_dokan_stripe_express_payment_request_button_theme', + buttonLocations: '//select[@id="woocommerce_dokan_stripe_express_payment_request_button_locations"]/..//span[@class="select2-selection select2-selection--multiple"]', + buttonLocationsValues: '.select2-results ul li', + buttonSize: '#woocommerce_dokan_stripe_express_payment_request_button_size', + // Advanced Settings + displayNoticeToNonConnectedSellers: '#woocommerce_dokan_stripe_express_notice_on_vendor_dashboard', + sendAnnouncementToNonConnectedSellers: '#woocommerce_dokan_stripe_express_announcement_to_sellers', + announcementInterval: '#woocommerce_dokan_stripe_express_notice_interval', + debugLog: '#woocommerce_dokan_stripe_express_debug', + stripeExpressSaveChanges: '.woocommerce-save-button', + }, + + // Accounts + automaticPasswordGeneration: '#woocommerce_registration_generate_password', + accountSaveChanges: '.woocommerce-save-button', + + // Update Success Message + updatedSuccessMessage: '#message.updated.inline p', + }, + }, + + // Products + products: { + // Products Menus + allProductsMenu: '//li[@id="menu-posts-product"]//a[text()="All Products"]', + addNewMenu: '//li[@id="menu-posts-product"]//a[text()="Add New"]', + categoriesMenu: '//li[@id="menu-posts-product"]//a[text()="Categories"]', + tagsMenu: '//li[@id="menu-posts-product"]//a[text()="Tags"]', + addOnsMenu: '//li[@id="menu-posts-product"]//a[text()="Add-ons"]', + attributesMenu: '//li[@id="menu-posts-product"]//a[text()="Attributes"]', + + // Product + product: { + // Add New Product + productName: '#title', + // Product Data + productType: '#product-type', + virtual: '#\\_virtual', + downloadable: '#\\_downloadable', + + // Add New Product Sub Menus + general: '.general_options a', + inventory: '.inventory_options a', + shipping: '.shipping_options a', + linkedProducts: '.linked_product_options a', + attributes: '.attribute_options a', + generateVariations: 'button.generate_variations', + variations: '.variations_options a', + advanced: '.advanced_options a', + auction: '.auction_tab_options a', + bookingAvailability: '.bookings_availability_options a', + bookingCosts: '.bookings_pricing_options a', + + // General + regularPrice: '#\\_regular_price', + salePrice: '#\\_sale_price', + salePriceDateFrom: '#\\_sale_price_dates_from', + salePriceDateTo: '#\\_sale_price_dates_to', + addDownloadableFiles: '.insert', + fileName: '.file_name > .input_text', + fileUrl: '.file_url > .input_text', + chooseFile: '.upload_file_button', + downloadLimit: '#\\_download_limit', + downloadExpiry: '#\\_download_expiry', + taxStatus: '#\\_tax_status', + taxClass: '#\\_tax_class', + enableWholesale: '#enable_wholesale', + wholesalePrice: '#wholesale_price', + minimumQuantityForWholesale: '#wholesale_quantity', + enableMinMaxRule: '#product_wise_activation', + minimumQuantityToOrder: '#min_quantity', + maximumQuantityToOrder: '#max_quantity', + minimumAmountToOrder: '#min_amount', + maximumAmountToOrder: '#max_amount', + orderRules: '#\\_donot_count', + categoryRules: '#ignore_from_cat', + + // External Product + productUrl: '#\\_product_url', + buttonText: '#\\_button_text', + + // Simple Subscription + subscriptionPrice: '#\\_subscription_price', + subscriptionPeriodInterval: '#\\_subscription_period_interval', + subscriptionPeriod: '#\\_subscription_period', + expireAfter: '#\\_subscription_length', + signUpFee: '#\\_subscription_sign_up_fee', + subscriptionTrialLength: '#\\_subscription_trial_length', + subscriptionTrialPeriod: '#\\_subscription_trial_period', + // Dokan Subscription + numberOfProducts: '#\\_no_of_product', + packValidity: '#\\_pack_validity', + advertisementSlot: '#\\_dokan_advertisement_slot_count', + expireAfterDays: '#\\_dokan_advertisement_validity', + dokanSubscriptionAdminCommissionType: '#\\_subscription_product_admin_commission_type', + dokanSubscriptionAdminCommissionSingle: '.show_if_product_pack #admin_commission', + dokanSubscriptionAdminCommissionCombined: '.subscription_additional_fee > .input-text', + allowedProductTypes: '.dokan_subscription_allowed_product_types .select2-search__field', + allowedCategoriesUncategorized: '._vendor_allowed_categories .select2-search__field', + restrictGalleryImageUpload: '#\\_enable_gallery_restriction', + recurringPayment: '#\\_enable_recurring_payment', + billingCycleRange: '#\\_dokan_subscription_period_interval', + billingCyclePeriodInterval: '#\\_dokan_subscription_period', + billingCycleStop: '#\\_dokan_subscription_length', + enableTrial: '#dokan_subscription_enable_trial', + trialPeriodRange: '.dokan-subscription-range', + trialPeriodPeriod: '//select[@name="dokan_subscription_trial_period_types"]', + // Auction + itemCondition: '#\\_auction_item_condition', + auctionType: '#\\_auction_type', + proxyBidding: '#\\_auction_proxy', + startPrice: '#\\_auction_start_price', + bidIncrement: '#\\_auction_bid_increment', + reservedPrice: '#\\_auction_reserved_price', + buyItNowPrice: '//label[contains(text(),"Buy it now price")]/..//input[@id="_regular_price"]', + auctionDatesFrom: '#\\_auction_dates_from', + auctionDatesTo: '#\\_auction_dates_to', + + // Booking + bookingDurationType: '#\\_wc_booking_duration_type', + bookingDuration: '#\\_wc_booking_duration', + bookingDurationMin: '#\\_wc_booking_min_duration', + bookingDurationMax: '#\\_wc_booking_max_duration', + bookingDurationUnit: '#\\_wc_booking_duration_unit', + calendarDisplayMode: '#\\_wc_booking_calendar_display_mode', + requiresConfirmation: '#\\_wc_booking_requires_confirmation', + canBeCancelled: '#\\_wc_booking_user_can_cancel', + // Booking Availability + MaxBookingsPerBlock: '#\\_wc_booking_qty', + MinimumBlockBookableMinDate: '#\\_wc_booking_min_date', + MinimumBlockBookableMinDateUnit: '#\\_wc_booking_min_date_unit', + MaximumBlockBookableMaxDate: '#\\_wc_booking_max_date', + MaximumBlockBookableMaxDateUnit: '#\\_wc_booking_max_date_unit', + RequireABufferPeriodOf: '#\\_wc_booking_buffer_period', + AdjacentBuffering: '#\\_wc_booking_apply_adjacent_buffer', + AllDatesAre: '#\\_wc_booking_default_date_availability', + CheckRulesAgainst: '#\\_wc_booking_check_availability_against', + RestrictSelectableDay: '#\\_wc_booking_has_restricted_days', + // Booking Costs + baseCost: '#\\_wc_booking_cost', + blockCost: '#\\_wc_booking_block_cost', + displayCost: '#\\_wc_display_cost', + + // Inventory + sku: '#\\_sku', + manageStock: '#\\_manage_stock', + stockQuantity: '#\\_stock', + allowBackOrders: '#\\_backorders', + lowStockThreshold: '#\\_low_stock_amount', + stockStatus: '#\\_stock_status', + soldIndividually: '#\\_sold_individually', + // Shipping + weightKg: '#\\_weight', + length: '#product_length', + width: '#product_width', + height: '#product_height', + shippingClass: '#product_shipping_class', + // Linked Products + upSells: '//label[contains(text(),"Grouped products")]/..//input[@class="select2-search__field"]', + crossSells: '//label[contains(text(),"Upsells")]/..//input[@class="select2-search__field"]', + // Attributes + addExistingAttribute: '#product_attributes .select2-selection__arrow', + addExistingAttributeInput: '.select2-search.select2-search--dropdown .select2-search__field', + addExistingAttributeValues: '.select2-results ul li', + customProductAttribute: '.attribute_taxonomy', + addAttribute: '.add_attribute', + attributeName: '.attribute_name .attribute_name', + attributeValues: '.woocommerce_attribute_data textarea', + selectAll: '.select_all_attributes', + selectNone: '.minus', + addNewAttribute: '.button.add_new_attribute', + visibleOnTheProductPage: '//input[contains(@name, "attribute_visibility")]', + usedForVariations: '//input[contains(@name, "attribute_variation")]', + saveAttributes: '.save_attributes', + // Variations + productVariations: '.woocommerce_variation', + addVariations: '#field_to_edit', + go: '.bulk_edit', // invokes default js alert + // Advanced + purchaseNote: '#\\_purchase_note', + menuOrder: '#menu_order', + enableReviews: '#comment_status', + adminCommissionType: '#\\_per_product_admin_commission_type', + adminCommissionSingle: '.show_if_simple #admin_commission', + adminCommissionCombined: '.additional_fee > .input-text', + // Vendor + // storeName: '#dokan_product_author_override', + // storeName: 'div#sellerdiv span.select2-selection__arrow', // todo: dokansellerdiv on git action nd sellerdiv on local why + storeName: '//div[contains(@id, "sellerdiv")]//span[@class="select2-selection__arrow"]', + // storeNameOptions: '#dokan_product_author_override option', + storeNameInput: '.select2-search.select2-search--dropdown .select2-search__field', + storeNameOption: (text: string) => `//select[@id='dokan_product_author_override']//option[contains(text(),'${text}')]`, // Select Option by text + + // Category + category: (categoryName: string) => `//label[contains(text(), ' ${categoryName}')]/input`, + // Tags + tagInput: '#new-tag-product_tag', + addTag: '.tagadd', + // Status + editStatus: '.edit-post-status.hide-if-no-js', + status: '#post-status-select #post_status', + // Publish + saveDraft: '#save-post', + preview: '#post-preview', + publish: '#publishing-action #publish', + updatedSuccessMessage: '.updated.notice.notice-success p', + }, + + // Categories + category: { + name: '#tag-name', + slug: '#tag-slug', + parentCategory: '#parent', + description: '#tag-description', + commissionType: '#per_category_admin_commission_type', + adminCommissionFromThisCategory: '.wc_input_price:nth-child(2)', + displayType: '#display_type', + uploadOrAddImage: '.upload_image_button', + addNewCategory: '#submit', + categoryCell: (categoryName: string) => `//td[contains(text(), '${categoryName.toLowerCase()}')]/..`, + }, + + // Attributes + attribute: { + name: '#attribute_label', + slug: '#attribute_name', + enableArchives: '#attribute_public', + defaultSortOrder: '#attribute_orderby', + addAttribute: '#submit', + attributeCell: (attributeName: string) => `//td[contains(text(), '${attributeName.toLowerCase()}')]/..`, + configureTerms: (attributeName: string) => `//td[contains(text(), '${attributeName.toLowerCase()}')]/..//a[normalize-space()="Configure terms"]`, + // Terms + attributeTerm: '#tag-name', + attributeTermSlug: '#tag-slug', + description: '#tag-description', + addAttributeTerm: '#submit', + attributeTermCell: (attributeTerm: string) => `//td[contains(text(), '${attributeTerm.toLowerCase()}')]/..`, + }, + }, + + // Bookings + bookings: { + // Menus + allBooking: '//li[@id="menu-posts-wc_booking"]//a[contains(text(),"All Bookings")]', + resources: '//li[@id="menu-posts-wc_booking"]//a[contains(text(),"Resources")]', + addBooking: '//li[@id="menu-posts-wc_booking"]//a[contains(text(),"Add Booking")]', + calendar: '//li[@id="menu-posts-wc_booking"]//a[contains(text(),"Calendar")]', + sendNotification: '//li[@id="menu-posts-wc_booking"]//a[contains(text(),"Send Notification")]', + settings: '//li[@id="menu-posts-wc_booking"]//a[contains(text(),"Settings")]', + }, + + // Marketing + marketing: { + // Menus + coupons: '//li[@id="toplevel_page_woocommerce-marketing"]//a[contains(text(),"Coupons")]', + + // Coupon + + addCoupon: '//a[contains(text(),"Add coupon")]', + + addNewCoupon: { + // Coupon Sub Menus + general: 'a[href="#general_coupon_data"]', + vendorLimits: 'a[href="#vendor_usage_limit_coupon_data"]', + usageRestriction: 'a[href="#usage_restriction_coupon_data"]', + usageLimits: 'a[href="#usage_limit_coupon_data"]', + + couponCode: '#title', + couponDescription: '#woocommerce-coupon-description', + + // General + discountType: '#discount_type', // percent, fixed_cart, fixed_product, sign_up_fee, sign_up_fee_percent, recurring_fee, recurring_percent, booking_person + couponAmount: '#coupon_amount', + allowFreeShipping: '#free_shipping', + couponExpiryDate: '#expiry_date', + + // Vendor Limits + enableForAllVendors: '#admin_coupons_enabled_for_vendor', + couponPriceDeduct: '#coupon_commissions_type', + vendors: '.dokan-admin-coupons-include-vendors .select2-search__field', + products: '.dokan-coupons-include-product-search-group .select2-search__field', + excludeProducts: '//label[contains(text(),"Exclude products")]/..//input[@class="select2-search__field"]', + showOnStores: '#admin_coupons_show_on_stores', + notifyVendors: '#admin_coupons_send_notify_to_vendors', + + // Usage Restriction + minimumSpend: '#minimum_amount', + maximumSpend: '#maximum_amount', + individualUseOnly: '#individual_use', + excludeSaleItems: '#exclude_sale_items', + productCategories: '//label[contains(text(),"Product categories")]/..//input[@class="select2-search__field"]', + excludeCategories: '//label[contains(text(),"Exclude categories")]/..//input[@class="select2-search__field"]', + allowedEmails: '#customer_email', + + // Usage Limits + usageLimitPerCoupon: '//input[@id="usage_limit"]', + usageLimitPerUser: '#usage_limit_per_user', + + publish: '#publish', + publishSuccessMessage: '#message.notice-success p', + publishSuccess: '//p[normalize-space()="Coupon updated."]', + }, + }, + + // Appearance + appearance: { + // Menus + themes: '//li[@id="menu-appearance"]//a[contains(text(),"Themes")]', + addNew: '//div[@class="wrap"]//a[contains(text(),"Add New")]', + searchTheme: '#wp-filter-search-input', + }, + + // Plugins + plugins: { + // Plugins Menus + installedPlugins: '//a[text()="Installed Plugins"]', + plugin: (pluginSlug: string) => `//tr[@data-slug='${pluginSlug}']`, + + // Add New Plugins + addNew: '.page-title-action', + searchPlugin: '#search-plugins', + uploadPlugin: '.upload', + chooseFile: '#pluginzip', + installNow: '#install-plugin-submit', + activatePlugin: '.button.button-primary', + activateCustomPlugin: (plugin: string) => `//strong[normalize-space()="${plugin}"]/..//div//span[@class="activate"]`, + }, + + // Users + users: { + // Users Menu + menus: { + allUsers: '//li[@id="menu-users"]//a[contains(text(),"All Users")]', + addNew: '//li[@id="menu-users"]//a[contains(text(),"Add New")]', + profile: '//li[@id="menu-users"]//a[contains(text(),"Profile")]', + }, + + // All Users + allUsersAddNew: '.page-title-action', + editUser: '.visible > .edit > a', + + // Add New User + newUser: { + username: '#user_login', + email: '#email', + firstName: '#first_name', + lastName: '#last_name', + website: '#url', + language: '#locale', + password: '#pass1', + sendUserNotification: '#send_user_notification', + role: '#role', + addNewUser: '#createusersub', + }, + + // Edit User info + userInfo: { + // Personal Info + role: '#role', + firstName: '#first_name', + lastName: '#last_name', + nickname: '#nickname', + displayNamePubliclyAs: '#display_name', + + // Contact Info + email: '#email', + website: '#url', + + // About the User + biographicalInfo: '#description', + + // Account Management + setNewPassword: '.wp-generate-pw', + newPassword: '#pass1', + + // Customer Billing Address + billingAddress: { + firstName: '#billing_first_name', + lastName: '#billing_last_name', + company: '#billing_company', + address1: '#billing_address_1', + address2: '#billing_address_2', + city: '#billing_city', + postcode: '#billing_postcode', + // country: '#select2-billing_country-container', + // countryInput: '.select2-results ul li', + country: '//select[@id="billing_country"]/..//span[@class="select2-selection__arrow"]', + countryInput: '.select2-search.select2-search--dropdown .select2-search__field', + state: '//select[@id="billing_state"]/..//span[@class="select2-selection__arrow"]', + stateInput: '.select2-search.select2-search--dropdown .select2-search__field', + phone: '#billing_phone', + email: '#billing_email', + companyIdOrEuidNumber: '#billing_dokan_company_id_number', + vatOrTaxNumber: '#billing_dokan_vat_number', + bank: '#billing_dokan_bank_name', + bankIban: '#billing_dokan_bank_iban', + }, + + // Customer Shipping Address + shippingAddress: { + copyFromBillingAddress: '#copy_billing', + firstName: '#shipping_first_name', + lastName: '#shipping_last_name', + company: '#shipping_company', + address1: '#shipping_address_1', + address2: '#shipping_address_2', + city: '#shipping_city', + postcode: '#shipping_postcode', + country: '//select[@id="shipping_country"]/..//span[@class="select2-selection__arrow"]', + countryInput: '.select2-search.select2-search--dropdown .select2-search__field', + state: '//select[@id="shipping_state"]/..//span[@class="select2-selection__arrow"]', + stateInput: '.select2-search.select2-search--dropdown .select2-search__field', + phone: '#shipping_phone', + }, + + // Dokan Options + dokanOptions: { + banner: '.dokan-banner .button-area a', + storeName: '//input[@name="dokan_store_name"]', + storeUrl: '#seller-url', + address1: '//input[@name="dokan_store_address[street_1]"]', + address2: '//input[@name="dokan_store_address[street_2]"]', + city: '//input[@name="dokan_store_address[city]"]', + postcode: '//input[@name="dokan_store_address[zip]"]', + // country: '#select2-country-container', + // countryValues: '.select2-results ul li', + // state: '##select2-state-container', + // stateValues: '.select2-results ul li', + country: '(//span[@class="select2-selection__arrow"])[1]', + countryInput: '.select2-search.select2-search--dropdown .select2-search__field', + state: '(//span[@class="select2-selection__arrow"])[2]', + stateInput: '.select2-search.select2-search--dropdown .select2-search__field', + + phone: '//input[@name="dokan_store_phone"]', + companyName: '//input[@name="dokan_company_name"]', + companyIdOrEuidNumber: '//input[@name="dokan_company_id_number"]', + vatOrTaxNumber: '//input[@name="dokan_vat_number"]', + bank: '//input[@name="dokan_bank_name"]', + bankIban: '//input[@name="dokan_bank_iban"]', + facebook: '//input[@name="dokan_social[fb]"]', + twitter: '//input[@name="dokan_social[twitter]"]', + pinterest: '//input[@name="dokan_social[pinterest]"]', + linkedin: '//input[@name="dokan_social[linkedin]"]', + youtube: '//input[@name="dokan_social[youtube]"]', + instagram: '//input[@name="dokan_social[instagram]"]', + flickr: '//input[@name="dokan_social[flickr]"]', + selling: '#dokan_enable_selling', + publishing: '#dokan_publish', + adminCommissionType: '#dokan_admin_percentage_type', + adminCommission: '#admin-commission', + featuredVendor: '#dokan_feature', + withdrawThreshold: '#withdraw_date_limit', + auction: '#dokan_disable_auction', + // Dokan Subscription + assignSubscriptionPack: '.dps_assign_pack select', + }, + }, + + // Update User + updateUser: 'input#submit', + updateSuccessMessage: '//strong[normalize-space()="User updated."]', + }, + + // Tools + tools: { + // Menus + import: '//li[@id="menu-tools"]//a[text()="Import"]', + export: '//li[@id="menu-tools"]//a[text()="Export"]', + }, + + // Settings + settings: { + // Settings Menus + general: '//li[@id="menu-settings"]//a[text()="General"]', + writing: '//li[@id="menu-settings"]//a[text()="Writing"]', + reading: '//li[@id="menu-settings"]//a[text()="Reading"]', + discussion: '//li[@id="menu-settings"]//a[text()="Discussion"]', + media: '//li[@id="menu-settings"]//a[text()="Media"]', + permalinks: '//li[@id="menu-settings"]//a[text()="Permalinks"]', + privacy: '//li[@id="menu-settings"]//a[text()="Privacy"]', + + // General Settings + siteTitle: '#blogname', + tagline: '#blogdescription', + wordPressAddressUrl: '#siteurl', + siteAddressUrl: '#home', + administrationEmailAddress: '#new_admin_email', + membership: '#users_can_register', + newUserDefaultRole: '#default_role', + siteLanguage: '#WPLANG', + timezone: '#timezone_string', + customDateFormat: '//input[@id="date_format_custom_radio" and @name="date_format"]', + timeFormat: '//input[@id="time_format_custom_radio" and @name="time_format"]', + weekStartsOn: '#start_of_week', + generalSaveChanges: '#submit', + + // Permalinks Settings + // Common Settings + numeric: '//input[@value="/archives/%post_id%"]/..', + // postName: "//input[@value='/%postname%/' and @type='radio']/..", + postName: '#permalink-input-post-name', + // Optional Settings + shopBaseWithCategory: '//input[@value="/shop/%product_cat%/"]', + customBase: '#woocommerce_custom_selection', + customBaseInput: '#woocommerce_permalink_structure', + permalinkSaveChanges: '#submit', + + // Update Settings + updatedSuccessMessage: '#setting-error-settings_updated strong', + }, + }, + + // Vendor + + vendor: { + // Vendor Registration + vRegistration: { + // Vendor Registration + regEmail: 'input#reg_email', + regPassword: 'input#reg_password', + regVendor: '//input[@value="seller"]', + firstName: 'input#first-name', + lastName: 'input#last-name', + shopName: 'input#company-name', + shopUrl: 'input#seller-url', + street1: 'input#dokan_address\\[street_1\\]', + street2: 'input#dokan_address\\[street_2\\]', + city: 'input#dokan_address\\[city\\]', + zipCode: 'input#dokan_address\\[zip\\]', + country: 'select#dokan_address_country', + state: 'select#dokan_address_state', + companyName: 'input#dokan-company-name', + companyId: 'input#dokan-company-id-number', + vatNumber: 'input#dokan-vat-number', + bankName: 'input#dokan-bank-name', + bankIban: 'input#dokan-bank-iban', + phone: 'input#shop-phone', + subscriptionPack: '#dokan-subscription-pack', + subscriptionPackOptions: '#dokan-subscription-pack option', + // Register Button + register: 'button.woocommerce-Button', + }, + + // Vendor Setup Wizard + vSetup: { + // Intro + letsGo: '.lets-go-btn', + notRightNow: '.not-right-now-btn', + + // Store Setup + street1: '#address\\[street_1\\]', + street2: '#address\\[street_2\\]', + city: '#address\\[city\\]', + zipCode: '#address\\[zip\\]', + country: '#select2-addresscountry-container', + countryInput: '//input[@class="select2-search__field" and @aria-owns="select2-addresscountry-results"]', + state: '#select2-calc_shipping_state-container', + // state: '//span[@id="select2-calc_shipping_state-container"]/..//span[@class="select2-selection__arrow"]', + stateInput: '//input[@class="select2-search__field" and @aria-owns="select2-calc_shipping_state-results"]', + // state: '#calc_shipping_state', + storeCategories: '//select[contains(@id,"dokan_store_categories")]/..//span[@class="select2-selection select2-selection--multiple"]', + storeCategoriesInput: '//input[@class="select2-search__field" and @aria-owns="select2-dokan_store_categories-results"]', + highlightedResult: '.select2-results__option.select2-results__option--highlighted', + selectedStoreCategories: '//select[contains(@id,"dokan_store_categories")]/..//li[@class="select2-selection__choice"]', + map: 'input#dokan-map-add', + mapResultFirst: '(//ul//li[@class="ui-menu-item"]//div[@class="ui-menu-item-wrapper"])[1]', + mapResultByName: (location: string) => `//li[@class="ui-menu-item"]//div[contains(text(), "${location}")],`, // New York, NY, USA + email: '//input[@id="show_email"]/..//label', + continueStoreSetup: '.store-step-continue', + skipTheStepStoreSetup: '.store-step-skip-btn', + + // Payment Setup + // Paypal + paypal: '//input[@name="settings[paypal][email]"]', + // Bank + bankAccountName: '#ac_name', + bankAccountType: '#ac_type', + bankRoutingNumber: '//input[@name="settings[bank][routing_number]"]', + bankAccountNumber: '//input[@name="settings[bank][ac_number]"]', + bankName: '//input[@name="settings[bank][bank_name]"]', + bankAddress: '//textarea[@name="settings[bank][bank_addr]"]', + bankIban: '//input[@name="settings[bank][iban]"]', + bankSwiftCode: '//input[@name="settings[bank][swift]"]', + declaration: '#declaration', + // Custom Payment Method + customPayment: '//input[@name="settings[dokan_custom][value]"]', + // Paypal Marketplace + paypalMarketplace: '#vendor_paypal_email_address', + paypalMarketplaceSigUp: '.vendor_paypal_connect', + // Stripe + ConnectWithStripe: '.dokan-stripe-connect-link', + // Skrill + skrill: '//input[@name="settings[skrill][email]"]', + // Continue from Payment Setup + continuePaymentSetup: '.payment-continue-btn', + skipTheStepPaymentSetup: '.payment-step-skip-btn', + + // Last Step + goToStoreDashboard: '.wc-setup-actions.step .button', + returnToMarketplace: '.wc-return-to-dashboard', + }, + + // Vendor Dashboard + vDashboard: { + // Dashboard Menus + menus: { + dashboard: '.dashboard a', + products: '.products a', + orders: '.orders a', + userSubscription: '.user-subscription a', + coupons: '.coupons a', + reports: '.reports a', + deliveryTime: '.delivery-time-dashboard a', + reviews: '.reviews a', + withdraw: '.withdraw a', + badges: '.seller-badge a', + returnRequest: '.return-request a', + staff: '.staffs a', + followers: '.followers a', + booking: '.booking a', + analytics: '.analytics a', + announcements: '.announcement a', + tools: '.tools a', + auction: '.auction a', + support: '.support a', + settings: '.settings a', + visitStore: '//i[@class="fas fa-external-link-alt"]/..', + editAccount: '.fa-user', + }, + + // profile Progress + profileProgress: { + profileProgressDiv: '.dokan-profile-completeness', + dokanProgressBar: '.dokan-progress', + dokanProgressBarText: '.dokan-progress-bar', + nextStep: '.dokan-alert.dokan-alert-info.dokan-panel-alert', + }, + + // At a Glance + atAGlance: { + atAGlanceDiv: '.dashboard-widget.big-counter', + + netSalesTitle: '//div[normalize-space()="Net Sales"]', + earningTitle: '//div[normalize-space()="Earning"]', + pageviewTitle: '//div[normalize-space()="Pageview"]', + orderTitle: '//div[normalize-space()="Order"]', + + salesValue: '//div[@class="title" and contains(text(), "Net Sales")]/..//div[@class="count"]', + earningValue: '//div[@class="title" and contains(text(), "Earning")]/..//div[@class="count"]', + pageViewValue: '//div[@class="title" and contains(text(), "Pageview")]/..//div[@class="count"]', + orderValue: '//div[@class="title" and contains(text(), "Order")]/..//div[@class="count"]', + }, + + // sells graph + graph: { + graphDiv: '.dashboard-widget.sells-graph', + widgetTitle: '.sells-graph .widget-title', + chart: '.chart-container', + }, + + // orders + orders: { + ordersDiv: '.dashboard-widget.orders', + widgetTitle: '.orders .widget-title', + totalTitle: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Total"]', + completedTitle: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Completed"]', + pendingTitle: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Pending"]', + processingTitle: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Processing"]', + cancelledTitle: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Cancelled"]', + refundedTitle: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Refunded"]', + onholdTitle: '//div[@class="dashboard-widget orders"]//span[normalize-space()="On hold"]', + + totalValue: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Total"]/..//span[@class="count"]', + completedValue: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Completed"]/..//span[@class="count"]', + pendingValue: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Pending"]/..//span[@class="count"]', + processingValue: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Processing"]/..//span[@class="count"]', + cancelledValue: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Cancelled"]/..//span[@class="count"]', + refundedValue: '//div[@class="dashboard-widget orders"]//span[normalize-space()="Refunded"]/..//span[@class="count"]', + onholdValue: '//div[@class="dashboard-widget orders"]//span[normalize-space()="On hold"]/..//span[@class="count"]', + + pieChart: '#order-stats', + }, + + // reviews + reviews: { + reviewsDiv: '.dashboard-widget.reviews', + widgetTitle: '.reviews .widget-title', + allTitle: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="All"]', + pendingTitle: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="Pending"]', + spamTitle: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="Spam"]', + trashTitle: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="Trash"]', + + allValue: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="All"]/..//span[@class="count"]', + pendingValue: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="Pending"]/..//span[@class="count"]', + spamValue: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="Spam"]/..//span[@class="count"]', + trashValue: '//div[@class="dashboard-widget reviews"]//span[normalize-space()="Trash"]/..//span[@class="count"]', + }, + + // products + products: { + productsDiv: '.dashboard-widget.products', + addNewProduct: '//a[normalize-space()="+ Add new product"]', + widgetTitle: '.products .widget-title', + totalTitle: '//div[@class="dashboard-widget products"]//span[normalize-space()="Total"]', + liveTitle: '//div[@class="dashboard-widget products"]//span[normalize-space()="Live"]', + offlineTitle: '//div[@class="dashboard-widget products"]//span[normalize-space()="Offline"]', + pendingReviewTitle: '//div[@class="dashboard-widget products"]//span[normalize-space()="Pending Review"]', + + totalValue: '//div[@class="dashboard-widget products"]//span[normalize-space()="Total"]/..//span[@class="count"]', + liveValue: '//div[@class="dashboard-widget products"]//span[normalize-space()="Live"]/..//span[@class="count"]', + offlineValue: '//div[@class="dashboard-widget products"]//span[normalize-space()="Offline"]/..//span[@class="count"]', + pendingReviewValue: '//div[@class="dashboard-widget products"]//span[normalize-space()="Pending Review"]/..//span[@class="count"]', + }, + + // announcement + announcement: { + announcementDiv: '.dashboard-widget.dokan-announcement-widget', + widgetTitle: '.dokan-announcement-widget .widget-title', + seeAll: '//a[normalize-space()="See All"]', + + // announcementContent: '.dokan-dashboard-announce-content', + // announcementDate: '.dokan-dashboard-announce-date', + }, + }, + + // Products + product: { + // Menus + menus: { + all: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"All")]', + online: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"Online")]', + draft: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"Draft")]', + pendingReview: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"Pending Review")]', + inStock: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"In stock")]', + }, + + // Import Export Product + importExport: { + import: '//span[@class="dokan-add-product-link"]//a[contains(text(),"Import")]', + export: '//span[@class="dokan-add-product-link"]//a[contains(text(),"Export")]', + }, + + // Filter + filters: { + filterByDate: 'select#filter-by-date', + filterByCategory: 'select#product_cat', + filterByType: 'select#filter-by-type', // simple, variable, external, grouped, subscription, variable-subscription + filterByOther: '//select[@name="filter_by_other"]', // featured, top_rated, best_selling + filter: '//button[normalize-space()="Filter"]', + reset: '//a[normalize-space()="Reset"]', + }, + + // Search product + search: { + searchInput: 'input[placeholder="Search Products"]', + searchBtn: 'button[name="product_listing_search"]', + }, + + // Bulk Action + bulkActions: { + selectAll: '#cb-select-all', + selectAction: '#bulk-product-action-selector', // edit, delete, publish + applyAction: '#bulk-product-action', + }, + + // Table + table: { + productTable: '#dokan-product-list-table', + imageColumn: '//th[normalize-space()="Image"]', + nameColumn: '//th[normalize-space()="Name"]', + statusColumn: '//th[normalize-space()="Status"]', + productAdvertisementColumn: '//th[@class="product-advertisement-th"]', + skuColumn: '//th[normalize-space()="SKU"]', + stockColumn: '//th[normalize-space()="Stock"]', + priceColumn: '//th[normalize-space()="Price"]', + typeColumn: '//th[normalize-space()="Type"]', + viewsColumn: '//th[normalize-space()="Views"]', + dateColumn: '//th[normalize-space()="Date"]', + }, + + // Product Sub Options + numberOfRowsFound: '#dokan-product-list-table tbody tr', + productCell: (productName: string) => `//a[contains(text(),'${productName}')]/../..`, + productLink: (productName: string) => `//a[contains(text(),'${productName}')]`, + editProduct: (productName: string) => `//a[contains(text(),'${productName}')]/../..//span[@class="edit"]//a`, + buyAdvertisement: (productName: string) => `//a[contains(text(),'${productName}')]/../../..//td[@class="product-advertisement-td"]//span`, + advertisementStatus: (productName: string) => `//a[contains(text(),'${productName}')]/../../..//td[@class="product-advertisement-td"]//i[contains(@class,'fa fa-circle')]`, + permanentlyDelete: (productName: string) => `//a[contains(text(),'${productName}')]/../..//span[@class="delete"]//a`, + view: (productName: string) => `//a[contains(text(),'${productName}')]/../..//span[@class="view"]//a`, + quickEdit: (productName: string) => `//a[contains(text(),'${productName}')]/../..//span[@class="item-inline-edit"]//a`, + duplicate: (productName: string) => `//a[contains(text(),'${productName}')]/../..//span[@class="duplicate"]//a`, + + // Create Product + create: { + closeCreateProductPopup: 'a.iziModal-button-close', // todo: need to update, everywhere + addNewProduct: 'span.dokan-add-product-link .dokan-btn.dokan-btn-theme:first-child', + productPopup: '#dokan-add-product-popup', + productName: '//input[@name="post_title"]', + productImage: '.dokan-feat-image-btn', + productAddGalleryImage: '.fa-plus', + productPrice: '#_regular_price', + productDiscountedPrice: '#_sale_price', + productDiscountedPriceSchedule: '.sale_schedule', + productScheduleFrom: '.dokan-start-date', + productScheduleTo: '.dokan-end-date', + productScheduleCancel: '.cancel_sale_schedule.dokan-hide', + productTags: '.select2-search__field', + productDescription: 'textarea[placeholder="Enter some short description about this product..."]', + createProduct: '#dokan-create-new-product-btn', + createAndNewProduct: '#dokan-create-and-add-new-product-btn', + }, + + // category + category: { + productCategoryModalOnProductPopup: '#dokan-add-new-product-form #dokan-category-open-modal', + productCategoryModal: '.dokan-select-product-category.dokan-category-open-modal', + productCategory: '#select2-product_cat-container', + productCategorySearchInput: '#dokan-single-cat-search-input', + productCategorySearchResult: '#dokan-cat-search-res-ul li', + searchedResultText: '.dokan-cat-search-res-item', + productCategoryDone: '#dokan-single-cat-select-btn', + productCategoryAlreadySelectedPopup: '.swal2-confirm', + productCategoryModalClose: '#dokan-category-close-modal', + productCategoryValues: '.select2-results ul li', + }, + + // Edit Product + edit: { + productEditContainer: '.product-edit-new-container.product-edit-container', + + viewProduct: '.dokan-right .dokan-btn', + title: '#post_title', + + // Permalink + permalinkEdit: '.edit-slug', + confirmPermalinkEdit: '.cancel', + cancelPermalinkEdit: '.save', + + // Image + addProductImage: '.dokan-feat-image-btn', + uploadedProductImage: '.image-wrap img', + removeProductImage: '.close.dokan-remove-feat-image', + addGalleryImage: '.fa-plus', + uploadGalleryImage: '#dokan-product-images .image', + removeGalleryImage: '.action-delete', + + // Product Type + productType: '#product_type', + downloadable: '#\\_downloadable', + virtual: '#\\_virtual', + price: '#\\_regular_price', + discountedPrice: '#\\_sale_price', + discountedPriceSchedule: '.sale_schedule', + scheduleFrom: '.dokan-start-date', + scheduleTo: '.dokan-end-date', + scheduleCancel: '.cancel_sale_schedule', + category: '#select2-product_cat-container', + tags: '.select2-search__field', + + // External Product + productUrl: '#\\_product_url', + buttonText: '#\\_button_text', + + // Simple Subscription + subscriptionPrice: '#\\_subscription_price', + subscriptionPeriodInterval: '#\\_subscription_period_interval', + subscriptionPeriod: '#\\_subscription_period', + expireAfter: '#\\_subscription_length', + signUpFee: '#\\_subscription_sign_up_fee', + subscriptionTrialLength: '#\\_subscription_trial_length', + subscriptionTrialPeriod: '#\\_subscription_trial_period', + + // Short Description + shortDescription: { + shortDescriptionIframe: '.dokan-product-short-description iframe', + shortDescriptionHtmlBody: '#tinymce', + }, + + // Description + description: { + descriptionIframe: '.dokan-product-description iframe', + descriptionHtmlBody: '#tinymce', + }, + + // Inventory + inventory: { + sku: '#\\_sku', + stockStatus: '#\\_stock_status', + enableProductStockManagement: '#\\_manage_stock', + stockQuantity: '//input[@name="_stock"]', + lowStockThreshold: '//input[@name="_low_stock_amount"]', + allowBackOrders: '#\\_backorders', + allowOnlyOneQuantityOfThisProductToBeBoughtInASingleOrder: '#\\_sold_individually', + }, + + // Geolocation + geolocation: { + sameAsStore: '#\\_dokan_geolocation_use_store_settings', + productLocation: '#\\_dokan_geolocation_product_location', + }, + + // Add-Ons + addOns: { + addField: '.wc-pao-add-field', + type: '#wc-pao-addon-content-type-0', + displayAs: '#wc-pao-addon-content-display-0', + titleRequired: '#wc-pao-addon-content-name-0', + formatTitle: '#wc-pao-addon-content-title-format', + enableDescription: 'wc-pao-addon-description-enable-0', + addDescription: '#wc-pao-addon-description-0', + requiredField: '#wc-pao-addon-required-0', + import: '.wc-pao-import-addons', + export: '.wc-pao-export-addons', + excludeAddons: '\\_product_addons_exclude_global', + expandAll: '.wc-pao-expand-all', + closeAll: '.wc-pao-close-all', + + // Add-Ons Option + options: { + enterAnOption: '.wc-pao-addon-content-label > input', + optionPriceType: '.wc-pao-addon-option-price-type', + optionPrice: '.wc-pao-addon-content-price input', + addOption: '.wc-pao-add-option', + removeOptionCrossIcon: '.wc-pao-addon-content-remove > .button', + cancelRemoveOption: '.swal2-cancel', + okRemoveOption: '.swal2-confirm', + }, + }, + }, + + // Shipping + shipping: { + thisProductRequiresShipping: '#\\_disable_shipping', + weight: '#\\_weight', + length: '#\\_length', + width: '#\\_width', + height: '#\\_height', + shippingClass: '#product_shipping_class', + shippingSettings: '.help-block > a', + }, + + // Tax + tax: { + taxStatus: '#\\_tax_status', + taxClass: '#\\_tax_class', + }, + + // Linked Products + linkedProduct: { + upSells: '//label[contains(text(),"Upsells")]/..//input[@class="select2-search__field"]', + crossSells: '//label[contains(text(),"Cross-sells ")]/..//input[@class="select2-search__field"]', + }, + + // Attribute + attribute: { + customProductAttribute: '#predefined_attribute', + addAttribute: '.add_new_attribute', + visibleOnTheProductPage: '//input[contains(@name, "attribute_visibility")]', + usedForVariations: '//input[contains(@name, "attribute_variation")]', + selectTerms: '.dokan-attribute-values .select2-search__field', + selectAll: 'button.dokan-select-all-attributes', + selectNone: 'button.dokan-select-no-attributes', + addNew: 'button.dokan-add-new-attribute', + removeAttribute: '.dokan-product-remove-attribute', + confirmRemoveAttribute: '.swal2-confirm', + cancelRemoveAttribute: '.swal2-cancel', + saveAttributes: '.dokan-save-attribute', + addVariations: '#field_to_edit', + go: '.do_variation_action', + confirmGo: '.swal2-confirm', + okSuccessAlertGo: '.swal2-confirm', + cancelGo: '.swal2-cancel.swal2-styled', + variationPrice: '.swal2-input', + okVariationPrice: '.swal2-confirm', + cancelVariationPrice: '.swal2-cancel', + saveVariationChanges: '.save-variation-changes', + cancelVariationChanges: '.cancel-variation-changes', + defaultAttribute: '.dokan-variation-default-select > .dokan-form-control', + }, + + // Discount Options + discount: { + enableBulkDiscount: 'input#\\_is_lot_discount', + lotMinimumQuantity: 'input#\\_lot_discount_quantity', + lotDiscountInPercentage: 'input#\\_lot_discount_amount', + }, + + // Rma Options + rma: { + overrideYourDefaultRmaSettingsForThisProduct: '#dokan_rma_product_override', + label: '#dokan-rma-label', + type: '#dokan-warranty-type', + length: '#dokan-warranty-length', + lengthValue: '//input[@name="warranty_length_value"]', + lengthDuration: '#dokan-warranty-length-duration', + refundReasonsFirst: '(//label[normalize-space()="Refund Reasons:"]/..//input)[1]', + refundReasons: '//label[normalize-space()="Refund Reasons:"]/..//input', + rmaPolicyIframe: '#wp-warranty_policy-wrap iframe', + rmaPolicyHtmlBody: '#tinymce', + }, + + // Wholesale Options + wholesale: { + enableWholeSaleForThisProduct: '#wholesale\\[enable_wholesale\\]', + wholesalePrice: '#dokan-wholesale-price', + minimumQuantityForWholesale: '#dokan-wholesale-qty', + }, + + // Min-Max Options + minMax: { + enableMinMaxRulesThisProduct: '#product_wise_activation', + minimumQuantity: '#min_quantity', + maximumQuantity: '#max_quantity', + minimumAmount: '#min_amount', + maximumAmount: '#max_amount', + orderRulesDoNotCount: '#\\_donot_count', + categoryRulesExclude: '#ignore_from_cat', + }, + + // Other Options + productStatus: '#post_status', + visibility: '#\\_visibility', + purchaseNote: '#\\_purchase_note', + enableProductReviews: '#\\_enable_reviews', + + // Advertise Product + advertisement: { + advertiseThisProduct: '#dokan_advertise_single_product', + confirmAdvertiseThisProduct: '.swal2-confirm', + okSuccessAlertAdvertiseThisProduct: '.swal2-confirm', + cancelAdvertiseThisProduct: '.swal2-cancel', + }, + + // Save Product + saveProduct: '.dokan-btn-lg', + updatedSuccessMessage: '.dokan-message', + + quickEditProduct: { + // title : (productName: string) => `//fieldset//input[contains(@value, "${productName}")]`, + title: '(//tr[@class="dokan-product-list-inline-edit-form"]//input[@class="dokan-form-control"])[1]', + update: '(//button[@type="button"][normalize-space()="Update"])[1]', + }, + + confirmAction: '.swal2-actions .swal2-confirm', + cancelAction: '.swal2-actions .swal2-cancel', + successMessage: '.swal2-actions .swal2-confirm', + dokanMessage: '.dokan-message', + dokanSuccessMessage: '.dokan-alert.dokan-alert-success', + }, + + // Orders + orders: { + // Menus + menus: { + all: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "All")]', + completed: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "Completed")]', + processing: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "Processing")]', + onHold: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "On-hold")]', + pending: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "Pending")]', + cancelled: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "Cancelled")]', + refunded: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "Refunded")]', + failed: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(), "Failed")]', + }, + + // Export Order + export: { + exportAll: '//input[@name="dokan_order_export_all"]', + exportFiltered: '//input[@name="dokan_order_export_filtered"]', + }, + + // Filter + filters: { + filterByCustomer: { + dropDown: '.select2-selection .select2-selection__arrow', + input: '.select2-search__field', + searchedResult: '.select2-results__option--highlighted', + }, + + filterByDate: { + dateRangeInput: 'input#order_filter_date_range', + startDateInput: 'input#order_filter_start_date', + endDateInput: 'input#order_filter_end_date', + }, + + filter: '//button[normalize-space()="Filter"]', + reset: '//a[normalize-space()="Reset"]', + }, + + search: { + searchInput: '//input[@placeholder="Search Orders"]', + searchBtn: '//button[normalize-space()="Filter"]', + }, + + // Bulk Actions + bulkActions: { + selectAll: '#cb-select-all', + selectAction: '#bulk-order-action-selector', // wc-on-hold, wc-processing, wc-completed + applyAction: '#bulk-order-action', + }, + + // Table + table: { + orderTable: '.dokan-table.dokan-table-striped', + orderColumn: '//th[normalize-space()="Order"]', + totalColumn: '//th[normalize-space()="Order Total"]', + earningColumn: '//th[normalize-space()="Earning"]', + statusColumn: '//th[normalize-space()="Status"]', + customerColumn: '//th[normalize-space()="Customer"]', + dateColumn: '//th[normalize-space()="Date"]', + shipmentColumn: '//th[normalize-space()="Shipment"]', + actionColumn: '//th[normalize-space()="Action"]', + }, + + numberOfRowsFound: '.dokan-table.dokan-table tbody tr', + // Order Details from Table + orderTotalTable: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../../..//td[@class='dokan-order-total']//bdi`, + orderTotalAfterRefundTable: (orderNumber: string) => `///strong[contains(text(),'Order ${orderNumber}')]/../../..//td[@class='dokan-order-total']//ins//bdi`, + vendorEarningTable: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../../..//td[@class='dokan-order-earning']//span[@class="woocommerce-Price-amount amount"]`, + orderStatusTable: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../../..//td[@class='dokan-order-status']//span`, + + // Order Sub-Actions + orderLink: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/..`, + processing: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../../..//a[@data-original-title='Processing']`, + complete: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../../..//a[@data-original-title='Complete']`, + view: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../../..//a[@data-original-title='View']`, + + // order details + orderDetails: { + orderNumber: '//strong[contains(text(),"Order#")]', + orderDate: '//span[contains(text(),"Order Date:")]/..', + orderTotal: '//td[contains(text(),"Order Total:")]/..//bdi', + orderTotalBeforeRefund: '//td[contains(text(),"Order Total:")]/..//del', + orderTotalAfterRefund: '//td[contains(text(),"Order Total:")]/..//ins//bdi', + discount: '//td[contains(text(),"Discount")]/..//bdi', + shippingMethod: '//tr[contains(@class,"shipping")]//td[@class="name"]//div[@class="view"]', + shippingCost: '//td[contains(text(),"Shipping")]/..//bdi', + tax: '//td[contains(text(),"Tax")]/..//bdi', + refunded: '.total.refunded-total bdi', + + // todo: add lite order details locators + // lite + total: '//th[contains(text(),"Total:")]/..//td//span[@class="woocommerce-Price-amount amount"]', + }, + + // general details + generalDetails: { + generalDetailsDiv: '//strong[normalize-space()="General Details"]/../..', + orderDetails: '.list-unstyled.order-status', + customerDetails: '.list-unstyled.customer-details', + }, + + // status + status: { + currentOrderStatus: '.order-status .dokan-label', + selectedOrderStatus: '//select[@id="order_status"]//option[@selected="selected"]', + edit: '.dokan-edit-status', + orderStatus: '#order_status', // wc-pending, wc-processing, wc-completed, wc-cancelled, wc-refunded, wc-failed, wc-checkout-draft + updateOrderStatus: '//input[@name="dokan_change_status"]', + }, + + // Refund + refund: { + refundDiv: '#woocommerce-order-items', + requestRefund: '.dokan-btn.refund-items', + productQuantity: (productName: string) => `//td[@class='name' and @data-sort-value='${productName}']/..//td[@class='quantity']//div[@class="view"]`, + productCost: (productName: string) => `//td[@class='name' and @data-sort-value='${productName}']/..//td[@class='line_cost']//div[@class="view"]`, + productTax: (productName: string) => `//td[@class='name' and @data-sort-value='${productName}']/..//td[@class='line_tax']//div[@class="view"]`, + refundProductQuantity: (productName: string) => `//td[@class='name' and @data-sort-value='${productName}']/..//td[@class='quantity']//div[@class='refund']//input`, + refundProductCostAmount: (productName: string) => `//td[@class='name' and @data-sort-value='${productName}']/..//input[@class='refund_line_total wc_input_price']`, + refundProductTaxAmount: (productName: string) => `//td[@class='name' and @data-sort-value='${productName}']/..//input[@class='refund_line_tax wc_input_price']`, + shippingCost: '//tbody[@id="order_shipping_line_items"]//td[@class="line_cost"]//div[@class="view"]', + shippingTax: '//tbody[@id="order_shipping_line_items"]//td[@class="line_tax"]//div[@class="view"]', + refundShippingAmount: '//tbody[@id="order_shipping_line_items"]//td[@class="line_cost"]//input[@class="refund_line_total wc_input_price"]', + refundShippingTaxAmount: '//tbody[@id="order_shipping_line_items"]//td[@class="line_tax"]//input[@class="refund_line_tax wc_input_price"]', + + refundReason: '#refund_reason', + refundManually: '.dokan-btn.do-manual-refund', + confirmRefund: '.swal2-confirm.swal2-styled.swal2-default-outline', + refundRequestSuccessMessage: '#swal2-html-container', + refundRequestSuccessMessageOk: '.swal2-confirm.swal2-styled.swal2-default-outline', + cancelRefund: '.dokan-btn.cancel-action', + }, + + // add note + orderNote: { + orderNoteDiv: '//strong[normalize-space()="Order Notes"]/../..', + orderNoteInput: '#add-note-content', + orderNoteType: '#order_note_type', // Customer note, Private note + addNote: 'input[value="Add Note"]', + }, + + // tracking number + trackingDetails: { + addTrackingNumber: '#dokan-add-tracking-number', + shippingProvider: '#shipping_provider', + trackingNumber: '#tracking_number', + dateShipped: '#shipped-date', + addTrackingDetails: '#add-tracking-details', + cancelAddTrackingDetails: '#dokan-cancel-tracking-note', + }, + + // shipment + shipment: { + shipmentDiv: '//strong[normalize-space()="Shipments"]/../..', + createNewShipment: '#create-tracking-status-action', + shipmentOrderItem: (productName: string) => `//div[@id="dokan-order-shipping-status-tracking-panel"]//td//a[contains( text(),"${productName}")]/../..//input[@name="shipment_order_item_select"]`, + shipmentOrderItemQty: (productName: string) => `//div[@id="dokan-order-shipping-status-tracking-panel"]//td//a[contains( text(),"${productName}")]/../..//input[@class="shipping_order_item_qty"]`, + shippingStatus: '#shipping_status', // ss_delivered, ss_cancelled, ss_proceccing, ss_ready_for_pickup, ss_pickedup, ss_on_the_way + shippingProvider: '#shipping_status_provider', // sp-dhl, sp-dpd, sp-fedex, sp-polish-shipping-providers, sp-ups, sp-usps, sp-other + dateShipped: '#shipped_status_date', + trackingNumber: '#tracking_status_number', + comments: '#tracking_status_comments', + notifyCustomer: '#shipped_status_is_notify', + createShipment: '#add-tracking-status-details', + cancelCreateShipment: '#cancel-tracking-status-details', + }, + + // downloadable product permission + downloadableProductPermission: { + downloadableProductPermissionDiv: '//strong[normalize-space()="Downloadable Product Permission"]/../..', + downloadableProductInput: '.select2-search__field', + grantAccess: '.grant_access', + revokeAccess: '.revoke_access', + confirmAction: '.swal2-actions .swal2-confirm', + cancelAction: '.swal2-actions .swal2-cancel', + }, + }, + + // User Subscriptions + vUserSubscriptions: { + // Filter + filters: { + filterByCustomer: '//select[@id="dokan-filter-customer"]/..//span[@class="select2-selection__arrow"]', + filterByCustomerInput: '.select2-search__field', + filterByDate: 'input#order_date_filter', + filter: '.dokan-btn', + result: '.select2-results__option.select2-results__option--highlighted', + }, + + // table + table: { + table: '.dokan-user-subscription-content table', + statusColumn: '//th[normalize-space()="Status"]', + subscriptionColumn: '//th[normalize-space()="Subscription"]', + itemColumn: '//th[normalize-space()="Item"]', + totalColumn: '//th[normalize-space()="Total"]', + startColumn: '//th[normalize-space()="Start"]', + nextPaymentColumn: '//th[normalize-space()="Next Payment"]', + endColumn: '//th[normalize-space()="End"]', + }, + + noSubscriptionsFound: '//div[@class="dokan-error" and contains(text(), "No subscription found")]', + numberOfRowsFound: '.dokan-table.dokan-table tbody tr', + + // Edit Subscription + subscription: 'td a strong', + // Edit Subscription Order Status + editSubscriptionOrderStatus: '.dokan-edit-status small', + subscriptionOrderStatus: '#order_status', + updateSubscriptionOrderStatus: '//input[@name="dokan_vps_change_status"]', + cancelSubscriptionOrderStatus: '.dokan-btn-default', + // Downloadable Product Permission + chooseADownloadableProduct: '.select2-search__field', + grantAccess: '.grant_access', + downloadsRemaining: '.form-input', + accessExpires: 'td .short ', + removeAccess: '.revoke_access', + confirmRemoveAccess: '.swal2-confirm', + cancelRemoveAccess: '.swal2-cancel', + // Subscription Schedule + billingInterval: '#\\_billing_interval', + billingPeriod: '#\\_billing_period', + nextPayment: '#next_payment', + nextPaymentHour: '#next_payment_hour', + nextPaymentMinute: '#next_payment_minute', + endDate: '#end', + endDateHour: '#end_hour', + endDateMinute: '#end_minute', + updateSchedule: '//input[@name="dokan_change_subscription_schedule"]', + // Subscription Notes + addNoteContent: '#add-note-content', + orderNoteType: '#order_note_type', + addNote: '.btn', + + dokanError: '.dokan-error', + }, + + vRequestQuotes: { + requestQuotesText: '//h3[normalize-space()="Request Quotes"]', + noQuoteMessage: '//div[contains(@class, "woocommerce-message woocommerce-message--info")]', + goToShop: '//a[normalize-space()="Go to shop"]', + + // table + table: { + quoteTable: 'table.my_account_quotes', + quoteColumn: '//th[normalize-space()="Quote #"]', + quoteNameColumn: '//th[normalize-space()="Quote Name"]', + statusColumn: '//th[normalize-space()="Status"]', + dateColumn: '//th[normalize-space()="Date"]', + actionColumn: '//th[normalize-space()="Action"]', + }, + + viewQuoteDetails: (quoteTitle: string) => `//td[normalize-space()="${quoteTitle}"]/..//a[@class="woocommerce-button button view"]`, + + quoteDetails: { + basicDetails: { + requestQuotesText: '//h3[normalize-space()="Request Quotes"]', + + basicDetailsTable: '//table[contains(@class,"quote_details") and not(contains(@class,"cart"))]', + quoteNumberText: '//th[@class="quote-number"]', + customerNameText: '//th[@class="customer-name"]', + customerEmailText: '//th[@class="customer-email"]', + quoteDateText: '//th[@class="quote-date"]', + quoteStatusText: '//th[@class="quote-status"]', + + quoteNumberValue: '//td[@class="quote-number"]', + customerNameValue: '//td[@class="customer-name"]', + customerEmailValue: '//td[@class="customer-email"]', + quoteDateValue: '//td[@class="quote-date"]', + quoteStatusValue: '//th[@class="quote-status"]/..//td', + }, + + quoteItemDetails: { + quoteDetailsText: '//h2[normalize-space()="Quote Details"]', + + table: { + quoteDetailsTable: '//table[contains(@class,"quote_details") and contains(@class,"cart")]', + productColumn: '//th[@class="product-name"]', + priceColumn: '//th[normalize-space()="Price"]', + offeredPriceColumn: '//th[normalize-space()="Offered Price"]', + quantityColumn: '//th[@class="product-quantity"]', + subtotalColumn: '//th[normalize-space()="Subtotal"]', + offeredSubtotalColumn: '//th[normalize-space()="Offered Subtotal"]', + }, + }, + + quoteTotals: { + quoteTotalsTitle: '//h2[normalize-space()="Quote totals"]', + quoteTotalsDiv: '.cart_totals', + quoteTotalsTable: '//div[@class="cart_totals"]//table[contains(@class,"table_quote_totals")]', + + subTotalText: '//tr[@class="cart-subtotal"]//th', + offeredPriceSubtotalText: '//tr[@class="cart-subtotal offered"]//th', + + subTotalValue: '//td[@data-title="Subtotal (standard)"]', + offeredPriceSubtotalValue: '//td[@data-title="Offered Price Subtotal"]', + }, + + offeredPriceInput: (productName: string) => `//a[normalize-space()="${productName}"]/../..//input[@class="input-text offered-price-input text"]`, + quantityInput: (productName: string) => `//a[normalize-space()="${productName}"]/../..//div[@class="quantity"]//input`, + + updateQuote: 'button[name="dokan_update_quote"]', + approveThisQuote: 'button[name="approved_by_vendor_button"]', + convertToOrder: 'button[name="dokan_convert_to_order_customer"]', + + message: '.woocommerce-message', + }, + }, + + // Coupons + vCoupon: { + couponText: '.dokan-dashboard-header .left-header-content .entry-title', + + // Menus + menus: { + myCoupons: '//a[normalize-space()="My Coupons"]', + marketplaceCoupons: '//a[normalize-space()="Marketplace Coupons"]', + }, + + marketPlaceCoupon: { + marketPlaceCoupon: '#marketplace-coupon', + couponCell: (couponCode: string) => `//td[contains(@class, "coupon-code")]//span[contains(text(), "${couponCode}")]`, + }, + + // Table + table: { + couponsTable: '#vendor-own-coupon .dokan-table', + codeColumn: '//th[normalize-space()="Code"]', + couponTypeColumn: '//th[normalize-space()="Coupon type"]', + couponAmountColumn: '//th[normalize-space()="Coupon amount"]', + productIdsColumn: '//th[normalize-space()="Product IDs"]', + usageOrLimitColumn: '//th[normalize-space()="Usage / Limit"]', + expiryDateColumn: '//th[normalize-space()="Expiry date"]', + }, + + couponRow: (couponCode: string) => `//span[normalize-space()="${couponCode}"]/../../../../..`, + couponCell: (couponCode: string) => `//span[normalize-space()="${couponCode}"]/../../../..`, + couponLink: (couponCode: string) => `//span[normalize-space()="${couponCode}"]/..`, + couponEdit: (couponCode: string) => `//span[normalize-space()="${couponCode}"]/../../../..//div[@class="row-actions"]//span[@class="edit"]`, + couponDelete: (couponCode: string) => `//span[normalize-space()="${couponCode}"]/../../../..//div[@class="row-actions"]//span[@class="delete"]`, + + // Create Coupon + addNewCoupon: '.dokan-btn', + couponTitle: '#title', + description: '#description', + discountType: '#discount_type', + amount: '#coupon_amount', + emailRestrictions: '#email_restrictions', + usageLimit: '#usage_limit', + usageLimitPerUser: '#usage_limit_per_user', + expireDate: '#dokan-expire', + excludeSaleItems: '#checkboxes-2', + minimumAmount: '#minium_ammount', + product: '//label[contains(text(), "Product")]/..//input[@class="select2-search__field"]', + selectAll: '.dokan-coupon-product-select-all', + clear: '.dokan-coupon-product-clear-all', + applyForNewProducts: '#apply_new_products', + excludeProducts: '//label[contains(text(), "Exclude products")]/..//input[@class="select2-search__field"]', + showOnStore: '#checkboxes-3', + createCoupon: '.dokan-btn-danger', + + // Coupon Dashboard + createdCoupon: '.coupon-code.column-primary strong span', + couponSaveSuccessMessage: 'Coupon has been saved successfully!', // todo: move all success message to test data + couponUpdateSuccessMessage: 'Coupon has been updated successfully!', + + dokanMessage: '.dokan-message', + + // Coupon Error + couponError: '.dokan-alert.dokan-alert-danger', + }, + + // Reports + vReports: { + reportsText: '//h1[normalize-space()="Reports"]', + + // Menus + menus: { + overview: '//ul[@class="dokan_tabs"]//a[contains(text(), "Overview")]', + salesByDay: '//ul[@class="dokan_tabs"]//a[contains(text(), "Sales by day")]', + topSelling: '//ul[@class="dokan_tabs"]//a[contains(text(), "Top selling")]', + topEarning: '//ul[@class="dokan_tabs"]//a[contains(text(), "Top earning")]', + statement: '//ul[@class="dokan_tabs"]//a[contains(text(), "Statement")]', + }, + + // chart + chart: { + legendDetails: '.dokan-reports-sidebar ul.chart-legend', + chartDiv: 'div.chart-container', + chartLegend: 'div.chart.chart-legend-container', + chart: 'div.chart-placeholder.main', + }, + + // date picker + datePicker: { + from: '#from', + to: '#to', + show: 'input[value="Show"]', + }, + + topSelling: { + // table + table: { + topSellingTable: '.table.table-striped', + productColumn: '//th[normalize-space()="Product"]', + salesColumn: '//th[normalize-space()="Sales"]', + }, + + noProductsFound: '//td[normalize-space()="No products found in given range."]', + }, + + topEarning: { + // table + table: { + topEarningTable: '.table.table-striped', + productColumn: '//th[normalize-space()="Product"]', + salesColumn: '//th[normalize-space()="Sales"]', + earningColumn: '//th[normalize-space()="Earning"]', + }, + + noProductsFound: '//td[normalize-space()="No products found in given range."]', + }, + + statement: { + exportStatements: '.dokan-right', + + // table + table: { + statementsTable: '.table.table-striped', + balanceDateColumn: '//th[normalize-space()="Balance Date"]', + trnDateColumn: '//th[normalize-space()="Trn Date"]', + idColumn: '//th[normalize-space()="ID"]', + typeColumn: '//th[normalize-space()="Type"]', + debitColumn: '//th[normalize-space()="Debit"]', + creditColumn: '//th[normalize-space()="Credit"]', + balanceColumn: '//th[normalize-space()="Balance"]', + }, + + noStatementsFound: '//td[normalize-space()="No Result found!"]', + }, + }, + + // Deliverytime + vDeliveryTime: { + deliveryTimeAndStorePickup: '//h1[normalize-space()="Delivery Time & Store Pickup"]', + + // Filter + filter: { + deliveryTimeFilter: '#delivery-type-filter', // delivery, store-pickup + filter: '//button[normalize-space()="Filter"]', + }, + + // calendar Navigation + navigation: { + month: '.fc-dayGridMonth-button', + week: '.fc-timeGridWeek-button', + day: '.fc-timeGridDay-button', + list: '.fc-listWeek-button', + today: '.fc-today-button', + previous: '.fc-prev-button', + next: '.fc-next-button', + }, + + deliveryTimeCalender: 'div#delivery-time-calendar', + }, + + // Review + vReviews: { + reviewsText: '//h1[normalize-space()="Reviews"]', + + // Menus + menus: { + approved: '//div[@id="dokan-comments_menu"]//a[contains(text(), "Approved")]', + pending: '//div[@id="dokan-comments_menu"]//a[contains(text(), "Pending")]', + spam: '//div[@id="dokan-comments_menu"]//a[contains(text(), "Spam")]', + trash: '//div[@id="dokan-comments_menu"]//a[contains(text(), "Trash")]', + }, + + // Bulk Action + bulkActions: { + selectAll: '.dokan-check-all', + selectAction: 'select[name="comment_status"]', // none, hold, spam, trash, approve, delete + applyAction: 'input[value="Apply"]', + }, + + // table + table: { + table: '#dokan-comments-table', + authorColumn: '//th[normalize-space()="Author"]', + commentColumn: '//th[normalize-space()="Comment"]', + linkToColumn: '//th[normalize-space()="Link To"]', + ratingColumn: '//th[normalize-space()="Rating"]', + }, + + noReviewsFound: '//td[normalize-space()="No Results Found"]', + numberOfRowsFound: '.dokan-reviews-content tbody tr', + + // Review Actions + reviewRow: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/../..`, + reviewMessageCell: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/..`, + unApproveReview: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/..//ul[@class='dokan-cmt-row-actions']//a[contains(text(),'Unapprove')]`, + approveReview: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/..//ul[@class='dokan-cmt-row-actions']//a[contains(text(),'Approve')]`, + spamReview: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/..//ul[@class='dokan-cmt-row-actions']//a[contains(text(),'Spam')]`, + trashReview: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/..//ul[@class='dokan-cmt-row-actions']//a[contains(text(),'Trash')]`, + restoreReview: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/..//ul[@class='dokan-cmt-row-actions']//a[contains(text(),'Restore')]`, + permanentlyDeleteReview: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/..//ul[@class='dokan-cmt-row-actions']//a[contains(text(),'Delete Permanently')]`, + reviewLink: (reviewMessage: string) => `//div[contains(text(),'${reviewMessage}')]/../..//td[@class="col-link"]//a`, + viewReview: '//a[contains(text(),"View Comment")]', + + reviewDetails: { + reviewer: 'strong.woocommerce-review__author', + reviewPublishDate: 'time.woocommerce-review__published-date', + reviewMessage: '.comment-text .description p', + rating: '#reviews div.star-rating', + reviewMessageByMessage: (reviewMessage: string) => `//div[@class="description"]//p[contains(text(), '${reviewMessage}')]`, + }, + }, + + // Withdraw + vWithdraw: { + withdrawText: '.dokan-dashboard-content.dokan-withdraw-content h1', + + // balance + balance: { + balanceDiv: '//strong[normalize-space()="Balance"]/../..', + balancePro: '//p[contains(text(),"Your Balance:")]//a//span[@class="woocommerce-Price-amount amount"]', + balanceLite: '//p[contains(text(),"Your Balance:")]//strong[1]', + minimumWithdrawAmount: '//p[contains(text(),"Your Balance:")]//strong[2]', + }, + + // payment details + paymentDetails: { + manual: { + paymentDetailsDiv: '//strong[normalize-space()="Payment Details"]/../..', + lastPaymentSection: '//strong[normalize-space()="Last Payment"]/..', + }, + schedule: { + ScheduleSection: '//input[@id="dokan-schedule-enabler-switch"]/../../..', + }, + }, + + // withdraw payment methods + withdrawPaymentMethods: { + paymentMethodsDiv: '#dokan-withdraw-payment-method-list', + paymentMethods: '#dokan-withdraw-payment-method-list .dokan-panel-inner-container', + makeMethodDefault: (methodName: string) => `//div[@id='dokan-withdraw-payment-method-list']//strong[contains( text(), '${methodName}')]/../..//button[contains(@class, 'dokan-btn')]`, + setupMethod: (methodName: string) => `//strong[contains( text(), '${methodName}')]/../..//a[@class='dokan-btn']`, + defaultMethod: (methodName: string) => `//div[@id='dokan-withdraw-payment-method-list']//strong[contains( text(), '${methodName}')]/../..//button[contains(@class, 'dokan-btn-default')]`, + defaultPaymentMethodUpdateSuccessMessage: 'Default method update successful.', + }, + + // view payments + viewPayments: { + viewPayments: '#dokan-withdraw-display-requests-button', + + menus: { + pendingRequests: '//ul[contains(@class,"subsubsub")]//a[contains(text(), "Pending Requests")]', + approvedRequests: '//ul[contains(@class,"subsubsub")]//a[contains(text(), "Approved Requests")]', + cancelledRequests: '//ul[contains(@class,"subsubsub")]//a[contains(text(), "Cancelled Requests")]', + }, + + requestWithdraw: '#dokan-request-withdraw-button', + withdrawDashboard: '.dokan-add-product-link a', + + table: { + withdrawTable: '.dokan-table.dokan-table-striped', + amountColumn: '//th[normalize-space()="Amount"]', + methodColumn: '//th[normalize-space()="Method"]', + dateColumn: '//th[normalize-space()="Date"]', + cancelColumn: '//th[normalize-space()="Cancel"]', + statusColumn: '//th[normalize-space()="Status"]', + }, + + noRowsFound: '//td[normalize-space()="No pending withdraw request"]', + }, + + // Manual Withdraw Request + manualWithdrawRequest: { + requestWithdraw: '#dokan-request-withdraw-button', + closeModal: '.iziModal-button-close', + withdrawAmount: '#withdraw-amount', + withdrawMethod: '#withdraw-method', + submitRequest: '#dokan-withdraw-request-submit', + withdrawRequestSaveSuccessMessage: 'Withdraw request successful.', + cancelWithdrawRequestSuccess: '.dokan-alert.dokan-alert-success', + cancelWithdrawRequestSaveSuccessMessage: 'Your request has been cancelled successfully!', + cancelRequest: '//strong[normalize-space()="Pending Requests"]/..//a[normalize-space()="Cancel"]', + pendingRequest: '//strong[normalize-space()="Pending Requests"]', + pendingRequestAlert: '.dokan-alert.dokan-alert-danger', + pendingRequestAlertMessage: 'You already have pending withdraw request(s). Please submit your request after approval or cancellation of your previous request.', + }, + + // Auto withdraw Disbursement Schedule + autoWithdrawDisbursement: { + enableSchedule: '//input[@id="dokan-schedule-enabler-switch"]/..', + editSchedule: '#dokan-withdraw-display-schedule-popup', + closeModal: '.mfp-close', // todo: need to update, everywhere + preferredPaymentMethod: '#preferred-payment-method', + preferredSchedule: (schedule: string) => `#withdraw-schedule-${schedule}\\>`, + onlyWhenBalanceIs: '#minimum-withdraw-amount', + maintainAReserveBalance: '#withdraw-remaining-amount', + changeSchedule: '#dokan-withdraw-schedule-request-submit', + scheduleMessage: '//div[@class="dokan-switch-container"]/..//p', + dokanBottomPopup: '#swal2-html-container', // todo: make it global and use to assert every popup massage frontend + withdrawScheduleSaveSuccessMessage: 'Withdraw schedule changed successfully.', + }, + }, + + // badges + vBadges: { + badgesText: '#dokan-seller-badge .entry-title', + + description: '//p[contains(text(), "Vendors with a good selling history on our marketplace are identified by seller badges")]', + + search: '#post-search-input', + + // filters + filterBadges: '.tablenav.top .actions select', // all, my_badges, available_badges + + // table + table: { + table: '#dokan-seller-badge table', + acquiredBadgeColumn: 'thead th[class="column badge_logo"]', + descriptionColumn: 'thead th[class="column badge_description"]', + actionColumn: 'thead th[class="column badge_view"]', + }, + + sellerBadgeCell: (name: string) => `//strong[contains(text(),'${name}')]/../..`, + numberOfBadgesFound: '.tablenav.top .displaying-num', + + congratsModal: { + closeModal: '.modal-close.modal-close-link', + sellerBadgeModal: '.seller-badge-modal .seller-badge-modal-content', + modalBody: '.modal-body', + congratsMessage: '//div[@class="modal-title"]//h2[contains(text(), "Congratulations!")]', + acquiredBadges: '//div[@class="modal-sub-title"]//h3[contains(text(), "Acquired Badge & Level:")]', + }, + }, + + // reverse withdrawal + vReverseWithdrawal: { + reverseWithdrawalText: '//h1[normalize-space()="Reverse Withdrawal"]', + + reverseWithdrawalNotice: { + noticeDiv: 'div.dokan-alert.dokan-alert-danger', + noticeText: 'div.dokan-alert.dokan-alert-danger strong', + }, + + reverseBalanceSection: { + reverseBalanceSection: 'div.reverse-balance-section', + reversePayBalance: 'div.reverse-balance', + reversePayBalanceAmount: 'div.reverse-balance .woocommerce-Price-amount.amount', + reverseThreshold: 'div.reverse-threshold', + reverseThresholdAmount: 'div.reverse-threshold .woocommerce-Price-amount.amount', + }, + + payNow: 'input#reverse_pay', + confirmAction: '.swal2-actions .swal2-confirm', + + filters: { + dateRangeInput: 'input#trn_date_filter', + startDateInput: 'input#trn_date_form_filter_alt', + endDateInput: 'input#trn_date_to_filter_alt', + filter: '//input[@value="Filter"]', + }, + + table: { + reverseWithdrawalTable: '.dokan-table.dokan-table-striped', + transactionIdColumn: '//th[normalize-space()="Transaction ID"]', + dateColumn: '//th[normalize-space()="Date"]', + transactionTypeColumn: '//th[normalize-space()="Transaction Type"]', + noteColumn: '//th[normalize-space()="Note"]', + debitColumn: '//th[normalize-space()="Debit"]', + creditColumn: '//th[normalize-space()="Credit"]', + balanceColumn: '//th[normalize-space()="Balance"]', + }, + + noRowsFound: '//td[normalize-space()="No transactions found!"]', + numberOfRowsFound: '.dokan-table.dokan-table-striped tbody tr', + openingBalanceRow: '//td[normalize-space()="Opening Balance"]/..', + totalBalanceRow: '//b[normalize-space()="Balance:"]/../..', + }, + + // Return Request + vReturnRequest: { + // Menus + menus: { + all: '//ul[contains(@class,"request-statuses-filter")]//a[contains(text(),"All")]', + new: '//ul[contains(@class,"request-statuses-filter")]//a[contains(text(),"New")]', + completed: '//ul[contains(@class,"request-statuses-filter")]//a[contains(text(),"Completed")]', + processing: '//ul[contains(@class,"request-statuses-filter")]//a[contains(text(),"Processing")]', + }, + + // table + table: { + table: '.rma-request-listing-table', + detailsColumn: '//th[normalize-space()="Details"]', + productsColumn: '//th[normalize-space()="Products"]', + typeColumn: '//th[normalize-space()="Type"]', + statusColumn: '//th[normalize-space()="Status"]', + lastUpdatedColumn: '//th[normalize-space()="Last Updated"]', + }, + + noRowsFound: '//td[normalize-space()="No request found"]', + numberOfRowsFound: '.rma-request-listing-table tbody tr', + + // Refund Request table Actions + returnRequestCell: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../..`, + manage: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../..//a[@class='request-manage']`, + delete: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../..//a[@class='request-delete']`, + view: (orderNumber: string) => `//strong[contains(text(),'Order ${orderNumber}')]/../../..//i[@class='far fa-eye']`, + + // return request details + returnRequestDetails: { + backToList: '.left-header-content a', + + basicDetails: { + basicDetails: '//div[normalize-space()="Details"]/..', + orderId: '//strong[normalize-space()="Order ID :"]', + customerName: '//strong[normalize-space()="Customer Name :"]', + requestType: '//strong[normalize-space()="Request Type :"]', + products: '//strong[normalize-space()="Products :"]', + }, + + additionalDetails: { + additionalDetailsDiv: '.additional-details', + reason: '//p[normalize-space()="Reason"]/..//p[@class="details-value"]', + reasonDetails: '//p[normalize-space()="Reason Details"]/..//p[@class="details-value"]', + }, + + // status + status: { + statusDiv: '//div[normalize-space()="Status"]/..', + lastUpdated: '//strong[normalize-space()="Last Updated"]', + changeStatus: 'select#status', // new, processing, completed, rejected, reviewing + update: '//input[@value="Update"]', + sendRefund: '.dokan-send-refund-request', + }, + + // conversations + conversations: { + conversationsDiv: '//div[normalize-space()="Conversations"]/..', + message: '#message', + sendMessage: 'input[name="dokan_rma_send_message"]', + }, + + modal: { + taxRefundColumn: '//div[@class="iziModal-content"]//th[contains(text(),"Tax Refund")]', + subTotalRefundColumn: '//div[@class="iziModal-content"]//th[contains(text(),"Subtotal Refund")]', + + taxAmount: (productName: string) => `(//a[contains(text(),'${productName}')]/../..//bdi)[1]`, + subTotal: (productName: string) => `(//a[contains(text(),'${productName}')]/../..//bdi)[2]`, + taxRefund: (productName: string) => `//div[@class="iziModal-content"]//td//a[contains(text(),'${productName}')]/../..//input[contains(@name,"refund_tax")]`, + subTotalRefund: (productName: string) => `//div[@class="iziModal-content"]//td//a[contains(text(),'${productName}')]/../..//input[contains(@name,"refund_amount")]`, + + sendRequest: '//div[@class="iziModal-content"]//input[@name="dokan_refund_submit"]', + sendRequestSuccessMessage: '.dokan-alert.dokan-alert-info', + }, + }, + }, + + // Staff + vStaff: { + staffText: '.dokan-staffs-content h1', + + // Table + table: { + vendorStaffTable: '.dokan-table.dokan-table-striped.vendor-staff-table', + nameColumn: '//th[normalize-space()="Name"]', + emailColumn: '//th[normalize-space()="Email"]', + phoneColumn: '//th[normalize-space()="Phone"]', + registeredDateColumn: '//th[normalize-space()="Registered Date"]', + }, + + noRowsFound: '//div[@class ="dokan-error" and normalize-space()="No staff found"]', + staffCell: (staffName: string) => `//td//a[contains(text(),"${staffName}")]/..`, + + // Add Staff + addStaff: { + addNewStaff: '.dokan-btn', + firstName: '#first_name', + lastName: '#last_name', + email: '#email', + phone: '#phone', + createStaff: '.dokan-btn', + + dokanAlert: '.dokan-alert-danger', + userAlreadyExists: '//strong[normalize-space()="Sorry, that username already exists!"]', + }, + + // Edit Staff + editStaff: { + editStaff: (staffName: string) => `//a[contains(text(), "${staffName}")]/..//span[@class="edit"]//a`, + password: '#reg_password', + updateStaff: '//input[@name="staff_creation"]', + }, + + deleteStaff: { + deleteStaff: (staffName: string) => `//a[contains(text(), "${staffName}")]/..//span[@class="delete"]//a`, + okDelete: '.swal2-confirm', + cancelDelete: '.swal2-cancel', + deleteSuccessMessage: '.dokan-alert.dokan-alert-success', + }, + + // Manage Permission + managePermission: { + managePermission: (staffName: string) => `//a[contains(text(), "${staffName}")]/..//span[@class="permission"]//a`, + + // Overview + overview: { + viewSalesOverview: '#dokan_view_sales_overview', + viewSalesReportChart: '#dokan_view_sales_report_chart', + viewAnnouncement: '#dokan_view_announcement', + viewOrderReport: '#dokan_view_order_report', + viewReviewReport: '#dokan_view_review_reports', + viewProductStatusReport: '#dokan_view_product_status_report', + }, + + // Order + order: { + viewOrder: '#dokan_view_order', + manageOrder: '#dokan_manage_order', + manageOrderNote: '#dokan_manage_order_note', + manageRefund: '#dokan_manage_refund', + exportOrder: '#dokan_export_order', + }, + + // Review + review: { + viewReviews: '#dokan_view_reviews', + manageReviews: '#dokan_manage_reviews', + }, + + // Product + product: { + addProduct: '#dokan_add_product', + editProduct: '#dokan_edit_product', + deleteProduct: '#dokan_delete_product', + viewProduct: '#dokan_view_product', + duplicateProduct: '#dokan_duplicate_product', + importProduct: '#dokan_import_product', + exportProduct: '#dokan_export_product', + }, + + // Booking + booking: { + manageBookingProducts: '#dokan_manage_booking_products', + manageBookingCalendar: '#dokan_manage_booking_calendar', + manageBookings: '#dokan_manage_bookings', + manageBookingResource: '#dokan_manage_booking_resource', + addBookingProduct: '#dokan_add_booking_product', + editBookingProduct: '#dokan_edit_booking_product', + deleteBookingProduct: '#dokan_delete_booking_product', + }, + + // Store Support + storeSupport: { + manageSupportTicket: '#dokan_manage_support_tickets', + }, + + // Report + report: { + viewOverviewReport: '#dokan_view_overview_report', + viewDailySalesReport: '#dokan_view_daily_sale_report', + viewTopSellingReport: '#dokan_view_top_selling_report', + viewTopEarningReport: '#dokan_view_top_earning_report', + viewStatementReport: '#dokan_view_statement_report', + }, + + // Coupon + coupon: { + addCoupon: '#dokan_add_coupon', + editCoupon: '#dokan_edit_coupon', + deleteCoupon: '#dokan_delete_coupon', + }, + + // Withdraw + withdraw: { + manageWithdraw: '#dokan_manage_withdraw', + }, + + // Menu + menu: { + viewOverviewMenu: '#dokan_view_overview_menu', + viewProductMenu: '#dokan_view_product_menu', + viewOrderMenu: '#dokan_view_order_menu', + viewCouponMenu: '#dokan_view_coupon_menu', + viewReportMenu: '#dokan_view_report_menu', + viewReviewMenu: '#dokan_view_review_menu', + viewWithdrawMenu: '#dokan_view_withdraw_menu', + viewStoreSettingsMenu: '#dokan_view_store_settings_menu', + viewPaymentSettingsMenu: '#dokan_view_store_payment_menu', + viewShippingSettingsMenu: '#dokan_view_store_shipping_menu', + viewSocialSettingsMenu: '#dokan_view_store_social_menu', + viewSeoSettingsMenu: '#dokan_view_store_seo_menu', + // viewBookingMenu:'#dokan_view_booking_menu', // todo: add booking check + viewToolsMenu: '#dokan_view_tools_menu', + // viewAuctionMenu:'#dokan_view_auction_menu', // todo: add auction check + viewVerificationSettingsMenu: '#dokan_view_store_verification_menu', + }, + + // Auction + auction: { + addAuctionProduct: '#dokan_add_auction_product', + editAuctionProduct: '#dokan_edit_auction_product', + deleteAuctionProduct: '#dokan_delete_auction_product', + }, + + updateStaffPermission: '.dokan-btn', + }, + }, + + vFollowers: { + storeFollowersText: '//h1[normalize-space()="Store Followers"]', + + table: { + followersTable: '.dokan-table.dokan-table-striped.product-listing-table.dokan-inline-editable-table', + nameColumn: '//th[normalize-space()="Name"]', + followedAtColumn: '//th[normalize-space()="Followed At"]', + }, + + noRowsFound: '//td[normalize-space()="Your store does not have any follower."]', + numberOfRowsFound: 'table.dokan-table tbody tr', + }, + + // Booking + vBooking: { + allBookingProductText: '.dokan-dashboard-content h1', + + addNewBookingProduct: '//a[contains(text(),"Add New Booking Product")]', + addBookingBtn: '//a[normalize-space()="Add Booking"]', + + // Menus + menus: { + allBookingProduct: '//ul[@class="dokan_tabs"]//a[contains(text(),"All Booking Product")]', + manageBookings: '//ul[@class="dokan_tabs"]//a[contains(text(),"Manage Bookings")]', + calendar: '//ul[@class="dokan_tabs"]//a[contains(text(),"Calendar")]', + manageResources: '//ul[@class="dokan_tabs"]//a[contains(text(),"Manage Resources")]', + }, + + // Filter + filters: { + filterByDate: '#filter-by-date', + filterByCategory: '#product_cat', + filterByOther: 'select[name="filter_by_other"]', + filter: '//button[normalize-space()="Filter"]', + }, + + // Search product + search: { + searchInput: 'input[name="product_search_name"]', + search: 'button[name="product_listing_search"]', + }, + + // table + table: { + table: 'table.dokan-table.product-listing-table', + imageColumn: '//th[normalize-space()="Image"]', + nameColumn: '//th[normalize-space()="Name"]', + statusColumn: '//th[normalize-space()="Status"]', + skuColumn: '//th[normalize-space()="SKU"]', + stockColumn: '//th[normalize-space()="Stock"]', + priceColumn: '//th[normalize-space()="Price"]', + typeColumn: '//th[normalize-space()="Type"]', + viewsColumn: '//th[normalize-space()="Views"]', + dateColumn: '//th[normalize-space()="Date"]', + }, + + noProductFound: '//td[normalize-space()="No product found"]', + numberOfRowsFound: '.product-listing-table tbody tr', + productCell: (name: string) => `//p//a[normalize-space()="${name}"]/../..`, + edit: (name: string) => `//a[normalize-space()="${name}"]/../..//span[@class="edit"]`, + permanentlyDelete: (name: string) => `//a[normalize-space()="${name}"]/../..//span[@class="delete"]`, + duplicate: (name: string) => `//a[normalize-space()="${name}"]/../..//span[@class="duplicate"]`, + view: (name: string) => `//a[normalize-space()="${name}"]/../..//span[@class="view"]`, + + confirmDelete: '.swal2-confirm', + cancelDelete: '.swal2-cancel', + dokanSuccessMessage: '.dokan-alert.dokan-alert-success', + + // Create Booking Product + booking: { + viewProduct: '.view-product', + productName: '#post_title', + ProductImage: '.dokan-feat-image-btn', + virtual: '#\\_virtual', + accommodationBooking: '#\\_is_dokan_accommodation', + productCategory: '#select2-product_cat-container', + productCategoryInput: '.select2-search--dropdown > .select2-search__field', + tags: '.select2-search__field', + + // Accommodation Booking Options + minimumNumberOfNightsAllowedInABooking: '#\\_wc_booking_min_duration', + maximumNumberOfNightsAllowedInABooking: '#\\_wc_booking_max_duration', + checkInTime: '#\\_dokan_accommodation_checkin_time', + checkOutTime: '#\\_dokan_accommodation_checkout_time', + + // General Booking Options + bookingDurationType: '#\\_wc_booking_duration_type', + bookingDuration: 'input#\\_wc_booking_duration', + bookingDurationMin: 'input#\\_wc_booking_min_duration', + bookingDurationMax: 'input#\\_wc_booking_max_duration', + bookingDurationUnit: '#\\_wc_booking_duration_unit', + + calendarDisplayMode: '#\\_wc_booking_calendar_display_mode', + + // Checkboxes + enableCalendarRangePicker: '#\\_wc_booking_enable_range_picker', + requiresConfirmation: '#\\_wc_booking_requires_confirmation', + canBeCancelled: '#\\_wc_booking_user_can_cancel', + bookingCanBeCancelledLimit: '#\\_wc_booking_cancel_limit', + bookingCanBeCancelledLimitUnit: '#\\_wc_booking_cancel_limit_unit', + + // Shipping + thisProductRequiresShipping: '#\\_disable_shipping', + weight: '#\\_weight', + length: '#\\_length', + width: '#\\_width', + height: '#\\_height', + shippingClass: '#product_shipping_class', + shippingSettings: '.help-block > a', + + // Tax + taxStatus: '#\\_tax_status', + taxClass: '#\\_tax_class', + + // Availability + maxBookingsPerBlock: '#\\_wc_booking_qty', + minimumBookingWindowIntoTheFutureDate: '#\\_wc_booking_min_date', + minimumBookingWindowIntoTheFutureDateUnit: '#\\_wc_booking_min_date_unit', + maximumBookingWindowIntoTheFutureDate: '#\\_wc_booking_max_date', + maximumBookingWindowIntoTheFutureDateUnit: '#\\_wc_booking_max_date_unit', + requireABufferPeriodOfMonthsBetweenBookings: '#\\_wc_booking_buffer_period', + adjacentBuffering: '#\\_wc_booking_apply_adjacent_buffer', + allDatesAre: '#\\_wc_booking_default_date_availability', + checkRulesAgainst: '#\\_wc_booking_check_availability_against', + restrictStartAndEndDays: '#dokan_booking_has_restricted_days_field', + sunday: '#\\_wc_booking_restricted_days\\[0\\]', + monday: '#\\_wc_booking_restricted_days\\[1\\]', + tuesday: '#\\_wc_booking_restricted_days\\[2\\]', + wednesday: '#\\_wc_booking_restricted_days\\[3\\]', + thursday: '#\\_wc_booking_restricted_days\\[4\\]', + friday: '#\\_wc_booking_restricted_days\\[5\\]', + saturday: '#\\_wc_booking_restricted_days\\[6\\]', + + // Setavailabilityrange + addRangeAvailability: '//div[@id="bookings_availability"]//a[contains(text(),"Add Range")]', + rangeTypeAbility: '.wc_booking_availability_type > select', + rangeFromAbility: '.from_date > .date-picker ', + rangeToAbility: '.to_date > .date-picker ', + bookableAbility: '//select[@name="wc_booking_availability_bookable[]"]', + priorityAbility: '.priority > input', + cancelAbility: '#availability_rows .remove', + + // Costs + baseCost: '#\\_wc_booking_cost', + blockCost: '#\\_wc_booking_block_cost', + displayCost: '#\\_wc_display_cost', + + // Cost-range + addRangeCost: 'dokan-booking-range-table > tfoot .button', + rangeTypeCostRange: '.wc_booking_pricing_type > select', + rangeFromCostRange: '.from_date > .date-picker', + rangeToCostRange: '.to_date > .date-picker ', + baseCostModifier: '//select[@name="wc_booking_pricing_base_cost_modifier[]"]', + baseCostRange: '//input[@name="wc_booking_pricing_base_cost[]"]', + blockCostModifier: '//select[@name="wc_booking_pricing_cost_modifier[]"]', + blockCostRange: '//input[@name="wc_booking_pricing_cost[]"]', + cancelCostRange: '#pricing_rows .remove', + + // Extra Options + + // Has Persons + hasPersons: '#\\_wc_booking_has_persons', + minPersons: '#\\_wc_booking_min_persons_group', + maxPersons: '#\\_wc_booking_max_persons_group', + multiplyAllCostsByPersonCount: '#\\_wc_booking_person_cost_multiplier', + countPersonsAsBookings: '#\\_wc_booking_person_qty_multiplier', + enablePersonTypes: '#\\_wc_booking_has_person_types', + + // Add Person + addPersonType: '.add_person', + personTypeName: '//label[contains(text(),"Person Type Name:")]/..//input', + personBaseCost: '//label[contains(text(),"Base Cost:")]/..//input', + personBlockCost: '//label[contains(text(),"Block Cost:")]/..//input', + description: '.person_description', + min: '//label[contains(text(),"Min:")]/..//input', + max: '//label[contains(text(),"Max:")]/..//input', + unlink: '.unlink_booking_person', // invokes default js alert + + // Has Resources + hasResources: '#\\_wc_booking_has_resources', + + // Add Resource + label: '#\\_wc_booking_resource_label', + resourcesAre: '#\\_wc_booking_resources_assignment', + addResourceId: '.add_resource_id', + addResource: '.add_resource', + resourceBaseCost: '//label[contains(text(),"Base Cost:")]/..//input', + resourceBlockCost: '//label[contains(text(),"Block Cost:")]/..//input', + removeResource: '.remove_booking_resource.button', // invokes default js alert + + // Short Description + shortDescriptionIframe: '.dokan-product-short-description iframe', + shortDescriptionHtmlBody: '#tinymce', + + // Description + descriptionIframe: '.dokan-auction-post-content iframe', + descriptionHtmlBody: '#tinymce', + + // Inventory + sku: '#\\_sku', + stockStatus: '#\\_stock_status', + enableProductStockManagement: '#\\_manage_stock', + stockQuantity: '//input[@name="_stock"]', + lowStockThreshold: '//input[@name="_low_stock_amount"]', + allowBackOrders: '#\\_backorders', + allowOnlyOneQuantityOfThisProductToBeBoughtInASingleOrder: '#\\_sold_individually', + + // Geolocation + sameAsStore: '#\\_dokan_geolocation_use_store_settings', + productLocation: '#\\_dokan_geolocation_product_location', + + // add-ons + addField: '.wc-pao-add-field', + type: '#wc-pao-addon-content-type-0', + displayAs: '#wc-pao-addon-content-display-0', + titleRequired: '#wc-pao-addon-content-name-0', + formatTitle: '#wc-pao-addon-content-title-format', + enableDescription: 'wc-pao-addon-description-enable-0', + addDescription: '#wc-pao-addon-description-0', + requiredField: '#wc-pao-addon-required-0', + bookingsMultiplyCostByPersonCount: '#addon_wc_booking_person_qty_multiplier_0', + bookingsMultiplyCostByBlockCount: '#addon_wc_booking_block_qty_multiplier_0', + import: '.wc-pao-import-addons', + export: '.wc-pao-export-addons', + excludeAddons: '#\\_product_addons_exclude_global', + expandAll: '.wc-pao-expand-all', + closeAll: '.wc-pao-close-all', + + // Add-Ons Option + enterAnOption: '.wc-pao-addon-content-label > input', + optionPriceType: '.wc-pao-addon-option-price-type', + optionPrice: '.wc-pao-addon-content-price input', + addOption: '.wc-pao-add-option', + removeOptionCrossIcon: '.wc-pao-addon-content-remove > .button', + cancelRemoveOption: '.swal2-cancel', + okRemoveOption: '.swal2-confirm', + + // Other Options + productStatus: '#post_status', + visibility: '#\\_visibility', + purchaseNote: '#\\_purchase_note', + enableProductReviews: '#\\_enable_reviews', + + // Save Product + saveProduct: '.dokan-btn-lg', + }, + + viewBooking: { + productImage: '.woocommerce-product-gallery__image--placeholder img.wp-post-image', + productName: '.product_title.entry-title', + price: '.summary .price .woocommerce-Price-amount.amount', + bookingCalendar: 'div#wc-bookings-booking-form', + bookNow: '.single_add_to_cart_button', + getSupport: '.dokan-store-support-btn', + }, + + // Add Booking + addBooking: { + selectCustomerDropdown: '//span[@id="select2-customer_id-container"]/..//span[@class="select2-selection__arrow"]', + selectCustomerInput: '.select2-search__field', + searchedResult: '.select2-results__option.select2-results__option--highlighted', + selectABookableProductDropdown: '//span[@id="select2-bookable_product_id-container"]/..//span[@class="select2-selection__arrow"]', + selectABookableProduct: (productName: string) => `//li[contains(@class,"select2-results__option") and contains(text(), '${productName}')]`, + + createANewCorrespondingOrderForThisNewBooking: '//input[@name="booking_order" and @value="new"]', + assignThisBookingToAnExistingOrderWithThisId: '//input[@name="booking_order" and @value="existing"]', + bookingOrderId: '.text', + dontCreateAnOrderForThisBooking: '//label[normalize-space()="Don"t create an order for this booking."]/..//input', + next: '.button-primary', + selectCalendarDay: (month: number, day: number) => `//td[@title="This date is available" and @ data-month="${month}"]//a[@data-date="${day}"]`, + + addBooking: 'input[value="Add Booking"][type="submit"]', + + successMessage: '.woocommerce-message', + }, + + // Manage Booking + manageBookings: { + manageBookingsText: '//h1[normalize-space()="Manage Bookings"]', + + // Menus + menus: { + all: '//ul[contains(@class,"order-statuses-filter")]//a[contains(text(),"All")]', + unPaid: '//ul[contains(@class,"order-statuses-filter")]//span[contains(text(),"Un-paid")]/..', + paidAndConfirmed: '//ul[contains(@class,"order-statuses-filter")]//span[contains(text(),"Paid & Confirmed")]/..', + completed: '//ul[contains(@class,"order-statuses-filter")]//span[contains(text(),"Complete")]/..', + }, + + noBookingsFound: '//div[normalize-space()="No Bookings found"]', + + view: '.dokan-btn', + editBookingStatus: '.dokan-edit-status', + selectOrderStatus: '#booking_order_status', + UpdateOrderStatus: '.dokan-btn-success', + cancelUpdateOrderStatus: 'dokan-btn-default', + }, + + // calendar + calendar: { + calendarText: '//h1[normalize-space()="Calendar"]', + calendar: '.wc_bookings_calendar_form', + + filterBookings: '#calendar-bookings-filter', + + month: { + month: '//select[@name="calendar_month"]', + year: '//select[@name="calendar_year"]', + // previous: '.prev', + // next: '.next', + dayView: '.day', + }, + + day: { + calendarDay: '//input[@placeholder="yyyy-mm-dd"]', + monthView: '.month', + }, + }, + + // Manage Resources + manageResources: { + manageResourcesText: '.dokan-dashboard-content h1', + + addNewResource: '.dokan-btn.dokan-right', + + // table + table: { + table: 'table.dokan-table.product-listing-table', + nameColumn: '//th[normalize-space()="Name"]', + parentColumn: '//th[normalize-space()="Parent"]', + }, + + noResourceFound: '//td[normalize-space()="No Resource found"]', + + resource: { + resourceName: '.swal2-input', + cancelAddNewResource: '.swal2-cancel', + confirmAddNewResource: '.swal2-confirm', + resourceRow: (resourceName: string) => `//a[contains(text(),'${resourceName}')]/../..`, + resourceCell: (resourceName: string) => `//a[contains(text(),'${resourceName}')]/..`, + editResource: (resourceName: string) => `//a[contains(text(),'${resourceName}')]/../..//a[contains(text(),'Edit')]`, + deleteResource: (resourceName: string) => `//a[contains(text(),'${resourceName}')]/../..//button[contains(text(),'Remove')]`, + + // Edit Resource + resourceTitle: '#post_title', + availableQuantity: '#\\_wc_booking_qty', + rangeTypeResource: '.wc_booking_availability_type > select', + rangeFromResource: '.from_date > .date-picker', + rangeToResource: '.to_date > .date-picker ', + bookableResource: '//select[contains(@name,"wc_booking_availability_type")]', + priorityResource: '.priority > input', + addRangeResource: '.button', + saveResource: '.dokan-btn-lg', + }, + }, + }, + + // Analytics + vAnalytics: { + analyticsText: '//h1[normalize-space()="Analytics"]', + + // Menus + menus: { + general: '//a[normalize-space()="General"]', + topPages: '//a[normalize-space()="Top pages"]', + location: '//a[normalize-space()="Location"]', + system: '//a[normalize-space()="System"]', + promotions: '//a[normalize-space()="Promotions"]', + keyword: '//a[normalize-space()="Keyword"]', + }, + + datePicker: { + from: '#from', + to: '#to', + show: 'input[value="Show"]', + }, + + noAnalyticsFound: '//div[contains(text(), "There is no analytics found for your store.")]', + }, + + // Announcements + vAnnouncement: { + announcementText: '.dokan-notice-listing h1', + + announcementDiv: '.dokan-announcement-wrapper-item', + announcementDate: '.dokan-annnouncement-date', + announcementHeading: '.dokan-announcement-heading', + announcementContent: '.dokan-announcement-content', + removeAnnouncement: '.remove_announcement', + + announcementLink: (title: string) => `//div[@class="dokan-announcement-heading"]//h3[contains(text(),"${title}")]/..`, + firstAnnouncementLink: (title: string) => `(//div[@class="dokan-announcement-heading"]//h3[contains(text(),"${title}")]/..)[1]`, + deleteAnnouncement: (title: string) => `//div[@class="dokan-announcement-heading"]//h3[contains(text(),"${title}")]/../../../..//a[@class="remove_announcement"]`, + confirmDeleteAnnouncement: '.swal2-confirm', + cancelDeleteAnnouncement: '.swal2-cancel', + + // announcement details + announcement: { + title: '.dokan-notice-single-notice-area .entry-title', + date: '.dokan-single-announcement-date', + content: '.dokan-notice-single-notice-area .entry-content', + backToAllNotice: '//a[normalize-space()="Back to all Notice"]', + }, + }, + + // Tools + vTools: { + toolsText: '//h1[normalize-space()="Tools"]', + + // Menus + menus: { + import: '//ul[@class="dokan_tabs"]//a[contains(text(),"Import")]', + export: '//ul[@class="dokan_tabs"]//a[contains(text(),"Export")]', + }, + + // Import + import: { + // xml + xml: { + importXmlText: '//h1[normalize-space()="Import XML"]', + chooseXmlFile: '//div[@id="import"]//input[@name="import"]', + xml: '//input[@value="Import"]', + completionMessage: '//p[contains(text(), "All done.")]', + }, + + // csv + csv: { + importCsvText: '//h1[normalize-space()="Import CSV"]', + csv: '#import > .dokan-btn', + + chooseCsv: '#upload', + updateExistingProducts: '#woocommerce-importer-update-existing', + continue: '.button', + runTheImporter: '.button', + viewImportLog: '.woocommerce-importer-done-view-errors', + viewProducts: '.button', + completionMessage: '.woocommerce-importer-done', + }, + }, + + // Export + export: { + // xml + xml: { + exportXmlText: '//h1[normalize-space()="Export XML"]', + all: '#export_all', + product: '#export_product', + variation: '#export_variation_product', + exportXml: '//input[@value="Export"]', + }, + + // csv + csv: { + exportCsvText: '//h1[normalize-space()="Export CSV"]', + exportCsv: '#export > .dokan-btn', + whichColumns: '//label[normalize-space()="Which columns should be exported?"]/../..//input[@class="select2-search__field"]', + whichProductTypes: '//label[normalize-space()="Which product types should be exported?"]/../..//input[@class="select2-search__field"]', + customMeta: '#woocommerce-exporter-meta', + generateCsv: '.woocommerce-exporter-button', + }, + }, + }, + + // Auction + vAuction: { + // Menus + menus: { + all: '//ul[contains(@class,"dokan-listing-filter")]//a[contains(text(),"All")]', + online: '//ul[contains(@class,"dokan-listing-filter")]//a[contains(text(),"Online")]', + pendingReview: '//ul[contains(@class,"dokan-listing-filter")]//a[contains(text(),"Pending Review")]', + draft: '//ul[contains(@class,"dokan-listing-filter")]//a[contains(text(),"Draft")]', + }, + + addNewActionProduct: '.dokan-add-product-link .dokan-btn-theme', + actionsActivity: '.button-ml .dokan-btn', + + // Filter + filters: { + dateRange: 'input#auction_date_range', + filter: '//button[normalize-space()="Filter"]', + filterReset: '//a[normalize-space()="Reset"]', + }, + + // Search + search: 'input[name ="search"]', + + // table + table: { + table: 'table.dokan-table.product-listing-table', + imageColumn: '//th[normalize-space()="Image"]', + nameColumn: '//th[normalize-space()="Name"]', + statusColumn: '//th[normalize-space()="Status"]', + sKUColumn: '//th[normalize-space()="SKU"]', + stockColumn: '//th[normalize-space()="Stock"]', + priceColumn: '//th[normalize-space()="Price"]', + typeColumn: '//th[normalize-space()="Type"]', + viewsColumn: '//th[normalize-space()="Views"]', + dateColumn: '//th[normalize-space()="Date"]', + }, + + noAuctionsFound: '//td[normalize-space()="No product found"]', + productCell: (name: string) => `//a[normalize-space()="${name}"]/../..`, + edit: (name: string) => `//a[normalize-space()="${name}"]/../..//span[@class="edit"]`, + permanentlyDelete: (name: string) => `//a[normalize-space()="${name}"]/../..//span[@class="delete"]`, + view: (name: string) => `//a[normalize-space()="${name}"]/../..//span[@class="view"]`, + + confirmDelete: '.swal2-confirm', + cancelDelete: '.swal2-cancel', + dokanSuccessMessage: '.dokan-alert.dokan-alert-success', + + // Create Auction Product + auction: { + // basic info + productName: '.dokan-auction-post-title input[name="post_title"]', + productShortDescription: '#post_excerpt', + ProductImage: '.dokan-feat-image-btn', + uploadProductImage: '#\\__wp-uploader-id-1', + addGalleryImage: '.fa-plus', + uploadGalleryImage: '#\\__wp-uploader-id-4', + category: 'select2-product_cat-container', + categoryValues: '.select2-results ul li', + productTag: '.select2-search__field', + downloadable: '#\\_downloadable', + virtual: '#\\_virtual', + + // General Options + itemCondition: '#\\_auction_item_condition', + auctionType: '#\\_auction_type', + enableProxyBiddingForThisAuctionProduct: '.dokan-form-group > .checkbox > label', + startPrice: '#\\_auction_start_price', + bidIncrement: '#\\_auction_bid_increment', + reservedPrice: '#\\_auction_reserved_price', + buyItNowPrice: '#\\_regular_price', + auctionStartDate: '#\\_auction_dates_from', + auctionEndDate: '#\\_auction_dates_to', + enableAutomaticRelistingForThisAuction: '#\\_auction_automatic_relist', + relistIfFailAfterNHours: '#\\_auction_relist_fail_time', + relistIfNotPaidAfterNHours: '#\\_auction_relist_not_paid_time', + relistAuctionDurationInH: '#\\_auction_relist_duration', + + // Shipping + thisProductRequiresShipping: '#\\_disable_shipping', + weight: '#\\_weight', + length: '#\\_length', + width: '#\\_width', + height: '#\\_height', + shippingClass: '#product_shipping_class', + shippingSettings: '.help-block a', + + // Tax + taxStatus: '#\\_tax_status', + taxClass: '#\\_tax_class', + + // Short Description + shortDescription: '#post-excerpt', + + // Description + productDescriptionIframe: '.dokan-auction-post-content iframe', + productDescriptionHtmlBody: '#tinymce', + + // Add Auction + addAuctionProduct: 'input[value="Add auction Product"]', + updateAuctionProduct: 'input[value="Update Product"]', + }, + + viewAuction: { + productImage: '.woocommerce-product-gallery__image--placeholder img.wp-post-image', + productName: '.product_title.entry-title', + startingOrCurrentBid: '.summary .auction-price .amount', + itemCondition: '.curent-bid', + auctionTime: '#countdown.auction-time', + auctionEnd: '.auction-end', + reversePriceStatus: '.reserve.hold', + + noBidOption: '//div[@class="woocommerce-info" and contains(text(), "You are not allowed to bid your own product.")]', + bidQuantity: 'div.quantity.buttons_added', + bidButton: '.bid_button', + buyNow: '.single_add_to_cart_button', + getSupport: '.dokan-store-support-btn', + + auctionHistoryTab: '#tab-title-simle_auction_history', + }, + + // Auction Activity + actionActivity: { + actionActivityText: '//h1[contains(text(), "Auctions Activity")]', + backToActions: '//a[normalize-space()="Auctions"]', + + // Filter + filters: { + filterByDate: { + dateRangeInput: 'input#auction-activity-datetime-range', + startDateInput: 'input#_auction_dates_from', + endDateInput: 'input#_auction_dates_to', + }, + + filter: 'button[name="auction_activity_date_filter"]', + filterReset: 'button#auction-clear-filter-button', + }, + + // Search + search: { + searchInput: 'input[name="auction_activity_search"]', + search: '.search-box .dokan-btn', + }, + + // table + table: { + table: 'table.dokan-table.product-listing-table', + auctionColumn: '//th[normalize-space()="Auction"]', + userNameColumn: '//th[normalize-space()="User Name"]', + userEmailColumn: '//th[normalize-space()="User Email"]', + bidColumn: '//th[normalize-space()="Bid"]', + dateColumn: '//th[normalize-space()="Date"]', + proxyColumn: '//th[normalize-space()="Proxy"]', + }, + + noActivityFound: '//td[normalize-space()="No Auctions Activity Found!"]', + numOfRowsFound: '.dokan-table.product-listing-table tbody tr', + }, + }, + + // Support + vSupport: { + // Menus + menus: { + allTickets: '//ul[contains(@class,"dokan-support-topic-counts")]//a[contains(text(), "All Tickets")]', + openTickets: '//ul[contains(@class,"dokan-support-topic-counts")]//a[contains(text(), "Open Tickets")]', + closedTickets: '//ul[contains(@class,"dokan-support-topic-counts")]//a[contains(text(), "Closed Tickets")]', + }, + + // Filter + filters: { + filterByCustomer: '//select[@id="dokan-search-support-customers"]/..//span[@class="select2-selection__arrow"]', + filterByCustomerInput: '.select2-search__field', + + filterByDate: { + dateRangeInput: 'input#support_ticket_date_filter', + startDateInput: 'input#support_ticket_start_date_filter_alt', + endDateInput: 'input#support_ticket_end_date_filter_alt', + }, + + tickedIdOrKeyword: '#dokan-support-ticket-search-input', + search: '//input[@class="dokan-btn" and @value="Search"]', + result: '.select2-results__option.select2-results__option--highlighted', + }, + + // table + table: { + table: '.dokan-support-table', + topicColumn: '//th[normalize-space()="Topic"]', + titleColumn: '//th[normalize-space()="Title"]', + customerColumn: '//th[normalize-space()="Customer"]', + statusColumn: '//th[normalize-space()="Status"]', + dateColumn: '//th[normalize-space()="Date"]', + actionColumn: '//th[normalize-space()="Action"]', + }, + + numOfRowsFound: 'table.dokan-support-table tbody tr', + noSupportTicketFound: '//div[@class="dokan-error" and contains(text(), "No tickets found!")]', + storeSupportLink: (id: string) => `//strong[normalize-space()="#${id}"]/..`, + storeSupportCellById: (id: string) => `//strong[normalize-space()="#${id}"]/../..`, + storeSupportCellByTitle: (title: string) => `//a[normalize-space()="${title}"]/..`, + storeSupportsCellByCustomer: (customerName: string) => `//strong[contains(text(),'${customerName}')]/../..`, + + supportTicketDetails: { + backToTickets: '.dokan-dashboard-content > a', + + basicDetails: { + basicDetailsDiv: 'div.dokan-support-single-title', + ticketTitle: '//span[contains(@class,"dokan-chat-title") and not(contains(@class,"dokan-chat-status"))]', + ticketId: 'span.dokan-chat-title.dokan-chat-status', + }, + + chatStatus: { + status: 'div.dokan-chat-status-box span.dokan-chat-status', + open: 'div.dokan-chat-status-box span.dokan-chat-status.chat-open', + closed: 'div.dokan-chat-status-box span.dokan-chat-status.chat-closed', + }, + + orderReference: { + orderReferenceSpan: 'span.order-reference', + orderReferenceText: (orderId: string) => `//strong[normalize-space()="Referenced Order #${orderId}"]`, + orderReferenceLink: (orderId: string) => `//strong[normalize-space()="Referenced Order #${orderId}"]/..`, + }, + + chatBox: { + mainChat: 'div.dokan-dss-chat-box.main-topic', + otherChats: 'ul.dokan-support-commentlist', + }, + + replyBox: { + addReplyText: '//strong[normalize-space()="Add Reply"]', + closeTicketText: '//strong[normalize-space()="Ticket Closed"]', + replyBoxDiv: 'div.dokan-panel.dokan-panel-default.dokan-dss-panel-default', + addReply: '#dokan-support-commentform #comment', + submitReply: '#submit', + }, + }, + + // Manage Ticket + + ticketStatus: 'div.dokan-chat-status-box span.dokan-chat-status', + chatReply: '#comment', + changeStatus: 'select.dokan-support-topic-select', // 1 + submitReply: '#submit', + okEmptySubmit: '.swal2-confirm', + + // Close Ticket + closeTicket: '//td[@data-title="Action"]//a[contains(@class, "dokan-support-status-change") and @data-original-title="Close Topic" ]', + + // reOpen Ticket + reOpenTicket: '//td[@data-title="Action"]//a[contains(@class, "dokan-support-status-change") and @data-original-title="Re-open Topic" ]', + + confirmCloseTicket: '.swal2-confirm', + cancelCloseTicket: '.swal2-cancel', + }, + + // Vendor Account Details + vAccountDetails: { + firstName: '#account_first_name', + lastName: '#account_last_name', + email: '#account_email', + currentPassword: '#password_current', + NewPassword: '#password_1', + confirmNewPassword: '#password_2', + saveChanges: '.dokan-btn', + saveSuccessMessage: 'Account details changed successfully.', + }, + + // Search Similar Product + vSpmv: { + // Search similar product spmv + search: { + searchDiv: '.dokan-spmv-add-new-product-search-box-area', + subHeader: '//p[@class="sub-header"]', + toggleBtn: '#dokan-spmv-area-toggle-button', + // toggleBtn: '#dokan-spmv-area-toggle-button i.fa-caret-down', + searchInput: 'input[name="search"]', + search: 'input.dokan-btn-search', + orCreateNew: '.dokan-spmv-add-new-product-search-box-area .dokan-product-listing a', + }, + + // table + table: { + table: '#dokan-spmv-product-list-table', + productNameColumn: '//th[normalize-space()="Product Name"]', + priceColumn: '//th[normalize-space()="Price"]', + vendorColumn: '//th[normalize-space()="Vendor"]', + actionsColumn: '//th[normalize-space()="Actions"]', + }, + + noProductsFound: '//td[normalize-space()="No product found."]', + numberOfRowsFound: '#dokan-spmv-product-list-table tbody tr', + resultCount: '.woocommerce-result-count', + sortProduct: 'select.orderby', // popularity, rating, date, price, price-desc, bid_asc, bid_desc, auction_end, auction_started, auction_activity + editProduct: (productName: string) => `//a[normalize-space()="${productName}"]/../../..//a[@class="dokan-btn"]`, + addToStore: 'button.dokan-spmv-clone-product', + + productDetails: { + sellThisItem: 'button[name="dokan_sell_this_item"]', + }, + }, + + // Settings + vSettings: { + store: '.store > a', + addons: '.product-addon > a', + payment: '.payment > a', + verification: '.verification > a', + deliveryTime: '.delivery-time > a', + shipping: '.shipping > a', + shipStation: '.shipstation > a', + socialProfile: '.social > a', + rma: '.rma > a', + storeSEO: '.seo > a', + }, + + // Store Settings + vStoreSettings: { + settingsText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + // Wp Image Upload + wpUploadFiles: '#menu-item-upload', + uploadedMedia: '.attachment-preview', + selectFiles: '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[@class="browser button button-hero"]', + select: '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[contains(@class, "media-button-select")]', + crop: '//div[@class="supports-drag-drop" and @style="position: relative;"]//button[contains(@class, "media-button-insert")]', + + // Banner and Profile Image + banner: '.dokan-banner .dokan-banner-drag', + bannerImage: '//div[@class="image-wrap"]//img[@class="dokan-banner-img"]', + removeBannerImage: '.close.dokan-remove-banner-image', + profilePicture: '.dokan-pro-gravatar-drag', + profilePictureImage: '//div[@class="dokan-left gravatar-wrap"]//img[@class="dokan-gravatar-img"]', + removeProfilePictureImage: '.dokan-close.dokan-remove-gravatar-image', + + // Basic Store Info + storeName: '#dokan_store_name', + phoneNo: '#setting_phone', + + // store categories + storeCategories: { + storeCategoryDropDown: '//label[contains(text(), "Store Category")]/..//span[@class="select2-selection__arrow"]', + storeCategoryInput: '//span[@class="select2-search select2-search--dropdown"]//input[@role="searchbox"]', + storeCategoriesInput: '//label[contains(text(), "Store Categories")]/..//input[@class="select2-search__field"]', + result: '.select2-results__option.select2-results__option--highlighted', + }, + + multipleLocation: '#multiple-store-location', + addLocation: '#show-add-store-location-section-btn', + editLocation: '.store-pickup-location-edit-btn', + locationName: '#store-location-name-input', + + // Address + address: { + street: '#dokan_address\\[street_1\\]', + street2: '#dokan_address\\[street_2\\]', + city: '#dokan_address\\[city\\]', + postOrZipCode: '#dokan_address\\[zip\\]', + country: '#dokan_address_country', + state: '#dokan-states-box #dokan_address_state', + saveLocation: '#dokan-save-store-location-btn', + cancelSaveLocation: '#cancel-store-location-section-btn', + deleteSaveLocation: '.store-pickup-location-delete-btn', + }, + + // Company Info + companyInfo: { + companyName: '#settings_dokan_company_name', + companyId: '#settings_dokan_company_id_number', + vatOrTaxNumber: '#setting_vat_number', + nameOfBank: '#setting_bank_name', + bankIban: '#setting_bank_iban', + }, + + // Email + email: '//label[contains(text(), "Email")]/..//input[@type="checkbox"]', + + // Map + map: '#dokan-map-add', + + // Terms and Conditions + termsAndConditions: '//label[contains(text(), "Terms and Conditions")]/..//input[@type="checkbox"]', + termsAndConditionsIframe: '#dokan_tnc_text iframe', + termsAndConditionsHtmlBody: '#tinymce', + + // Store Opening Closing Time + storeOpeningClosingTime: '#dokan-store-time-enable', + + // lite locators + lite: { + openingClosingTimeEnable: (day: string) => `select[name="${day}[working_status]"]`, + openingTimeInput: (day: string) => `input#opening-time\\[${day}\\]`, + closingTimeInput: (day: string) => `input#closing-time\\[${day}\\]`, + }, + // openingTime: (day: string) => `#opening-time-${day}`, + // closingTime: (day: string) => `#closing-time-${day}`, + // addNewRow: (day: string) => `#store-tab-${day} .added-store-opening-time > .fa`, + // deleteOneRow: '.remove-store-closing-time > .fa', + openingClosingTimeSwitch: (day: string) => `//label[@for='${day}-working-status']/p[@class='switch tips']`, + openingTime: (day: string) => `input#opening-time-${day}`, + openingTimeHiddenInput: (day: string) => `//input[@name='opening_time[${day}][]']`, + closingTime: (day: string) => `input#closing-time-${day}`, + closingTimeHiddenInput: (day: string) => `//input[@name='closing_time[${day}][]']`, + storeOpenNotice: '//input[@name="dokan_store_open_notice"]', + storeCloseNotice: '//input[@name="dokan_store_close_notice"]', + + // Vacation + goToVacation: '#dokan-seller-vacation-activate', + closingStyle: 'label .form-control', + setVacationMessageInstantly: '//textarea[@id="dokan-seller-vacation-message" and @name="setting_vacation_message"]', + setVacationMessageDatewise: '//textarea[@id="dokan-seller-vacation-message" and @name="dokan_seller_vacation_datewise_message"]', + vacationDateRange: '#dokan-seller-vacation-date-from-range', + vacationDateRangeFrom: 'input#dokan-seller-vacation-date-from', + vacationDateRangeTo: 'input#dokan-seller-vacation-date-to', + saveVacationEdit: '#dokan-seller-vacation-save-edit', + cancelVacationEdit: '#dokan-seller-vacation-cancel-edit', + noVacationIsSet: '//td[contains( text(),"No vacation is set")]', + vacationRow: '//td[@class="dokan-seller-vacation-list-action"]/..', + editSavedVacationSchedule: '.dokan-seller-vacation-list-action .fas', + deleteSavedVacationSchedule: '.dokan-seller-vacation-remove-schedule', + confirmDeleteSavedVacationSchedule: '.swal2-confirm', + cancelDeleteSavedVacationSchedule: '.swal2-cancel', + + // catalog mode + removeAddToCartButton: 'input#catalog_mode_hide_add_to_cart_button', + hideProductPrice: 'input#catalog_mode_hide_product_price', + enableRequestQuoteSupport: 'input#catalog_mode_request_a_quote_support', + + // Discount + enableStoreWideDiscount: '#lbl_setting_minimum_quantity', + minimumOrderAmount: '#setting_minimum_order_amount', + percentage: '#setting_order_percentage', + + // Biography + biographyIframe: '#wp-vendor_biography-wrap iframe', + biographyHtmlBody: '#tinymce', + + // Store Support + showSupportButtonInStore: '#support_checkbox', + showSupportButtonInSingleProduct: '#support_checkbox_product', + supportButtonText: '#dokan_support_btn_name', + + // Min-Max + enableMinMaxQuantities: '#enable_vendor_min_max_quantity', + minimumProductQuantityToPlaceAnOrder: '#min_quantity_to_order', + maximumProductQuantityToPlaceAnOrder: '#max_quantity_to_order', + enableMinMaxAmount: '#enable_vendor_min_max_amount', + minimumAmountToPlaceAnOrder: '#min_amount_to_order', + maximumAmountToPlaceAnOrder: '#max_amount_to_order', + selectProducts: '//label[contains(text(), "Select Products")]/..//input[contains(@class,"select2-search__field")]', + selectAll: '.dokan-min-max-product-select-all', + clear: '.dokan-min-max-product-clear-all', + selectCategory: 'select#product_cat', + selectCategorySearch: '//select[@id="product_cat"]/..//input[@class="select2-search__field"]', + selectCategorySearchedResult: '.select2-results__option.select2-results__option--highlighted', + alreadySelectedOption: (option: string) => `//li[@class="select2-selection__choice" and @title="${option}"]`, + + // Update Settings + updateSettingsTop: 'button.dokan-update-setting-top-button', + updateSettings: '//input[@name="dokan_update_store_settings"]', + updateSettingsSuccessMessage: '.dokan-alert.dokan-alert-success p', + }, + + // addon settings + vAddonSettings: { + productAddonsText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + createNewAddon: '.dokan-pa-all-addons .dokan-btn', + createNew: '//a[normalize-space()="Create New"]', + + // table + table: { + addonTable: '#global-addons-table', + nameColumn: 'th[scope="col"]', + priorityColumn: '//th[normalize-space()="Priority"]', + productCategoriesColumn: '//th[normalize-space()="Product Categories"]', + numberOfFieldsColumn: '//th[normalize-space()="Number of Fields"]', + }, + + noRowsFound: '//td[normalize-space()="No add-ons found."]', + firstAddonRow: '#the-list tr td .edit a', + addonRow: (addon: string) => `//a[contains(text(), '${addon}')]/../..`, + editAddon: (addon: string) => `//a[contains(text(), '${addon}')]/..//a[contains(text(), 'Edit')]`, + deleteAddon: (addon: string) => `//a[contains(text(), '${addon}')]/..//a[contains(text(), 'Delete')]`, + + backToAddonLists: '.back-to-addon-lists-btn', + + addon: { + name: '#addon-reference', + priority: '#addon-priority', + productCategories: '.select2-search__field', + + // Addon fields + addonFieldsRow: (addonField: string) => `//h3[@class="wc-pao-addon-name" and contains(text(), "${addonField}")]/../..//span[@class="wc-pao-addon-toggle"]`, + addField: '.wc-pao-add-field', + type: 'select.wc-pao-addon-type-select', + displayAs: '.wc-pao-addon-display-select', + titleRequired: '.wc-pao-addon-content-name', + formatTitle: '#wc-pao-addon-content-title-format', + enableDescription: '.wc-pao-addon-description-enable', + addDescription: '.wc-pao-addon-description.show', + requiredField: '.wc-pao-addon-required-setting input', + enterAnOption: '//input[@placeholder="Enter an option"]', + optionPriceType: '.wc-pao-addon-option-price-type', + optionPriceInput: '.wc-pao-addon-content-price .wc_input_price', + import: '.wc-pao-import-addons', + export: '.wc-pao-export-addons', + expandAll: '.wc-pao-expand-all', + closeAll: '.wc-pao-close-all', + publishOrUpdate: '#submit', + addonUpdateSuccessMessage: '.dokan-alert.dokan-alert-success', + }, + }, + + // Payment Settings + vPaymentSettings: { + paymentMethodText: '.dokan-dashboard-content.dokan-settings-content h1', + + paymentMethods: { + paymentMethodsDiv: '.dokan-payment-settings-summary', + addPaymentMethodDropDown: '#toggle-vendor-payment-method-drop-down', + noOfPaymentMethods: '//button[contains(text(),"Manage")]', + }, + + // Paypal + paypal: '.payment-field-paypal .dokan-form-control', + + // Bank Transfer + bankAccountName: '//input[@name="settings[bank][ac_name]"]', + bankAccountType: '#ac_type', + bankAccountNumber: '//input[@name="settings[bank][ac_number]"]', + bankName: '//input[@name="settings[bank][bank_name]"]', + bankAddress: '//textarea[@name="settings[bank][bank_addr]"]', + bankRoutingNumber: '//input[@name="settings[bank][routing_number]"]', + bankIban: '//input[@name="settings[bank][iban]"]', + bankSwiftCode: '//input[@name="settings[bank][swift]"]', + declaration: '#declaration', + addAccount: 'button.save.dokan-btn', + disconnectAccount: 'button.dokan_payment_disconnect_btn', + + // Skrill + skrill: '//input[@name="settings[skrill][email]"]', + + // Custom Payment Method + customPayment: '//input[@name="settings[dokan_custom][value]"]', + + // payment email + paymentEmail: 'input.dokan-form-control', + + // disconnect + disconnectPayment: '//button[normalize-space()="Disconnect"]', + + // Update Settings + updateSettings: 'input.dokan-btn', + updateSettingsSuccessMessage: '.dokan-alert.dokan-alert-success p', + + // Stripe + ConnectWithStripe: '.dokan-stripe-connect-link', + + // Paypal Marketplace + paypalMarketplace: '#vendor_paypal_email_address', + paypalMarketplaceSigUp: '.vendor_paypal_connect', + + // Razorpay + rzSignup: '.vendor_razorpay_connect', + rzClosePopup: '.mfp-close', // todo: need to update, everywhere + // Existing Account Info + rzIHaveAlreadyAnAccount: '#dokan_razorpay_existing_user_chekbox', + rzAccountId: '#dokan_razorpay_account_id', + rzConnectExistingAccount: '#dokan_razorpay_vendor_register_button', + // New Account Info + rzAccountName: '#razorpay_account_name', + rzAccountEmail: '#razorpay_account_email', + rzYourCompanyName: '#razorpay_business_name', + rzYourCompanyType: '#razorpay_business_type', + rzBankAccountName: '#razorpay_beneficiary_name', + rzBankAccountNumber: '#razorpay_account_number', + rzBankIfscCode: '#razorpay_ifsc_code', + rzBankAccountType: '#razorpay_account_type', + rzConnectAccount: '#dokan_razorpay_vendor_register_button', + + // Mangopay + // Mangopay Payment Setup Options + accountForm: '.dokan-mp-account', + bankAccount: '.dokan-mp-bank', + verification: '.dokan-mp-verification', + eWallets: '.dokan-mp-wallets', + + // Connect & Account Info + dateOfBirth: '#dokan-mangopay-user-birthday', + nationality: '#dokan-mangopay-user-nationality', + typeOfUser: '#dokan-mangopay-user-status', + typeOfBusiness: '#dokan-mangopay-business-type', + companyNumber: '#dokan-mangopay-company-number', + address: '#dokan-mangopay-address1', + addressDetails: '#dokan-mangopay-address2', + country: '#dokan-mangopay-country', + state: '#dokan-mangopay-state', + city: '#dokan-mangopay-city', + postcode: '#dokan-mangopay-postcode', + connect: '#dokan-mangopay-account-connect', + disconnect: '#dokan-mangopay-account-disconnect', + update: '#dokan-mangopay-account-connect', + // Bank Account + addNew: '#dokan-mp-bank-account-add-new', + accountType: '#dokan-mangopay-vendor-acccount-type', + // Iban + ibanIban: '#dokan-mangopay-vendor-acccount-IBAN-iban', + ibanBic: '#dokan-mangopay-vendor-acccount-IBAN-bic', + // Gb + gbAccountNumber: '#dokan-mangopay-vendor-acccount-GB-account_number', + gbSortCode: '#dokan-mangopay-vendor-acccount-GB-sort_code', + // Us + usAccountNumber: '#dokan-mangopay-vendor-acccount-US-account_number', + usAba: '#dokan-mangopay-vendor-acccount-US-aba', + usDepositAccountType: '#dokan-mangopay-vendor-acccount-US-datype', + // Ca + caBankName: '#dokan-mangopay-vendor-acccount-CA-bank_name', + caInstitutionNumber: '#dokan-mangopay-vendor-acccount-CA-inst_number', + caBranchCode: '#dokan-mangopay-vendor-acccount-CA-branch_code', + caAccountNumber: '#dokan-mangopay-vendor-acccount-CA-account_number', + // Others + othersCountry: '#dokan-mangopay-vendor-acccount-OTHER-country', + othersBic: '#dokan-mangopay-vendor-acccount-OTHER-bic', + othersAccountNumber: '#dokan-mangopay-vendor-acccount-OTHER-account_number', + // Account Holders Details + accountHolderDetails: { + accountHoldersName: '#dokan-mangopay-vendor-account-name', + accountHoldersAddress: '#dokan-mangopay-vendor-account-address1', + accountHoldersAddressDetails: '#dokan-mangopay-vendor-account-address2', + accountHoldersCountry: '#dokan-mangopay-vendor-account-country', + accountHoldersState: '#dokan-mangopay-vendor-account-state', + city: '#dokan-mangopay-vendor-account-city', + postcode: '#dokan-mangopay-vendor-account-postcode', + submit: '#dokan-mp-bank-account-create', + cancel: '#dokan-mp-bank-account-cancel', + }, + + // Verification + kyc: { + documentType: '#dokan-kyc-file-type', + chooseFiles: '#dokan-kyc-file', + // Ubo + Ubo: { + createAnUboDeclaration: '#ubo_create_declaration_button', + addUbo: '#ubo_add_button', + FirstName: '#dokan_mp_first_name', + LastName: '#dokan_mp_last_name', + DateOfBirth: '#dokan_mp_birthday', + Nationality: '#dokan_mp_nationality', + Address: '#dokan_mp_address_line1', + AddressDetails: '#dokan_mp_address_line2', + Country: '#dokan_mp_country', + State: '#dokan_mp_region', + City: '#dokan_mp_city', + Postcode: '#dokan_mp_postal_code', + BirthplaceCity: '#dokan_mp_birthplace_city_field', + BirthplaceCountry: '#dokan_mp_birthplace_country_field', + sendUbo: 'add_button_ubo_element', + cancelUbo: 'cancel_button_ubo_element', + }, + submit: '#dokan-mangopay-submit-kyc', + }, + }, + + // Verification Settings + vVerificationSettings: { + 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', + }, + }, + + // Delivery Time Settings + vDeliveryTimeSettings: { + settingsText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + // Delivery Support + homeDelivery: '//input[@type="checkbox" and @name="delivery"]', + storePickup: '#enable-store-location-pickup', + deliveryBlockedBuffer: '#pre_order_date', + timeSlot: '#delivery_time_slot', + orderPerSlot: '#order_per_slot', + + // Delivery Day + deliveryDaySwitches: '.dokan-status p.switch.tips', + deliveryDaySwitch: (day: string) => `//label[@for='${day}-working-status']//p[@class='switch tips']`, + deliveryDaySwitchColor: (day: string) => `//label[@for='${day}-working-status']//p[@class='switch tips']//div[contains(@class,'minitoggle')]`, + + // Individual Day Settings + openingTime: (day: string) => `input#delivery-opening-time-${day}`, + openingTimeHiddenInput: (day: string) => `//input[@name='delivery_opening_time[${day}][]']`, + closingTime: (day: string) => `input#delivery-closing-time-${day}`, + closingTimeHiddenInput: (day: string) => `//input[@name='delivery_closing_time[${day}][]']`, + + closeDeliveryTime: (day: string) => `//label[normalize-space()="${helpers.capitalize(day)}" and @for="working-days"]/..//a[@class="remove-store-closing-time"]`, + addHours: (day: string) => `//label[normalize-space()="${helpers.capitalize(day)}" and @for="working-days"]/..//a[@class="added-store-opening-time "]`, + + updateSettings: '.dokan-btn.dokan-btn-danger.dokan-btn-theme', + settingsSuccessMessage: '.dokan-message strong', + }, + + // Shipping Settings + vShippingSettings: { + shippingSettingsText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + // Shipping Policies + shippingPolicies: { + clickHereToAddShippingPolicies: '//a[normalize-space()="Click here to add Shipping Policies"]', + backToZoneList: '.router-link-active', + processingTime: '#shipping-settings #dps_pt', + shippingPolicy: '#shipping-settings #_dps_shipping_policy', + refundPolicy: '//label[normalize-space()="Refund Policy"]/..//textarea[@class="dokan-form-control"]', + saveSettings: '.dokan-btn-danger', + }, + + // table + table: { + shippingZone: '.shipping-zone-table', + zoneNameColumn: '//th[normalize-space()="Zone Name"]', + regionsColumn: '//th[normalize-space()="Region(s)"]', + shippingMethodColumn: '//th[normalize-space()="Shipping Method"]', + }, + + // Zone-wise Shipping Settings + ZonWiseAddShippingMethod: (zone: string) => `//a[contains(text(),'${zone}')]/../..//a[contains(text(),'Add Shipping Method')]`, + shippingZoneCell: (shippingZone: string) => `//a[contains(text(), '${shippingZone}')]/..`, + editShippingZone: (shippingZone: string) => `//a[contains(text(), '${shippingZone}')]/..//div//a[contains(text(), 'Edit')]`, + addShippingMethod: '//a[contains(text(),"Add Shipping Method")]', + shippingMethod: '#shipping_method', + shippingMethodPopupAddShippingMethod: '.button.button-primary.button-large', + shippingMethodCell: (shippingMethodName: string) => `//td[contains(text(),'${shippingMethodName}')]/..`, + editShippingMethod: (shippingMethodName: string) => `//td[contains(text(),'${shippingMethodName}')]/..//div//a[contains(text(), 'Edit')]`, + deleteShippingMethod: (shippingMethodName: string) => `//td[contains(text(),'${shippingMethodName}')]/..//div//a[contains(text(), 'Delete')]`, + + // Edit Shipping Methods + // Flat Rate + flatRateMethodTitle: '#method_title', + flatRateCost: '#method_cost', + flatRateTaxStatus: '#method_tax_status', + flatRateDescription: '#method_description', + flatRateNoShippingClassCost: '#no_class_cost', + flatRateCalculationType: '#calculation_type', + // Free Shipping + freeShippingTitle: '#method_title', + freeShippingMinimumOrderAmount: '#minimum_order_amount', + // Local Pickup + localPickupTitle: '#method_title', + localPickupCost: '#method_cost', + localPickupTaxStatus: '#method_tax_status', + localPickupDescription: '#method_description', + // Dokan Table Rate Shipping + tableRateShippingMethodTitle: '#table_rate_title', + tableRateShippingTaxStatus: '//select[@name="table_rate_tax_status"]', + tableRateShippingTaxIncludedInShippingCosts: '//select[@name="table_rate_prices_include_tax"]', + tableRateShippingHandlingFee: '#table_rate_order_handling_fee', + tableRateShippingMaximumShippingCost: '#table_rate_max_shipping_cost', + // Rates + tableRateShippingCalculationType: '#dokan_table_rate_calculation_type', + tableRateShippingHandlingFeePerOrder: '#dokan_table_rate_handling_fee', + tableRateShippingMinimumCostPerOrder: '#dokan_table_rate_min_cost', + tableRateShippingMaximumCostPerOrder: '#dokan_table_rate_max_cost', + tableRateShippingUpdateSettings: '//input[@name="dokan_update_table_rate_shipping_settings"]', + tableRateShippingUpdateSettingsSuccessMessage: '.dokan-message Strong', + // Dokan Distance Rate Shipping + distanceRateShippingMethodTitle: '#distance_rate_title', + distanceRateShippingTaxStatus: '#distance_rate_tax_status', + distanceRateShippingTransportationMode: '#dokan_distance_rate_mode', + distanceRateShippingAvoid: '#dokan_distance_rate_avoid', + distanceRateShippingDistanceUnit: '#dokan_distance_rate_unit', + distanceRateShippingShowDistance: '#dokan_distance_rate_show_distance', + distanceRateShippingShowDuration: '#dokan_distance_rate_show_duration', + // Shipping Address + distanceRateShippingAddress1: '#dokan_distance_rate_address_1', + distanceRateShippingAddress2: '#dokan_distance_rate_address_2', + distanceRateShippingCity: '#dokan_distance_rate_city', + distanceRateShippingZipOrPostalCode: '#dokan_distance_rate_postal_code', + distanceRateShippingStateOrProvince: '#dokan_distance_rate_state_province', + distanceRateShippingCountry: '#dokan_distance_rate_country', + distanceRateShippingUpdateSettings: '//input[@name="dokan_update_distance_rate_shipping_settings"]', + distanceRateShippingUpdateSettingsSuccessMessage: '.dokan-message Strong', + // Edit save Shipping Settings + shippingSettingsSaveSettings: '.button.button-primary.button-large', + + // Save Changes + saveChanges: '//input[@value="Save Changes"]', + updateSettingsSuccessMessage: '.dokan-alert.dokan-alert-success span', + + // Previous Shipping Settings + previousShippingSettings: { + previousShippingSettings: '//a[contains( text(), "Click Here")]', + backToZoneWiseShippingSettings: '.dokan-page-help a', + enableShipping: '//input[@type="checkbox" and @name="dps_enable_shipping"]', + defaultShippingPrice: '#shipping_type_price', + perProductAdditionalPrice: '#additional_product', + perQtyAdditionalPrice: '#additional_qty', + processingTime: '#dps_pt', + shippingPolicy: '//label[contains(text(),"Shipping Policy")]/..//textarea[@name="dps_ship_policy"]', + refundPolicy: '//label[contains(text(),"Refund Policy")]/..//textarea[@name="dps_refund_policy"]', + shipsFrom: '//select[@name="dps_form_location"]', + shipTo: '(//select[@name="dps_country_to[]"])[1]', + cost: '(//input[@name="dps_country_to_price[]"])[1]', + addLocation: '.dokan-btn-default', + previousShippingSaveSettings: '//input[@name="dokan_update_shipping_options"]', + }, + }, + + // shipStation settings + vShipStationSettings: { + shipStationText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + authenticationKey: '//label[normalize-space()="Authentication Key"]/..//code', + selectedStatus: '//label[@for="dokan-shipstation-export-statuses"]/..//li[@class="select2-selection__choice"]', + exportOrderStatusesInput: '//label[normalize-space()="Export Order Statuses"]/..//span[@class="select2-selection select2-selection--multiple"]//input[@class="select2-search__field"]', + shippedOrderStatusDropdown: '.select2-selection__arrow', + shippedOrderStatusInput: '(//input[@class="select2-search__field"])[2]', + result: '.select2-results__option.select2-results__option--highlighted', + + saveChanges: '#dokan-store-shipstation-form-submit', + saveSuccessMessage: '#swal2-html-container', + successOk: '.swal2-confirm', + }, + + // social profile settings + vSocialProfileSettings: { + socialProfileText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + platforms: { + facebook: '#settings\\[social\\]\\[fb\\]', + twitter: '#settings\\[social\\]\\[twitter\\]', + pinterest: '#settings\\[social\\]\\[pinterest\\]', + linkedin: '#settings\\[social\\]\\[linkedin\\]', + youtube: '#settings\\[social\\]\\[youtube\\]', + instagram: '#settings\\[social\\]\\[instagram\\]', + flickr: '#settings\\[social\\]\\[flickr\\]', + }, + + // updateSettings: '.dokan-btn.dokan-btn-danger.dokan-btn-theme', + updateSettings: 'input[value="Update Settings"]', + // updateSettings: "//input[@name='dokan_update_profile_settings']/..", + // updateSettings: "//input[@class='dokan-btn dokan-btn-danger dokan-btn-theme']/..", + updateSettingsSuccessMessage: '.dokan-alert.dokan-alert-success p', + }, + + // rma settings + vRmaSettings: { + returnAndWarrantyText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + label: '#dokan-rma-label', + type: '#dokan-warranty-type', + length: '#dokan-warranty-length', + lengthValue: '//input[@name="warranty_length_value"]', + lengthDuration: '#dokan-warranty-length-duration', + refundReasons: '#dokan-store-rma-form .checkbox input', + refundReasonsFirst: '(//form[@id="dokan-store-rma-form"]//div[@class="checkbox"]//input)[1]', + refundPolicyIframe: 'iframe', + refundPolicyHtmlBody: '#tinymce', + saveChanges: '#dokan-store-rma-form-submit', + updateSettingsSuccessMessage: '.dokan-alert.dokan-alert-success', + }, + + // Store Seo Settings + vStoreSeoSettings: { + storeSeoText: '.dokan-settings-content h1', + visitStore: '//a[normalize-space()="Visit Store"]', + + seoTitle: '#dokan-seo-meta-title', + metaDescription: '#dokan-seo-meta-desc', + metaKeywords: '#dokan-seo-meta-keywords', + + facebook: { + facebookTitle: '#dokan-seo-og-title', + facebookDescription: '#dokan-seo-og-desc', + facebookImage: '//label[contains( text(), "Facebook Image :")]/..//a[contains(@class, "dokan-gravatar-drag")]', + }, + + twitter: { + twitterTitle: '#dokan-seo-twitter-title', + twitterDescription: '#dokan-seo-twitter-desc', + twitterImage: '//label[contains( text(), "Twitter Image")]/..//a[contains(@class, "dokan-gravatar-drag")]', + }, + + saveChanges: '#dokan-store-seo-form-submit', + updateSettingsSuccessMessage: '.dokan-alert.dokan-alert-success', + }, + }, + + // Customer + + customer: { + // Customer Registration + cRegistration: { + regEmail: '#reg_email', + regPassword: '#reg_password', + regAsCustomer: '//input[@value="customer"]', + regCustomerWelcomeMessage: '//div[@class="woocommerce-MyAccount-content"]//p[contains(text(),"Hello")]', + // Register Button + register: '.woocommerce-Button', + }, + + // Customer Home Menus + cHomeMenus: { + home: '//ul[@class="nav-menu"]//a[contains(text(),"Home")]', + cart: '//ul[@class="nav-menu"]//a[contains(text(),"Cart")]', + checkout: '//ul[@class="nav-menu"]//a[contains(text(),"Checkout")]', + dashboard: '//ul[@class="nav-menu"]//a[contains(text(),"Dashboard")]', + myAccount: '//ul[@class="nav-menu"]//a[contains(text(),"My account")]', + myOrders: '//ul[@class="nav-menu"]//a[contains(text(),"My Orders")]', + requestForQuote: '//ul[@class="nav-menu"]//a[contains(text(),"Request for Quote")]', + samplePage: '//ul[@class="nav-menu"]//a[contains(text(),"Sample Page")]', + shop: '//ul[@class="nav-menu"]//a[contains(text(),"Shop")]', + storeList: '//ul[@class="nav-menu"]//a[contains(text(),"Store List")]', + }, + + // Customer My Account + cMyAccount: { + dashboard: '.woocommerce-MyAccount-navigation-link--dashboard a', + orders: '.woocommerce-MyAccount-navigation-link--orders a', + subscriptions: '.woocommerce-MyAccount-navigation-link--subscriptions a', + downloads: '.woocommerce-MyAccount-navigation-link--downloads a', + addresses: '.woocommerce-MyAccount-navigation-link--edit-address a', + paymentMethods: '.woocommerce-MyAccount-navigation-link--payment-methods a', + rmaRequests: '.woocommerce-MyAccount-navigation-link--rma-requests a', + accountDetails: '.woocommerce-MyAccount-navigation-link--edit-account a', + vendors: 'woocommerce-MyAccount-navigation-link--following a', + sellerSupportTickets: '.woocommerce-MyAccount-navigation-link--support-tickets a', + bookings: '.woocommerce-MyAccount-navigation-link--bookings a', + auctions: '.woocommerce-MyAccount-navigation-link--auctions-endpoint a', + logout: '.woocommerce-MyAccount-navigation-link--customer-logout a', + }, + + // Customer Dashboard + cDashboard: { + // Become Vendor + becomeVendor: '//a[contains(text(),"Become a Vendor")]', + firstName: '#first-name', + lastName: '#last-name', + shopName: '#company-name', + shopUrl: '#seller-url', + address: '#seller-address', + phone: '#shop-phone', + companyName: '#dokan-company-name', + companyId: '#dokan-company-id-number', + vatNumber: '#dokan-vat-number', + bankName: '#dokan-bank-name', + bankIban: '#dokan-bank-iban', + termsAndConditions: '#tc_agree', + subscriptionPack: '#dokan-subscription-pack', + becomeAVendor: '.dokan-btn', + + // Become Wholesale Customer + becomeWholesaleCustomer: '#dokan-become-wholesale-customer-btn', + wholesaleRequestReturnMessage: '.dokan-wholesale-migration-wrapper div.woocommerce-info', + }, + + // Customer Orders + cOrders: { + // Request Warranty + requestWarranty: { + view: (orderNumber: string) => `//a[contains(text(),'${orderNumber}')]/../..//a[contains(@class,'woocommerce-button button view')]`, + recentOrdersWarrantyRequest: (orderNumber: string) => `//td[@class='${orderNumber}']/..//a[@class='button request_warranty']`, + + ordersWarrantyRequest: (orderNumber: string) => `//a[contains(text(),'#${orderNumber}')]/../..//a[@class='woocommerce-button button request_warranty']`, + warrantyRequestItemCheckbox: (productName: string) => `//a[contains(text(),'${productName}')]/../..//input[@type='checkbox' and contains(@name,'request_item')]`, + warrantyRequestItemQuantity: (productName: string) => `//a[contains(text(),'${productName}')]/../..//select[contains(@name,'request_item_qty')]`, + warrantyRequestType: '#type', // replace, refund, coupon + warrantyRequestReason: '#reasons', + warrantyRequestDetails: '#warranty_request_details', + warrantySubmitRequest: 'input[name="warranty_submit_request"]', + }, + + // Order Details + orderDetails: { + orderDetailsLInk: (orderNumber: string) => `//a[contains(text(), '#${orderNumber}')]/../..//a[contains(text(), 'View')]`, + orderNumber: '//div[@class="woocommerce-MyAccount-content"]//p//mark[@class="order-number"]', + orderDate: '//div[@class="woocommerce-MyAccount-content"]//p//mark[@class="order-date"]', + orderStatus: '//div[@class="woocommerce-MyAccount-content"]//p//mark[@class="order-status"]', + subTotal: '//th[contains(text(),"Subtotal:")]/..//span[@class="woocommerce-Price-amount amount"]', + orderDiscount: '//th[contains(text(),"Order Discount:")]/..//span[@class="woocommerce-Price-amount amount"]', + quantityDiscount: '//th[contains(text(),"Quantity Discount:")]/..//span[@class="woocommerce-Price-amount amount"]', + discount: '//th[text()="Discount:"]/..//span[@class="woocommerce-Price-amount amount"]', + shippingMethod: '//th[contains(text(),"Shipping:")]/..//small', + shippingCost: '//th[contains(text(),"Shipping:")]/..//span[@class="woocommerce-Price-amount amount"]', + tax: '//th[contains(text(),"Tax:")]/..//span[@class="woocommerce-Price-amount amount"]', + paymentMethod: '//th[contains(text(),"Payment method:")]/..//td', + orderTotal: '//th[contains(text(),"Total:")]/..//span[@class="woocommerce-Price-amount amount"]', + }, + }, + + // Customer Subscription + cSubscription: { + view: (orderNumber: string) => `//a[contains(text(),'Order #${orderNumber}')]/../..//a[@class="woocommerce-button button view"]`, + + subscriptionDetails: { + subscriptionHeading: 'h1.entry-title', + + // actions + actions: { + cancel: 'td a.button.cancel', + changeAddress: 'td a.button.change_address', + changePayment: 'td a.button.change_payment_method', + reActivate: 'td a.button.reactivate', + renewNow: 'td a.button.subscription_renewal_early', + }, + + changePaymentMethod: '//input[@id="place_order"]', // todo: add & move to separate group -> payment change locators + + // todo: add more locators + }, + }, + + // Customer Downloads + cDownloads: { + view: (orderNumber: string) => `//a[contains(text(),'Order #${orderNumber}')]/../..//a[@class="woocommerce-button button view"]`, + }, + + // Customer Address + cAddress: { + // Billing Address + billing: { + editBillingAddress: '//h3[contains(text(),"Billing address")]/..//a[@class="edit"]', + billingFirstName: '#billing_first_name', + billingLastName: '#billing_last_name', + billingCompanyName: '#billing_company', + billingCompanyID: '#billing_dokan_company_id_number', + billingVatOrTaxNumber: '#billing_dokan_vat_number', + billingNameOfBank: '#billing_dokan_bank_name', + billingBankIban: '#billing_dokan_bank_iban', + // 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: '(//span[@class="select2-selection__arrow"])[2]', + billingStateInput: '.select2-search.select2-search--dropdown .select2-search__field', + billingStateValues: '.select2-results ul li', + billingZipCode: '#billing_postcode', + billingPhone: '#billing_phone', + billingEmailAddress: '#billing_email', + billingSaveAddress: '//button[@name="save_address"]', + // Success Message + successMessage: '.woocommerce-message', + }, + + // Shipping Address + shipping: { + editShippingAddress: '//h3[contains(text(),"Shipping address")]/..//a[@class="edit"]', + shippingFirstName: '#shipping_first_name', + shippingLastName: '#shipping_last_name', + shippingCompanyName: '#shipping_company', + // 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: '(//span[@class="select2-selection__arrow"])[2]', + shippingStateInput: '.select2-search.select2-search--dropdown .select2-search__field', + shippingStateValues: '.select2-results ul li', + shippingZipCode: '#shipping_postcode', + shippingSaveAddress: '//button[@name="save_address"]', + + // Success Message + successMessage: '.woocommerce-message', + }, + }, + + // Customer Rma Requests + cRma: { + allRequestText: '//h2[normalize-space()="All Requests"]', + + // table + table: { + rmaRequestsTable: 'table.my_account_orders.table.table-striped', + orderIdColumn: '//th[@class="rma-order-id"]', + vendor: '//th[@class="rma-vendor"]', + type: '//th[@class="rma-details"]', + status: '//th[@class="rma-status"]', + }, + + noRowsFound: '//td[normalize-space()="No request found"]', + numberOfRowsFound: 'table tbody tr.order', + + view: (orderNumber: string) => `//a[contains(text(),'Order #${orderNumber}')]/../..//a[@class="woocommerce-button button view"]`, + // Conversations + message: '#message', + sendMessage: '.woocommerce-button', + }, + + // Customer Payment Methods + cPaymentMethods: { + deleteMethod: '.delete', + addPaymentMethod: '.woocommerce-MyAccount-content .button', + + // Stripe Card + stripeCardIframe: '#dokan-stripe-card-element iframe', + stripeCardNumber: '.CardNumberField-input-wrapper .InputElement', + // stripeCardNumber1: "//input[@name='cardnumber']/..", + // stripeCardNumber: "//input[@name='cardnumber']", + stripeCardExpiryDate: '.CardField-expiry .InputElement', + stripeCardCvc: '.CardField-cvc .InputElement', + + addPaymentMethodCard: '#place_order', + }, + + // Customer Account Details + cAccountDetails: { + firstName: '#account_first_name', + lastName: '#account_last_name', + displayName: '#account_display_name', + email: '#account_email', + currentPassword: '#password_current', + NewPassword: '#password_1', + confirmNewPassword: '#password_2', + saveChanges: '.woocommerce-Button', + }, + + // Customer Followed Vendors + cVendors: { + noVendorFound: '.dokan-error', + + // Store card + storeCard: { + storeCardDiv: 'div.store-wrapper', + storeCardHeader: 'div.store-header', + // header details + storeBanner: 'div.store-banner', + openCloseStatus: 'span.dokan-store-is-open-close-status', + + storeCardContent: 'div.store-content', + // content details + featuredLabel: 'div.featured-label', + storeData: 'div.store-data', + storeAddress: 'p.store-address', + storePhone: 'p.store-phone', + + storeCardFooter: 'div.store-footer', + // footer details + storeAvatar: 'div.seller-avatar', + visitStore: 'a[title="Visit Store"]', + followUnFollowButton: 'button.dokan-follow-store-button', + }, + + visitStore: (storeName: string) => `//a[text()='${storeName}']/../../../../..//a[@title='Visit Store']`, + followUnFollowStore: (storeName: string) => `//a[text()='${storeName}']/../../../../..//button[contains(@class,'dokan-follow-store-button')]`, + currentFollowStatus: (storeName: string) => `//a[text()='${storeName}']/../../../../..//button[contains(@class,'dokan-follow-store-button')]//span[@class='dokan-follow-store-button-label-current']`, + }, + + // Customer Support Tickets + cSupportTickets: { + // Menus + menus: { + allTickets: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"All Tickets")]', + openTickets: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"Open Tickets")]', + closedTickets: '//ul[contains(@class,"subsubsub")]//a[contains(text(),"Closed Tickets")]', + }, + + // table + table: { + table: '.dokan-support-table', + topicColumn: '//th[normalize-space()="Topic"]', + storeNameColumn: '//th[normalize-space()="Store Name"]', + titleColumn: '//th[normalize-space()="Title"]', + statusColumn: '//th[normalize-space()="Status"]', + dateColumn: '//th[normalize-space()="Date"]', + }, + + noSupportTicketFound: '//div[@class="dokan-error" and contains(text(), "No tickets found!")]', + firstSupportTicket: '(//div[@class="dokan-support-topics-list"]//tr//td//a)[1]', + supportTicketLink: (ticketId: string) => `//tr//td[normalize-space()="#${ticketId}"]//a`, + + supportTicketDetails: { + backToTickets: '//a[contains(text(),"← Back to Tickets")]', + + basicDetails: { + basicDetailsDiv: 'div.dokan-support-single-title', + ticketTitle: '//span[contains(@class,"dokan-chat-title") and not(contains(@class,"dokan-chat-status"))]', + ticketId: 'span.dokan-chat-title.dokan-chat-status', + }, + + chatStatus: { + status: 'div.dokan-chat-status-box span.dokan-chat-status', + open: 'div.dokan-chat-status-box span.dokan-chat-status.chat-open', + closed: 'div.dokan-chat-status-box span.dokan-chat-status.chat-closed', + }, + + orderReference: { + orderReferenceSpan: 'span.order-reference', + orderReferenceText: (orderId: string) => `//strong[normalize-space()="Referenced Order #${orderId}"]`, + orderReferenceLink: (orderId: string) => `//strong[normalize-space()="Referenced Order #${orderId}"]/..`, + }, + + chatBox: { + mainChat: 'div.dokan-dss-chat-box.main-topic', + otherChats: 'ul.dokan-support-commentlist', + }, + + replyBox: { + addReplyText: '//strong[normalize-space()="Add Reply"]', + replyBoxDiv: 'div.dokan-panel.dokan-panel-default.dokan-dss-panel-default', + addReply: '#dokan-support-commentform #comment', + submitReply: '#submit', + }, + + chatText: (text: string) => `//div[contains(@class, 'dokan-chat-text')]//p[contains(text(),'${text}')]`, + + closedTicket: { + closedTicketHeading: '//strong[normalize-space()="Ticket Closed"]', + closedTicketMessage: '.dokan-alert.dokan-alert-warning', + }, + }, + }, + + // Customer Bookings + cBookings: { + selectCalendarDay: (month: number, day: number) => `//td[@title="This date is available" and @ data-month="${month}"]//a[@data-date="${day}"]`, + view: (orderNumber: string) => `//a[contains(text(),'Order #${orderNumber}')]/../..//a[@class="woocommerce-button button view"]`, + bookNow: 'button.wc-bookings-booking-form-button', + }, + + // Customer Auctions Settings + cAuctions: { + view: (orderNumber: string) => `//a[contains(text(),'Order #${orderNumber}')]/../..//a[@class="woocommerce-button button view"]`, + bidValue: '//input[@name="bid_value"]', + plus: '//input[@value="+"]', + minus: '//input[@value="-"]', + bid: '.bid_button', + }, + + // Customer Shop Page + cShop: { + shopText: '//h1[normalize-space()="Shop"]', + + map: { + locationMap: '#dokan-geolocation-locations-map', + map: '//button[normalize-space()="Map"]', + satellite: '//button[normalize-space()="Satellite"]', + fullScreenToggle: '//button[@title="Toggle fullscreen view"]', + pegman: '//button[@title="Drag Pegman onto the map to open Street View"]', + zoomIn: '//button[@title="Zoom in"]', + zoomOut: '//button[@title="Zoom out"]', + productOnMap: { + productPin: '//div[@id="dokan-geolocation-locations-map"]//img[contains(@src, "maps.gstatic.com/mapfiles/transparent.png")]/../..//div[@role="button"]', + productCluster: '//div[@id="dokan-geolocation-locations-map"]//div[contains(@style, "dokan-pro/modules/geolocation/assets/images")]', + productOnMap: '//span[normalize-space()="To navigate, press the arrow keys."]/..//div', + productPopup: '.dokan-geo-map-info-window', + productListPopup: '.dokan-geo-map-info-windows-in-popup', + productOnList: (productName: string) => `//h3[@class="info-title"]//a[contains(text(),"${productName}")]`, + closePopup: 'button.icon-close', + }, + }, + + // Filter + filters: { + searchProduct: '.dokan-form-control', + location: '.location-address input', + selectCategory: '#product_cat', + radiusSlider: '.dokan-range-slider', + search: '.dokan-btn', + }, + + mapResultFirst: '(//div[contains(@class,"pac-container")]//div[@class="pac-item"])[1]', + + searchProductLite: '(//input[@class="search-field"])[1]', + + // sort + sort: '.woocommerce-ordering .orderby', // popularity, rating, date, price, price-desc + + // Product Card + productCard: { + card: '#main .products', + productDetailsLink: '#main .products .woocommerce-LoopProduct-link', + productTitle: '#main .products .woocommerce-loop-product__title', + productPrice: '#main .products .price', + addToCart: '#main .products a.add_to_cart_button', + viewCart: 'a.added_to_cart', + bidNow: '.button.product_type_auction', + }, + + // Pagination + pagination: { + pagination: '(//nav[@class="woocommerce-pagination"])[1]', + previous: '.prev', + next: '.next', + }, + }, + + // Customer Single Product + cSingleProduct: { + // Product Details + productDetails: { + productImage: '.woocommerce-product-gallery__wrapper img.wp-post-image', + productTitle: '.product_title.entry-title', + quantity: '.quantity input.qty', + addToCart: '.single_add_to_cart_button', + viewCart: '.woocommerce .woocommerce-message > .button', + category: '.product_meta .posted_in', + }, + + // Sub menus + menus: { + description: '.tabs description_tab a', + shipping: '.tabs .shipping_tab a', + reviews: '.tabs .reviews_tab a', + vendorInfo: '.tabs .seller_tab a', + location: '.tabs .geolocation_tab a', + moreProducts: '.tabs .more_seller_product_tab a', + warrantyPolicy: '.tabs .refund_policy_tab a', + productEnquiry: '.tabs .seller_enquiry_form_tab a', + + // description: '#tab-title-description a', + // reviews: '#tab-title-reviews', + // vendorInfo: '#tab-title-seller a', + // location: '#tab-title-geolocation a', + // moreProducts: '#tab-title-more_seller_product a', + // warrantyPolicy: '#tab-title-refund_policy a', + // productEnquiry: '#tab-title-seller_enquiry_form a', + }, + + // Product description + description: { + // descriptionHeading: '//h2[normalize-space()="Description"]', // todo: storefrontOnly + content: 'div[id="tab-description"] p', + }, + + // Shipping + shipping: { + shippingCountryTitle: '#tab-shipping p', + shippingCountries: '#tab-shipping p strong', + }, + + // Product Reviews + reviews: { + // reviewsHeading: '//h2[normalize-space()="Reviews"]', // todo: storefrontOnly + noReviews: '.woocommerce-noreviews', + ratings: '.comment-form-rating .stars', + rating: (star: string) => `.star-${star}`, + reviewMessage: '#comment', + submitReview: '#submit', + submittedReview: (reviewMessage: string) => `//div[@class='comment_container']//div[@class='description']// p[text()='${reviewMessage}']`, + awaitingApprovalReview: (reviewMessage: string) => + `//div[@class='comment_container']//div[@class='description']// p[text()='${reviewMessage}']/../..//p//em[@class='woocommerce-review__awaiting-approval']`, + duplicateCommentAlert: '#error-page .wp-die-message p', + backFromDuplicateCommentAlert: '//a[contains(text(),"« Back")]', + }, + + // Product vendor info + vendorInfo: { + // vendorInfoHeading:'//h2[normalize-space()="Vendor Information"]', // todo: storefrontOnly + storeName: '.store-name', + vendor: '.seller-name', + storeAddress: '.store-address', + }, + + // Product Location + location: { + // locationHeading: '//h2[normalize-space()="Product Location"]', // todo: storefrontOnly + productLocation: 'div[id="tab-geolocation"] address', + map: '#dokan-geolocation-locations-map', + }, + + // More Products + moreProducts: { + moreProductsDiv: '#tab-more_seller_product .products', + product: '#tab-more_seller_product .product', + }, + + // warrantyPolicy + warrantyPolicy: { + content: 'div[id="tab-refund_policy"] p', + }, + + // Product Enquiry + productEnquiry: { + productEnquiryHeading: '//h3[normalize-space()="Product Enquiry"]', + enquiryMessage: '#dokan-enq-message', + submitEnquiry: 'input.dokan-btn-theme', + submitEnquirySuccessMessage: '.alert.alert-success', + + // guest user + guest: { + guestName: '#name', + guestEmail: '#dokan-product-enquiry #email', + }, + }, + + // related product + relatedProducts: { + relatedProductHeading: '//h2[normalize-space()="Related products"]', + products: '.related.products .products', + }, + + // vendor highlighted info + vendorHighlightedInfo: { + vendorInfoDiv: '.dokan-vendor-info-wrap', + vendorImage: '.dokan-vendor-image', + vendorInfo: '.dokan-vendor-info', + vendorName: '.dokan-vendor-name', + vendorRating: '.dokan-vendor-rating', + }, + + // Get Support + getSupport: { + getSupport: '.dokan-store-support-btn', + closeGetSupportPopup: 'button.icon-close', + subject: '#dokan-support-subject', + getSupportOrderId: '.dokan-select', + message: '#dokan-support-msg', + submitGetSupport: '#support-submit-btn', + }, + + // Report Abuse + reportAbuse: { + reportAbuse: 'a.dokan-report-abuse-button', + reportReasonByNumber: (reasonNumber: string) => `li:nth-child(${reasonNumber}) input`, // By Number + reportReasonByName: (reasonName: string) => `//input[@value='${reasonName}']/..`, // By Name + reportDescription: 'textarea[name="description"]', + reportSubmit: '#dokan-report-abuse-form-submit-btn', + reportSubmitSuccessMessage: '#swal2-html-container', + confirmReportSubmit: '.swal2-confirm', + + // non logged User + nonLoggedUser: { + // userName: '#login-name', + // userPassword: '#login-password', + // login: '#support-submit-btn', + userName: '#dokan-login-form-username', + userPassword: '#dokan-login-form-password', + login: '#dokan-login-form-submit-btn', + createAccount: '.dokan-btn.dokan-btn-theme', + }, + + // guest user + guestName: '//input[@name="customer_name"]', + guestEmail: '//input[@name="customer_email"]', + }, + + // Other Available Vendor + otherAvailableVendor: { + OtherAvailableVendorViewStore: '.fa-external-link-alt', + OtherAvailableVendorViewProduct: '.view', + OtherAvailableVendorAddToCart: '.fa-shopping-cart', + }, + + // Product addon + productAddon: { + addOnSelect: '.wc-pao-addon-select', + }, + }, + + cSpmv: { + otherAvailableVendorDiv: 'div.dokan-other-vendor-camparison', + availableVendorDisplayAreaTitle: 'div.dokan-other-vendor-camparison h3', + availableVendorTable: '.table.dokan-other-vendor-camparison-table', + otherVendorAvailableTab: 'li#tab-title-vendor_comaprison', + + availableVendorDetails: { + vendor: { + vendorCell: '.table-row .table-cell.vendor', + avatar: '.table-row .table-cell.vendor .avatar', + vendorLink: '.table-row .table-cell.vendor a', + }, + + price: { + priceCell: '.table-row .table-cell.price', + priceAmount: '.table-row .table-cell.price .amount', + }, + + rating: { + ratingCell: '.table-row .table-cell.rating', + rating: '.table-row .table-cell.rating .woocommerce-product-rating', + }, + + actions: { + actionsCell: '.table-row .table-cell.action-area', + viewStore: '.table-row .table-cell.action-area .link', + viewProduct: '.table-row .table-cell.action-area .view', + addToCart: '.table-row .table-cell.action-area .cart', + + viewStoreByVendor: (storeName: string) => `//a[normalize-space()="${storeName}"]/../..//div[@class="table-cell action-area"]//a[@class="dokan-btn tips link"]`, + viewProductByVendor: (storeName: string) => `//a[normalize-space()="${storeName}"]/../..//div[@class="table-cell action-area"]//a[@class="dokan-btn tips view"]`, + addToCartByVendor: (storeName: string) => `//a[normalize-space()="${storeName}"]/../..//div[@class="table-cell action-area"]//a[@class="dokan-btn tips cart"]`, + }, + }, + }, + + // Customer Store List Page + cStoreList: { + storeListText: '//h1[normalize-space()="Store List"]', + + map: { + locationMap: '#dokan-geolocation-locations-map', + map: '//button[normalize-space()="Map"]', + satellite: '//button[normalize-space()="Satellite"]', + fullScreenToggle: '//button[@title="Toggle fullscreen view"]', + pegman: '//button[@title="Drag Pegman onto the map to open Street View"]', + zoomIn: '//button[@title="Zoom in"]', + zoomOut: '//button[@title="Zoom out"]', + storeOnMap: { + storePin: '//div[@id="dokan-geolocation-locations-map"]//img[contains(@src, "maps.gstatic.com/mapfiles/transparent.png")]/../..//div[@role="button"]', + storeCluster: '//div[@id="dokan-geolocation-locations-map"]//div[contains(@style, "dokan-pro/modules/geolocation/assets/images")]', + storeOnMap: '//span[normalize-space()="To navigate, press the arrow keys."]/..//div', + storePopup: '.dokan-geo-map-info-window', + storeListPopup: '.dokan-geo-map-info-windows-in-popup', + storeOnList: (storeName: string) => `//h3[@class="info-title"]//a[contains(text(),"${storeName}")]`, + closePopup: 'button.icon-close', + }, + }, + + currentLayout: '.entry-content #dokan-seller-listing-wrap', + + // Filters + filters: { + filterDiv: 'div#dokan-store-listing-filter-wrap', + + totalStoreCount: 'p.item.store-count', + filterButton: 'button.dokan-store-list-filter-button', + + // Sortby + sortBy: '#stores_orderby', // most_recent, total_orders, random + + // View Style + gridView: '.dashicons-screenoptions', + listView: '.dashicons-menu-alt', + + filterDetails: { + searchVendor: '.store-search-input', + location: '.location-address input', + radiusSlider: 'input.dokan-range-slider', + categoryInput: '.category-input', + featured: '#featured', + openNow: '#open-now', + ratings: '.store-ratings.item', + rating: (star: string) => `.star-${star}`, + + apply: '#apply-filter-btn', + }, + }, + + category: (category: string) => `//div[@class="category-box store_category"]//ul//li[contains(text(), '${category}')]`, + categoryFirst: '(//div[@class="category-box store_category"]//ul//li)[1]', + mapResultFirst: '(//div[contains(@class,"pac-container")]//div[@class="pac-item"])[1]', + + // Store card + storeCard: { + storeCardDiv: 'div.store-wrapper', + storeCardHeader: 'div.store-header', + // header details + storeBanner: 'div.store-banner', + openCloseStatus: 'span.dokan-store-is-open-close-status', + + storeCardContent: 'div.store-content', + // content details + featuredLabel: 'div.featured-label', + storeData: 'div.store-data', + storeAddress: 'p.store-address', + storePhone: 'p.store-phone', + + storeCardFooter: 'div.store-footer', + // footer details + storeAvatar: 'div.seller-avatar', + visitStore: 'a[title="Visit Store"]', + followUnFollowButton: 'button.dokan-follow-store-button', + }, + + visitStore: (storeName: string) => `//a[text()='${storeName}']/../../../../..//a[@title='Visit Store']`, + followUnFollowStore: (storeName: string) => `//a[text()='${storeName}']/../../../../..//button[contains(@class,'dokan-follow-store-button')]`, + currentFollowStatus: (storeName: string) => `//a[text()='${storeName}']/../../../../..//button[contains(@class,'dokan-follow-store-button')]//span[@class='dokan-follow-store-button-label-current']`, + followUnFollowStoreSingleStore: 'button.dokan-follow-store-button', + currentFollowStatusSingleStore: 'span.dokan-follow-store-button-label-current', + }, + + // Customer Single Store + cSingleStore: { + // Store Profile Summary + storeProfile: { + storeProfileSummary: '.dokan-single-store .profile-info-summery', + + storeBanner: '.profile-info-img', + + profileInfoHead: '.profile-info-head', + profileImage: '.profile-img.profile-img-circle', + storeName: '.profile-info-head .store-name', + + profileInfo: '.profile-info', + storeInfo: '.dokan-store-info', + storeAddress: '.dokan-store-address', + storePhone: '.dokan-store-phone', + // storeEmail: '.dokan-store-email', + // storeRating: '.dokan-store-rating', + // storeOpenClose: '.dokan-store-open-close', + storeSocial: '.store-social', + }, + + // Store open close time + storeTime: { + storeTimeDropDown: '.store-open-close-notice', + storeTimeDiv: '#vendor-store-times', + storeTimeHeading: '.store-times-heading', + storeDays: '#vendor-store-times .store-days', + storeTimes: '#vendor-store-times .store-times', + }, + + // Social icons + storeSocialIcons: { + facebook: '.fa-facebook-square', + twitter: '.fa-twitter-square', + pinterest: '.fa-pinterest-square', + linked: '.fa-linkedin', + youtube: '.fa-youtube-square', + instagram: '.fa-instagram', + flickr: '.fa-flickr', + }, + + // Store Tabs + storeTabs: { + follow: '.dokan-follow-store-button', + getSupport: 'button.dokan-store-support-btn', + share: '.dokan-share-btn', + + products: '//div[@class="dokan-store-tabs"]//a[contains(text(),"Products")]', + toc: '//div[@class="dokan-store-tabs"]//a[contains(text(),"Terms and Conditions")]', + reviews: '//div[@class="dokan-store-tabs"]//a[contains(text(),"Reviews")]', + }, + + // Search product + search: { + input: '.product-name-search', + button: '.search-store-products', + }, + + searchedProduct: '.woocommerce-loop-product__title', + + // Sort + sortBy: '.orderby', // popularity, rating, date, price, price-desc + + storeProducts: '.seller-items', + + // Product Card + productCard: { + card: '.seller-items .product', + productDetailsLink: '.seller-items .product .woocommerce-LoopProduct-link', + productTitle: '.seller-items .product .woocommerce-loop-product__title', + productPrice: '.seller-items .product .price', + addToCart: '.seller-items .product .add_to_cart_button', + }, + + // Pagination + pagination: '.dokan-pagination', + + // Review + review: { + close: 'button.icon-close', + noReviewsFound: '//span[normalize-space()="No Reviews found"]', + write: '//button[normalize-space()="Write a Review"]', + // write: '.add-review-btn', + edit: '.edit-review-btn', + rating: '.jq-ry-rated-group.jq-ry-group', + title: '#dokan-review-title', + message: '#dokan-review-details', + submit: '#support-submit-btn', + submittedReview: (reviewMessage: string) => `//div[@class='review_comment_container']//div[@class='description']// p[text()='${reviewMessage}']`, + + reviewDetails: { + yourReview: '//h3[normalize-space()="Your Review"]', + author: '#dokan-store-review-single p strong[itemprop="author"]', + rating: '#dokan-store-review-single .dokan-rating div', + title: '#dokan-store-review-single .description h4', + content: '#dokan-store-review-single .description p', + edit: '.edit-review-btn', + }, + }, + + // Get Support + getSupport: { + // close: '.mfp-close', // todo: this locator don't exits delete this from all + close: 'button.icon-close', + subject: 'input#dokan-support-subject', + orderId: 'select.dokan-select', + message: 'textarea#dokan-support-msg', + submit: 'input#support-submit-btn', + + // guest User + userName: '#login-name', + userPassword: '#login-password', + login: '#support-submit-btn', + createAccount: '.dokan-btn.dokan-btn-theme', + }, + + // Share Store + sharePlatForms: { + facebook: '.jssocials-share-facebook a', + twitter: '.jssocials-share-twitter a', + linkedin: '.jssocials-share-linkedin a', + pinterest: '.jssocials-share-pinterest a', + mail: '.jssocials-share-email a', + }, + + // terms and conditions + toc: { + tocContent: '#store-toc-wrapper #store-toc p', + }, + + // store coupon + storeCoupon: { + storeCouponDiv: '.store-coupon-wrap', + couponTitle: '.coupon-title', + couponBody: '.coupon-body', + couponCode: '..coupon-code', + coupon: (code: string) => `//span[@class="coupon-code"]//strong[normalize-space()="${code}"]`, + }, + }, + + cMyOrders: { + myOrdersText: '//h1[normalize-space()="My Orders"]', + recentOrdersText: '//h2[normalize-space()="Recent Orders"]', + + // Table + table: { + myOrdersTable: '.shop_table.my_account_orders.table', + orderColumn: 'th.order-number', + dateColumn: 'th.order-date', + statusColumn: 'th.order-status', + totalColumn: '//span[normalize-space()="Total"]/..', + vendorColumn: '//span[normalize-space()="Vendor"]/..', + actionsColumn: 'th.order-actions', + }, + + noOrdersFound: '.dokan-info', + orderNumber: (orderNumber: string) => `//a[normalize-space()="${orderNumber}"]`, + orderView: (orderNumber: string) => `//a[normalize-space()="${orderNumber}"]/../..//a[@class="button view"]`, + orderPay: (orderNumber: string) => `//a[normalize-space()="${orderNumber}"]/../..//a[@class="button pay"]`, + orderCancel: (orderNumber: string) => `//a[normalize-space()="${orderNumber}"]/../..//a[@class="button cancel"]`, + orderRequestWarranty: (orderNumber: string) => `//a[normalize-space()="${orderNumber}"]/../..//a[@class="button request_warranty"]`, + }, + + cRequestForQuote: { + singleProductDetails: { + addToQuote: '.cart a.dokan_request_button', + viewQuote: '.added_to_quote', + }, + + orderDetails: { + quoteNoteOnOrderDetails: '//td[normalize-space()="Created by converting quote to order."]', + }, + + // request for quote + requestForQuote: { + requestForQuoteText: '//h1[normalize-space()="Request for Quote"]', + noQuotesFound: '//p[@class="cart-empty"]', + returnToShop: '//a[normalize-space()="Return To Shop"]', + + quoteItemDetails: { + quoteDetailsText: '//h2[normalize-space()="Quote Details"]', + + table: { + quoteDetailsTable: '//table[contains(@class,"quote_details") and contains(@class,"cart")]', + productColumn: '//th[@class="product-name"]', + priceColumn: '//th[normalize-space()="Price"]', + offeredPriceColumn: '//th[normalize-space()="Offered Price"]', + quantityColumn: '//th[@class="product-quantity"]', + subtotalColumn: '//th[normalize-space()="Subtotal"]', + offeredSubtotalColumn: '//th[normalize-space()="Offered Subtotal"]', + }, + }, + + quoteTotals: { + quoteTotalsTitle: '//h2[normalize-space()="Quote totals"]', + quoteTotalsDiv: '.cart_totals', + quoteTotalsTable: '//div[@class="cart_totals"]//table[contains(@class,"table_quote_totals")]', + + subTotalText: '//tr[@class="cart-subtotal"]', + offeredPriceSubtotalText: '//tr[@class="cart-subtotal offered"]//th', + + subTotalValue: '//td[@data-title="Subtotal (standard)"]', + offeredPriceSubtotalValue: '//td[@data-title="Offered Price Subtotal"]', + }, + + offeredPriceInput: (productName: string) => `//a[normalize-space()="${productName}"]/../..//input[@class="input-text offered-price-input text"]`, + quantityInput: (productName: string) => `//a[normalize-space()="${productName}"]/../..//div[@class="quantity"]//input`, + + updateQuote: 'button#dokan_update_quote_btn', + placeQuote: 'button[name="dokan_checkout_place_quote"]', + + guest: { + fullName: 'input[name="name_field"]', + email: 'input[name="email_field"]', + companyName: 'input[name="company_field"]', + phoneNumber: 'input[name="phone_field"]', + }, + + message: '.woocommerce-message', + }, + + // requested quote + requestedQuote: { + requestedQuoteText: '//h1[normalize-space()="Requested Quotes"]', + + noQuoteMessage: '//div[contains(@class, "woocommerce-message woocommerce-message--info")]', + goToShop: '//a[normalize-space()="Go to shop"]', + + // table + table: { + quoteTable: 'table.my_account_quotes', + quoteColumn: '//th[normalize-space()="Quote #"]', + quoteNameColumn: '//th[normalize-space()="Quote Name"]', + statusColumn: '//th[normalize-space()="Status"]', + dateColumn: '//th[normalize-space()="Date"]', + actionColumn: '//th[normalize-space()="Action"]', + }, + + pagination: 'ul.pagination', + + viewQuoteDetails: (quoteId: string) => `//td[normalize-space()="Quote ${quoteId}"]/..//a[@class="woocommerce-button button view"]`, + + // requested quote details + requestedQuoteDetails: { + requestedQuoteText: '//h1[normalize-space()="Requested Quotes"]', + + basicDetails: { + basicDetailsTable: '(//table[@class="shop_table shop_table_responsive table_quote_totals dokan-table order-items"])[1]', + quoteNumberText: '//th[normalize-space()="Quote #"]', + quoteDateText: '//th[normalize-space()="Quote Date"]', + quoteStatusText: '//th[normalize-space()="Current Status"]', + + quoteNumberValue: '//th[normalize-space()="Quote #"]/..//td', + quoteDateValue: '//th[normalize-space()="Quote Date"]/..//td', + quoteStatusValue: '//th[normalize-space()="Current Status"]/..//td', + }, + + viewOrder: '//a[normalize-space()="View Order"]', + + quoteItemDetails: { + quoteDetailsText: '//h2[normalize-space()="Quote Details"]', + + table: { + quoteDetailsTable: '//table[contains(@class,"quote_details") and contains(@class,"cart")]', + productColumn: '//th[@class="product-name"]', + priceColumn: '//th[normalize-space()="Price"]', + offeredPriceColumn: '//th[normalize-space()="Offered Price"]', + quantityColumn: '//th[@class="product-quantity"]', + subtotalColumn: '//th[normalize-space()="Subtotal"]', + offeredSubtotalColumn: '//th[normalize-space()="Offered Subtotal"]', + }, + }, + + quoteTotals: { + quoteTotalsTitle: '//h2[normalize-space()="Quote totals"]', + quoteTotalsDiv: '.cart_totals', + quoteTotalsTable: '//div[@class="cart_totals"]//table[contains(@class,"table_quote_totals")]', + + subTotalText: '//tr[@class="cart-subtotal"]', + offeredPriceSubtotalText: '//tr[@class="cart-subtotal offered"]//th', + + subTotalValue: '//td[@data-title="Subtotal (standard)"]', + offeredPriceSubtotalValue: '//td[@data-title="Offered Price Subtotal"]', + }, + + offeredPriceInput: (productName: string) => `//a[normalize-space()="${productName}"]/../..//input[@class="input-text offered-price-input text"]`, + quantityInput: (productName: string) => `//a[normalize-space()="${productName}"]/../..//div[@class="quantity"]//input`, + + updateQuote: 'button[name="dokan_update_quote"]', + + message: '.woocommerce-message', + }, + }, + }, + + // Customer Header Cart + cHeaderCart: { + // Cart Content + cartContent: '.cart-contents .woocommerce-Price-amount', + removeItem: '.remove', + viewCart: '//p[contains(@class,"woocommerce-mini-cart__buttons")]//a[contains(text(),"View cart")]', + checkout: '//p[contains(@class,"woocommerce-mini-cart__buttons")]//a[contains(text(),"Checkout")]', + }, + + // Customer Cart + cCart: { + cartPageHeader: 'h1.entry-title', + + // Edit Cart + cartItem: (productName: string) => `//td[@class='product-name']//a[contains(text(),'${productName}')]`, + removeItem: (productName: string) => `//a[contains(text(),'${productName}')]/../..//a[@class='remove']`, + quantity: (productName: string) => `//a[contains(text(),'${productName}')]/../..//input[@class='input-text qty text']`, + couponCode: '#coupon_code', + applyCoupon: '//button[@name="apply_coupon"]', + removeCoupon: (couponCode: string) => `.cart-discount.coupon-${couponCode.toLowerCase()} .woocommerce-remove-coupon`, + updateCart: '//button[@name="update_cart"]', + + cartDetails: { + cartTotal: 'tr.cart-subtotal span.woocommerce-Price-amount.amount', + shipping: '//ul[@id="shipping_method"]//input[@checked="checked"]/..//span[@class="woocommerce-Price-amount amount"]', + tax: 'tr.tax-rate span.woocommerce-Price-amount.amount', + orderTotal: 'tr.order-total span.woocommerce-Price-amount.amount', + }, + + // Shipping Methods + shippingMethod: (vendorName: string, shippingMethod: string) => `//th[contains(text(),'Shipping: ${vendorName}')]/..//label[contains(text(),'${shippingMethod}')]/..//input`, // For Vendor-Wise or Admin Shipping Method + vendorShippingMethod: (shippingMethod: string) => `//label[contains(text(),'${shippingMethod}')]/..//input`, // For Unique Shipping Method + + // Proceed to Checkout + proceedToCheckout: '.checkout-button.button.wc-forward', + + // Remove All Item + productCrossIcon: '.product-remove a', + firstProductCrossIcon: '(//td[@class="product-remove"]//a)[1]', + cartEmptyMessage: '.cart-empty.woocommerce-info', + }, + + cWholesale: { + shop: { + wholesalePrice: 'span.dokan-wholesale-price', + wholesaleAmount: 'span.dokan-wholesale-price span.woocommerce-Price-amount.amount', + }, + + singleProductDetails: { + wholesaleInfo: 'p.dokan-wholesale-meta', + wholesalePrice: 'p.dokan-wholesale-meta .woocommerce-Price-amount.amount', + minimumQuantity: '(//p[@class="dokan-wholesale-meta"]//strong)[2]', + }, + }, + + // Customer Checkout + cCheckout: { + checkoutPageHeader: '.entry-title', + + orderDetails: { + orderDetailsHeading: 'h3#order_review_heading', + orderDetailsDiv: 'div#order_review', + + cartTotal: 'tr.cart-subtotal span.woocommerce-Price-amount.amount', + shipping: '//ul[@id="shipping_method"]//input[@checked="checked"]/..//span[@class="woocommerce-Price-amount amount"]', + tax: 'tr.tax-rate span.woocommerce-Price-amount.amount', + orderTotal: 'tr.order-total span.woocommerce-Price-amount.amount', + }, + + // Billing Details + billingAddress: { + billingFirstName: '#billing_first_name', + billingLastName: '#billing_last_name', + billingCompanyName: '#billing_company', + billingCompanyIDOrEuidNumber: '#billing_dokan_company_id_number', + billingVatOrTaxNumber: '#billing_dokan_vat_number', + billingNameOfBank: '#billing_dokan_bank_name', + billingBankIban: '#billing_dokan_bank_iban', + // billingCountryOrRegion: "#select2-billing_country-container", + billingCountryOrRegion: '.select2-selection__arrow', + billingCountryOrRegionValues: '.select2-results ul li', + billingStreetAddress: '#billing_address_1', + billingStreetAddress2: '#billing_address_2', + billingTownCity: '#billing_city', + billingPhone: '#billing_phone', + billingEmailAddress: '#billing_email', + billingState: '#select2-billing_state-container', + billingStateValues: '.select2-results ul li', + billingZipCode: '#billing_postcode', + }, + + // Shipping Details + shippingAddress: { + shipToADifferentAddress: '#ship-to-different-address-checkbox', + shippingFirstName: '#shipping_first_name', + shippingLastName: '#shipping_last_name', + shippingCompanyName: '#shipping_company', + // 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-selection__arrow', + shippingStateValues: '.select2-results ul li', + shippingZipCode: '#shipping_postcode', + }, + + // Order Comments + orderComments: '#order_comments', + + // Shipping Methods + shippingMethod: (vendorName: string, shippingMethod: string) => `//th[contains(text(),'Shipping: ${vendorName}')]/..//label[contains(text(),'${shippingMethod}')]/..//input`, // For Vendor-Wise or Admin Shipping Method + vendorShippingMethod: (shippingMethod: string) => `//label[contains(text(),'${shippingMethod}')]/..//input`, // For Unique Shipping Method + + // Payment Methods + directBankTransfer: '.payment_method_bacs label', + checkPayments: '.payment_method_cheque label', + cashOnDelivery: '.payment_method_cod label', + paypalAdaptive: '.payment_method_dokan_paypal_adaptive label', + stripeConnect: '.wc_payment_method.payment_method_dokan-stripe-connect label[for="payment_method_dokan-stripe-connect"]', + wireCardCreditCard: '.payment_method_dokan-moip-connect label', + paypalMarketPlace: '.wc_payment_method.payment_method_dokan_paypal_marketplace label', + stripeExpress: '.wc_payment_method.payment_method_dokan_stripe_express label', + + // Place Order + placeOrder: '#place_order', + }, + + cPayWithStripe: { + strip: '#payment_method_dokan-stripe-connect', + savedTestCard4242: '//label[contains(text(),"Visa ending in 4242")]/..//input', + userNewPaymentMethod: '#wc-dokan-stripe-connect-payment-token-new', + stripeConnectIframe: 'div#dokan-stripe-card-element iframe[title="Secure card payment input frame"]', + creditCard: '#card-tab', + cardNumber: 'input[name="cardnumber"]', + expDate: 'input[name="exp-date"]', + cvc: 'input[name="cvc"]', + savePaymentInformation: '#wc-dokan-stripe-connect-new-payment-method', + }, + + cPayWithPaypalMarketPlace: { + paypalMarketPlace: '.payment_method_dokan_paypal_marketplace label', + }, + + cPayWithRazorpay: { + razorPay: '.payment_method_dokan_razorpay label', + }, + + cPayWithMangoPay: { + mangoPay: '.payment_method_dokan_mangopay label', + creditCard: '//input[@name="dokan_mangopay_payment_type"]', + cardType: '#dokan-mangopay-card-type', + registeredCard: '#dokan-mangopay-payment-type-registeredcard', + registerCardType: '#registered_card_type', + cardNumber: '#dokan-mp-ccnumber', + cvc: '#dokan-mp-cccrypto', + expDateMonth: '#preauth_ccdate_month', + expDateYear: '#preauth_ccdate_year', + register: '#save_preauth_card_button', + }, + + cPayWithStripeExpress: { + savedTestCard4242: '//label[contains(text(),"Visa ending in 4242")]/..//input', + userNewPaymentMethod: '#wc-dokan_stripe_express-payment-token-new', + savePaymentInformation: '#wc-dokan_stripe_express-new-payment-method', + stripeExpressIframe: '#dokan-stripe-express-element iframe', + creditCard: '#card-tab', + gPay: '#google_pay-tab', + iDeal: '#ideal-tab', + iDealBanks: '#Field-bankInput', + cardNumber: '#Field-numberInput', + expDate: '#Field-expiryInput', + cvc: '#Field-cvcInput', + }, + + cDeliveryTime: { + deliveryTimeDiv: 'div#dokan-delivery-time-box', + + deliveryDetailsText: '//h3[normalize-space()="Delivery details"]', + deliveryTimeZone: 'div.delivery-timezone.dokan-delivery-time-tooltip', + + deliveryTimeBody: 'div.delivery-time-body', + vendorInfo: 'div.delivery-time-body .vendor-info', + + delivery: '//div[@class="dokan-store-location-selector"]//div[@data-selector="delivery"]', + storePickup: '//div[@class="dokan-store-location-selector"]//div[@data-selector="store-pickup"]', + + deliveryTimeInput: '//input[@class="delivery-time-date-picker form-control input"]', + deliveryTimeInputHidden: '//input[@class="delivery-time-date-picker flatpickr-input"]', + deliveryDate: (date: string) => `//div[contains(@class,"flatpickr-calendar")]//div[@class="dayContainer"]//span[contains(@class,"flatpickr-day") and @aria-label="${date}"]`, + + timePicker: 'select.delivery-time-slot-picker', + locationPicker: 'select.delivery-store-location-picker', + + orderDetails: { + deliveryTimeDetails: 'div#dokan-delivery-time-slot-order-details', + storePickupDetails: 'div#dokan-store-location-order-details', + deliveryTimeTitle: 'div#dokan-delivery-time-slot-order-details .main strong', + storePickupTitle: 'div#dokan-store-location-order-details .main strong', + }, + }, + + cOrderReceived: { + orderReceivedHeading: '//h1[normalize-space()="Order received"]', + orderReceivedSuccessMessage: '.woocommerce-notice.woocommerce-notice--success.woocommerce-thankyou-order-received', + + // Order Details + orderDetails: { + // basic info + orderNumber: '.woocommerce-order-overview__order.order strong', + orderDate: '.woocommerce-order-overview__date.date strong', + email: '.woocommerce-order-overview__email.email strong', + total: '.woocommerce-order-overview__total.total strong', + paymentMethod: '.woocommerce-order-overview__payment-method.method strong', + + subTotal: '//th[normalize-space()="Subtotal:"]//..//span[@class="woocommerce-Price-amount amount"]', + shippingMethod: '//th[normalize-space()="Shipping:"]/..//small', + shippingCost: '//th[normalize-space()="Shipping:"]/..//span[@class="woocommerce-Price-amount amount"]', + tax: '//th[normalize-space()="Tax:"]//..//span[@class="woocommerce-Price-amount amount"]', + orderPaymentMethod: '//th[normalize-space()="Payment method:"]//..//td', + orderTotal: '//th[normalize-space()="Total:"]//..//span[@class="woocommerce-Price-amount amount"]', + + subOrders: { + subOrders: '//h2[normalize-space()="Sub Orders"]', + multiVendorNote: '.dokan-info', + multiOrders: '.my_account_orders', + // note: 'This order has products from multiple vendors. So we divided this order into multiple vendor orders. Each order will be handled by their respective vendor independently.' + }, + }, + + // customer details + customerDetails: { + customerDetailsSection: '.woocommerce-customer-details .addresses', + // Billing address + billingAddressHeading: '//h2[normalize-space()="Billing address"]', + billingAddress: '.woocommerce-column--billing-address address', + // shipping address + shippingAddressHeading: '//h2[normalize-space()="Shipping address"]', + shippingAddress: '.woocommerce-column--shipping-address address', + }, + + getSupport: '.dokan-store-support-btn', + }, + + cOrderDetails: { + // Order Details + orderDetails: { + orderDetailsHeading: '.woocommerce-order-details', + orderDetailsTable: '.woocommerce-table--order-details', + + orderNumber: '.order-number', + orderDate: '.order-date', + orderStatus: '.order-status', + + // title + subTotalTitle: '//th[normalize-space()="Subtotal:"]', + shipping: '//th[normalize-space()="Shipping:"]', + paymentMethodTitle: '//th[normalize-space()="Payment method:"]', + orderTotalTitle: '//th[normalize-space()="Total:"]', + + // values + subTotalValue: '//th[normalize-space()="Subtotal:"]//..//span[@class="woocommerce-Price-amount amount"]', + shippingMethodValue: '//th[normalize-space()="Shipping:"]/..//small', + shippingCostValue: '//th[normalize-space()="Shipping:"]/..//span[@class="woocommerce-Price-amount amount"]', + paymentMethodValue: '//th[normalize-space()="Payment method:"]//..//td', + orderTotalValue: '//th[normalize-space()="Total:"]//..//span[@class="woocommerce-Price-amount amount"]', + }, + + // order update [shows when order note exists] + orderUpdates: { + orderReceivedHeading: '//h2[normalize-space()="Order updates"]', + allOrderNotes: 'ol.woocommerce-OrderUpdates.commentlist.notes', + singleOrderNote: 'div.woocommerce-OrderUpdate-description.description p', + orderNote: (note: string) => `//div[@class="woocommerce-OrderUpdate-description description"]//p[contains(text(),"${note}")]`, + }, + + // customer details + customerDetails: { + customerDetailsSection: '.woocommerce-customer-details .addresses', + // Billing address + billingAddressHeading: '//h2[normalize-space()="Billing address"]', + billingAddress: '.woocommerce-column--billing-address address', + // shipping address + shippingAddressHeading: '//h2[normalize-space()="Shipping address"]', + shippingAddress: '.woocommerce-column--shipping-address address', + }, + + orderAgain: '.order-again .button', + getSupport: '.dokan-store-support-btn', + }, + + cDokanSelector: { + dokanAlertSuccessMessage: '.white-popup.dokan-alert-success', + dokanSuccessMessage: '.dokan-alert.dokan-alert-success', + dokanAlertClose: 'button.icon-close', + }, + + cWooSelector: { + wooCommerceSuccessMessage: 'div.woocommerce .woocommerce-message', + wooCommerceError: '.woocommerce .woocommerce-error', + wooCommerceInfo: '.woocommerce .woocommerce-info', + }, + }, +}; diff --git a/tests/pw/pages/sellerBadgesPage.ts b/tests/pw/pages/sellerBadgesPage.ts new file mode 100644 index 0000000000..35b4f17aa4 --- /dev/null +++ b/tests/pw/pages/sellerBadgesPage.ts @@ -0,0 +1,312 @@ +import { Page, expect, test } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { StoresPage } from '@pages/storesPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { sellerBadge } from '@utils/interfaces'; + +export class SellerBadgesPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + storesPage = new StoresPage(this.page); + + // seller badge + + // seller badge render properly + async adminSellerBadgeRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.sellerBadge); + + // seller badge text is visible + await this.toBeVisible(selector.admin.dokan.sellerBadge.sellerBadgeText); + + // create badge is visible + await this.toBeVisible(selector.admin.dokan.sellerBadge.createBadge); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.sellerBadge.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.sellerBadge.bulkActions); + + // search seller badge is visible + await this.toBeVisible(selector.admin.dokan.sellerBadge.search); + + // seller badge table elements are visible + await this.multipleElementVisible(selector.admin.dokan.sellerBadge.table); + } + + // search seller badge + async searchSellerBadge(badgeName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.sellerBadge); + + await this.clearInputField(selector.admin.dokan.sellerBadge.search); + await this.typeAndWaitForResponseAndLoadState(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.search, badgeName); + await this.toBeVisible(selector.admin.dokan.sellerBadge.sellerBadgeCell(badgeName)); + } + + // view seller badge + async viewSellerBadge(badgeName: string) { + await this.searchSellerBadge(badgeName); + + await this.hover(selector.admin.dokan.sellerBadge.sellerBadgeRow(badgeName)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.sellerBadgeEdit(badgeName)); + + // badge condition box is visible + await this.toBeVisible(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.badgeConditionBox); + + // badge event elements are visible + const { badgeEvent, badgePublishedStatus, ...badgeEvents } = selector.admin.dokan.sellerBadge.badgeDetails.badgeEvents; + await this.multipleElementVisible(badgeEvents); + + // badge photo elements are visible + await this.multipleElementVisible(selector.admin.dokan.sellerBadge.badgeDetails.badgePhoto); + + // badge status elements are visible + const { create, ...badgeStatus } = selector.admin.dokan.sellerBadge.badgeDetails.badgeStatus; + await this.multipleElementVisible(badgeStatus); + } + + // create seller badge + async createSellerBadge(badge: sellerBadge) { + await this.goIfNotThere(data.subUrls.backend.dokan.sellerBadge); + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadgeEvent, selector.admin.dokan.sellerBadge.createBadge); + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeEvents.badgeEventDropdown); + const isPublished = await this.isVisible(selector.admin.dokan.sellerBadge.badgeDetails.badgeEvents.badgePublishedStatus(badge.badgeName)); + if (isPublished) { + console.log('Badge is already published'); + test.skip(); + // throw new Error('Badge is already published'); + } + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeEvents.badgeEvent(badge.badgeName)); + await this.clearAndType(selector.admin.dokan.sellerBadge.badgeDetails.badgeEvents.badgeName, badge.badgeName); + + const isLevelExists = await this.isVisible(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.startingLevelValue); + if (isLevelExists) { + await this.clearAndType(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.startingLevelValue, badge.startingLevelValue); + for (let i = 1; i < badge.maxLevel; i++) { + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.addBadgeLevel); + } + } else { + if (badge.badgeName === 'Trending Product') { + await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.trendingProductPeriod, badge.trendingProductPeriod); + await this.clearAndType(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.trendingProductTopBestSellingProduct, badge.trendingProductTopBestSellingProduct); + } + if (badge.badgeName === 'Verified Seller') { + // await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.verifiedSellerMethod, badge.verificationMethod); + const methods: string[] = Object.values(badge.verifiedSellerMethod); + for (let i = 1; i <= methods.length; i++) { + await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.verifiedSellerMethod1(i), methods[i - 1] as string); + if (i === methods.length) { + continue; + } + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.addBadgeLevel); + } + } + } + + await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.badgeStatus.badgeStatus, badge.badgeStatus); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.badgeDetails.badgeStatus.create); + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeAddedSuccessfully); + } + + // edit seller badge + async editSellerBadge(badge: sellerBadge) { + await this.searchSellerBadge(badge.badgeName); + + await this.hover(selector.admin.dokan.sellerBadge.sellerBadgeRow(badge.badgeName)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.sellerBadgeEdit(badge.badgeName)); + + await this.clearAndType(selector.admin.dokan.sellerBadge.badgeDetails.badgeEvents.badgeName, badge.badgeName); + + const isLevelExists = await this.isVisible(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.startingLevelValue); + if (isLevelExists) { + // remove previous badge level + const maxLevel = await this.countLocator(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.badgeLevel); + for (let i = 1; i < maxLevel; i++) { + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.removeBadgeLevel); + } + // add badge level + await this.clearAndType(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.startingLevelValue, badge.startingLevelValue); + for (let i = 1; i < badge.maxLevel; i++) { + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.addBadgeLevel); + } + } else { + if (badge.badgeName === 'Trending Product') { + await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.trendingProductPeriod, badge.trendingProductPeriod); + await this.clearAndType(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.trendingProductTopBestSellingProduct, badge.trendingProductTopBestSellingProduct); + } + if (badge.badgeName === 'Verified Seller') { + // await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.verifiedSellerMethod, badge.verificationMethod); + // remove previous badge level + await this.waitForSelector(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.badgeLevel); + const maxLevel = await this.countLocator(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.badgeLevel); + for (let i = 1; i < maxLevel; i++) { + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.removeBadgeLevel); + } + + // add badge level + const methods: string[] = Object.values(badge.verifiedSellerMethod); + for (let i = 1; i <= methods.length; i++) { + await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.verifiedSellerMethod1(i), methods[i - 1] as string); + if (i === methods.length) { + continue; + } + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeCondition.addBadgeLevel); + } + } + } + + await this.selectByValue(selector.admin.dokan.sellerBadge.badgeDetails.badgeStatus.badgeStatus, badge.badgeStatus); + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeStatus.update); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.badgeDetails.confirmBadgeUpdate); + await this.click(selector.admin.dokan.sellerBadge.badgeDetails.badgeAddedSuccessfully); + } + + // preview seller badge + async previewSellerBadge(badgeName: string) { + await this.searchSellerBadge(badgeName); + + const badgeLevel = await this.getElementText(selector.admin.dokan.sellerBadge.sellerBadgeLevel(badgeName)); + + await this.hover(selector.admin.dokan.sellerBadge.sellerBadgeRow(badgeName)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.sellerBadgePreview(badgeName)); + + // badge preview modal is visible + await this.toBeVisible(selector.admin.dokan.sellerBadge.previewBadgeDetails.modal); + + // badge preview header elements are visible + await this.multipleElementVisible(selector.admin.dokan.sellerBadge.previewBadgeDetails.modalHeader); + + await this.toHaveCount(selector.admin.dokan.sellerBadge.previewBadgeDetails.levelBox, Number(badgeLevel)); + + await this.click(selector.admin.dokan.sellerBadge.previewBadgeDetails.modalHeader.modalClose); + } + + // filter vendors by badge + async filterVendorsByBadge(badgeName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.vendors); + + await this.clickIfVisible(selector.admin.dokan.vendors.filters.clearFilter); + await this.selectByLabel(selector.admin.dokan.vendors.filters.filterByBadges, badgeName); + + const count = (await this.getElementText(selector.admin.dokan.vendors.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } + + // seller badge vendors + async sellerBadgeVendors(badgeName: string) { + await this.searchSellerBadge(badgeName); + + await this.hover(selector.admin.dokan.sellerBadge.sellerBadgeRow(badgeName)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.sellerBadgeVendors(badgeName)); + // await this.toBeVisible(selector.admin.dokan.vendors.vendorCell(badgeName)); + const count = (await this.getElementText(selector.admin.dokan.vendors.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } + + // badges acquired by vendor + async sellerBadgeAcquiredByVendor(vendorName: string) { + await this.storesPage.searchVendor(vendorName); + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.vendors.vendorViewDetails(vendorName)); + await this.toBeVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.badgesAcquired.badgesAcquired); + // todo: add assertions for achieved badges + } + + // update seller badge + async updateSellerBadge(badgeName: string, status: string) { + await this.searchSellerBadge(badgeName); + + await this.hover(selector.admin.dokan.sellerBadge.sellerBadgeRow(badgeName)); + + switch (status) { + case 'publish': + await this.click(selector.admin.dokan.sellerBadge.sellerBadgePublish(badgeName)); + break; + + case 'draft': + await this.click(selector.admin.dokan.sellerBadge.sellerBadgeDraft(badgeName)); + break; + + case 'delete': + await this.click(selector.admin.dokan.sellerBadge.sellerBadgeDelete(badgeName)); + break; + + default: + break; + } + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.confirmAction); + await this.click(selector.admin.dokan.sellerBadge.successMessage); + } + + // seller badge bulk action + async sellerBadgeBulkAction(action: string, badgeName?: string) { + badgeName ? await this.searchSellerBadge(badgeName) : await this.goIfNotThere(data.subUrls.backend.dokan.sellerBadge); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.sellerBadge.noRowsFound); + + await this.click(selector.admin.dokan.sellerBadge.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.sellerBadge.bulkActions.selectAction, action); + await this.click(selector.admin.dokan.sellerBadge.bulkActions.applyAction); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.sellerBadge, selector.admin.dokan.sellerBadge.confirmAction); + await this.click(selector.admin.dokan.sellerBadge.successMessage); + } + + // vendor seller badge render properly + async vendorSellerBadgeRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.badges); + + // badges text is visible + await this.toBeVisible(selector.vendor.vBadges.badgesText); + + // badge description text is visible + await this.toBeVisible(selector.vendor.vBadges.description); + + // badge search is visible + await this.toBeVisible(selector.vendor.vBadges.search); + + // badge filter is visible + await this.toBeVisible(selector.vendor.vBadges.filterBadges); + + // seller badge table elements are visible + await this.multipleElementVisible(selector.vendor.vBadges.table); + } + + // vendor achieved badges congrats popup + async sellerBadgeCongratsPopup() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.badges); + + const congratsModalIsVisible = await this.isVisible(selector.vendor.vBadges.congratsModal.sellerBadgeModal); + if (congratsModalIsVisible) { + // seller badge congrats modal elements are visible + await this.multipleElementVisible(selector.vendor.vBadges.congratsModal); + + await this.clickIfVisible(selector.vendor.vBadges.congratsModal.closeModal); + } else { + console.log('No Congrats message appeared'); + } + } + + // vendor search seller badge + async vendorSearchSellerBadge(badgeName: string) { + await this.clickIfVisible(selector.vendor.vBadges.congratsModal.closeModal); + await this.goIfNotThere(data.subUrls.frontend.vDashboard.badges); + await this.clearAndType(selector.vendor.vBadges.search, badgeName); + await this.toBeVisible(selector.vendor.vBadges.sellerBadgeCell(badgeName)); + } + + // vendor filter seller badge + async filterSellerBadges(option: string) { + await this.clickIfVisible(selector.vendor.vBadges.congratsModal.closeModal); + + await this.goIfNotThere(data.subUrls.frontend.vDashboard.badges); + await this.selectByValue(selector.vendor.vBadges.filterBadges, option); + const count = (await this.getElementText(selector.vendor.vBadges.numberOfBadgesFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } +} diff --git a/tests/pw/pages/settingsPage.ts b/tests/pw/pages/settingsPage.ts new file mode 100644 index 0000000000..9043a580d2 --- /dev/null +++ b/tests/pw/pages/settingsPage.ts @@ -0,0 +1,550 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { dokanSettings } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class SettingsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // settings + + // dokan settings render properly + async dokanSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.settings); + + // settings text is visible + await this.toBeVisible(selector.admin.dokan.settings.settingsText); + + // settings section elements are visible + await this.multipleElementVisible(selector.admin.dokan.settings.sections); + + // settings header elements are visible + await this.multipleElementVisible(selector.admin.dokan.settings.header); + + // settings field is visible + await this.toBeVisible(selector.admin.dokan.settings.fields); + + // settings save Changes is visible + await this.toBeVisible(selector.admin.dokan.settings.saveChanges); + } + + // search settings + async searchSettings(settings: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.settings); + + await this.clearAndType(selector.admin.dokan.settings.search.input, settings); + await this.toBeVisible(selector.admin.dokan.settings.fields); + await this.click(selector.admin.dokan.settings.search.close); + } + + // scroll to top settings + async scrollToTopSettings() { + await this.goIfNotThere(data.subUrls.backend.dokan.settings); + + await this.scrollToBottom(); + await this.toBeVisible(selector.admin.dokan.settings.backToTop); + } + + // dokan settings + + // admin set dokan general settings + async setDokanGeneralSettings(general: dokanSettings['general']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.general); + + // site options + await this.enableSwitcher(selector.admin.dokan.settings.general.adminAreaAccess); + await this.clearAndType(selector.admin.dokan.settings.general.vendorStoreUrl, general.vendorStoreUrl); + await this.typeFrameSelector(selector.admin.dokan.settings.general.setupWizardMessageIframe, selector.admin.dokan.settings.general.setupWizardMessageHtmlBody, general.setupWizardMessage); + DOKAN_PRO && (await this.click(selector.admin.dokan.settings.general.sellingProductTypes(general.sellingProductTypes))); + + // vendor store options + await this.enableSwitcher(selector.admin.dokan.settings.general.storeTermsAndConditions); + await this.clearAndType(selector.admin.dokan.settings.general.storeProductPerPage, general.storeProductPerPage); + if (DOKAN_PRO) { + await this.enableSwitcher(selector.admin.dokan.settings.general.enableTermsAndCondition); + await this.click(selector.admin.dokan.settings.general.storCategory(general.storCategory)); + } + + // product page settings + await this.enableSwitcher(selector.admin.dokan.settings.general.showVendorInfo); + await this.enableSwitcher(selector.admin.dokan.settings.general.enableMoreProductsTab); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.general.generalSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, general.saveSuccessMessage); + } + + // admin set dokan selling settings + async setDokanSellingSettings(selling: dokanSettings['selling']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.sellingOptions); + + // commission settings + await this.selectByValue(selector.admin.dokan.settings.selling.commissionType, selling.commissionType); + await this.clearAndType(selector.admin.dokan.settings.selling.adminCommission, selling.adminCommission); + // await this.click(selector.admin.dokan.settings.selling.shippingFeeRecipient(selling.shippingFeeRecipient)); //todo: makes test flaky + await this.click(selector.admin.dokan.settings.selling.productTaxFeeRecipient(selling.productTaxFeeRecipient)); + await this.click(selector.admin.dokan.settings.selling.shippingTaxFeeRecipient(selling.shippingTaxFeeRecipient)); + + // vendor capabilities + await this.enableSwitcher(selector.admin.dokan.settings.selling.enableSelling); + await this.enableSwitcher(selector.admin.dokan.settings.selling.onePageProductCreate); + await this.enableSwitcher(selector.admin.dokan.settings.selling.orderStatusChange); + await this.enableSwitcher(selector.admin.dokan.settings.selling.selectAnyCategory); + if (DOKAN_PRO) { + await this.click(selector.admin.dokan.settings.selling.newProductStatus(selling.newProductStatus)); + await this.enableSwitcher(selector.admin.dokan.settings.selling.duplicateProduct); + await this.click(selector.admin.dokan.settings.selling.productCategorySelection(selling.productCategorySelection)); + await this.enableSwitcher(selector.admin.dokan.settings.selling.vendorsCanCreateTags); + await this.enableSwitcher(selector.admin.dokan.settings.selling.orderDiscount); + await this.enableSwitcher(selector.admin.dokan.settings.selling.productDiscount); + await this.enableSwitcher(selector.admin.dokan.settings.selling.vendorProductReviewStatusChange); + await this.enableSwitcher(selector.admin.dokan.settings.selling.guestProductEnquiry); + await this.enableSwitcher(selector.admin.dokan.settings.selling.newVendorEnableAuction); + await this.enableSwitcher(selector.admin.dokan.settings.selling.enableMinMaxQuantities); + await this.enableSwitcher(selector.admin.dokan.settings.selling.enableMinMaxAmount); + } + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.selling.sellingOptionsSaveChanges); + await this.toHaveValue(selector.admin.dokan.settings.selling.adminCommission, selling.adminCommission); + } + + // Admin Set Dokan Withdraw Settings + async setDokanWithdrawSettings(withdraw: dokanSettings['withdraw']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.withdrawOptions); + + // Withdraw Options + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.withdrawMethodsPaypal); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.withdrawMethodsBankTransfer); + if (DOKAN_PRO) { + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.withdrawMethodsDokanCustom); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.withdrawMethodsSkrill); + await this.clearAndType(selector.admin.dokan.settings.withdraw.customMethodName, withdraw.customMethodName); + await this.clearAndType(selector.admin.dokan.settings.withdraw.customMethodType, withdraw.customMethodType); + } + await this.clearAndType(selector.admin.dokan.settings.withdraw.minimumWithdrawAmount, withdraw.minimumWithdrawAmount); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.orderStatusForWithdrawCompleted); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.orderStatusForWithdrawProcessing); + if (DOKAN_PRO) { + await this.clearAndType(selector.admin.dokan.settings.withdraw.withdrawThreshold, withdraw.withdrawThreshold); + + // Disbursement Schedule Settings + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.withdrawDisbursementManual); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.withdrawDisbursementAuto); + + // Disbursement Schedule + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.disburseMentQuarterlySchedule); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.disburseMentMonthlySchedule); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.disburseMentBiweeklySchedule); + await this.enableSwitcher(selector.admin.dokan.settings.withdraw.disburseMentWeeklySchedule); + + // Quarterly Schedule + await this.selectByValue(selector.admin.dokan.settings.withdraw.quarterlyScheduleMonth, withdraw.quarterlyScheduleMonth); + await this.selectByValue(selector.admin.dokan.settings.withdraw.quarterlyScheduleWeek, withdraw.quarterlyScheduleWeek); + await this.selectByValue(selector.admin.dokan.settings.withdraw.quarterlyScheduleDay, withdraw.quarterlyScheduleDay); + // Monthly Schedule + await this.selectByValue(selector.admin.dokan.settings.withdraw.monthlyScheduleWeek, withdraw.monthlyScheduleWeek); + await this.selectByValue(selector.admin.dokan.settings.withdraw.monthlyScheduleDay, withdraw.monthlyScheduleDay); + // Biweekly Schedule + await this.selectByValue(selector.admin.dokan.settings.withdraw.biweeklyScheduleWeek, withdraw.biweeklyScheduleWeek); + await this.selectByValue(selector.admin.dokan.settings.withdraw.biweeklyScheduleDay, withdraw.biweeklyScheduleDay); + // Weekly Schedule + await this.selectByValue(selector.admin.dokan.settings.withdraw.weeklyScheduleDay, withdraw.weeklyScheduleDay); + } + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.withdraw.withdrawSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, withdraw.saveSuccessMessage); + } + + // Admin Set Dokan Reverse Withdraw Settings + async setDokanReverseWithdrawSettings(reverseWithdraw: dokanSettings['reverseWithdraw']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.reverseWithdrawal); + + // reverse withdraw options + await this.enableSwitcher(selector.admin.dokan.settings.reverseWithdraw.enableReverseWithdrawal); + await this.enableSwitcher(selector.admin.dokan.settings.reverseWithdraw.enableReverseWithdrawalForThisGateway); + + await this.selectByValue(selector.admin.dokan.settings.reverseWithdraw.billingType, reverseWithdraw.billingType); + await this.clearAndType(selector.admin.dokan.settings.reverseWithdraw.reverseBalanceThreshold, reverseWithdraw.reverseBalanceThreshold); + await this.clearAndType(selector.admin.dokan.settings.reverseWithdraw.gracePeriod, reverseWithdraw.gracePeriod); + + await this.enableSwitcher(selector.admin.dokan.settings.reverseWithdraw.disableAddToCartButton); + await this.enableSwitcher(selector.admin.dokan.settings.reverseWithdraw.hideWithdrawMenu); + await this.enableSwitcher(selector.admin.dokan.settings.reverseWithdraw.MakeVendorStatusInactive); + + await this.enableSwitcher(selector.admin.dokan.settings.reverseWithdraw.displayNoticeDuringGracePeriod); + DOKAN_PRO && (await this.enableSwitcher(selector.admin.dokan.settings.reverseWithdraw.sendAnnouncement)); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.reverseWithdraw.reverseWithdrawSaveChanges); + await this.toHaveValue(selector.admin.dokan.settings.reverseWithdraw.reverseBalanceThreshold, reverseWithdraw.reverseBalanceThreshold); + } + + // Admin Set Dokan Page Settings + async setPageSettings(page: dokanSettings['page']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.pageSettings); + + await this.selectByLabel(selector.admin.dokan.settings.page.dashboard, page.dashboard); + await this.selectByLabel(selector.admin.dokan.settings.page.myOrders, page.myOrders); + await this.selectByLabel(selector.admin.dokan.settings.page.storeListing, page.storeListing); + await this.selectByLabel(selector.admin.dokan.settings.page.termsAndConditions, page.termsAndConditions); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.page.pageSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, page.saveSuccessMessage); + } + + // Admin Set Dokan Appearance Settings + async setDokanAppearanceSettings(appearance: dokanSettings['appearance']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.appearance); + + // Appearance Settings + await this.enableSwitcher(selector.admin.dokan.settings.appearance.showMapOnStorePage); + await this.click(selector.admin.dokan.settings.appearance.mapApiSourceGoogleMaps); + await this.clearAndType(selector.admin.dokan.settings.appearance.googleMapApiKey, appearance.googleMapApiKey); + await this.enableSwitcher(selector.admin.dokan.settings.appearance.showContactFormOnStorePage); + await this.click(selector.admin.dokan.settings.appearance.storeHeaderTemplate2); + await this.click(selector.admin.dokan.settings.appearance.storeHeaderTemplate1); + if (DOKAN_PRO) { + await this.clearAndType(selector.admin.dokan.settings.appearance.storeBannerWidth, appearance.storeBannerWidth); + await this.clearAndType(selector.admin.dokan.settings.appearance.storeBannerHeight, appearance.storeBannerHeight); + await this.enableSwitcher(selector.admin.dokan.settings.appearance.storeOpeningClosingTimeWidget); + } + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.appearance.appearanceSaveChanges); + await this.toHaveValue(selector.admin.dokan.settings.appearance.googleMapApiKey, appearance.googleMapApiKey); + } + + // Admin Set Dokan Privacy Policy Settings + async setDokanPrivacyPolicySettings(privacyPolicy: dokanSettings['privacyPolicy']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.privacyPolicy); + + // Privacy Policy Settings + await this.enableSwitcher(selector.admin.dokan.settings.privacyPolicy.enablePrivacyPolicy); + await this.selectByValue(selector.admin.dokan.settings.privacyPolicy.privacyPage, privacyPolicy.privacyPage); + await this.typeFrameSelector(selector.admin.dokan.settings.privacyPolicy.privacyPolicyIframe, selector.admin.dokan.settings.privacyPolicy.privacyPolicyHtmlBody, privacyPolicy.privacyPolicyContent); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.privacyPolicy.privacyPolicySaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, privacyPolicy.saveSuccessMessage); + } + + // Admin Set Dokan Color Settings + async setDokanColorSettings(colors: dokanSettings['colors']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.colors); + + // Colors Settings + if (colors.paletteChoice === 'pre-defined') { + await this.click(selector.admin.dokan.settings.colors.predefineColorPalette); + await this.click(selector.admin.dokan.settings.colors.colorPalette[colors.colorPalette as keyof typeof selector.admin.dokan.settings.colors.colorPalette]); + } + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.colors.colorsSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, colors.saveSuccessMessage); + } + + // Admin Set Dokan Live Search Settings + async setDokanLiveSearchSettings(liveSearch: dokanSettings['liveSearch']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.liveSearch); + + // Live Search Settings + await this.selectByValue(selector.admin.dokan.settings.liveSearch.liveSearchOptions, liveSearch.liveSearchOption); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.liveSearch.liveSearchSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, liveSearch.saveSuccessMessage); + } + + // Admin Set Dokan Store Support Settings + async setDokanStoreSupportSettings(storeSupport: dokanSettings['storeSupport']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.storeSupport); + + // Store Support Settings + await this.enableSwitcher(selector.admin.dokan.settings.storeSupport.displayOnOrderDetails); + await this.selectByValue(selector.admin.dokan.settings.storeSupport.displayOnSingleProductPage, storeSupport.displayOnSingleProductPage); + await this.clearAndType(selector.admin.dokan.settings.storeSupport.supportButtonLabel, storeSupport.supportButtonLabel); + await this.enableSwitcher(selector.admin.dokan.settings.storeSupport.supportTicketEmailNotification); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.storeSupport.storeSupportSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, storeSupport.saveSuccessMessage); + } + + // Admin Set Dokan Email Verification Settings + async setDokanEmailVerificationSettings(emailVerification: dokanSettings['emailVerification']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.emailVerification); + + // Email Verification Settings + await this.enableSwitcher(selector.admin.dokan.settings.emailVerification.enableEmailVerification); + await this.clearAndType(selector.admin.dokan.settings.emailVerification.registrationNotice, emailVerification.registrationNotice); + await this.clearAndType(selector.admin.dokan.settings.emailVerification.loginNotice, emailVerification.loginNotice); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.emailVerification.emailVerificationSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, emailVerification.saveSuccessMessage); + } + + // Admin Set Dokan Shipping Status Settings + async setDokanShippingStatusSettings(shippingStatus: dokanSettings['shippingStatus']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.shippingStatus); + + // Shipping Status Settings + await this.enableSwitcher(selector.admin.dokan.settings.shippingStatus.allowShipmentTracking); + + // shipping status + await this.enableSwitcher(selector.admin.dokan.settings.shippingStatus.shippingProviders.australiaPost); + await this.enableSwitcher(selector.admin.dokan.settings.shippingStatus.shippingProviders.canadaPost); + await this.enableSwitcher(selector.admin.dokan.settings.shippingStatus.shippingProviders.cityLink); + + await this.clearAndType(selector.admin.dokan.settings.shippingStatus.customShippingStatusInput, shippingStatus.customShippingStatus); + await this.click(selector.admin.dokan.settings.shippingStatus.customShippingStatusAdd); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.shippingStatus.shippingStatusSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, shippingStatus.saveSuccessMessage); + } + + // Admin Set Dokan Quote Settings + async setDokanQuoteSettings(quote: dokanSettings['quote']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.quote); + + // Live Search Settings + await this.enableSwitcher(selector.admin.dokan.settings.quote.enableQuoteForOutOfStockProducts); + await this.enableSwitcher(selector.admin.dokan.settings.quote.enableAjaxAddToQuote); + await this.enableSwitcher(selector.admin.dokan.settings.quote.redirectToQuotePage); + + await this.clearAndType(selector.admin.dokan.settings.quote.decreaseOfferedPrice, quote.decreaseOfferedPrice); + // await this.enableSwitcher(selector.admin.dokan.settings.quote.enableConvertToOrder); + // await this.enableSwitcher(selector.admin.dokan.settings.quote.enableQuoteConverterDisplay); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.quote.quoteSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, quote.saveSuccessMessage); + } + + // Admin Set Dokan Rma Settings + async setDokanRmaSettings(rma: dokanSettings['rma']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.rma); + + // Rma Settings + await this.selectByValue(selector.admin.dokan.settings.rma.orderStatus, rma.orderStatus); + await this.enableSwitcher(selector.admin.dokan.settings.rma.enableRefundRequests); + await this.enableSwitcher(selector.admin.dokan.settings.rma.enableCouponRequests); + + for (const rmaReason of rma.rmaReasons) { + await this.deleteIfExists(selector.admin.dokan.settings.rma.reasonsForRmaSingle(rmaReason)); + await this.clearAndType(selector.admin.dokan.settings.rma.reasonsForRmaInput, rmaReason); + await this.click(selector.admin.dokan.settings.rma.reasonsForRmaAdd); + } + + await this.typeFrameSelector(selector.admin.dokan.settings.rma.refundPolicyIframe, selector.admin.dokan.settings.rma.refundPolicyHtmlBody, rma.refundPolicyHtmlBody); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.rma.rmaSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, rma.saveSuccessMessage); + } + + // Admin Set Dokan Wholesale Settings + async setDokanWholesaleSettings(wholesale: dokanSettings['wholesale']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.wholesale); + + // Wholesale Settings + await this.click(selector.admin.dokan.settings.wholesale.whoCanSeeWholesalePrice(wholesale.whoCanSeeWholesalePrice)); + await this.enableSwitcher(selector.admin.dokan.settings.wholesale.showWholesalePriceOnShopArchive); + await this.disableSwitcher(selector.admin.dokan.settings.wholesale.needApprovalForCustomer); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.wholesale.wholesaleSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, wholesale.saveSuccessMessage); + } + + // Admin Set Dokan Eu Compliance Settings + async setDokanEuComplianceSettings(euCompliance: dokanSettings['euCompliance']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.euComplianceFields); + + // Eu Compliance Settings + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.vendorExtraFieldsCompanyName); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.vendorExtraFieldsCompanyIdOrEuidNumber); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.vendorExtraFieldsVatOrTaxNumber); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.vendorExtraFieldsNameOfBank); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.vendorExtraFieldsBankIban); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.displayInVendorRegistrationForm); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.customerExtraFieldsCompanyIdOrEuidNumber); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.customerExtraFieldsVatOrTaxNumber); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.customerExtraFieldsNameOfBank); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.customerExtraFieldsBankIban); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.enableGermanizedSupportForVendors); + await this.enableSwitcher(selector.admin.dokan.settings.euCompliance.vendorsWillBeAbleToOverrideInvoiceNumber); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.euCompliance.euComplianceFieldsSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, euCompliance.saveSuccessMessage); + } + + // Admin Set Dokan Delivery Time Settings + async setDokanDeliveryTimeSettings(deliveryTime: dokanSettings['deliveryTime']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.deliveryTime); + + // Delivery Time Settings + await this.enableSwitcher(selector.admin.dokan.settings.deliveryTime.allowVendorSettings); + await this.enableSwitcher(selector.admin.dokan.settings.deliveryTime.homeDelivery); + await this.enableSwitcher(selector.admin.dokan.settings.deliveryTime.storePickup); + await this.clearAndType(selector.admin.dokan.settings.deliveryTime.deliveryDateLabel, deliveryTime.deliveryDateLabel); + await this.clearAndType(selector.admin.dokan.settings.deliveryTime.deliveryBlockedBuffer, deliveryTime.deliveryBlockedBuffer); + await this.clearAndType(selector.admin.dokan.settings.deliveryTime.timeSlot, deliveryTime.timeSlot); + await this.clearAndType(selector.admin.dokan.settings.deliveryTime.orderPerSlot, deliveryTime.orderPerSlot); + await this.clearAndType(selector.admin.dokan.settings.deliveryTime.deliveryBoxInfo, deliveryTime.deliveryBoxInfo); + await this.disableSwitcher(selector.admin.dokan.settings.deliveryTime.requireDeliveryDateAndTime); + for (const day of deliveryTime.days) { + await this.enableSwitcher(selector.admin.dokan.settings.deliveryTime.deliveryDay(day)); + if (deliveryTime.choice === 'full-day') { + await this.click(selector.admin.dokan.settings.deliveryTime.openingTime(day)); + await this.page.getByRole('listitem').filter({ hasText: 'Full day' }).click(); + } else { + await this.page.getByRole('listitem').filter({ hasText: deliveryTime.openingTime }).click(); + await this.click(selector.admin.dokan.settings.deliveryTime.closingTime(day)); + await this.page.getByRole('listitem').filter({ hasText: deliveryTime.closingTime }).click(); + } + } + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.deliveryTime.deliveryTimeSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, deliveryTime.saveSuccessMessage); + } + + // Admin Set Dokan Product Advertising Settings + async setDokanProductAdvertisingSettings(productAdvertising: dokanSettings['productAdvertising']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.productAdvertising); + + // Product Advertising Settings + await this.clearAndType(selector.admin.dokan.settings.productAdvertising.noOfAvailableSlot, productAdvertising.noOfAvailableSlot); + await this.clearAndType(selector.admin.dokan.settings.productAdvertising.expireAfterDays, productAdvertising.expireAfterDays); + await this.enableSwitcher(selector.admin.dokan.settings.productAdvertising.vendorCanPurchaseAdvertisement); + await this.clearAndType(selector.admin.dokan.settings.productAdvertising.advertisementCost, productAdvertising.advertisementCost); + await this.enableSwitcher(selector.admin.dokan.settings.productAdvertising.enableAdvertisementInSubscription); + await this.enableSwitcher(selector.admin.dokan.settings.productAdvertising.markAdvertisedProductAsFeatured); + await this.enableSwitcher(selector.admin.dokan.settings.productAdvertising.displayAdvertisedProductOnTop); + await this.enableSwitcher(selector.admin.dokan.settings.productAdvertising.outOfStockVisibility); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.productAdvertising.productAdvertisingSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, productAdvertising.saveSuccessMessage); + } + + // Admin Set Dokan Geolocation Settings + async setDokanGeolocationSettings(geolocation: dokanSettings['geolocation']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.geolocation); + + // Geolocation Settings + await this.click(selector.admin.dokan.settings.geolocation.locationMapPosition(geolocation.locationMapPosition)); + await this.click(selector.admin.dokan.settings.geolocation.showMap(geolocation.showMap)); + await this.enableSwitcher(selector.admin.dokan.settings.geolocation.showFiltersBeforeLocationMap); + await this.enableSwitcher(selector.admin.dokan.settings.geolocation.productLocationTab); + await this.click(selector.admin.dokan.settings.geolocation.radiusSearchUnit(geolocation.radiusSearchUnit)); + await this.clearAndType(selector.admin.dokan.settings.geolocation.radiusSearchMinimumDistance, geolocation.radiusSearchMinimumDistance); + await this.clearAndType(selector.admin.dokan.settings.geolocation.radiusSearchMaximumDistance, geolocation.radiusSearchMaximumDistance); + await this.clearAndType(selector.admin.dokan.settings.geolocation.mapZoomLevel, geolocation.mapZoomLevel); + await this.focus(selector.admin.dokan.settings.geolocation.defaultLocation); + await this.typeAndWaitForResponse(data.subUrls.gmap, selector.admin.dokan.settings.geolocation.defaultLocation, geolocation.defaultLocation); + // await this.press(data.key.arrowDown); + // await this.press(data.key.enter); + await this.click(selector.admin.dokan.settings.geolocation.mapResultFirst); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.geolocation.geolocationSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, geolocation.saveSuccessMessage); + } + + // Admin Set Dokan Product Report Abuse Settings + async setDokanProductReportAbuseSettings(productReportAbuse: dokanSettings['productReportAbuse']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.productReportAbuse); + + // Product Report Abuse Settings + await this.deleteIfExists(selector.admin.dokan.settings.productReportAbuse.reasonsForAbuseReportSingle(productReportAbuse.reasonsForAbuseReport)); + await this.clearAndType(selector.admin.dokan.settings.productReportAbuse.reasonsForAbuseReportInput, productReportAbuse.reasonsForAbuseReport); + await this.click(selector.admin.dokan.settings.productReportAbuse.reasonsForAbuseReportAdd); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.productReportAbuse.productReportAbuseSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, productReportAbuse.saveSuccessMessage); + } + + // Admin Set Dokan Spmv Settings + async setDokanSpmvSettings(spmv: dokanSettings['spmv']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.singleProductMultiVendor); + + await this.enableSwitcher(selector.admin.dokan.settings.spmv.enableSingleProductMultipleVendor); + await this.clearAndType(selector.admin.dokan.settings.spmv.sellItemButtonText, spmv.sellItemButtonText); + await this.clearAndType(selector.admin.dokan.settings.spmv.availableVendorDisplayAreaTitle, spmv.availableVendorDisplayAreaTitle); + await this.selectByValue(selector.admin.dokan.settings.spmv.availableVendorSectionDisplayPosition, spmv.availableVendorSectionDisplayPosition); + await this.selectByValue(selector.admin.dokan.settings.spmv.showSpmvProducts, spmv.showSpmvProducts); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.spmv.singleProductMultiVendorSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, spmv.saveSuccessMessage); + } + + // Admin Set Dokan Vendor Subscription Settings + async setDokanVendorSubscriptionSettings(subscription: dokanSettings['vendorSubscription']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.vendorSubscription); + + // Vendor Subscription Settings + await this.selectByLabel(selector.admin.dokan.settings.vendorSubscriptions.subscription, subscription.displayPage); + await this.enableSwitcher(selector.admin.dokan.settings.vendorSubscriptions.enableProductSubscription); + await this.enableSwitcher(selector.admin.dokan.settings.vendorSubscriptions.enableSubscriptionInRegistrationForm); + await this.enableSwitcher(selector.admin.dokan.settings.vendorSubscriptions.enableEmailNotification); + await this.clearAndType(selector.admin.dokan.settings.vendorSubscriptions.noOfDays, subscription.noOfDays); + await this.selectByValue(selector.admin.dokan.settings.vendorSubscriptions.productStatus, subscription.productStatus); + await this.clearAndType(selector.admin.dokan.settings.vendorSubscriptions.cancellingEmailSubject, subscription.cancellingEmailSubject); + await this.clearAndType(selector.admin.dokan.settings.vendorSubscriptions.cancellingEmailBody, subscription.cancellingEmailBody); + await this.clearAndType(selector.admin.dokan.settings.vendorSubscriptions.alertEmailSubject, subscription.alertEmailSubject); + await this.clearAndType(selector.admin.dokan.settings.vendorSubscriptions.alertEmailBody, subscription.alertEmailBody); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.vendorSubscriptions.vendorSubscriptionSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, subscription.saveSuccessMessage); + } + + // disable dokan vendor subscription + async disableDokanVendorSubscription(subscription: dokanSettings['vendorSubscription']) { + await this.goToDokanSettings(); + await this.click(selector.admin.dokan.settings.menus.vendorSubscription); + + // Disabling Vendor Subscription + await this.disableSwitcher(selector.admin.dokan.settings.vendorSubscriptions.enableProductSubscription); + + // save settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.vendorSubscriptions.vendorSubscriptionSaveChanges); + await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, subscription.saveSuccessMessage); + } +} diff --git a/tests/pw/pages/shippingPage.ts b/tests/pw/pages/shippingPage.ts new file mode 100644 index 0000000000..d0817620d2 --- /dev/null +++ b/tests/pw/pages/shippingPage.ts @@ -0,0 +1,142 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +// import { shipping } from '@utils/interfaces'; + +export class shippingPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // Shipping Methods + + // Admin Setup Woocommerce Settings + async setWoocommerceShippingSettings(data: any) { + await this.enablePasswordInputField(data); + await this.addShippingMethod(data.shipping.shippingMethods.flatRate); + await this.addShippingMethod(data.shipping.shippingMethods.freeShipping); + await this.addShippingMethod(data.shipping.shippingMethods.tableRateShipping); + await this.addShippingMethod(data.shipping.shippingMethods.distanceRateShipping); + await this.addShippingMethod(data.shipping.shippingMethods.vendorShipping); + await this.deleteShippingMethod(data.shipping.shippingMethods.flatRate); + await this.deleteShippingZone(data.shipping.shippingZone); + } + + // Enable-Disable Shipping + async enableShipping(enable = true) { + await this.goToWooCommerceSettings(); + await this.click(selector.admin.wooCommerce.settings.enableShipping); + enable + ? await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.enableShippingValues, data.shipping.enableShipping) + : await this.setDropdownOptionSpan(selector.admin.wooCommerce.settings.enableShippingValues, data.shipping.disableShipping); + await this.click(selector.admin.wooCommerce.settings.generalSaveChanges); + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, data.shipping.saveSuccessMessage); + } + + // Admin Add Shipping Method + async addShippingMethod(shipping: any) { + await this.goToWooCommerceSettings(); + + await this.click(selector.admin.wooCommerce.settings.shipping); + + const zoneIsVisible = await this.isVisible(selector.admin.wooCommerce.settings.shippingZoneCell(shipping.shippingZone)); + if (!zoneIsVisible) { + // Add Shipping Zone + await this.click(selector.admin.wooCommerce.settings.addShippingZone); + await this.clearAndType(selector.admin.wooCommerce.settings.zoneName, shipping.shippingZone); + // await this.selectByValue(selector.admin.wooCommerce.settings.zoneRegions, shippingCountry) //use select values 'country:US', + await this.click(selector.admin.wooCommerce.settings.zoneRegions); + await this.type(selector.admin.wooCommerce.settings.zoneRegions, shipping.shippingCountry); + await this.press(data.key.enter); + } else { + // Edit Shipping Zone + await this.hover(selector.admin.wooCommerce.settings.shippingZoneCell(shipping.shippingZone)); + await this.click(selector.admin.wooCommerce.settings.editShippingMethod(shipping.shippingZone)); + } + + const methodIsVisible = await this.isVisible(selector.admin.wooCommerce.settings.shippingMethodCell(helpers.replaceAndCapitalize(shipping.shippingMethod))); + if (!methodIsVisible) { + // Add Shipping Method + await this.click(selector.admin.wooCommerce.settings.addShippingMethods); + await this.selectByValue(selector.admin.wooCommerce.settings.shippingMethod, shipping.selectShippingMethod); + await this.click(selector.admin.wooCommerce.settings.addShippingMethod); + } + + // Edit Shipping Method Options + await this.hover(selector.admin.wooCommerce.settings.shippingMethodCell(shipping.shippingMethod)); + await this.click(selector.admin.wooCommerce.settings.editShippingMethod(shipping.shippingMethod)); + + switch (shipping.selectShippingMethod) { + // Flat Rate + case 'flat_rate': + await this.clearAndType(selector.admin.wooCommerce.settings.flatRateMethodTitle, shipping.shippingMethod); + await this.selectByValue(selector.admin.wooCommerce.settings.flatRateTaxStatus, shipping.taxStatus); + await this.clearAndType(selector.admin.wooCommerce.settings.flatRateCost, shipping.shippingCost); + break; + + // Free Shipping + case 'free_shipping': + await this.clearAndType(selector.admin.wooCommerce.settings.freeShippingTitle, shipping.shippingMethod); + // await this.selectByValue(selector.admin.wooCommerce.settings.freeShippingRequires, shipping.freeShippingRequires) + // await this.clearAndType(selector.admin.wooCommerce.settings.freeShippingMinimumOrderAmount,shipping.freeShippingMinimumOrderAmount) + // await this.check(selector.admin.wooCommerce.settings.freeShippingCouponsDiscounts) + break; + + // Local Pickup + case 'local_pickup': + await this.clearAndType(selector.admin.wooCommerce.settings.localPickupTitle, shipping.shippingMethod); + await this.selectByValue(selector.admin.wooCommerce.settings.localPickupTaxStatus, shipping.taxStatus); + await this.clearAndType(selector.admin.wooCommerce.settings.localPickupCost, shipping.shippingCost); + break; + + // Dokan Table Rate Shipping + case 'dokan_table_rate_shipping': + await this.clearAndType(selector.admin.wooCommerce.settings.dokanTableRateShippingMethodTitle, shipping.shippingMethod); + break; + + // Dokan Distance Rate Shipping + case 'dokan_distance_rate_shipping': + await this.clearAndType(selector.admin.wooCommerce.settings.dokanDistanceRateShippingMethodTitle, shipping.shippingMethod); + break; + + // Vendor Shipping + case 'dokan_vendor_shipping': + await this.clearAndType(selector.admin.wooCommerce.settings.vendorShippingMethodTitle, shipping.shippingMethod); + await this.selectByValue(selector.admin.wooCommerce.settings.vendorShippingTaxStatus, shipping.taxStatus); + break; + + default: + break; + } + + await this.click(selector.admin.wooCommerce.settings.shippingMethodSaveChanges); + await this.toBeVisible(selector.admin.wooCommerce.settings.shippingMethodCell(shipping.shippingMethod)); + } + + // Admin Delete Shipping Zone + async deleteShippingZone(shippingZone: string) { + await this.click(selector.admin.wooCommerce.settings.shipping); + + await this.hover(selector.admin.wooCommerce.settings.shippingZoneCell(shippingZone)); + await this.clickAndAccept(selector.admin.wooCommerce.settings.deleteShippingZone(shippingZone)); + + const shippingZoneIsVisible = await this.isVisible(selector.admin.wooCommerce.settings.shippingZoneCell(shippingZone)); + expect(shippingZoneIsVisible).toBe(false); + } + + // Admin Delete Shipping Method + async deleteShippingMethod(shipping: any) { + await this.click(selector.admin.wooCommerce.settings.shipping); + + await this.hover(selector.admin.wooCommerce.settings.shippingZoneCell(shipping.shippingZone)); + await this.click(selector.admin.wooCommerce.settings.editShippingZone(shipping.shippingZone)); + await this.hover(selector.admin.wooCommerce.settings.shippingMethodCell(shipping.shippingMethod)); + await this.click(selector.admin.wooCommerce.settings.deleteShippingMethod(shipping.shippingMethod)); + await this.click(selector.admin.wooCommerce.settings.shippingZoneSaveChanges); + + const shippingMethodIsVisible = await this.isVisible(selector.admin.wooCommerce.settings.shippingMethodCell(shipping.shippingMethod)); + expect(shippingMethodIsVisible).toBe(false); + } +} diff --git a/tests/pw/pages/shopPage.ts b/tests/pw/pages/shopPage.ts new file mode 100644 index 0000000000..d1865db586 --- /dev/null +++ b/tests/pw/pages/shopPage.ts @@ -0,0 +1,107 @@ +import { Page } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +const { DOKAN_PRO } = process.env; + +export class ShopPage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // shop + + // shop render properly + async shopRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.shop); + + // shop text is visible + await this.toBeVisible(selector.customer.cShop.shopText); + + if (DOKAN_PRO) { + // map elements are visible + const { productOnMap, ...map } = selector.customer.cShop.map; + await this.multipleElementVisible(map); + + // product filter elements are visible + await this.multipleElementVisible(selector.customer.cShop.filters); + } + + // product card elements are visible + await this.notToHaveCount(selector.customer.cShop.productCard.card, 0); + await this.notToHaveCount(selector.customer.cShop.productCard.productDetailsLink, 0); + await this.notToHaveCount(selector.customer.cShop.productCard.productTitle, 0); + await this.notToHaveCount(selector.customer.cShop.productCard.productPrice, 0); + await this.notToHaveCount(selector.customer.cShop.productCard.addToCart, 0); + } + + // sort products + async sortProducts(sortBy: string) { + await this.goIfNotThere(data.subUrls.frontend.shop); + await this.selectByValueAndWaitForResponse(data.subUrls.frontend.shop, selector.customer.cShop.sort, sortBy); + } + + // search product + async searchProduct(productName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.shop); + if (!DOKAN_PRO) { + await this.clearAndType(selector.customer.cShop.searchProductLite, productName); + await this.pressAndWaitForLoadState(data.key.enter); + await this.toContainText(selector.customer.cSingleProduct.productDetails.productTitle, productName); + } else { + await this.clearAndType(selector.customer.cShop.filters.searchProduct, productName); + await this.clickAndWaitForLoadState(selector.customer.cShop.filters.search); + await this.toContainText(selector.customer.cShop.productCard.productTitle, productName); + } + } + + // filter products + async filterProducts(filterBy: string, value: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.shop); + + switch (filterBy) { + case 'by-location': + await this.typeAndWaitForResponse(data.subUrls.gmap, selector.customer.cShop.filters.location, value); + await this.press(data.key.arrowDown); + await this.pressAndWaitForResponse(data.subUrls.gmap, data.key.enter); + break; + + case 'by-category': + await this.selectByValue(selector.customer.cShop.filters.selectCategory, value); + break; + + default: + break; + } + + await this.clickAndWaitForLoadState(selector.customer.cShop.filters.search); + await this.notToHaveCount(selector.customer.cShop.productCard.card, 0); + } + + // products on map + async productOnMap(productName?: string) { + await this.goIfNotThere(data.subUrls.frontend.shop); + // await this.click(selector.customer.cShop.map.productOnMap.productOnMap); + // await this.toBeVisibleAnyOfThem([selector.customer.cShop.map.productOnMap.productPopup, selector.customer.cShop.map.productOnMap.productListPopup]); // implement this instead of if-else soln + const storePinIsVisible = await this.isVisible(selector.customer.cShop.map.productOnMap.productPin); + if (storePinIsVisible) { + await this.click(selector.customer.cShop.map.productOnMap.productPin); + await this.toBeVisible(selector.customer.cShop.map.productOnMap.productPopup); + } else { + await this.click(selector.customer.cShop.map.productOnMap.productCluster); + await this.toBeVisible(selector.customer.cShop.map.productOnMap.productListPopup); + await this.click(selector.customer.cShop.map.productOnMap.closePopup); + } + productName && (await this.toBeVisible(selector.customer.cShop.map.productOnMap.productOnList(productName))); + } + + // go to product details + async goToProductDetailsFromShop(productName: string): Promise { + await this.searchProduct(productName); + if (DOKAN_PRO) { + await this.clickAndWaitForResponse(data.subUrls.frontend.productCustomerPage, selector.customer.cShop.productCard.productDetailsLink); + await this.toContainText(selector.customer.cSingleProduct.productDetails.productTitle, productName); + } + } +} diff --git a/tests/pw/pages/singleProductPage.ts b/tests/pw/pages/singleProductPage.ts new file mode 100644 index 0000000000..4d05815e88 --- /dev/null +++ b/tests/pw/pages/singleProductPage.ts @@ -0,0 +1,128 @@ +import { Page } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { product } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class SingleProductPage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // single product page + + // single product render properly + async singleProductRenderProperly(productName: string) { + await this.goToProductDetails(productName); + + // basic details are visible + const { viewCart, ...productDetails } = selector.customer.cSingleProduct.productDetails; + await this.multipleElementVisible(productDetails); + + // description elements are visible + // await this.click(selector.customer.cSingleProduct.menus.description); + await this.multipleElementVisible(selector.customer.cSingleProduct.description); + + // review elements are visible + await this.click(selector.customer.cSingleProduct.menus.reviews); + + await this.toBeVisible(selector.customer.cSingleProduct.reviews.ratings); + await this.toBeVisible(selector.customer.cSingleProduct.reviews.reviewMessage); + await this.toBeVisible(selector.customer.cSingleProduct.reviews.submitReview); + + // vendor info elements are visible + await this.click(selector.customer.cSingleProduct.menus.vendorInfo); + await this.multipleElementVisible(selector.customer.cSingleProduct.vendorInfo); + + // more products elements are visible + await this.click(selector.customer.cSingleProduct.menus.moreProducts); + await this.toBeVisible(selector.customer.cSingleProduct.moreProducts.moreProductsDiv); + await this.notToHaveCount(selector.customer.cSingleProduct.moreProducts.product, 0); + + // related products elements are visible + await this.multipleElementVisible(selector.customer.cSingleProduct.relatedProducts); + + if (DOKAN_PRO) { + // get support is visible + await this.toBeVisible(selector.customer.cSingleProduct.getSupport.getSupport); + + // report abuse is visible + await this.toBeVisible(selector.customer.cSingleProduct.reportAbuse.reportAbuse); + + // vendor highlighted info elements are visible + await this.multipleElementVisible(selector.customer.cSingleProduct.vendorHighlightedInfo); + + // product shipping elements are visible + // await this.click(selector.customer.cSingleProduct.menus.shipping); + // await this.multipleElementVisible(selector.customer.cSingleProduct.shipping); // todo: need vendor shipping + + // product location elements are visible + await this.click(selector.customer.cSingleProduct.menus.location); + await this.multipleElementVisible(selector.customer.cSingleProduct.location); + + // // warranty policy is visible + // await this.click(selector.customer.cSingleProduct.menus.warrantyPolicy); + // await this.multipleElementVisible(selector.customer.cSingleProduct.warrantyPolicy); // todo: need warranty policy + + // product enquiry is visible + await this.click(selector.customer.cSingleProduct.menus.productEnquiry); + const { submitEnquirySuccessMessage, guest, ...productEnquiry } = selector.customer.cSingleProduct.productEnquiry; + await this.multipleElementVisible(productEnquiry); + } + } + + // review product + async reviewProduct(productName: string, review: product['review']): Promise { + await this.goToProductDetails(productName); + const reviewMessage = review.reviewMessage(); + await this.click(selector.customer.cSingleProduct.menus.reviews); + await this.click(selector.customer.cSingleProduct.reviews.rating(review.rating)); + await this.clearAndType(selector.customer.cSingleProduct.reviews.reviewMessage, reviewMessage); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.productReview, selector.customer.cSingleProduct.reviews.submitReview, 302); + await this.toContainText(selector.customer.cSingleProduct.reviews.submittedReview(reviewMessage), reviewMessage); + } + + // product vendor info + async productVendorInfo(productName: string) { + await this.goToProductDetails(productName); + await this.click(selector.customer.cSingleProduct.menus.vendorInfo); + await this.multipleElementVisible(selector.customer.cSingleProduct.vendorInfo); + } + + // product location + async productLocation(productName: string) { + await this.goToProductDetails(productName); + await this.click(selector.customer.cSingleProduct.menus.location); + await this.multipleElementVisible(selector.customer.cSingleProduct.location); + } + + // product warranty policy + async productWarrantyPolicy(productName: string) { + await this.goToProductDetails(productName); + await this.click(selector.customer.cSingleProduct.menus.warrantyPolicy); + await this.multipleElementVisible(selector.customer.cSingleProduct.warrantyPolicy); + } + + // view vendor more product + async viewMoreProducts(productName: string) { + await this.goToProductDetails(productName); + await this.click(selector.customer.cSingleProduct.menus.moreProducts); + + await this.toBeVisible(selector.customer.cSingleProduct.moreProducts.moreProductsDiv); + await this.notToHaveCount(selector.customer.cSingleProduct.moreProducts.product, 0); + } + + // view vendor more product + async viewRelatedProducts(productName: string) { + await this.goToProductDetails(productName); + await this.multipleElementVisible(selector.customer.cSingleProduct.relatedProducts); + } + + // view highlighted vendor info + async viewHighlightedVendorInfo(productName: string) { + await this.goToProductDetails(productName); + await this.multipleElementVisible(selector.customer.cSingleProduct.vendorHighlightedInfo); + } +} diff --git a/tests/pw/pages/singleStorePage.ts b/tests/pw/pages/singleStorePage.ts new file mode 100644 index 0000000000..fa91551540 --- /dev/null +++ b/tests/pw/pages/singleStorePage.ts @@ -0,0 +1,96 @@ +import { Page } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; + +const { DOKAN_PRO } = process.env; + +export class SingleStorePage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // single store + + // single store render properly + async singleStoreRenderProperly(storeName: string) { + // todo: update for other layouts + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + + // store profile elements are visible + await this.multipleElementVisible(selector.customer.cSingleStore.storeProfile); + + // store tab elements are visible + if (!DOKAN_PRO) { + await this.toBeVisible(selector.customer.cSingleStore.storeTabs.products); + // await this.toBeVisible(selector.customer.cSingleStore.storeTabs.toc); // todo: need vendor toc + } else { + const { toc, ...storeTabs } = selector.customer.cSingleStore.storeTabs; + await this.multipleElementVisible(storeTabs); + } + + // search elements are visible + await this.multipleElementVisible(selector.customer.cSingleStore.search); + + // sortby element is visible + await this.toBeVisible(selector.customer.cSingleStore.sortBy); + + // store products are visible + await this.toBeVisible(selector.customer.cSingleStore.storeProducts); + + // product card elements are visible + await this.notToHaveCount(selector.customer.cSingleStore.productCard.card, 0); + await this.notToHaveCount(selector.customer.cSingleStore.productCard.productDetailsLink, 0); + await this.notToHaveCount(selector.customer.cSingleStore.productCard.productTitle, 0); + await this.notToHaveCount(selector.customer.cSingleStore.productCard.productPrice, 0); + await this.notToHaveCount(selector.customer.cSingleStore.productCard.addToCart, 0); + + // store social icons are visible + await this.multipleElementVisible(selector.customer.cSingleStore.storeSocialIcons); + } + + // sort products on single store + async singleStoreSortProducts(storeName: string, sortBy: string) { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.selectByValueAndWaitForResponse(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName)), selector.customer.cSingleStore.sortBy, sortBy); + } + + // search product on single store + async singleStoreSearchProduct(storeName: string, productName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.clearAndType(selector.customer.cSingleStore.search.input, productName); + await this.clickAndWaitForResponse(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName)), selector.customer.cSingleStore.search.button); + await this.toContainText(selector.customer.cSingleStore.productCard.productTitle, productName); + } + + // store open close + async storeOpenCloseTime(storeName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.hover(selector.customer.cSingleStore.storeTime.storeTimeDropDown); + + await this.toBeVisible(selector.customer.cSingleStore.storeTime.storeTimeDiv); + await this.toBeVisible(selector.customer.cSingleStore.storeTime.storeTimeHeading); + + await this.toHaveCount(selector.customer.cSingleStore.storeTime.storeDays, 7); + await this.toHaveCount(selector.customer.cSingleStore.storeTime.storeTimes, 7); + } + + // store terms and condition + async storeTermsAndCondition(storeName: string, toc: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.clickAndWaitForResponse(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName)), selector.customer.cSingleStore.storeTabs.toc); + await this.toContainText(selector.customer.cSingleStore.toc.tocContent, toc); + } + + // store share + async storeShare(storeName: string, site: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.click(selector.customer.cSingleStore.storeTabs.share); + // ensure page suppose to open on new tab + await this.toHaveAttribute(selector.customer.cSingleStore.sharePlatForms[site as keyof typeof selector.customer.cSingleStore.sharePlatForms], 'target', '_blank'); + // force page to open on same tab + await this.setAttributeValue(selector.customer.cSingleStore.sharePlatForms[site as keyof typeof selector.customer.cSingleStore.sharePlatForms], 'target', '_self'); + await this.clickAndWaitForUrl(new RegExp('.*' + site + '.*'), selector.customer.cSingleStore.sharePlatForms[site as keyof typeof selector.customer.cSingleStore.sharePlatForms]); + } +} diff --git a/tests/pw/pages/spmvPage.ts b/tests/pw/pages/spmvPage.ts new file mode 100644 index 0000000000..fcf381efa3 --- /dev/null +++ b/tests/pw/pages/spmvPage.ts @@ -0,0 +1,184 @@ +import { Page, expect } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; + +export class SpmvPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // admin + + async assignSpmvProduct(productId: string, storeName: string) { + await this.goIfNotThere(data.subUrls.backend.wc.productDetails(productId)); + + await this.focus(selector.admin.dokan.spmv.searchVendor); + + const alreadyAssigned = await this.isVisible(selector.admin.dokan.spmv.unassignVendor(storeName)); + alreadyAssigned && (await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.spmv.unassignVendor(storeName))); + + await this.typeViaPageAndWaitForResponse(data.subUrls.ajax, selector.admin.dokan.spmv.searchVendor, storeName); + await this.toContainText(selector.admin.dokan.spmv.highlightedResult, storeName); + await this.click(selector.admin.dokan.spmv.searchedResult(storeName)); + await this.click(selector.admin.dokan.spmv.spmvDiv); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.spmv.assignVendor); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.updateSuccessMessage); + } + + // vendor + + // vendor spmv render properly + async vendorSpmvRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.spmv); + + // search box elements are visible + const { toggleBtn, ...search } = selector.vendor.vSpmv.search; + await this.multipleElementVisible(search); + + // table elements are visible + await this.multipleElementVisible(selector.vendor.vSpmv.table); + + // number of elements found is visible + await this.toBeVisible(selector.vendor.vSpmv.resultCount); + + // sort is visible + await this.toBeVisible(selector.vendor.vSpmv.sortProduct); + } + + // vendor search similar product + async searchSimilarProduct(productName: string, from: string): Promise { + switch (from) { + case 'popup': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + await this.click(selector.vendor.product.create.addNewProduct); + await this.click(selector.vendor.vSpmv.search.toggleBtn); + break; + + case 'booking': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.booking); + await this.click(selector.vendor.vBooking.addNewBookingProduct); + await this.click(selector.vendor.vSpmv.search.toggleBtn); + break; + + case 'auction': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.auction); + await this.clickAndWaitForLoadState(selector.vendor.vAuction.addNewActionProduct); + await this.click(selector.vendor.vSpmv.search.toggleBtn); + break; + + case 'spmv': + await this.goIfNotThere(data.subUrls.frontend.vDashboard.spmv); + break; + + default: + break; + } + + const searchInputIsVisible = await this.isVisible(selector.vendor.vSpmv.search.searchInput); + if (!searchInputIsVisible) { + // forcing spmv search section to open via removing class + const spmvSearchDiv = (await this.getClassValue(selector.vendor.vSpmv.search.searchDiv))!; + await this.setAttributeValue(selector.vendor.vSpmv.search.searchDiv, 'class', spmvSearchDiv.replace('section-closed', '')); + } + + await this.clearAndType(selector.vendor.vSpmv.search.searchInput, productName); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.spmv, selector.vendor.vSpmv.search.search); + await this.toContainText(selector.vendor.vSpmv.resultCount, 'Showing the single result'); + } + + // got to product edit from spmv + async goToProductEditFromSPMV(productName: string): Promise { + await this.searchSimilarProduct(productName, 'spmv'); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.vSpmv.editProduct(productName)); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + } + + // sort spmv product + async sortSpmvProduct(sortBy: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.spmv); + await this.selectByValueAndWaitForResponse(data.subUrls.frontend.vDashboard.spmv, selector.vendor.vSpmv.sortProduct, sortBy); + await this.notToHaveCount(selector.vendor.vSpmv.numberOfRowsFound, 0); + } + + // clone product + async cloneProduct(productName: string): Promise { + await this.searchSimilarProduct(productName, 'spmv'); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.vSpmv.addToStore); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + } + + // clone product via sell item button + async cloneProductViaSellItemButton(productName: string): Promise { + await this.goToProductDetails(productName); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.vSpmv.productDetails.sellThisItem); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + } + + // view other available vendors + async viewOtherAvailableVendors(productName: string): Promise { + await this.goToProductDetails(productName); + + // if display inside product tab + await this.clickIfVisible(selector.customer.cSpmv.otherVendorAvailableTab); + + await this.toBeVisible(selector.customer.cSpmv.otherAvailableVendorDiv); + await this.toBeVisible(selector.customer.cSpmv.availableVendorDisplayAreaTitle); + await this.toBeVisible(selector.customer.cSpmv.availableVendorTable); + + // vendor + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.vendor.vendorCell, 0); + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.vendor.avatar, 0); + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.vendor.vendorLink, 0); + + // price + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.price.priceCell, 0); + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.price.priceAmount, 0); + + // rating + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.rating.ratingCell, 0); + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.rating.rating, 0); + + // actions + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.actions.actionsCell, 0); + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.actions.viewStore, 0); + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.actions.viewProduct, 0); + await this.notToHaveCount(selector.customer.cSpmv.availableVendorDetails.actions.addToCart, 0); + } + + // view other available vendor + async viewOtherAvailableVendor(productName: string, storeName: string): Promise { + await this.goToProductDetails(productName); + + // if display inside product tab + await this.clickIfVisible(selector.customer.cSpmv.otherVendorAvailableTab); + + await this.clickAndWaitForLoadState(selector.customer.cSpmv.availableVendorDetails.actions.viewStoreByVendor(storeName)); + await expect(this.page).toHaveURL(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName)) + '/'); + } + + // view other available vendor product + async viewOtherAvailableVendorProduct(productName: string, storeName: string): Promise { + await this.goToProductDetails(productName); + + // if display inside product tab + await this.clickIfVisible(selector.customer.cSpmv.otherVendorAvailableTab); + + await this.clickAndWaitForLoadState(selector.customer.cSpmv.availableVendorDetails.actions.viewProductByVendor(storeName)); + await this.toContainText(selector.customer.cSingleProduct.productDetails.productTitle, productName); + } + + // add to cart other available vendor product + async addToCartOtherAvailableVendorsProduct(productName: string, storeName: string): Promise { + await this.goToProductDetails(productName); + + // if display inside product tab + await this.clickIfVisible(selector.customer.cSpmv.otherVendorAvailableTab); + + await this.clickAndWaitForLoadState(selector.customer.cSpmv.availableVendorDetails.actions.addToCartByVendor(storeName)); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, `“${productName}” has been added to your cart.`); + } +} diff --git a/tests/pw/pages/storeCategoriesPage.ts b/tests/pw/pages/storeCategoriesPage.ts new file mode 100644 index 0000000000..680718ca01 --- /dev/null +++ b/tests/pw/pages/storeCategoriesPage.ts @@ -0,0 +1,98 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { storeCategory } from '@utils/interfaces'; + +export class StoreCategoriesPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // store categories + + // store categories render properly + async adminStoreCategoryRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.vendors); + await this.click(selector.admin.dokan.vendors.storeCategories); + + // add new category elements are visible + await this.multipleElementVisible(selector.admin.dokan.vendors.storeCategory.addNewCategory); + + // search category input is visible + await this.toBeVisible(selector.admin.dokan.vendors.storeCategory.search); + + // store category table elements are visible + await this.multipleElementVisible(selector.admin.dokan.vendors.storeCategory.table); + } + + // add store category + async addStoreCategory(storeCategory: storeCategory) { + await this.goIfNotThere(data.subUrls.backend.dokan.vendors); + await this.click(selector.admin.dokan.vendors.storeCategories); + + await this.clearAndType(selector.admin.dokan.vendors.storeCategory.addNewCategory.name, storeCategory.name); + await this.clearAndType(selector.admin.dokan.vendors.storeCategory.addNewCategory.description, storeCategory.description); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeCategories, selector.admin.dokan.vendors.storeCategory.addNewCategory.addNewCategory); + } + + // search store category + async searchStoreCategory(categoryName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.storeCategories); + // await this.click(selector.admin.dokan.vendors.storeCategories); + + await this.clearInputField(selector.admin.dokan.vendors.storeCategory.search); + + await this.typeAndWaitForResponse(data.subUrls.api.dokan.storeCategories, selector.admin.dokan.vendors.storeCategory.search, categoryName); + await this.toBeVisible(selector.admin.dokan.vendors.storeCategory.storeCategoryCell(categoryName)); + } + + // edit store category + async editStoreCategory(storeCategory: storeCategory) { + await this.searchStoreCategory(storeCategory.name); + + await this.hover(selector.admin.dokan.vendors.storeCategory.storeCategoryCell(storeCategory.name)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeCategories, selector.admin.dokan.vendors.storeCategory.storeCategoryEdit(storeCategory.name)); + await this.clearAndType(selector.admin.dokan.vendors.storeCategory.editCategory.name, storeCategory.name); + await this.clearAndType(selector.admin.dokan.vendors.storeCategory.editCategory.description, storeCategory.description); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeCategories, selector.admin.dokan.vendors.storeCategory.editCategory.update); + } + + // update store category + async updateStoreCategory(categoryName: string, action: string) { + await this.searchStoreCategory(categoryName); + + await this.hover(selector.admin.dokan.vendors.storeCategory.storeCategoryCell(categoryName)); + + switch (action) { + case 'set-default': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeCategories, selector.admin.dokan.vendors.storeCategory.storeCategorySetDefault(categoryName)); + break; + + case 'delete': + await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.storeCategories, selector.admin.dokan.vendors.storeCategory.storeCategoryDelete(categoryName)); + break; + + default: + break; + } + } + + // vendor + + // vendor update store category + async vendorUpdateStoreCategory(category: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsStore); + const isSingleCategory = await this.isVisible(selector.vendor.vStoreSettings.storeCategories.storeCategoryDropDown); + if (isSingleCategory) { + await this.click(selector.vendor.vStoreSettings.storeCategories.storeCategoryDropDown); + await this.clearAndType(selector.vendor.vStoreSettings.storeCategories.storeCategoryInput, category); + } else { + await this.clearAndType(selector.vendor.vStoreSettings.storeCategories.storeCategoriesInput, category); + } + await this.toContainText(selector.vendor.vStoreSettings.storeCategories.result, category); + await this.press(data.key.enter); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vStoreSettings.updateSettings); + await this.toContainText(selector.vendor.vStoreSettings.updateSettingsSuccessMessage, 'Your information has been saved successfully'); + } +} diff --git a/tests/pw/pages/storeListingPage.ts b/tests/pw/pages/storeListingPage.ts new file mode 100644 index 0000000000..2b254ecdac --- /dev/null +++ b/tests/pw/pages/storeListingPage.ts @@ -0,0 +1,157 @@ +import { Page, expect } from '@playwright/test'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; + +const { DOKAN_PRO } = process.env; + +export class StoreListingPage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // store list + + // store list render properly + async storeListRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + + // store list text is visible + await this.toBeVisible(selector.customer.cStoreList.storeListText); + + // map elements are visible + if (DOKAN_PRO) { + const { storeOnMap, ...map } = selector.customer.cStoreList.map; + await this.multipleElementVisible(map); + } + + // store filter elements are visible + const { filterDetails, ...filters } = selector.customer.cStoreList.filters; + await this.multipleElementVisible(filters); + + // click filter button to view filter details + await this.click(selector.customer.cStoreList.filters.filterButton); + + // store filter detail elements are visible + if (!DOKAN_PRO) { + await this.toBeVisible(selector.customer.cStoreList.filters.filterDetails.searchVendor); + await this.toBeVisible(selector.customer.cStoreList.filters.filterDetails.apply); + } else { + const { rating, ...filterDetails } = selector.customer.cStoreList.filters.filterDetails; + await this.multipleElementVisible(filterDetails); + } + + // store card elements are visible + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeCardDiv, 0); + + // card header + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeCardHeader, 0); + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeBanner, 0); + + // card content + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeCardContent, 0); + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeData, 0); + + // card footer + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeCardFooter, 0); + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeAvatar, 0); + await this.notToHaveCount(selector.customer.cStoreList.storeCard.visitStore, 0); + DOKAN_PRO && (await this.notToHaveCount(selector.customer.cStoreList.storeCard.followUnFollowButton, 0)); + } + + // sort store + async sortStores(sortBy: string) { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + await this.selectByValueAndWaitForResponse(data.subUrls.frontend.storeListing, selector.customer.cStoreList.filters.sortBy, sortBy); + } + + // store view layout + async storeViewLayout(style: string) { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + + switch (style) { + case 'grid': + await this.click(selector.customer.cStoreList.filters.gridView); + break; + + case 'list': + await this.click(selector.customer.cStoreList.filters.listView); + break; + + default: + break; + } + await this.toHaveClass(selector.customer.cStoreList.currentLayout, style + '-view'); + } + + // search store + async searchStore(storeName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + await this.click(selector.customer.cStoreList.filters.filterButton); + await this.clearAndType(selector.customer.cStoreList.filters.filterDetails.searchVendor, storeName); + await this.clickAndWaitForResponse(data.subUrls.frontend.storeListing, selector.customer.cStoreList.filters.filterDetails.apply); + await this.toBeVisible(selector.customer.cStoreList.visitStore(storeName)); + } + + // filter stores + async filterStores(filterBy: string, value?: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + await this.click(selector.customer.cStoreList.filters.filterButton); + + switch (filterBy) { + case 'by-location': + await this.typeAndWaitForResponse(data.subUrls.gmap, selector.customer.cStoreList.filters.filterDetails.location, value!); + await this.click(selector.customer.cStoreList.mapResultFirst); + // await this.press(data.key.arrowDown); + // await this.pressAndWaitForResponse(data.subUrls.gmap, data.key.enter); + break; + + case 'by-category': + await this.click(selector.customer.cStoreList.filters.filterDetails.categoryInput); + await this.click(selector.customer.cStoreList.category(value!)); + break; + + case 'by-ratings': + await this.click(selector.customer.cStoreList.filters.filterDetails.rating(value!)); + break; + + case 'featured': + await this.click(selector.customer.cStoreList.filters.filterDetails.featured); + break; + + case 'open-now': + await this.click(selector.customer.cStoreList.filters.filterDetails.openNow); + break; + + default: + break; + } + + await this.clickAndWaitForResponse(data.subUrls.frontend.storeListing, selector.customer.cStoreList.filters.filterDetails.apply); + await this.notToHaveCount(selector.customer.cStoreList.storeCard.storeCardDiv, 0); + } + + // stores on map + async storeOnMap(storeName?: string) { + await this.goIfNotThere(data.subUrls.frontend.storeListing); + const storePinIsVisible = await this.isVisible(selector.customer.cStoreList.map.storeOnMap.storePin); + if (storePinIsVisible) { + await this.click(selector.customer.cStoreList.map.storeOnMap.storePin); + await this.toBeVisible(selector.customer.cStoreList.map.storeOnMap.storePopup); + } else { + await this.click(selector.customer.cStoreList.map.storeOnMap.storeCluster); + await this.toBeVisible(selector.customer.cStoreList.map.storeOnMap.storeListPopup); + await this.click(selector.customer.cStoreList.map.storeOnMap.closePopup); + } + storeName && (await this.toBeVisible(selector.customer.cStoreList.map.storeOnMap.storeOnList(storeName))); + } + + // go to single store from store listing + async goToSingleStoreFromStoreListing(storeName: string): Promise { + await this.searchStore(storeName); + await this.clickAndWaitForLoadState(selector.customer.cStoreList.storeCard.visitStore); + const storeUrl = this.isCurrentUrl(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + expect(storeUrl).toBeTruthy(); + } +} diff --git a/tests/pw/pages/storeReviewsPage.ts b/tests/pw/pages/storeReviewsPage.ts new file mode 100644 index 0000000000..ee782c82ec --- /dev/null +++ b/tests/pw/pages/storeReviewsPage.ts @@ -0,0 +1,137 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; +import { storeReview } from '@utils/interfaces'; + +export class StoreReviewsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // store reviews + + // store reviews render properly + async adminStoreReviewsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.storeReviews); + + // store reviews text is visible + await this.toBeVisible(selector.admin.dokan.storeReviews.storeReviewsText); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.storeReviews.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.storeReviews.bulkActions); + + // filter elements are visible + const { filterInput, filterClear, ...filters } = selector.admin.dokan.storeReviews.filters; + await this.multipleElementVisible(filters); + + // store reviews table elements are visible + await this.multipleElementVisible(selector.admin.dokan.storeReviews.table); + } + + // filter store reviews + async filterStoreReviews(vendorName: string) { + await this.goto(data.subUrls.backend.dokan.storeReviews); + + // filter by vendor + await this.click(selector.admin.dokan.storeReviews.filters.filterByVendor); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.storeReviews.filters.filterInput, vendorName); + await this.pressAndWaitForResponse(data.subUrls.api.dokan.storeReviews, data.key.enter); + } + + // view store review + async viewStoreReview() { + await this.goto(data.subUrls.backend.dokan.storeReviews); + await this.click(selector.admin.dokan.storeReviews.storeReviewFirstLink); + const { rating, ...editReview } = selector.admin.dokan.storeReviews.editReview; + await this.multipleElementVisible(editReview); + await this.click(selector.admin.dokan.storeReviews.editReview.modalClose); + } + + // edit store review + async editStoreReview(review: storeReview['review']) { + await this.goto(data.subUrls.backend.dokan.storeReviews); + await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); + await this.click(selector.admin.dokan.storeReviews.storeReviewEdit); + + await this.click(selector.admin.dokan.storeReviews.editReview.rating(review.rating)); + await this.clearAndType(selector.admin.dokan.storeReviews.editReview.title, review.title); + await this.clearAndType(selector.admin.dokan.storeReviews.editReview.content, review.content); + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.editReview.update); + } + + // delete store review + async deleteStoreReview() { + await this.goto(data.subUrls.backend.dokan.storeReviews); + await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewDelete); + } + + // restore store review + async restoreStoreReview() { + await this.goto(data.subUrls.backend.dokan.storeReviews); + // await this.goIfNotThere(data.subUrls.backend.dokan.storeReviews); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.navTabs.trash); + + await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewRestore); + } + + // permanently delete store review + async permanentlyDeleteStoreReview() { + await this.goto(data.subUrls.backend.dokan.storeReviews); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.navTabs.trash); + + await this.hover(selector.admin.dokan.storeReviews.storeReviewFirstCell); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.storeReviewPermanentlyDelete); + } + + // store reviews bulk action + async storeReviewsBulkAction(action: string) { + await this.goto(data.subUrls.backend.dokan.storeReviews); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.storeReviews.noRowsFound); + + await this.click(selector.admin.dokan.storeReviews.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.storeReviews.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeReviews, selector.admin.dokan.storeReviews.bulkActions.applyAction); + } + + // customer review store + async reviewStore(storeName: string, review: storeReview['review'], action: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.storeReviews(helpers.slugify(storeName))); + // await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + // await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.storeReviews(helpers.slugify(storeName)), selector.customer.cSingleStore.storeTabs.reviews); + + // write new or edit previous review + if (action === 'create') { + await this.click(selector.customer.cSingleStore.review.write); + } else { + await this.click(selector.customer.cSingleStore.review.edit); + } + await this.setAttributeValue(selector.customer.cSingleStore.review.rating, 'style', review.ratingByWidth); + await this.clearAndType(selector.customer.cSingleStore.review.title, review.title); + await this.clearAndType(selector.customer.cSingleStore.review.message, review.content); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleStore.review.submit); + await this.toContainText(selector.customer.cSingleStore.review.submittedReview(review.content), review.content); + } + + // view own review + async viewOwnReview(storeName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.storeReviews(helpers.slugify(storeName))); + await this.multipleElementVisible(selector.customer.cSingleStore.review.reviewDetails); + } + + // cant review own store + async cantReviewOwnStore(storeName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.storeReviews(helpers.slugify(storeName))); + await this.notToBeVisible(selector.customer.cSingleStore.review.write); + await this.notToBeVisible(selector.customer.cSingleStore.review.edit); + } +} diff --git a/tests/pw/pages/storeSupportsPage.ts b/tests/pw/pages/storeSupportsPage.ts new file mode 100644 index 0000000000..79b0eaef3b --- /dev/null +++ b/tests/pw/pages/storeSupportsPage.ts @@ -0,0 +1,429 @@ +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 { customer, date } from '@utils/interfaces'; + +export class StoreSupportsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + customerPage = new CustomerPage(this.page); + + // store support + + // store support render properly + async adminStoreSupportRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.storeSupport); + + // store support text is visible + await this.toBeVisible(selector.admin.dokan.storeSupport.storeSupportText); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.storeSupport.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.storeSupport.bulkActions); + + // filter elements are visible + const { filterInput, result, ...filters } = selector.admin.dokan.storeSupport.filters; + await this.multipleElementVisible(filters); + + // search store support is visible + await this.toBeVisible(selector.admin.dokan.storeSupport.searchTicket); + + // store support table elements are visible + await this.multipleElementVisible(selector.admin.dokan.storeSupport.table); + } + + // admin view support ticket details + async adminViewSupportTicketDetails(supportTicketId: string) { + await this.searchSupportTicket(supportTicketId); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketLink(supportTicketId)); + + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketDetails.backToTickets); + + // chat elements are visible + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketDetails.ticketTitle); + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketDetails.chatStatus); + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketDetails.chatBox); + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketDetails.chatAuthor); + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketDetails.chatReply); + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketDetails.sendReply); + + // ticket summary elements are visible + const { reopenTicket, ...ticketSummary } = selector.admin.dokan.storeSupport.supportTicketDetails.ticketSummary; + await this.multipleElementVisible(ticketSummary); + } + + // search support ticket + async searchSupportTicket(idOrTitle: string, closed?: boolean) { + await this.goIfNotThere(data.subUrls.backend.dokan.storeSupport); + closed && (await this.clickAndWaitForLoadState(selector.admin.dokan.storeSupport.navTabs.closed)); // go to closed tab + + await this.clearInputField(selector.admin.dokan.storeSupport.searchTicket); + await this.typeAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.searchTicket, idOrTitle); + const count = (await this.getElementText(selector.admin.dokan.storeSupport.numberOfRowsFound))?.split(' ')[0]; + if (!isNaN(Number(idOrTitle))) { + await this.toBeVisible(selector.admin.dokan.storeSupport.supportTicketCell(idOrTitle)); + } else { + expect(Number(count)).toBeGreaterThan(0); + } + } + + // decrease unread support ticket count + async decreaseUnreadSupportTicketCount(supportTicketId: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.storeSupport); + const getUnreadCount = Number(await this.getElementText(selector.admin.dokan.storeSupport.unreadTicketCount)); + await this.searchSupportTicket(supportTicketId); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketLink(supportTicketId)); + const getNewUnreadCount = Number(await this.getElementText(selector.admin.dokan.storeSupport.unreadTicketCount)); + expect(getNewUnreadCount).toEqual(getUnreadCount - 1); + } + + // filter store supports + async filterSupportTickets(input: string, filterBy: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.storeSupport); + + switch (filterBy) { + case 'by-vendor': + await this.click(selector.admin.dokan.storeSupport.filters.filterByVendors); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.storeSupport.filters.filterInput, input); + await this.toContainText(selector.admin.dokan.storeSupport.filters.result, input); + await this.press(data.key.enter); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.filters.filterButton); + break; + + case 'by-customer': + await this.click(selector.admin.dokan.storeSupport.filters.filterByCustomers); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.filters.filterInput, input); + await this.toContainText(selector.admin.dokan.storeSupport.filters.result, input); + await this.press(data.key.enter); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.filters.filterButton); + break; + + default: + break; + } + + const count = (await this.getElementText(selector.admin.dokan.storeSupport.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } + + // reply to support ticket + async replySupportTicket(supportTicketId: string, replyMessage: string, replier = 'admin') { + await this.searchSupportTicket(supportTicketId); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketLink(supportTicketId)); + + if (replier === 'vendor') { + await this.selectByValue(selector.admin.dokan.storeSupport.supportTicketDetails.chatAuthor, 'vendor'); + } + + await this.clearAndType(selector.admin.dokan.storeSupport.supportTicketDetails.chatReply, replyMessage); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketDetails.sendReply); + } + + // update support ticket email notification + async updateSupportTicketEmailNotification(supportTicketId: string, action: string) { + await this.searchSupportTicket(supportTicketId); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketLink(supportTicketId)); + + switch (action) { + case 'enable': + await this.enableSwitcherAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketDetails.ticketSummary.emailNotification); + break; + + case 'disable': + await this.disableSwitcherAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketDetails.ticketSummary.emailNotification); + break; + + default: + break; + } + } + + // close support ticket + async closeSupportTicket(supportTicketId: string) { + await this.searchSupportTicket(supportTicketId); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketLink(supportTicketId)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketDetails.ticketSummary.closeTicket); + } + + // reopen support ticket + async reopenSupportTicket(supportTicketId: string) { + await this.searchSupportTicket(supportTicketId, true); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketLink(supportTicketId)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.supportTicketDetails.ticketSummary.reopenTicket); + } + + // store support bulk action + async storeSupportBulkAction(action: string, supportTicketId?: string) { + await this.goto(data.subUrls.backend.dokan.storeSupport); // not used ternary -> page need to reload before reflecting api update + supportTicketId && (await this.searchSupportTicket(supportTicketId)); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.storeSupport.noRowsFound); + + await this.click(selector.admin.dokan.storeSupport.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.storeSupport.bulkActions.selectAction, action); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.dokan.storeSupport, selector.admin.dokan.storeSupport.bulkActions.applyAction); + } + + // vendor + + // vendor store support render properly + async vendorStoreSupportRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.storeSupport); + + // store support menu elements are visible + await this.multipleElementVisible(selector.vendor.vSupport.menus); + + const { filterByCustomerInput, filterByDate, result, ...filters } = selector.vendor.vSupport.filters; + await this.toBeVisible(selector.vendor.vSupport.filters.filterByDate.dateRangeInput); + await this.multipleElementVisible(filters); + + const noSupportTicket = await this.isVisible(selector.vendor.vSupport.noSupportTicketFound); + if (noSupportTicket) { + console.log('No Support Tickets Found!!'); + return; + } + + // store support table elements are visible + await this.multipleElementVisible(selector.vendor.vSupport.table); + } + + // vendor view support ticket details + async vendorViewSupportTicketDetails(supportTicketId: string) { + await this.vendorSearchSupportTicket('id', supportTicketId); + await this.clickAndWaitForLoadState(selector.vendor.vSupport.storeSupportLink(supportTicketId)); + + await this.toBeVisible(selector.vendor.vSupport.supportTicketDetails.backToTickets); + + // basic details elements are visible + await this.multipleElementVisible(selector.vendor.vSupport.supportTicketDetails.basicDetails); + + // chat status is visible + await this.toBeVisible(selector.vendor.vSupport.supportTicketDetails.chatStatus.status); + + // first chat is visible + await this.toBeVisible(selector.vendor.vSupport.supportTicketDetails.chatBox.mainChat); + + // chat reply box elements are visible + const ticketIsOpen = await this.isVisible(selector.vendor.vSupport.supportTicketDetails.chatStatus.open); + const { addReplyText, closeTicketText, ...replyBox } = selector.vendor.vSupport.supportTicketDetails.replyBox; + ticketIsOpen && (await this.toBeVisible(addReplyText)); + !ticketIsOpen && (await this.multipleElementVisible(closeTicketText)); + await this.multipleElementVisible(replyBox); + } + + // vendor filter support tickets + async vendorFilterSupportTickets(filterBy: string, inputValue: string | date['dateRange']) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.storeSupport); + + switch (filterBy) { + case 'by-customer': + await this.click(selector.vendor.vSupport.filters.filterByCustomer); + // await this.clearAndType(selector.vendor.vSupport.filters.filterByCustomerInput, input); + await this.typeAndWaitForResponse(data.subUrls.ajax, selector.vendor.vSupport.filters.filterByCustomerInput, inputValue as string); + await this.toContainText(selector.vendor.vSupport.filters.result, inputValue as string); + await this.clickAndWaitForLoadState(selector.vendor.vSupport.filters.search); + await this.notToHaveCount(selector.vendor.vSupport.storeSupportsCellByCustomer(inputValue as string), 0); + break; + + case 'by-date': + if (typeof inputValue !== 'string') { + await this.setAttributeValue(selector.vendor.vSupport.filters.filterByDate.dateRangeInput, 'value', helpers.dateFormatFYJ(inputValue.startDate) + ' - ' + helpers.dateFormatFYJ(inputValue.endDate)); + await this.setAttributeValue(selector.vendor.vSupport.filters.filterByDate.startDateInput, 'value', inputValue.startDate); + await this.setAttributeValue(selector.vendor.vSupport.filters.filterByDate.endDateInput, 'value', inputValue.endDate); + await this.clickAndWaitForLoadState(selector.vendor.vSupport.filters.search); + } + break; + + default: + break; + } + await this.notToHaveCount(selector.vendor.vSupport.numOfRowsFound, 0); + } + + // vendor search support ticket + async vendorSearchSupportTicket(searchBy: string, input: string, closed?: boolean) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.storeSupport); + if (closed) { + await this.clickAndWaitForLoadState(selector.vendor.vSupport.menus.closedTickets); + } + + await this.clearAndType(selector.vendor.vSupport.filters.tickedIdOrKeyword, input); + await this.clickAndWaitForLoadState(selector.vendor.vSupport.filters.search); + + switch (searchBy) { + case 'id': + await this.toBeVisible(selector.vendor.vSupport.storeSupportCellById(input)); + break; + + case 'title': + await this.notToHaveCount(selector.vendor.vSupport.storeSupportCellByTitle(input), 0); + break; + + default: + break; + } + } + + // vendor reply to support ticket + async vendorReplySupportTicket(supportTicketId: string, replyMessage: string) { + await this.vendorSearchSupportTicket('id', supportTicketId); + await this.clickAndWaitForLoadState(selector.vendor.vSupport.storeSupportLink(supportTicketId)); + await this.clearAndType(selector.vendor.vSupport.chatReply, replyMessage); + await this.clickAndWaitForResponse('wp-comments-post.php', selector.vendor.vSupport.submitReply, 302); + } + + // vendor close support ticket + async vendorCloseSupportTicket(supportTicketId: string) { + await this.vendorSearchSupportTicket('id', supportTicketId); + await this.click(selector.vendor.vSupport.closeTicket); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.storeSupport, selector.vendor.vSupport.confirmCloseTicket); + } + + // vendor reopen support ticket + async vendorReopenSupportTicket(supportTicketId: string) { + await this.vendorSearchSupportTicket('id', supportTicketId, true); + await this.click(selector.vendor.vSupport.reOpenTicket); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.storeSupport, selector.vendor.vSupport.confirmCloseTicket); + } + + // vendor close support ticket with a reply + async vendorCloseSupportTicketWithReply(supportTicketId: string, replyMessage: string) { + await this.vendorSearchSupportTicket('id', supportTicketId); + await this.clickAndWaitForLoadState(selector.vendor.vSupport.storeSupportLink(supportTicketId)); + await this.toContainText(selector.vendor.vSupport.ticketStatus, 'Open'); + await this.selectByValue(selector.vendor.vSupport.changeStatus, '1'); + await this.clearAndType(selector.vendor.vSupport.chatReply, replyMessage); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.storeSupport, selector.vendor.vSupport.submitReply); + await this.toContainText(selector.vendor.vSupport.ticketStatus, 'Closed'); + } + + // vendor reopen support ticket with a reply + async vendorReopenSupportTicketWithReply(supportTicketId: string, replyMessage: string) { + await this.vendorSearchSupportTicket('id', supportTicketId, true); + await this.clickAndWaitForLoadState(selector.vendor.vSupport.storeSupportLink(supportTicketId)); + await this.toContainText(selector.vendor.vSupport.ticketStatus, 'Closed'); + await this.clearAndType(selector.vendor.vSupport.chatReply, replyMessage); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.storeSupport, selector.vendor.vSupport.submitReply); + await this.toContainText(selector.vendor.vSupport.ticketStatus, 'Open'); + } + + // customer + + // customer store support render properly + async customerStoreSupportRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.supportTickets); + + // menu elements are visible + await this.multipleElementVisible(selector.customer.cSupportTickets.menus); + const noSupportTicket = await this.isVisible(selector.customer.cSupportTickets.noSupportTicketFound); + if (noSupportTicket) { + console.log('No Support Tickets Found!!'); + return; + } + + // store support table elements are visible + await this.multipleElementVisible(selector.customer.cSupportTickets.table); + } + + // customer view support ticket details + async customerViewSupportTicketDetails(supportTicketId: string) { + await this.goIfNotThere(data.subUrls.frontend.supportTickets); + const supportTicketIdIsVisible = await this.isVisible(selector.customer.cSupportTickets.supportTicketLink(supportTicketId)); + if (supportTicketIdIsVisible) { + await this.clickAndWaitForLoadState(selector.customer.cSupportTickets.supportTicketLink(supportTicketId)); + } else { + await this.goIfNotThere(data.subUrls.frontend.supportTicketDetails(supportTicketId)); + } + + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.backToTickets); + + // basic details elements are visible + await this.multipleElementVisible(selector.customer.cSupportTickets.supportTicketDetails.basicDetails); + + // chat status is visible + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.chatStatus.status); + + // first chat is visible + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.chatBox.mainChat); + + // chat reply box elements are visible is ticket is open + const ticketIsOpen = await this.isVisible(selector.customer.cSupportTickets.supportTicketDetails.chatStatus.open); + ticketIsOpen && (await this.multipleElementVisible(selector.customer.cSupportTickets.supportTicketDetails.replyBox)); + // closed ticket elements are visible is ticket is close + !ticketIsOpen && (await this.multipleElementVisible(selector.customer.cSupportTickets.supportTicketDetails.closedTicket)); + } + + // customer ask for store support + async storeSupport(input: string, getSupport: customer['getSupport'], action: string): Promise { + switch (action) { + case 'store': + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(input))); + break; + + case 'product': + await this.goIfNotThere(data.subUrls.frontend.productDetails(helpers.slugify(input))); + break; + + case 'order': + await this.goIfNotThere(data.subUrls.frontend.orderDetails(input)); + break; + + case 'order-received': { + const [orderId, orderKey] = input.split(','); + await this.goIfNotThere(data.subUrls.frontend.orderReceivedDetails(orderId as string, orderKey as string)); + break; + } + + default: + break; + } + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleStore.storeTabs.getSupport); + const isGuest = await this.isVisible(selector.customer.cSingleStore.getSupport.userName); + if (isGuest) { + await this.clearAndType(selector.customer.cSingleStore.getSupport.userName, getSupport.username); + await this.clearAndType(selector.customer.cSingleStore.getSupport.userPassword, getSupport.userPassword); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleStore.getSupport.login); + } + await this.clearAndType(selector.customer.cSingleStore.getSupport.subject, getSupport.subject); + getSupport.orderId && (await this.selectByValue(selector.customer.cSingleStore.getSupport.orderId, getSupport.orderId)); + await this.clearAndType(selector.customer.cSingleStore.getSupport.message, getSupport.message); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleStore.getSupport.submit); + await this.toContainText(selector.customer.cDokanSelector.dokanAlertSuccessMessage, getSupport.supportSubmitSuccessMessage); + // close popup + await this.click(selector.customer.cSingleStore.getSupport.close); + } + + // customer cant send message to closed support ticket + async viewOrderReferenceNumberOnSupportTicket(supportTicketId: string, orderId: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.supportTicketDetails(supportTicketId)); + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.orderReference.orderReferenceSpan); + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.orderReference.orderReferenceText(orderId)); + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.orderReference.orderReferenceLink(orderId)); + } + + // customer send message to support ticket + async sendMessageToSupportTicket(supportTicketId: string, supportTicket: customer['supportTicket']): Promise { + const message = supportTicket.message(); + await this.goIfNotThere(data.subUrls.frontend.supportTicketDetails(supportTicketId)); + await this.clearAndType(selector.customer.cSupportTickets.supportTicketDetails.replyBox.addReply, message); + await this.clickAndWaitForResponse(data.subUrls.frontend.submitSupport, selector.customer.cSupportTickets.supportTicketDetails.replyBox.submitReply, 302); + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.chatText(message)); + } + + // customer can't send message to closed support ticket + async cantSendMessageToSupportTicket(supportTicketId: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.supportTicketDetails(supportTicketId)); + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.chatStatus.closed); + await this.toBeVisible(selector.customer.cSupportTickets.supportTicketDetails.closedTicket.closedTicketHeading); + await this.toContainText(selector.customer.cSupportTickets.supportTicketDetails.closedTicket.closedTicketMessage, 'This ticket has been closed. Open a new support ticket if you have any further query.'); + } +} diff --git a/tests/pw/pages/storesPage.ts b/tests/pw/pages/storesPage.ts new file mode 100644 index 0000000000..9944e6e7b4 --- /dev/null +++ b/tests/pw/pages/storesPage.ts @@ -0,0 +1,363 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { vendor } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class StoresPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // vendors + + // vendors render properly + async adminVendorsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.vendors); + + // vendor text is visible + await this.toBeVisible(selector.admin.dokan.vendors.vendorsText); + + // and new vendor is visible + await this.toBeVisible(selector.admin.dokan.vendors.addNewVendor); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.vendors.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.vendors.bulkActions); + + // search vendor input is visible + await this.toBeVisible(selector.admin.dokan.vendors.search); + + // vendor table elements are visible + const { categoryColumn, ...table } = selector.admin.dokan.vendors.table; + await this.multipleElementVisible(table); + } + + // view vendor details + async viewVendorDetails(storeName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.vendorDetails(storeName)); + + // profile info elements are visible + const { featuredVendor, storeRating, storeCategory, ...profileInfo } = selector.admin.dokan.vendors.vendorDetails.profileInfo; + await this.multipleElementVisible(profileInfo); + + // profile banner elements are visible + await this.multipleElementVisible(selector.admin.dokan.vendors.vendorDetails.profileBanner); + + // badges acquired elements are visible + const badgesAcquired = await this.isVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.badgesAcquired.badgesAcquired); + badgesAcquired && (await this.toBeVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.badgesAcquired.badgesAcquired)); + + // product & revenue elements are visible + await this.toBeVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.productRevenue.productRevenueSection); + await this.multipleElementVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.productRevenue.products); + await this.multipleElementVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.productRevenue.revenue); + await this.multipleElementVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.productRevenue.others); + + // vendor info elements are visible + await this.multipleElementVisible(selector.admin.dokan.vendors.vendorDetails.vendorSummary.vendorInfo); + } + + // email vendor + async emailVendor(storeName: string, email: vendor['vendorInfo']['sendEmail']) { + await this.goIfNotThere(data.subUrls.backend.dokan.vendorDetails(storeName)); + + await this.click(selector.admin.dokan.vendors.vendorDetails.profileInfo.sendEmail); + + await this.clearAndType(selector.admin.dokan.vendors.vendorDetails.sendEmail.subject, email.subject); + await this.clearAndType(selector.admin.dokan.vendors.vendorDetails.sendEmail.message, email.message); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.vendorDetails.sendEmail.sendEmail); + } + + // admin add new vendors + async addVendor(vendorInfo: vendor['vendorInfo']) { + await this.goIfNotThere(data.subUrls.backend.dokan.vendors); + + const firstName = vendorInfo.firstName(); + const email = vendorInfo.email(); + const shopName = vendorInfo.shopName(); + const username = firstName + vendorInfo.nanoid; + + // add new vendor + await this.click(selector.admin.dokan.vendors.addNewVendor); + // account info + await this.type(selector.admin.dokan.vendors.newVendor.firstName, firstName); + await this.type(selector.admin.dokan.vendors.newVendor.lastName, vendorInfo.lastName()); + await this.type(selector.admin.dokan.vendors.newVendor.storeName, shopName); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.newVendor.storeUrl, shopName); + await this.type(selector.admin.dokan.vendors.newVendor.phoneNumber, vendorInfo.phoneNumber); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.newVendor.email, email); + await this.click(selector.admin.dokan.vendors.newVendor.generatePassword); + await this.clearAndType(selector.admin.dokan.vendors.newVendor.password, vendorInfo.password); + await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.newVendor.username, username); + if (DOKAN_PRO) { + await this.type(selector.admin.dokan.vendors.newVendor.companyName, vendorInfo.companyName); + await this.type(selector.admin.dokan.vendors.newVendor.companyIdEuidNumber, vendorInfo.companyId); + await this.type(selector.admin.dokan.vendors.newVendor.vatOrTaxNumber, vendorInfo.vatNumber); + await this.type(selector.admin.dokan.vendors.newVendor.nameOfBank, vendorInfo.bankName); + await this.type(selector.admin.dokan.vendors.newVendor.bankIban, vendorInfo.bankIban); + } + await this.click(selector.admin.dokan.vendors.newVendor.next); + // address + await this.type(selector.admin.dokan.vendors.newVendor.street1, vendorInfo.street1); + await this.type(selector.admin.dokan.vendors.newVendor.street2, vendorInfo.street2); + await this.type(selector.admin.dokan.vendors.newVendor.city, vendorInfo.city); + await this.type(selector.admin.dokan.vendors.newVendor.zip, vendorInfo.zipCode); + await this.click(selector.admin.dokan.vendors.newVendor.country); + await this.type(selector.admin.dokan.vendors.newVendor.countryInput, vendorInfo.country); + await this.press(data.key.enter); + await this.click(selector.admin.dokan.vendors.newVendor.state); + await this.type(selector.admin.dokan.vendors.newVendor.stateInput, vendorInfo.state); + await this.press(data.key.enter); + await this.click(selector.admin.dokan.vendors.newVendor.next); + // payment options + await this.type(selector.admin.dokan.vendors.newVendor.accountName, vendorInfo.accountName); + await this.type(selector.admin.dokan.vendors.newVendor.accountNumber, vendorInfo.accountNumber); + await this.type(selector.admin.dokan.vendors.newVendor.bankName, vendorInfo.bankName); + await this.type(selector.admin.dokan.vendors.newVendor.bankAddress, vendorInfo.bankAddress); + await this.type(selector.admin.dokan.vendors.newVendor.routingNumber, vendorInfo.routingNumber); + await this.type(selector.admin.dokan.vendors.newVendor.iban, vendorInfo.iban); + await this.type(selector.admin.dokan.vendors.newVendor.swift, vendorInfo.swiftCode); + await this.fill(selector.admin.dokan.vendors.newVendor.payPalEmail, vendorInfo.email()); + await this.check(selector.admin.dokan.vendors.newVendor.enableSelling); + await this.check(selector.admin.dokan.vendors.newVendor.publishProductDirectly); + await this.check(selector.admin.dokan.vendors.newVendor.makeVendorFeature); + // create vendor + await this.clickAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.newVendor.createVendor); + await this.toContainText(selector.admin.dokan.vendors.sweetAlertTitle, 'Vendor Created'); + await this.click(selector.admin.dokan.vendors.closeSweetAlert); + } + + // edit vendor + async editVendor(vendor: vendor) { + await this.searchVendor(vendor.storeName); + + await this.hover(selector.admin.dokan.vendors.vendorRow(vendor.storeName)); + await this.clickAndWaitForLoadState(selector.admin.dokan.vendors.vendorEdit(vendor.storeName)); + + if (!DOKAN_PRO) { + // basic info + await this.selectByValue(selector.admin.users.userInfo.role, vendor.vendorInfo.role); + await this.clearAndType(selector.admin.users.userInfo.firstName, vendor.username); + await this.clearAndType(selector.admin.users.userInfo.lastName, vendor.lastname); + await this.clearAndType(selector.admin.users.userInfo.nickname, vendor.username); + + // contact info + await this.clearAndType(selector.admin.users.userInfo.email, vendor.username + data.vendor.vendorInfo.emailDomain); + + // About the user + await this.clearAndType(selector.admin.users.userInfo.biographicalInfo, vendor.vendorInfo.biography); + + // vendor address + + // billing + await this.clearAndType(selector.admin.users.userInfo.billingAddress.firstName, vendor.username); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.lastName, vendor.lastname); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.company, vendor.vendorInfo.companyName); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.address1, vendor.vendorInfo.street1); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.address2, vendor.vendorInfo.street2); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.city, vendor.vendorInfo.city); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.postcode, vendor.vendorInfo.zipCode); + await this.click(selector.admin.users.userInfo.billingAddress.country); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.countryInput, vendor.vendorInfo.country); + await this.press(data.key.enter); + await this.click(selector.admin.users.userInfo.billingAddress.state); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.stateInput, vendor.vendorInfo.state); + await this.press(data.key.enter); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.phone, vendor.vendorInfo.phoneNumber); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.email, vendor.username + data.vendor.vendorInfo.emailDomain); + + // pro edit user + // await this.clearAndType(selector.admin.users.userInfo.billingAddress.companyIdOrEuidNumber, vendor.vendorInfo.companyId); + // await this.clearAndType(selector.admin.users.userInfo.billingAddress.vatOrTaxNumber, vendor.vendorInfo.vatNumber); + // await this.clearAndType(selector.admin.users.userInfo.billingAddress.bank, vendor.vendorInfo.bankName); + // await this.clearAndType(selector.admin.users.userInfo.billingAddress.bankIban, vendor.vendorInfo.bankIban); + + // shipping + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.firstName, vendor.username); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.lastName, vendor.lastname); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.company, vendor.vendorInfo.companyName); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.address1, vendor.vendorInfo.street1); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.address2, vendor.vendorInfo.street2); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.city, vendor.vendorInfo.city); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.postcode, vendor.vendorInfo.zipCode); + await this.click(selector.admin.users.userInfo.shippingAddress.country); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.countryInput, vendor.vendorInfo.country); + await this.press(data.key.enter); + await this.click(selector.admin.users.userInfo.shippingAddress.state); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.stateInput, vendor.vendorInfo.state); + await this.press(data.key.enter); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.phone, vendor.vendorInfo.phoneNumber); + + // dokan options + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.storeName, vendor.vendorInfo.storeName); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.storeUrl, vendor.vendorInfo.storeName); + // store address + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.address1, vendor.vendorInfo.street1); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.address2, vendor.vendorInfo.street2); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.city, vendor.vendorInfo.city); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.postcode, vendor.vendorInfo.zipCode); + await this.click(selector.admin.users.userInfo.dokanOptions.country); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.countryInput, vendor.vendorInfo.country); + await this.press(data.key.enter); + await this.click(selector.admin.users.userInfo.dokanOptions.state); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.stateInput, vendor.vendorInfo.state); + await this.press(data.key.enter); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.phone, vendor.vendorInfo.phoneNumber); + + // pro edit user + // await this.clearAndType(selector.admin.users.userInfo.dokanOptions.companyName, vendor.vendorInfo.companyName); + // await this.clearAndType(selector.admin.users.userInfo.dokanOptions.companyIdOrEuidNumber, vendor.vendorInfo.companyId); + // await this.clearAndType(selector.admin.users.userInfo.dokanOptions.vatOrTaxNumber, vendor.vendorInfo.vatNumber); + // await this.clearAndType(selector.admin.users.userInfo.dokanOptions.bank, vendor.vendorInfo.bankName); + // await this.clearAndType(selector.admin.users.userInfo.dokanOptions.bankIban, vendor.vendorInfo.bankIban); + + // social profiles + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.facebook, vendor.vendorInfo.socialProfileUrls.facebook); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.twitter, vendor.vendorInfo.socialProfileUrls.twitter); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.pinterest, vendor.vendorInfo.socialProfileUrls.pinterest); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.linkedin, vendor.vendorInfo.socialProfileUrls.linkedin); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.youtube, vendor.vendorInfo.socialProfileUrls.youtube); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.instagram, vendor.vendorInfo.socialProfileUrls.instagram); + await this.clearAndType(selector.admin.users.userInfo.dokanOptions.flickr, vendor.vendorInfo.socialProfileUrls.flickr); + + // other settings + await this.check(selector.admin.users.userInfo.dokanOptions.selling); + await this.check(selector.admin.users.userInfo.dokanOptions.publishing); + await this.check(selector.admin.users.userInfo.dokanOptions.featuredVendor); + + // update user + await this.clickAndWaitForResponse(data.subUrls.backend.user, selector.admin.users.updateUser, 302); + await this.toContainText(selector.admin.users.updateSuccessMessage, 'User updated.'); + } else { + // basic + await this.clearAndType(selector.admin.dokan.vendors.editVendor.firstName, vendor.username); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.lastName, vendor.lastname); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.storeName, vendor.vendorInfo.storeName); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.phoneNumber, vendor.vendorInfo.phone); // todo: change input after fix + await this.clearAndType(selector.admin.dokan.vendors.editVendor.email, vendor.username + data.vendor.vendorInfo.emailDomain); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.companyName, vendor.vendorInfo.companyName); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.companyIdEuidNumber, vendor.vendorInfo.companyId); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.vatOrTaxNumber, vendor.vendorInfo.vatNumber); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.nameOfBank, vendor.vendorInfo.bankName); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.bankIban, vendor.vendorInfo.bankIban); + + // address + await this.clearAndType(selector.admin.dokan.vendors.editVendor.street1, vendor.vendorInfo.street1); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.street2, vendor.vendorInfo.street2); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.city, vendor.vendorInfo.city); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.zipCode, vendor.vendorInfo.zipCode); + await this.click(selector.admin.dokan.vendors.editVendor.country); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.countryInput, vendor.vendorInfo.country); + await this.press(data.key.enter); + await this.click(selector.admin.dokan.vendors.editVendor.state); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.stateInput, vendor.vendorInfo.state); + await this.press(data.key.enter); + + // social options + await this.clearAndType(selector.admin.dokan.vendors.editVendor.facebook, vendor.vendorInfo.socialProfileUrls.facebook); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.flickr, vendor.vendorInfo.socialProfileUrls.flickr); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.twitter, vendor.vendorInfo.socialProfileUrls.twitter); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.youtube, vendor.vendorInfo.socialProfileUrls.youtube); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.linkedin, vendor.vendorInfo.socialProfileUrls.linkedin); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.pinterest, vendor.vendorInfo.socialProfileUrls.pinterest); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.instagram, vendor.vendorInfo.socialProfileUrls.instagram); + + // payment options + // bank + await this.clearAndType(selector.admin.dokan.vendors.editVendor.accountName, vendor.vendorInfo.payment.bankAccountName); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.accountNumber, vendor.vendorInfo.payment.bankAccountNumber); + await this.selectByValue(selector.admin.dokan.vendors.editVendor.accountType, vendor.vendorInfo.payment.bankAccountType); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.bankName, vendor.vendorInfo.payment.bankName); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.bankAddress, vendor.vendorInfo.payment.bankAddress); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.routingNumber, vendor.vendorInfo.payment.bankRoutingNumber); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.iban, vendor.vendorInfo.payment.bankIban); + await this.clearAndType(selector.admin.dokan.vendors.editVendor.swift, vendor.vendorInfo.payment.bankSwiftCode); + + // paypal + await this.clearAndType(selector.admin.dokan.vendors.editVendor.payPalEmail, vendor.vendorInfo.payment.email()); + + // todo: admin commission + // todo: vendor subscription + + // other settings + await this.enableSwitcher(selector.admin.dokan.vendors.editVendor.enableSelling); + await this.enableSwitcher(selector.admin.dokan.vendors.editVendor.publishProductDirectly); + await this.enableSwitcher(selector.admin.dokan.vendors.editVendor.makeVendorFeature); + + await this.clickAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.editVendor.saveChanges); + await this.click(selector.admin.dokan.vendors.editVendor.confirmSaveChanges); + } + } + + // search vendor + async searchVendor(vendorName: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.vendors); + + await this.clearInputField(selector.admin.dokan.vendors.search); + + await this.typeAndWaitForResponseAndLoadState(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.search, vendorName); + await this.toBeVisible(selector.admin.dokan.vendors.vendorCell(vendorName)); + + // negative scenario + // await this.typeAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.search, vendorName + 'abcdefgh'); + // await this.toBeVisible(selector.admin.dokan.vendors.noRowsFound); + } + + // update vendor + async updateVendor(vendorName: string, action: string) { + await this.searchVendor(vendorName); + + switch (action) { + case 'enable': + await this.enableSwitcherAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.statusSlider(vendorName)); + break; + + case 'disable': + await this.disableSwitcherAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.statusSlider(vendorName)); + break; + + default: + break; + } + } + + // view vendor orders, products + async viewVendor(vendorName: string, action: string) { + await this.searchVendor(vendorName); + + await this.hover(selector.admin.dokan.vendors.vendorRow(vendorName)); + + switch (action) { + case 'products': + await this.clickAndWaitForLoadState(selector.admin.dokan.vendors.vendorProducts(vendorName)); + break; + + case 'orders': + await this.clickAndWaitForLoadState(selector.admin.dokan.vendors.vendorOrders(vendorName)); + break; + + default: + break; + } + + const count = (await this.getElementText(selector.admin.dokan.vendors.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } + + // vendor bulk action + async vendorBulkAction(action: string, vendorName?: string) { + vendorName ? await this.searchVendor(vendorName) : await this.goIfNotThere(data.subUrls.backend.dokan.vendors); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.vendors.noRowsFound); + + await this.click(selector.admin.dokan.vendors.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.vendors.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.stores, selector.admin.dokan.vendors.bulkActions.applyAction); + } +} diff --git a/tests/pw/pages/taxPage.ts b/tests/pw/pages/taxPage.ts new file mode 100644 index 0000000000..961fa2143d --- /dev/null +++ b/tests/pw/pages/taxPage.ts @@ -0,0 +1,45 @@ +import { Page, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { tax } from '@utils/interfaces'; + +export class TaxPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // Tax methods + + // Admin Enable-Disable Tax + async enableTax(enable = true) { + await this.goToWooCommerceSettings(); + enable ? await this.check(selector.admin.wooCommerce.settings.enableTaxes) : await this.uncheck(selector.admin.wooCommerce.settings.enableTaxes); + await this.click(selector.admin.wooCommerce.settings.generalSaveChanges); + await this.toContainText(selector.admin.wooCommerce.settings.updatedSuccessMessage, data.tax.saveSuccessMessage); + } + + // Admin Add Standard Tax Rate + async addStandardTaxRate(tax: tax) { + await this.goToWooCommerceSettings(); + + // Enable Tax + await this.enableTax(); + + // Set Tax Rate + await this.click(selector.admin.wooCommerce.settings.tax); + await this.click(selector.admin.wooCommerce.settings.standardRates); + const taxIsVisible = await this.isVisible(selector.admin.wooCommerce.settings.taxRate); + if (!taxIsVisible) { + await this.click(selector.admin.wooCommerce.settings.insertRow); + } + await this.clearAndType(selector.admin.wooCommerce.settings.taxRate, tax.taxRate); + await this.click(selector.admin.wooCommerce.settings.taxTable); + + await this.click(selector.admin.wooCommerce.settings.taxRateSaveChanges); + + const newTaxRate = await this.getElementValue(selector.admin.wooCommerce.settings.taxRate); + // expect(newTaxRate).toBe(String(Number(tax.taxRate).toPrecision(5))) + expect(newTaxRate).toBe(tax.taxRate); + } +} diff --git a/tests/pw/pages/toolsPage.ts b/tests/pw/pages/toolsPage.ts new file mode 100644 index 0000000000..67aaf4f0e9 --- /dev/null +++ b/tests/pw/pages/toolsPage.ts @@ -0,0 +1,92 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { tools } from '@utils/interfaces'; + +export class ToolsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // tools + + // tools render properly + async adminToolsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + + // tools text is visible + await this.toBeVisible(selector.admin.dokan.tools.toolsText); + + // Page Installation elements are visible + await this.multipleElementVisible(selector.admin.dokan.tools.pageInstallation); + + // Check For Duplicate Orders are visible + await this.multipleElementVisible(selector.admin.dokan.tools.checkForDuplicateOrders); + + // Dokan Setup Wizard elements are visible + await this.multipleElementVisible(selector.admin.dokan.tools.dokanSetupWizard); + + // Regenerate Variable Product Variations Author Ids elements are visible elements are visible + await this.multipleElementVisible(selector.admin.dokan.tools.regenerateVariableProductVariationsAuthorIds); + + // Import Dummy Data elements are visible + await this.multipleElementVisible(selector.admin.dokan.tools.importDummyData); + + // Test Distance Matrix API (Google MAP) elements are visible + const { enabledSuccess, ...testDistanceMatrixApi } = selector.admin.dokan.tools.testDistanceMatrixApi; + await this.multipleElementVisible(testDistanceMatrixApi); + } + + // dokan page installation + async dokanPageInstallation() { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + + // all page created button should be disabled + await this.hasClass(selector.admin.dokan.tools.pageInstallation.allPagesCreated, 'button-disabled'); + // todo: enable the button then install pages again + // await this.setAttributeValue(selector.admin.dokan.tools.pageInstallation.allPagesCreated, 'class', 'button button-primary'); + // await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.dokan.tools.pageInstallation.allPagesCreated); + } + + // check for duplicate order + async checkForDuplicateOrders() { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.dokan.tools.checkForDuplicateOrders.checkOrders); + } + + // regenerate variable product variations author IDs + async regenerateVariableProductVariationsAuthorIds() { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.dokan.tools.regenerateVariableProductVariationsAuthorIds.regenerate); + } + + // clear dummy data + async clearDummyData() { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.dummyData, selector.admin.dokan.tools.importDummyData.import); + await this.click(selector.admin.dokan.dummyData.clearDummyData); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.dummyData, selector.admin.dokan.dummyData.confirmClearDummyData); + } + + // import dummy data + async importDummyData() { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.dummyData, selector.admin.dokan.tools.importDummyData.import); + // await this.clickAndWaitForResponse(data.subUrls.api.dokan.dummyData, selector.admin.dokan.dummyData.runTheImporter); + // todo: wait for multiple request one after another + // const subUrls = [[data.subUrls.api.dokan.dummyData], [data.subUrls.api.dokan.dummyData], [data.subUrls.api.dokan.dummyData], [data.subUrls.api.dokan.dummyData], [data.subUrls.api.dokan.dummyData]]; + // await this.clickAndWaitForResponses(subUrls, selector.admin.dokan.dummyData.runTheImporter); + // await this.toBeVisible(selector.admin.dokan.dummyData.importComplete); + } + + // test distance matrix API + async testDistanceMatrixApi(address: tools['distanceMatrixApi']) { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + + await this.clearAndType(selector.admin.dokan.tools.testDistanceMatrixApi.address1, address.address3); + await this.clearAndType(selector.admin.dokan.tools.testDistanceMatrixApi.address2, address.address4); + await this.click(selector.admin.dokan.tools.testDistanceMatrixApi.getDistance); + await this.toContainText(selector.admin.dokan.tools.testDistanceMatrixApi.enabledSuccess, 'Distance Matrix API is enabled.'); + } +} diff --git a/tests/pw/pages/vendorAnalyticsPage.ts b/tests/pw/pages/vendorAnalyticsPage.ts new file mode 100644 index 0000000000..522da36a33 --- /dev/null +++ b/tests/pw/pages/vendorAnalyticsPage.ts @@ -0,0 +1,41 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class VendorAnalyticsPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // vendor analytics + + // vendor analytics render properly + async vendorAnalyticsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.analytics); + + // analytics text is visible + await this.toBeVisible(selector.vendor.vAnalytics.analyticsText); + + // analytics menu elements are visible + await this.multipleElementVisible(selector.vendor.vAnalytics.menus); + + // date-picker elements are visible + await this.multipleElementVisible(selector.vendor.vAnalytics.datePicker); + + await this.clickAndWaitForLoadState(selector.vendor.vAnalytics.menus.topPages); + await this.toBeVisible(selector.vendor.vAnalytics.noAnalyticsFound); + + await this.clickAndWaitForLoadState(selector.vendor.vAnalytics.menus.location); + await this.toBeVisible(selector.vendor.vAnalytics.noAnalyticsFound); + + await this.clickAndWaitForLoadState(selector.vendor.vAnalytics.menus.system); + await this.toBeVisible(selector.vendor.vAnalytics.noAnalyticsFound); + + await this.clickAndWaitForLoadState(selector.vendor.vAnalytics.menus.promotions); + await this.toBeVisible(selector.vendor.vAnalytics.noAnalyticsFound); + + await this.clickAndWaitForLoadState(selector.vendor.vAnalytics.menus.keyword); + await this.toBeVisible(selector.vendor.vAnalytics.noAnalyticsFound); + } +} diff --git a/tests/pw/pages/vendorAuctionsPage.ts b/tests/pw/pages/vendorAuctionsPage.ts new file mode 100644 index 0000000000..1eb9d77e1a --- /dev/null +++ b/tests/pw/pages/vendorAuctionsPage.ts @@ -0,0 +1,193 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { product, date } from '@utils/interfaces'; + +export class AuctionsPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + customerPage = new CustomerPage(this.page); + + // auctions + + // Admin Add Auction Product + async adminAddAuctionProduct(product: product['auction']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // Name + await this.clearAndType(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + await this.click(selector.admin.products.product.auction); + await this.selectByValue(selector.admin.products.product.itemCondition, product.itemCondition); + await this.selectByValue(selector.admin.products.product.auctionType, product.auctionType); + await this.clearAndType(selector.admin.products.product.startPrice, product.regularPrice()); + await this.clearAndType(selector.admin.products.product.bidIncrement, product.bidIncrement()); + await this.clearAndType(selector.admin.products.product.reservedPrice, product.reservedPrice()); + await this.clearAndType(selector.admin.products.product.buyItNowPrice, product.buyItNowPrice()); + await this.clearAndType(selector.admin.products.product.auctionDatesFrom, product.startDate); + await this.clearAndType(selector.admin.products.product.auctionDatesTo, product.endDate); + + // Category + await this.click(selector.admin.products.product.category(product.category)); + + // Vendor Store Name + await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + await this.scrollToTop(); + + // Publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + } + + // vendor auction render properly + async vendorAuctionRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.auction); + + // auctions menu elements are visible + await this.multipleElementVisible(selector.vendor.vAuction.menus); + + // add new auction product button is visible + await this.toBeVisible(selector.vendor.vAuction.addNewActionProduct); + + // auction activity button is visible + await this.toBeVisible(selector.vendor.vAuction.actionsActivity); + + // filter elements are visible + await this.multipleElementVisible(selector.vendor.vAuction.filters); + + // search element is visible + await this.toBeVisible(selector.vendor.vAuction.search); + + // auction product table elements are visible + await this.multipleElementVisible(selector.vendor.vAuction.table); + } + + // vendor + + // update auction product fields + async updateAuctionProductFields(product: product['auction']) { + await this.clearAndType(selector.vendor.vAuction.auction.productName, product.name); + // await this.addProductCategory(product.category); + await this.selectByValue(selector.vendor.vAuction.auction.itemCondition, product.itemCondition); + await this.selectByValue(selector.vendor.vAuction.auction.auctionType, product.auctionType); + await this.clearAndType(selector.vendor.vAuction.auction.startPrice, product.regularPrice()); + await this.clearAndType(selector.vendor.vAuction.auction.bidIncrement, product.bidIncrement()); + await this.clearAndType(selector.vendor.vAuction.auction.reservedPrice, product.reservedPrice()); + await this.clearAndType(selector.vendor.vAuction.auction.buyItNowPrice, product.buyItNowPrice()); + await this.removeAttribute(selector.vendor.vAuction.auction.auctionStartDate, 'readonly'); + await this.removeAttribute(selector.vendor.vAuction.auction.auctionEndDate, 'readonly'); + await this.clearAndType(selector.vendor.vAuction.auction.auctionStartDate, product.startDate); + await this.clearAndType(selector.vendor.vAuction.auction.auctionEndDate, product.endDate); + // todo: add more fields + } + + // add auction product + async addAuctionProduct(product: product['auction']) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.auction); + await this.clickAndWaitForLoadState(selector.vendor.vAuction.addNewActionProduct); + await this.updateAuctionProductFields(product); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.productAuction, selector.vendor.vAuction.auction.addAuctionProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // edit auction product + async editAuctionProduct(product: product['auction']) { + await this.searchAuctionProduct(product.name); + await this.hover(selector.vendor.vAuction.productCell(product.name)); + await this.clickAndWaitForLoadState(selector.vendor.vAuction.edit(product.name)); + await this.updateAuctionProductFields(product); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.auction, selector.vendor.vAuction.auction.updateAuctionProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // view auction product + async viewAuctionProduct(productName: string) { + await this.searchAuctionProduct(productName); + await this.hover(selector.vendor.vAuction.productCell(productName)); + await this.clickAndWaitForLoadState(selector.vendor.vAuction.view(productName)); + + // auction product elements are visible + const { bidQuantity, bidButton, ...viewAuction } = selector.vendor.vAuction.viewAuction; + await this.multipleElementVisible(viewAuction); + } + + // vendor can't bid own auction product + async cantBidOwnProduct(productName: string) { + await this.goToProductDetails(productName); + await this.toBeVisible(selector.vendor.vAuction.viewAuction.noBidOption); + } + + // search auction product + async searchAuctionProduct(productName: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.auction); + await this.clearAndType(selector.vendor.vAuction.search, productName); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.auction, selector.vendor.vAuction.filters.filter); + await this.toBeVisible(selector.vendor.vAuction.productCell(productName)); + } + + // delete auction product + async deleteAuctionProduct(productName: string) { + await this.searchAuctionProduct(productName); + await this.hover(selector.vendor.vAuction.productCell(productName)); + await this.click(selector.vendor.vAuction.permanentlyDelete(productName)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.auction, selector.vendor.vAuction.confirmDelete); + await this.toContainText(selector.vendor.vAuction.dokanSuccessMessage, 'Product successfully deleted'); + } + + // vendor auction activity render properly + async vendorAuctionActivityRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.auctionActivity); + + // auction activity text is visible + await this.toBeVisible(selector.vendor.vAuction.actionActivity.actionActivityText); + + // back to auctions is visible + await this.toBeVisible(selector.vendor.vAuction.actionActivity.backToActions); + + // filter elements are visible + const { filterByDate, ...filters } = selector.vendor.vAuction.actionActivity.filters; + await this.multipleElementVisible(filters); + await this.toBeVisible(filterByDate.dateRangeInput); + + // search elements are visible + await this.multipleElementVisible(selector.vendor.vAuction.actionActivity.search); + + // auction activity table elements are visible + await this.multipleElementVisible(selector.vendor.vAuction.actionActivity.table); + } + + // filter auction activity + async filterAuctionActivity(inputValue: date['dateRange']) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.auctionActivity); + await this.setAttributeValue(selector.vendor.vAuction.actionActivity.filters.filterByDate.dateRangeInput, 'value', helpers.dateFormatFYJ(inputValue.startDate) + ' - ' + helpers.dateFormatFYJ(inputValue.endDate)); + await this.setAttributeValue(selector.vendor.vAuction.actionActivity.filters.filterByDate.startDateInput, 'value', inputValue.startDate); + await this.setAttributeValue(selector.vendor.vAuction.actionActivity.filters.filterByDate.endDateInput, 'value', inputValue.endDate); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.auctionActivity, selector.vendor.vAuction.actionActivity.filters.filter); + await this.notToHaveCount(selector.vendor.vAuction.actionActivity.numOfRowsFound, 0); + } + + // search auction activity + async searchAuctionActivity(input: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.auctionActivity); + await this.clearAndType(selector.vendor.vAuction.actionActivity.search.searchInput, input); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.auctionActivity, selector.vendor.vAuction.actionActivity.search.search); + await this.notToHaveCount(selector.vendor.vAuction.actionActivity.numOfRowsFound, 0); + } + + // customer + + async bidAuctionProduct(productName: string) { + await this.goToProductDetails(productName); + await this.click(selector.vendor.vAuction.viewAuction.bidButton); + } + + async buyAuctionProduct(productName: string) { + await this.customerPage.addProductToCart(productName, 'single-product'); + await this.customerPage.placeOrder(); + } +} diff --git a/tests/pw/pages/vendorBookingPage.ts b/tests/pw/pages/vendorBookingPage.ts new file mode 100644 index 0000000000..7f3d895e89 --- /dev/null +++ b/tests/pw/pages/vendorBookingPage.ts @@ -0,0 +1,307 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { product, bookings, bookingResource } from '@utils/interfaces'; + +export class BookingPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + customerPage = new CustomerPage(this.page); + + // booking + + // Admin Add Booking Product + async adminAddBookingProduct(product: product['booking']) { + await this.goIfNotThere(data.subUrls.backend.wc.addNewProducts); + + // Name + await this.clearAndType(selector.admin.products.product.productName, product.productName()); + await this.selectByValue(selector.admin.products.product.productType, product.productType); + await this.click(selector.admin.products.product.general); + await this.selectByValue(selector.admin.products.product.bookingDurationType, product.bookingDurationType); + await this.clearAndType(selector.admin.products.product.bookingDurationMax, product.bookingDurationMax); + await this.selectByValue(selector.admin.products.product.calendarDisplayMode, product.calendarDisplayMode); + + // Costs + await this.click(selector.admin.products.product.bookingCosts); + await this.clearAndType(selector.admin.products.product.baseCost, product.baseCost); + await this.clearAndType(selector.admin.products.product.blockCost, product.blockCost); + + // Category + await this.click(selector.admin.products.product.category(product.category)); + + // Vendor Store Name + await this.select2ByText(selector.admin.products.product.storeName, selector.admin.products.product.storeNameInput, product.storeName); + await this.scrollToTop(); + + // Publish + await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.products.product.publish, 302); + await this.toContainText(selector.admin.products.product.updatedSuccessMessage, data.product.publishSuccessMessage); + } + + // vendor + + // vendor booking render properly + async vendorBookingRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.booking); + + // add booking product text is visible + await this.toBeVisible(selector.vendor.vBooking.allBookingProductText); + + // booking menu elements are visible + await this.multipleElementVisible(selector.vendor.vBooking.menus); + + // add new booking product button is visible + await this.toBeVisible(selector.vendor.vBooking.addNewBookingProduct); + + // add booking button is visible + await this.toBeVisible(selector.vendor.vBooking.addBookingBtn); + + // filter elements are visible + await this.multipleElementVisible(selector.vendor.vBooking.filters); + + // search elements are visible + await this.multipleElementVisible(selector.vendor.vBooking.search); + + // booking product table elements are visible + await this.multipleElementVisible(selector.vendor.vBooking.table); + } + + // vendor manage booking render properly + async vendorManageBookingRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.manageBooking); + + // manage booking text is visible + await this.toBeVisible(selector.vendor.vBooking.manageBookings.manageBookingsText); + + // manage booking menu elements are visible + await this.toBeVisible(selector.vendor.vBooking.manageBookings.menus.all); + + const noBookingsFound = await this.isVisible(selector.vendor.vBooking.manageBookings.noBookingsFound); + if (noBookingsFound) { + return; + } + // todo: add more fields + } + + // vendor manage booking render properly + async vendorBookingCalendarRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.bookingCalendar); + + // manage booking text is visible + await this.toBeVisible(selector.vendor.vBooking.calendar.calendarText); + + // calendar is visible + await this.toBeVisible(selector.vendor.vBooking.calendar.calendar); + + // calendar filterBookings is visible + await this.toBeVisible(selector.vendor.vBooking.calendar.filterBookings); + + // calendar month view elements are visible + await this.multipleElementVisible(selector.vendor.vBooking.calendar.month); + + await this.clickAndWaitForLoadState(selector.vendor.vBooking.calendar.month.dayView); + + // calendar day view elements are visible + await this.multipleElementVisible(selector.vendor.vBooking.calendar.day); + } + + // vendor manage booking render properly + async vendorManageResourcesRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.manageResources); + + // manage resource text is visible + await this.toBeVisible(selector.vendor.vBooking.manageResources.manageResourcesText); + + // add new resource is visible + await this.toBeVisible(selector.vendor.vBooking.manageResources.addNewResource); + + // booking product table elements are visible + await this.multipleElementVisible(selector.vendor.vBooking.manageResources.table); + + const noBookingsFound = await this.isVisible(selector.vendor.vBooking.manageResources.noResourceFound); + if (noBookingsFound) { + return; + } + // todo: add more fields + } + + // update booking product fields + async updateBookingProductFields(product: product['booking']) { + await this.clearAndType(selector.vendor.vBooking.booking.productName, product.name); + // await this.addProductCategory(product.category); + // general booking options + await this.selectByValue(selector.vendor.vBooking.booking.bookingDurationType, product.bookingDurationType); + await this.clearAndType(selector.vendor.vBooking.booking.bookingDurationMin, product.bookingDurationMin); + await this.clearAndType(selector.vendor.vBooking.booking.bookingDurationMax, product.bookingDurationMax); + await this.selectByValue(selector.vendor.vBooking.booking.bookingDurationUnit, product.bookingDurationUnit); + // calendar display mode + await this.selectByValue(selector.vendor.vBooking.booking.calendarDisplayMode, product.calendarDisplayMode); + await this.check(selector.vendor.vBooking.booking.enableCalendarRangePicker); + // availability + await this.clearAndType(selector.vendor.vBooking.booking.maxBookingsPerBlock, product.maxBookingsPerBlock); + await this.clearAndType(selector.vendor.vBooking.booking.minimumBookingWindowIntoTheFutureDate, product.minimumBookingWindowIntoTheFutureDate); + await this.selectByValue(selector.vendor.vBooking.booking.minimumBookingWindowIntoTheFutureDateUnit, product.minimumBookingWindowIntoTheFutureDateUnit); + await this.clearAndType(selector.vendor.vBooking.booking.maximumBookingWindowIntoTheFutureDate, product.maximumBookingWindowIntoTheFutureDate); + await this.selectByValue(selector.vendor.vBooking.booking.maximumBookingWindowIntoTheFutureDateUnit, product.maximumBookingWindowIntoTheFutureDateUnit); + // costs + await this.clearAndType(selector.vendor.vBooking.booking.baseCost, product.baseCost); + await this.clearAndType(selector.vendor.vBooking.booking.blockCost, product.blockCost); + // todo: add more fields + } + + // vendor add booking product + async addBookingProduct(product: product['booking']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.booking); + await this.clickAndWaitForLoadState(selector.vendor.vBooking.addNewBookingProduct); + await this.updateBookingProductFields(product); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.productBooking, selector.vendor.vBooking.booking.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // edit booking product + async editBookingProduct(product: product['booking']) { + await this.searchBookingProduct(product.name); + await this.hover(selector.vendor.vBooking.productCell(product.name)); + await this.clickAndWaitForLoadState(selector.vendor.vBooking.edit(product.name)); + await this.updateBookingProductFields(product); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.booking, selector.vendor.vBooking.booking.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + } + + // view booking product + async viewBookingProduct(productName: string) { + await this.searchBookingProduct(productName); + await this.hover(selector.vendor.vBooking.productCell(productName)); + await this.clickAndWaitForLoadState(selector.vendor.vBooking.view(productName)); + + // booking product elements are visible + const { bookingCalendar, bookNow, getSupport, ...viewBooking } = selector.vendor.vBooking.viewBooking; + await this.multipleElementVisible(viewBooking); + // todo: actual value can be asserted + } + + // vendor can't buy own booking product + async cantBuyOwnBookingProduct(productName: string) { + await this.goToProductDetails(productName); + await this.notToBeVisible(selector.vendor.vBooking.viewBooking.bookingCalendar); + await this.notToBeVisible(selector.vendor.vBooking.viewBooking.bookNow); + } + + // filter products + async filterBookingProducts(filterBy: string, value: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.booking); + + switch (filterBy) { + case 'by-date': + await this.selectByNumber(selector.vendor.vBooking.filters.filterByDate, value); + break; + + case 'by-category': + await this.selectByLabel(selector.vendor.vBooking.filters.filterByCategory, value); + break; + + case 'by-other': + await this.selectByValue(selector.vendor.vBooking.filters.filterByOther, value); + break; + + default: + break; + } + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.booking, selector.vendor.vBooking.filters.filter); + await this.notToHaveCount(selector.vendor.vBooking.numberOfRowsFound, 0); + } + + // search booking product + async searchBookingProduct(productName: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.booking); + await this.clearAndType(selector.vendor.vBooking.search.searchInput, productName); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.booking, selector.vendor.vBooking.search.search); + await this.toBeVisible(selector.vendor.vBooking.productCell(productName)); + } + + // delete booking product + async duplicateBookingProduct(productName: string) { + await this.searchBookingProduct(productName); + await this.hover(selector.vendor.vBooking.productCell(productName)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.booking, selector.vendor.vBooking.duplicate(productName)); + await this.toContainText(selector.vendor.vBooking.dokanSuccessMessage, 'Product succesfully duplicated'); + } + + // delete booking product + async deleteBookingProduct(productName: string) { + await this.searchBookingProduct(productName); + await this.hover(selector.vendor.vBooking.productCell(productName)); + await this.click(selector.vendor.vBooking.permanentlyDelete(productName)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.booking, selector.vendor.vBooking.confirmDelete); + await this.toContainText(selector.vendor.vBooking.dokanSuccessMessage, 'Product successfully deleted'); + } + + // add booking resource + async addBookingResource(resourceName: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.manageResources); + + await this.clickAndWaitForLoadState(selector.vendor.vBooking.manageResources.addNewResource); + await this.clearAndType(selector.vendor.vBooking.manageResources.resource.resourceName, resourceName); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vBooking.manageResources.resource.confirmAddNewResource); + await this.toBeVisible(selector.vendor.vBooking.manageResources.resource.resourceCell(resourceName)); + } + + // add booking resource + async editBookingResource(resource: bookingResource) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.manageResources); + await this.clickAndWaitForLoadState(selector.vendor.vBooking.manageResources.resource.editResource(resource.name)); + + await this.clearAndType(selector.vendor.vBooking.manageResources.resource.resourceTitle, resource.name); + await this.clearAndType(selector.vendor.vBooking.manageResources.resource.availableQuantity, resource.quantity); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.manageResources, selector.vendor.vBooking.manageResources.resource.saveResource); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, 'Success! The Resource has been updated successfully.'); + } + + // delete booking resource + async deleteBookingResource(resourceName: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.manageResources); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vBooking.manageResources.resource.deleteResource(resourceName)); + await this.notToBeVisible(selector.vendor.vBooking.manageResources.resource.resourceCell(resourceName)); + } + + // add booking + async addBooking(productName: string, bookings: bookings, customerName?: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.addBooking); + + if (customerName) { + await this.click(selector.vendor.vBooking.addBooking.selectCustomerDropdown); + await this.typeAndWaitForResponse(data.subUrls.ajax, selector.vendor.vBooking.addBooking.selectCustomerInput, customerName); + await this.toContainText(selector.vendor.vBooking.addBooking.searchedResult, customerName); + await this.press(data.key.arrowDown); + await this.press(data.key.enter); + } + + await this.click(selector.vendor.vBooking.addBooking.selectABookableProductDropdown); + await this.click(selector.vendor.vBooking.addBooking.selectABookableProduct(productName)); + + await this.click(selector.vendor.vBooking.addBooking.createANewCorrespondingOrderForThisNewBooking); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.addBooking, selector.vendor.vBooking.addBooking.next); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cBookings.selectCalendarDay(bookings.startDate.getMonth(), bookings.startDate.getDate())); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cBookings.selectCalendarDay(bookings.endDate.getMonth(), bookings.endDate.getDate())); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.addBooking, selector.vendor.vBooking.addBooking.addBooking); + await this.toContainText(selector.vendor.vBooking.addBooking.successMessage, 'The booking has been added successfully.'); + } + + // customer + + async buyBookableProduct(productName: string, bookings: bookings) { + await this.goIfNotThere(data.subUrls.frontend.productDetails(helpers.slugify(productName))); + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cBookings.selectCalendarDay(bookings.startDate.getMonth(), bookings.startDate.getDate())); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cBookings.selectCalendarDay(bookings.endDate.getMonth(), bookings.endDate.getDate())); + await this.clickAndWaitForResponse(data.subUrls.frontend.productDetails(helpers.slugify(productName)), selector.customer.cBookings.bookNow); + await this.customerPage.placeOrder(); + } +} diff --git a/tests/pw/pages/vendorDashboardPage.ts b/tests/pw/pages/vendorDashboardPage.ts new file mode 100644 index 0000000000..0e89873b69 --- /dev/null +++ b/tests/pw/pages/vendorDashboardPage.ts @@ -0,0 +1,42 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +const { DOKAN_PRO } = process.env; + +export class VendorDashboardPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // vendor dashboard + + // vendor dashboard render properly + async vendorDashboardRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.dashboard); + + // at a glance elements are visible + await this.multipleElementVisible(selector.vendor.vDashboard.atAGlance); + + // graph elements are visible + await this.multipleElementVisible(selector.vendor.vDashboard.graph); + + // orders elements are visible + await this.multipleElementVisible(selector.vendor.vDashboard.orders); + + // products elements are visible + await this.multipleElementVisible(selector.vendor.vDashboard.products); + + if (DOKAN_PRO) { + // profile progress elements are visible + await this.multipleElementVisible(selector.vendor.vDashboard.profileProgress); + + // reviews elements are visible + await this.multipleElementVisible(selector.vendor.vDashboard.reviews); + + // announcement elements are visible + await this.multipleElementVisible(selector.vendor.vDashboard.announcement); + } + } +} diff --git a/tests/pw/pages/vendorDeliveryTimePage.ts b/tests/pw/pages/vendorDeliveryTimePage.ts new file mode 100644 index 0000000000..1af8533837 --- /dev/null +++ b/tests/pw/pages/vendorDeliveryTimePage.ts @@ -0,0 +1,133 @@ +import { Page, expect } from '@playwright/test'; +// import { VendorPage } from '@pages/vendorPage'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { vendor, deliveryTime } from '@utils/interfaces'; + +export class VendorDeliveryTimePage extends CustomerPage { + constructor(page: Page) { + super(page); + } + + // delivery time + + // vendor delivery time render properly + async vendorDeliveryTimeRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.deliveryTime); + + // delivery time and store pickup text is visible + await this.toBeVisible(selector.vendor.vDeliveryTime.deliveryTimeAndStorePickup); + + // delivery time calendar is visible + await this.toBeVisible(selector.vendor.vDeliveryTime.deliveryTimeCalender); + + // delivery time filter elements are visible + await this.multipleElementVisible(selector.vendor.vDeliveryTime.filter); + + // delivery time navigation elements are visible + await this.multipleElementVisible(selector.vendor.vDeliveryTime.navigation); + } + + // vendor delivery time settings render properly + async vendorDeliveryTimeSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsDeliveryTime); + + // settings text is visible + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.settingsText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.visitStore); + + // delivery support elements are visible + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.homeDelivery); + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.storePickup); + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.deliveryBlockedBuffer); + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.timeSlot); + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.orderPerSlot); + await this.notToHaveCount(selector.vendor.vDeliveryTimeSettings.deliveryDaySwitches, 0); + + // update settings is visible + await this.toBeVisible(selector.vendor.vDeliveryTimeSettings.updateSettings); + } + + // vendor set delivery settings + async setDeliveryTimeSettings(deliveryTime: vendor['deliveryTime']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsDeliveryTime); + // delivery support + await this.check(selector.vendor.vDeliveryTimeSettings.homeDelivery); + await this.check(selector.vendor.vDeliveryTimeSettings.storePickup); + await this.clearAndType(selector.vendor.vDeliveryTimeSettings.deliveryBlockedBuffer, deliveryTime.deliveryBlockedBuffer); + await this.clearAndType(selector.vendor.vDeliveryTimeSettings.timeSlot, deliveryTime.timeSlot); + await this.clearAndType(selector.vendor.vDeliveryTimeSettings.orderPerSlot, deliveryTime.orderPerSlot); + for (const day of deliveryTime.days) { + await this.enableSwitcherDeliveryTime(selector.vendor.vDeliveryTimeSettings.deliveryDaySwitch(day)); + if (deliveryTime.choice === 'full-day') { + await this.click(selector.vendor.vDeliveryTimeSettings.openingTime(day)); + await this.page.getByRole('listitem').filter({ hasText: 'Full day' }).click(); + } else { + await this.setAttributeValue(selector.vendor.vDeliveryTimeSettings.openingTime(day), 'value', deliveryTime.openingTime); + await this.setAttributeValue(selector.vendor.vDeliveryTimeSettings.openingTimeHiddenInput(day), 'value', deliveryTime.openingTime); + await this.setAttributeValue(selector.vendor.vDeliveryTimeSettings.closingTime(day), 'value', deliveryTime.closingTime); + await this.setAttributeValue(selector.vendor.vDeliveryTimeSettings.closingTimeHiddenInput(day), 'value', deliveryTime.closingTime); + } + } + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.settingsDeliveryTime, selector.vendor.vDeliveryTimeSettings.updateSettings, 302); + await this.toContainText(selector.vendor.vDeliveryTimeSettings.settingsSuccessMessage, deliveryTime.saveSuccessMessage); + } + + // filter delivery time + async filterDeliveryTime(value: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.deliveryTime); + await this.selectByValue(selector.vendor.vDeliveryTime.filter.deliveryTimeFilter, value); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.deliveryTime, selector.vendor.vDeliveryTime.filter.filter); + // todo: add more assertion + // todo: need order via delivery time; via api for assertion + } + + // update calender views + async updateCalendarView(value: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.deliveryTime); + + await this.click(selector.vendor.vDeliveryTime.navigation[value as keyof typeof selector.vendor.vDeliveryTime.navigation]); + const currentView = await this.getAttributeValue(selector.vendor.vDeliveryTime.navigation[value as keyof typeof selector.vendor.vDeliveryTime.navigation], 'aria-pressed'); + expect(currentView).toContain('true'); + } + + // customer + + // place order with delivery time and store pickup + async placeOrderWithDeliverTimeStorePickup(deliveryType: string, deliveryTime: deliveryTime, paymentMethod = 'bank') { + await this.goToCheckout(); + + switch (deliveryType) { + case 'delivery-time': + await this.click(selector.customer.cDeliveryTime.delivery); + await this.click(selector.customer.cDeliveryTime.deliveryTimeInput); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cDeliveryTime.deliveryDate(deliveryTime.date)); + await this.selectByNumber(selector.customer.cDeliveryTime.timePicker, 1); + break; + + case 'store-pickup': + await this.click(selector.customer.cDeliveryTime.storePickup); + await this.click(selector.customer.cDeliveryTime.deliveryTimeInput); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.customer.cDeliveryTime.deliveryDate(deliveryTime.date)); + await this.selectByNumber(selector.customer.cDeliveryTime.timePicker, 1); + await this.selectByNumber(selector.customer.cDeliveryTime.locationPicker, 1); + break; + + default: + break; + } + + await this.paymentOrder(paymentMethod); + + if (deliveryType == 'delivery-time') { + await this.toBeVisible(selector.customer.cDeliveryTime.orderDetails.deliveryTimeDetails); + await this.toContainText(selector.customer.cDeliveryTime.orderDetails.deliveryTimeTitle, 'Delivery Date'); + } else { + await this.toBeVisible(selector.customer.cDeliveryTime.orderDetails.storePickupDetails); + await this.toContainText(selector.customer.cDeliveryTime.orderDetails.storePickupTitle, 'Store location pickup'); + } + } +} diff --git a/tests/pw/pages/vendorPage.ts b/tests/pw/pages/vendorPage.ts new file mode 100644 index 0000000000..bd3e1735d9 --- /dev/null +++ b/tests/pw/pages/vendorPage.ts @@ -0,0 +1,325 @@ +import { Page, expect, test } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { LoginPage } from '@pages/loginPage'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { vendor, vendorSetupWizard } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class VendorPage extends BasePage { + constructor(page: Page) { + super(page); + } + + loginPage = new LoginPage(this.page); + customer = new CustomerPage(this.page); + + // navigation + + async goToMyAccount(): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + } + + async goToVendorDashboard(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.dashboard); + } + + async goToProductDetails(productName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.productDetails(helpers.slugify(productName))); + } + + // go to order details + async goToOrderDetails(orderNumber: string): Promise { + await this.searchOrder(orderNumber); + await this.clickAndWaitForLoadState(selector.vendor.orders.view(orderNumber)); + await this.toContainText(selector.vendor.orders.orderDetails.orderNumber, orderNumber); + } + + // go to product edit + async goToProductEdit(productName: string): Promise { + await this.searchProduct(productName); + await this.hover(selector.vendor.product.productCell(productName)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.editProduct(productName)); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + } + + // vendor registration + async vendorRegister(vendorInfo: vendor['vendorInfo'], setupWizardData: vendorSetupWizard): Promise { + const username = vendorInfo.firstName() + vendorInfo.lastName().replace("'", ''); + + await this.goToMyAccount(); + const regIsVisible = await this.isVisible(selector.customer.cRegistration.regEmail); + !regIsVisible && (await this.loginPage.logout()); + await this.clearAndType(selector.vendor.vRegistration.regEmail, username + data.vendor.vendorInfo.emailDomain); + await this.clearAndType(selector.vendor.vRegistration.regPassword, vendorInfo.password); + await this.focusAndClick(selector.vendor.vRegistration.regVendor); + await this.waitForVisibleLocator(selector.vendor.vRegistration.firstName); + await this.clearAndType(selector.vendor.vRegistration.firstName, username); + await this.clearAndType(selector.vendor.vRegistration.lastName, vendorInfo.lastName()); + await this.clearAndType(selector.vendor.vRegistration.shopName, vendorInfo.shopName()); + await this.click(selector.vendor.vRegistration.shopUrl); + + // fill address if enabled on registration + const addressInputIsVisible = await this.isVisible(selector.vendor.vRegistration.street1); + if (addressInputIsVisible) { + await this.clearAndType(selector.vendor.vRegistration.street1, vendorInfo.street1); + await this.clearAndType(selector.vendor.vRegistration.street2, vendorInfo.street2); + await this.clearAndType(selector.vendor.vRegistration.city, vendorInfo.city); + await this.clearAndType(selector.vendor.vRegistration.zipCode, vendorInfo.zipCode); + await this.selectByValue(selector.vendor.vRegistration.country, vendorInfo.countrySelectValue); + await this.selectByValue(selector.vendor.vRegistration.state, vendorInfo.stateSelectValue); + } + if (DOKAN_PRO) { + await this.clearAndType(selector.vendor.vRegistration.companyName, vendorInfo.companyName); + await this.clearAndType(selector.vendor.vRegistration.companyId, vendorInfo.companyId); + await this.clearAndType(selector.vendor.vRegistration.vatNumber, vendorInfo.vatNumber); + await this.clearAndType(selector.vendor.vRegistration.bankName, vendorInfo.bankName); + await this.clearAndType(selector.vendor.vRegistration.bankIban, vendorInfo.bankIban); + } + await this.clearAndType(selector.vendor.vRegistration.phone, vendorInfo.phoneNumber); + await this.checkIfVisible(selector.customer.cDashboard.termsAndConditions); + // await this.checkIfVisible(selector.customer.cDashboard.termsAndConditions); // todo: fix + const subscriptionPackIsVisible = await this.isVisible(selector.vendor.vRegistration.subscriptionPack); + subscriptionPackIsVisible && (await this.selectByLabel(selector.vendor.vRegistration.subscriptionPack, data.predefined.vendorSubscription.nonRecurring)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.setupWizard, selector.vendor.vRegistration.register); + const registrationErrorIsVisible = await this.isVisible(selector.customer.cWooSelector.wooCommerceError); + if (registrationErrorIsVisible) { + const hasError = await this.hasText(selector.customer.cWooSelector.wooCommerceError, data.customer.registration.registrationErrorMessage); + if (hasError) { + console.log('User already exists!!'); + return; + } + } + subscriptionPackIsVisible && (await this.customer.placeOrder('bank', false, true, false)); + await this.vendorSetupWizard(setupWizardData); + } + + // vendor setup wizard + async vendorSetupWizard(setupWizardData: vendorSetupWizard): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.setupWizard); + if (setupWizardData.choice) { + await this.click(selector.vendor.vSetup.letsGo); + await this.clearAndType(selector.vendor.vSetup.street1, setupWizardData.street1); + await this.clearAndType(selector.vendor.vSetup.street2, setupWizardData.street2); + await this.clearAndType(selector.vendor.vSetup.city, setupWizardData.city); + await this.clearAndType(selector.vendor.vSetup.zipCode, setupWizardData.zipCode); + await this.click(selector.vendor.vSetup.country); + await this.type(selector.vendor.vSetup.countryInput, setupWizardData.country); + await this.toContainText(selector.vendor.vSetup.highlightedResult, setupWizardData.country); + await this.press(data.key.enter); + await this.click(selector.vendor.vSetup.state); + await this.type(selector.vendor.vSetup.stateInput, setupWizardData.state); + await this.toContainText(selector.vendor.vSetup.highlightedResult, setupWizardData.state); + await this.press(data.key.enter); + + // store categories + const storeCategoriesEnabled = await this.isVisible(selector.vendor.vSetup.storeCategories); + if (storeCategoriesEnabled) { + const allStoreCategories = await this.getMultipleElementTexts(selector.vendor.vSetup.selectedStoreCategories); + const categoryIsSelected = allStoreCategories.includes('×' + setupWizardData.storeCategory); + if (!categoryIsSelected) { + await this.click(selector.vendor.vSetup.storeCategories); + await this.type(selector.vendor.vSetup.storeCategoriesInput, setupWizardData.storeCategory); + await this.toContainText(selector.vendor.vSetup.highlightedResult, setupWizardData.storeCategory); + await this.click(selector.vendor.vSetup.highlightedResult); + } + } + + // map + const geoLocationEnabled = await this.isVisible(selector.vendor.vSetup.map); + if (geoLocationEnabled) { + await this.typeAndWaitForResponse(data.subUrls.gmap, selector.vendor.vSetup.map, setupWizardData.mapLocation); + // await this.press(data.key.arrowDown); + // await this.press(data.key.enter); + await this.click(selector.vendor.vSetup.mapResultFirst); + } + + await this.check(selector.vendor.vSetup.email); + await this.click(selector.vendor.vSetup.continueStoreSetup); + + // payment + + // paypal + await this.clearAndType(selector.vendor.vSetup.paypal, setupWizardData.paypal()); + // bank transfer + await this.clearAndType(selector.vendor.vSetup.bankAccountName, setupWizardData.bankAccountName); + await this.selectByValue(selector.vendor.vSetup.bankAccountType, setupWizardData.bankAccountType); + await this.clearAndType(selector.vendor.vSetup.bankAccountNumber, setupWizardData.bankAccountNumber); + await this.clearAndType(selector.vendor.vSetup.bankRoutingNumber, setupWizardData.bankRoutingNumber); + await this.clearAndType(selector.vendor.vSetup.bankName, setupWizardData.bankName); + await this.clearAndType(selector.vendor.vSetup.bankAddress, setupWizardData.bankAddress); + await this.clearAndType(selector.vendor.vSetup.bankIban, setupWizardData.bankIban); + await this.clearAndType(selector.vendor.vSetup.bankSwiftCode, setupWizardData.bankSwiftCode); + await this.check(selector.vendor.vSetup.declaration); + // custom method + await this.typeIfVisible(selector.vendor.vSetup.customPayment, setupWizardData.customPayment); + // skrill + await this.typeIfVisible(selector.vendor.vSetup.skrill, setupWizardData.skrill); + await this.click(selector.vendor.vSetup.continuePaymentSetup); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.dashboard, selector.vendor.vSetup.goToStoreDashboard); + } else { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.dashboard, selector.vendor.vSetup.notRightNow); + } + await this.toBeVisible(selector.vendor.vDashboard.menus.dashboard); + } + + // vendor account details render properly + async vendorAccountDetailsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.editAccountVendor); + + const { saveSuccessMessage, ...accountDetails } = selector.vendor.vAccountDetails; + await this.multipleElementVisible(accountDetails); + } + + // vendor add vendor details + async addVendorDetails(vendor: vendor): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.editAccountVendor); + await this.clearAndType(selector.vendor.vAccountDetails.firstName, vendor.username); + await this.clearAndType(selector.vendor.vAccountDetails.lastName, vendor.lastname); + await this.clearAndType(selector.vendor.vAccountDetails.email, vendor.username + vendor.vendorInfo.emailDomain); + // await this.updatePassword(vendor.vendorInfo.password, vendor.vendorInfo.password1); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.editAccountVendor, selector.vendor.vAccountDetails.saveChanges, 302); + await expect(this.page.getByText(selector.vendor.vAccountDetails.saveSuccessMessage)).toBeVisible(); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.vendor.vendorInfo.account.updateSuccessMessage); + + // cleanup: reset password + // await this.updatePassword(vendor.vendorInfo.password1, vendor.vendorInfo.password, true); + } + + // vendor update password + async updatePassword(currentPassword: string, newPassword: string, saveChanges = false): Promise { + await this.type(selector.vendor.vAccountDetails.currentPassword, currentPassword); + await this.type(selector.vendor.vAccountDetails.NewPassword, newPassword); + await this.type(selector.vendor.vAccountDetails.confirmNewPassword, newPassword); + if (saveChanges) { + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.editAccountVendor, selector.vendor.vAccountDetails.saveChanges, 302); + await expect(this.page.getByText(selector.vendor.vAccountDetails.saveSuccessMessage)).toBeVisible(); + } + } + + // get total vendor earnings + async getTotalVendorEarning(): Promise { + await this.goToVendorDashboard(); + return helpers.price((await this.getElementText(selector.vendor.vDashboard.atAGlance.earningValue)) as string); + } + + // get order details vendor + async getOrderDetails(orderNumber: string): Promise { + await this.searchOrder(orderNumber); + + const orderDetails = { + vendorEarning: 0, + orderNumber: '', + orderTotalBeforeRefund: 0, + orderTotal: 0, + orderStatus: '', + orderDate: '', + discount: 0, + shippingMethod: '', + shippingCost: 0, + tax: 0, + refunded: 0, + }; + + orderDetails.vendorEarning = helpers.price((await this.getElementText(selector.vendor.orders.vendorEarningTable(orderNumber))) as string); + await this.clickAndWaitForLoadState(selector.vendor.orders.view(orderNumber)); + + orderDetails.orderNumber = ((await this.getElementText(selector.vendor.orders.orderDetails.orderNumber)) as string).split('#')[1] as string; + + const refundedOrderTotalIsVisible = await this.isVisible(selector.vendor.orders.orderDetails.orderTotalAfterRefund); + if (refundedOrderTotalIsVisible) { + orderDetails.orderTotalBeforeRefund = helpers.price((await this.getElementText(selector.vendor.orders.orderDetails.orderTotalBeforeRefund)) as string); + orderDetails.orderTotal = helpers.price((await this.getElementText(selector.vendor.orders.orderDetails.orderTotalAfterRefund)) as string); + } else { + orderDetails.orderTotal = helpers.price((await this.getElementText(selector.vendor.orders.orderDetails.orderTotal)) as string); + } + + orderDetails.orderStatus = ((await this.getElementText(selector.vendor.orders.status.currentOrderStatus)) as string).replace('-', ' '); + + const orderDate = ((await this.getElementText(selector.vendor.orders.orderDetails.orderDate)) as string)?.split(':')[1]?.trim() as string; + orderDetails.orderDate = orderDate?.substring(0, orderDate.indexOf(',', orderDate.indexOf(',') + 1)); + + const discountIsVisible = await this.isVisible(selector.vendor.orders.orderDetails.discount); + if (discountIsVisible) { + orderDetails.discount = helpers.price((await this.getElementText(selector.vendor.orders.orderDetails.discount)) as string); + } + + const shippingMethodIsVisible = await this.isVisible(selector.vendor.orders.orderDetails.shippingMethod); + if (shippingMethodIsVisible) { + orderDetails.shippingCost = helpers.price((await this.getElementText(selector.vendor.orders.orderDetails.shippingCost)) as string); + } + + const taxIsVisible = await this.isVisible(selector.vendor.orders.orderDetails.tax); + if (taxIsVisible) { + orderDetails.tax = helpers.price((await this.getElementText(selector.vendor.orders.orderDetails.tax)) as string); + } + + const refundIsVisible = await this.isVisible(selector.vendor.orders.orderDetails.refunded); + if (refundIsVisible) { + orderDetails.refunded = helpers.price((await this.getElementText(selector.vendor.orders.orderDetails.refunded)) as string); + } + + console.log(orderDetails); + return orderDetails; + } + + // visit store + async visitStore(storeName: string) { + 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 + 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)) + '/'); + } + + // search product vendor dashboard + async searchProduct(productName: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.products); + + await this.clearAndType(selector.vendor.product.search.searchInput, productName); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.products, selector.vendor.product.search.searchBtn); + await this.toBeVisible(selector.vendor.product.productLink(productName)); + } + + // search order + async searchOrder(orderNumber: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.orders); + + await this.clearAndType(selector.vendor.orders.search.searchInput, orderNumber); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.orders, selector.vendor.orders.search.searchBtn); + await this.toBeVisible(selector.vendor.orders.orderLink(orderNumber)); + await this.toHaveCount(selector.vendor.orders.numberOfRowsFound, 1); + } + + async buyProductAdvertising(productName: string) { + await this.searchProduct(productName); + const advertisementStatus = await this.hasColor(selector.vendor.product.advertisementStatus(productName), 'rgb(255, 99, 71)'); + if (advertisementStatus) { + console.log('Product advertisement is currently ongoing.'); + test.skip(); + // throw new Error('Product advertisement is currently ongoing.'); + } + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.product.buyAdvertisement(productName)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.product.confirmAction); + await this.click(selector.vendor.product.successMessage); + const orderId = await this.customer.paymentOrder(); + return orderId; + } + + // vendor set banner and profile picture settings + // async bannerAndProfilePictureSettings(banner: string, profilePicture: string): Promise { // todo: fix banner and profile update + // // upload banner and profile picture + // await this.removePreviouslyUploadedImage(selector.vendor.vStoreSettings.bannerImage, selector.vendor.vStoreSettings.removeBannerImage); + // await this.click(selector.vendor.vStoreSettings.banner); + // await this.wpUploadFile(banner); + + // await this.removePreviouslyUploadedImage(selector.vendor.vStoreSettings.profilePictureImage, selector.vendor.vStoreSettings.removeProfilePictureImage); + // await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vStoreSettings.profilePicture); + // await this.wpUploadFile(profilePicture); + // } +} diff --git a/tests/pw/pages/vendorProductSubscriptionPage.ts b/tests/pw/pages/vendorProductSubscriptionPage.ts new file mode 100644 index 0000000000..baf8736aef --- /dev/null +++ b/tests/pw/pages/vendorProductSubscriptionPage.ts @@ -0,0 +1,125 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { customer } from '@utils/interfaces'; + +export class VendorProductSubscriptionPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + customerPage = new CustomerPage(this.page); + + // product subscription + + // vendor return request render properly + async vendorUserSubscriptionsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.userSubscriptions); + + // filter + const { filterByCustomerInput, result, ...filters } = selector.vendor.vUserSubscriptions.filters; + await this.multipleElementVisible(filters); + + const noSubscriptionsFound = await this.isVisible(selector.vendor.vUserSubscriptions.noSubscriptionsFound); + if (noSubscriptionsFound) { + return; + } + } + + // vendor view product subscription + async viewProductSubscription(value: string) { + // todo: go to subscription details via link , get subscription id via api + // todo: + } + + // filter product subscriptions + async filterProductSubscriptions(filterBy: string, inputValue: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.userSubscriptions); + + switch (filterBy) { + case 'by-customer': + await this.click(selector.vendor.vUserSubscriptions.filters.filterByCustomer); + await this.typeAndWaitForResponse(data.subUrls.ajax, selector.vendor.vUserSubscriptions.filters.filterByCustomerInput, inputValue); + await this.toContainText(selector.vendor.vUserSubscriptions.filters.result, inputValue); + await this.press(data.key.enter); + break; + + case 'by-date': + await this.setAttributeValue(selector.vendor.vUserSubscriptions.filters.filterByDate, 'value', inputValue); + break; + + default: + break; + } + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.userSubscriptions, selector.vendor.vUserSubscriptions.filters.filter); + await this.notToHaveCount(selector.vendor.vUserSubscriptions.numberOfRowsFound, 0); + } + + // customer + + // cancel product subscription + async customerViewProductSubscription(subscriptionId: string) { + await this.goIfNotThere(data.subUrls.frontend.productSubscriptionDetails(subscriptionId)); + + // subscription heading is visible + await this.toBeVisible(selector.customer.cSubscription.subscriptionDetails.subscriptionHeading); + + // subscription action elements are visible + const { reActivate, ...actions } = selector.customer.cSubscription.subscriptionDetails.actions; + await this.multipleElementVisible(actions); + // todo: add more fields + } + + // cancel product subscription + async cancelProductSubscription(subscriptionId: string) { + await this.goIfNotThere(data.subUrls.frontend.productSubscriptionDetails(subscriptionId)); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.productSubscriptionDetails(subscriptionId), selector.customer.cSubscription.subscriptionDetails.actions.cancel, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'Your subscription has been cancelled.'); + } + + // reactivate product subscription + async reactivateProductSubscription(subscriptionId: string) { + await this.goIfNotThere(data.subUrls.frontend.productSubscriptionDetails(subscriptionId)); + const subscriptionIsActive = await this.isVisible(selector.customer.cSubscription.subscriptionDetails.actions.cancel); + subscriptionIsActive && (await this.cancelProductSubscription(subscriptionId)); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.productSubscriptionDetails(subscriptionId), selector.customer.cSubscription.subscriptionDetails.actions.reActivate, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'Your subscription has been reactivated.'); + } + + // change address of product subscription + async changeAddressOfProductSubscription(subscriptionId: string, shippingInfo: customer['customerInfo']['shipping']) { + await this.goIfNotThere(data.subUrls.frontend.productSubscriptionDetails(subscriptionId)); + + await this.clickAndWaitForLoadState(selector.customer.cSubscription.subscriptionDetails.actions.changeAddress); + await this.customerPage.updateShippingFields(shippingInfo); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.shippingAddress, selector.customer.cAddress.shipping.shippingSaveAddress, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.customer.address.addressChangeSuccessMessage); + } + + // change payment of product subscription + async changePaymentOfProductSubscription(subscriptionId: string) { + await this.goIfNotThere(data.subUrls.frontend.productSubscriptionDetails(subscriptionId)); + await this.clickAndWaitForLoadState(selector.customer.cSubscription.subscriptionDetails.actions.changePayment); + // todo: change to new card + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.productSubscriptionDetails(subscriptionId), selector.customer.cSubscription.subscriptionDetails.changePaymentMethod); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'Payment method updated.'); + } + + // renew product subscription + async renewProductSubscription(subscriptionId: string) { + await this.goIfNotThere(data.subUrls.frontend.productSubscriptionDetails(subscriptionId)); + await this.clickAndWaitForLoadState(selector.customer.cSubscription.subscriptionDetails.actions.renewNow); + await this.customerPage.paymentOrder('stripe'); + } + + // buy product subscription + async buyProductSubscription(productName: string) { + await this.customerPage.addProductToCart(productName, 'single-product'); + await this.customerPage.placeOrder('stripe'); + } +} diff --git a/tests/pw/pages/vendorReportsPage.ts b/tests/pw/pages/vendorReportsPage.ts new file mode 100644 index 0000000000..eece465c1b --- /dev/null +++ b/tests/pw/pages/vendorReportsPage.ts @@ -0,0 +1,67 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class VendorReportsPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // vendor reports + + // vendor reports render properly + async vendorReportsRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.reports); + + // reports text is visible + await this.toBeVisible(selector.vendor.vReports.reportsText); + + // reports menu elements are visible + await this.multipleElementVisible(selector.vendor.vReports.menus); + + // chart elements are visible + await this.multipleElementVisible(selector.vendor.vReports.chart); + + await this.clickAndWaitForLoadState(selector.vendor.vReports.menus.salesByDay); + + // date picker elements are visible + await this.multipleElementVisible(selector.vendor.vReports.datePicker); + // chart elements are visible + await this.multipleElementVisible(selector.vendor.vReports.chart); + + await this.clickAndWaitForLoadState(selector.vendor.vReports.menus.topSelling); + + // date picker elements are visible + await this.multipleElementVisible(selector.vendor.vReports.datePicker); + + // top selling table elements are visible + await this.multipleElementVisible(selector.vendor.vReports.topSelling.table); + + await this.clickAndWaitForLoadState(selector.vendor.vReports.menus.topEarning); + + // date picker elements are visible + await this.multipleElementVisible(selector.vendor.vReports.datePicker); + + // top earning table elements are visible + await this.multipleElementVisible(selector.vendor.vReports.topEarning.table); + + await this.clickAndWaitForLoadState(selector.vendor.vReports.menus.statement); + + // date picker elements are visible + await this.multipleElementVisible(selector.vendor.vReports.datePicker); + + // statement table elements are visible + await this.multipleElementVisible(selector.vendor.vReports.statement.table); + + // export statements button is visible + await this.toBeVisible(selector.vendor.vReports.statement.exportStatements); + } + + // vendor export statement + async exportStatement(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.statement); + const isDisabled = await this.hasAttribute(selector.vendor.vReports.statement.exportStatements, 'disabled'); + !isDisabled && (await this.clickAndWaitForDownload(selector.vendor.vReports.statement.exportStatements)); + } +} diff --git a/tests/pw/pages/vendorReturnRequestPage.ts b/tests/pw/pages/vendorReturnRequestPage.ts new file mode 100644 index 0000000000..7934595c05 --- /dev/null +++ b/tests/pw/pages/vendorReturnRequestPage.ts @@ -0,0 +1,144 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { order } from '@utils/interfaces'; +import { helpers } from '@utils/helpers'; + +export class VendorReturnRequestPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // return request + + // vendor return request render properly + async vendorReturnRequestRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.returnRequest); + + // return request menu elements are visible + await this.toBeVisible(selector.vendor.vReturnRequest.menus.all); + + // return request table elements are visible + await this.multipleElementVisible(selector.vendor.vReturnRequest.table); + + const noRequestsFound = await this.isVisible(selector.vendor.vReturnRequest.noRowsFound); + if (noRequestsFound) { + return; + } + + await this.notToHaveCount(selector.vendor.vReturnRequest.numberOfRowsFound, 0); + } + + // vendor view rma details + async vendorViewRmaDetails(orderNumber: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.returnRequest); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.returnRequest, selector.vendor.vReturnRequest.view(orderNumber)); + + // back to list is visible + await this.toBeVisible(selector.vendor.vReturnRequest.returnRequestDetails.backToList); + + // basic details elements are visible + await this.multipleElementVisible(selector.vendor.vReturnRequest.returnRequestDetails.basicDetails); + + // additional details elements are visible + await this.multipleElementVisible(selector.vendor.vReturnRequest.returnRequestDetails.additionalDetails); + + // status elements are visible + const { sendRefund, ...status } = selector.vendor.vReturnRequest.returnRequestDetails.status; + await this.multipleElementVisible(status); + + // conversations elements are visible + await this.multipleElementVisible(selector.vendor.vReturnRequest.returnRequestDetails.conversations); + } + + // vendor send rma message + async vendorSendRmaMessage(orderNumber: string, message: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.returnRequest); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.returnRequest, selector.vendor.vReturnRequest.view(orderNumber)); + await this.clearAndType(selector.vendor.vReturnRequest.returnRequestDetails.conversations.message, message); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.returnRequest, selector.vendor.vReturnRequest.returnRequestDetails.conversations.sendMessage, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.customer.rma.sendMessage); + } + + // vendor update rma status + async vendorUpdateRmaStatus(orderNumber: string, status: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.returnRequest); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.returnRequest, selector.vendor.vReturnRequest.view(orderNumber)); + await this.selectByValue(selector.vendor.vReturnRequest.returnRequestDetails.status.changeStatus, status); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReturnRequest.returnRequestDetails.status.update); + } + + // vendor send rma refund + async vendorRmaRefund(orderNumber: string, productName: string, status: string) { + // await this.goIfNotThere(data.subUrls.frontend.vDashboard.returnRequest); // todo: + await this.goto(data.subUrls.frontend.vDashboard.returnRequest); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.returnRequest, selector.vendor.vReturnRequest.view(orderNumber)); + const sendRefundIsVisible = await this.isVisible(selector.vendor.vReturnRequest.returnRequestDetails.status.sendRefund); + !sendRefundIsVisible && (await this.vendorUpdateRmaStatus(orderNumber, status)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vReturnRequest.returnRequestDetails.status.sendRefund); + const taxIsVisible = await this.isVisible(selector.vendor.vReturnRequest.returnRequestDetails.modal.taxRefundColumn); + if (taxIsVisible) { + const tax = (await this.getElementText(selector.vendor.vReturnRequest.returnRequestDetails.modal.taxAmount(productName))) as string; + await this.type(selector.vendor.vReturnRequest.returnRequestDetails.modal.taxRefund(productName), helpers.removeCurrencySign(tax)); + } + const subtotal = (await this.getElementText(selector.vendor.vReturnRequest.returnRequestDetails.modal.subTotal(productName))) as string; + await this.type(selector.vendor.vReturnRequest.returnRequestDetails.modal.subTotalRefund(productName), helpers.removeCurrencySign(subtotal)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vReturnRequest.returnRequestDetails.modal.sendRequest); + await this.toContainText(selector.vendor.vReturnRequest.returnRequestDetails.modal.sendRequestSuccessMessage, 'Already send refund request. Wait for admin approval'); + } + + // vendor delete rma request + async vendorDeleteRmaRequest(orderNumber: string) { + // await this.goIfNotThere(data.subUrls.frontend.vDashboard.returnRequest); // todo: + await this.goto(data.subUrls.frontend.vDashboard.returnRequest); + await this.hover(selector.vendor.vReturnRequest.returnRequestCell(orderNumber)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.returnRequest, selector.vendor.vReturnRequest.delete(orderNumber)); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'Return Request has been deleted successfully'); + } + + // customer + + // customer return request render properly + async customerReturnRequestRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.rmaRequests); + + // allRequestText is visible + await this.toBeVisible(selector.customer.cRma.allRequestText); + + // return request table elements are visible + await this.multipleElementVisible(selector.customer.cRma.table); + + const noRequestsFound = await this.isVisible(selector.customer.cRma.noRowsFound); + if (noRequestsFound) { + console.log('No request found'); + return; + } + + await this.notToHaveCount(selector.customer.cRma.numberOfRowsFound, 0); + } + + // customer request warranty + async customerRequestWarranty(orderNumber: string, productName: string, refund: order['requestWarranty']) { + await this.goIfNotThere(data.subUrls.frontend.myOrders); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.requestWarranty, selector.customer.cMyOrders.orderRequestWarranty(orderNumber)); + + await this.click(selector.customer.cOrders.requestWarranty.warrantyRequestItemCheckbox(productName)); + await this.selectByValue(selector.customer.cOrders.requestWarranty.warrantyRequestItemQuantity(productName), refund.itemQuantity); + await this.selectByValue(selector.customer.cOrders.requestWarranty.warrantyRequestType, refund.refundRequestType); + const refundReasonIsVisible = await this.isVisible(selector.customer.cOrders.requestWarranty.warrantyRequestReason); + refundReasonIsVisible && (await this.selectByValue(selector.customer.cOrders.requestWarranty.warrantyRequestReason, refund.refundRequestReasons)); + await this.clearAndType(selector.customer.cOrders.requestWarranty.warrantyRequestDetails, refund.refundRequestDetails); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.requestWarranty, selector.customer.cOrders.requestWarranty.warrantySubmitRequest, 302); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, refund.refundSubmitSuccessMessage); + } + + // customer send Rma message + async customerSendRmaMessage(orderNumber: string, message: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.rmaRequests); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.viewRmaRequests, selector.customer.cRma.view(orderNumber)); + await this.clearAndType(selector.customer.cRma.message, message); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.viewRmaRequests, selector.customer.cRma.sendMessage); + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.customer.rma.sendMessage); + } +} diff --git a/tests/pw/pages/vendorSettingsPage.ts b/tests/pw/pages/vendorSettingsPage.ts new file mode 100644 index 0000000000..e92f9e2f40 --- /dev/null +++ b/tests/pw/pages/vendorSettingsPage.ts @@ -0,0 +1,483 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { vendor } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class VendorSettingsPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // vendor settings + + // vendor settings render properly + async vendorStoreSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsStore); + + // settings text is visible + await this.toBeVisible(selector.vendor.vStoreSettings.settingsText); + + // todo: update for lite + + // visit store link is visible + await this.toBeVisible(selector.vendor.vStoreSettings.banner); + await this.toBeVisible(selector.vendor.vStoreSettings.profilePicture); + await this.toBeVisible(selector.vendor.vStoreSettings.storeName); + await this.toBeVisible(selector.vendor.vStoreSettings.phoneNo); + DOKAN_PRO && (await this.toBeVisible(selector.vendor.vStoreSettings.multipleLocation)); + + // store address location elements are visible + const { saveLocation, cancelSaveLocation, deleteSaveLocation, ...address } = selector.vendor.vStoreSettings.address; + await this.multipleElementVisible(address); + DOKAN_PRO && (await this.toBeVisible(saveLocation)); + + // company info elements are visible + DOKAN_PRO && (await this.multipleElementVisible(selector.vendor.vStoreSettings.companyInfo)); + + await this.toBeVisible(selector.vendor.vStoreSettings.email); + + // map is visible + // await this.toBeVisible(selector.vendor.vStoreSettings.map); //todo: gmap not reading from env + + // todo: catalog, discount, vacation, open close, store category + + // biography is visible + DOKAN_PRO && (await this.toBeVisible(selector.vendor.vStoreSettings.biographyIframe)); + + // todo: min-max, store-support + + // update settings are visible + await this.toBeVisible(selector.vendor.vStoreSettings.updateSettingsTop); + await this.toBeVisible(selector.vendor.vStoreSettings.updateSettings); + } + + // vendor shipstation render properly + async vendorShipstationSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipstation); + + // shipstation text is visible + await this.toBeVisible(selector.vendor.vShipStationSettings.shipStationText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vShipStationSettings.visitStore); + + // authentication key is visible + await this.toBeVisible(selector.vendor.vShipStationSettings.authenticationKey); + + // export order statuses is visible + await this.toBeVisible(selector.vendor.vShipStationSettings.exportOrderStatusesInput); + + // Shipped Order Status is visible + await this.toBeVisible(selector.vendor.vShipStationSettings.shippedOrderStatusDropdown); + + // save changes is visible + await this.toBeVisible(selector.vendor.vShipStationSettings.saveChanges); + } + + // vendor social profile render properly + async vendorSocialProfileSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsSocialProfile); + + // social profile text is visible + await this.toBeVisible(selector.vendor.vSocialProfileSettings.socialProfileText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vSocialProfileSettings.visitStore); + + // social platform elements are visible + await this.multipleElementVisible(selector.vendor.vSocialProfileSettings.platforms); + + // update settings is visible + await this.toBeVisible(selector.vendor.vSocialProfileSettings.updateSettings); + } + + // vendor rma render properly + async vendorRmaSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsRma); + + // return and warranty text is visible + await this.toBeVisible(selector.vendor.vRmaSettings.returnAndWarrantyText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vRmaSettings.visitStore); + + // rma label input is visible + await this.toBeVisible(selector.vendor.vRmaSettings.label); + + // rma type input is visible + await this.toBeVisible(selector.vendor.vRmaSettings.type); + + // rma policy input is visible + await this.toBeVisible(selector.vendor.vRmaSettings.refundPolicyIframe); + + // save changes is visible + await this.toBeVisible(selector.vendor.vRmaSettings.saveChanges); + } + + // vendor store seo render properly + async vendorStoreSeoSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsSeo); + + // store seo text is visible + await this.toBeVisible(selector.vendor.vStoreSeoSettings.storeSeoText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vStoreSeoSettings.visitStore); + + // seo title is visible + await this.toBeVisible(selector.vendor.vStoreSeoSettings.seoTitle); + + // meta description is visible + await this.toBeVisible(selector.vendor.vStoreSeoSettings.metaDescription); + + // meta keywords is visible + await this.toBeVisible(selector.vendor.vStoreSeoSettings.metaKeywords); + + // store seo facebook elements are visible + await this.multipleElementVisible(selector.vendor.vStoreSeoSettings.facebook); + + // store seo twitter elements are visible + await this.multipleElementVisible(selector.vendor.vStoreSeoSettings.twitter); + + // save changes is visible + await this.toBeVisible(selector.vendor.vStoreSeoSettings.saveChanges); + } + + // store settings + + // update store map via settings save + async updateStoreMapViaSettingsSave() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsStore); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vStoreSettings.updateSettings); + await this.toContainText(selector.vendor.vStoreSettings.updateSettingsSuccessMessage, 'Your information has been saved successfully'); + } + + // vendor set store settings + async setStoreSettings(vendorInfo: vendor['vendorInfo'], topic: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsStore); + + switch (topic) { + case 'banner-profile': + // await this.bannerAndProfilePictureSettings(); // todo: + break; + + case 'basic': + await this.basicInfoSettings(vendorInfo); + break; + + case 'address': + await this.setStoreAddress(vendorInfo); + break; + + case 'company-info': + await this.setCompanyInfo(vendorInfo); + break; + + case 'map': + await this.mapSettings(vendorInfo.mapLocation); + break; + + case 'toc': + await this.termsAndConditionsSettings(vendorInfo.termsAndConditions); + break; + + case 'open-close': + await this.openingClosingTimeSettings(vendorInfo.openingClosingTime); + break; + + case 'vacation': + await this.vacationSettings(vendorInfo.vacation); + break; + + case 'catalog': + await this.catalogModeSettings(); + break; + + case 'discount': + await this.discountSettings(vendorInfo.amountDiscount); + break; + + case 'biography': + await this.biographySettings(vendorInfo.biography); + break; + + case 'store-support': + await this.storeSupportSettings(vendorInfo.supportButtonText); + break; + + case 'min-max': + await this.minMaxSettings(vendorInfo.minMax); + break; + + default: + break; + } + + // update settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vStoreSettings.updateSettings); + await this.toContainText(selector.vendor.vStoreSettings.updateSettingsSuccessMessage, data.vendor.vendorInfo.storeSettingsSaveSuccessMessage); + } + + // vendor set basic info settings + async basicInfoSettings(vendorInfo: vendor['vendorInfo']): Promise { + // store basic info + await this.clearAndType(selector.vendor.vStoreSettings.storeName, vendorInfo.storeName); + await this.clearAndType(selector.vendor.vStoreSettings.phoneNo, vendorInfo.phoneNumber); + // email + await this.check(selector.vendor.vStoreSettings.email); + } + + // vendor set store address + async setStoreAddress(vendorInfo: vendor['vendorInfo']): Promise { + await this.clearAndType(selector.vendor.vStoreSettings.address.street, vendorInfo.street1); + await this.clearAndType(selector.vendor.vStoreSettings.address.street2, vendorInfo.street2); + await this.clearAndType(selector.vendor.vStoreSettings.address.city, vendorInfo.city); + await this.clearAndType(selector.vendor.vStoreSettings.address.postOrZipCode, vendorInfo.zipCode); + await this.selectByValue(selector.vendor.vStoreSettings.address.country, vendorInfo.countrySelectValue); + await this.selectByValue(selector.vendor.vStoreSettings.address.state, vendorInfo.stateSelectValue); + } + + // vendor set company info + async setCompanyInfo(vendorInfo: vendor['vendorInfo']): Promise { + await this.clearAndType(selector.vendor.vStoreSettings.companyInfo.companyName, vendorInfo.companyName); + await this.clearAndType(selector.vendor.vStoreSettings.companyInfo.companyId, vendorInfo.companyId); + await this.clearAndType(selector.vendor.vStoreSettings.companyInfo.vatOrTaxNumber, vendorInfo.vatNumber); + await this.clearAndType(selector.vendor.vStoreSettings.companyInfo.nameOfBank, vendorInfo.bankName); + await this.clearAndType(selector.vendor.vStoreSettings.companyInfo.bankIban, vendorInfo.bankIban); + } + + // vendor set map settings + async mapSettings(mapLocation: string): Promise { + const geoLocationEnabled = await this.isVisible(selector.vendor.vStoreSettings.map); + if (geoLocationEnabled) { + await this.typeAndWaitForResponse(data.subUrls.gmap, selector.vendor.vStoreSettings.map, mapLocation); + await this.press(data.key.arrowDown); + await this.press(data.key.enter); + } + } + + // vendor set terms and conditions settings + async termsAndConditionsSettings(termsAndConditions: string): Promise { + const tocEnabled = await this.isVisible(selector.vendor.vStoreSettings.termsAndConditions); + if (tocEnabled) { + await this.check(selector.vendor.vStoreSettings.termsAndConditions); + await this.typeFrameSelector(selector.vendor.vStoreSettings.termsAndConditionsIframe, selector.vendor.vStoreSettings.termsAndConditionsHtmlBody, termsAndConditions); + } + } + + // vendor set opening closing time settings + async openingClosingTimeSettings(openingClosingTime: vendor['vendorInfo']['openingClosingTime']): Promise { + const openCloseTimeEnabled = await this.isVisible(selector.vendor.vStoreSettings.storeOpeningClosingTime); + if (openCloseTimeEnabled) { + await this.check(selector.vendor.vStoreSettings.storeOpeningClosingTime); + for (const day of openingClosingTime.days) { + if (DOKAN_PRO) { + await this.enableSwitcherDeliveryTime(selector.vendor.vStoreSettings.openingClosingTimeSwitch(day)); + await this.setAttributeValue(selector.vendor.vStoreSettings.openingTime(day), 'value', openingClosingTime.openingTime); + await this.setAttributeValue(selector.vendor.vStoreSettings.openingTimeHiddenInput(day), 'value', openingClosingTime.openingTime); + await this.setAttributeValue(selector.vendor.vStoreSettings.closingTime(day), 'value', openingClosingTime.closingTime); + await this.setAttributeValue(selector.vendor.vStoreSettings.closingTimeHiddenInput(day), 'value', openingClosingTime.closingTime); + } else { + // lite + await this.selectByValue(selector.vendor.vStoreSettings.lite.openingClosingTimeEnable(day), openingClosingTime.statusLite); + await this.clearAndType(selector.vendor.vStoreSettings.lite.openingTimeInput(day), openingClosingTime.openingTime); + await this.clearAndType(selector.vendor.vStoreSettings.lite.closingTimeInput(day), openingClosingTime.closingTime); + } + } + await this.clearAndType(selector.vendor.vStoreSettings.storeOpenNotice, openingClosingTime.storeOpenNotice); + await this.clearAndType(selector.vendor.vStoreSettings.storeCloseNotice, openingClosingTime.storeCloseNotice); + } + } + + // vendor set vacation settings + async vacationSettings(vacation: vendor['vendorInfo']['vacation']): Promise { + const vacationModeEnabled = await this.isVisible(selector.vendor.vStoreSettings.goToVacation); + if (vacationModeEnabled) { + await this.check(selector.vendor.vStoreSettings.goToVacation); + await this.selectByValue(selector.vendor.vStoreSettings.closingStyle, vacation.closingStyle); + + switch (vacation.closingStyle) { + // instantly close + case 'instantly': + await this.clearAndType(selector.vendor.vStoreSettings.setVacationMessageInstantly, vacation.instantly.vacationMessage); + break; + + // datewise close + case 'datewise': { + const vacationDayFrom = vacation.datewise.vacationDayFrom(); + const vacationDayTo = vacation.datewise.vacationDayTo(vacationDayFrom); + await this.setAttributeValue(selector.vendor.vStoreSettings.vacationDateRange, 'value', helpers.dateFormatFYJ(vacationDayFrom) + ' - ' + helpers.dateFormatFYJ(vacationDayTo)); + await this.setAttributeValue(selector.vendor.vStoreSettings.vacationDateRangeFrom, 'value', vacationDayFrom); + await this.setAttributeValue(selector.vendor.vStoreSettings.vacationDateRangeTo, 'value', vacationDayTo); + await this.clearAndType(selector.vendor.vStoreSettings.setVacationMessageDatewise, vacation.datewise.vacationMessage); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vStoreSettings.saveVacationEdit); + break; + } + + default: + break; + } + } + } + + // vendor delete pervious datewise vacation settings if any + async deletePreviousDatewiseVacation() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsStore); + const noVacationIsSetIsVisible = await this.isVisible(selector.vendor.vStoreSettings.noVacationIsSet); + if (!noVacationIsSetIsVisible) { + await this.hover(selector.vendor.vStoreSettings.vacationRow); + await this.click(selector.vendor.vStoreSettings.deleteSavedVacationSchedule); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vStoreSettings.confirmDeleteSavedVacationSchedule); + } + + // update settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vStoreSettings.updateSettings); + await this.toContainText(selector.vendor.vStoreSettings.updateSettingsSuccessMessage, data.vendor.vendorInfo.storeSettingsSaveSuccessMessage); + } + + // vendor set catalog mode settings + async catalogModeSettings(): Promise { + const catalogModeEnabled = await this.isVisible(selector.vendor.vStoreSettings.removeAddToCartButton); + if (catalogModeEnabled) { + await this.check(selector.vendor.vStoreSettings.removeAddToCartButton); + await this.check(selector.vendor.vStoreSettings.hideProductPrice); + await this.checkIfVisible(selector.vendor.vStoreSettings.enableRequestQuoteSupport); + } + } + + // reset catalog + async resetCatalog(): Promise { + await this.uncheck(selector.vendor.vStoreSettings.removeAddToCartButton); + // update settings + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vStoreSettings.updateSettings); + await this.toContainText(selector.vendor.vStoreSettings.updateSettingsSuccessMessage, data.vendor.vendorInfo.storeSettingsSaveSuccessMessage); + } + + // vendor set discount settings + async discountSettings(amountDiscount: vendor['vendorInfo']['amountDiscount']): Promise { + const discountEnabled = await this.isVisible(selector.vendor.vStoreSettings.enableStoreWideDiscount); + if (discountEnabled) { + await this.check(selector.vendor.vStoreSettings.enableStoreWideDiscount); + await this.clearAndType(selector.vendor.vStoreSettings.minimumOrderAmount, amountDiscount.minimumOrderAmount); + await this.clearAndType(selector.vendor.vStoreSettings.percentage, amountDiscount.discountPercentage); + } + } + + // vendor set biography settings + async biographySettings(biography: string): Promise { + await this.typeFrameSelector(selector.vendor.vStoreSettings.biographyIframe, selector.vendor.vStoreSettings.biographyHtmlBody, biography); + } + + // vendor set store support settings + async storeSupportSettings(supportButtonText: string): Promise { + const storeSupportEnabled = await this.isVisible(selector.vendor.vStoreSettings.removeAddToCartButton); + if (storeSupportEnabled) { + await this.check(selector.vendor.vStoreSettings.showSupportButtonInStore); + await this.check(selector.vendor.vStoreSettings.showSupportButtonInSingleProduct); + await this.clearAndType(selector.vendor.vStoreSettings.supportButtonText, supportButtonText); + } + } + + // vendor set minmax settings + async minMaxSettings(minMax: vendor['vendorInfo']['minMax']): Promise { + const minMaxEnabled = await this.isVisible(selector.vendor.vStoreSettings.enableMinMaxQuantities); + if (minMaxEnabled) { + // min max quantities + await this.check(selector.vendor.vStoreSettings.enableMinMaxQuantities); + await this.clearAndType(selector.vendor.vStoreSettings.minimumProductQuantityToPlaceAnOrder, minMax.minimumProductQuantity); + await this.clearAndType(selector.vendor.vStoreSettings.maximumProductQuantityToPlaceAnOrder, minMax.maximumProductQuantity); + + // min max amount + await this.check(selector.vendor.vStoreSettings.enableMinMaxAmount); + await this.clearAndType(selector.vendor.vStoreSettings.minimumAmountToPlaceAnOrder, minMax.minimumAmount); + await this.clearAndType(selector.vendor.vStoreSettings.maximumAmountToPlaceAnOrder, minMax.maximumAmount); + await this.click(selector.vendor.vStoreSettings.clear); + await this.click(selector.vendor.vStoreSettings.selectAll); + const multipleCategory = await this.isVisible(selector.vendor.vStoreSettings.selectCategorySearch); + if (multipleCategory) { + await this.select2ByTextMultiSelector(selector.vendor.vStoreSettings.selectCategorySearch, selector.vendor.vStoreSettings.selectCategorySearchedResult, minMax.category); + } else { + await this.selectByLabel(selector.vendor.vStoreSettings.selectCategory, minMax.category); + } + } + } + + // vendor set shipstation settings + async setShipStation(shipStation: vendor['shipStation']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipstation); + + const allStatus = await this.getMultipleElementTexts(selector.vendor.vShipStationSettings.selectedStatus); + const statusIsSelected = allStatus.includes('×' + shipStation.status); + if (!statusIsSelected) { + await this.clearAndType(selector.vendor.vShipStationSettings.exportOrderStatusesInput, shipStation.status); + await this.toContainText(selector.vendor.vShipStationSettings.result, shipStation.status); + await this.press(data.key.enter); + } + + // await this.click(selector.vendor.vShipStationSettings.shippedOrderStatusDropdown); + // await this.clearAndType(selector.vendor.vShipStationSettings.shippedOrderStatusInput, shipStation.status);// todo: need to fix -> locator issue + // await this.toContainText(selector.vendor.vShipStationSettings.result, shipStation.status); + // await this.press(data.key.enter); + + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.vendor.vShipStationSettings.saveChanges); + await this.toContainText(selector.vendor.vShipStationSettings.saveSuccessMessage, 'Your changes has been updated!'); + await this.click(selector.vendor.vShipStationSettings.successOk); + } + + // vendor set social profile settings + async setSocialProfile(urls: vendor['socialProfileUrls']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsSocialProfile); + await this.clearAndType(selector.vendor.vSocialProfileSettings.platforms.facebook, urls.facebook); + await this.clearAndType(selector.vendor.vSocialProfileSettings.platforms.twitter, urls.twitter); + await this.clearAndType(selector.vendor.vSocialProfileSettings.platforms.pinterest, urls.pinterest); + await this.clearAndType(selector.vendor.vSocialProfileSettings.platforms.linkedin, urls.linkedin); + await this.clearAndType(selector.vendor.vSocialProfileSettings.platforms.youtube, urls.youtube); + await this.clearAndType(selector.vendor.vSocialProfileSettings.platforms.instagram, urls.instagram); + await this.clearAndType(selector.vendor.vSocialProfileSettings.platforms.flickr, urls.flickr); + await this.keyPressOnLocator(selector.vendor.vSocialProfileSettings.updateSettings, data.key.enter); + await this.toContainText(selector.vendor.vSocialProfileSettings.updateSettingsSuccessMessage, urls.saveSuccessMessage); + } + + // vendor set rma settings + async setRmaSettings(rma: vendor['rma']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsRma); + await this.clearAndType(selector.vendor.vRmaSettings.label, rma.label); + await this.selectByValue(selector.vendor.vRmaSettings.type, rma.type); + await this.selectByValue(selector.vendor.vRmaSettings.length, rma.rmaLength); + // todo: add addon + if (rma.rmaLength === 'limited') { + await this.clearAndType(selector.vendor.vRmaSettings.lengthValue, rma.lengthValue); + await this.selectByValue(selector.vendor.vRmaSettings.lengthDuration, rma.lengthDuration); + } + // check if refund reason exists + const refundReasonIsVisible = await this.isVisible(selector.vendor.vRmaSettings.refundReasonsFirst); + if (refundReasonIsVisible) { + await this.checkMultiple(selector.vendor.vRmaSettings.refundReasons); + } + await this.typeFrameSelector(selector.vendor.vRmaSettings.refundPolicyIframe, selector.vendor.vRmaSettings.refundPolicyHtmlBody, rma.refundPolicyHtmlBody); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.settingsRma, selector.vendor.vRmaSettings.saveChanges, 302); + await this.toContainText(selector.vendor.vRmaSettings.updateSettingsSuccessMessage, rma.saveSuccessMessage); + } + + // vendor set seo settings + async setStoreSeo(seo: vendor['seo']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsSeo); + + await this.clearAndType(selector.vendor.vStoreSeoSettings.seoTitle, seo.seoTitle); + await this.clearAndType(selector.vendor.vStoreSeoSettings.metaDescription, seo.metaDescription); + await this.clearAndType(selector.vendor.vStoreSeoSettings.metaKeywords, seo.metaKeywords); + + await this.clearAndType(selector.vendor.vStoreSeoSettings.facebook.facebookTitle, seo.facebookTitle); + await this.clearAndType(selector.vendor.vStoreSeoSettings.facebook.facebookDescription, seo.facebookDescription); + + await this.clearAndType(selector.vendor.vStoreSeoSettings.twitter.twitterTitle, seo.twitterTitle); + await this.clearAndType(selector.vendor.vStoreSeoSettings.twitter.twitterDescription, seo.twitterDescription); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vStoreSeoSettings.saveChanges); + await this.toContainText(selector.vendor.vStoreSeoSettings.updateSettingsSuccessMessage, 'Your changes has been updated!'); + } +} diff --git a/tests/pw/pages/vendorShippingPage.ts b/tests/pw/pages/vendorShippingPage.ts new file mode 100644 index 0000000000..1d74080fed --- /dev/null +++ b/tests/pw/pages/vendorShippingPage.ts @@ -0,0 +1,187 @@ +import { Page, expect } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { vendor, shipping } from '@utils/interfaces'; + +export class VendorShippingPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // vendor shipping settings + + // vendor shipping render properly + async vendorShippingSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipping); + + // shipstation text is visible + await this.toBeVisible(selector.vendor.vShippingSettings.shippingSettingsText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vShippingSettings.visitStore); + + // add shipping policies is visible + await this.toBeVisible(selector.vendor.vShippingSettings.shippingPolicies.clickHereToAddShippingPolicies); + + // previous shipping settings link is visible + await this.toBeVisible(selector.vendor.vShippingSettings.shippingPolicies.clickHereToAddShippingPolicies); + + // shipping zone table elements are visible + await this.multipleElementVisible(selector.vendor.vShippingSettings.table); + + await this.clickAndWaitForLoadState(selector.vendor.vShippingSettings.shippingPolicies.clickHereToAddShippingPolicies); + + // shipping policy elements are visible + const { clickHereToAddShippingPolicies, ...companyVerifications } = selector.vendor.vShippingSettings.shippingPolicies; + await this.multipleElementVisible(companyVerifications); + + await this.clickAndWaitForLoadState(selector.vendor.vShippingSettings.shippingPolicies.backToZoneList); + + await this.clickAndWaitForLoadState(selector.vendor.vShippingSettings.previousShippingSettings.previousShippingSettings); + + // previous shipping settings elements are visible + const { previousShippingSettings, ...previousShipping } = selector.vendor.vShippingSettings.previousShippingSettings; + await this.multipleElementVisible(previousShipping); + + // await this.goBack(); + } + + // set shipping policies + async setShippingPolicies(shippingPolicy: vendor['shipping']['shippingPolicy']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipping); + await this.click(selector.vendor.vShippingSettings.shippingPolicies.clickHereToAddShippingPolicies); + await this.selectByValue(selector.vendor.vShippingSettings.shippingPolicies.processingTime, shippingPolicy.processingTime); + await this.clearAndType(selector.vendor.vShippingSettings.shippingPolicies.shippingPolicy, shippingPolicy.shippingPolicy); + await this.clearAndType(selector.vendor.vShippingSettings.shippingPolicies.refundPolicy, shippingPolicy.refundPolicy); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vShippingSettings.shippingPolicies.saveSettings); + await this.toContainText(selector.vendor.vShippingSettings.updateSettingsSuccessMessage, shippingPolicy.saveSuccessMessage); + } + + // vendor set all shipping settings + async setAllShippingSettings(): Promise { + await this.addShippingMethod(data.vendor.shipping.shippingMethods.flatRate); + await this.addShippingMethod(data.vendor.shipping.shippingMethods.freeShipping); + await this.addShippingMethod(data.vendor.shipping.shippingMethods.localPickup); + await this.addShippingMethod(data.vendor.shipping.shippingMethods.tableRateShipping); + await this.addShippingMethod(data.vendor.shipping.shippingMethods.distanceRateShipping); + } + + // vendor add shipping method + async addShippingMethod(shipping: any, forceAdd = false, skip?: boolean): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipping); + // edit shipping zone + await this.hover(selector.vendor.vShippingSettings.shippingZoneCell(shipping.shippingZone)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vShippingSettings.editShippingZone(shipping.shippingZone)); + + // add shipping method if not available + let methodExists = await this.isVisible(selector.vendor.vShippingSettings.shippingMethodCell(shipping.shippingMethod)); + if (!methodExists || forceAdd) { + await this.click(selector.vendor.vShippingSettings.addShippingMethod); + await this.selectByValue(selector.vendor.vShippingSettings.shippingMethod, shipping.selectShippingMethod); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vShippingSettings.shippingMethodPopupAddShippingMethod); + await expect(this.page.getByText(shipping.shippingMethodSaveSuccessMessage)).toBeVisible(); + await expect(this.page.getByText(shipping.zoneSaveSuccessMessage)).toBeVisible(); + methodExists = true; + } + + // option to skip if shipping method is already available + if (methodExists && skip) { + return; + } + + // edit shipping method + await this.hover(selector.vendor.vShippingSettings.shippingMethodCell(shipping.shippingMethod)); + await this.click(selector.vendor.vShippingSettings.editShippingMethod(shipping.shippingMethod)); + + switch (shipping.selectShippingMethod) { + // flat rate + case 'flat_rate': + await this.clearAndType(selector.vendor.vShippingSettings.flatRateMethodTitle, shipping.shippingMethodTitle); + await this.clearAndType(selector.vendor.vShippingSettings.flatRateCost, shipping.shippingCost); + await this.selectByValue(selector.vendor.vShippingSettings.flatRateTaxStatus, shipping.taxStatus); + await this.clearAndType(selector.vendor.vShippingSettings.flatRateDescription, shipping.description); + await this.selectByValue(selector.vendor.vShippingSettings.flatRateCalculationType, shipping.calculationType); + break; + + // free shipping + case 'free_shipping': + await this.clearAndType(selector.vendor.vShippingSettings.freeShippingTitle, shipping.shippingMethodTitle); + await this.clearAndType(selector.vendor.vShippingSettings.freeShippingMinimumOrderAmount, shipping.freeShippingMinimumOrderAmount); + break; + + // local pickup + case 'local_pickup': + await this.clearAndType(selector.vendor.vShippingSettings.localPickupTitle, shipping.shippingMethodTitle); + await this.clearAndType(selector.vendor.vShippingSettings.localPickupCost, shipping.shippingCost); + await this.selectByValue(selector.vendor.vShippingSettings.localPickupTaxStatus, shipping.taxStatus); + await this.clearAndType(selector.vendor.vShippingSettings.flatRateDescription, shipping.description); + break; + + // dokan table rate shipping + case 'dokan_table_rate_shipping': + await this.clearAndType(selector.vendor.vShippingSettings.tableRateShippingMethodTitle, shipping.shippingMethodTitle); + await this.selectByValue(selector.vendor.vShippingSettings.tableRateShippingTaxStatus, shipping.taxStatus); + await this.selectByValue(selector.vendor.vShippingSettings.tableRateShippingTaxIncludedInShippingCosts, shipping.taxIncludedInShippingCosts); + await this.clearAndType(selector.vendor.vShippingSettings.tableRateShippingHandlingFee, shipping.handlingFee); + await this.clearAndType(selector.vendor.vShippingSettings.tableRateShippingMaximumShippingCost, shipping.maximumShippingCost); + // rates + // await this.selectByValue(selector.vendor.vShippingSettings.tableRateShippingCalculationType, shipping.calculationType) + await this.clearAndType(selector.vendor.vShippingSettings.tableRateShippingHandlingFeePerOrder, shipping.handlingFeePerOrder); + await this.clearAndType(selector.vendor.vShippingSettings.tableRateShippingMinimumCostPerOrder, shipping.minimumCostPerOrder); + await this.clearAndType(selector.vendor.vShippingSettings.tableRateShippingMaximumCostPerOrder, shipping.maximumCostPerOrder); + await this.click(selector.vendor.vShippingSettings.tableRateShippingUpdateSettings); + await this.toContainText(selector.vendor.vShippingSettings.tableRateShippingUpdateSettingsSuccessMessage, shipping.tableRateSaveSuccessMessage); + return; + + // dokan distance rate shipping + case 'dokan_distance_rate_shipping': + await this.clearAndType(selector.vendor.vShippingSettings.distanceRateShippingMethodTitle, shipping.shippingMethodTitle); + await this.selectByValue(selector.vendor.vShippingSettings.distanceRateShippingTaxStatus, shipping.taxStatus); + await this.selectByValue(selector.vendor.vShippingSettings.distanceRateShippingTransportationMode, shipping.transportationMode); + await this.selectByValue(selector.vendor.vShippingSettings.distanceRateShippingAvoid, shipping.avoid); + await this.selectByValue(selector.vendor.vShippingSettings.distanceRateShippingDistanceUnit, shipping.distanceUnit); + await this.check(selector.vendor.vShippingSettings.distanceRateShippingShowDistance); + await this.check(selector.vendor.vShippingSettings.distanceRateShippingShowDuration); + // shipping address + await this.clearAndType(selector.vendor.vShippingSettings.distanceRateShippingAddress1, shipping.street1); + await this.clearAndType(selector.vendor.vShippingSettings.distanceRateShippingAddress2, shipping.street2); + await this.clearAndType(selector.vendor.vShippingSettings.distanceRateShippingCity, shipping.city); + await this.clearAndType(selector.vendor.vShippingSettings.distanceRateShippingZipOrPostalCode, shipping.zipCode); + await this.clearAndType(selector.vendor.vShippingSettings.distanceRateShippingStateOrProvince, shipping.state); + await this.selectByValue(selector.vendor.vShippingSettings.distanceRateShippingCountry, shipping.country); + await this.click(selector.vendor.vShippingSettings.distanceRateShippingUpdateSettings); + await this.toContainText(selector.vendor.vShippingSettings.distanceRateShippingUpdateSettingsSuccessMessage, shipping.distanceRateSaveSuccessMessage); + return; + + default: + break; + } + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vShippingSettings.shippingSettingsSaveSettings); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vShippingSettings.saveChanges); + await this.toContainText(selector.vendor.vShippingSettings.updateSettingsSuccessMessage, shipping.saveSuccessMessage); + } + + // vendor add shipping method + async deleteShippingMethod(shipping: shipping['shippingMethods']['flatRate']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsShipping); + + // edit shipping zone + await this.hover(selector.vendor.vShippingSettings.shippingZoneCell(shipping.shippingZone)); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vShippingSettings.editShippingZone(shipping.shippingZone)); + + const noOfMethods = await this.countLocator(selector.vendor.vShippingSettings.shippingMethodCell(shipping.shippingMethod)); + + if (noOfMethods > 1) { + this.lastLocator(selector.vendor.vShippingSettings.shippingMethodCell(shipping.shippingMethod)).hover(); + const deleteMethod = this.lastLocator(selector.vendor.vShippingSettings.deleteShippingMethod(shipping.shippingMethod)); + await this.clickLocatorAndWaitForResponse(data.subUrls.ajax, deleteMethod); + await this.toHaveCount(selector.vendor.vShippingSettings.shippingMethodCell(shipping.shippingMethod), noOfMethods - 1); + } else { + await this.hover(selector.vendor.vShippingSettings.shippingMethodCell(shipping.shippingMethod)); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vShippingSettings.deleteShippingMethod(shipping.shippingMethod)); + await this.notToBeVisible(selector.vendor.vShippingSettings.shippingZoneCell(shipping.shippingZone)); + } + } +} diff --git a/tests/pw/pages/vendorStaffPage.ts b/tests/pw/pages/vendorStaffPage.ts new file mode 100644 index 0000000000..621fcc6cd4 --- /dev/null +++ b/tests/pw/pages/vendorStaffPage.ts @@ -0,0 +1,117 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { staff } from '@utils/interfaces'; + +export class VendorStaffPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // vendor staff + + // vendor staff render properly + async vendorStaffRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.staff); + + // staff text is visible + await this.toBeVisible(selector.vendor.vStaff.staffText); + + // add new staff is visible + await this.toBeVisible(selector.vendor.vStaff.addStaff.addNewStaff); + + const noStaff = await this.isVisible(selector.vendor.vStaff.noRowsFound); + + if (noStaff) { + await this.toContainText(selector.vendor.vStaff.noRowsFound, 'No staff found'); + console.log('No staff found on staff page'); + } else { + // vendor staff table elements are visible + await this.multipleElementVisible(selector.vendor.vStaff.table); + } + } + + // update staff fields + async updateStaffFields(staff: staff) { + await this.clearAndType(selector.vendor.vStaff.addStaff.firstName, staff.firstName); + await this.clearAndType(selector.vendor.vStaff.addStaff.lastName, staff.lastName); + await this.clearAndType(selector.vendor.vStaff.addStaff.email, staff.email); + await this.clearAndType(selector.vendor.vStaff.addStaff.phone, staff.phone); + const isPasswordVisible = await this.isVisible(selector.vendor.vStaff.editStaff.password); + isPasswordVisible && (await this.clearAndType(selector.vendor.vStaff.editStaff.password, staff.password)); + } + + // add new staff + async addStaff(staff: staff) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.staff); + await this.clickAndWaitForLoadState(selector.vendor.vStaff.addStaff.addNewStaff); + await this.updateStaffFields(staff); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.staff, selector.vendor.vStaff.addStaff.createStaff); + const userAlreadyExists = await this.isVisible(selector.vendor.vStaff.addStaff.userAlreadyExists); + if (userAlreadyExists) { + console.log('Staff already exists!!'); + return; + } + await this.toBeVisible(selector.vendor.vStaff.staffCell(staff.firstName + ' ' + staff.lastName)); + } + + // edit staff + async editStaff(staff: staff) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.staff); + await this.hover(selector.vendor.vStaff.staffCell(staff.firstName + ' ' + staff.lastName)); + await this.clickAndWaitForLoadState(selector.vendor.vStaff.editStaff.editStaff(staff.firstName + ' ' + staff.lastName)); + await this.updateStaffFields(staff); + await this.pressOnLocatorAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.staff, selector.vendor.vStaff.editStaff.updateStaff, data.key.enter); + await this.toBeVisible(selector.vendor.vStaff.staffCell(staff.firstName + ' ' + staff.lastName)); + } + + // add new staff + async deleteStaff(staffName: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.staff); + await this.hover(selector.vendor.vStaff.staffCell(staffName)); + await this.click(selector.vendor.vStaff.deleteStaff.deleteStaff(staffName)); + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.staff, selector.vendor.vStaff.deleteStaff.okDelete, 302); + await this.toContainText(selector.vendor.vStaff.deleteStaff.deleteSuccessMessage, 'Staff deleted successfully'); + } + + // manage staff permission + async manageStaffPermission(staffName: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.staff); + await this.hover(selector.vendor.vStaff.staffCell(staffName)); + await this.clickAndWaitForLoadState(selector.vendor.vStaff.managePermission.managePermission(staffName)); + + // manage overview permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.overview); + + // manage order permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.order); + + // manage review permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.review); + + // manage product permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.product); + + // manage booking permission + // await this.multipleElementCheck(selector.vendor.vStaff.managePermission.booking); // todo: add booking module + plugin check + + // manage store support permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.storeSupport); + + // manage report permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.report); + + // manage coupon permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.coupon); + + // manage withdraw permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.withdraw); + + // manage menu permission + await this.multipleElementCheck(selector.vendor.vStaff.managePermission.menu); + + // manage auction permission + // await this.multipleElementCheck(selector.vendor.vStaff.managePermission.auction); // todo: add auction module + plugin check + } +} diff --git a/tests/pw/pages/vendorToolsPage.ts b/tests/pw/pages/vendorToolsPage.ts new file mode 100644 index 0000000000..7c9cef1e0b --- /dev/null +++ b/tests/pw/pages/vendorToolsPage.ts @@ -0,0 +1,100 @@ +import { Page } from '@playwright/test'; +import { VendorPage } from '@pages/vendorPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; + +export class VendorToolsPage extends VendorPage { + constructor(page: Page) { + super(page); + } + + // tools + + // vendor tools render properly + async vendorToolsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.tools); + + // tools text is visible + await this.toBeVisible(selector.vendor.vTools.toolsText); + + // tools menus are visible + await this.multipleElementVisible(selector.vendor.vTools.menus); + + // import + + // import xml elements are visible + const { completionMessage, ...xml } = selector.vendor.vTools.import.xml; + await this.multipleElementVisible(xml); + + // csv + + // import csv text is visible + await this.toBeVisible(selector.vendor.vTools.import.csv.importCsvText); + + // import csv button is visible + await this.toBeVisible(selector.vendor.vTools.import.csv.csv); + + // export + + await this.click(selector.vendor.vTools.menus.export); + + // export xml elements are visible + await this.multipleElementVisible(selector.vendor.vTools.export.xml); + + // export csv text is visible + await this.toBeVisible(selector.vendor.vTools.export.csv.exportCsvText); + + // export csv button is visible + await this.toBeVisible(selector.vendor.vTools.export.csv.exportCsv); + + await this.click(selector.vendor.vTools.export.csv.exportCsv); + + // export csv elements are visible + const { exportCsvText, exportCsv, ...csv } = selector.vendor.vTools.export.csv; + await this.multipleElementVisible(csv); + } + + async importProduct(importType: string, filePath: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.tools); + + switch (importType) { + case 'xml': + await this.uploadFile(selector.vendor.vTools.import.xml.chooseXmlFile, filePath); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.tools, selector.vendor.vTools.import.xml.xml); + await this.toBeVisible(selector.vendor.vTools.import.xml.completionMessage); + break; + + case 'csv': // todo: add wait for uploading file, add api level assertion + await this.clickAndWaitForLoadState(selector.vendor.vTools.import.csv.csv); + await this.uploadFile(selector.vendor.vTools.import.csv.chooseCsv, filePath); + await this.click(selector.vendor.vTools.import.csv.updateExistingProducts); + await this.clickAndWaitForLoadState(selector.vendor.vTools.import.csv.continue); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.csvImport, selector.vendor.vTools.import.csv.runTheImporter); + await this.toContainText(selector.vendor.vTools.import.csv.completionMessage, 'Import complete!'); + break; + + default: + break; + } + } + + async exportProduct(exportType: string) { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.export); + + switch (exportType) { + case 'xml': + await this.click(selector.vendor.vTools.export.xml.all); + await this.clickAndWaitForDownload(selector.vendor.vTools.export.xml.exportXml); + break; + + case 'csv': + await this.clickAndWaitForLoadState(selector.vendor.vTools.export.csv.exportCsv); + await this.click(selector.vendor.vTools.export.csv.customMeta); + await this.clickAndWaitForDownload(selector.vendor.vTools.export.csv.generateCsv); + break; + + default: + break; + } + } +} diff --git a/tests/pw/pages/vendorVerificationsPage.ts b/tests/pw/pages/vendorVerificationsPage.ts new file mode 100644 index 0000000000..dc24a22162 --- /dev/null +++ b/tests/pw/pages/vendorVerificationsPage.ts @@ -0,0 +1,334 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { vendor } from '@utils/interfaces'; + +export class vendorVerificationsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // verification requests + + // verification requests render properly + async adminVerificationsRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + + // tools text is visible + await this.toBeVisible(selector.admin.dokan.verifications.verificationRequestsText); + + // navTab elements are visible + await this.multipleElementVisible(selector.admin.dokan.verifications.navTabs); + + // verification table elements are visible + await this.multipleElementVisible(selector.admin.dokan.verifications.table); + } + + // approve verification requests + async approveVerificationRequest(storeName: string, verificationType: string, action: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + + const verificationRequestIsExists = await this.isVisible(selector.admin.dokan.verifications.vendorRow(storeName)); + + if (!verificationRequestIsExists) { + console.log('No pending verification request found!!'); + return; + } + + await this.hover(selector.admin.dokan.verifications.vendorRow(storeName)); + + switch (verificationType) { + case 'id': + if (action === 'approve') { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.idRequest.approveRequest(storeName)); + } else { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.idRequest.rejectRequest(storeName)); + } + break; + + case 'address': + if (action === 'approve') { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.addressRequest.approveRequest(storeName)); + } else { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.addressRequest.rejectRequest(storeName)); + } + + break; + + case 'company': + if (action === 'approve') { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.companyRequest.approveRequest(storeName)); + } else { + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.companyRequest.rejectRequest(storeName)); + } + + break; + + default: + break; + } + } + + // disapprove verification requests + async disapproveVerificationRequest(storeName: string, verificationType: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.verifications); + + await this.clickAndWaitForLoadState(selector.admin.dokan.verifications.navTabs.approved); + + const verificationRequestIsExists = await this.isVisible(selector.admin.dokan.verifications.vendorRow(storeName)); + if (!verificationRequestIsExists) { + console.log('No approved verification request found!!'); + return; + } + + await this.hover(selector.admin.dokan.verifications.vendorRow(storeName)); + + switch (verificationType) { + case 'id': + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.idRequest.disapproveRequest(storeName)); + break; + + case 'address': + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.addressRequest.disapproveRequest(storeName)); + break; + + case 'company': + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.verifications.companyRequest.disapproveRequest(storeName)); + break; + + default: + break; + } + } + + // vendor + + // vendor verifications render properly + async vendorVerificationsSettingsRenderProperly() { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + + // verification text is visible + await this.toBeVisible(selector.vendor.vVerificationSettings.verificationText); + + // visit store link is visible + await this.toBeVisible(selector.vendor.vVerificationSettings.visitStore); + + // verification div and heading text + + // id + await this.toBeVisible(selector.vendor.vVerificationSettings.id.idVerificationDiv); + await this.toBeVisible(selector.vendor.vVerificationSettings.id.idVerificationText); + + // address + await this.toBeVisible(selector.vendor.vVerificationSettings.address.addressVerificationDiv); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.addressVerificationText); + + // company + await this.toBeVisible(selector.vendor.vVerificationSettings.company.companyVerificationDiv); + await this.toBeVisible(selector.vendor.vVerificationSettings.company.companyVerificationText); + + // verification request is pending + + // id + const idRequestIsPending = await this.isVisible(selector.vendor.vVerificationSettings.id.idPendingFeedback); + if (idRequestIsPending) { + await this.toContainText(selector.vendor.vVerificationSettings.id.idPendingFeedback, 'Your ID verification request is pending'); + await this.toBeVisible(selector.vendor.vVerificationSettings.id.cancelIdVerificationRequest); + } + + // address + const addressRequestIsPending = await this.isVisible(selector.vendor.vVerificationSettings.address.addressPendingFeedback); + if (addressRequestIsPending) { + await this.toContainText(selector.vendor.vVerificationSettings.address.addressPendingFeedback, 'Your Address verification request is pending'); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.cancelAddressVerificationRequest); + } + + // company + const companyRequestIsPending = await this.isVisible(selector.vendor.vVerificationSettings.company.companyPendingFeedback); + if (companyRequestIsPending) { + await this.toContainText(selector.vendor.vVerificationSettings.company.companyPendingFeedback, 'Your company verification request is pending'); + await this.toBeVisible(selector.vendor.vVerificationSettings.company.cancelCompanyVerificationRequest); + } + + // verification request is approved + + // id + const idRequestIsApproved = await this.isVisible(selector.vendor.vVerificationSettings.id.idApproveFeedback); + if (idRequestIsApproved) { + await this.toContainText(selector.vendor.vVerificationSettings.id.idApproveFeedback, 'Your ID verification request is approved'); + } + + // address + const addressRequestIsApproved = await this.isVisible(selector.vendor.vVerificationSettings.address.addressApproveFeedback); + if (addressRequestIsApproved) { + await this.toContainText(selector.vendor.vVerificationSettings.address.addressApproveFeedback, 'Your Address verification request is approved'); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.startAddressVerification); + } + + // company + const companyRequestIsApproved = await this.isVisible(selector.vendor.vVerificationSettings.company.companyApproveFeedback); + if (companyRequestIsApproved) { + await this.toContainText(selector.vendor.vVerificationSettings.company.companyApproveFeedback, 'Your company verification request is approved'); + await this.toBeVisible(selector.vendor.vVerificationSettings.company.startCompanyVerification); + } + + // no verification request is submitted + + // id + if (!idRequestIsPending && !idRequestIsApproved) { + await this.toBeVisible(selector.vendor.vVerificationSettings.id.startIdVerification); + + await this.click(selector.vendor.vVerificationSettings.id.startIdVerification); + + await this.toBeVisible(selector.vendor.vVerificationSettings.id.passport); + await this.toBeVisible(selector.vendor.vVerificationSettings.id.nationalIdCard); + await this.toBeVisible(selector.vendor.vVerificationSettings.id.drivingLicense); + const previousUploadedPhotoIsVisible = await this.isVisible(selector.vendor.vVerificationSettings.id.previousUploadedPhoto); + previousUploadedPhotoIsVisible && (await this.toBeVisible(selector.vendor.vVerificationSettings.id.uploadPhoto)); + await this.toBeVisible(selector.vendor.vVerificationSettings.id.submitId); + await this.toBeVisible(selector.vendor.vVerificationSettings.id.cancelSubmitId); + } + + // address + if (!addressRequestIsPending && !addressRequestIsApproved) { + await this.toBeVisible(selector.vendor.vVerificationSettings.address.startAddressVerification); + + await this.click(selector.vendor.vVerificationSettings.address.startAddressVerification); + + await this.toBeVisible(selector.vendor.vVerificationSettings.address.street); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.street2); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.city); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.postOrZipCode); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.country); + const previousUploadedResidenceProofIsVisible = await this.isVisible(selector.vendor.vVerificationSettings.address.previousUploadedResidenceProof); + !previousUploadedResidenceProofIsVisible && (await this.toBeVisible(selector.vendor.vVerificationSettings.address.uploadResidenceProof)); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.submitAddress); + await this.toBeVisible(selector.vendor.vVerificationSettings.address.cancelSubmitAddress); + } + + // company + if (!companyRequestIsPending && !companyRequestIsApproved) { + await this.toBeVisible(selector.vendor.vVerificationSettings.company.startCompanyVerification); + + await this.click(selector.vendor.vVerificationSettings.company.startCompanyVerification); + + await this.toBeVisible(selector.vendor.vVerificationSettings.company.uploadFiles); + await this.toBeVisible(selector.vendor.vVerificationSettings.company.submitCompanyInfo); + await this.toBeVisible(selector.vendor.vVerificationSettings.company.cancelSubmitCompanyInfo); + } + } + + // vendor send id verification request + async sendIdVerificationRequest(verification: vendor['verification']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + + const idRequestIsApproved = await this.isVisible(selector.vendor.vVerificationSettings.id.idApproveFeedback); + if (idRequestIsApproved) { + return; + } + + // cancel previous verification request if any + const cancelRequestIsVisible = await this.isVisible(selector.vendor.vVerificationSettings.id.cancelIdVerificationRequest); + if (cancelRequestIsVisible) { + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vVerificationSettings.id.cancelIdVerificationRequest); + await this.toContainText(selector.vendor.vVerificationSettings.id.idUpdateSuccessMessage, verification.idRequestSubmitCancel); + } + + // id verification + await this.click(selector.vendor.vVerificationSettings.id.startIdVerification); + await this.wait(0.5); // todo: resolve this + + // remove previously uploaded image + const uploadPhotoBtnIsVisible = await this.isVisible(selector.vendor.vVerificationSettings.id.uploadPhoto); + if (!uploadPhotoBtnIsVisible) { + // await this.hover(selector.vendor.vVerificationSettings.id.previousUploadedPhoto); // todo: not working: playwright issue + // await this.click(selector.vendor.vVerificationSettings.id.removePreviousUploadedPhoto); + + await this.setAttributeValue('.gravatar-wrap', 'class', 'gravatar-wrap dokan-hide'); + await this.setAttributeValue('.gravatar-button-area.dokan-hide', 'class', 'gravatar-button-area'); + } + + await this.click(selector.vendor.vVerificationSettings.id.uploadPhoto); + await this.uploadMedia(verification.file); + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vVerificationSettings.id.submitId); + await this.toContainText(selector.vendor.vVerificationSettings.id.idUpdateSuccessMessage, verification.idRequestSubmitSuccessMessage); + } + + // vendor send address verification request + async sendAddressVerificationRequest(verification: vendor['verification']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.settingsVerification); + + // cancel previous verification request if any + const cancelRequestIsVisible = await this.isVisible(selector.vendor.vVerificationSettings.address.cancelAddressVerificationRequest); + if (cancelRequestIsVisible) { + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vVerificationSettings.address.cancelAddressVerificationRequest); + await this.toContainText(selector.vendor.vVerificationSettings.address.addressUpdateSuccessMessage, verification.addressRequestSubmitCancel); + } + + // address verification + await this.click(selector.vendor.vVerificationSettings.address.startAddressVerification); + await this.clearAndType(selector.vendor.vVerificationSettings.address.street, verification.street1); + await this.clearAndType(selector.vendor.vVerificationSettings.address.street2, verification.street2); + await this.clearAndType(selector.vendor.vVerificationSettings.address.city, verification.city); + await this.clearAndType(selector.vendor.vVerificationSettings.address.postOrZipCode, verification.zipCode); + await this.selectByValue(selector.vendor.vVerificationSettings.address.country, verification.country); + await this.selectByValue(selector.vendor.vVerificationSettings.address.state, verification.state); + + // remove previously uploaded image + const uploadProofBtnIsVisible = await this.isVisible(selector.vendor.vVerificationSettings.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(selector.vendor.vVerificationSettings.address.uploadResidenceProof); + await this.uploadMedia(verification.file); + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vVerificationSettings.address.submitAddress); + await this.toContainText(selector.vendor.vVerificationSettings.address.addressUpdateSuccessMessage, verification.addressRequestSubmitSuccessMessage); + } + + // 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(selector.vendor.vVerificationSettings.company.cancelCompanyVerificationRequest); + if (cancelRequestIsVisible) { + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vVerificationSettings.company.cancelCompanyVerificationRequest); + await this.toContainText(selector.vendor.vVerificationSettings.company.companyInfoUpdateSuccessMessage, verification.companyRequestSubmitCancel); + } + + // company verification + await this.click(selector.vendor.vVerificationSettings.company.startCompanyVerification); + await this.wait(1); + + // remove previously uploaded company file + const UploadedCompanyFileIsVisible = await this.isVisible(selector.vendor.vVerificationSettings.company.uploadedFileFirst); + if (UploadedCompanyFileIsVisible) { + await this.click(selector.vendor.vVerificationSettings.company.uploadedFileFirst); + } + + await this.click(selector.vendor.vVerificationSettings.company.uploadFiles); + await this.uploadMedia(verification.file); + + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.vendor.vVerificationSettings.company.submitCompanyInfo); + await this.toContainText(selector.vendor.vVerificationSettings.company.companyInfoUpdateSuccessMessage, verification.companyRequestSubmitSuccessMessage); + } + + // upload media // todo: move to base-page and merge with wpUploadFile + async uploadMedia(file: string) { + await this.wait(0.5); + const uploadedMediaIsVisible = await this.isVisible(selector.wpMedia.uploadedMediaFirst); + if (uploadedMediaIsVisible) { + await this.click(selector.wpMedia.uploadedMediaFirst); + } else { + await this.uploadFile(selector.wpMedia.selectFilesInput, file); + const isSelectDisabled = await this.isDisabled(selector.wpMedia.select); + isSelectDisabled && (await this.click(selector.wpMedia.selectUploadedMedia)); + await this.click(selector.wpMedia.select); + } + } +} diff --git a/tests/pw/pages/wholesaleCustomersPage.ts b/tests/pw/pages/wholesaleCustomersPage.ts new file mode 100644 index 0000000000..dc3ae46439 --- /dev/null +++ b/tests/pw/pages/wholesaleCustomersPage.ts @@ -0,0 +1,191 @@ +import { Page, expect } from '@playwright/test'; +import { LoginPage } from '@pages/loginPage'; +import { AdminPage } from '@pages/adminPage'; +import { CustomerPage } from '@pages/customerPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { customer } from '@utils/interfaces'; + +export class WholesaleCustomersPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + loginPage = new LoginPage(this.page); + customerPage = new CustomerPage(this.page); + + // wholesale customers + + // wholesale customers render properly + async adminWholesaleCustomersRenderProperly() { + await this.goIfNotThere(data.subUrls.backend.dokan.wholeSaleCustomer); + + // wholesale customer text is visible + await this.toBeVisible(selector.admin.dokan.wholesaleCustomer.wholesaleCustomerText); + + // nav tabs are visible + await this.multipleElementVisible(selector.admin.dokan.wholesaleCustomer.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.wholesaleCustomer.bulkActions); + + // search wholesale customer input is visible + await this.toBeVisible(selector.admin.dokan.wholesaleCustomer.search); + + // wholesale customer table elements are visible + await this.multipleElementVisible(selector.admin.dokan.wholesaleCustomer.table); + } + + // search wholesale customer + async searchWholesaleCustomer(wholesaleCustomer: string) { + await this.goIfNotThere(data.subUrls.backend.dokan.wholeSaleCustomer); + + await this.clearInputField(selector.admin.dokan.wholesaleCustomer.search); + + await this.typeAndWaitForResponse(data.subUrls.api.dokan.wholesaleCustomers, selector.admin.dokan.wholesaleCustomer.search, wholesaleCustomer); + await this.toBeVisible(selector.admin.dokan.wholesaleCustomer.wholesaleCustomerCell(wholesaleCustomer)); + } + + // edit wholesale customer + async editWholesaleCustomer(wholesaleCustomer: customer) { + await this.searchWholesaleCustomer(wholesaleCustomer.username); + await this.hover(selector.admin.dokan.wholesaleCustomer.wholesaleCustomerCell(wholesaleCustomer.username)); + await this.clickAndWaitForLoadState(selector.admin.dokan.wholesaleCustomer.wholesaleCustomerEdit(wholesaleCustomer.username)); + + // basic info + await this.selectByValue(selector.admin.users.userInfo.role, wholesaleCustomer.customerInfo.role); + await this.clearAndType(selector.admin.users.userInfo.firstName, wholesaleCustomer.username); + await this.clearAndType(selector.admin.users.userInfo.lastName, wholesaleCustomer.lastname); + await this.clearAndType(selector.admin.users.userInfo.nickname, wholesaleCustomer.username); + + // contact info + await this.clearAndType(selector.admin.users.userInfo.email, wholesaleCustomer.username + data.customer.customerInfo.emailDomain); + + // About the user + await this.clearAndType(selector.admin.users.userInfo.biographicalInfo, wholesaleCustomer.customerInfo.biography); + + // customer address + + // billing + await this.clearAndType(selector.admin.users.userInfo.billingAddress.firstName, wholesaleCustomer.username); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.lastName, wholesaleCustomer.lastname); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.company, wholesaleCustomer.customerInfo.companyName); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.address1, wholesaleCustomer.customerInfo.street1); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.address2, wholesaleCustomer.customerInfo.street2); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.city, wholesaleCustomer.customerInfo.city); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.postcode, wholesaleCustomer.customerInfo.zipCode); + await this.click(selector.admin.users.userInfo.billingAddress.country); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.countryInput, wholesaleCustomer.customerInfo.country); + await this.press(data.key.enter); + await this.click(selector.admin.users.userInfo.billingAddress.state); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.stateInput, wholesaleCustomer.customerInfo.state); + await this.press(data.key.enter); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.phone, wholesaleCustomer.customerInfo.phone); + await this.clearAndType(selector.admin.users.userInfo.billingAddress.email, wholesaleCustomer.username + data.customer.customerInfo.emailDomain); + + // shipping + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.firstName, wholesaleCustomer.username); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.lastName, wholesaleCustomer.lastname); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.company, wholesaleCustomer.customerInfo.companyName); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.address1, wholesaleCustomer.customerInfo.street1); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.address2, wholesaleCustomer.customerInfo.street2); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.city, wholesaleCustomer.customerInfo.city); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.postcode, wholesaleCustomer.customerInfo.zipCode); + await this.click(selector.admin.users.userInfo.shippingAddress.country); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.countryInput, wholesaleCustomer.customerInfo.country); + await this.press(data.key.enter); + await this.click(selector.admin.users.userInfo.shippingAddress.state); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.stateInput, wholesaleCustomer.customerInfo.state); + await this.press(data.key.enter); + await this.clearAndType(selector.admin.users.userInfo.shippingAddress.phone, wholesaleCustomer.customerInfo.phone); + + // update user + await this.clickAndWaitForResponse(data.subUrls.backend.user, selector.admin.users.updateUser, 302); + await this.toContainText(selector.admin.users.updateSuccessMessage, 'User updated.'); + } + + // view wholesale customer orders + async viewWholesaleCustomerOrders(wholesaleCustomer: string) { + await this.searchWholesaleCustomer(wholesaleCustomer); + await this.hover(selector.admin.dokan.wholesaleCustomer.wholesaleCustomerCell(wholesaleCustomer)); + await this.clickAndWaitForLoadState(selector.admin.dokan.wholesaleCustomer.wholesaleCustomerOrders(wholesaleCustomer)); + const count = (await this.getElementText(selector.admin.dokan.wholesaleCustomer.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } + + // update wholesale customer + async updateWholesaleCustomer(wholesaleCustomer: string, action: string) { + await this.searchWholesaleCustomer(wholesaleCustomer); + + switch (action) { + case 'enable': + await this.enableSwitcherAndWaitForResponse(data.subUrls.api.dokan.wholesaleCustomers, selector.admin.dokan.wholesaleCustomer.statusSlider(wholesaleCustomer)); + break; + + case 'disable': + await this.disableSwitcherAndWaitForResponse(data.subUrls.api.dokan.wholesaleCustomers, selector.admin.dokan.wholesaleCustomer.statusSlider(wholesaleCustomer)); + break; + + case 'delete': + await this.hover(selector.admin.dokan.wholesaleCustomer.wholesaleCustomerCell(wholesaleCustomer)); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.wholesaleCustomers, selector.admin.dokan.wholesaleCustomer.wholesaleCustomerRemove(wholesaleCustomer)); + break; + + default: + break; + } + } + + // wholesale customers bulk action + async wholesaleCustomerBulkAction(action: string, wholesaleCustomer?: string) { + wholesaleCustomer ? await this.searchWholesaleCustomer(wholesaleCustomer) : await this.goIfNotThere(data.subUrls.backend.dokan.wholeSaleCustomer); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.wholesaleCustomer.noRowsFound); + + await this.click(selector.admin.dokan.wholesaleCustomer.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.wholesaleCustomer.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.wholesaleCustomers, selector.admin.dokan.wholesaleCustomer.bulkActions.applyAction); + } + + // customer request to become wholesale customer + async customerRequestForBecomeWholesaleCustomer(): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + await this.click(selector.customer.cDashboard.becomeWholesaleCustomer); + await this.toContainText(selector.customer.cDashboard.wholesaleRequestReturnMessage, data.wholesale.wholesaleRequestSendMessage); + } + + // customer become wholesale customer + async customerBecomeWholesaleCustomer(): Promise { + await this.goIfNotThere(data.subUrls.frontend.myAccount); + const currentUser = await this.getCurrentUser(); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.wholesaleRegister, selector.customer.cDashboard.becomeWholesaleCustomer); + const neeApproval = await this.isVisible(selector.customer.cDashboard.wholesaleRequestReturnMessage); + if (!neeApproval) { + await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, data.wholesale.becomeWholesaleCustomerSuccessMessage); + } else { + await this.toContainText(selector.customer.cDashboard.wholesaleRequestReturnMessage, data.wholesale.wholesaleRequestSendMessage); + await this.loginPage.switchUser(data.admin); + await this.updateWholesaleCustomer(currentUser as string, 'enable'); + } + } + + // view wholesale price + async viewWholeSalePrice(productName: string) { + await this.customerPage.searchProduct(productName); + await this.toBeVisible(selector.customer.cWholesale.shop.wholesalePrice); + await this.toBeVisible(selector.customer.cWholesale.shop.wholesaleAmount); + + await this.customerPage.goToProductDetails(productName); + await this.toBeVisible(selector.customer.cWholesale.singleProductDetails.wholesaleInfo); + } + + // assert wholesale price + async assertWholesalePrice(wholesalePrice: string, minimumWholesaleQuantity: string) { + await this.customerPage.goToCheckout(); + const subtotal = Number(helpers.price((await this.getElementText(selector.customer.cCheckout.orderDetails.cartTotal)) as string)); + const calcSubTotal = helpers.roundToTwo(helpers.subtotal([Number(wholesalePrice)], [Number(minimumWholesaleQuantity)])); + expect(subtotal).toEqual(calcSubTotal); + } +} diff --git a/tests/pw/pages/withdrawsPage.ts b/tests/pw/pages/withdrawsPage.ts new file mode 100644 index 0000000000..5c3b2404a6 --- /dev/null +++ b/tests/pw/pages/withdrawsPage.ts @@ -0,0 +1,226 @@ +import { Page, test, expect } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; +import { vendor } from '@utils/interfaces'; + +const { DOKAN_PRO } = process.env; + +export class WithdrawsPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // withdraws + + // withdraws render properly + async adminWithdrawsRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); + + // withdraw text is visible + await this.toBeVisible(selector.admin.dokan.withdraw.withdrawText); + + // nav tabs elements are visible + await this.multipleElementVisible(selector.admin.dokan.withdraw.navTabs); + + // bulk action elements are visible + await this.multipleElementVisible(selector.admin.dokan.withdraw.bulkActions); + + // filter elements are visible + const { filterInput, clearFilter, result, ...filters } = selector.admin.dokan.withdraw.filters; + await this.multipleElementVisible(filters); + + // withdraw table elements are visible + await this.multipleElementVisible(selector.admin.dokan.withdraw.table); + } + + // filter withdraws + async filterWithdraws(input: string, action: string): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); + + switch (action) { + case 'by-vendor': + await this.click(selector.admin.dokan.withdraw.filters.filterByVendor); + break; + + case 'by-payment-method': + await this.click(selector.admin.dokan.withdraw.filters.filterByPaymentMethods); + break; + + default: + break; + } + await this.fill(selector.admin.dokan.withdraw.filters.filterInput, input); + await this.toContainText(selector.admin.dokan.withdraw.filters.result, input); + // todo: need to wait for focus event + await this.pressAndWaitForResponse(data.subUrls.api.dokan.withdraws, data.key.enter); + const count = (await this.getElementText(selector.admin.dokan.withdraw.numberOfRowsFound))?.split(' ')[0]; + expect(Number(count)).toBeGreaterThan(0); + } + + // export withdraws + async exportWithdraws() { + await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); + await this.clickAndWaitForDownload(selector.admin.dokan.withdraw.exportWithdraws); + } + + // add note to withdraw request + async addNoteWithdrawRequest(vendorName: string, note: string): Promise { + await this.filterWithdraws(vendorName, 'by-vendor'); + + await this.click(selector.admin.dokan.withdraw.withdrawAddNote(vendorName)); + await this.clearAndType(selector.admin.dokan.withdraw.addNote, note); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.withdraws, selector.admin.dokan.withdraw.updateNote); + } + + // add note to withdraw request + async updateWithdrawRequest(vendorName: string, action: string): Promise { + await this.filterWithdraws(vendorName, 'by-vendor'); + + switch (action) { + case 'approve': + await this.clickAndWaitForResponse(data.subUrls.api.dokan.withdraws, selector.admin.dokan.withdraw.withdrawApprove(vendorName)); + break; + + case 'cancel': + await this.hover(selector.admin.dokan.withdraw.withdrawCell(vendorName)); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.withdraws, selector.admin.dokan.withdraw.withdrawCancel(vendorName)); + break; + + case 'delete': + await this.hover(selector.admin.dokan.withdraw.withdrawCell(vendorName)); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.api.dokan.withdraws, selector.admin.dokan.withdraw.withdrawDelete(vendorName)); + break; + + default: + break; + } + } + + // withdraw bulk action + async withdrawBulkAction(action: string): Promise { + await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); + + // ensure row exists + await this.notToBeVisible(selector.admin.dokan.withdraw.noRowsFound); + + await this.click(selector.admin.dokan.withdraw.bulkActions.selectAll); + await this.selectByValue(selector.admin.dokan.withdraw.bulkActions.selectAction, action); + await this.clickAndWaitForResponse(data.subUrls.api.dokan.withdraws, selector.admin.dokan.withdraw.bulkActions.applyAction); + } + + // withdraw + + // withdraw render properly + async vendorWithdrawRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.withdraw); + + // withdraw text is visible + await this.toBeVisible(selector.vendor.vWithdraw.withdrawText); + + // balance elements are visible + const { balanceLite, balancePro, ...balance } = selector.vendor.vWithdraw.balance; + await this.multipleElementVisible(balance); + DOKAN_PRO ? await this.toBeVisible(balancePro) : await this.toBeVisible(balanceLite); + + // request withdraw is visible + await this.toBeVisible(selector.vendor.vWithdraw.manualWithdrawRequest.requestWithdraw); + + // payment details manual elements are visible + await this.multipleElementVisible(selector.vendor.vWithdraw.paymentDetails.manual); + + // view payments is visible + await this.toBeVisible(selector.vendor.vWithdraw.viewPayments.viewPayments); + + if (DOKAN_PRO) { + // payment details schedule elements are visible + await this.multipleElementVisible(selector.vendor.vWithdraw.paymentDetails.schedule); + + // enable & edit schedule is visible + await this.toBeVisible(selector.vendor.vWithdraw.autoWithdrawDisbursement.enableSchedule); + await this.toBeVisible(selector.vendor.vWithdraw.autoWithdrawDisbursement.editSchedule); + } + + // todo: pending request can be added + + // withdraw payment methods div elements are visible + await this.toBeVisible(selector.vendor.vWithdraw.withdrawPaymentMethods.paymentMethodsDiv); + + await this.notToHaveCount(selector.vendor.vWithdraw.withdrawPaymentMethods.paymentMethods, 0); + + // todo: add request & disbursement modal + } + + // withdraw requests render properly + async vendorWithdrawRequestsRenderProperly(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.withdrawRequests); + + // withdraw requests menus are visible + await this.multipleElementVisible(selector.vendor.vWithdraw.viewPayments.menus); + + // request withdraw button is visible + await this.toBeVisible(selector.vendor.vWithdraw.viewPayments.requestWithdraw); + + // withdraw dashboard button is visible + await this.toBeVisible(selector.vendor.vWithdraw.viewPayments.withdrawDashboard); + + // withdraw requests table elements are visible + await this.multipleElementVisible(selector.vendor.vWithdraw.viewPayments.table); + } + + // vendor request withdraw + async requestWithdraw(withdraw: vendor['withdraw']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.withdraw); + + if (helpers.price(withdraw.currentBalance) > helpers.price(withdraw.minimumWithdrawAmount)) { + await this.click(selector.vendor.vWithdraw.manualWithdrawRequest.requestWithdraw); + await this.clearAndType(selector.vendor.vWithdraw.manualWithdrawRequest.withdrawAmount, String(withdraw.minimumWithdrawAmount)); + await this.selectByValue(selector.vendor.vWithdraw.manualWithdrawRequest.withdrawMethod, withdraw.withdrawMethod.default); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vWithdraw.manualWithdrawRequest.submitRequest); + // await expect(this.page.getByText(selector.vendor.vWithdraw.manualWithdrawRequest.withdrawRequestSaveSuccessMessage)).toBeVisible(); // todo: + } else { + console.log('Vendor balance is less than minimum withdraw amount'); + test.skip(); + // throw new Error('Vendor balance is less than minimum withdraw amount'); + } + } + + // vendor can't request withdraw when pending request exists + async cantRequestWithdraw(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.withdraw); + await this.click(selector.vendor.vWithdraw.manualWithdrawRequest.requestWithdraw); + await this.toContainText(selector.vendor.vWithdraw.manualWithdrawRequest.pendingRequestAlert, selector.vendor.vWithdraw.manualWithdrawRequest.pendingRequestAlertMessage); + await this.click(selector.vendor.vWithdraw.manualWithdrawRequest.closeModal); + } + + // vendor cancel withdraw request + async cancelWithdrawRequest(): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.withdraw); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.withdrawRequests, selector.vendor.vWithdraw.manualWithdrawRequest.cancelRequest, 302); + await this.toContainText(selector.vendor.vWithdraw.manualWithdrawRequest.cancelWithdrawRequestSuccess, selector.vendor.vWithdraw.manualWithdrawRequest.cancelWithdrawRequestSaveSuccessMessage); + } + + // vendor add auto withdraw disbursement schedule + async addAutoWithdrawDisbursementSchedule(withdraw: vendor['withdraw']): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.withdraw); + await this.enableSwitcherDisbursement(selector.vendor.vWithdraw.autoWithdrawDisbursement.enableSchedule); + await this.click(selector.vendor.vWithdraw.autoWithdrawDisbursement.editSchedule); + await this.selectByValue(selector.vendor.vWithdraw.autoWithdrawDisbursement.preferredPaymentMethod, withdraw.preferredPaymentMethod); + await this.click(selector.vendor.vWithdraw.autoWithdrawDisbursement.preferredSchedule(withdraw.preferredSchedule)); + await this.selectByValue(selector.vendor.vWithdraw.autoWithdrawDisbursement.onlyWhenBalanceIs, withdraw.minimumWithdrawAmount); + await this.selectByValue(selector.vendor.vWithdraw.autoWithdrawDisbursement.maintainAReserveBalance, withdraw.reservedBalance); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.vWithdraw.autoWithdrawDisbursement.changeSchedule); + await this.notToContainText(selector.vendor.vWithdraw.autoWithdrawDisbursement.scheduleMessage, data.vendor.withdraw.scheduleMessageInitial); + } + + // vendor add default withdraw payment methods + async addDefaultWithdrawPaymentMethods(preferredSchedule: string): Promise { + await this.goIfNotThere(data.subUrls.frontend.vDashboard.withdraw); + const methodIsDefault = await this.isVisible(selector.vendor.vWithdraw.withdrawPaymentMethods.defaultMethod(preferredSchedule)); + if (!methodIsDefault) { + await this.clickAndWaitForLoadState(selector.vendor.vWithdraw.withdrawPaymentMethods.makeMethodDefault(preferredSchedule)); + await this.toBeVisible(selector.vendor.vWithdraw.withdrawPaymentMethods.defaultMethod(preferredSchedule)); + } + } +} diff --git a/tests/pw/pages/wpPage.ts b/tests/pw/pages/wpPage.ts new file mode 100644 index 0000000000..735bc409fa --- /dev/null +++ b/tests/pw/pages/wpPage.ts @@ -0,0 +1,54 @@ +import { Page } from '@playwright/test'; +import { AdminPage } from '@pages/adminPage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { plugin, wpSettings } from '@utils/interfaces'; + +export class WpPage extends AdminPage { + constructor(page: Page) { + super(page); + } + + // wordpress site settings + + // plugin activation check + async checkActivePlugins(plugins: plugin) { + await this.goIfNotThere(data.subUrls.backend.plugins); + for (const pluginSlug of plugins.pluginSlugs) { + await this.toHaveClass(selector.admin.plugins.plugin(pluginSlug), plugins.activeClass); + } + } + + // admin set wordpress site settings + async setWpSettings(wpSettings: wpSettings) { + await this.setWpGeneralSettings(wpSettings.general); + await this.setPermalinkSettings(wpSettings.permalink); + } + + // set wp general settings + async setWpGeneralSettings(general: wpSettings['general']) { + await this.goto(data.subUrls.backend.general); + + // enable user registration + await this.check(selector.admin.settings.membership); + // timezone + await this.selectByValue(selector.admin.settings.timezone, general.timezone); + await this.click(selector.admin.settings.generalSaveChanges); + await this.toContainText(selector.admin.settings.updatedSuccessMessage, general.saveSuccessMessage); + } + + // admin set permalink settings + async setPermalinkSettings(permalink: wpSettings['permalink']) { + await this.goto(data.subUrls.backend.permalinks); + + // set permalinks settings + await this.click(selector.admin.settings.postName); + const customBaseIsVisible = await this.isVisible(selector.admin.settings.customBase); + if (customBaseIsVisible) { + await this.click(selector.admin.settings.customBase); + await this.clearAndType(selector.admin.settings.customBaseInput, permalink.customBaseInput); + } + await this.click(selector.admin.settings.permalinkSaveChanges); + await this.toContainText(selector.admin.settings.updatedSuccessMessage, permalink.saveSuccessMessage); + } +} diff --git a/tests/pw/tests/api/_coverage.teardown.ts b/tests/pw/tests/api/_coverage.teardown.ts new file mode 100644 index 0000000000..71a0d48daf --- /dev/null +++ b/tests/pw/tests/api/_coverage.teardown.ts @@ -0,0 +1,56 @@ +import { test } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { helpers } from '@utils/helpers'; +import { execSync } from 'child_process'; + +test.describe('get api test coverage', () => { + let apiUtils: ApiUtils; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get coverage ', async () => { + const [, responseBody1] = await apiUtils.get(endPoints.getAllDokanEndpointsAdmin); + const [, responseBody2] = await apiUtils.get(endPoints.getAllDokanEndpointsV1); + const [, responseBody3] = await apiUtils.get(endPoints.getAllDokanEndpointsV2); + const allRoutes = [...Object.keys(responseBody1.routes), ...Object.keys(responseBody2.routes), ...Object.keys(responseBody3.routes)]; + // const allRoutes = [ ...Object.keys(responseBody3.routes)]; + const allRouteObjValues = [...Object.values(responseBody1.routes), ...Object.values(responseBody2.routes), ...Object.values(responseBody3.routes)]; + // const allRouteObjValues = [ ...Object.values(responseBody3.routes)]; + const allRouteMethods: string[][] = allRouteObjValues.map(route => route.methods); + // console.log(allRoutes); + // console.log(allRouteMethods); + let coverageArray = allRouteMethods.flatMap((methods, i) => methods.map(method => `${method} ${allRoutes[i]}`)); + coverageArray = [...new Set(coverageArray)]; + coverageArray = coverageArray.filter(e => !e.includes('PATCH')); + // console.log(coverageArray); + console.log(coverageArray.length); + getCoverage(coverageArray); + }); +}); + +function getCoverage(coverageArray: any[]) { + const totalEndPoints = coverageArray.length; + let coveredEndPoints = 0; + const nonCoveredEndpoints: string[] = []; + //Iterates through the coverageArray to grep each file in the test directory looking for matches + for (const route of coverageArray) { + const pattern = `COVERAGE_TAG: ${helpers.escapeRegex(route)}$`; + const output = execSync(`grep -irl -E '${pattern}' tests/api | cat `, { encoding: 'utf-8' }); + // console.log('route: ', pattern); + // console.log('grep_Output: ', output); + if (output.toString() != '') { + coveredEndPoints += 1; + } else { + console.log(`Endpoint with no coverage: ${route}`); + nonCoveredEndpoints.push(route); + } + } + + const percentCovered = ((coveredEndPoints / totalEndPoints) * 100).toFixed(2); + console.log('Total Endpoints: ' + totalEndPoints); + console.log('Covered Endpoints: ' + coveredEndPoints); + console.log('Coverage: ' + percentCovered + '%'); +} diff --git a/tests/pw/tests/api/_env.setup.ts b/tests/pw/tests/api/_env.setup.ts new file mode 100644 index 0000000000..447600b84d --- /dev/null +++ b/tests/pw/tests/api/_env.setup.ts @@ -0,0 +1,51 @@ +import { test as setup, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; +import { helpers } from '@utils/helpers'; + +setup.describe(' setup environment', () => { + let apiUtils: ApiUtils; + + setup.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + }); + + setup('setup store settings @lite', async () => { + const [response] = await apiUtils.put(endPoints.updateSettings, { data: payloads.setupStore }); + expect(response.ok()).toBeTruthy(); + }); + + setup('create customer @lite', async () => { + const [, customerId] = await apiUtils.createCustomer(payloads.createCustomer1, payloads.adminAuth); + process.env.CUSTOMER_ID = customerId; + }); + + setup('create vendor @lite', async () => { + const [, sellerId] = await apiUtils.createStore(payloads.createStore1, payloads.adminAuth); + process.env.VENDOR_ID = sellerId; + }); + + // setup('set dokan general settings @lite', async () => { + // await dbUtils.setDokanSettings(dbData.dokan.optionName.general, { ...dbData.dokan.generalSettings, store_category_type: 'single' }); + // }); + + // setup('admin set dokan selling settings @lite', async () => { + // await dbUtils.setDokanSettings(dbData.dokan.optionName.selling, dbData.dokan.sellingSettings); + // }); + + // setup('admin set dokan withdraw settings @lite', async () => { + // await dbUtils.setDokanSettings(dbData.dokan.optionName.withdraw, dbData.dokan.withdrawSettings); + // }); + + // setup('admin set dokan reverse withdraw settings @lite', async () => { + // await dbUtils.setDokanSettings(dbData.dokan.optionName.reverseWithdraw, dbData.dokan.reverseWithdrawSettings); + // }); + + // setup('get test environment info @lite', async () => { + // const [, summaryInfo] = await apiUtils.getSystemStatus(); + // helpers.writeFile('systemInfo.json', JSON.stringify(summaryInfo)); + // }); +}); diff --git a/tests/pw/tests/api/abuseReports.spec.ts b/tests/pw/tests/api/abuseReports.spec.ts new file mode 100644 index 0000000000..192f4bdfca --- /dev/null +++ b/tests/pw/tests/api/abuseReports.spec.ts @@ -0,0 +1,50 @@ +//COVERAGE_TAG: GET /dokan/v1/abuse-reports/abuse-reasons +//COVERAGE_TAG: GET /dokan/v1/abuse-reports +//COVERAGE_TAG: DELETE /dokan/v1/abuse-reports/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/abuse-reports/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; + +const { VENDOR_ID, CUSTOMER_ID } = process.env; + +test.describe('abuse report api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + const [, productId] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendorAuth); + await dbUtils.createAbuseReport(dbData.dokan.createAbuseReport, productId, VENDOR_ID, CUSTOMER_ID); + await dbUtils.createAbuseReport(dbData.dokan.createAbuseReport, productId, VENDOR_ID, CUSTOMER_ID); + }); + + test('get all abuse report reasons @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllAbuseReportReasons); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all abuse reports @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllAbuseReports); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a abuse report @pro', async () => { + const abuseReportId = await apiUtils.getAbuseReportId(); + const [response, responseBody] = await apiUtils.delete(endPoints.deleteAbuseReport(abuseReportId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete batch abuse reports @pro', async () => { + const allAbuseReportIds = (await apiUtils.getAllAbuseReports())?.map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.delete(endPoints.deleteBatchAbuseReports, { data: { items: allAbuseReportIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/admins.spec.ts b/tests/pw/tests/api/admins.spec.ts new file mode 100644 index 0000000000..2a44cc5b6d --- /dev/null +++ b/tests/pw/tests/api/admins.spec.ts @@ -0,0 +1,82 @@ +//COVERAGE_TAG: GET /dokan/v1/admin/report/overview +//COVERAGE_TAG: GET /dokan/v1/admin/report/summary +//COVERAGE_TAG: GET /dokan/v1/admin/dashboard/feed +//COVERAGE_TAG: GET /dokan/v1/admin/help +//COVERAGE_TAG: GET /dokan/v1/admin/changelog/lite +//COVERAGE_TAG: GET /dokan/v1/admin/changelog/pro +//COVERAGE_TAG: GET /dokan/v1/admin/notices/admin +//COVERAGE_TAG: GET /dokan/v1/admin/notices/promo +//COVERAGE_TAG: GET /dokan/v1/admin/logs +//COVERAGE_TAG: GET /dokan/v1/admin/logs/export + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; + +test.describe('admin api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get admin report overview @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminReportOverview); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get admin report summary @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminReportSummary); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get admin dashboard feed @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminDashboardFeed); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get admin help @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminHelp); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get changelog lite @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminChangelogLite); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get changelog pro @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminChangelogPro); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get admin notices @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminNotices); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get admin promo notices @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminPromoNotices); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get admin logs @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminLogs); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get admin export logs @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAdminExportLogs); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/announcements.spec.ts b/tests/pw/tests/api/announcements.spec.ts new file mode 100644 index 0000000000..149e8db445 --- /dev/null +++ b/tests/pw/tests/api/announcements.spec.ts @@ -0,0 +1,68 @@ +//COVERAGE_tag: GET /dokan/v1/announcement +//COVERAGE_TAG: GET /dokan/v1/announcement/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/announcement +//COVERAGE_TAG: POST /dokan/v1/announcement/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/announcement/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/announcement/(?P[\d]+)/restore +//COVERAGE_TAG: PUT /dokan/v1/announcement/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('announcements api test', () => { + let apiUtils: ApiUtils; + let announcementId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, announcementId] = await apiUtils.createAnnouncement(payloads.createAnnouncement()); + }); + + test('get all announcements @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllAnnouncements); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single announcement @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleAnnouncement(announcementId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a announcement @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createAnnouncement, { data: payloads.createAnnouncement() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a announcement @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateAnnouncement(announcementId), { data: payloads.updateAnnouncement }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a announcement @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteAnnouncement(announcementId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('restore a deleted announcement @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.restoreDeletedAnnouncement(announcementId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch announcements @pro', async () => { + const allAnnouncementIds = (await apiUtils.getAllAnnouncements()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchAnnouncements, { data: { trash: allAnnouncementIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + + // restore all announcements + await apiUtils.updateBatchAnnouncements('restore', allAnnouncementIds); + }); +}); diff --git a/tests/pw/tests/api/attributeTerms.spec.ts b/tests/pw/tests/api/attributeTerms.spec.ts new file mode 100644 index 0000000000..0c4f6661ae --- /dev/null +++ b/tests/pw/tests/api/attributeTerms.spec.ts @@ -0,0 +1,65 @@ +//COVERAGE_TAG: GET /dokan/v1/products/attributes/(?P[\d]+)/terms +//COVERAGE_TAG: GET /dokan/v1/products/attributes/(?P[\d]+)/terms/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/products/attributes/(?P[\d]+)/terms +//COVERAGE_TAG: PUT /dokan/v1/products/attributes/(?P[\d]+)/terms/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/products/attributes/(?P[\d]+)/terms/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/products/attributes/(?P[\d]+)/terms/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('attribute term api test', () => { + let apiUtils: ApiUtils; + let attributeId: string; + let attributeTermId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, attributeId, attributeTermId] = await apiUtils.createAttributeTerm(payloads.createAttribute(), payloads.createAttributeTerm()); + }); + + test('get all attribute terms @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllAttributeTerms(attributeId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single attribute term @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleAttributeTerm(attributeId, attributeTermId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create an attribute term @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createAttributeTerm(attributeId), { data: payloads.createAttributeTerm() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update an attribute term @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateAttributeTerm(attributeId, attributeTermId), { data: payloads.updateAttributeTerm() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete an attribute term @lite', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteAttributeTerm(attributeId, attributeTermId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch attribute terms @lite', async () => { + const allAttributeTermIds = (await apiUtils.getAllAttributeTerms(attributeId)).map((a: { id: unknown }) => a.id); + + const batchAttributeTerms: object[] = []; + for (const attributeTermId of allAttributeTermIds.slice(0, 2)) { + batchAttributeTerms.push({ ...payloads.updateBatchAttributesTemplate(), id: attributeTermId }); + } + + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchAttributeTerms(attributeId), { data: { update: batchAttributeTerms } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/attributes.spec.ts b/tests/pw/tests/api/attributes.spec.ts new file mode 100644 index 0000000000..3f95ae64c8 --- /dev/null +++ b/tests/pw/tests/api/attributes.spec.ts @@ -0,0 +1,112 @@ +//COVERAGE_TAG: GET /dokan/v1/products/attributes +//COVERAGE_TAG: GET /dokan/v1/products/attributes/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/products/attributes +//COVERAGE_TAG: PUT /dokan/v1/products/attributes/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/products/attributes/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/products/attributes/batch +//COVERAGE_TAG: PUT /dokan/v1/products/attributes/set-default/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/products/attributes/edit-product/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('attribute api test', () => { + let apiUtils: ApiUtils; + let productId: string; + let attributeId: string; + let attribute: any; + let attributeTerm: any; + let attributeTermId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, productId] = await apiUtils.createProduct(payloads.createProduct()); + [attributeTerm, attributeId, attributeTermId] = await apiUtils.createAttributeTerm(payloads.createAttribute(), payloads.createAttributeTerm()); + attribute = await apiUtils.getSingleAttribute(attributeId); + }); + + test('get all attributes @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllAttributes); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single attribute @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleAttribute(attributeId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create an attribute @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createAttribute, { data: payloads.createAttribute() }); + expect(response.status()).toBe(201); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update an attribute @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateAttribute(attributeId), { data: payloads.updateAttribute() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete an attribute @lite', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteAttribute(attributeId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch attributes @lite', async () => { + const allAttributeIds = (await apiUtils.getAllAttributes()).map((a: { id: unknown }) => a.id); + + const batchAttributes: object[] = []; + for (const attributeId of allAttributeIds.slice(0, 2)) { + batchAttributes.push({ ...payloads.updateBatchAttributesTemplate(), id: attributeId }); + } + + const [response, responseBody] = await apiUtils.put(endPoints.batchUpdateAttributes, { data: { update: batchAttributes } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('set default attribute @lite', async () => { + const payload = { + id: attribute.id, + name: attribute.name, + option: attributeTerm.name, + options: [], + }; + const [response, responseBody] = await apiUtils.put(endPoints.setDefaultAttribute(productId), { data: { attributes: [payload] } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update product attribute @lite', async () => { + const payload = { + attributes: [ + { + all_terms: [ + { + label: attributeTerm.name, + slug: attributeTerm.slug, + taxonomy: attribute.slug, + value: attributeTerm.id, + }, + ], + id: attribute.id, + name: attribute.name, + options: [attributeTerm.name], + slug: attribute.slug, + taxonomy: true, + variation: false, + visible: true, + }, + ], + }; + const [response, responseBody] = await apiUtils.post(endPoints.updateProductAttribute(productId), { data: payload }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/calculation.spec.ts b/tests/pw/tests/api/calculation.spec.ts new file mode 100644 index 0000000000..edc0a373b3 --- /dev/null +++ b/tests/pw/tests/api/calculation.spec.ts @@ -0,0 +1,70 @@ +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { helpers } from '@utils/helpers'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; + +test.describe('calculation test', () => { + let apiUtils: ApiUtils; + let taxRate: number; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + taxRate = await apiUtils.setUpTaxRate(payloads.enableTaxRate, payloads.createTaxRate); + // todo: get tax rate instead of setup if possible + }); + + test('calculation test @pro', async () => { + // todo: modify for lite as well + const [commission, feeRecipient] = await dbUtils.getSellingInfo(); + + const [, res, oid] = await apiUtils.createOrder(payloads.createProduct(), payloads.createOrder); + // console.log( res ); + console.log('Cal: order id:', oid); + + // const discountTotal = res.discount_total; + // const discountTax = res.discount_tax; + const shippingFee = res.shipping_total; + const shippingTax = res.shipping_tax; + const cartTax = res.cart_tax; + const totalTax = res.total_tax; + const orderTotal = res.total; + const gatewayFee = 0; + // const paymentMethod = res.payment_method_ti; + const productPrice = res.line_items[0].subtotal; + const productQuantity = res.line_items[0].quantity; + + const orderReport = await apiUtils.getSingleOrderLog(String(oid)); + // console.log(orderReport); + const adminCommission = orderReport.commission; + const vendorEarning = orderReport.vendor_earning; + // todo: compare with all order total + // todo: add discount scenario + + const calculatedSubTotal = helpers.subtotal([productPrice], [productQuantity]); // todo: update it for multiple products + const calculatedProductTax = helpers.productTax(taxRate, calculatedSubTotal); + const calculatedShippingTax = helpers.shippingTax(taxRate, shippingFee); + const calculatedTotalTax = helpers.roundToTwo(calculatedProductTax + calculatedShippingTax); + const calculatedOrderTotal = helpers.orderTotal(calculatedSubTotal, calculatedProductTax, calculatedShippingTax, shippingFee); + const calculatedAdminCommission = helpers.adminCommission(calculatedSubTotal, commission, calculatedProductTax, calculatedShippingTax, shippingFee, gatewayFee, feeRecipient); + const calculatedVendorEarning = helpers.vendorEarning(calculatedSubTotal, calculatedAdminCommission, calculatedProductTax, calculatedShippingTax, shippingFee, gatewayFee, feeRecipient); + + console.log( + `\ncalculatedSubTotal: ${calculatedSubTotal}\n`, + `calculatedOrderTotal: ${calculatedOrderTotal}\n`, + `calculatedVendorEarning: ${calculatedVendorEarning}\n`, + `calculatedAdminCommission: ${calculatedAdminCommission}\n`, + `providedShippingFee: ${shippingFee}\n`, + `calculatedShippingTax: ${calculatedShippingTax}\n`, + `calculatedProductTax: ${calculatedProductTax}\n`, + `calculatedTotalTax: ${calculatedTotalTax}\n`, + ); + + expect(calculatedProductTax).toEqual(Number(cartTax)); + expect(calculatedShippingTax).toEqual(Number(shippingTax)); + expect(calculatedTotalTax).toEqual(Number(totalTax)); + expect(calculatedOrderTotal).toEqual(Number(orderTotal)); + expect(calculatedAdminCommission).toEqual(Number(adminCommission)); + expect(calculatedVendorEarning).toEqual(Number(vendorEarning)); + }); +}); diff --git a/tests/pw/tests/api/coupons.spec.ts b/tests/pw/tests/api/coupons.spec.ts new file mode 100644 index 0000000000..326123aa43 --- /dev/null +++ b/tests/pw/tests/api/coupons.spec.ts @@ -0,0 +1,52 @@ +//COVERAGE_TAG: GET /dokan/v1/coupons +//COVERAGE_TAG: GET /dokan/v1/coupons/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/coupons +//COVERAGE_TAG: PUT /dokan/v1/coupons/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/coupons/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('coupon api test', () => { + let apiUtils: ApiUtils; + let couponId: string; + let productId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, productId] = await apiUtils.createProduct(payloads.createProduct()); + [, couponId] = await apiUtils.createCoupon([productId], payloads.createCoupon()); + }); + + test('get all coupons @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllCoupons); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single coupon @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleCoupon(couponId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a coupon @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createCoupon, { data: { ...payloads.createCoupon(), product_ids: productId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a coupon @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateCoupon(couponId), { data: payloads.updateCoupon() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a coupon @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteCoupon(couponId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/customers.spec.ts b/tests/pw/tests/api/customers.spec.ts new file mode 100644 index 0000000000..fa3ca036bb --- /dev/null +++ b/tests/pw/tests/api/customers.spec.ts @@ -0,0 +1,65 @@ +//COVERAGE_TAG: GET /dokan/v1/request-for-quote/customers +//COVERAGE_TAG: GET /dokan/v1/request-for-quote/customers/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/request-for-quote/customers +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/customers/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/request-for-quote/customers/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/customers/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('customers api test', () => { + let apiUtils: ApiUtils; + let customerId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, customerId] = await apiUtils.createCustomer(payloads.createCustomer()); + }); + + test('get all customers @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllCustomers); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single customer @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleCustomer(customerId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a customer @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createCustomer, { data: payloads.createCustomer() }); + expect(response.status()).toBe(201); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a customer @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateCustomer(customerId), { data: payloads.updateCustomer() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a customer @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteCustomer(customerId), { params: payloads.paramsForceDelete }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch customers @pro', async () => { + const allCustomerIds = (await apiUtils.getAllCustomers()).map((a: { id: unknown }) => a.id); + + const batchCustomers: object[] = []; + for (const customerId of allCustomerIds.slice(0, 2)) { + batchCustomers.push({ ...payloads.updateBatchCustomersTemplate(), id: customerId }); + } + + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchCustomers, { data: { update: batchCustomers } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/dokanEndpoints.spec.ts b/tests/pw/tests/api/dokanEndpoints.spec.ts new file mode 100644 index 0000000000..d6ea9ecf0b --- /dev/null +++ b/tests/pw/tests/api/dokanEndpoints.spec.ts @@ -0,0 +1,33 @@ +//COVERAGE_TAG: GET /dokan/v1 +//COVERAGE_TAG: GET /dokan/v1/admin +//COVERAGE_TAG: GET /dokan/v2 + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; + +test.describe('dokan api endpoints test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get all dokan v1 endpoints @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllDokanEndpointsV1); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all dokan v2 endpoints @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllDokanEndpointsV2); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all dokan v1 admin endpoints @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllDokanEndpointsAdmin); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/dummyData.spec.ts b/tests/pw/tests/api/dummyData.spec.ts new file mode 100644 index 0000000000..d1d7ea86fa --- /dev/null +++ b/tests/pw/tests/api/dummyData.spec.ts @@ -0,0 +1,34 @@ +//COVERAGE_TAG: GET /dokan/v1/dummy-data/status +//COVERAGE_TAG: POST /dokan/v1/dummy-data/import +//COVERAGE_TAG: DELETE /dokan/v1/dummy-data/clear + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('dummy Data api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get dummy data status @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getDummyDataStatus); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('import dummy data @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.importDummyData, { data: payloads.dummyData }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('clear dummy data @lite', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.clearDummyData); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/followStores.spec.ts b/tests/pw/tests/api/followStores.spec.ts new file mode 100644 index 0000000000..e2252eefc4 --- /dev/null +++ b/tests/pw/tests/api/followStores.spec.ts @@ -0,0 +1,38 @@ +//COVERAGE_TAG: GET /dokan/v1/follow-store +//COVERAGE_TAG: POST /dokan/v1/follow-store +//COVERAGE_TAG: GET /dokan/v1/follow-store/followers + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +// import { payloads } from '@utils/payloads'; + +test.describe('follow store api test', () => { + let apiUtils: ApiUtils; + let sellerId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + // [, sellerId,] = await apiUtils.createStore(payloads.createStore()); + [, sellerId] = await apiUtils.getCurrentUser(); + // await apiUtils.followUnfollowStore(sellerId); + }); + + test('get store follow status @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getStoreFollowStatus, { params: { vendor_id: sellerId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('follow-unfollow a store @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.followUnfollowStore, { data: { vendor_id: Number(sellerId) } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get followers @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getFollowers); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/modules.spec.ts b/tests/pw/tests/api/modules.spec.ts new file mode 100644 index 0000000000..f45254fb3c --- /dev/null +++ b/tests/pw/tests/api/modules.spec.ts @@ -0,0 +1,39 @@ +//COVERAGE_TAG: GET /dokan/v1/admin/modules +//COVERAGE_TAG: PUT /dokan/v1/admin/modules/deactivate +//COVERAGE_TAG: PUT /dokan/v1/admin/modules/activate + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { helpers } from '@utils/helpers'; + +test.describe('modules api test', () => { + let apiUtils: ApiUtils; + let randomModule: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + randomModule = helpers.randomItem(await apiUtils.getAllModuleIds()); + }); + + test('get all modules @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllModules); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('deactivate a module @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.deactivateModule, { data: { module: [randomModule] } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + + // reactivate module + // await apiUtils.activateModules(randomModule) + }); + + test('activate a module @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.activateModule, { data: { module: [randomModule] } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/orderDownloads.spec.ts b/tests/pw/tests/api/orderDownloads.spec.ts new file mode 100644 index 0000000000..70f7596045 --- /dev/null +++ b/tests/pw/tests/api/orderDownloads.spec.ts @@ -0,0 +1,48 @@ +//COVERAGE_TAG: GET /dokan/v2/orders/(?P[\d]+)/downloads +//COVERAGE_TAG: POST /dokan/v2/orders/(?P[\d]+)/downloads +//COVERAGE_TAG: DELETE /dokan/v2/orders/(?P[\d]+)/downloads + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('order downloads api test', () => { + let apiUtils: ApiUtils; + let downloadableProductId: string; + let orderId: string; + let downloadId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + const [responseBody] = await apiUtils.uploadMedia('../../tests/pw/utils/sampleData/avatar.png', payloads.mimeTypes.png, payloads.adminAuth); // todo: update image path + const downloads = [ + { + id: String(responseBody.id), + name: responseBody.title.raw, + file: responseBody.source_url, + }, + ]; + [, downloadableProductId] = await apiUtils.createProduct({ ...payloads.createDownloadableProduct(), downloads }); + [, , orderId] = await apiUtils.createOrder(payloads.createProduct(), payloads.createOrder); + [, downloadId] = await apiUtils.createOrderDownload(orderId, [downloadableProductId]); + }); + + test('get all order downloads @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllOrderDownloads(orderId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create order downloads @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createOrderDownload(orderId), { data: { ids: [downloadableProductId] } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete order downloads @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteOrderDownload(orderId), { data: { permission_id: downloadId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/orderNotes.spec.ts b/tests/pw/tests/api/orderNotes.spec.ts new file mode 100644 index 0000000000..d5a8a5a42f --- /dev/null +++ b/tests/pw/tests/api/orderNotes.spec.ts @@ -0,0 +1,49 @@ +//COVERAGE_TAG: GET /dokan/v1/orders/(?P[\d]+)/notes +//COVERAGE_TAG: GET /dokan/v1/orders/(?P[\d]+)/notes/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/orders/(?P[\d]+)/notes +//COVERAGE_TAG: DELETE /dokan/v1/orders/(?P[\d]+)/notes/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v2/orders/(?P[\d]+)/notes +//COVERAGE_TAG: GET /dokan/v2/orders/(?P[\d]+)/notes/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v2/orders/(?P[\d]+)/notes +//COVERAGE_TAG: DELETE /dokan/v2/orders/(?P[\d]+)/notes/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('order note api test', () => { + let apiUtils: ApiUtils; + let orderId: string; + let orderNoteId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, orderId, orderNoteId] = await apiUtils.createOrderNote(payloads.createProduct(), payloads.createOrder, payloads.createOrderNote); + }); + + test('get all order notes @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllOrderNotes(orderId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single order note @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleOrderNote(orderId, orderNoteId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create an order note @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createOrderNote(orderId), { data: payloads.createOrderNote }); + expect(response.status()).toBe(201); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete an order note @lite', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteOrderNote(orderId, orderNoteId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/orders.spec.ts b/tests/pw/tests/api/orders.spec.ts new file mode 100644 index 0000000000..2ff62f1930 --- /dev/null +++ b/tests/pw/tests/api/orders.spec.ts @@ -0,0 +1,65 @@ +//COVERAGE_TAG: GET /dokan/v1/orders +//COVERAGE_TAG: GET /dokan/v1/orders/summary +//COVERAGE_TAG: GET /dokan/v1/orders/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/orders/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v2/orders +//COVERAGE_TAG: GET /dokan/v2/orders/summary +//COVERAGE_TAG: GET /dokan/v2/orders/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v2/orders/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v2/orders/bulk-actions + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +let apiUtils: ApiUtils; + +const versions = ['v1', 'v2']; +for (const version of versions) { + test.describe(`order api test ${version}`, () => { + let orderId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, , orderId] = await apiUtils.createOrder(payloads.createProduct(), payloads.createOrder); + }); + + test('get all orders @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllOrders.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get orders summary @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getOrdersSummary.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get orders with param date-range @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllOrders.replace('v1', version), { params: payloads.paramsGetOrdersWithDateRange }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single order @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleOrder(orderId).replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update an order @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateOrder(orderId).replace('v1', version), { data: payloads.updateOrder }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + }); +} + +test('update batch orders @v2 @lite', async () => { + const allOrderIds = (await apiUtils.getAllOrders())?.map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.post(endPoints.updateBatchOrders, { data: { order_ids: allOrderIds, status: 'wc-completed' } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); +}); diff --git a/tests/pw/tests/api/productAdvertisements.spec.ts b/tests/pw/tests/api/productAdvertisements.spec.ts new file mode 100644 index 0000000000..424f1e7748 --- /dev/null +++ b/tests/pw/tests/api/productAdvertisements.spec.ts @@ -0,0 +1,60 @@ +//COVERAGE_TAG: GET /dokan/v1/product_adv/stores +//COVERAGE_TAG: GET /dokan/v1/product_adv +//COVERAGE_TAG: POST /dokan/v1/product_adv/create +//COVERAGE_TAG: PUT /dokan/v1/product_adv/(?P[\d]+)/expire +//COVERAGE_TAG: DELETE /dokan/v1/product_adv/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/product_adv/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('product advertisement api test', () => { + let apiUtils: ApiUtils; + let productAdvertisementId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, productAdvertisementId] = await apiUtils.createProductAdvertisement(payloads.createProduct()); + }); + + test('get all advertised product stores @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllProductAdvertisementStores); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all advertised product @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllProductAdvertisements); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a product advertisement @pro', async () => { + const [body, productId] = await apiUtils.createProduct(payloads.createProduct()); + const sellerId = body.store.id; + const [response, responseBody] = await apiUtils.post(endPoints.createProductAdvertisement, { data: { vendor_id: sellerId, product_id: productId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('expire a product advertisement @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.expireProductAdvertisement(productAdvertisementId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a product advertisement @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteProductAdvertisement(productAdvertisementId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch product advertisements @pro', async () => { + const allProductAdvertisementIds = (await apiUtils.getAllProductAdvertisements()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchProductAdvertisements, { data: { ids: allProductAdvertisementIds, action: 'delete' } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/productBlock.spec.ts b/tests/pw/tests/api/productBlock.spec.ts new file mode 100644 index 0000000000..45c3628f8e --- /dev/null +++ b/tests/pw/tests/api/productBlock.spec.ts @@ -0,0 +1,31 @@ +//COVERAGE_TAG: GET /dokan/v1/blocks/products/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v1/blocks/product-variation/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('product block api test', () => { + let apiUtils: ApiUtils; + let productId: string; + let variationId: string; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get product block details @lite', async () => { + [, productId] = await apiUtils.createProduct(payloads.createDownloadableProduct()); + const [response, responseBody] = await apiUtils.get(endPoints.getProductBlockDetails(productId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get variable product block details @pro', async () => { + [, variationId] = await apiUtils.createVariableProductWithVariation(payloads.createAttribute(), payloads.createAttributeTerm(), payloads.createVariableProduct()); + const [response, responseBody] = await apiUtils.get(endPoints.getProductBlockDetails(variationId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/productDuplicate.spec.ts b/tests/pw/tests/api/productDuplicate.spec.ts new file mode 100644 index 0000000000..4dc9959f81 --- /dev/null +++ b/tests/pw/tests/api/productDuplicate.spec.ts @@ -0,0 +1,22 @@ +//COVERAGE_TAG: POST /dokan/v2/products/(?P[\d]+)/duplicate + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('product duplicate api test', () => { + let apiUtils: ApiUtils; + let productId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, productId] = await apiUtils.createProduct(payloads.createProduct()); + }); + + test('create duplicate product @v2 @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createDuplicateProduct(productId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/productFilter.spec.ts b/tests/pw/tests/api/productFilter.spec.ts new file mode 100644 index 0000000000..b6de2634b9 --- /dev/null +++ b/tests/pw/tests/api/productFilter.spec.ts @@ -0,0 +1,21 @@ +//COVERAGE_TAG: GET /dokan/v2/products/filter-by-data + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('product filter api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + await apiUtils.createProduct(payloads.createProduct()); + }); + + test('get products filter by data @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getProductsFilterByData); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/productReviews.spec.ts b/tests/pw/tests/api/productReviews.spec.ts new file mode 100644 index 0000000000..4ad9cf46b5 --- /dev/null +++ b/tests/pw/tests/api/productReviews.spec.ts @@ -0,0 +1,36 @@ +//COVERAGE_TAG: GET /dokan/v1/reviews +//COVERAGE_TAG: GET /dokan/v1/reviews/summary +//COVERAGE_TAG: PUT /dokan/v1/reviews/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('product review api test', () => { + let apiUtils: ApiUtils; + let reviewId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, reviewId] = await apiUtils.createProductReview(payloads.createProduct(), payloads.createProductReview()); + }); + + test('get all product reviews @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllProductReviews); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get product reviews summary @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getProductReviewSummary); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a product review @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateStoreReview(reviewId), { data: payloads.updateProductReview }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/productVariations.spec.ts b/tests/pw/tests/api/productVariations.spec.ts new file mode 100644 index 0000000000..5d927e9222 --- /dev/null +++ b/tests/pw/tests/api/productVariations.spec.ts @@ -0,0 +1,65 @@ +//COVERAGE_TAG: GET /dokan/v1/products/(?P[\d]+)/variations +//COVERAGE_TAG: GET /dokan/v1/products/(?P[\d]+)/variations/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/products/(?P[\d]+)/variations +//COVERAGE_TAG: PUT /dokan/v1/products/(?P[\d]+)/variations/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/products/(?P[\d]+)/variations/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/products/(?P[\d]+)/variations/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('product variation api test', () => { + test.use({ extraHTTPHeaders: { Authorization: payloads.adminAuth.Authorization } }); + + let apiUtils: ApiUtils; + let productId: string; + let variationId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [productId, variationId] = await apiUtils.createVariableProductWithVariation(payloads.createAttribute(), payloads.createAttributeTerm(), payloads.createVariableProduct()); + }); + + test('get all product variations @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllProductVariations(productId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single product variation @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleProductVariation(productId, variationId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a product variation @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createProductVariation(productId), { data: payloads.createProductVariation }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a product variation @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateProductVariation(productId, variationId), { data: payloads.updateProductVariation() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a product variation @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteProductVariation(productId, variationId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch product variations @pro', async () => { + test.skip(true, 'fatal error exists'); + const [productId] = await apiUtils.createVariableProductWithVariation(payloads.createAttribute(), payloads.createAttributeTerm(), payloads.createVariableProduct()); + // console.log(productId); + // console.log({ ...payloads.batchProductVariation, id: productId }); + const [response, responseBody] = await apiUtils.put(endPoints.batchUpdateProductVariations(productId), { data: { update: { ...payloads.batchProductVariation, id: productId } } }); + // console.log(responseBody); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/products.spec.ts b/tests/pw/tests/api/products.spec.ts new file mode 100644 index 0000000000..4c92280455 --- /dev/null +++ b/tests/pw/tests/api/products.spec.ts @@ -0,0 +1,121 @@ +//COVERAGE_TAG: GET /dokan/v1/products/summary +//COVERAGE_TAG: GET /dokan/v1/products/top_rated +//COVERAGE_TAG: GET /dokan/v1/products/best_selling +//COVERAGE_TAG: GET /dokan/v1/products/featured +//COVERAGE_TAG: GET /dokan/v1/products/latest +//COVERAGE_TAG: GET /dokan/v1/products/multistep-categories +//COVERAGE_TAG: GET /dokan/v1/products +//COVERAGE_TAG: GET /dokan/v1/products/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v1/products/(?P[\d]+)/related +//COVERAGE_TAG: POST /dokan/v1/products +//COVERAGE_TAG: PUT /dokan/v1/products/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/products/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v2/products/summary +//COVERAGE_TAG: GET /dokan/v2/products/top_rated +//COVERAGE_TAG: GET /dokan/v2/products/best_selling +//COVERAGE_TAG: GET /dokan/v2/products/featured +//COVERAGE_TAG: GET /dokan/v2/products/latest +//COVERAGE_TAG: GET /dokan/v2/products/multistep-categories +//COVERAGE_TAG: GET /dokan/v2/products +//COVERAGE_TAG: GET /dokan/v2/products/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v2/products/(?P[\d]+)/related +//COVERAGE_TAG: POST /dokan/v2/products +//COVERAGE_TAG: PUT /dokan/v2/products/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v2/products/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +const versions = ['v1', 'v2']; + +for (const version of versions) { + test.describe(`product api test ${version}`, () => { + let apiUtils: ApiUtils; + let productId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, productId] = await apiUtils.createProduct(payloads.createProduct()); + }); + + test('get products summary @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getProductsSummary.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get top rated products @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getTopRatedProducts.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get best selling products @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getBestSellingProducts.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get featured products @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getFeaturedProducts.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get latest products @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getLatestProducts.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all multiStep categories @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllMultiStepCategories.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all products @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllProducts.replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single product @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleProduct(productId).replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all related products @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllRelatedProducts(productId).replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a product @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createProduct.replace('v1', version), { data: payloads.createProduct() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a product @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateProduct(productId).replace('v1', version), { data: payloads.updateProduct() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a product @lite', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteProduct(productId).replace('v1', version)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get filtered products @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllProducts.replace('v1', version), { params: payloads.filterParams }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + }); +} diff --git a/tests/pw/tests/api/quoteRequests.spec.ts b/tests/pw/tests/api/quoteRequests.spec.ts new file mode 100644 index 0000000000..19f720e3b6 --- /dev/null +++ b/tests/pw/tests/api/quoteRequests.spec.ts @@ -0,0 +1,75 @@ +//COVERAGE_TAG: GET /dokan/v1/request-for-quote +//COVERAGE_TAG: GET /dokan/v1/request-for-quote/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/request-for-quote +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/request-for-quote/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/(?P[\d]+)/restore +//COVERAGE_TAG: POST /dokan/v1/request-for-quote/convert-to-order +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('request quote api test', () => { + let apiUtils: ApiUtils; + let requestQuoteId: string; + const productId: string[] = []; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + const [, pId] = await apiUtils.createProduct(payloads.createProduct()); + productId.push(pId); + [, requestQuoteId] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId }); + }); + + test('get all request quotes @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllQuoteRequests); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single request quote @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleRequestQuote(requestQuoteId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a request quote @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createQuoteRequest, { data: { ...payloads.createQuoteRequest(), product_ids: productId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a request quote @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateRequestQuote(requestQuoteId), { data: { ...payloads.updateRequestQuote, product_ids: productId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a request quote @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteQuoteRequest(requestQuoteId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('restore a deleted request quote @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.restoreRequestQuote(requestQuoteId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('convert request quote to order @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.convertRequestQuoteToOrder, { data: { ...payloads.convertToOrder, quote_id: requestQuoteId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch request quote @pro ', async () => { + const allRequestQuoteIds = (await apiUtils.getAllQuoteRequests()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchRequestQuotes, { data: { trash: allRequestQuoteIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/quoteRules.spec.ts b/tests/pw/tests/api/quoteRules.spec.ts new file mode 100644 index 0000000000..021d71e773 --- /dev/null +++ b/tests/pw/tests/api/quoteRules.spec.ts @@ -0,0 +1,65 @@ +//COVERAGE_TAG: GET /dokan/v1/request-for-quote/quote-rule +//COVERAGE_TAG: GET /dokan/v1/request-for-quote/quote-rule/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/request-for-quote/quote-rule +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/quote-rule/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/request-for-quote/quote-rule/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/quote-rule/(?P[\d]+)/restore +//COVERAGE_TAG: PUT /dokan/v1/request-for-quote/quote-rule/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('quote rules api test', () => { + let apiUtils: ApiUtils; + let quoteRuleId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, quoteRuleId] = await apiUtils.createQuoteRule(payloads.createQuoteRule()); + }); + + test('get all quote rules @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllQuoteRules); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single quote rule @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleQuoteRule(quoteRuleId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a quote rule @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createQuoteRule, { data: payloads.createQuoteRule() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a quote rule @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateQuoteRule(quoteRuleId), { data: payloads.updateQuoteRule }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a quote rule @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteQuoteRule(quoteRuleId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('restore a deleted quote rule @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.restoreQuoteRule(quoteRuleId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch quote rules @pro', async () => { + const allQuoteRuleIds = (await apiUtils.getAllQuoteRules()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchQuoteRules, { data: { trash: allQuoteRuleIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/rankMath.spec.ts b/tests/pw/tests/api/rankMath.spec.ts new file mode 100644 index 0000000000..dbf58c8502 --- /dev/null +++ b/tests/pw/tests/api/rankMath.spec.ts @@ -0,0 +1,23 @@ +//COVERAGE_TAG: POST /dokan/v2/(?P[\d]+)/store-current-editable-post + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe.skip('rank math api test', () => { + let apiUtils: ApiUtils; + let productId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, productId] = await apiUtils.createProduct(payloads.createProduct()); + }); + + test('rank math @pro', async () => { + test.skip(!!process.env.CI, 'feature not merged yet!'); + const [response, responseBody] = await apiUtils.post(endPoints.rankMath(productId), { data: {} }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/refunds.spec.ts b/tests/pw/tests/api/refunds.spec.ts new file mode 100644 index 0000000000..def02a6dc9 --- /dev/null +++ b/tests/pw/tests/api/refunds.spec.ts @@ -0,0 +1,63 @@ +//COVERAGE_TAG: GET /dokan/v1/refunds +//COVERAGE_TAG: PUT /dokan/v1/refunds/(?P[\d]+)/cancel +//COVERAGE_TAG: DELETE /dokan/v1/refunds/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/refunds/(?P[\d]+)/approve +//COVERAGE_TAG: PUT /dokan/v1/refunds/batch + +import { test, expect, APIResponse } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('refunds api test', () => { + let apiUtils: ApiUtils; + // let orderId: string; + let refundId: string; + let orderResponseBody: APIResponse; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, orderResponseBody] = await apiUtils.createOrderWithStatus(payloads.createProduct(), payloads.createOrder, 'wc-processing', payloads.vendorAuth); + [, refundId] = await dbUtils.createRefund(orderResponseBody); + }); + + test('get all refunds @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllRefunds, { headers: payloads.vendorAuth }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all refunds by status @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllRefunds, { params: { status: 'pending' }, headers: payloads.vendorAuth }); // pending, cancelled, completed + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('cancel a refund @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.cancelRefund(refundId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a refund @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteRefund(refundId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('approve a refund @pro', async () => { + const [, refundId] = await dbUtils.createRefund(orderResponseBody); + const [response, responseBody] = await apiUtils.put(endPoints.approveRefund(refundId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch refunds @pro', async () => { + await dbUtils.createRefund(orderResponseBody); + const allPendingRefundsIds = (await apiUtils.getAllRefunds('pending', payloads.vendorAuth)).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchRefunds, { data: { cancelled: allPendingRefundsIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/reports.spec.ts b/tests/pw/tests/api/reports.spec.ts new file mode 100644 index 0000000000..e579472bd1 --- /dev/null +++ b/tests/pw/tests/api/reports.spec.ts @@ -0,0 +1,42 @@ +//COVERAGE_TAG: GET /dokan/v1/reports/sales_overview +//COVERAGE_TAG: GET /dokan/v1/reports/summary +//COVERAGE_TAG: GET /dokan/v1/reports/top_earners +//COVERAGE_TAG: GET /dokan/v1/reports/top_selling + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('report api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + await apiUtils.createOrder(payloads.createProduct(), payloads.createOrder); + }); + + test('get sales overview report @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSalesOverviewReport); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get summary report @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSummaryReport); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get top earners report @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getTopEarnersReport); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get top selling products report @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getTopSellingProductsReport); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/reverseWithdrawal.spec.ts b/tests/pw/tests/api/reverseWithdrawal.spec.ts new file mode 100644 index 0000000000..984a1eb36c --- /dev/null +++ b/tests/pw/tests/api/reverseWithdrawal.spec.ts @@ -0,0 +1,67 @@ +//COVERAGE_TAG: GET /dokan/v1/reverse-withdrawal/transaction-types +//COVERAGE_TAG: GET /dokan/v1/reverse-withdrawal/stores +//COVERAGE_TAG: GET /dokan/v1/reverse-withdrawal/stores-balance +//COVERAGE_TAG: GET /dokan/v1/reverse-withdrawal/transactions +//COVERAGE_TAG: GET /dokan/v1/reverse-withdrawal/vendor-due-status +//COVERAGE_TAG: POST /dokan/v1/reverse-withdrawal/add-to-cart + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { dbData } from '@utils/dbData'; + +test.describe('reverse withdrawal api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + await dbUtils.setDokanSettings(dbData.dokan.optionName.reverseWithdraw, dbData.dokan.reverseWithdrawSettings); + + const [, , orderId] = await apiUtils.createOrderWithStatus(payloads.createProduct(), payloads.createOrderCod, data.order.orderStatus.processing, payloads.vendorAuth); + await apiUtils.updateOrderStatus(orderId, data.order.orderStatus.completed, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.reverseWithdraw, { ...dbData.dokan.reverseWithdrawSettings, enabled: 'off' }); + }); + + test('get reverse withdrawal transaction types @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getReverseWithdrawalTransactionTypes); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all reverse withdrawal stores @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllReverseWithdrawalStores); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all reverse withdrawal store balance @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllReverseWithdrawalStoreBalance); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all reverse withdrawal transactions @lite', async () => { + const storeId = await apiUtils.getReverseWithdrawalStoreId(); + const [response, responseBody] = await apiUtils.get(endPoints.getAllReverseWithdrawalTransactions, { params: { ...payloads.paramsReverseWithdrawalTransactions, vendor_id: storeId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get reverse withdrawal vendor due status @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getReverseWithdrawalVendorDueStatus); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('add reverse withdrawal payment product to cart @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.getReverseWithdrawalAddProductToCart, { data: payloads.amountToPay, headers: payloads.vendorAuth }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/roles.spec.ts b/tests/pw/tests/api/roles.spec.ts new file mode 100644 index 0000000000..8547061dbe --- /dev/null +++ b/tests/pw/tests/api/roles.spec.ts @@ -0,0 +1,19 @@ +//COVERAGE_TAG: GET /dokan/v1/request-for-quote/roles + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; + +test.describe('roles api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get all user roles @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllUserRoles); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/sellerBadge.spec.ts b/tests/pw/tests/api/sellerBadge.spec.ts new file mode 100644 index 0000000000..6d31b9c4a1 --- /dev/null +++ b/tests/pw/tests/api/sellerBadge.spec.ts @@ -0,0 +1,97 @@ +//COVERAGE_TAG: GET /dokan/v1/seller-badge/verification-types +//COVERAGE_TAG: GET /dokan/v1/seller-badge/events +//COVERAGE_TAG: GET /dokan/v1/seller-badge +//COVERAGE_TAG: GET /dokan/v1/seller-badge/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v1/seller-badge/vendor-unseen-badges +//COVERAGE_TAG: PUT /dokan/v1/seller-badge/set-badge-as-seen +//COVERAGE_TAG: POST /dokan/v1/seller-badge +//COVERAGE_TAG: PUT /dokan/v1/seller-badge/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/seller-badge/row-actions +//COVERAGE_TAG: DELETE /dokan/v1/seller-badge/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/seller-badge/bulk-actions + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('seller badge api test', () => { + let apiUtils: ApiUtils; + let badgeId: string; + let currentUserId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + // delete previous badges + await apiUtils.deleteAllSellerBadges(); + [, currentUserId] = await apiUtils.getCurrentUser(); + [, badgeId] = await apiUtils.createSellerBadge(payloads.createSellerBadgeExclusiveToPlatform); + }); + + test('get verified-seller verification types @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVerifiedSellerVerificationTypes); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all seller badge events @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllSellerBadgeEvents); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all seller badges @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllSellerBadges); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single seller badge @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleSellerBadge(badgeId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor unseen seller badges @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorUnseenSellerBadges, { params: { vendor_id: currentUserId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('set vendor seller badges as seen @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.setSellerBadgeAsSeen, { data: { vendor_id: currentUserId, badge_id: badgeId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a seller badge @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createSellerBadge, { data: payloads.createSellerBadgeProductsPublished }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a seller badge @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateSellerBadge(badgeId), { data: payloads.updateSellerBadge }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update row actions @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.setSellerBadgeRowActions, { data: { ids: badgeId, action: 'draft' } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a seller badge @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteSellerBadge(badgeId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch seller badges @pro', async () => { + const allBadgeIds = (await apiUtils.getAllSellerBadges()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchSellerBadges, { data: { ids: allBadgeIds, action: 'draft' } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/settings.spec.ts b/tests/pw/tests/api/settings.spec.ts new file mode 100644 index 0000000000..4587873762 --- /dev/null +++ b/tests/pw/tests/api/settings.spec.ts @@ -0,0 +1,27 @@ +//COVERAGE_TAG: GET /dokan/v1/settings +//COVERAGE_TAG: PUT /dokan/v1/settings + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('settings api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get settings @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSettings); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update settings @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateSettings, { data: payloads.updateSettings }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/setttingsGroup.spec.ts b/tests/pw/tests/api/setttingsGroup.spec.ts new file mode 100644 index 0000000000..2f4010fa14 --- /dev/null +++ b/tests/pw/tests/api/setttingsGroup.spec.ts @@ -0,0 +1,64 @@ +//COVERAGE_TAG: GET /dokan/v2/settings +//COVERAGE_TAG: GET /dokan/v2/settings/(?P[\w-]+) +//COVERAGE_TAG: POST /dokan/v2/settings/(?P[\w-]+) +//COVERAGE_TAG: GET /dokan/v2/settings/(?P[\w-]+)/(?P[\w-]+) +//COVERAGE_TAG: POST /dokan/v2/settings/(?P[\w-]+)/(?P[\w-]+) +//COVERAGE_TAG: GET /dokan/v2/settings/(?P[\w-]+)/(?P[\w-]+)/(?P[\w-]+) +//COVERAGE_TAG: POST /dokan/v2/settings/(?P[\w-]+)/(?P[\w-]+)/(?P[\w-]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('new settings api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get store settings @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getStoreSettings); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single setting group @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleSettingGroup('store')); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update single setting group @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateSingleSettingGroup('store'), { data: payloads.updateSettingsGroup }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get sub settings from single settings group @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSubSettingFromSingleSettingGroup('store', 'store_name')); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update sub settings from single settings group @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateSubSettingFromSingleSettingGroup('store', 'store_name'), { data: payloads.updateSubSettingFromSingleSettingGroup }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get sub sub settings from single settings group @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSubSubSettingFromSingleSettingGroup('store', 'address', 'street_1')); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update sub sub settings from single settings group @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateSubSubSettingFromSingleSettingGroup('store', 'address', 'street_1'), { + data: payloads.updateSubSubSettingFromSingleSettingGroup, + }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/spmv.spec.ts b/tests/pw/tests/api/spmv.spec.ts new file mode 100644 index 0000000000..97ec5b6923 --- /dev/null +++ b/tests/pw/tests/api/spmv.spec.ts @@ -0,0 +1,36 @@ +//COVERAGE_TAG: GET /dokan/v1/spmv-product/settings +//COVERAGE_TAG: GET /dokan/v1/spmv-product/search +//COVERAGE_TAG: POST /dokan/v1/spmv-product/add-to-store + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('spmv API test', () => { + let apiUtils: ApiUtils; + let productId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, productId] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendor2Auth); + }); + + test('get spmv settings @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSpmvSettings); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get spmv products @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSpmvProducts, { data: payloads.spmvSearch }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('add spmv product to store @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.addToStore, { data: { product_id: productId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/storeCategories.spec.ts b/tests/pw/tests/api/storeCategories.spec.ts new file mode 100644 index 0000000000..83ff1f7d8e --- /dev/null +++ b/tests/pw/tests/api/storeCategories.spec.ts @@ -0,0 +1,68 @@ +//COVERAGE_TAG: GET /dokan/v1/store-categories/default-category +//COVERAGE_TAG: PUT /dokan/v1/store-categories/default-category +//COVERAGE_TAG: GET /dokan/v1/store-categories +//COVERAGE_TAG: GET /dokan/v1/store-categories/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/store-categories +//COVERAGE_TAG: PUT /dokan/v1/store-categories/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/store-categories/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('store categories api test', () => { + let apiUtils: ApiUtils; + let categoryId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, categoryId] = await apiUtils.createStoreCategory(payloads.createStoreCategory()); + }); + + test('get default store category @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getDefaultStoreCategory); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('set default store category @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.setDefaultStoreCategory, { data: { id: categoryId } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + + // restore default store category + await apiUtils.setDefaultStoreCategory('Uncategorized', payloads.adminAuth); + }); + + test('get all store categories @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllStoreCategories); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single store category @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleStoreCategory(categoryId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a store category @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createStoreCategory, { data: payloads.createStoreCategory() }); + expect(response.status()).toBe(201); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a store category @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateStoreCategory(categoryId), { data: payloads.updateStoreCategory() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a store category @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteStoreCategory(categoryId), { params: payloads.paramsDeleteStoreCategory }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/storeReviews.spec.ts b/tests/pw/tests/api/storeReviews.spec.ts new file mode 100644 index 0000000000..80e54ca8cb --- /dev/null +++ b/tests/pw/tests/api/storeReviews.spec.ts @@ -0,0 +1,79 @@ +//COVERAGE_TAG: GET /dokan/v1/stores/(?P[\d]+)/reviews +//COVERAGE_TAG: POST /dokan/v1/stores/(?P[\d]+)/reviews +//COVERAGE_TAG: GET /dokan/v1/store-reviews +//COVERAGE_TAG: GET /dokan/v1/store-reviews/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/store-reviews/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/store-reviews/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/store-reviews/(?P[\d]+)/restore +//COVERAGE_TAG: PUT /dokan/v1/store-reviews/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('store reviews api test', () => { + let apiUtils: ApiUtils; + let sellerId: string; + let reviewId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + // let [, sId,] = await apiUtils.createStore(payloads.createStore()) + [, sellerId] = await apiUtils.getCurrentUser(); + [, reviewId] = await apiUtils.createStoreReview(sellerId, payloads.createStoreReview, payloads.customerAuth); + }); + + test('get store reviews @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getStoreReviews(sellerId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a store review @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createStoreReview(sellerId), { data: payloads.createStoreReview }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all store reviews @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllStoreReviews); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single store review @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleStoreReview(reviewId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a store review @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateStoreReview(reviewId), { data: payloads.updateStoreReview }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a store review @pro', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.deleteStoreReview(reviewId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('restore a deleted store review @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.restoreDeletedStoreReview(reviewId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch store review @pro', async () => { + const allStoreReviewIds = (await apiUtils.getAllStoreReviews()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchStoreReviews, { data: { trash: allStoreReviewIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + + // restore all store reviews + // await apiUtils.updateBatchStoreReviews('restore', allStoreReviewIds); + await apiUtils.updateBatchStoreReviews('restore', []); + }); +}); diff --git a/tests/pw/tests/api/stores.spec.ts b/tests/pw/tests/api/stores.spec.ts new file mode 100644 index 0000000000..9045622e54 --- /dev/null +++ b/tests/pw/tests/api/stores.spec.ts @@ -0,0 +1,118 @@ +//COVERAGE_TAG: GET /dokan/v1/stores +//COVERAGE_TAG: GET /dokan/v1/stores/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/stores +//COVERAGE_TAG: PUT /dokan/v1/stores/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/stores/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v1/stores/current-visitor +//COVERAGE_TAG: GET /dokan/v1/stores/(?P[\d]+)/stats +//COVERAGE_TAG: GET /dokan/v1/stores/check +//COVERAGE_TAG: GET /dokan/v1/stores/(?P[\d]+)/categories +//COVERAGE_TAG: GET /dokan/v1/stores/(?P[\d]+)/products +//COVERAGE_TAG: PUT /dokan/v1/stores/(?P[\d]+)/status +//COVERAGE_TAG: POST /dokan/v1/stores/(?P[\d]+)/contact +//COVERAGE_TAG: POST /dokan/v1/stores/(?P[\d]+)/email +//COVERAGE_TAG: PUT /dokan/v1/stores/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('stores api test', () => { + let apiUtils: ApiUtils; + let sellerId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, sellerId] = await apiUtils.createStore(payloads.createStore()); + // let [, id] = await apiUtils.getCurrentUser() + }); + + test('get all stores @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllStores); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single store @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleStore(sellerId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a store @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createStore, { data: payloads.createStore() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a store @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateStore(sellerId), { data: payloads.updateStore() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a store @lite', async () => { + const [, sId] = await apiUtils.createStore(payloads.createStore()); + const [response, responseBody] = await apiUtils.delete(endPoints.deleteStore(sId), { params: payloads.paramsDeleteStore }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get store current visitor @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getStoreCurrentVisitor); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get store stats @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getStoreStats(sellerId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get store slug availability @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getStoresSlugAvaility); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get store categories @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getStoreCategories(sellerId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get store products @lite', async () => { + const [, sId] = await apiUtils.getCurrentUser(); + await apiUtils.createProduct(payloads.createProduct()); + const [response, responseBody] = await apiUtils.get(endPoints.getStoreProducts(sId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a store status @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateStoreStatus(sellerId), { data: payloads.updateStoreStatus }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('client contact store @lite', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.clientContactStore(sellerId), { data: payloads.clientContactStore }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('admin email store @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.adminEmailStore(sellerId), { data: payloads.adminEmailStore }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch stores @lite', async () => { + const allStoreIds = (await apiUtils.getAllStores()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchStores, { data: { approved: allStoreIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/supportTickets.spec.ts b/tests/pw/tests/api/supportTickets.spec.ts new file mode 100644 index 0000000000..2f7347ecaa --- /dev/null +++ b/tests/pw/tests/api/supportTickets.spec.ts @@ -0,0 +1,83 @@ +//COVERAGE_TAG: GET /dokan/v1/admin/support-ticket/customers +//COVERAGE_TAG: GET /dokan/v1/admin/support-ticket +//COVERAGE_TAG: GET /dokan/v1/admin/support-ticket/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/admin/support-ticket/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/admin/support-ticket/(?P[\d]+)/status +//COVERAGE_TAG: POST /dokan/v1/admin/support-ticket/(?P[\d]+)/email-notification +//COVERAGE_TAG: DELETE /dokan/v1/admin/support-ticket/(?P[\d]+)/comment +//COVERAGE_TAG: PUT /dokan/v1/admin/support-ticket/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +const { VENDOR_ID, CUSTOMER_ID } = process.env; + +test.describe('support ticket api test', () => { + let apiUtils: ApiUtils; + let supportTicketId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, supportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, author: CUSTOMER_ID, store_id: VENDOR_ID }); + }); + + test('get all support ticket customers @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllSupportTicketCustomers); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all support tickets @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllSupportTickets); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single support ticket @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleSupportTicket(supportTicketId), { params: { vendor_id: VENDOR_ID } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a support ticket comment @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createSupportTicketComment(supportTicketId), { data: payloads.createSupportTicketComment }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a support ticket status @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateSupportTicketStatus(supportTicketId), { data: payloads.updateSupportTicketStatus }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + + // reopen support ticket + await apiUtils.updateSupportTicketStatus(supportTicketId, 'open'); + }); + + test('update a support ticket email notification @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateSupportTicketEmailNotification(supportTicketId), { data: payloads.updateSupportTicketEmailNotification }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a support ticket comment @pro', async () => { + const supportTicketCommentId = await apiUtils.createSupportTicketComment(supportTicketId, payloads.createSupportTicketComment); + const [response, responseBody] = await apiUtils.delete(endPoints.deleteSupportTicketComment(supportTicketCommentId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch support tickets @pro', async () => { + const allSupportTicketIds = (await apiUtils.getAllSupportTickets()).map((a: { ID: unknown }) => a.ID); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchSupportTickets, { data: { close: allSupportTicketIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + + // reopen all support tickets + for (const supportTicketId of allSupportTicketIds) { + await apiUtils.updateSupportTicketStatus(supportTicketId, 'open'); + } + }); +}); diff --git a/tests/pw/tests/api/vendorDashborad.spec.ts b/tests/pw/tests/api/vendorDashborad.spec.ts new file mode 100644 index 0000000000..0f02f20a1b --- /dev/null +++ b/tests/pw/tests/api/vendorDashborad.spec.ts @@ -0,0 +1,61 @@ +//COVERAGE_TAG: GET /dokan/v1/vendor-dashboard +//COVERAGE_TAG: GET /dokan/v1/vendor-dashboard/profile +//COVERAGE_TAG: GET /dokan/v1/vendor-dashboard/sales +//COVERAGE_TAG: GET /dokan/v1/vendor-dashboard/products +//COVERAGE_TAG: GET /dokan/v1/vendor-dashboard/orders +//COVERAGE_TAG: GET /dokan/v1/vendor-dashboard/preferences +//COVERAGE_TAG: GET /dokan/v1/vendor-dashboard/profile-progressbar + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; + +test.describe('vendor dashboard api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get vendor dashboard statistics @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorDashboardStatistics); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor profile information @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorProfileInformation); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor sales report @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorSalesReport); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor product reports summary @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorProductReportsSummary); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor order reports summary @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorOrderReportsSummary); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor store preferences @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorStorePreferences); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor profile progress bar data @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorProfileProgressBarData); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/vendorStaff.spec.ts b/tests/pw/tests/api/vendorStaff.spec.ts new file mode 100644 index 0000000000..4cee96271e --- /dev/null +++ b/tests/pw/tests/api/vendorStaff.spec.ts @@ -0,0 +1,73 @@ +//COVERAGE_TAG: GET /dokan/v1/vendor-staff +//COVERAGE_TAG: GET /dokan/v1/vendor-staff/(?P[\d]+) +//COVERAGE_TAG: POST /dokan/v1/vendor-staff +//COVERAGE_TAG: PUT /dokan/v1/vendor-staff/(?P[\d]+) +//COVERAGE_TAG: GET /dokan/v1/vendor-staff/capabilities +//COVERAGE_TAG: GET /dokan/v1/vendor-staff/(?P[\d]+)/capabilities +//COVERAGE_TAG: PUT /dokan/v1/vendor-staff/(?P[\d]+)/capabilities +//COVERAGE_TAG: DELETE /dokan/v1/vendor-staff/(?P[\d]+) + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('vendor staff api test', () => { + let apiUtils: ApiUtils; + let staffId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, staffId] = await apiUtils.createVendorStaff(payloads.createStaff(), payloads.vendorAuth); + }); + + test.use({ extraHTTPHeaders: { Authorization: payloads.vendorAuth.Authorization } }); + + test('get all vendor staffs @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllVendorStaffs); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single vendor staff @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleVendorStaff(staffId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a vendor staff @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.createVendorStaff, { data: payloads.createStaff() }); + expect(response.status()).toBe(201); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a vendor staff @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateVendorStaff(staffId), { data: payloads.updateStaff() }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all vendor staff capabilities @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllVendorStaffCapabilities); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get vendor staff capabilities @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getVendorStaffCapabilities(staffId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update vendor staff capabilities @pro', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateVendorStaffCapabilities(staffId), { data: payloads.updateCapabilities }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a vendor staff @pro', async () => { + const [response] = await apiUtils.delete(endPoints.deleteVendorStaff(staffId), { params: payloads.paramsForceDelete }); + expect(response.ok()).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/wholesaleCustomers.spec.ts b/tests/pw/tests/api/wholesaleCustomers.spec.ts new file mode 100644 index 0000000000..b14c571d26 --- /dev/null +++ b/tests/pw/tests/api/wholesaleCustomers.spec.ts @@ -0,0 +1,51 @@ +//COVERAGE_TAG: GET /dokan/v1/wholesale/customers +//COVERAGE_TAG: POST /dokan/v1/wholesale/register +//COVERAGE_TAG: POST /dokan/v1/wholesale/customer/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/wholesale/customers/batch + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('wholesale customers api test', () => { + let apiUtils: ApiUtils; + let wholesaleCustomerId: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, wholesaleCustomerId] = await apiUtils.createWholesaleCustomer(payloads.createCustomer(), payloads.adminAuth); + }); + + test('get all wholesale customers @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllWholesaleCustomers); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a wholesale customer @pro', async () => { + const [, customerId] = await apiUtils.createCustomer(payloads.createCustomer()); + const [response, responseBody] = await apiUtils.post(endPoints.createWholesaleCustomer, { data: { id: String(customerId) } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a wholesale customer @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateCustomer(wholesaleCustomerId), { data: payloads.updateWholesaleCustomer }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('delete a wholesale customer @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateCustomer(wholesaleCustomerId), { data: payloads.deleteWholesaleCustomer }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch wholesale customers @pro', async () => { + const allWholesaleCustomerIds = (await apiUtils.getAllWholesaleCustomers()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchWholesaleCustomer, { data: { activate: allWholesaleCustomerIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/withdrawSettings.spec.ts b/tests/pw/tests/api/withdrawSettings.spec.ts new file mode 100644 index 0000000000..f28d7ccfd7 --- /dev/null +++ b/tests/pw/tests/api/withdrawSettings.spec.ts @@ -0,0 +1,48 @@ +//COVERAGE_TAG: GET /dokan/v2/withdraw/settings +//COVERAGE_TAG: GET /dokan/v2/withdraw/summary +//COVERAGE_TAG: GET /dokan/v2/withdraw/disbursement +//COVERAGE_TAG: POST /dokan/v2/withdraw/disbursement +//COVERAGE_TAG: POST /dokan/v2/withdraw/disbursement/disable + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; + +test.describe('withdraw api test', () => { + let apiUtils: ApiUtils; + + test.beforeAll(({ request }) => { + apiUtils = new ApiUtils(request); + }); + + test('get withdraw settings @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getWithdrawSettings); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get withdraw summary @v2 @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getWithdrawSummary); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get withdraw disbursement settings @v2 @pro', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getWithdrawDisbursementSettings); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update withdraw disbursement settings @v2 @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.updateWithdrawDisbursementSettings, { data: payloads.updateWithdrawDisbursementSettings }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('disable withdraw disbursement @v2 @pro', async () => { + const [response, responseBody] = await apiUtils.post(endPoints.disableWithdrawDisbursement); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/api/withdraws.spec.ts b/tests/pw/tests/api/withdraws.spec.ts new file mode 100644 index 0000000000..92caee6593 --- /dev/null +++ b/tests/pw/tests/api/withdraws.spec.ts @@ -0,0 +1,87 @@ +//COVERAGE_TAG: GET /dokan/v1/withdraw/balance +//COVERAGE_TAG: GET /dokan/v1/withdraw +//COVERAGE_TAG: GET /dokan/v1/withdraw/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/withdraw/(?P[\d]+) +//COVERAGE_TAG: DELETE /dokan/v1/withdraw/(?P[\d]+) +//COVERAGE_TAG: PUT /dokan/v1/withdraw/batch +//COVERAGE_TAG: POST /dokan/v1/withdraw + +import { test, expect } from '@playwright/test'; +import { ApiUtils } from '@utils/apiUtils'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; +import { helpers } from '@utils/helpers'; + +test.describe('withdraw api test', () => { + let apiUtils: ApiUtils; + let withdrawId: string; + let minimumWithdrawLimit: string; + + test.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + [, minimumWithdrawLimit] = await apiUtils.getMinimumWithdrawLimit(); + await apiUtils.createOrderWithStatus(payloads.createProduct(), payloads.createOrder, 'wc-completed'); + const [responseBody, id] = await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }); + withdrawId = responseBody.message === 'You already have a pending withdraw request' ? await apiUtils.getWithdrawId() : id; + }); + + test('get withdraw payment methods @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getWithdrawPaymentMethods); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get balance details @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getBalanceDetails); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all withdraws @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllWithdraws); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get all withdraws by status @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getAllWithdraws, { params: { status: 'pending' } }); // pending, cancelled, approved + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('get single withdraw @lite', async () => { + const [response, responseBody] = await apiUtils.get(endPoints.getSingleWithdraw(withdrawId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update a withdraw @lite', async () => { + const [response, responseBody] = await apiUtils.put(endPoints.updateWithdraw(withdrawId), { data: payloads.updateWithdraw }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('cancel a withdraw @lite', async () => { + const [response, responseBody] = await apiUtils.delete(endPoints.cancelWithdraw(withdrawId)); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('update batch withdraws @lite', async () => { + const allWithdrawIds = (await apiUtils.getAllWithdraws()).map((a: { id: unknown }) => a.id); + const [response, responseBody] = await apiUtils.put(endPoints.updateBatchWithdraws, { data: { approved: allWithdrawIds } }); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); + + test('create a withdraw @lite', async () => { + // cancel any pending withdraw + const pendingRequest = await apiUtils.getAllWithdrawsByStatus('pending'); + helpers.isObjEmpty(pendingRequest) === false && (await apiUtils.cancelWithdraw(withdrawId)); + + const [response, responseBody] = await apiUtils.post(endPoints.createWithdraw, { data: { ...payloads.createWithdraw, amount: minimumWithdrawLimit } }); + expect(response.status()).toBe(201); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/e2e/_auth.setup.spec.ts b/tests/pw/tests/e2e/_auth.setup.spec.ts new file mode 100644 index 0000000000..9242f8045f --- /dev/null +++ b/tests/pw/tests/e2e/_auth.setup.spec.ts @@ -0,0 +1,58 @@ +import { test as setup, expect } from '@playwright/test'; +import { LoginPage } from '@pages/loginPage'; +import { WpPage } from '@pages/wpPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +setup.describe('authenticate users & set permalink', () => { + setup('authenticate admin @lite', async ({ page }) => { + const loginPage = new LoginPage(page); + await loginPage.adminLogin(data.admin, data.auth.adminAuthFile); + }); + + setup('admin set WpSettings @lite', async ({ page }) => { + const loginPage = new LoginPage(page); + const wpPage = new WpPage(page); + await loginPage.adminLogin(data.admin); + await wpPage.setPermalinkSettings(data.wpSettings.permalink); + process.env.SERVER_URL = process.env.BASE_URL + '/wp-json'; + }); + + setup('add customer1 @lite', async ({ request }) => { + const apiUtils = new ApiUtils(request); + const [, customerId] = await apiUtils.createCustomer(payloads.createCustomer1, payloads.adminAuth); + process.env.CUSTOMER_ID = customerId; + }); + + setup('add vendor1 @lite', async ({ request }) => { + const apiUtils = new ApiUtils(request); + const [, sellerId] = await apiUtils.createStore(payloads.createStore1, payloads.adminAuth); + await apiUtils.updateCustomer(sellerId, payloads.updateAddress, payloads.adminAuth); + process.env.VENDOR_ID = sellerId; + }); + + setup('add vendor2 @lite', async ({ request }) => { + const apiUtils = new ApiUtils(request); + const [, sellerId] = await apiUtils.createStore(payloads.createStore2, payloads.adminAuth); + await apiUtils.updateCustomer(sellerId, payloads.updateAddress, payloads.adminAuth); + process.env.VENDOR2_ID = sellerId; + }); + + setup('authenticate customer @lite', async ({ page }) => { + const loginPage = new LoginPage(page); + await loginPage.login(data.customer, data.auth.customerAuthFile); + }); + + setup('authenticate vendor @lite', async ({ page }) => { + const loginPage = new LoginPage(page); + await loginPage.login(data.vendor, data.auth.vendorAuthFile); + }); + + setup('dokan pro enabled or not @pro', async ({ request }) => { + const apiUtils = new ApiUtils(request); + const res = await apiUtils.pluginsActiveOrNot(data.plugin.dokanPro, payloads.adminAuth); + process.env.DOKAN_PRO = String(res); + expect(res).toBeTruthy(); + }); +}); diff --git a/tests/pw/tests/e2e/_environment.setup.spec.ts b/tests/pw/tests/e2e/_environment.setup.spec.ts new file mode 100644 index 0000000000..40a3aa3799 --- /dev/null +++ b/tests/pw/tests/e2e/_environment.setup.spec.ts @@ -0,0 +1,381 @@ +import { test as setup, expect, Page } from '@playwright/test'; +import { ProductAdvertisingPage } from '@pages/productAdvertisingPage'; +import { ReverseWithdrawsPage } from '@pages/reverseWithdrawsPage'; +import { VendorSettingsPage } from '@pages/vendorSettingsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; +import { data } from '@utils/testData'; + +const { CUSTOMER_ID, DOKAN_PRO, HPOS } = process.env; + +setup.describe('setup site & woocommerce & user settings', () => { + setup.use({ extraHTTPHeaders: { Authorization: payloads.adminAuth.Authorization } }); + + let apiUtils: ApiUtils; + + setup.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + }); + + setup('check active plugins @lite', async () => { + setup.skip(!process.env.CI, 'skip plugin check on local'); + const activePlugins = (await apiUtils.getAllPlugins({ status: 'active' })).map((a: { plugin: string }) => a.plugin.split('/')[1]); + DOKAN_PRO ? expect(activePlugins).toEqual(expect.arrayContaining(data.plugin.plugins)) : expect(activePlugins).toEqual(expect.arrayContaining(data.plugin.pluginsLite)); + // expect(activePlugins.every((plugin: string) => data.plugin.plugins.includes(plugin))).toBeTruthy(); + }); + + setup('check active dokan modules @pro', async () => { + const activeModules = await apiUtils.getAllModuleIds({ status: 'active' }); + expect(activeModules).toEqual(expect.arrayContaining(data.modules.modules)); + }); + + setup('set wordPress site settings @lite', async () => { + const siteSettings = await apiUtils.setSiteSettings(payloads.siteSettings); + expect(siteSettings).toEqual(expect.objectContaining(payloads.siteSettings)); + }); + + // setup.skip('reset dokan previous settings @lite', async () => { + // setup.skip(!!process.env.CI, 'skip previous settings check'); + // await apiUtils.deleteAllSellerBadges(); + // await apiUtils.deleteAllQuoteRules(); + // }); + + setup('set woocommerce settings @lite', async () => { + await apiUtils.updateBatchWcSettingsOptions('general', payloads.general); + await apiUtils.updateBatchWcSettingsOptions('account', payloads.account); + HPOS && (await apiUtils.updateBatchWcSettingsOptions('advanced', payloads.advanced)); + }); + + setup('set tax rate @lite', async () => { + await apiUtils.setUpTaxRate(payloads.enableTaxRate, payloads.createTaxRate); + }); + + setup('set shipping methods @lite', async () => { + // delete previous shipping zones + const allShippingZoneIds = (await apiUtils.getAllShippingZones()).map((a: { id: string }) => a.id); + // allShippingZoneIds = helpers.removeItem(allShippingZoneIds, 0) // avoid remove default zone id + if (allShippingZoneIds.length) { + for (const shippingZoneId of allShippingZoneIds) { + await apiUtils.deleteShippingZone(shippingZoneId); + } + } + + // create shipping zone, location and method + const [, zoneId] = await apiUtils.createShippingZone(payloads.createShippingZone); + await apiUtils.addShippingZoneLocation(zoneId, payloads.addShippingZoneLocation); + await apiUtils.addShippingZoneMethod(zoneId, payloads.addShippingMethodFlatRate); + // await apiUtils.addShippingZoneMethod(zoneId, payloads.addShippingMethodFreeShipping); + // await apiUtils.addShippingZoneMethod(zoneId, payloads.addShippingMethodLocalPickup); + if (DOKAN_PRO) { + await apiUtils.addShippingZoneMethod(zoneId, payloads.addShippingMethodDokanTableRateShipping); + await apiUtils.addShippingZoneMethod(zoneId, payloads.addShippingMethodDokanDistanceRateShipping); + await apiUtils.addShippingZoneMethod(zoneId, payloads.addShippingMethodDokanVendorShipping); + } + }); + + setup('set basic payments @lite', async () => { + await apiUtils.updatePaymentGateway('bacs', payloads.bcs); + await apiUtils.updatePaymentGateway('cheque', payloads.cheque); + await apiUtils.updatePaymentGateway('cod', payloads.cod); + // await apiUtils.updatePaymentGateway('dokan-stripe-connect', payloads.stripeConnect); + // await apiUtils.updatePaymentGateway('dokan_paypal_marketplace', payloads.payPal); + // await apiUtils.updatePaymentGateway('dokan_mangopay', payloads.mangoPay); + // await apiUtils.updatePaymentGateway('dokan_razorpay', payloads.razorpay); + // await apiUtils.updatePaymentGateway('dokan_stripe_express', payloads.stripeExpress); + }); + + setup('add categories and attributes @lite', async () => { + // delete previous categories + const allCategoryIds = (await apiUtils.getAllCategories()).map((a: { id: string }) => a.id); + await apiUtils.updateBatchCategories('delete', allCategoryIds); + + // delete previous attributes + const allAttributeIds = (await apiUtils.getAllAttributes()).map((a: { id: string }) => a.id); + await apiUtils.updateBatchAttributes('delete', allAttributeIds); + + // create category + await apiUtils.createCategory(payloads.createCategory); + + // create attribute, attribute term + const [, attributeId] = await apiUtils.createAttribute({ name: 'sizes' }); + await apiUtils.createAttributeTerm(attributeId, { name: 's' }); + await apiUtils.createAttributeTerm(attributeId, { name: 'l' }); + await apiUtils.createAttributeTerm(attributeId, { name: 'm' }); + }); + + setup('disable simple-auction ajax bid check @pro', async () => { + const [, , status] = await apiUtils.getSinglePlugin('wa/woocommerce-simple-auctions', payloads.adminAuth); + console.log(status); + status === 'active' && (await dbUtils.updateWpOptionTable('simple_auctions_live_check', 'no')); + }); +}); + +setup.describe('setup user settings', () => { + setup.use({ extraHTTPHeaders: { Authorization: payloads.adminAuth.Authorization } }); + + let apiUtils: ApiUtils; + + setup.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + }); + + // Vendor Details + setup('add vendor1 product @lite', async () => { + // delete previous store products with predefined name if any + await apiUtils.deleteAllProducts(data.predefined.simpleProduct.product1.name, payloads.vendorAuth); + + // create store product + const product = { ...payloads.createProduct(), name: data.predefined.simpleProduct.product1.name }; + const [, productId] = await apiUtils.createProduct(product, payloads.vendorAuth); + process.env.PRODUCT_ID = productId; + }); + + setup('add vendor2 product @lite', async () => { + // delete previous store products with predefined name if any + await apiUtils.deleteAllProducts(data.predefined.vendor2.simpleProduct.product1.name, payloads.vendor2Auth); + + // create store product + const product = { ...payloads.createProduct(), name: data.predefined.vendor2.simpleProduct.product1.name }; + const [, productId] = await apiUtils.createProduct(product, payloads.vendor2Auth); + process.env.V2_PRODUCT_ID = productId; + }); + + setup('add vendor coupon @pro', async () => { + // create store coupon + const allProductIds = (await apiUtils.getAllProducts(payloads.vendorAuth)).map((o: { id: string }) => o.id); + await apiUtils.createCoupon(allProductIds, payloads.createCoupon1, payloads.vendorAuth); + }); + + // setup.skip('admin add vendor products @lite', async () => { + + // const product = payloads.createProduct(); + // await apiUtils.createProduct({ ...product, status: 'publish', in_stock: false }, payloads.vendorAuth); + // await apiUtils.createProduct({ ...product, status: 'draft', in_stock: true }, payloads.vendorAuth); + // await apiUtils.createProduct({ ...product, status: 'pending', in_stock: true }, payloads.vendorAuth); + // await apiUtils.createProduct({ ...product, status: 'publish', in_stock: true }, payloads.vendorAuth); + // }); + + setup('add test vendor orders @pro', async () => { + await apiUtils.createOrder(payloads.createProduct(), { ...payloads.createOrder, customer_id: CUSTOMER_ID }, payloads.vendorAuth); + }); +}); + +setup.describe('setup dokan settings', () => { + let apiUtils: ApiUtils; + + setup.beforeAll(async ({ request }) => { + apiUtils = new ApiUtils(request); + }); + + setup('set dokan general settings @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.general, dbData.dokan.generalSettings); + }); + + setup('admin set dokan selling settings @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.selling, dbData.dokan.sellingSettings); + }); + + setup('admin set dokan withdraw settings @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.withdraw, dbData.dokan.withdrawSettings); + }); + + setup('admin set dokan reverse withdraw settings @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.reverseWithdraw, dbData.dokan.reverseWithdrawSettings); + }); + + setup('admin set dokan page settings @lite', async () => { + const [, pageId] = await apiUtils.createPage(payloads.tocPage, payloads.adminAuth); + const pageSettings = await dbUtils.getDokanSettings(dbData.dokan.optionName.page); + pageSettings['reg_tc_page'] = String(pageId); + await dbUtils.setDokanSettings(dbData.dokan.optionName.page, pageSettings); + }); + + setup('admin set dokan appearance settings @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.appearance, dbData.dokan.appearanceSettings); + }); + + setup('admin set dokan privacy policy settings @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.privacyPolicy, dbData.dokan.privacyPolicySettings); + }); + + setup('admin set dokan color settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.colors, dbData.dokan.colorsSettings); + }); + + setup('admin set dokan store support settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.storeSupport, dbData.dokan.storeSupportSettings); + }); + + setup('admin set dokan shipping status settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.shippingStatus, dbData.dokan.shippingStatusSettings); + }); + + setup('admin set dokan quote settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.quote, dbData.dokan.quoteSettings); + }); + + setup('admin set dokan rma settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.rma, dbData.dokan.rmaSettings); + }); + + setup('admin set dokan wholesale settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.wholesale, dbData.dokan.wholesaleSettings); + }); + + setup('admin set dokan eu compliance settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.euCompliance, dbData.dokan.euComplianceSettings); + }); + + setup('admin set dokan delivery time settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.deliveryTime, dbData.dokan.deliveryTimeSettings); + }); + + setup('admin set dokan product advertising settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.productAdvertising, dbData.dokan.productAdvertisingSettings); + }); + + setup('admin set dokan geolocation settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.geolocation, dbData.dokan.geolocationSettings); + }); + + setup('admin set dokan product report abuse settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.productReportAbuse, dbData.dokan.productReportAbuseSettings); + }); + + setup('admin set dokan spmv settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.spmv, dbData.dokan.spmvSettings); + }); + + setup('admin set dokan vendor subscription settings @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.vendorSubscription, dbData.dokan.vendorSubscriptionSettings); + }); +}); + +setup.describe('setup dokan settings e2e', () => { + let productAdvertisingPage: ProductAdvertisingPage; + let reverseWithdrawsPage: ReverseWithdrawsPage; + let vendorPage: VendorSettingsPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + + setup.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + productAdvertisingPage = new ProductAdvertisingPage(aPage); + reverseWithdrawsPage = new ReverseWithdrawsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendorPage = new VendorSettingsPage(vPage); + + apiUtils = new ApiUtils(request); + }); + + setup.afterAll(async () => { + await aPage.close(); + await vPage.close(); + }); + + setup('recreate product advertisement payment product via settings save @pro', async () => { + await productAdvertisingPage.recreateProductAdvertisementPaymentViaSettingsSave(); + }); + + setup('product advertisement payment product exists @pro', async () => { + const product = await apiUtils.checkProductExistence('Product Advertisement Payment', payloads.adminAuth); + expect(product).toBeTruthy(); + }); + + setup('recreate reverse withdrawal payment product via settings save @lite', async () => { + await reverseWithdrawsPage.reCreateReverseWithdrawalPaymentViaSettingsSave(); + }); + + setup('reverse Withdraw payment product exists @lite', async () => { + const product = await apiUtils.checkProductExistence('Reverse Withdrawal Payment', payloads.adminAuth); + expect(product).toBeTruthy(); + }); + + setup('save store settings to update store on map @lite', async () => { + await vendorPage.updateStoreMapViaSettingsSave(); + }); + + // dokan settings + + // setup.skip('admin set WpSettings @lite', async ()=> { + // await adminPage.setPermalinkSettings(data.wpSettings.permalink); + // }); + + // setup('admin set dokan general settings @lite', async ()=> { + // await adminPage.setDokanGeneralSettings(data.dokanSettings.general); + // }); + + // setup('admin set dokan selling settings @lite', async ()=> { + // await adminPage.setDokanSellingSettings(data.dokanSettings.selling); + // }); + + // setup('admin set dokan withdraw settings @lite', async ()=> { + // await adminPage.setDokanWithdrawSettings(data.dokanSettings.withdraw); + // }); + + // setup('admin set dokan reverse withdraw settings @lite', async ()=> { + // await adminPage.setDokanReverseWithdrawSettings(data.dokanSettings.reverseWithdraw); + // }); + + // setup('admin set dokan page settings @lite', async ()=> { + // await adminPage.setPageSettings(data.dokanSettings.page); + // }); + + // setup('admin set dokan appearance settings @lite', async ()=> { + // await adminPage.setDokanAppearanceSettings(data.dokanSettings.appearance); + // }); + + // setup('admin set dokan privacy policy settings @lite', async ()=> { + // await adminPage.setDokanPrivacyPolicySettings(data.dokanSettings.privacyPolicy); + // }); + + // setup('admin set dokan store support settings @pro', async ()=> { + // await adminPage.setDokanStoreSupportSettings(data.dokanSettings.storeSupport); + // }); + + // setup('admin set dokan rma settings @pro', async ()=> { + // await adminPage.setDokanRmaSettings(data.dokanSettings.rma); + // }); + + // setup('admin set dokan wholesale settings @pro', async ()=> { + // await adminPage.setDokanWholesaleSettings(data.dokanSettings.wholesale); + // }); + + // setup('admin set dokan eu compliance settings @pro', async ()=> { + // await adminPage.setDokanEuComplianceSettings(data.dokanSettings.euCompliance); + // }); + + // setup.skip('admin set dokan delivery time settings @pro', async ()=> { + // await adminPage.setDokanDeliveryTimeSettings(data.dokanSettings.deliveryTime); + // }); + + // setup('admin set dokan product advertising settings @pro', async ()=> { + // await adminPage.setDokanProductAdvertisingSettings(data.dokanSettings.productAdvertising); + // }); + + // setup('admin set dokan geolocation settings @pro', async ()=> { + // await adminPage.setDokanGeolocationSettings(data.dokanSettings.geolocation); + // }); + + // setup('admin set dokan product report abuse settings @pro', async ()=> { + // await adminPage.setDokanProductReportAbuseSettings(data.dokanSettings.productReportAbuse); + // }); + + // setup('admin set dokan spmv settings @pro', async ()=> { + // await adminPage.setDokanSpmvSettings(data.dokanSettings.spmv); + // }); + + // setup.skip('admin set dokan vendor subscription settings @pro', async ()=> { + // await adminPage.setDokanVendorSubscriptionSettings(data.dokanSettings.vendorSubscription); + // }); + + // setup.skip('admin add dokan subscription @pro', async ()=> { + // await adminPage.addDokanSubscription({ ...data.product.vendorSubscription, + // productName: data.predefined.vendorSubscription.nonRecurring, }); + // }); +}); diff --git a/tests/pw/tests/e2e/_localSite.install.ts b/tests/pw/tests/e2e/_localSite.install.ts new file mode 100644 index 0000000000..96fc0c0f17 --- /dev/null +++ b/tests/pw/tests/e2e/_localSite.install.ts @@ -0,0 +1,63 @@ +import { test } from '@playwright/test'; +import { data } from '@utils/testData'; +import { LoginPage } from '@pages/loginPage'; +import { LocalSetupPage } from '@pages/localSetupPage'; +import { ApiUtils } from '@utils/apiUtils'; +// import { apiEndpoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; + +test.describe('setup local site', () => { + test.skip(!!process.env.CI, 'skip site setup on CI'); + + // test('download wordpress to desired folder', async ({ page }) => { + + // todo: + /* + 1. create everything using bash script if needed + 2. get desired folder path + 3. download wordpress zip and unzip it + 4. clone desired plugins to wp-plugins + 5. clone theme to theme folder + */ + + // }); + + // test('delete database or all tables ', async ({ page }) => { + // }); + + test('admin setup WP', async ({ page }) => { + const loginPage = new LoginPage(page); + const localSetupPage = new LocalSetupPage(page); + await localSetupPage.setupWp(data.installWp); + await loginPage.adminLogin(data.admin); + await localSetupPage.setPermalinkSettings(data.wpSettings.permalink); + }); + + test('activate basic auth plugin', async () => { + await dbUtils.updateWpOptionTable(dbData.optionName.activePlugins, dbData.plugins, 'serialize'); + // await dbUtils.updateWpOptionTable(dbData.dokan.optionName.dokanActiveModules, dbData.dokan.modules, 'serialize'); + }); + + // test('install and activate theme', async ({ request }) => {} + + // todo: skip global setup for local_setup + + test('activate dokan & woocommerce plugins', async ({ request }) => { + const apiUtils = new ApiUtils(request); + const plugins = [ + 'woocommerce/woocommerce', + 'dokan/dokan', + 'dokan-pro/dokan-pro', + 'woocommerce-bookings/woocommerce-bookings', + 'woocommerce-product-addons/woocommerce-product-addons', + 'woocommerce-simple-auctions/woocommerce-simple-auctions', + 'woocommerce-subscriptions/woocommerce-subscriptions', + ]; + for (const plugin of plugins) { + const activePlugins = await apiUtils.updatePlugin(plugin, { status: 'active' }, payloads.adminAuth); + console.log(activePlugins); + } + }); +}); diff --git a/tests/pw/tests/e2e/abuseReports.spec.ts b/tests/pw/tests/e2e/abuseReports.spec.ts new file mode 100644 index 0000000000..c2361509c6 --- /dev/null +++ b/tests/pw/tests/e2e/abuseReports.spec.ts @@ -0,0 +1,80 @@ +import { test, Page } from '@playwright/test'; +import { AbuseReportsPage } from '@pages/abuseReportsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { dbData } from '@utils/dbData'; +import { payloads } from '@utils/payloads'; + +const { VENDOR_ID, CUSTOMER_ID } = process.env; + +test.describe('Abuse report test', () => { + let admin: AbuseReportsPage; + let customer: AbuseReportsPage; + let guest: AbuseReportsPage; + let aPage: Page, cPage: Page, uPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new AbuseReportsPage(aPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new AbuseReportsPage(cPage); + + const guestContext = await browser.newContext(data.auth.noAuth); + uPage = await guestContext.newPage(); + guest = new AbuseReportsPage(uPage); + + apiUtils = new ApiUtils(request); + const productId = await apiUtils.getProductId(data.predefined.simpleProduct.product1.name, payloads.vendorAuth); + await dbUtils.createAbuseReport(dbData.dokan.createAbuseReport, productId, VENDOR_ID, CUSTOMER_ID); + }); + + test.afterAll(async () => { + await aPage.close(); + await cPage.close(); + await uPage.close(); + }); + + test('dokan abuse report menu page is rendering properly @pro @explo', async () => { + await admin.adminAbuseReportRenderProperly(); + }); + + test('admin can view abuse report details @pro @explo', async () => { + await admin.abuseReportDetails(); + }); + + test('admin can filter abuse reports by abuse reason @pro', async () => { + await admin.filterAbuseReports('This content is spam', 'by-reason'); + }); + + test('admin can filter abuse reports by product @pro', async () => { + await admin.filterAbuseReports(data.predefined.simpleProduct.product1.name, 'by-product'); + }); + + test('admin can filter abuse reports by vendor @pro', async () => { + await admin.filterAbuseReports(data.predefined.vendorStores.vendor1, 'by-vendor'); + }); + + test('admin can perform abuse report bulk action @pro', async () => { + await admin.abuseReportBulkAction('delete'); + }); + + // customer + + test('customer can report product @pro', async () => { + await customer.reportProduct(data.predefined.simpleProduct.product1.name, data.product.report); + }); + + test('guest customer can report product @pro', async () => { + await guest.reportProduct(data.predefined.simpleProduct.product1.name, data.product.report); + }); + + test('only logged-in customer can report product @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.productReportAbuse, { ...dbData.dokan.productReportAbuseSettings, reported_by_logged_in_users_only: 'on' }); + await guest.reportProduct(data.predefined.simpleProduct.product1.name, data.product.report); + }); +}); diff --git a/tests/pw/tests/e2e/admin.spec.ts b/tests/pw/tests/e2e/admin.spec.ts new file mode 100644 index 0000000000..612341b448 --- /dev/null +++ b/tests/pw/tests/e2e/admin.spec.ts @@ -0,0 +1,95 @@ +import { test, Page } from '@playwright/test'; +import { LoginPage } from '@pages/loginPage'; +import { AdminPage } from '@pages/adminPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Admin user functionality test', () => { + test.use({ storageState: { cookies: [], origins: [] } }); + + let loginPage: LoginPage; + let page: Page; + + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + page = await context.newPage(); + loginPage = new LoginPage(page); + }); + + test.afterAll(async () => { + await page.close(); + }); + + test('admin can login @lite', async () => { + await loginPage.adminLogin(data.admin); + }); + + test('admin can logout @lite', async () => { + await loginPage.adminLogin(data.admin); + await loginPage.logoutBackend(); + }); +}); + +test.describe('Admin functionality test', () => { + let adminPage: AdminPage; + let aPage: Page; + + test.beforeAll(async ({ browser }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + adminPage = new AdminPage(aPage); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + // test('admin can add categories @lite', async ( ) => { + // await adminPage.addCategory(data.product.category.randomCategory()); + // }); + + // test('admin can add attributes @lite', async ( ) => { + // await adminPage.addAttributes(data.product.attribute.randomAttribute()); + // }); + + // settings + + // tax settings + // test('admin can set standard tax rate', async ( ) => { + // await adminPage.addStandardTaxRate(data.tax) + // }) + + // shipping settings + // test('admin can set flat rate shipping', async ( ) => { + // await adminPage.addShippingMethod(data.shipping.shippingMethods.flatRate); + // }); + + // test('admin can set free shipping', async ( ) => { + // await adminPage.addShippingMethod(data.shipping.shippingMethods.freeShipping) + // }) + + // test('admin can set local pickup shipping', async ( ) => { + // await adminPage.addShippingMethod(data.shipping.shippingMethods.localPickup) + // }) + + // test('admin can set table rate shipping', async ( ) => { + // await adminPage.addShippingMethod(data.shipping.shippingMethods.tableRateShipping) + // }) + + // test('admin can set distance rate shipping', async ( ) => { + // await adminPage.addShippingMethod(data.shipping.shippingMethods.distanceRateShipping) + // }) + + // test('admin can set vendor shipping', async ( ) => { + // await adminPage.addShippingMethod(data.shipping.shippingMethods.vendorShipping) + // }) + + test('dokan notice @lite', async () => { + await adminPage.dokanNotice(); + }); + + test('dokan promotion @lite', async () => { + await adminPage.dokanPromotion(); + }); +}); diff --git a/tests/pw/tests/e2e/adminDashboard.spec.ts b/tests/pw/tests/e2e/adminDashboard.spec.ts new file mode 100644 index 0000000000..019a0a14cc --- /dev/null +++ b/tests/pw/tests/e2e/adminDashboard.spec.ts @@ -0,0 +1,35 @@ +import { test, Page } from '@playwright/test'; +import { AdminDashboardPage } from '@pages/adminDashboardPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Admin dashboard test', () => { + let admin: AdminDashboardPage; + let aPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new AdminDashboardPage(aPage); + apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan admin dashboard is rendering properly @lite @explo', async () => { + await admin.adminDashboardRenderProperly(); + }); + + test('admin dashboard at a glance values are accurate @lite', async () => { + const summary = await apiUtils.getAdminReportSummary(payloads.adminAuth); + await admin.dokanAtAGlanceValueAccuracy(summary); + }); + + test('admin can add dokan news subscriber @lite', async () => { + await admin.addDokanNewsSubscriber(data.user.userDetails); + }); +}); diff --git a/tests/pw/tests/e2e/announcements.spec.ts b/tests/pw/tests/e2e/announcements.spec.ts new file mode 100644 index 0000000000..c0d6498bc7 --- /dev/null +++ b/tests/pw/tests/e2e/announcements.spec.ts @@ -0,0 +1,94 @@ +import { test, Page } from '@playwright/test'; +import { AnnouncementsPage } from '@pages/announcementsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Announcements test', () => { + let admin: AnnouncementsPage; + let aPage: Page; + let apiUtils: ApiUtils; + let announcementTitle: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new AnnouncementsPage(aPage); + + apiUtils = new ApiUtils(request); + [, , announcementTitle] = await apiUtils.createAnnouncement({ ...payloads.createAnnouncement(), status: 'draft' }, payloads.adminAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan announcements menu page is rendering properly @pro @explo', async () => { + await admin.adminAnnouncementsRenderProperly(); + }); + + test('admin can add announcement @pro', async () => { + await admin.addAnnouncement({ ...data.announcement, title: data.announcement.randomTitle() }); + }); + + test('admin can schedule announcement @pro', async () => { + await admin.addAnnouncement({ ...data.announcement, title: data.announcement.randomTitle(), publishType: 'schedule' }); + }); + + test('admin can edit announcement @pro', async () => { + await admin.editAnnouncement({ ...data.announcement, title: announcementTitle }); + }); + + test('admin can trash announcement @pro', async () => { + await admin.updateAnnouncement(announcementTitle, 'trash'); + }); + + test('admin can restore announcement @pro', async () => { + const [, , announcementTitle] = await apiUtils.createAnnouncement({ ...payloads.createAnnouncement(), status: 'trash' }, payloads.adminAuth); + await admin.updateAnnouncement(announcementTitle, 'restore'); + }); + + test('admin can permanently delete announcement @pro', async () => { + const [, , announcementTitle] = await apiUtils.createAnnouncement({ ...payloads.createAnnouncement(), status: 'trash' }, payloads.adminAuth); + await admin.updateAnnouncement(announcementTitle, 'permanently-delete'); + }); + + test('admin can perform announcements bulk action @pro', async () => { + // await apiUtils.createAnnouncement(payloads.createAnnouncement(), payloads.adminAuth); + await admin.announcementBulkAction('trash'); + }); +}); + +test.describe('Announcements test vendor', () => { + let vendor: AnnouncementsPage; + let vPage: Page; + let apiUtils: ApiUtils; + const announcement = payloads.createAnnouncement(); + + test.beforeAll(async ({ browser, request }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new AnnouncementsPage(vPage); + + apiUtils = new ApiUtils(request); + await apiUtils.createAnnouncement(announcement, payloads.adminAuth); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + // vendor + + test('vendor announcement menu page is rendering properly @pro @explo', async () => { + await vendor.vendorAnnouncementsRenderProperly(); + }); + + test('vendor can view announcement details @pro', async () => { + await vendor.vendorViewAnnouncement(announcement); + }); + + test('vendor can delete announcement @pro', async () => { + await vendor.vendorDeleteAnnouncement(announcement.title); + }); +}); diff --git a/tests/pw/tests/e2e/calculation.spec.ts b/tests/pw/tests/e2e/calculation.spec.ts new file mode 100644 index 0000000000..526bb6925c --- /dev/null +++ b/tests/pw/tests/e2e/calculation.spec.ts @@ -0,0 +1,115 @@ +// import { test, expect, Page } from '@playwright/test'; +// import { data } from '@utils/testData'; +// import { helpers } from '@utils/helpers'; +// import { LoginPage } from '@pages/loginPage'; +// import { AdminPage } from '@pages/adminPage'; +// import { CustomerPage } from '@pages/customerPage'; +// import { VendorPage } from '@pages/vendorPage'; + +// test.describe.skip( 'Calculation functionality test', () => { +// test('refund through rma test', async ({ page }) => { +// const loginPage = new LoginPage(page); +// const adminPage = new AdminPage(page); +// const vendorPage = new VendorPage(page); +// const customerPage = new CustomerPage(page); +// // let productName = data.product.name.simple +// const productName = 'product1'; +// //create product +// // await loginPage.login(data.vendor) +// // await vendorPage.addSimpleProduct(data.product.name.simple, data.product.price, data.product.category +// // buy product +// // await loginPage.switchUser(data.customer) +// await loginPage.login(data.customer); +// const cOrderDetails = await customerPage.buyProduct(productName, false, true); +// //update order status +// await loginPage.switchUser(data.vendor); +// await vendorPage.changeOrderStatus(cOrderDetails.orderNumber, data.orderStatus[1]); +// //send refund request +// await loginPage.switchUser(data.customer); +// await customerPage.sendWarrantyRequest(cOrderDetails.orderNumber, productName, data.order.refundRequestType, data.order.refundRequestReasons, data.order.refundRequestDetails); +// //vendor approve rma request +// await loginPage.switchUser(data.vendor); +// await vendorPage.approveReturnRequest(cOrderDetails.orderNumber, productName); +// // await vendorPage.deleteReturnRequest(orderId +// //admin approve refund request +// await loginPage.switchUser(data.admin); +// await adminPage.approveRefundRequest(cOrderDetails.orderNumber, true); +// }); + +// test('vendor refund test', async ({ page }) => { +// const loginPage = new LoginPage(page); +// const adminPage = new AdminPage(page); +// const vendorPage = new VendorPage(page); +// const customerPage = new CustomerPage(page); +// // let productName = data.product.name.simple +// const productName = 'product1'; +// //create product +// // await loginPage.login(data.vendor) +// // await vendorPage.addSimpleProduct(productName, data.product.price, data.product.category +// // buy product +// // await loginPage.switchUser(data.customer) +// await loginPage.login(data.customer); +// const cOrderDetails = await customerPage.buyProduct(productName, false, true); +// //refund order +// await loginPage.switchUser(data.vendor); +// await vendorPage.changeOrderStatus(cOrderDetails.orderNumber, data.orderStatus[1]); +// await vendorPage.refundOrder(cOrderDetails.orderNumber, productName, true); +// // approve refund request +// await loginPage.switchUser(data.admin); +// await adminPage.approveRefundRequest(cOrderDetails.orderNumber, true); +// }); + +// test( 'calculation test', async ( { browser } ) => { +// const adminContext = await browser.newContext( { storageState: 'adminStorageState.json' } ); +// const adminPage = await adminContext.newPage(); +// const vendorContext = await browser.newContext( { storageState: 'vendorStorageState.json' } ); +// const vendorPage = await vendorContext.newPage(); +// const customerContext = await browser.newContext( { storageState: 'customerStorageState.json' } ); +// const customerPage = await customerContext.newPage(); + +// const productName = data.predefined.simpleProduct.product1.name; + +// const cOrderDetails0 = await customerPage.buyProduct( productName, false, true, 'bank' ); +// const cOrderDetails = await customerPage.getOrderDetails( cOrderDetails0.orderNumber ); + +// //vendor order details +// const aOrderDetails = await adminPage.getOrderDetails( cOrderDetails.orderNumber ); + +// //admin order details +// const vOrderDetails = await vendorPage.getOrderDetails( cOrderDetails.orderNumber ); + +// console.log( 'cOrderDetails: ', cOrderDetails, 'aOrderDetails: ', aOrderDetails, 'vOrderDetails: ', vOrderDetails ); + +// const subtotal = cOrderDetails.subtotal; +// const taxRate = Number( process.env.TAX_RATE ); +// const commissionRate = Number( process.env.COMMISSION_RATE ); +// const shipping = 0; +// const gatewayFee = 0; +// const calculatedTax = helpers.tax( taxRate, subtotal, shipping ); +// const calculatedOrderTotal = helpers.orderTotal( subtotal, calculatedTax, shipping ); +// const calculatedAdminCommission = helpers.adminCommission( subtotal, commissionRate, calculatedTax, shipping, gatewayFee ); +// const calculatedVendorEarning = helpers.vendorEarning( subtotal, calculatedAdminCommission, calculatedTax, shipping, gatewayFee ); +// console.log( calculatedTax, calculatedOrderTotal, calculatedAdminCommission, calculatedVendorEarning ); + +// console.log( `orderNumber : c:${ cOrderDetails.orderNumber }, a:${ aOrderDetails.orderNumber }, v:${ vOrderDetails.orderNumber }` ); +// console.log( `orderStatus : c:${ cOrderDetails.orderStatus }, a:${ aOrderDetails.orderStatus }, v:${ vOrderDetails.orderStatus }` ); +// console.log( `orderStatus : c:${ cOrderDetails.orderDate }, a:${ aOrderDetails.orderDate }, v:${ vOrderDetails.orderDate }` ); +// console.log( `subtotal : c:${ cOrderDetails.subtotal }` ); +// console.log( `shipping : c:${ cOrderDetails.shippingMethod }, v:${ vOrderDetails.shippingMethod }` ); +// console.log( `shipping : c:${ cOrderDetails.shippingCost }, a:${ aOrderDetails.shippingCost }, v:${ vOrderDetails.shippingCost }` ); +// console.log( `tax : cal:${ calculatedTax }, c:${ cOrderDetails.tax }, a:${ aOrderDetails.tax }, v:${ vOrderDetails.tax }` ); +// console.log( `orderTotal : cal:${ calculatedOrderTotal }, a:${ aOrderDetails.orderTotal },` ); +// console.log( `commission : cal:${ calculatedAdminCommission }, a:${ aOrderDetails.commission }` ); +// console.log( `vendorEarning : cal:${ calculatedVendorEarning }, a:${ aOrderDetails.vendorEarning }, v:${ vOrderDetails.vendorEarning }` ); + +// expect( cOrderDetails.orderNumber == aOrderDetails.orderNumber == vOrderDetails.orderNumber ).toBeTruthy(); +// expect( cOrderDetails.orderStatus == aOrderDetails.orderStatus == vOrderDetails.orderStatus ).toBeTruthy(); +// expect( cOrderDetails.orderDate == aOrderDetails.orderDate == vOrderDetails.orderDate ).toBeTruthy(); +// expect( calculatedTax == cOrderDetails.tax == aOrderDetails.tax == vOrderDetails.tax ).toBeTruthy(); +// expect( cOrderDetails.shippingMethod == vOrderDetails.shippingMethod ).toBeTruthy(); +// expect( cOrderDetails.shippingCost == aOrderDetails.shippingCost == vOrderDetails.shippingCost ).toBeTruthy(); +// expect( calculatedOrderTotal == cOrderDetails.orderTotal == aOrderDetails.orderTotal == vOrderDetails.orderTotal ).toBeTruthy(); +// expect( calculatedAdminCommission == aOrderDetails.commission ).toBeTruthy(); +// expect( calculatedVendorEarning == aOrderDetails.vendorEarning == vOrderDetails.vendorEarning ).toBeTruthy(); +// } ); +// } ); diff --git a/tests/pw/tests/e2e/coupons.spec.ts b/tests/pw/tests/e2e/coupons.spec.ts new file mode 100644 index 0000000000..fd1023f9c2 --- /dev/null +++ b/tests/pw/tests/e2e/coupons.spec.ts @@ -0,0 +1,78 @@ +import { test, Page } from '@playwright/test'; +import { CouponsPage } from '@pages/couponsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +const { PRODUCT_ID } = process.env; + +test.describe('Coupons test', () => { + let admin: CouponsPage; + let vendor: CouponsPage; + let customer: CouponsPage; + let aPage: Page, vPage: Page, cPage: Page; + let apiUtils: ApiUtils; + let marketplaceCouponCode: string; + let couponCode: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new CouponsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new CouponsPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new CouponsPage(cPage); + + apiUtils = new ApiUtils(request); + [, , marketplaceCouponCode] = await apiUtils.createMarketPlaceCoupon(payloads.createMarketPlaceCoupon(), payloads.adminAuth); + [, , couponCode] = await apiUtils.createCoupon([PRODUCT_ID], payloads.createCoupon(), payloads.vendorAuth); + }); + + test.afterAll(async () => { + await aPage.close(); // todo: close multiple pages to base page + await vPage.close(); + await cPage.close(); + }); + + test('admin can add marketplace coupon @pro', async () => { + await admin.addMarketplaceCoupon({ ...data.coupon, title: data.coupon.couponTitle() }); + }); + + test('vendor coupon menu page is rendering properly @pro @explo', async () => { + await vendor.vendorCouponsRenderProperly(); + }); + + test('vendor can view marketPlace coupon @pro @explo', async () => { + await vendor.viewMarketPlaceCoupon(marketplaceCouponCode); + }); + + test('vendor can add coupon @pro', async () => { + await vendor.addCoupon({ ...data.coupon, title: data.coupon.couponTitle() }); + }); + + test('vendor can edit coupon @pro', async () => { + await vendor.editCoupon({ ...data.coupon, title: couponCode }); + }); + + test('vendor can delete coupon @pro', async () => { + const [, , couponCode] = await apiUtils.createCoupon([PRODUCT_ID], payloads.createCoupon(), payloads.vendorAuth); + await vendor.deleteCoupon(couponCode); + }); + + test('customer can view coupon on single store @pro', async () => { + await customer.viewStoreCoupon(data.predefined.vendorStores.vendor1, couponCode); + }); + + test('customer can apply coupon @pro', async () => { + await customer.applyCoupon(data.predefined.simpleProduct.product1.name, data.predefined.coupon.couponCode); + }); + + test('customer can buy product with coupon @pro', async () => { + await customer.buyProductWithCoupon(data.predefined.simpleProduct.product1.name, data.predefined.coupon.couponCode); + }); +}); diff --git a/tests/pw/tests/e2e/customer.spec.ts b/tests/pw/tests/e2e/customer.spec.ts new file mode 100644 index 0000000000..9e6c93edf3 --- /dev/null +++ b/tests/pw/tests/e2e/customer.spec.ts @@ -0,0 +1,94 @@ +import { test, Page, BrowserContext } from '@playwright/test'; +import { LoginPage } from '@pages/loginPage'; +import { CustomerPage } from '@pages/customerPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Customer user functionality test', () => { + test.use({ storageState: { cookies: [], origins: [] } }); + + let loginPage: LoginPage; + let customer: CustomerPage; + let page: Page; + + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + page = await context.newPage(); + loginPage = new LoginPage(page); + customer = new CustomerPage(page); + }); + + test.afterAll(async () => { + await page.close(); + }); + + test('customer can register @lite', async () => { + await customer.customerRegister(data.customer.customerInfo); + }); + + test('customer can login @lite', async () => { + await loginPage.login(data.customer); + }); + + test('customer can logout @lite', async () => { + await loginPage.login(data.customer); + await loginPage.logout(); + }); + + test('customer can become a vendor @lite', async () => { + await customer.customerRegister(data.customer.customerInfo); + await customer.customerBecomeVendor(data.customer.customerInfo); + }); +}); + +test.describe('Customer functionality test', () => { + let customer: CustomerPage; + let cPage: Page; + let customerContext: BrowserContext; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + customerContext = await browser.newContext({ storageState: data.auth.customerAuthFile }); + cPage = await customerContext.newPage(); + customer = new CustomerPage(cPage); + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await cPage.close(); + }); + + test('customer can add billing details @lite', async () => { + await customer.addBillingAddress(data.customer.customerInfo.billing); + }); + + test('customer can add shipping details @lite', async () => { + await customer.addShippingAddress(data.customer.customerInfo.shipping); + }); + + test('customer can add customer details @lite', async () => { + await customer.addCustomerDetails(data.customer); + }); + + test('customer can add product to cart @lite', async () => { + const productName = data.predefined.simpleProduct.product1.name; + await customer.addProductToCart(productName, 'single-product'); + await customer.productIsOnCart(productName); + }); + + test('customer can buy product @lite', async () => { + await customer.addProductToCart(data.predefined.simpleProduct.product1.name, 'single-product'); + await customer.placeOrder(); + }); + + test('customer can buy multi vendor products @lite', async () => { + await customer.addProductToCart(data.predefined.simpleProduct.product1.name, 'single-product'); + await customer.addProductToCart(data.predefined.vendor2.simpleProduct.product1.name, 'single-product', false); + await customer.placeOrder(); + }); + + // test.skip('customer can download downloadables @lite', async ( ) => { + // pre: complete download product + // }); +}); diff --git a/tests/pw/tests/e2e/emailVerification.spec.ts b/tests/pw/tests/e2e/emailVerification.spec.ts new file mode 100644 index 0000000000..71c27b167e --- /dev/null +++ b/tests/pw/tests/e2e/emailVerification.spec.ts @@ -0,0 +1,32 @@ +import { test, Page } from '@playwright/test'; +import { EmailVerificationsPage } from '@pages/emailVerificationsPage'; +import { data } from '@utils/testData'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; + +test.describe('Email verifications test', () => { + let guest: EmailVerificationsPage; + let uPage: Page; + const user = { username: data.user.username() + data.user.userDetails.emailDomain, password: data.user.password }; + + test.beforeAll(async ({ browser }) => { + const guestContext = await browser.newContext(data.auth.noAuth); + uPage = await guestContext.newPage(); + guest = new EmailVerificationsPage(uPage); + + await dbUtils.setDokanSettings(dbData.dokan.optionName.emailVerification, { ...dbData.dokan.emailVerificationSettings, enabled: 'on' }); + }); + + test.afterAll(async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.emailVerification, dbData.dokan.emailVerificationSettings); + await uPage.close(); + }); + + test('user can see registration notice (2-step authentication) while registering as customer @pro ', async () => { + await guest.register(user); + }); + + test('user can see registration notice (2-step authentication) while loggingIn @pro ', async () => { + await guest.login(user); + }); +}); diff --git a/tests/pw/tests/e2e/followStore.spec.ts b/tests/pw/tests/e2e/followStore.spec.ts new file mode 100644 index 0000000000..7d43927e6d --- /dev/null +++ b/tests/pw/tests/e2e/followStore.spec.ts @@ -0,0 +1,52 @@ +import { test, Page } from '@playwright/test'; +import { FollowStorePage } from '@pages/followStorePage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Follow stores functionality test', () => { + let vendor: FollowStorePage; + let customer: FollowStorePage; + let vPage: Page, cPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new FollowStorePage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new FollowStorePage(cPage); + + // apiUtils = new ApiUtils(request); + // todo: need followers + }); + + test.afterAll(async () => { + await vPage.close(); + await cPage.close(); + }); + + // follow store + + test('customer followed vendors menu page is rendering properly @pro @explo', async () => { + await customer.customerFollowedVendorsRenderProperly(); + }); + + test('customer can follow store on store listing @pro', async () => { + await customer.followStore(data.predefined.vendorStores.vendor1, data.predefined.vendorStores.followFromStoreListing); + }); + + test('customer can follow store on single store @pro', async () => { + await customer.followStore(data.predefined.vendorStores.vendor1, data.predefined.vendorStores.followFromSingleStore); + }); + + test('vendor followers menu page is rendering properly @pro @explo', async () => { + await vendor.vendorFollowersRenderProperly(); + }); + + test('vendor can view followers @pro ', async () => { + await vendor.vendorViewFollowers(); + }); +}); diff --git a/tests/pw/tests/e2e/help.spec.ts b/tests/pw/tests/e2e/help.spec.ts new file mode 100644 index 0000000000..87245030af --- /dev/null +++ b/tests/pw/tests/e2e/help.spec.ts @@ -0,0 +1,26 @@ +import { test, Page } from '@playwright/test'; +import { HelpPage } from '@pages/helpPage'; +import { data } from '@utils/testData'; + +test.describe('Dokan help test', () => { + let admin: HelpPage; + let aPage: Page; + + test.beforeAll(async ({ browser }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new HelpPage(aPage); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan help menu page is rendering properly @lite @explo', async () => { + await admin.adminHelpRenderProperly(); + }); + + test('dokan get help dropdown is rendering properly @lite @explo', async () => { + await admin.adminGetHelpDropdownRenderProperly(); + }); +}); diff --git a/tests/pw/tests/e2e/license.spec.ts b/tests/pw/tests/e2e/license.spec.ts new file mode 100644 index 0000000000..f6293a12f0 --- /dev/null +++ b/tests/pw/tests/e2e/license.spec.ts @@ -0,0 +1,30 @@ +import { test, Page } from '@playwright/test'; +import { LicensePage } from '@pages/licensePage'; +import { data } from '@utils/testData'; + +test.describe('License test', () => { + let admin: LicensePage; + let aPage: Page; + + test.beforeAll(async ({ browser }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new LicensePage(aPage); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan license menu page is rendering properly @pro @explo', async () => { + await admin.adminLicenseRenderProperly(); + }); + + // test.skip('admin can activate license @pro', async ( ) => { + // await admin.activateLicense(data.dokanLicense.correctKey); + // }); + + test("admin can't activate license with incorrect key @pro @neg", async () => { + await admin.activateLicense(data.dokanLicense.incorrectKey, 'incorrect'); + }); +}); diff --git a/tests/pw/tests/e2e/modules.spec.ts b/tests/pw/tests/e2e/modules.spec.ts new file mode 100644 index 0000000000..3408b233b8 --- /dev/null +++ b/tests/pw/tests/e2e/modules.spec.ts @@ -0,0 +1,46 @@ +import { test, Page } from '@playwright/test'; +import { ModulesPage } from '@pages/modulesPage'; +import { data } from '@utils/testData'; + +test.describe('Modules test', () => { + let admin: ModulesPage; + let aPage: Page; + + test.beforeAll(async ({ browser }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new ModulesPage(aPage); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan modules menu page is rendering properly @pro @explo', async () => { + await admin.adminModulesRenderProperly(); + }); + + test('admin can search module @pro', async () => { + await admin.searchModule(data.modules.modulesName.AuctionIntegration); + }); + + test('admin can filter modules by category @pro', async () => { + await admin.filterModules(data.modules.moduleCategory.productManagement); + }); + + test('admin can deactivate module @pro', async () => { + await admin.activateDeactivateModule(data.modules.modulesName.AuctionIntegration); + }); + + test('admin can activate module @pro', async () => { + await admin.activateDeactivateModule(data.modules.modulesName.AuctionIntegration); + }); + + test('admin can perform module bulk action @pro', async () => { + await admin.moduleBulkAction('activate'); + }); + + test('admin can change module view layout @pro', async () => { + await admin.moduleViewLayout(data.modules.layout.list); + }); +}); diff --git a/tests/pw/tests/e2e/myOrders.spec.ts b/tests/pw/tests/e2e/myOrders.spec.ts new file mode 100644 index 0000000000..d1d0f3a6bd --- /dev/null +++ b/tests/pw/tests/e2e/myOrders.spec.ts @@ -0,0 +1,54 @@ +import { test, Page } from '@playwright/test'; +import { MyOrdersPage } from '@pages/myOrdersPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +const { CUSTOMER_ID, PRODUCT_ID } = process.env; + +test.describe('My orders functionality test', () => { + let customer: MyOrdersPage; + let cPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new MyOrdersPage(cPage); + apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await cPage.close(); + }); + + test('customer my orders page is rendering properly @lite', async () => { + await customer.myOrdersRenderProperly(); + }); + + test('customer can view order details @lite', async () => { + const [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.completed, payloads.vendorAuth); + await customer.viewOrderDetails(orderId); + }); + + test('customer can view order note @lite', async () => { + const orderNote = data.orderNote.note(); + const [, orderId] = await apiUtils.createOrderNote(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, { ...payloads.createOrderNoteForCustomer, note: orderNote }, payloads.vendorAuth); + await customer.viewOrderNote(orderId, orderNote); + }); + + test('customer can pay pending payment order @lite', async () => { + const [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.pending, payloads.vendorAuth); + await customer.payPendingOrder(orderId, 'bank'); + }); + + test('customer can cancel order @lite', async () => { + const [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.pending, payloads.vendorAuth); + await customer.cancelPendingOrder(orderId); + }); + + test('customer can order again @lite', async () => { + const [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.completed, payloads.vendorAuth); + await customer.orderAgain(orderId); + }); +}); diff --git a/tests/pw/tests/e2e/orders.spec.ts b/tests/pw/tests/e2e/orders.spec.ts new file mode 100644 index 0000000000..ba6d0d4552 --- /dev/null +++ b/tests/pw/tests/e2e/orders.spec.ts @@ -0,0 +1,96 @@ +import { test, Page } from '@playwright/test'; +import { OrdersPage } from '@pages/ordersPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; + +const { DOKAN_PRO, CUSTOMER_ID, PRODUCT_ID } = process.env; + +test.describe('Order functionality test', () => { + let vendor: OrdersPage; + let vPage: Page; + let apiUtils: ApiUtils; + let orderId: string; + + test.beforeAll(async ({ browser, request }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new OrdersPage(vPage); + + apiUtils = new ApiUtils(request); + [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.onhold, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + // orders + + test('vendor order menu page is rendering properly @lite @explo', async () => { + await vendor.vendorOrdersRenderProperly(); + }); + + test('vendor can export all orders @lite', async () => { + await vendor.exportOrders('all'); + }); + + test('vendor can export filtered orders @lite', async () => { + await vendor.filterOrders('by-customer', data.customer.username); + await vendor.exportOrders('filtered'); + }); + + test('vendor can search order @lite', async () => { + await vendor.searchOrder(orderId); + }); + + test('vendor can filter orders by customer @lite', async () => { + await vendor.filterOrders('by-customer', data.customer.username); + }); + + test('vendor can filter orders by date range @lite', async () => { + await vendor.filterOrders('by-date', data.date.dateRange); + }); + + test('vendor can view order details @lite', async () => { + await vendor.viewOrderDetails(orderId); + }); + + test('vendor can update order status on table @lite', async () => { + await vendor.updateOrderStatusOnTable(orderId, data.order.orderStatus.processing); + }); + + test('vendor can update order status on order details @lite', async () => { + await vendor.updateOrderStatus(orderId, data.order.orderStatus.completed); + }); + + test('vendor can add order note @lite', async () => { + await vendor.addOrderNote(orderId, data.orderNote.customer); + }); + + test('vendor can add private order note @lite', async () => { + await vendor.addOrderNote(orderId, data.orderNote.private); + }); + + test('vendor can add tracking details to order @lite', async () => { + DOKAN_PRO && (await dbUtils.setDokanSettings(dbData.dokan.optionName.shippingStatus, { ...dbData.dokan.shippingStatusSettings, enabled: 'off' })); + await vendor.addTrackingDetails(orderId, data.orderTrackingDetails); + DOKAN_PRO && (await dbUtils.setDokanSettings(dbData.dokan.optionName.shippingStatus, { ...dbData.dokan.shippingStatusSettings, enabled: 'on' })); + }); + + test('vendor can add shipment to order @pro', async () => { + await vendor.addShipment(orderId, data.orderShipmentDetails); + }); + + // test.skip('vendor can add downloadable product permission to order @lite', async ( ) => { + // const [,, downloadableProductName] = await apiUtils.createProduct(payloads.createDownloadableProduct(), payloads.vendorAuth); + // await vendor.addDownloadableProduct(orderId, downloadableProductName); + // await vendor.removeDownloadableProduct(orderId, downloadableProductName); + // }); + + test('vendor can perform order bulk action @lite', async () => { + await vendor.orderBulkAction('completed', orderId); + }); +}); diff --git a/tests/pw/tests/e2e/payments.spec.ts b/tests/pw/tests/e2e/payments.spec.ts new file mode 100644 index 0000000000..bc92c9a5e0 --- /dev/null +++ b/tests/pw/tests/e2e/payments.spec.ts @@ -0,0 +1,89 @@ +import { test, Page } from '@playwright/test'; +import { PaymentsPage } from '@pages/paymentsPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; + +test.describe('Payments test', () => { + // let admin: PaymentsPage; + let vendor: PaymentsPage; + // let aPage: Page, vPage: Page; + let vPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + // const adminContext = await browser.newContext(data.auth.adminAuth); + // aPage = await adminContext.newPage(); + // admin = new PaymentsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new PaymentsPage(vPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + // await aPage.close(); + await vPage.close(); + }); + + // test('admin can add basic payment methods', async ( ) => { + // await adminPage.setupBasicPaymentMethods(data.payment) + // }) + + // test('admin can add strip payment method', async ( ) => { + // await adminPage.setupStripeConnect(data.payment) + // }) + + // test('admin can add paypal marketplace payment method', async ( ) => { + // await adminPage.setupPaypalMarketPlace(data.payment) + // }) + + // test('admin can add mangopay payment method', async ( ) => { + // await adminPage.setupMangoPay(data.payment) + // }) + + // test('admin can add razorpay payment method', async ( ) => { + // await adminPage.setupRazorpay(data.payment) + // }) + + // test('admin can add strip express payment method', async ( ) => { + // await adminPage.setupStripeExpress(data.payment) + // }) + + test('vendor payment menu is rendering properly @lite @explo', async () => { + await vendor.vendorPaymentSettingsRenderProperly(); + }); + + test('vendor can add paypal payment method @lite', async () => { + await vendor.setBasicPayment({ ...data.vendor.payment, methodName: 'paypal' }); + }); + + test('vendor can add bank payment method @lite', async () => { + await vendor.setBankTransfer(data.vendor.payment); + }); + + test('vendor can add skrill payment method @pro', async () => { + await vendor.setBasicPayment({ ...data.vendor.payment, methodName: 'skrill' }); + }); + + test('vendor can add custom payment method @pro', async () => { + await vendor.setBasicPayment({ ...data.vendor.payment, methodName: 'custom' }); + }); + + test('vendor can disconnect paypal payment method @lite', async () => { + await vendor.disconnectBasicPayment({ ...data.vendor.payment, methodName: 'paypal' }); + }); + + test('vendor can disconnect bank payment method @lite', async () => { + await vendor.disconnectBasicPayment({ ...data.vendor.payment, methodName: 'bank' }); + }); + + test('vendor can disconnect skrill payment method @pro', async () => { + await vendor.disconnectBasicPayment({ ...data.vendor.payment, methodName: 'skrill' }); + }); + + test('vendor can disconnect custom payment method @pro', async () => { + await vendor.disconnectBasicPayment({ ...data.vendor.payment, methodName: 'custom' }); + }); +}); diff --git a/tests/pw/tests/e2e/proPromo.spec.ts b/tests/pw/tests/e2e/proPromo.spec.ts new file mode 100644 index 0000000000..7c079c692f --- /dev/null +++ b/tests/pw/tests/e2e/proPromo.spec.ts @@ -0,0 +1,29 @@ +import { test, Page } from '@playwright/test'; +import { ProPromoPage } from '@pages/proPromoPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Dokan pro feature promo test', () => { + let admin: ProPromoPage; + let aPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new ProPromoPage(aPage); + + apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan pro features promo @liteOnly', async () => { + // await apiUtils.updatePlugin('dokan-pro/dokan-pro', { status:'inactive' }, payloads.adminAuth); + await admin.dokanProPromo(); + // await apiUtils.updatePlugin('dokan-pro/dokan-pro', { status:'active' }, payloads.adminAuth); + }); +}); diff --git a/tests/pw/tests/e2e/productAddons.spec.ts b/tests/pw/tests/e2e/productAddons.spec.ts new file mode 100644 index 0000000000..aceb86b332 --- /dev/null +++ b/tests/pw/tests/e2e/productAddons.spec.ts @@ -0,0 +1,40 @@ +import { test, Page } from '@playwright/test'; +import { ProductAddonsPage } from '@pages/productAddonsPage'; +import { data } from '@utils/testData'; + +test.describe('Product addon functionality test', () => { + let vendor: ProductAddonsPage; + let vPage: Page; + let addonName: string; + let addonFieldTitle: string; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new ProductAddonsPage(vPage); + + addonName = data.vendor.addon.randomName(); + addonFieldTitle = data.vendor.addon.randomTitle(); + await vendor.addAddon({ ...data.vendor.addon, name: addonName, titleRequired: addonFieldTitle }); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor product addons menu page is rendering properly @pro @explo', async () => { + await vendor.vendorProductAddonsSettingsRenderProperly(); + }); + + test('vendor can add addons @pro', async () => { + await vendor.addAddon({ ...data.vendor.addon, name: data.vendor.addon.randomName() }); + }); + + test('vendor can edit addon @pro', async () => { + await vendor.editAddon({ ...data.vendor.addon, name: addonName, titleRequired: addonFieldTitle }); + }); + + test('vendor can delete addon @pro', async () => { + await vendor.deleteAddon({ ...data.vendor.addon, name: addonName }); + }); +}); diff --git a/tests/pw/tests/e2e/productAdvertising.spec.ts b/tests/pw/tests/e2e/productAdvertising.spec.ts new file mode 100644 index 0000000000..ffb7f81bf4 --- /dev/null +++ b/tests/pw/tests/e2e/productAdvertising.spec.ts @@ -0,0 +1,81 @@ +import { test, Page } from '@playwright/test'; +import { ProductAdvertisingPage } from '@pages/productAdvertisingPage'; +import { VendorPage } from '@pages/vendorPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Product Advertising test', () => { + let admin: ProductAdvertisingPage; + let vendor: VendorPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + let productName: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new ProductAdvertisingPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorPage(vPage); + + apiUtils = new ApiUtils(request); + [, , productName] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendorAuth); + await apiUtils.createProductAdvertisement(payloads.createProduct(), payloads.vendorAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + }); + + test('dokan product advertising menu page is rendering properly @pro @explo', async () => { + await admin.adminProductAdvertisingRenderProperly(); + }); + + test('admin can add product advertisement @pro', async () => { + await admin.addNewProductAdvertisement({ ...data.productAdvertisement, advertisedProduct: productName }); + }); + + test('admin can search advertised product @pro', async () => { + await admin.searchAdvertisedProduct(productName); + }); + + test('admin can filter advertised product by stores @pro', async () => { + await admin.filterAdvertisedProduct(data.productAdvertisement.filter.byStore, 'by-store'); + }); + + test('admin can filter advertised product by creation process @pro', async () => { + await admin.filterAdvertisedProduct(data.productAdvertisement.filter.createVia.admin, 'by-creation'); + }); + + test('admin can expire advertised product @pro', async () => { + await admin.updateAdvertisedProduct(productName, 'expire'); + }); + + test('admin can delete advertised product @pro', async () => { + await admin.updateAdvertisedProduct(productName, 'delete'); + }); + + test('admin can perform product advertising bulk action @pro', async () => { + // await apiUtils.createProductAdvertisement(payloads.createProduct(), payloads.vendorAuth); + await admin.productAdvertisingBulkAction('delete'); + }); + + test('vendor can buy product advertising @pro', async () => { + const orderId = await vendor.buyProductAdvertising(data.productAdvertisement.advertisedProduct); + await apiUtils.updateOrderStatus(orderId, 'wc-completed', payloads.adminAuth); + }); + + // test('vendor can buy booking product advertising @pro', async ( ) => { // todo: + // const orderId = await vendor.buyProductAdvertising(data.productAdvertisement.advertisedProduct); + // await apiUtils.updateOrderStatus(orderId, 'wc-completed', payloads.adminAuth); + // }); + + // test('vendor can buy auction product advertising @pro', async ( ) => { // todo: + // const orderId = await vendor.buyProductAdvertising(data.productAdvertisement.advertisedProduct); + // await apiUtils.updateOrderStatus(orderId, 'wc-completed', payloads.adminAuth); + // }); +}); diff --git a/tests/pw/tests/e2e/productEnquiry.spec.ts b/tests/pw/tests/e2e/productEnquiry.spec.ts new file mode 100644 index 0000000000..f494585c12 --- /dev/null +++ b/tests/pw/tests/e2e/productEnquiry.spec.ts @@ -0,0 +1,48 @@ +import { test, Page } from '@playwright/test'; +import { ProductEnquiryPage } from '@pages/productEnquiryPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { dbData } from '@utils/dbData'; +import { payloads } from '@utils/payloads'; + +const { VENDOR_ID, CUSTOMER_ID } = process.env; + +test.describe('Product Enquiry test', () => { + // let admin: ProductEnquiryPage; + let customer: ProductEnquiryPage; + let guest: ProductEnquiryPage; + let cPage: Page, uPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + // const adminContext = await browser.newContext(data.auth.adminAuth); + // aPage = await adminContext.newPage(); + // admin = new ProductEnquiryPage(aPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new ProductEnquiryPage(cPage); + + const guestContext = await browser.newContext(data.auth.noAuth); + uPage = await guestContext.newPage(); + guest = new ProductEnquiryPage(uPage); + + apiUtils = new ApiUtils(request); + const productId = await apiUtils.getProductId(data.predefined.simpleProduct.product1.name, payloads.vendorAuth); + await dbUtils.createAbuseReport(dbData.dokan.createAbuseReport, productId, VENDOR_ID, CUSTOMER_ID); + }); + + test.afterAll(async () => { + await cPage.close(); + await uPage.close(); + }); + + test('customer can enquire product @pro', async () => { + await customer.enquireProduct(data.predefined.simpleProduct.product1.name, data.product.enquiry); + }); + + test('guest customer can enquire product @pro', async () => { + await guest.enquireProduct(data.predefined.simpleProduct.product1.name, data.product.enquiry); + }); +}); diff --git a/tests/pw/tests/e2e/productReviews.spec.ts b/tests/pw/tests/e2e/productReviews.spec.ts new file mode 100644 index 0000000000..8969c77b99 --- /dev/null +++ b/tests/pw/tests/e2e/productReviews.spec.ts @@ -0,0 +1,68 @@ +import { test, Page } from '@playwright/test'; +import { ProductReviewsPage } from '@pages/productReviewsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +const { PRODUCT_ID } = process.env; + +test.describe('Product Reviews test', () => { + let vendor: ProductReviewsPage; + let vPage: Page; + let apiUtils: ApiUtils; + let reviewMessage: string; + + test.beforeAll(async ({ browser, request }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new ProductReviewsPage(vPage); + + apiUtils = new ApiUtils(request); + [, , reviewMessage] = await apiUtils.createProductReview(PRODUCT_ID, payloads.createProductReview(), payloads.vendorAuth); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor product reviews menu page is rendering properly @pro @explo', async () => { + await vendor.vendorProductReviewsRenderProperly(); + }); + + test('vendor can view product review @pro @explo', async () => { + await vendor.viewProductReview(reviewMessage); + }); + + test('vendor can unApprove product review @pro', async () => { + await vendor.updateProductReview('unApprove', reviewMessage); + }); + + test('vendor can spam product review @pro', async () => { + const [, , reviewMessage] = await apiUtils.createProductReview(PRODUCT_ID, payloads.createProductReview(), payloads.vendorAuth); + await vendor.updateProductReview('spam', reviewMessage); + }); + + test('vendor can trash product review @pro', async () => { + const [, , reviewMessage] = await apiUtils.createProductReview(PRODUCT_ID, payloads.createProductReview(), payloads.vendorAuth); + await vendor.updateProductReview('trash', reviewMessage); + }); + + test('vendor can approve product review @pro', async () => { + const [, , reviewMessage] = await apiUtils.createProductReview(PRODUCT_ID, { ...payloads.createProductReview(), status: 'hold' }, payloads.vendorAuth); + await vendor.updateProductReview('approve', reviewMessage); + }); + + test('vendor can restore trashed product review @pro', async () => { + const [, , reviewMessage] = await apiUtils.createProductReview(PRODUCT_ID, { ...payloads.createProductReview(), status: 'trash' }, payloads.vendorAuth); + await vendor.updateProductReview('restore', reviewMessage); + }); + + test('vendor can permanently-delete product review @pro', async () => { + const [, , reviewMessage] = await apiUtils.createProductReview(PRODUCT_ID, { ...payloads.createProductReview(), status: 'trash' }, payloads.vendorAuth); + await vendor.updateProductReview('permanently-delete', reviewMessage); + }); + + test('vendor can perform product reviews bulk action @pro', async () => { + await vendor.productReviewsBulkActions('hold'); + }); +}); diff --git a/tests/pw/tests/e2e/products.spec.ts b/tests/pw/tests/e2e/products.spec.ts new file mode 100644 index 0000000000..81bd68761d --- /dev/null +++ b/tests/pw/tests/e2e/products.spec.ts @@ -0,0 +1,154 @@ +import { test, Page } from '@playwright/test'; +import { ProductsPage } from '@pages/productsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Product functionality test', () => { + let admin: ProductsPage; + let vendor: ProductsPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + let productName: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new ProductsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new ProductsPage(vPage); + + apiUtils = new ApiUtils(request); + [, , productName] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendorAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + }); + + test('admin can add product category @lite', async () => { + await admin.addCategory(data.product.category.randomCategory()); + }); + + test('admin can add product attribute @lite', async () => { + await admin.addAttribute(data.product.attribute.randomAttribute()); + }); + + test('admin can add simple product @lite', async () => { + await admin.addSimpleProduct(data.product.simple); + }); + + // test('admin can add variable product @pro', async ( ) => { + // await admin.addVariableProduct(data.product.variable); + // }); + + test('admin can add simple subscription @pro', async () => { + await admin.addSimpleSubscription(data.product.simpleSubscription); + }); + + // test('admin can add variable subscription @pro', async ( ) => { + // await admin.addVariableSubscription(data.product.variableSubscription); + // }); + + test('admin can add external product @lite', async () => { + await admin.addExternalProduct(data.product.external); + }); + + test('admin can add vendor subscription @pro', async () => { + await admin.addDokanSubscription(data.product.vendorSubscription); + }); + + // vendors + + // todo: move create product in separate files, or product functionality to another page + + test('vendor can add simple product @lite', async () => { + await vendor.vendorAddSimpleProduct(data.product.simple, false); + }); + + test('vendor can add variable product @pro', async () => { + await vendor.vendorAddVariableProduct(data.product.variable, false); + }); + + test('vendor can add simple subscription product @pro', async () => { + await vendor.vendorAddSimpleSubscription(data.product.simpleSubscription, false); + }); + + test('vendor can add variable subscription product @pro', async () => { + await vendor.vendorAddVariableSubscription(data.product.variableSubscription, false); + }); + + test('vendor can add external product @pro', async () => { + await vendor.vendorAddExternalProduct(data.product.external, false); + }); + + test('vendor can add product product category @lite', async () => { + await vendor.vendorAddProductCategory(data.predefined.simpleProduct.product1.name, data.product.category.unCategorized); + }); + + test('vendor product menu page is rendering properly @lite @explo', async () => { + await vendor.vendorProductsRenderProperly(); + }); + + test('vendor can export products @pro', async () => { + await vendor.exportProducts(); + }); + + test('vendor can search product @lite', async () => { + await vendor.searchProduct(data.predefined.simpleProduct.product1.name); + }); + + test('vendor can filter products by date @lite', async () => { + await vendor.filterProducts('by-date', '1'); + }); + + test('vendor can filter products by category @lite', async () => { + await vendor.filterProducts('by-category', 'Uncategorized'); + }); + + test('vendor can filter products by type @pro', async () => { + await vendor.filterProducts('by-type', 'simple'); + }); + + test('vendor can filter products by other @pro', async () => { + await vendor.filterProducts('by-other', 'featured'); + }); + + test('vendor can view product @lite', async () => { + await vendor.viewProduct(data.predefined.simpleProduct.product1.name); + }); + + test("vendor can't buy own product @pro", async () => { + await vendor.cantBuyOwnProduct(productName); + }); + + test('vendor can edit product @lite', async () => { + await vendor.editProduct({ ...data.product.simple, editProduct: productName }); + }); + + test('vendor can quick edit product @pro', async () => { + await vendor.quickEditProduct({ ...data.product.simple, editProduct: productName }); + }); + + // test('vendor can add product quantity discount @pro', async ( ) => { + // await vendor.addProductQuantityDiscount(data.predefined.simpleProduct.product1.name, data.vendor.vendorInfo.quantityDiscount); + // }); + + test('vendor can add product rma settings @pro', async () => { + await vendor.addProductRmaSettings(data.predefined.simpleProduct.product1.name, data.vendor.rma); + }); + + // todo: add more product edit tests -> discount, wholesale, advertising + + test('vendor can duplicate product @pro', async () => { + await vendor.duplicateProduct(productName); + }); + + test('vendor can permanently delete product @lite', async () => { + const [, , productName] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendorAuth); + await vendor.permanentlyDeleteProduct(productName); + }); +}); diff --git a/tests/pw/tests/e2e/refunds.spec.ts b/tests/pw/tests/e2e/refunds.spec.ts new file mode 100644 index 0000000000..bc9592e771 --- /dev/null +++ b/tests/pw/tests/e2e/refunds.spec.ts @@ -0,0 +1,70 @@ +import { test, Page, APIResponse } from '@playwright/test'; +import { RefundsPage } from '@pages/refundsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +const { CUSTOMER_ID, PRODUCT_ID } = process.env; + +test.describe('Refunds test', () => { + let admin: RefundsPage; + let vendor: RefundsPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + let orderResponseBody: APIResponse; + let orderId: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new RefundsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new RefundsPage(vPage); + + apiUtils = new ApiUtils(request); + [, orderResponseBody, orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrder, data.order.orderStatus.processing, payloads.vendorAuth); + await dbUtils.createRefund(orderResponseBody); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('admin refunds menu page is rendering properly @pro @explo', async () => { + await admin.adminRefundRequestsRenderProperly(); + }); + + test('admin can search refund requests @pro', async () => { + await admin.searchRefundRequests(orderId); + // await admin.searchRefundRequests(data.predefined.vendorStores.vendor1); + }); + + test('admin can approve refund request @pro', async () => { + await admin.updateRefundRequests(orderId, 'approve'); + }); + + test('admin can cancel refund requests @pro', async () => { + const [, orderResponseBody, orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrder, data.order.orderStatus.processing, payloads.vendorAuth); + await dbUtils.createRefund(orderResponseBody); + await admin.updateRefundRequests(orderId, 'cancel'); + }); + + test('admin can perform refund requests bulk actions @pro', async () => { + const [, orderResponseBody, ,] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrder, data.order.orderStatus.processing, payloads.vendorAuth); + await dbUtils.createRefund(orderResponseBody); + await admin.refundRequestsBulkAction('completed'); + }); + + test('vendor can full refund @pro', async () => { + const [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.completed, payloads.vendorAuth); + await vendor.refundOrder(orderId, data.predefined.simpleProduct.product1.name); + }); + + test('vendor can partial refund @pro', async () => { + const [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.completed, payloads.vendorAuth); + await vendor.refundOrder(orderId, data.predefined.simpleProduct.product1.name, true); + }); +}); diff --git a/tests/pw/tests/e2e/reports.spec.ts b/tests/pw/tests/e2e/reports.spec.ts new file mode 100644 index 0000000000..0da8f57bda --- /dev/null +++ b/tests/pw/tests/e2e/reports.spec.ts @@ -0,0 +1,55 @@ +import { test, Page } from '@playwright/test'; +import { ReportsPage } from '@pages/reportsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +const { PRODUCT_ID } = process.env; + +test.describe('Reports test', () => { + let admin: ReportsPage; + let aPage: Page; + let apiUtils: ApiUtils; + let orderId: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new ReportsPage(aPage); + apiUtils = new ApiUtils(request); + [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrder, data.order.orderStatus.completed, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + // reports + + test('admin reports menu page is rendering properly @pro @explo', async () => { + await admin.adminReportsRenderProperly(); + }); + + // all logs + + test('admin All Logs menu page is rendering properly @pro @explo', async () => { + await admin.adminAllLogsRenderProperly(); + }); + + test('admin can search all logs @pro', async () => { + await admin.searchAllLogs(orderId); + }); + + test('admin can export all logs @pro', async () => { + // await admin.exportAllLogs(orderId); + await admin.exportAllLogs(); + }); + + test('admin can filter all logs by store name @pro', async () => { + await admin.filterAllLogsByStore(data.predefined.vendorStores.vendor1); + }); + + test('admin can filter all logs by order status @pro', async () => { + await admin.filterAllLogsByStatus('completed'); + }); +}); diff --git a/tests/pw/tests/e2e/requestForQuoteRules.spec.ts b/tests/pw/tests/e2e/requestForQuoteRules.spec.ts new file mode 100644 index 0000000000..9f698211e8 --- /dev/null +++ b/tests/pw/tests/e2e/requestForQuoteRules.spec.ts @@ -0,0 +1,55 @@ +import { test, Page } from '@playwright/test'; +import { RequestForQuotationsPage } from '@pages/requestForQuotationsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Request for quotation Rules test', () => { + let admin: RequestForQuotationsPage; + let aPage: Page; + let apiUtils: ApiUtils; + const quoteRuleTitle = data.requestForQuotation.quoteRule.title(); + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new RequestForQuotationsPage(aPage); + apiUtils = new ApiUtils(request); + await apiUtils.createQuoteRule({ ...payloads.createQuoteRule(), rule_name: quoteRuleTitle }, payloads.adminAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + // quote rules + + test('admin quote rules menu page is rendering properly @pro @explo', async () => { + await admin.adminQuoteRulesRenderProperly(); + }); + + test('admin can add quote rule @pro', async () => { + await admin.addQuoteRule({ ...data.requestForQuotation.quoteRule, title: data.requestForQuotation.quoteRule.title() }); + }); + + test('admin can edit quote rule @pro', async () => { + await admin.editQuoteRule({ ...data.requestForQuotation.quoteRule, title: quoteRuleTitle }); + }); + + test('admin can trash quote rule @pro', async () => { + await admin.updateQuoteRule(quoteRuleTitle, 'trash'); + }); + + test('admin can restore quote rule @pro', async () => { + await admin.updateQuoteRule(quoteRuleTitle, 'restore'); + }); + + test('admin can permanently delete quote rule @pro', async () => { + await apiUtils.createQuoteRule({ ...payloads.createQuoteRule(), rule_name: data.requestForQuotation.trashedQuoteRule.title, status: data.requestForQuotation.trashedQuoteRule.status }, payloads.adminAuth); + await admin.updateQuoteRule(data.requestForQuotation.trashedQuoteRule.title, 'permanently-delete'); + }); + + test('admin can perform quote rule bulk actions @pro', async () => { + await admin.quoteRulesBulkAction('trash'); + }); +}); diff --git a/tests/pw/tests/e2e/requestForQuotes.spec.ts b/tests/pw/tests/e2e/requestForQuotes.spec.ts new file mode 100644 index 0000000000..d8d4ee73bf --- /dev/null +++ b/tests/pw/tests/e2e/requestForQuotes.spec.ts @@ -0,0 +1,183 @@ +import { test, Page } from '@playwright/test'; +import { RequestForQuotationsPage } from '@pages/requestForQuotationsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +const { CUSTOMER_ID } = process.env; + +test.describe('Request for quotation test admin', () => { + let admin: RequestForQuotationsPage; + let aPage: Page; + let apiUtils: ApiUtils; + const productId: string[] = []; + let quoteTitle: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new RequestForQuotationsPage(aPage); + + apiUtils = new ApiUtils(request); + const [, pId] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendorAuth); + productId.push(pId); + [, , quoteTitle] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, user_id: CUSTOMER_ID }, payloads.adminAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + // quotes + + test('admin quotes menu page is rendering properly @pro @explo', async () => { + await admin.adminQuotesRenderProperly(); + }); + + test('admin can add quote @pro', async () => { + await admin.addQuote({ ...data.requestForQuotation.quote, title: data.requestForQuotation.quote.title() }); + }); + + test('admin can edit quote @pro', async () => { + await admin.editQuote({ ...data.requestForQuotation.quote, title: quoteTitle }); + }); + + test('admin can trash quote @pro', async () => { + await admin.updateQuote(quoteTitle, 'trash'); + }); + + test('admin can restore quote @pro', async () => { + const [, , quoteTitle] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, status: 'trash', user_id: CUSTOMER_ID }, payloads.adminAuth); + await admin.updateQuote(quoteTitle, 'restore'); + }); + + test('admin can permanently delete quote @pro', async () => { + const [, , quoteTitle] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, status: 'trash', user_id: CUSTOMER_ID }, payloads.adminAuth); + await admin.updateQuote(quoteTitle, 'permanently-delete'); + }); + + test('admin can approve quote @pro', async () => { + const [, , quoteTitle] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, user_id: CUSTOMER_ID }, payloads.adminAuth); + await admin.approveQuote(quoteTitle); + }); + + test('admin can convert quote to order @pro', async () => { + const [, , quoteTitle] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, status: 'approve', user_id: CUSTOMER_ID }, payloads.adminAuth); + await admin.convertQuoteToOrder(quoteTitle); + }); + + test('admin can perform quote bulk actions @pro', async () => { + await admin.quotesBulkAction('trash'); + }); +}); + +test.describe('Request for quotation test vendor', () => { + let vendor: RequestForQuotationsPage; + let vPage: Page; + let apiUtils: ApiUtils; + const productId: string[] = []; + let quoteTitle: string; + let productName: string; + let pId: string; + let quoteId: string; + + test.beforeAll(async ({ browser, request }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new RequestForQuotationsPage(vPage); + + apiUtils = new ApiUtils(request); + [, pId, productName] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendorAuth); + productId.push(pId); + [, quoteId, quoteTitle] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, user_id: CUSTOMER_ID }, payloads.adminAuth); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor request quotes menu page is rendering properly @pro @explo', async () => { + await vendor.vendorRequestQuotesRenderProperly(); + }); + + test('vendor can view request quote details @pro @explo', async () => { + await vendor.vendorViewQuoteDetails(quoteTitle); + }); + + test('vendor can update quote request @pro', async () => { + await vendor.vendorUpdateQuoteRequest(quoteId, { ...data.requestForQuotation.vendorUpdateQuote, productName: productName }); + }); + + test('vendor can approve quote request @pro', async () => { + await vendor.vendorApproveQuoteRequest(quoteId); + }); + + test('vendor can convert quote request to order @pro', async () => { + // const [, quoteId] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, status: 'approve', user_id: CUSTOMER_ID }, payloads.adminAuth); + await vendor.vendorConvertQuoteToOrder(quoteId); + }); +}); + +test.describe('Request for quotation test customer', () => { + let customer: RequestForQuotationsPage; + let guest: RequestForQuotationsPage; + let cPage: Page, uPage: Page; + let apiUtils: ApiUtils; + const productId: string[] = []; + let productName: string; + let pId: string; + let quoteId: string; + + test.beforeAll(async ({ browser, request }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new RequestForQuotationsPage(cPage); + + const guestContext = await browser.newContext(data.auth.noAuth); + uPage = await guestContext.newPage(); + guest = new RequestForQuotationsPage(uPage); + + apiUtils = new ApiUtils(request); + + [, pId, productName] = await apiUtils.createProduct(payloads.createProduct(), payloads.vendorAuth); + productId.push(pId); + const [responseBody] = await apiUtils.createQuoteRule({ ...payloads.createQuoteRule(), product_ids: productId, apply_on_all_product: '0' }, payloads.adminAuth); + // console.log(responseBody); + // console.log(productName); + [, quoteId] = await apiUtils.createQuoteRequest({ ...payloads.createQuoteRequest(), product_ids: productId, user_id: CUSTOMER_ID }, payloads.adminAuth); + }); + + test.afterAll(async () => { + await cPage.close(); + await uPage.close(); + }); + + test('customer request for quote menu page is rendering properly @pro @explo', async () => { + await customer.requestForQuoteRenderProperly(); + }); + + test('customer requested quote page is rendering properly @pro @explo', async () => { + await customer.requestedQuotesRenderProperly(); + }); + + test('customer can view requested quote details @pro @explo', async () => { + await customer.customerViewRequestedQuoteDetails(quoteId); + }); + + test('customer can update quote request @pro', async () => { + await customer.customerUpdateRequestedQuote(quoteId, { ...data.requestForQuotation.customerQuoteProduct, productName: productName }); + }); + + test('customer can pay order converted from quote request @pro', async () => { + await apiUtils.convertQuoteToOrder(quoteId, payloads.adminAuth); + await customer.payConvertedQuote(quoteId); + }); + + test.skip('customer can quote product @pro @explo', async () => { + await customer.customerQuoteProduct({ ...data.requestForQuotation.customerQuoteProduct, productName: productName }); + }); + + test.skip('guest customer can quote product @pro @explo', async () => { + await guest.customerQuoteProduct({ ...data.requestForQuotation.customerQuoteProduct, productName: productName }, data.requestForQuotation.guest()); + }); +}); diff --git a/tests/pw/tests/e2e/reverseWithdraws.spec.ts b/tests/pw/tests/e2e/reverseWithdraws.spec.ts new file mode 100644 index 0000000000..353e133fcb --- /dev/null +++ b/tests/pw/tests/e2e/reverseWithdraws.spec.ts @@ -0,0 +1,85 @@ +import { test, Page } from '@playwright/test'; +import { ReverseWithdrawsPage } from '@pages/reverseWithdrawsPage'; +// import { OrdersPage } from '@pages/ordersPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; + +const { PRODUCT_ID } = process.env; + +test.describe('Reverse withdraw test', () => { + let admin: ReverseWithdrawsPage; + let vendor: ReverseWithdrawsPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + // let orderId: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new ReverseWithdrawsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new ReverseWithdrawsPage(vPage); + // const vendor1 = new OrdersPage(vPage); + + apiUtils = new ApiUtils(request); + + await dbUtils.setDokanSettings(dbData.dokan.optionName.reverseWithdraw, dbData.dokan.reverseWithdrawSettings); + + // await admin.addReverseWithdrawal({ ...data.reverseWithdraw, amount: '1000', withdrawalBalanceType: 'debit' } ); + // await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrderCod, data.order.orderStatus.completed, payloads.vendorAuth); + // [,, orderId,]= await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrderCod, data.order.orderStatus.processing, payloads.vendorAuth); + // await vendor1.updateOrderStatusOnTable(orderId, 'complete'); + + const [, , orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, payloads.createOrderCod, data.order.orderStatus.processing, payloads.vendorAuth); + await apiUtils.updateOrderStatus(orderId, data.order.orderStatus.completed, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.reverseWithdraw, { ...dbData.dokan.reverseWithdrawSettings, enabled: 'off' }); + await aPage.close(); + await vPage.close(); + }); + + test('dokan admin reverse withdraw menu page is rendering properly @lite @explo', async () => { + await admin.adminReverseWithdrawRenderProperly(); + }); + + test.skip('filter reverse withdraws by store @lite', async () => { + await admin.filterReverseWithdraws(data.predefined.vendorStores.vendor1); + }); + + test('admin can crete reverse withdraws @lite', async () => { + await admin.addReverseWithdrawal(data.reverseWithdraw); + }); + + // vendor + + test('vendor reverse withdrawal menu page is rendering properly @lite @explo', async () => { + await vendor.vendorReverseWithdrawalRenderProperly(); + }); + + test('vendor can view reverse withdrawal notice @lite @explo', async () => { + await vendor.vendorViewReverseWithdrawalNotice(); + }); + + test('vendor can view reverse withdrawal announcement @pro @explo', async () => { + await vendor.vendorViewReverseWithdrawalAnnouncement(); + }); + + test('vendor can filter reverse withdrawals @lite', async () => { + await vendor.vendorFilterReverseWithdrawals(data.date.dateRange); + }); + + test('vendor can pay reverse pay balance @lite', async () => { + const orderId = await vendor.vendorPayReversePayBalance(); + await apiUtils.updateOrderStatus(orderId, data.order.orderStatus.completed, payloads.adminAuth); + }); + + // todo: vendor cant withdraw when reverse withdrawal rule applied + // todo: add to cart button removed when reverse withdrawal rule applied +}); diff --git a/tests/pw/tests/e2e/sellerBadges.spec.ts b/tests/pw/tests/e2e/sellerBadges.spec.ts new file mode 100644 index 0000000000..4ac106c542 --- /dev/null +++ b/tests/pw/tests/e2e/sellerBadges.spec.ts @@ -0,0 +1,99 @@ +import { test, Page } from '@playwright/test'; +import { SellerBadgesPage } from '@pages/sellerBadgesPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Seller badge test', () => { + let admin: SellerBadgesPage; + let vendor: SellerBadgesPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new SellerBadgesPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new SellerBadgesPage(vPage); + + apiUtils = new ApiUtils(request); + await apiUtils.createSellerBadge(payloads.createSellerBadgeProductsPublished, payloads.adminAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + }); + + test('dokan seller badge menu page is rendering properly @pro @explo', async () => { + await admin.adminSellerBadgeRenderProperly(); + }); + + test('admin can preview seller badge @pro @explo', async () => { + await admin.previewSellerBadge(data.sellerBadge.eventName.productsPublished); + }); + + test('admin can view seller badge details @pro @explo', async () => { + await admin.viewSellerBadge(data.sellerBadge.eventName.productsPublished); + }); + + test('admin can search seller badge @pro', async () => { + await admin.searchSellerBadge(data.sellerBadge.eventName.productsPublished); + }); + + test('admin can create seller badge @pro', async () => { + await admin.createSellerBadge({ ...data.sellerBadge, badgeName: data.sellerBadge.eventName.numberOfItemsSold }); + }); + + test('admin can edit seller badge @pro', async () => { + await admin.editSellerBadge({ ...data.sellerBadge, badgeName: data.sellerBadge.eventName.productsPublished }); + }); + + // test.skip('admin can filter vendors by seller badge @pro', async ( ) => { + // await admin.filterVendorsByBadge(data.sellerBadge.eventName.productsPublished); + // }); + + // test.skip('admin can view seller badge vendors @pro', async ( ) => { + // await admin.sellerBadgeVendors(data.sellerBadge.eventName.productsPublished); + // }); + + test('admin can view seller badges acquired by vendor @pro', async () => { + await admin.sellerBadgeAcquiredByVendor(data.predefined.vendorStores.vendor1); + }); + + test('admin can update seller badge status @pro', async () => { + await apiUtils.createSellerBadge(payloads.createSellerBadgeExclusiveToPlatform, payloads.adminAuth); + await admin.updateSellerBadge(data.sellerBadge.eventName.exclusiveToPlatform, 'draft'); + }); + + test('admin can delete seller badge @pro', async () => { + await apiUtils.createSellerBadge(payloads.createSellerBadgeExclusiveToPlatform, payloads.adminAuth); + await admin.updateSellerBadge(data.sellerBadge.eventName.exclusiveToPlatform, 'delete'); + }); + + test('admin can perform seller badge bulk action @pro', async () => { + await apiUtils.createSellerBadge(payloads.createSellerBadgeFeatureProducts, payloads.adminAuth); + await admin.sellerBadgeBulkAction('delete', data.sellerBadge.eventName.featuredProducts); + }); + + // vendor + + test('vendor badges menu page is rendering properly @pro @explo', async () => { + await vendor.vendorSellerBadgeRenderProperly(); + }); + + test('vendor can view badge acquired congratulation popup message action @pro', async () => { + await vendor.sellerBadgeCongratsPopup(); + }); + + test('vendor can search seller badge @pro', async () => { + await vendor.vendorSearchSellerBadge(data.sellerBadge.eventName.productsPublished); + }); + + test('vendor can filter seller badges @pro', async () => { + await vendor.filterSellerBadges('available_badges'); + }); +}); diff --git a/tests/pw/tests/e2e/settings.spec.ts b/tests/pw/tests/e2e/settings.spec.ts new file mode 100644 index 0000000000..351e842396 --- /dev/null +++ b/tests/pw/tests/e2e/settings.spec.ts @@ -0,0 +1,125 @@ +import { test, Page } from '@playwright/test'; +import { SettingsPage } from '@pages/settingsPage'; +import { dbData } from '@utils/dbData'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; + +test.describe('Settings test', () => { + let settingsPage: SettingsPage; + let aPage: Page; + + test.beforeAll(async ({ browser }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + settingsPage = new SettingsPage(aPage); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan settings menu page is rendering properly @lite @explo', async () => { + await settingsPage.dokanSettingsRenderProperly(); + }); + + test('admin can scroll to top on settings @lite', async () => { + await settingsPage.scrollToTopSettings(); + }); + + test('admin can search settings @lite', async () => { + await settingsPage.searchSettings('Selling Options'); + }); + + // dokan settings + + test('admin can set dokan general settings @lite', async () => { + await settingsPage.setDokanGeneralSettings(data.dokanSettings.general); + }); + + test('admin can set dokan selling settings @lite', async () => { + await settingsPage.setDokanSellingSettings(data.dokanSettings.selling); + }); + + test('admin can set dokan withdraw settings @lite', async () => { + await settingsPage.setDokanWithdrawSettings(data.dokanSettings.withdraw); + }); + + test('admin can set dokan reverse withdraw settings @lite', async () => { + await settingsPage.setDokanReverseWithdrawSettings(data.dokanSettings.reverseWithdraw); + }); + + test('admin can set dokan page settings @lite', async () => { + await settingsPage.setPageSettings(data.dokanSettings.page); + }); + + test('admin can set dokan appearance settings @lite', async () => { + await settingsPage.setDokanAppearanceSettings(data.dokanSettings.appearance); + }); + + test('admin can set dokan privacy policy settings @lite', async () => { + await settingsPage.setDokanPrivacyPolicySettings(data.dokanSettings.privacyPolicy); + }); + + test('admin can set dokan color settings @pro', async () => { + await settingsPage.setDokanColorSettings(data.dokanSettings.colors); + }); + + test('admin can set dokan live search settings @pro', async () => { + await settingsPage.setDokanLiveSearchSettings(data.dokanSettings.liveSearch); + }); + + test('admin can set dokan store support settings @pro', async () => { + await settingsPage.setDokanStoreSupportSettings(data.dokanSettings.storeSupport); + }); + + test('admin can set dokan email verification settings @pro', async () => { + await settingsPage.setDokanEmailVerificationSettings(data.dokanSettings.emailVerification); + // reset settings + await dbUtils.setDokanSettings(dbData.dokan.optionName.emailVerification, dbData.dokan.emailVerificationSettings); + }); + + test('admin can set dokan shipping status settings @pro', async () => { + await settingsPage.setDokanShippingStatusSettings(data.dokanSettings.shippingStatus); + }); + + test('admin can set dokan quote settings @pro', async () => { + await settingsPage.setDokanQuoteSettings(data.dokanSettings.quote); + }); + + test('admin can set dokan rma settings @pro', async () => { + await settingsPage.setDokanRmaSettings(data.dokanSettings.rma); + }); + + test('admin can set dokan wholesale settings @pro', async () => { + await settingsPage.setDokanWholesaleSettings(data.dokanSettings.wholesale); + }); + + test('admin can set dokan eu compliance settings @pro', async () => { + await settingsPage.setDokanEuComplianceSettings(data.dokanSettings.euCompliance); + }); + + test('admin can set dokan delivery time settings @pro', async () => { + await settingsPage.setDokanDeliveryTimeSettings(data.dokanSettings.deliveryTime); + }); + + test('admin can set dokan product advertising settings @pro', async () => { + await settingsPage.setDokanProductAdvertisingSettings(data.dokanSettings.productAdvertising); + }); + + test('admin can set dokan geolocation settings @pro', async () => { + await settingsPage.setDokanGeolocationSettings(data.dokanSettings.geolocation); + }); + + test('admin can set dokan product report abuse settings @pro', async () => { + await settingsPage.setDokanProductReportAbuseSettings(data.dokanSettings.productReportAbuse); + }); + + test('admin can set dokan spmv settings @pro', async () => { + await settingsPage.setDokanSpmvSettings(data.dokanSettings.spmv); + }); + + test('admin can set dokan vendor subscription settings @pro', async () => { + await settingsPage.setDokanVendorSubscriptionSettings(data.dokanSettings.vendorSubscription); + await dbUtils.setDokanSettings(dbData.dokan.optionName.vendorSubscription, dbData.dokan.vendorSubscriptionSettings); + }); +}); diff --git a/tests/pw/tests/e2e/shop.spec.ts b/tests/pw/tests/e2e/shop.spec.ts new file mode 100644 index 0000000000..a67e1b08f9 --- /dev/null +++ b/tests/pw/tests/e2e/shop.spec.ts @@ -0,0 +1,54 @@ +import { test, Page } from '@playwright/test'; +import { ShopPage } from '@pages/shopPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Shop functionality test', () => { + let customer: ShopPage; + let cPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new ShopPage(cPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await cPage.close(); + }); + + // shop page + + test('shop page is rendering properly @lite @explo', async () => { + await customer.shopRenderProperly(); + }); + + test('customer can sort products @lite', async () => { + await customer.sortProducts('price'); + }); + + test('customer can search product @lite', async () => { + await customer.searchProduct(data.predefined.simpleProduct.product1.name); + }); + + test('customer can filter products by category @pro', async () => { + await customer.filterProducts('by-category', 'uncategorized'); + }); + + test('customer can filter products by location @pro', async () => { + await customer.filterProducts('by-location', 'New York, NY, USA'); + }); + + test('customer can view products on map @pro', async () => { + await customer.productOnMap(); + // await customer.productOnMap(data.predefined.simpleProduct.product1.name); + }); + + test('customer can go to product details from shop @lite', async () => { + await customer.goToProductDetailsFromShop(data.predefined.simpleProduct.product1.name); + }); +}); diff --git a/tests/pw/tests/e2e/singleProduct.spec.ts b/tests/pw/tests/e2e/singleProduct.spec.ts new file mode 100644 index 0000000000..20c94c20d8 --- /dev/null +++ b/tests/pw/tests/e2e/singleProduct.spec.ts @@ -0,0 +1,56 @@ +import { test, Page } from '@playwright/test'; +import { SingleProductPage } from '@pages/singleProductPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Single product functionality test', () => { + let customer: SingleProductPage; + let cPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new SingleProductPage(cPage); + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await cPage.close(); + }); + + // single product page + + test('single product is rendering properly @lite @explo', async () => { + await customer.singleProductRenderProperly(data.predefined.simpleProduct.product1.name); + }); + + test('customer can view highlighted vendor info @lite', async () => { + await customer.viewHighlightedVendorInfo(data.predefined.simpleProduct.product1.name); + }); + + test('customer can view product vendor info @lite', async () => { + await customer.productVendorInfo(data.predefined.simpleProduct.product1.name); + }); + + test('customer can view product location @pro', async () => { + await customer.productLocation(data.predefined.simpleProduct.product1.name); + }); + + test('customer can view product warranty policy @pro', async () => { + await customer.productWarrantyPolicy(data.predefined.simpleProduct.product1.name); + }); + + test('customer can view more products @lite', async () => { + await customer.viewMoreProducts(data.predefined.simpleProduct.product1.name); + }); + + test('customer can view related products @lite', async () => { + await customer.viewRelatedProducts(data.predefined.simpleProduct.product1.name); + }); + + test('customer can review product @lite', async () => { + await customer.reviewProduct(data.predefined.simpleProduct.product1.name, data.product.review); + }); +}); diff --git a/tests/pw/tests/e2e/singleStore.spec.ts b/tests/pw/tests/e2e/singleStore.spec.ts new file mode 100644 index 0000000000..cd3eea9327 --- /dev/null +++ b/tests/pw/tests/e2e/singleStore.spec.ts @@ -0,0 +1,50 @@ +import { test, Page } from '@playwright/test'; +import { SingleStorePage } from '@pages/singleStorePage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Single store functionality test', () => { + let customer: SingleStorePage; + let cPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new SingleStorePage(cPage); + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await cPage.close(); + }); + + // single store page + + test('dokan single store page is rendering properly @lite @explo', async () => { + await customer.singleStoreRenderProperly(data.predefined.vendorStores.vendor1); + }); + + // test.skip('customer can view store open-close time on single store @lite', async ( ) => { + // // todo: pre: need store open close + // await customer.storeOpenCloseTime(data.predefined.vendorStores.vendor1); + // }); + + test('customer can search product on single store @lite', async () => { + await customer.singleStoreSearchProduct(data.predefined.vendorStores.vendor1, data.predefined.simpleProduct.product1.name); + }); + + test('customer can sort products on single store @lite', async () => { + await customer.singleStoreSortProducts(data.predefined.vendorStores.vendor1, 'price'); + }); + + // test.skip('customer can view store terms and conditions @lite', async ( ) => { + // // todo: pre need toc on store and admin settings + // await customer.storeTermsAndCondition(data.predefined.vendorStores.vendor1, data.vendor.toc); + // }); + + test('customer can share store @pro', async () => { + await customer.storeShare(data.predefined.vendorStores.vendor1, data.storeShare.facebook); + }); +}); diff --git a/tests/pw/tests/e2e/spmv.spec.ts b/tests/pw/tests/e2e/spmv.spec.ts new file mode 100644 index 0000000000..dbe4f1c735 --- /dev/null +++ b/tests/pw/tests/e2e/spmv.spec.ts @@ -0,0 +1,107 @@ +import { test, Page } from '@playwright/test'; +import { SpmvPage } from '@pages/spmvPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; +import { dbUtils } from '@utils/dbUtils'; +import { dbData } from '@utils/dbData'; + +test.describe('Vendor SPMV test', () => { + let admin: SpmvPage; + let vendor: SpmvPage; + let customer: SpmvPage; + let aPage: Page, vPage: Page, cPage: Page; + let apiUtils: ApiUtils; + let productName: string; + let productName1: string; + let productId: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new SpmvPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new SpmvPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new SpmvPage(cPage); + + apiUtils = new ApiUtils(request); + await dbUtils.setDokanSettings(dbData.dokan.optionName.selling, { ...dbData.dokan.sellingSettings, enable_min_max_quantity: 'off', enable_min_max_amount: 'off' }); // todo: might exists dokan issue -> min-max field is required on admin product edit + [, , productName] = await apiUtils.createProduct({ ...payloads.createProduct(), name: data.predefined.spmv.productName() }, payloads.vendor2Auth); + [, productId, productName1] = await apiUtils.createProduct({ ...payloads.createProduct(), name: data.predefined.spmv.productName() }, payloads.vendor2Auth); + await apiUtils.addSpmvProductToStore(productId, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.selling, dbData.dokan.sellingSettings); + await aPage.close(); + await vPage.close(); + await cPage.close(); + }); + + test('admin can assign SPMV product to other vendor @pro', async () => { + const [, productId] = await apiUtils.createProduct({ ...payloads.createProduct(), name: data.predefined.spmv.productName() }, payloads.vendor2Auth); + await admin.assignSpmvProduct(productId, data.predefined.vendorStores.vendor1); + }); + + test('vendor spmv menu page is rendering properly @pro @explo', async () => { + await vendor.vendorSpmvRenderProperly(); + }); + + test('vendor can search similar product on spmv page @pro ', async () => { + await vendor.searchSimilarProduct(productName, 'spmv'); + }); + + test('vendor can search similar product on product popup @pro', async () => { + await vendor.searchSimilarProduct(productName, 'popup'); + }); + + test('vendor can search similar booking product @pro', async () => { + const [, , bookableProductName] = await apiUtils.createBookableProduct(payloads.createBookableProduct(), payloads.vendor2Auth); + await vendor.searchSimilarProduct(bookableProductName, 'booking'); + }); + + test('vendor can search similar auction product @pro', async () => { + const [, , auctionProductName] = await apiUtils.createProduct(payloads.createAuctionProduct(), payloads.vendor2Auth); + await vendor.searchSimilarProduct(auctionProductName, 'auction'); + }); + + test('vendor can go to own product edit from spmv page @pro', async () => { + await vendor.goToProductEditFromSPMV(data.predefined.simpleProduct.product1.name); + }); + + test('vendor can sort spmv products @pro', async () => { + await vendor.sortSpmvProduct('price'); + }); + + test('vendor can clone product @pro', async () => { + await vendor.cloneProduct(productName); + }); + + test('vendor can clone product via sell item button @pro', async () => { + const [, , productName] = await apiUtils.createProduct({ ...payloads.createProduct(), name: data.predefined.spmv.productName() }, payloads.vendor2Auth); + await vendor.cloneProductViaSellItemButton(productName); + }); + + // customer + + test('customer can view other available vendors @pro', async () => { + await customer.viewOtherAvailableVendors(productName1); + }); + + test('customer can view other available vendor @pro', async () => { + await customer.viewOtherAvailableVendor(productName1, data.predefined.vendorStores.vendor1); + }); + + test('customer can view other available vendor product @pro', async () => { + await customer.viewOtherAvailableVendorProduct(productName1, data.predefined.vendorStores.vendor1); + }); + + test('customer can add to cart other available vendor product @pro', async () => { + await customer.addToCartOtherAvailableVendorsProduct(productName1, data.predefined.vendorStores.vendor1); + }); +}); diff --git a/tests/pw/tests/e2e/storeCategories.spec.ts b/tests/pw/tests/e2e/storeCategories.spec.ts new file mode 100644 index 0000000000..31378dcf33 --- /dev/null +++ b/tests/pw/tests/e2e/storeCategories.spec.ts @@ -0,0 +1,64 @@ +import { test, Page } from '@playwright/test'; +import { StoreCategoriesPage } from '@pages/storeCategoriesPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Store categories test', () => { + let admin: StoreCategoriesPage; + let vendor: StoreCategoriesPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + let categoryName: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new StoreCategoriesPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new StoreCategoriesPage(vPage); + + apiUtils = new ApiUtils(request); + [, , categoryName] = await apiUtils.createStoreCategory(payloads.createStoreCategory(), payloads.adminAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + }); + + // store categories + + test('admin store category page is rendering properly @pro @explo', async () => { + await admin.adminStoreCategoryRenderProperly(); + }); + + test('admin can add store category @pro', async () => { + await admin.addStoreCategory(data.storeCategory()); + }); + + test('admin can search store category @pro', async () => { + await admin.searchStoreCategory(categoryName); + }); + + test('admin can edit store category @pro', async () => { + await admin.editStoreCategory({ ...data.storeCategory(), name: categoryName }); + }); + + test('admin can set default store category @pro', async () => { + await admin.updateStoreCategory(categoryName, 'set-default'); + // reset default category + await apiUtils.setDefaultStoreCategory('Uncategorized', payloads.adminAuth); + }); + + test('admin can delete store category @pro', async () => { + await admin.updateStoreCategory(categoryName, 'delete'); + }); + + test('vendor can update own store category @pro', async () => { + const [, , categoryName] = await apiUtils.createStoreCategory(payloads.createStoreCategory(), payloads.adminAuth); + await vendor.vendorUpdateStoreCategory(categoryName); + }); +}); diff --git a/tests/pw/tests/e2e/storeReviews.spec.ts b/tests/pw/tests/e2e/storeReviews.spec.ts new file mode 100644 index 0000000000..6e940eb49a --- /dev/null +++ b/tests/pw/tests/e2e/storeReviews.spec.ts @@ -0,0 +1,95 @@ +import { test, Page } from '@playwright/test'; +import { StoreReviewsPage } from '@pages/storeReviewsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Store Reviews test', () => { + const { VENDOR_ID } = process.env; + + let admin: StoreReviewsPage; + let vendor: StoreReviewsPage; + let customer: StoreReviewsPage; + let aPage: Page, vPage: Page, cPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new StoreReviewsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new StoreReviewsPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new StoreReviewsPage(cPage); + + apiUtils = new ApiUtils(request); + + await apiUtils.updateBatchStoreReviews('trash', [], payloads.adminAuth); + await apiUtils.createStoreReview(VENDOR_ID, payloads.createStoreReview, payloads.customerAuth); + const [, reviewId] = await apiUtils.createStoreReview(VENDOR_ID, { ...payloads.createStoreReview, title: 'trashed test review' }, payloads.customerAuth); + await apiUtils.deleteStoreReview(reviewId, payloads.adminAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + await cPage.close(); + }); + + test('dokan store reviews menu page is rendering properly @pro @explo', async () => { + await admin.adminStoreReviewsRenderProperly(); + }); + + test('admin can view store review @pro @explo', async () => { + await admin.viewStoreReview(); + }); + + test('admin can edit store review @pro', async () => { + await admin.editStoreReview(data.storeReview.review()); + }); + + test('admin can filter store reviews by vendor @pro', async () => { + await admin.filterStoreReviews(data.storeReview.filter.byVendor); + }); + + test('admin can delete store review @pro', async () => { + await admin.deleteStoreReview(); + }); + + test('admin can restore deleted store review @pro', async () => { + await admin.restoreStoreReview(); + }); + + test('admin can permanently delete store review @pro', async () => { + await admin.permanentlyDeleteStoreReview(); + }); + + test('admin can perform store reviews bulk action @pro', async () => { + await apiUtils.createStoreReview(VENDOR_ID, payloads.createStoreReview, payloads.customerAuth); + await admin.storeReviewsBulkAction('trash'); + }); + + test('customer can review store @pro', async () => { + // remove any previous reviews + await apiUtils.updateBatchStoreReviews('trash', [], payloads.adminAuth); + await customer.reviewStore(data.predefined.vendorStores.vendor1, data.storeReview.review(), 'create'); + }); + + test('customer can edit store review @pro', async () => { + await customer.reviewStore(data.predefined.vendorStores.vendor1, data.storeReview.review(), 'edit'); + }); + + test('customer can view own review @pro', async () => { + await apiUtils.updateBatchStoreReviews('trash', [], payloads.adminAuth); + await apiUtils.createStoreReview(VENDOR_ID, payloads.createStoreReview, payloads.customerAuth); + await customer.viewOwnReview(data.predefined.vendorStores.vendor1); + }); + + test("vendor can't review own store @pro", async () => { + await vendor.cantReviewOwnStore(data.predefined.vendorStores.vendor1); + }); +}); diff --git a/tests/pw/tests/e2e/storeSupports.spec.ts b/tests/pw/tests/e2e/storeSupports.spec.ts new file mode 100644 index 0000000000..b496e1c832 --- /dev/null +++ b/tests/pw/tests/e2e/storeSupports.spec.ts @@ -0,0 +1,228 @@ +import { test, Page } from '@playwright/test'; +import { StoreSupportsPage } from '@pages/storeSupportsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; +import { responseBody } from '@utils/interfaces'; + +const { PRODUCT_ID, VENDOR_ID, CUSTOMER_ID } = process.env; + +test.describe('Store Support test (admin)', () => { + let admin: StoreSupportsPage; + let aPage: Page; + let apiUtils: ApiUtils; + let supportTicketId: string; + let closedSupportTicketId: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new StoreSupportsPage(aPage); + + apiUtils = new ApiUtils(request); + [, supportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + [, closedSupportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, status: 'closed', author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan store support menu page is rendering properly @pro @explo', async () => { + await admin.adminStoreSupportRenderProperly(); + }); + + test('unread count decrease after admin viewing a support ticket @pro', async () => { + await admin.decreaseUnreadSupportTicketCount(supportTicketId); + }); + + test('admin can view support ticket details @pro @explo', async () => { + await admin.adminViewSupportTicketDetails(supportTicketId); + }); + + test('admin can search support ticket @pro', async () => { + await admin.searchSupportTicket(supportTicketId); + // await admin.searchSupportTicket(data.storeSupport.title); // todo: + }); + + test('admin can filter support tickets by vendor @pro', async () => { + await admin.filterSupportTickets(data.storeSupport.filter.byVendor, 'by-vendor'); + }); + + test('admin can filter support tickets by customer @pro', async () => { + await admin.filterSupportTickets(data.storeSupport.filter.byCustomer, 'by-customer'); + }); + + test('admin can reply to support ticket as admin @pro', async () => { + await admin.replySupportTicket(supportTicketId, data.storeSupport.chatReply.asAdmin); + }); + + test('admin can reply to support ticket as vendor @pro', async () => { + await admin.replySupportTicket(supportTicketId, data.storeSupport.chatReply.asVendor); + }); + + test('admin can disable support ticket email notification @pro', async () => { + // await apiUtils.updateSupportTicketEmailNotification(supportTicketId, { notification: true, }, payloads.adminAuth); + await admin.updateSupportTicketEmailNotification(supportTicketId, 'disable'); + }); + + test('admin can enable support ticket email notification @pro', async () => { + await apiUtils.updateSupportTicketEmailNotification(supportTicketId, { notification: false }, payloads.adminAuth); + await admin.updateSupportTicketEmailNotification(supportTicketId, 'enable'); + }); + + test('admin can close support ticket @pro', async () => { + await admin.closeSupportTicket(supportTicketId); + }); + + test('admin can reopen closed support ticket @pro', async () => { + await admin.reopenSupportTicket(closedSupportTicketId); + }); + + test('admin can perform store support bulk action @pro', async () => { + const [, supportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + await admin.storeSupportBulkAction('close', supportTicketId); + }); +}); + +test.describe('Store Support test (customer)', () => { + let customer: StoreSupportsPage; + let guest: StoreSupportsPage; + let cPage: Page, uPage: Page; + let apiUtils: ApiUtils; + let orderId: string; + let responseBody: responseBody; + let supportTicketId: string; + + test.beforeAll(async ({ browser, request }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new StoreSupportsPage(cPage); + + const guestContext = await browser.newContext(data.auth.noAuth); + uPage = await guestContext.newPage(); + guest = new StoreSupportsPage(uPage); + + apiUtils = new ApiUtils(request); + [, responseBody, orderId] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.completed, payloads.vendorAuth); + [, supportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, author: CUSTOMER_ID, meta: { store_id: VENDOR_ID, order_id: orderId } }); + }); + + test.afterAll(async () => { + await cPage.close(); + await uPage.close(); + }); + + test('customer store support menu page is rendering properly @pro @explo', async () => { + await customer.customerStoreSupportRenderProperly(); + }); + + test('customer can view support ticket details @pro @explo', async () => { + await customer.customerViewSupportTicketDetails(supportTicketId); + }); + + test('customer can ask for store support on single product @pro', async () => { + await customer.storeSupport(data.predefined.simpleProduct.product1.name, data.customer.getSupport, 'product'); + }); + + test('customer can ask for store support on single store @pro', async () => { + await customer.storeSupport(data.predefined.vendorStores.vendor1, data.customer.getSupport, 'store'); + }); + + test('customer can ask for store support on order details @pro', async () => { + await customer.storeSupport(orderId, data.customer.getSupport, 'order'); + }); + + test('customer can ask for store support on order received @pro', async () => { + const orderKey = responseBody.order_key; + await customer.storeSupport(orderId + ',' + orderKey, data.customer.getSupport, 'order-received'); + }); + + test('customer can ask for store support for order @pro', async () => { + await customer.storeSupport(data.predefined.vendorStores.vendor1, { ...data.customer.getSupport, orderId: orderId }, 'store'); + }); + + test('customer can view reference order number on support ticket @pro', async () => { + await customer.viewOrderReferenceNumberOnSupportTicket(supportTicketId, orderId); + }); + + test('customer can send message to support ticket @pro', async () => { + await customer.sendMessageToSupportTicket(supportTicketId, data.customer.supportTicket); + }); + + test("customer can't send message to closed support ticket @pro", async () => { + const [, supportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, status: 'closed', author: CUSTOMER_ID, meta: { store_id: VENDOR_ID, order_id: orderId } }); + await customer.cantSendMessageToSupportTicket(supportTicketId); + }); + + test('guest customer need to login before asking for store support @pro', async () => { + await guest.storeSupport(data.predefined.vendorStores.vendor1, data.customer.getSupport, 'store'); + }); +}); + +test.describe('Store Support test (vendor)', () => { + let vendor: StoreSupportsPage; + let vPage: Page; + let apiUtils: ApiUtils; + let supportTicketId: string; + + test.beforeAll(async ({ browser, request }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new StoreSupportsPage(vPage); + + apiUtils = new ApiUtils(request); + [, supportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, status: 'closed', author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + // vendor + + test('vendor store support menu page is rendering properly @pro @explo', async () => { + await vendor.vendorStoreSupportRenderProperly(); + }); + + test('vendor can view support ticket details @pro @explo', async () => { + await vendor.vendorViewSupportTicketDetails(supportTicketId); + }); + + test('vendor can filter support tickets by customer @pro', async () => { + await vendor.vendorFilterSupportTickets('by-customer', data.storeSupport.filter.byCustomer); + }); + + test('vendor can filter support tickets by date range @pro', async () => { + await vendor.vendorFilterSupportTickets('by-date', data.date.dateRange); + }); + + test('vendor can search support ticket @pro', async () => { + await vendor.vendorSearchSupportTicket('id', supportTicketId); + // await vendor.vendorSearchSupportTicket('title', data.storeSupport.title); // todo: separate or in same test + }); + + test('vendor can reply to support ticket @pro', async () => { + await vendor.vendorReplySupportTicket(supportTicketId, data.storeSupport.chatReply.reply); + }); + + test('vendor can close support ticket @pro', async () => { + await vendor.vendorCloseSupportTicket(supportTicketId); + }); + + test('vendor can reopen closed support ticket @pro', async () => { + const [, closedSupportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, status: 'closed', author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + await vendor.vendorReopenSupportTicket(closedSupportTicketId); + }); + + test('vendor can close support ticket with a chat reply @pro', async () => { + const [, supportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + await vendor.vendorCloseSupportTicketWithReply(supportTicketId, 'closing this ticket'); + }); + + test('vendor can reopen closed support ticket with a chat reply @pro', async () => { + const [, closedSupportTicketId] = await apiUtils.createSupportTicket({ ...payloads.createSupportTicket, status: 'closed', author: CUSTOMER_ID, meta: { store_id: VENDOR_ID } }); + await vendor.vendorReopenSupportTicketWithReply(closedSupportTicketId, 'reopening this ticket'); + }); +}); diff --git a/tests/pw/tests/e2e/storelisting.spec.ts b/tests/pw/tests/e2e/storelisting.spec.ts new file mode 100644 index 0000000000..d2dee11efb --- /dev/null +++ b/tests/pw/tests/e2e/storelisting.spec.ts @@ -0,0 +1,69 @@ +import { test, Page } from '@playwright/test'; +import { StoreListingPage } from '@pages/storeListingPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Store listing functionality test', () => { + let customer: StoreListingPage; + let cPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new StoreListingPage(cPage); + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await cPage.close(); + }); + + // store listing + + test('dokan store list page is rendering properly @lite @explo', async () => { + await customer.storeListRenderProperly(); + }); + + test('customer can sort stores @lite', async () => { + await customer.sortStores(data.storeList.sort); + }); + + test('customer can change store view layout @lite', async () => { + await customer.storeViewLayout(data.storeList.layout.list); + }); + + test('customer can search store @lite', async () => { + await customer.searchStore(data.predefined.vendorStores.vendor1); + }); + + test('customer can filter stores by category @pro', async () => { + await customer.filterStores('by-category', 'Uncategorized'); + }); + + test('customer can filter stores by location @pro', async () => { + await customer.filterStores('by-location', 'New York, NY, USA'); + }); + + test.skip('customer can filter stores by ratings @pro', async () => { + await customer.filterStores('by-ratings', '1'); + }); + + test('customer can filter featured stores @pro', async () => { + await customer.filterStores('featured'); + }); + + test.skip('customer can filter open now stores @pro', async () => { + await customer.filterStores('open-now'); + }); + + test('customer can view stores on map @pro', async () => { + await customer.storeOnMap(); + // await customer.storeOnMap(data.predefined.vendorStores.vendor1); + }); + + test('customer can go to single store from store list @lite', async () => { + await customer.goToSingleStoreFromStoreListing(data.predefined.vendorStores.vendor1); + }); +}); diff --git a/tests/pw/tests/e2e/stores.spec.ts b/tests/pw/tests/e2e/stores.spec.ts new file mode 100644 index 0000000000..836e0b6d42 --- /dev/null +++ b/tests/pw/tests/e2e/stores.spec.ts @@ -0,0 +1,72 @@ +import { test, Page } from '@playwright/test'; +import { StoresPage } from '@pages/storesPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +const { VENDOR_ID } = process.env; + +test.describe('Stores test', () => { + let admin: StoresPage; + let aPage: Page; + // let apiUtils: ApiUtils; + // let storeName: string; + + test.beforeAll(async ({ browser }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new StoresPage(aPage); + // apiUtils = new ApiUtils(request); + // [,, storeName] = await apiUtils.createStore(payloads.createStore()); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + // stores + + test('admin vendors menu page is rendering properly @lite @explo', async () => { + await admin.adminVendorsRenderProperly(); + }); + + test('admin can view vendor details @pro', async () => { + await admin.viewVendorDetails(VENDOR_ID); + }); + + test('admin can email vendor @pro', async () => { + await admin.emailVendor(VENDOR_ID, data.vendor.vendorInfo.sendEmail); + }); + + test('admin can add vendor @lite', async () => { + await admin.addVendor(data.vendor.vendorInfo); + }); + + test('admin can search vendors @lite', async () => { + await admin.searchVendor(data.predefined.vendorStores.vendor1); + }); + + test("admin can disable vendor's selling capability @lite", async () => { + await admin.updateVendor(data.predefined.vendorStores.vendor1, 'disable'); + }); + + test("admin can enable vendor's selling capability @lite", async () => { + await admin.updateVendor(data.predefined.vendorStores.vendor1, 'enable'); + }); + + test('admin can edit vendor info @lite', async () => { + await admin.editVendor(data.vendor); + }); + + test('admin can view vendor products @lite', async () => { + await admin.viewVendor(data.predefined.vendorStores.vendor1, 'products'); + }); + + test('admin can view vendor orders @lite', async () => { + await admin.viewVendor(data.predefined.vendorStores.vendor1, 'orders'); + }); + + test('admin can perform vendor bulk actions @lite', async () => { + await admin.vendorBulkAction('approved'); + }); +}); diff --git a/tests/pw/tests/e2e/tools.spec.ts b/tests/pw/tests/e2e/tools.spec.ts new file mode 100644 index 0000000000..26db4fd507 --- /dev/null +++ b/tests/pw/tests/e2e/tools.spec.ts @@ -0,0 +1,56 @@ +import { test, Page } from '@playwright/test'; +import { ToolsPage } from '@pages/toolsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { payloads } from '@utils/payloads'; +import { data } from '@utils/testData'; + +test.describe('Tools test', () => { + let admin: ToolsPage; + let aPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new ToolsPage(aPage); + + apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + test('dokan tools menu page is rendering properly @pro @explo', async () => { + await admin.adminToolsRenderProperly(); + }); + + test('admin can perform dokan page Installation @pro', async () => { + await admin.dokanPageInstallation(); + }); + + test('admin can check for duplicate orders @pro', async () => { + await admin.checkForDuplicateOrders(); + }); + + test('admin can set dokan setup wizard @lite', async () => { + await admin.setDokanSetupWizard(data.dokanSetupWizard); + }); + + test('admin can regenerate variable product variations author IDs @pro', async () => { + await admin.regenerateVariableProductVariationsAuthorIds(); + }); + + // test.skip('admin can import dummy data @pro', async ( ) => { + // await admin.importDummyData(); + // }); + + test('admin can clear dummy data @pro', async () => { + await apiUtils.importDummyData(payloads.dummyData, payloads.adminAuth); + await admin.clearDummyData(); + }); + + test('admin can test distance matrix API @pro', async () => { + await admin.testDistanceMatrixApi(data.tools.distanceMatrixApi); + }); +}); diff --git a/tests/pw/tests/e2e/vendor.spec.ts b/tests/pw/tests/e2e/vendor.spec.ts new file mode 100644 index 0000000000..19eb23651b --- /dev/null +++ b/tests/pw/tests/e2e/vendor.spec.ts @@ -0,0 +1,72 @@ +import { test, Page } from '@playwright/test'; +import { LoginPage } from '@pages/loginPage'; +import { VendorPage } from '@pages/vendorPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Vendor user functionality test1', () => { + test.use({ storageState: { cookies: [], origins: [] } }); + + let loginPage: LoginPage; + let vendorPage: VendorPage; + let page: Page; + + test.beforeAll(async ({ browser }) => { + const context = await browser.newContext(); + page = await context.newPage(); + loginPage = new LoginPage(page); + vendorPage = new VendorPage(page); + }); + + test.afterAll(async () => { + await page.close(); + }); + + test('vendor can register @lite', async () => { + await vendorPage.vendorRegister(data.vendor.vendorInfo, { ...data.vendorSetupWizard, choice: false }); + }); + + test('vendor can login @lite', async () => { + await loginPage.login(data.vendor); + }); + + test('vendor can logout @lite', async () => { + await loginPage.login(data.vendor); + await loginPage.logout(); + }); +}); + +test.describe('Vendor functionality test', () => { + let vendor: VendorPage; + let vPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorPage(vPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor can setup setup-wizard @lite', async () => { + await vendor.vendorSetupWizard(data.vendorSetupWizard); + }); + + test('vendor account details menu page is rendering properly @lite @explo', async () => { + await vendor.vendorAccountDetailsRenderProperly(); + }); + + test('vendor update account details @lite', async () => { + await vendor.addVendorDetails(data.vendor); + }); + + test('vendor can visit own Store @lite', async () => { + await vendor.visitStore(data.predefined.vendorStores.vendor1); + }); +}); diff --git a/tests/pw/tests/e2e/vendorAnalytics.spec.ts b/tests/pw/tests/e2e/vendorAnalytics.spec.ts new file mode 100644 index 0000000000..4f1dda164a --- /dev/null +++ b/tests/pw/tests/e2e/vendorAnalytics.spec.ts @@ -0,0 +1,27 @@ +import { test, Page } from '@playwright/test'; +import { VendorAnalyticsPage } from '@pages/vendorAnalyticsPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Vendor analytics test', () => { + let vendor: VendorAnalyticsPage; + let vPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorAnalyticsPage(vPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor analytics menu page is rendering properly @pro @explo', async () => { + await vendor.vendorAnalyticsRenderProperly(); + }); +}); diff --git a/tests/pw/tests/e2e/vendorAuction.spec.ts b/tests/pw/tests/e2e/vendorAuction.spec.ts new file mode 100644 index 0000000000..8430cd9aa3 --- /dev/null +++ b/tests/pw/tests/e2e/vendorAuction.spec.ts @@ -0,0 +1,93 @@ +import { test, Page } from '@playwright/test'; +import { AuctionsPage } from '@pages/vendorAuctionsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Auction Product test', () => { + let admin: AuctionsPage; + let vendor: AuctionsPage; + let customer: AuctionsPage; + let aPage: Page, vPage: Page, cPage: Page; + let apiUtils: ApiUtils; + let auctionProductName: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new AuctionsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new AuctionsPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new AuctionsPage(cPage); + + apiUtils = new ApiUtils(request); + [, , auctionProductName] = await apiUtils.createProduct(payloads.createAuctionProduct(), payloads.vendorAuth); + + await customer.bidAuctionProduct(auctionProductName); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + await cPage.close(); + }); + + test('admin can add auction product @pro', async () => { + await admin.adminAddAuctionProduct(data.product.auction); + }); + + test('vendor auction menu page is rendering properly @pro @explo', async () => { + await vendor.vendorAuctionRenderProperly(); + }); + + test('vendor can add auction product @pro', async () => { + await vendor.addAuctionProduct({ ...data.product.auction, name: data.product.auction.productName() }); + }); + + test('vendor can edit auction product @pro', async () => { + await vendor.editAuctionProduct({ ...data.product.auction, name: auctionProductName }); + }); + + test('vendor can view auction product @pro', async () => { + await vendor.viewAuctionProduct(auctionProductName); + }); + + test("vendor can't bid own product @pro", async () => { + await vendor.cantBidOwnProduct(auctionProductName); + }); + + test('vendor can search auction product @pro', async () => { + await vendor.searchAuctionProduct(auctionProductName); + }); + + test('vendor can permanently delete auction product @pro', async () => { + const [, , auctionProductName] = await apiUtils.createProduct(payloads.createAuctionProduct(), payloads.vendorAuth); + await vendor.deleteAuctionProduct(auctionProductName); + }); + + test('vendor auction activity page is rendering properly @pro @explo', async () => { + await vendor.vendorAuctionActivityRenderProperly(); + }); + + test('vendor can filter auction activity @pro', async () => { + await vendor.filterAuctionActivity(data.date.dateRange); + }); + + test('vendor can search auction activity @pro', async () => { + await vendor.searchAuctionActivity(data.customer.username); + }); + + test('customer can bid auction product @pro', async () => { + await customer.bidAuctionProduct(auctionProductName); + }); + + test.skip('customer can buy auction product with buy it now price @pro', async () => { + const [, , auctionProductName] = await apiUtils.createProduct(payloads.createAuctionProduct(), payloads.vendorAuth); // todo: buy it now price is not saved by api + await customer.buyAuctionProduct(auctionProductName); + }); +}); diff --git a/tests/pw/tests/e2e/vendorBooking.spec.ts b/tests/pw/tests/e2e/vendorBooking.spec.ts new file mode 100644 index 0000000000..b5dbf4d652 --- /dev/null +++ b/tests/pw/tests/e2e/vendorBooking.spec.ts @@ -0,0 +1,129 @@ +import { test, Page } from '@playwright/test'; +import { BookingPage } from '@pages/vendorBookingPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { payloads } from '@utils/payloads'; +import { data } from '@utils/testData'; + +test.describe('Booking Product test', () => { + let admin: BookingPage; + let vendor: BookingPage; + let customer: BookingPage; + let aPage: Page, vPage: Page, cPage: Page; + let apiUtils: ApiUtils; + let bookableProductName: string; + const bookingResourceName = data.product.booking.resource.resourceName(); + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new BookingPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new BookingPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new BookingPage(cPage); + + apiUtils = new ApiUtils(request); + [, , bookableProductName] = await apiUtils.createBookableProduct(payloads.createBookableProduct(), payloads.vendorAuth); + + await vendor.addBookingResource(bookingResourceName); // todo: convert with api or db + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + await cPage.close(); + }); + + test('admin can add booking product @pro', async () => { + await admin.adminAddBookingProduct(data.product.booking); + }); + + test('vendor booking menu page is rendering properly @pro @explo', async () => { + await vendor.vendorBookingRenderProperly(); + }); + + test('vendor manage booking page is rendering properly @pro @explo', async () => { + await vendor.vendorManageBookingRenderProperly(); + }); + + test('vendor booking calendar page is rendering properly @pro @explo', async () => { + await vendor.vendorBookingCalendarRenderProperly(); + }); + + test('vendor manage booking resource page is rendering properly @pro @explo', async () => { + await vendor.vendorManageResourcesRenderProperly(); + }); + + test('vendor can add booking product @pro', async () => { + await vendor.addBookingProduct({ ...data.product.booking, name: data.product.booking.productName() }); + }); + + test('vendor can edit booking product @pro', async () => { + await vendor.editBookingProduct({ ...data.product.booking, name: bookableProductName }); + }); + + test('vendor can filter booking products by date @pro', async () => { + await vendor.filterBookingProducts('by-date', '1'); + }); + + test('vendor can filter booking products by category @pro', async () => { + await vendor.filterBookingProducts('by-category', 'Uncategorized'); + }); + + test('vendor can filter booking products by other @pro', async () => { + await vendor.filterBookingProducts('by-other', 'featured'); + }); + + test('vendor can view booking product @pro', async () => { + await vendor.viewBookingProduct(bookableProductName); + }); + + test("vendor can't buy own booking product @pro", async () => { + await vendor.cantBuyOwnBookingProduct(bookableProductName); + }); + + test('vendor can search booking product @pro', async () => { + await vendor.searchBookingProduct(bookableProductName); + }); + + test('vendor can duplicate booking product @pro', async () => { + await vendor.duplicateBookingProduct(bookableProductName); + }); + + test('vendor can permanently delete booking product @pro', async () => { + const [, , bookableProductName] = await apiUtils.createBookableProduct(payloads.createBookableProduct(), payloads.vendorAuth); + await vendor.deleteBookingProduct(bookableProductName); + }); + + test('vendor can add booking resource @pro', async () => { + await vendor.addBookingResource(data.product.booking.resource.resourceName()); + }); + + test('vendor can edit booking resource @pro', async () => { + await vendor.editBookingResource({ ...data.product.booking.resource, name: bookingResourceName }); + }); + + test('vendor can delete booking resource @pro', async () => { + const bookingResourceName = data.product.booking.resource.resourceName(); + await vendor.addBookingResource(bookingResourceName); + await vendor.deleteBookingResource(bookingResourceName); + }); + + test('vendor can add booking for guest customer @pro', async () => { + await vendor.addBooking(bookableProductName, data.bookings); + }); + + test('vendor can add booking for existing customer @pro', async () => { + await vendor.addBooking(bookableProductName, data.bookings, data.customer.username); + }); + + test('customer can buy bookable product @pro', async () => { + await customer.buyBookableProduct(bookableProductName, data.bookings); + }); + + // todo: vendor can add booking resource to booking product +}); diff --git a/tests/pw/tests/e2e/vendorDashboard.spec.ts b/tests/pw/tests/e2e/vendorDashboard.spec.ts new file mode 100644 index 0000000000..135fb7b852 --- /dev/null +++ b/tests/pw/tests/e2e/vendorDashboard.spec.ts @@ -0,0 +1,22 @@ +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 dashboard is rendering properly @lite @explo', async () => { + await vendor.vendorDashboardRenderProperly(); + }); +}); diff --git a/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts b/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts new file mode 100644 index 0000000000..e906b798a0 --- /dev/null +++ b/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts @@ -0,0 +1,62 @@ +import { test, Page } from '@playwright/test'; +import { VendorDeliveryTimePage } from '@pages/vendorDeliveryTimePage'; +import { dbData } from '@utils/dbData'; +import { dbUtils } from '@utils/dbUtils'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Vendor delivery time test', () => { + let vendor: VendorDeliveryTimePage; + let customer: VendorDeliveryTimePage; + let vPage: Page, cPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorDeliveryTimePage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new VendorDeliveryTimePage(cPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await vPage.close(); + await cPage.close(); + }); + + test('vendor delivery time menu page is rendering properly @pro @explo', async () => { + await vendor.vendorDeliveryTimeRenderProperly(); + }); + + test('vendor delivery time settings menu page is rendering properly @pro @explo', async () => { + await vendor.vendorDeliveryTimeSettingsRenderProperly(); + }); + + test('vendor can set delivery time settings @pro', async () => { + await vendor.setDeliveryTimeSettings(data.vendor.deliveryTime); + }); + + test('vendor can filter delivery time @pro', async () => { + await vendor.filterDeliveryTime('delivery'); + }); + + test('vendor can change view style of delivery time calender @pro', async () => { + await vendor.updateCalendarView('week'); + }); + + test('customer can buy product with delivery time @pro', async () => { + await customer.addProductToCart(data.predefined.simpleProduct.product1.name, 'single-product'); + await customer.placeOrderWithDeliverTimeStorePickup('delivery-time', data.deliveryTime); + }); + + test('customer can buy product with store pickup @pro', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.deliveryTime, { ...dbData.dokan.deliveryTimeSettings, allow_vendor_override_settings: 'off' }); // todo: added for: previous test is disable store pickup + await customer.addProductToCart(data.predefined.simpleProduct.product1.name, 'single-product'); + await customer.placeOrderWithDeliverTimeStorePickup('store-pickup', data.deliveryTime); + }); +}); diff --git a/tests/pw/tests/e2e/vendorProductSubscription.spec.ts b/tests/pw/tests/e2e/vendorProductSubscription.spec.ts new file mode 100644 index 0000000000..66a67c2fb4 --- /dev/null +++ b/tests/pw/tests/e2e/vendorProductSubscription.spec.ts @@ -0,0 +1,78 @@ +import { test, Page } from '@playwright/test'; +import { VendorProductSubscriptionPage } from '@pages/vendorProductSubscriptionPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Product subscriptions test', () => { + let vendor: VendorProductSubscriptionPage; + let customer: VendorProductSubscriptionPage; + let vPage: Page, cPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorProductSubscriptionPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new VendorProductSubscriptionPage(cPage); + + apiUtils = new ApiUtils(request); + const [, productId, productName] = await apiUtils.createProduct(payloads.createSimpleSubscriptionProduct(), payloads.vendorAuth); + }); + + test.afterAll(async () => { + await vPage.close(); + await cPage.close(); + }); + + test('vendor user subscriptions menu page is rendering properly @pro @explo', async () => { + await vendor.vendorUserSubscriptionsRenderProperly(); + }); + + // test.skip('vendor can view product subscription details @pro @explo', async ( ) => { + // await vendor.filterProductSubscriptions('by-customer', data.customer.username); + // }); + + // test.skip('vendor can filter user subscriptions by customer @pro', async ( ) => { + // await vendor.filterProductSubscriptions('by-customer', data.customer.username); + // }); + + // test.skip('vendor can filter user subscriptions by date @pro', async ( ) => { + // await vendor.filterProductSubscriptions('by-date', data.date.previousDate); + // }); + + // test.skip('vendor can view user subscription @pro', async ( ) => { + // await vendor.viewProductSubscription(data.customer.username); + // }); + + // test('customer can view product subscription details @pro @explo', async ( ) => { + // await customer.customerViewProductSubscription('2328'); + // }); + + // test('customer can cancel subscription @pro', async ( ) => { + // await customer.cancelProductSubscription('2328'); + // }); + + // test('customer can reactivate subscription @pro', async ( ) => { + // await customer.reactivateProductSubscription('2328'); + // }); + + // test('customer can change address of subscription @pro', async ( ) => { + // await customer.changeAddressOfProductSubscription('2328', data.customer.customerInfo.shipping); + // }); + + // test('customer can change payment of subscription @pro', async ( ) => { + // await customer.changePaymentOfProductSubscription('2328'); + // }); + + // test('customer can renew subscription @pro', async ( ) => { + // await customer.renewProductSubscription('2328'); + // }); + + // test('customer can buy product subscription @pro', async ( ) => { + // await customer.buyProductSubscription(data.predefined.simpleSubscription.product1); + // }); +}); diff --git a/tests/pw/tests/e2e/vendorReports.spec.ts b/tests/pw/tests/e2e/vendorReports.spec.ts new file mode 100644 index 0000000000..61b29decdb --- /dev/null +++ b/tests/pw/tests/e2e/vendorReports.spec.ts @@ -0,0 +1,31 @@ +import { test, Page } from '@playwright/test'; +import { VendorReportsPage } from '@pages/vendorReportsPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Vendor analytics test', () => { + let vendor: VendorReportsPage; + let vPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorReportsPage(vPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor reports menu page is rendering properly @pro @explo', async () => { + await vendor.vendorReportsRenderProperly(); + }); + + test('vendor can export statement @pro', async () => { + await vendor.exportStatement(); + }); +}); diff --git a/tests/pw/tests/e2e/vendorReturnRequest.spec.ts b/tests/pw/tests/e2e/vendorReturnRequest.spec.ts new file mode 100644 index 0000000000..42fce54efa --- /dev/null +++ b/tests/pw/tests/e2e/vendorReturnRequest.spec.ts @@ -0,0 +1,92 @@ +import { test, Page } from '@playwright/test'; +import { VendorReturnRequestPage } from '@pages/vendorReturnRequestPage'; +import { CustomerPage } from '@pages/customerPage'; +import { OrdersPage } from '@pages/ordersPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +// const { CUSTOMER_ID, PRODUCT_ID } = process.env; + +test.describe('Vendor RMA test', () => { + let vendor: VendorReturnRequestPage; + let vendor1: OrdersPage; + let customer: VendorReturnRequestPage; + let customer1: CustomerPage; + let vPage: Page, cPage: Page; + // let apiUtils: ApiUtils; + let orderId: string; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorReturnRequestPage(vPage); + vendor1 = new OrdersPage(vPage); + + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customer = new VendorReturnRequestPage(cPage); + customer1 = new CustomerPage(cPage); + + // todo: implement via api + await customer1.addProductToCartFromSingleProductPage(data.predefined.simpleProduct.product1.name); + await customer1.goToCheckout(); + orderId = await customer1.paymentOrder(); + await vendor1.updateOrderStatusOnTable(orderId, 'processing'); + await customer.customerRequestWarranty(orderId, data.predefined.simpleProduct.product1.name, data.rma.requestWarranty); + + // apiUtils = new ApiUtils(request); + + // [,, orderId, ] = await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.processing, payloads.vendorAuth); + // [,, orderId, ] = await apiUtils.createOrderWithStatus(payloads.createProduct(), { ...payloads.createOrder, customer_id: CUSTOMER_ID }, data.order.orderStatus.processing, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await vPage.close(); + await cPage.close(); + }); + + test('vendor return request menu page is rendering properly @pro @explo', async () => { + await vendor.vendorReturnRequestRenderProperly(); + }); + + test('vendor can view return request details @pro @explo', async () => { + await vendor.vendorViewRmaDetails(orderId); + }); + + test('customer can send rma message @pro', async () => { + await customer.customerSendRmaMessage(orderId, 'test customer rma message'); + }); + + test('vendor can send rma message @pro', async () => { + // todo: depends on customer can request warranty, remove dependency + await vendor.vendorSendRmaMessage(orderId, 'test vendor rma message'); + }); + + test('vendor can update rma status @pro', async () => { + await vendor.vendorUpdateRmaStatus(orderId, 'processing'); + }); + + test('vendor can rma refund @pro', async () => { + await vendor.vendorRmaRefund(orderId, data.predefined.simpleProduct.product1.name, 'processing'); + }); + + test('vendor can delete rma request @pro', async () => { + // todo:need separate rma request + await vendor.vendorDeleteRmaRequest(orderId); + }); + + // customer + + test('customer return request menu page is rendering properly @pro @explo', async () => { + await customer.customerReturnRequestRenderProperly(); + }); + + test('customer can request warranty @pro', async () => { + await customer1.addProductToCartFromSingleProductPage(data.predefined.simpleProduct.product1.name); + await customer1.goToCheckout(); + const orderId = await customer1.paymentOrder(); + await vendor1.updateOrderStatusOnTable(orderId, 'processing'); + await customer.customerRequestWarranty(orderId, data.predefined.simpleProduct.product1.name, data.rma.requestWarranty); + }); +}); diff --git a/tests/pw/tests/e2e/vendorSettings.spec.ts b/tests/pw/tests/e2e/vendorSettings.spec.ts new file mode 100644 index 0000000000..dab22c2021 --- /dev/null +++ b/tests/pw/tests/e2e/vendorSettings.spec.ts @@ -0,0 +1,121 @@ +import { test, Page } from '@playwright/test'; +import { VendorSettingsPage } from '@pages/vendorSettingsPage'; +import { dbData } from '@utils/dbData'; +// import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +// import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Vendor settings test', () => { + let vendor: VendorSettingsPage; + let vPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorSettingsPage(vPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor store settings menu page is rendering properly @lite @explo', async () => { + await vendor.vendorStoreSettingsRenderProperly(); + }); + + test('vendor shipstation settings menu page is rendering properly @pro @explo', async () => { + await vendor.vendorShipstationSettingsRenderProperly(); + }); + + test('vendor social profile settings menu page is rendering properly @pro @explo', async () => { + await vendor.vendorSocialProfileSettingsRenderProperly(); + }); + + test('vendor rma settings menu page is rendering properly @pro @explo', async () => { + await vendor.vendorRmaSettingsRenderProperly(); + }); + + test('vendor store seo settings menu page is rendering properly @pro @explo', async () => { + await vendor.vendorStoreSeoSettingsRenderProperly(); + }); + + // store settings + + // todo: ensure which settings need to reset, and test data should be what + + test('vendor can set store basic settings @lite', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'basic'); + }); + + test('vendor can set store address settings @lite', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'address'); + }); + + test('vendor can set company info settings @pro', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'company-info'); + }); + + test('vendor can set map settings @lite', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'map'); + }); + + test('vendor can set terms and conditions settings @lite', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'toc'); + }); + + test('vendor can set open-close settings @lite', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'open-close'); + }); + + test('vendor can set vacation settings @pro', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'vacation'); + }); + + test('vendor can set catalog settings @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.selling, dbData.dokan.sellingSettings); + await vendor.setStoreSettings(data.vendor.vendorInfo, 'catalog'); + // await vendor.resetCatalog(); + + // disable catalog + await dbUtils.setDokanSettings(dbData.dokan.optionName.selling, { ...dbData.dokan.sellingSettings, catalog_mode_hide_add_to_cart_button: 'off', catalog_mode_hide_product_price: 'off' }); + }); + + test('vendor can set discount settings @pro', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'discount'); + }); + + test('vendor can set biography settings @pro', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'biography'); + }); + + test('vendor can set store support settings @pro', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'store-support'); + }); + + test('vendor can set min-max settings @pro', async () => { + await vendor.setStoreSettings(data.vendor.vendorInfo, 'min-max'); + // disable min-max + await dbUtils.setDokanSettings(dbData.dokan.optionName.selling, { ...dbData.dokan.sellingSettings, enable_min_max_quantity: 'off', enable_min_max_amount: 'off' }); + }); + + test('vendor can set shipStation settings @pro', async () => { + await vendor.setShipStation(data.vendor.shipStation); + }); + + test('vendor can set social profile settings @pro', async () => { + await vendor.setSocialProfile(data.vendor.socialProfileUrls); + }); + + test('vendor can set rma settings @pro', async () => { + await vendor.setRmaSettings(data.vendor.rma); + }); + + test('vendor can set store seo settings @pro', async () => { + await vendor.setStoreSeo(data.vendor.seo); + }); +}); diff --git a/tests/pw/tests/e2e/vendorShipping.spec.ts b/tests/pw/tests/e2e/vendorShipping.spec.ts new file mode 100644 index 0000000000..0eae6c4956 --- /dev/null +++ b/tests/pw/tests/e2e/vendorShipping.spec.ts @@ -0,0 +1,61 @@ +import { test, Page } from '@playwright/test'; +import { VendorShippingPage } from '@pages/vendorShippingPage'; +// import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +// import { payloads } from '@utils/payloads'; + +test.describe('Vendor shipping test', () => { + let vendor: VendorShippingPage; + let vPage: Page; + // let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorShippingPage(vPage); + + // apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor shipping settings menu page is rendering properly @pro @explo', async () => { + await vendor.vendorShippingSettingsRenderProperly(); + }); + + test('vendor can set shipping policy @pro', async () => { + await vendor.setShippingPolicies(data.vendor.shipping.shippingPolicy); + }); + + test('vendor can add flat rate shipping @pro', async () => { + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.flatRate); + }); + + test('vendor can add free shipping @pro', async () => { + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.freeShipping); + }); + + test('vendor can add local pickup shipping @pro', async () => { + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.localPickup); + }); + + test('vendor can add table rate shipping @pro', async () => { + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.tableRateShipping); + }); + + test('vendor can add dokan distance rate shipping @pro', async () => { + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.distanceRateShipping); + }); + + test('vendor can edit shipping method @pro', async () => { + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.localPickup, false, true); + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.localPickup); + }); + + test('vendor can delete shipping method @pro', async () => { + await vendor.addShippingMethod(data.vendor.shipping.shippingMethods.flatRate, true, true); // todo: add with api v2 settings group + await vendor.deleteShippingMethod(data.vendor.shipping.shippingMethods.flatRate); + }); +}); diff --git a/tests/pw/tests/e2e/vendorStaff.spec.ts b/tests/pw/tests/e2e/vendorStaff.spec.ts new file mode 100644 index 0000000000..81565adae8 --- /dev/null +++ b/tests/pw/tests/e2e/vendorStaff.spec.ts @@ -0,0 +1,45 @@ +import { test, Page } from '@playwright/test'; +import { VendorStaffPage } from '@pages/vendorStaffPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe('Vendor staff test', () => { + let vendor: VendorStaffPage; + let vPage: Page; + let apiUtils: ApiUtils; + const staff = data.staff(); + + test.beforeAll(async ({ browser, request }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorStaffPage(vPage); + + apiUtils = new ApiUtils(request); + await apiUtils.createVendorStaff({...payloads.createStaff(), first_name: staff.firstName, last_name: staff.lastName}, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor staff menu page is rendering properly @pro @explo', async () => { + await vendor.vendorStaffRenderProperly(); + }); + + test('vendor can add new staff @pro', async () => { + await vendor.addStaff(data.staff()); + }); + + test('vendor can edit staff @pro', async () => { + await vendor.editStaff(staff); + }); + + test('vendor can manage staff permission @pro', async () => { + await vendor.manageStaffPermission(staff.firstName + ' ' + staff.lastName); + }); + + test('vendor can delete staff @pro', async () => { + await vendor.deleteStaff(staff.firstName + ' ' + staff.lastName); + }); +}); diff --git a/tests/pw/tests/e2e/vendorTools.spec.ts b/tests/pw/tests/e2e/vendorTools.spec.ts new file mode 100644 index 0000000000..64df8ca151 --- /dev/null +++ b/tests/pw/tests/e2e/vendorTools.spec.ts @@ -0,0 +1,38 @@ +import { test, Page } from '@playwright/test'; +import { VendorToolsPage } from '@pages/vendorToolsPage'; +import { data } from '@utils/testData'; + +test.describe('Vendor tools test', () => { + let vendor: VendorToolsPage; + let vPage: Page; + + test.beforeAll(async ({ browser }) => { + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new VendorToolsPage(vPage); + }); + + test.afterAll(async () => { + await vPage.close(); + }); + + test('vendor tools menu page is rendering properly @pro @explo', async () => { + await vendor.vendorToolsRenderProperly(); + }); + + test('vendor can export product as xml @pro', async () => { + await vendor.exportProduct('xml'); + }); + + test('vendor can export product as csv @pro', async () => { + await vendor.exportProduct('csv'); + }); + + test('vendor can import product as xml @pro', async () => { + await vendor.importProduct('xml', 'utils/sampleData/products.xml'); + }); + + test('vendor can import product as csv @pro', async () => { + await vendor.importProduct('csv', 'utils/sampleData/products.csv'); + }); +}); diff --git a/tests/pw/tests/e2e/vendorVerifications.spec.ts b/tests/pw/tests/e2e/vendorVerifications.spec.ts new file mode 100644 index 0000000000..51b8b2b701 --- /dev/null +++ b/tests/pw/tests/e2e/vendorVerifications.spec.ts @@ -0,0 +1,74 @@ +import { test, Page } from '@playwright/test'; +import { vendorVerificationsPage } from '@pages/vendorVerificationsPage'; +import { data } from '@utils/testData'; + +test.describe('Verifications test', () => { + let admin: vendorVerificationsPage; + let vendor: vendorVerificationsPage; + let aPage: Page, vPage: Page; + + test.beforeAll(async ({ browser }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new vendorVerificationsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new vendorVerificationsPage(vPage); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + }); + + // vendor + + test('vendor verifications settings menu page is rendering properly @pro @explo', async () => { + await vendor.vendorVerificationsSettingsRenderProperly(); + }); + + test('vendor can send id verification request @pro', async () => { + await vendor.sendIdVerificationRequest(data.vendor.verification); + }); + + test('vendor can send address verification request @pro', async () => { + await vendor.sendAddressVerificationRequest(data.vendor.verification); + }); + + test('vendor can send company verification request @pro', async () => { + await vendor.sendCompanyVerificationRequest(data.vendor.verification); + }); + + // todo: remove dependency: admin tests depends on vendor tests + + test('admin verifications menu page is rendering properly @pro @explo', async () => { + await admin.adminVerificationsRenderProperly(); + }); + + // test('admin can approve ID verification request @pro', async ( ) => { + // await admin.approveVerificationRequest(data.predefined.vendorInfo.username, 'id', 'approve'); + // }); + + // test('admin can approve address verification request @pro', async ( ) => { + // await admin.approveVerificationRequest(data.predefined.vendorInfo.username, 'address', 'approve'); + // }); + + // test('admin can approve company verification request @pro', async ( ) => { + // await admin.approveVerificationRequest(data.predefined.vendorInfo.username, 'company', 'approve'); + // }); + + // todo: admin can reject requests + + // test('admin can disapprove approved ID verification request @pro', async ( ) => { + // await admin.disapproveVerificationRequest(data.predefined.vendorInfo.username, 'id'); + // }); + + // test('admin can disapprove approved address verification request @pro', async ( ) => { + // await admin.disapproveVerificationRequest(data.predefined.vendorInfo.username, 'address'); + // }); + + // test('admin can disapprove approved company verification request @pro', async ( ) => { + // await admin.disapproveVerificationRequest(data.predefined.vendorInfo.username, 'company'); + // }); +}); diff --git a/tests/pw/tests/e2e/wholesaleCustomers.spec.ts b/tests/pw/tests/e2e/wholesaleCustomers.spec.ts new file mode 100644 index 0000000000..67bcfe8cc4 --- /dev/null +++ b/tests/pw/tests/e2e/wholesaleCustomers.spec.ts @@ -0,0 +1,121 @@ +import { test, Page } from '@playwright/test'; +import { WholesaleCustomersPage } from '@pages/wholesaleCustomersPage'; +import { CustomerPage } from '@pages/customerPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; +import { dbData } from '@utils/dbData'; + +test.describe('Wholesale customers test (admin)', () => { + let admin: WholesaleCustomersPage; + let customer: WholesaleCustomersPage; + let customerPage: CustomerPage; + let aPage: Page, cPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new WholesaleCustomersPage(aPage); + + const customerContext = await browser.newContext({ storageState: { cookies: [], origins: [] } }); + cPage = await customerContext.newPage(); + customerPage = new CustomerPage(cPage); + customer = new WholesaleCustomersPage(cPage); + + apiUtils = new ApiUtils(request); + + await apiUtils.createWholesaleCustomer(payloads.createCustomer(), payloads.adminAuth); + await apiUtils.createWholesaleCustomer(payloads.createCustomer1, payloads.adminAuth); + // [,, productName] = await apiUtils.createProduct(payloads.createWholesaleProduct(), payloads. vendorAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + await cPage.close(); + }); + + test('dokan wholesale customers menu page is rendering properly @pro @explo', async () => { + await admin.adminWholesaleCustomersRenderProperly(); + }); + + test('admin can search wholesale customer @pro', async () => { + await admin.searchWholesaleCustomer(data.predefined.customerInfo.username1); + }); + + test("admin can disable customer's wholesale capability @pro", async () => { + await admin.updateWholesaleCustomer(data.predefined.customerInfo.username1, 'disable'); + }); + + test("admin can enable customer's wholesale capability @pro", async () => { + await admin.updateWholesaleCustomer(data.predefined.customerInfo.username1, 'enable'); + }); + + test('admin can edit wholesale customer @pro', async () => { + await admin.editWholesaleCustomer(data.customer); + }); + + test('admin can view wholesale customer orders @pro', async () => { + await admin.viewWholesaleCustomerOrders(data.predefined.customerInfo.username1); + }); + + test('admin can delete wholesale customer @pro', async () => { + await admin.updateWholesaleCustomer(data.predefined.customerInfo.username1, 'delete'); + }); + + test('admin can perform wholesale customer bulk action @pro', async () => { + await admin.wholesaleCustomerBulkAction('activate'); + }); + + test('customer can become a wholesale customer', async () => { + await customerPage.customerRegister(data.customer.customerInfo); + await customer.customerBecomeWholesaleCustomer(); + }); + + test('customer can request for become a wholesale customer', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.wholesale, { ...dbData.dokan.wholesaleSettings, need_approval_for_wholesale_customer: 'on' }); + await customerPage.customerRegister(data.customer.customerInfo); + await customer.customerRequestForBecomeWholesaleCustomer(); + }); +}); + +test.describe.skip('Wholesale customers test customer', () => { + let customer: WholesaleCustomersPage; + let customerPage: CustomerPage; + let cPage: Page; + let apiUtils: ApiUtils; + let productName: string; + let wholesalePrice: string; + let minimumWholesaleQuantity: string; + + test.beforeAll(async ({ browser, request }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customerPage = new CustomerPage(cPage); + customer = new WholesaleCustomersPage(cPage); + + apiUtils = new ApiUtils(request); + await apiUtils.createWholesaleCustomer(payloads.createCustomer1, payloads.adminAuth); // todo: need to update customer auth if crated wholesale or move to env setup + + const [responseBody, ,] = await apiUtils.createProduct(payloads.createWholesaleProduct(), payloads.vendorAuth); + productName = responseBody.name; + wholesalePrice = responseBody.meta_data[0]['value']['price']; + minimumWholesaleQuantity = responseBody.meta_data[0]['value']['quantity']; + }); + + test.afterAll(async () => { + await cPage.close(); + }); + + test('customer can see wholesale price on shop archive', async () => { + await customer.viewWholeSalePrice(productName); + }); + + test('customer can buy wholesale product', async () => { + await customerPage.addProductToCart(productName, 'single-product', true, minimumWholesaleQuantity); + await customer.assertWholesalePrice(wholesalePrice, minimumWholesaleQuantity); + await customerPage.paymentOrder(); + await customerPage.loginPage.login(data.customer); + }); +}); diff --git a/tests/pw/tests/e2e/withdraws.spec.ts b/tests/pw/tests/e2e/withdraws.spec.ts new file mode 100644 index 0000000000..d56cd0efca --- /dev/null +++ b/tests/pw/tests/e2e/withdraws.spec.ts @@ -0,0 +1,110 @@ +import { test, Page } from '@playwright/test'; +import { WithdrawsPage } from '@pages/withdrawsPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +const { PRODUCT_ID } = process.env; + +test.describe('Withdraw test', () => { + let admin: WithdrawsPage; + let vendor: WithdrawsPage; + let aPage: Page, vPage: Page; + let apiUtils: ApiUtils; + let currentBalance: string; + let minimumWithdrawLimit: string; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + admin = new WithdrawsPage(aPage); + + const vendorContext = await browser.newContext(data.auth.vendorAuth); + vPage = await vendorContext.newPage(); + vendor = new WithdrawsPage(vPage); + + apiUtils = new ApiUtils(request); + [currentBalance, minimumWithdrawLimit] = await apiUtils.getMinimumWithdrawLimit(payloads.vendorAuth); + await apiUtils.createOrderWithStatus(PRODUCT_ID, { ...payloads.createOrder, line_items: [{ quantity: 10 }] }, 'wc-completed', payloads.vendorAuth); + await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }, payloads.vendorAuth); + }); + + test.afterAll(async () => { + await aPage.close(); + await vPage.close(); + }); + + test('admin withdraw menu page is rendering properly @lite @explo', async () => { + await admin.adminWithdrawsRenderProperly(); + }); + + test('admin can filter withdraws by vendor @lite', async () => { + await admin.filterWithdraws(data.predefined.vendorStores.vendor1, 'by-vendor'); + }); + + test('admin can filter withdraws by payment methods @lite', async () => { + await admin.filterWithdraws(data.vendor.withdraw.defaultWithdrawMethod.paypal, 'by-payment-method'); + }); + + test('admin can export withdraws', async () => { + await admin.exportWithdraws(); + }); + + test('admin can add note to withdraw request @lite', async () => { + await admin.addNoteWithdrawRequest(data.predefined.vendorStores.vendor1, 'test withdraw note'); + }); + + test('admin can approve withdraw request @lite', async () => { + await admin.updateWithdrawRequest(data.predefined.vendorStores.vendor1, 'approve'); + }); + + test('admin can cancel withdraw request @lite', async () => { + await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }, payloads.vendorAuth); + await admin.updateWithdrawRequest(data.predefined.vendorStores.vendor1, 'cancel'); + }); + + test('admin can delete withdraw request @lite', async () => { + await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }, payloads.vendorAuth); + await admin.updateWithdrawRequest(data.predefined.vendorStores.vendor1, 'delete'); + }); + + test('admin can perform withdraw bulk actions @lite', async () => { + await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }, payloads.vendorAuth); + await admin.withdrawBulkAction('cancelled'); + }); + + // vendor + + test('vendor withdraw menu page is rendering properly @lite @explo', async () => { + await vendor.vendorWithdrawRenderProperly(); + }); + + test('vendor withdraw requests page is rendering properly @lite @explo', async () => { + await vendor.vendorWithdrawRequestsRenderProperly(); + }); + + test('vendor can request withdraw @lite', async () => { + await apiUtils.cancelWithdraw('', payloads.vendorAuth); + await vendor.requestWithdraw({ ...data.vendor.withdraw, minimumWithdrawAmount: minimumWithdrawLimit, currentBalance: currentBalance }); + }); + + test("vendor can't request withdraw when pending request exits @lite", async () => { + await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }, payloads.vendorAuth); + await vendor.cantRequestWithdraw(); + }); + + test('vendor can cancel request withdraw @lite', async () => { + await apiUtils.createWithdraw({ ...payloads.createWithdraw, amount: minimumWithdrawLimit }, payloads.vendorAuth); + await vendor.cancelWithdrawRequest(); + }); + + test('vendor can add auto withdraw disbursement schedule @pro', async () => { + await vendor.addAutoWithdrawDisbursementSchedule({ ...data.vendor.withdraw, minimumWithdrawAmount: minimumWithdrawLimit }); + }); + + test('vendor can add default withdraw payment methods @lite', async () => { + await vendor.addDefaultWithdrawPaymentMethods(data.vendor.withdraw.defaultWithdrawMethod.bankTransfer); + // Cleanup + await vendor.addDefaultWithdrawPaymentMethods(data.vendor.withdraw.defaultWithdrawMethod.paypal); + }); +}); diff --git a/tests/pw/tsconfig.json b/tests/pw/tsconfig.json new file mode 100644 index 0000000000..15934ba53a --- /dev/null +++ b/tests/pw/tsconfig.json @@ -0,0 +1,60 @@ +{ + // "compileOnSave": true, + "compilerOptions": { + // project options + "lib": ["ESNext", "dom"] /* specifies which default set of type definitions to use ("DOM", "ES6", etc)*/, + "outDir": "lib" /* .js (as well as .d.ts, .js.map, etc.) files will be emitted into this directory.*/, + "removeComments": true /* Strips all comments from TypeScript files when converting into JavaScript- you rarely read compiled code so this saves space*/, + // "target": "ES6", /* Target environment. Most modern browsers support ES6, but you may want to set it to newer or older. (defaults to ES3)*/ + "target": "ES2017" /* Target environment. Most modern browsers support ES6, but you may want to set it to newer or older. (defaults to ES3)*/, + "module": "es2022" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */, + "allowJs": true /* Allow javascript files to be compiled. */, + "checkJs": true /* Report errors in .js files. */, + "declaration": true /* Generates corresponding '.d.ts' file. */, + "declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */, + // Module resolution + "rootDir": "." /* Specify the root directory of input files. */, + "baseUrl": "." /* Lets you set a base directory to resolve non-absolute module names.*/, + "paths": { + "@pages/*": ["pages/*"], + "@utils/*": ["utils/*"], + "@apiEndPoints": ["utils/apiEndPoints"], + "@apiUtils": ["utils/apiUtils"], + "@dbData": ["utils/dbData"], + "@dbUtils": ["utils/dbUtils"], + "@helpers": ["utils/helpers"], + "@interfaces": ["utils/interfaces"], + "@payloads": ["utils/payloads"], + "@testData": ["utils/testData"] + }, + "esModuleInterop": true /* fixes some issues TS originally had with the ES6 spec where TypeScript treats CommonJS/AMD/UMD modules similar to ES6 module*/, + "moduleResolution": "node" /* Pretty much always node for modern JS. Other option is "classic"*/, + "typeRoots": ["./node_modules/@types", "./types"] /* List of folders to include type definitions from. */, + "resolveJsonModule": true, + "importHelpers": true /* Import emit helpers from 'tslib'. */, + "downlevelIteration": true /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */, + // "allowSyntheticDefaultImports": true /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */, + // Source Map + "sourceMap": true /* enables the use of source maps for debuggers and error reporting etc*/, + "sourceRoot": "/" /* Specify the location where a debugger should locate TypeScript files instead of relative source locations.*/, + // Strict Checks + "alwaysStrict": true /* Ensures that your files are parsed in the ECMAScript strict mode, and emit “use strict” for each source file.*/, + "strict": true /* Enable all strict type-checking options. */, + "allowUnreachableCode": false /* pick up dead code paths*/, + "noImplicitAny": true /* In some cases where no type annotations are present, TypeScript will fall back to a type of any for a variable when it cannot infer the type.*/, + "strictNullChecks": true /* When strictNullChecks is true, null and undefined have their own distinct types and you’ll get a type error if you try to use them where a concrete value is expected.*/, + "strictFunctionTypes": true /* Enable strict checking of function types. */, + "strictBindCallApply": true /* Enable strict 'bind', 'call', and 'apply' methods on functions. */, + "strictPropertyInitialization": true /* Enable strict checking of property initialization in classes. */, + "noImplicitThis": true /* Raise error on 'this' expressions with an implied 'any' type. */, + "skipLibCheck": true /* Skip type checking of declaration files. */, + // Linter Checks + "noUnusedLocals": true /* Report errors on unused local variables.*/, + "noUnusedParameters": true /* Report errors on unused parameters in functions*/, + "noImplicitReturns": true /* Report error when not all code paths in function return a value. */, + "noUncheckedIndexedAccess": true /* accessing index must always check for undefined*/, + "noFallthroughCasesInSwitch": true /* Report errors for fallthrough cases in switch statement. */, + "forceConsistentCasingInFileNames": true /* Force consistent Casing In File Names */ + }, + "exclude": ["node_modules/**/*", "playwright/**/*", "playwright-report/**/*"] +} diff --git a/tests/pw/types/environment.d.ts b/tests/pw/types/environment.d.ts new file mode 100644 index 0000000000..d33e026753 --- /dev/null +++ b/tests/pw/types/environment.d.ts @@ -0,0 +1,44 @@ +export { }; + +declare global { + namespace NodeJS { + interface ProcessEnv { + // [key: string]: string + ADMIN: string; + ADMIN_PASSWORD: string; + VENDOR: string; + VENDOR2: string; + USER_PASSWORD: string; + CUSTOMER: string; + ADMIN_ID: string; + VENDOR_ID: string; + VENDOR2_ID: string; + CUSTOMER_ID: string; + PRODUCT_ID: string; + V2_PRODUCT_ID: string; + GMAP: string; + DOKAN_PRO: string + BASE_URL:string; + QUERY:string; + HEADLESS: string; + SLOWMO: string; + DEVTOOLS: string; + RETRY_TIMES: string; + TIME_OUT: string; + SERVER_URL: string; + ADMIN_AUTH: string; + VENDOR_AUTH: string; + CUSTOMER_AUTH: string; + DB_HOST_NAME: string; + DB_USER_NAME: string; + DB_USER_PASSWORD: string; + DATABASE: string; + DB_PORT: number; + DB_PREFIX: string; + API_TEST_RESULT: string + E2E_TEST_RESULT: string + + + } + } +} diff --git a/tests/pw/utils/apiEndPoints.ts b/tests/pw/utils/apiEndPoints.ts new file mode 100644 index 0000000000..33b5b34eda --- /dev/null +++ b/tests/pw/utils/apiEndPoints.ts @@ -0,0 +1,568 @@ +// const { SERVER_URL } = process.env; + +const SERVER_URL = process.env.SERVER_URL ? process.env.SERVER_URL : process.env.BASE_URL + '/wp-json'; + +export const endPoints = { + serverUrl: `${SERVER_URL}`, + getAllDokanEndpointsV1: `${SERVER_URL}/dokan/v1`, + getAllDokanEndpointsV2: `${SERVER_URL}/dokan/v2`, + getAllDokanEndpointsAdmin: `${SERVER_URL}/dokan/v1/admin`, + + // stores + getAllStores: `${SERVER_URL}/dokan/v1/stores`, + getSingleStore: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}`, + createStore: `${SERVER_URL}/dokan/v1/stores`, + updateStore: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}`, + deleteStore: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}`, + getStoresSlugAvaility: `${SERVER_URL}/dokan/v1/stores/check`, + getStoreCurrentVisitor: `${SERVER_URL}/dokan/v1/stores/current-visitor`, + getStoreStats: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/stats`, + getStoreCategories: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/categories`, + getStoreProducts: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/products`, + updateStoreStatus: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/status`, + clientContactStore: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/contact`, // post + adminEmailStore: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/email`, // post + updateBatchStores: `${SERVER_URL}/dokan/v1/stores/batch`, // method: approved, pending, delete + + // products + getAllProducts: `${SERVER_URL}/dokan/v1/products`, + getSingleProduct: (productId: string) => `${SERVER_URL}/dokan/v1/products/${productId}`, + createProduct: `${SERVER_URL}/dokan/v1/products`, + updateProduct: (productId: string) => `${SERVER_URL}/dokan/v1/products/${productId}`, + deleteProduct: (productId: string) => `${SERVER_URL}/dokan/v1/products/${productId}`, + getAllRelatedProducts: (productId: string) => `${SERVER_URL}/dokan/v1/products/${productId}/related`, + getProductsSummary: `${SERVER_URL}/dokan/v1/products/summary`, + getTopRatedProducts: `${SERVER_URL}/dokan/v1/products/top_rated`, + getBestSellingProducts: `${SERVER_URL}/dokan/v1/products/best_selling`, + getFeaturedProducts: `${SERVER_URL}/dokan/v1/products/featured`, + getLatestProducts: `${SERVER_URL}/dokan/v1/products/latest`, + getAllMultiStepCategories: `${SERVER_URL}/dokan/v1/products/multistep-categories`, + + // product attributes + getAllAttributes: `${SERVER_URL}/dokan/v1/products/attributes`, + getSingleAttribute: (attributeId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}`, + createAttribute: `${SERVER_URL}/dokan/v1/products/attributes`, + updateAttribute: (attributeId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}`, + deleteAttribute: (attributeId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}`, + batchUpdateAttributes: `${SERVER_URL}/dokan/v1/products/attributes/batch`, // method: create, update, delete + setDefaultAttribute: (productId: string) => `${SERVER_URL}/dokan/v1/products/attributes/set-default/${productId}`, + updateProductAttribute: (productId: string) => `${SERVER_URL}/dokan/v1/products/attributes/edit-product/${productId}`, + + // product attribute terms + getAllAttributeTerms: (attributeId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}/terms`, + getSingleAttributeTerm: (attributeId: string, attributeTermId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}/terms/${attributeTermId}`, + createAttributeTerm: (attributeId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}/terms`, + updateAttributeTerm: (attributeId: string, attributeTermId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}/terms/${attributeTermId}`, + deleteAttributeTerm: (attributeId: string, attributeTermId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}/terms/${attributeTermId}`, + updateBatchAttributeTerms: (attributeId: string) => `${SERVER_URL}/dokan/v1/products/attributes/${attributeId}/terms/batch`, // method: create, update, delete + + // product variations + getAllProductVariations: (productId: string) => `${SERVER_URL}/dokan/v1/products/${productId}/variations`, + getSingleProductVariation: (productId: string, variationId: string) => `${SERVER_URL}/dokan/v1/products/${productId}/variations/${variationId}`, + createProductVariation: (productId: string) => `${SERVER_URL}/dokan/v1/products/${productId}/variations`, + updateProductVariation: (productId: string, variationId: string) => `${SERVER_URL}/dokan/v1/products/${productId}/variations/${variationId}`, + deleteProductVariation: (productId: string, variationId: string) => `${SERVER_URL}/dokan/v1/products/${productId}/variations/${variationId}`, + batchUpdateProductVariations: (productId: string) => `${SERVER_URL}/dokan/v1/products/${productId}/variations/batch`, // method: create, update, delete + + // orders + getOrdersSummary: `${SERVER_URL}/dokan/v1/orders/summary`, + getAllOrders: `${SERVER_URL}/dokan/v1/orders`, + getSingleOrder: (orderId: string) => `${SERVER_URL}/dokan/v1/orders/${orderId}`, + updateOrder: (orderId: string) => `${SERVER_URL}/dokan/v1/orders/${orderId}`, + + // order notes + getAllOrderNotes: (orderId: string) => `${SERVER_URL}/dokan/v1/orders/${orderId}/notes`, + getSingleOrderNote: (orderId: string, noteId: string) => `${SERVER_URL}/dokan/v1/orders/${orderId}/notes/${noteId}`, + createOrderNote: (orderId: string) => `${SERVER_URL}/dokan/v1/orders/${orderId}/notes`, + deleteOrderNote: (orderId: string, noteId: string) => `${SERVER_URL}/dokan/v1/orders/${orderId}/notes/${noteId}`, + + // withdraws + getWithdrawPaymentMethods: `${SERVER_URL}/dokan/v1/withdraw/payment_methods`, + getBalanceDetails: `${SERVER_URL}/dokan/v1/withdraw/balance`, + getAllWithdraws: `${SERVER_URL}/dokan/v1/withdraw`, + getSingleWithdraw: (withdrawId: string) => `${SERVER_URL}/dokan/v1/withdraw/${withdrawId}`, + createWithdraw: `${SERVER_URL}/dokan/v1/withdraw`, // post + updateWithdraw: (withdrawId: string) => `${SERVER_URL}/dokan/v1/withdraw/${withdrawId}`, + cancelWithdraw: (withdrawId: string) => `${SERVER_URL}/dokan/v1/withdraw/${withdrawId}`, + updateBatchWithdraws: `${SERVER_URL}/dokan/v1/withdraw/batch`, // method: approved, pending, delete, cancelled + + // store settings + getSettings: `${SERVER_URL}/dokan/v1/settings`, + updateSettings: `${SERVER_URL}/dokan/v1/settings`, + + // dummy data + getDummyDataStatus: `${SERVER_URL}/dokan/v1/dummy-data/status`, + importDummyData: `${SERVER_URL}/dokan/v1/dummy-data/import`, + clearDummyData: `${SERVER_URL}/dokan/v1/dummy-data/clear`, + + // store categories + getDefaultStoreCategory: `${SERVER_URL}/dokan/v1/store-categories/default-category`, + setDefaultStoreCategory: `${SERVER_URL}/dokan/v1/store-categories/default-category`, // post + getAllStoreCategories: `${SERVER_URL}/dokan/v1/store-categories`, + getSingleStoreCategory: (categoryId: string) => `${SERVER_URL}/dokan/v1/store-categories/${categoryId}`, + createStoreCategory: `${SERVER_URL}/dokan/v1/store-categories`, + updateStoreCategory: (categoryId: string) => `${SERVER_URL}/dokan/v1/store-categories/${categoryId}`, + deleteStoreCategory: (categoryId: string) => `${SERVER_URL}/dokan/v1/store-categories/${categoryId}`, + + // coupons + getAllCoupons: `${SERVER_URL}/dokan/v1/coupons`, + getSingleCoupon: (couponId: string) => `${SERVER_URL}/dokan/v1/coupons/${couponId}`, + createCoupon: `${SERVER_URL}/dokan/v1/coupons`, + updateCoupon: (couponId: string) => `${SERVER_URL}/dokan/v1/coupons/${couponId}`, + deleteCoupon: (couponId: string) => `${SERVER_URL}/dokan/v1/coupons/${couponId}`, + + // reports + getSalesOverviewReport: `${SERVER_URL}/dokan/v1/reports/sales_overview`, + getSummaryReport: `${SERVER_URL}/dokan/v1/reports/summary`, + getTopEarnersReport: `${SERVER_URL}/dokan/v1/reports/top_earners`, + getTopSellingProductsReport: `${SERVER_URL}/dokan/v1/reports/top_selling`, + + // product reviews + getAllProductReviews: `${SERVER_URL}/dokan/v1/reviews`, + getProductReviewSummary: `${SERVER_URL}/dokan/v1/reviews/summary`, + updateReview: (reviewId: string) => `${SERVER_URL}/dokan/v1/reviews/${reviewId}`, + + // store reviews + getStoreReviews: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/reviews`, + createStoreReview: (sellerId: string) => `${SERVER_URL}/dokan/v1/stores/${sellerId}/reviews`, + getAllStoreReviews: `${SERVER_URL}/dokan/v1/store-reviews`, + getSingleStoreReview: (reviewId: string) => `${SERVER_URL}/dokan/v1/store-reviews/${reviewId}`, + updateStoreReview: (reviewId: string) => `${SERVER_URL}/dokan/v1/store-reviews/${reviewId}`, + deleteStoreReview: (reviewId: string) => `${SERVER_URL}/dokan/v1/store-reviews/${reviewId}`, + restoreDeletedStoreReview: (reviewId: string) => `${SERVER_URL}/dokan/v1/store-reviews/${reviewId}/restore`, // put + updateBatchStoreReviews: `${SERVER_URL}/dokan/v1/store-reviews/batch`, // method: trash, delete, restore + + // announcements + getAllAnnouncements: `${SERVER_URL}/dokan/v1/announcement`, + getSingleAnnouncement: (announcementId: string) => `${SERVER_URL}/dokan/v1/announcement/${announcementId}`, + createAnnouncement: `${SERVER_URL}/dokan/v1/announcement`, + updateAnnouncement: (announcementId: string) => `${SERVER_URL}/dokan/v1/announcement/${announcementId}`, + deleteAnnouncement: (announcementId: string) => `${SERVER_URL}/dokan/v1/announcement/${announcementId}`, + restoreDeletedAnnouncement: (announcementId: string) => `${SERVER_URL}/dokan/v1/announcement/${announcementId}/restore`, // put + updateBatchAnnouncements: `${SERVER_URL}/dokan/v1/announcement/batch`, // method: trash, delete, restore + + // refunds + getAllRefunds: `${SERVER_URL}/dokan/v1/refunds`, + approveRefund: (refundId: string) => `${SERVER_URL}/dokan/v1/refunds/${refundId}/approve`, // put + cancelRefund: (refundId: string) => `${SERVER_URL}/dokan/v1/refunds/${refundId}/cancel`, // put + deleteRefund: (refundId: string) => `${SERVER_URL}/dokan/v1/refunds/${refundId}`, + updateBatchRefunds: `${SERVER_URL}/dokan/v1/refunds/batch`, // method: completed, cancelled + + // follow store + getStoreFollowStatus: `${SERVER_URL}/dokan/v1/follow-store`, + followUnfollowStore: `${SERVER_URL}/dokan/v1/follow-store`, // post + getFollowers: `${SERVER_URL}/dokan/v1/follow-store/followers`, // post + + // abuse reports + getAllAbuseReportReasons: `${SERVER_URL}/dokan/v1/abuse-reports/abuse-reasons`, + getAllAbuseReports: `${SERVER_URL}/dokan/v1/abuse-reports`, + deleteAbuseReport: (abuseReportId: string) => `${SERVER_URL}/dokan/v1/abuse-reports/${abuseReportId}`, + deleteBatchAbuseReports: `${SERVER_URL}/dokan/v1/abuse-reports/batch`, // delete // method: items + + // product advertisements + getAllProductAdvertisementStores: `${SERVER_URL}/dokan/v1/product_adv/stores`, + getAllProductAdvertisements: `${SERVER_URL}/dokan/v1/product_adv`, + createProductAdvertisement: `${SERVER_URL}/dokan/v1/product_adv/create`, + expireProductAdvertisement: (productAdvertisementId: string) => `${SERVER_URL}/dokan/v1/product_adv/${productAdvertisementId}/expire`, // put + deleteProductAdvertisement: (productAdvertisementId: string) => `${SERVER_URL}/dokan/v1/product_adv/${productAdvertisementId}`, + updateBatchProductAdvertisements: `${SERVER_URL}/dokan/v1/product_adv/batch`, // method: delete + + // wholesale customers + getAllWholesaleCustomers: `${SERVER_URL}/dokan/v1/wholesale/customers`, + createWholesaleCustomer: `${SERVER_URL}/dokan/v1/wholesale/register`, + updateWholesaleCustomer: (wholesaleCustomerId: string) => `${SERVER_URL}/dokan/v1/wholesale/customer/${wholesaleCustomerId}`, + updateBatchWholesaleCustomer: `${SERVER_URL}/dokan/v1/wholesale/customers/batch`, // method: activate, deactivate, delete + + // request quote rules + getAllQuoteRules: `${SERVER_URL}/dokan/v1/request-for-quote/quote-rule`, + getSingleQuoteRule: (quoteRuleId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/quote-rule/${quoteRuleId}`, + createQuoteRule: `${SERVER_URL}/dokan/v1/request-for-quote/quote-rule`, + updateQuoteRule: (quoteRuleId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/quote-rule/${quoteRuleId}`, + deleteQuoteRule: (quoteRuleId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/quote-rule/${quoteRuleId}`, + restoreQuoteRule: (quoteRuleId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/quote-rule/${quoteRuleId}/restore`, // put + updateBatchQuoteRules: `${SERVER_URL}/dokan/v1/request-for-quote/quote-rule/batch`, // method: trash, delete, restore + + // request quotes + getAllQuoteRequests: `${SERVER_URL}/dokan/v1/request-for-quote`, + getSingleRequestQuote: (quoteRequestId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/${quoteRequestId}`, + createQuoteRequest: `${SERVER_URL}/dokan/v1/request-for-quote`, + updateRequestQuote: (quoteRequestId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/${quoteRequestId}`, + deleteQuoteRequest: (quoteRequestId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/${quoteRequestId}`, + restoreRequestQuote: (quoteRequestId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/${quoteRequestId}/restore`, // put + updateBatchRequestQuotes: `${SERVER_URL}/dokan/v1/request-for-quote/batch`, // method: trash + convertRequestQuoteToOrder: `${SERVER_URL}/dokan/v1/request-for-quote/convert-to-order`, // post + // customers (rfq) + getAllCustomers: `${SERVER_URL}/dokan/v1/request-for-quote/customers`, + getSingleCustomer: (customerId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/customers/${customerId}`, + createCustomer: `${SERVER_URL}/dokan/v1/request-for-quote/customers`, + updateCustomer: (customerId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/customers/${customerId}`, + deleteCustomer: (customerId: string) => `${SERVER_URL}/dokan/v1/request-for-quote/customers/${customerId}`, + updateBatchCustomers: `${SERVER_URL}/dokan/v1/request-for-quote/customers/batch`, // method: create, update, delete + // roles (rfq) + getAllUserRoles: `${SERVER_URL}/dokan/v1/request-for-quote/roles`, + + // reverse withdrawal + getReverseWithdrawalVendorDueStatus: `${SERVER_URL}/dokan/v1/reverse-withdrawal/vendor-due-status`, + getReverseWithdrawalAddProductToCart: `${SERVER_URL}/dokan/v1/reverse-withdrawal/add-to-cart`, + getReverseWithdrawalTransactionTypes: `${SERVER_URL}/dokan/v1/reverse-withdrawal/transaction-types`, + getAllReverseWithdrawalStores: `${SERVER_URL}/dokan/v1/reverse-withdrawal/stores`, + getAllReverseWithdrawalStoreBalance: `${SERVER_URL}/dokan/v1/reverse-withdrawal/stores-balance`, + getAllReverseWithdrawalTransactions: `${SERVER_URL}/dokan/v1/reverse-withdrawal/transactions`, + + // modules + getAllModules: `${SERVER_URL}/dokan/v1/admin/modules`, + activateModule: `${SERVER_URL}/dokan/v1/admin/modules/activate`, // put + deactivateModule: `${SERVER_URL}/dokan/v1/admin/modules/deactivate`, // put + + // support tickets + getAllSupportTicketCustomers: `${SERVER_URL}/dokan/v1/admin/support-ticket/customers`, + getAllSupportTickets: `${SERVER_URL}/dokan/v1/admin/support-ticket`, + getSingleSupportTicket: (supportTicketId: string) => `${SERVER_URL}/dokan/v1/admin/support-ticket/${supportTicketId}`, + createSupportTicketComment: (supportTicketId: string) => `${SERVER_URL}/dokan/v1/admin/support-ticket/${supportTicketId}`, + updateSupportTicketStatus: (supportTicketId: string) => `${SERVER_URL}/dokan/v1/admin/support-ticket/${supportTicketId}/status`, // post + updateSupportTicketEmailNotification: (supportTicketId: string) => `${SERVER_URL}/dokan/v1/admin/support-ticket/${supportTicketId}/email-notification`, // post + deleteSupportTicketComment: (supportTicketId: string) => `${SERVER_URL}/dokan/v1/admin/support-ticket/${supportTicketId}/comment`, + updateBatchSupportTickets: `${SERVER_URL}/dokan/v1/admin/support-ticket/batch`, // method: close + + // admin + getAdminReportSummary: `${SERVER_URL}/dokan/v1/admin/report/summary`, + getAdminReportOverview: `${SERVER_URL}/dokan/v1/admin/report/overview`, + getAdminDashboardFeed: `${SERVER_URL}/dokan/v1/admin/dashboard/feed`, + getAdminHelp: `${SERVER_URL}/dokan/v1/admin/help`, + getAdminChangelogLite: `${SERVER_URL}/dokan/v1/admin/changelog/lite`, + getAdminChangelogPro: `${SERVER_URL}/dokan/v1/admin/changelog/pro`, + getAdminNotices: `${SERVER_URL}/dokan/v1/admin/notices/admin`, + getAdminPromoNotices: `${SERVER_URL}/dokan/v1/admin/notices/promo`, + getAdminLogs: `${SERVER_URL}/dokan/v1/admin/logs`, + getAdminExportLogs: `${SERVER_URL}/dokan/v1/admin/logs/export`, + + // seller badge + getVerifiedSellerVerificationTypes: `${SERVER_URL}/dokan/v1/seller-badge/verification-types`, + getAllSellerBadgeEvents: `${SERVER_URL}/dokan/v1/seller-badge/events`, + getAllSellerBadges: `${SERVER_URL}/dokan/v1/seller-badge`, + getSingleSellerBadge: (badgeId: string) => `${SERVER_URL}/dokan/v1/seller-badge/${badgeId}`, + createSellerBadge: `${SERVER_URL}/dokan/v1/seller-badge`, + updateSellerBadge: (badgeId: string) => `${SERVER_URL}/dokan/v1/seller-badge/${badgeId}`, + deleteSellerBadge: (badgeId: string) => `${SERVER_URL}/dokan/v1/seller-badge/${badgeId}`, + updateBatchSellerBadges: `${SERVER_URL}/dokan/v1/seller-badge/bulk-actions`, + setSellerBadgeRowActions: `${SERVER_URL}/dokan/v1/seller-badge/row-actions`, + getVendorUnseenSellerBadges: `${SERVER_URL}/dokan/v1/seller-badge/vendor-unseen-badges`, + setSellerBadgeAsSeen: `${SERVER_URL}/dokan/v1/seller-badge/set-badge-as-seen`, + + // new v1 + + // product + getProductBlockDetails: (productId: string) => `${SERVER_URL}/dokan/v1/blocks/products/${productId}`, + getVariableProductBlockDetails: (productId: string) => `${SERVER_URL}/dokan/v1/blocks/product-variation/${productId}`, + + // vendor dashboard + getVendorDashboardStatistics: `${SERVER_URL}/dokan/v1/vendor-dashboard`, + getVendorProfileInformation: `${SERVER_URL}/dokan/v1/vendor-dashboard/profile`, + getVendorSalesReport: `${SERVER_URL}/dokan/v1/vendor-dashboard/sales`, + getVendorProductReportsSummary: `${SERVER_URL}/dokan/v1/vendor-dashboard/products`, + getVendorOrderReportsSummary: `${SERVER_URL}/dokan/v1/vendor-dashboard/orders`, + getVendorStorePreferences: `${SERVER_URL}/dokan/v1/vendor-dashboard/preferences`, + getVendorProfileProgressBarData: `${SERVER_URL}/dokan/v1/vendor-dashboard/profile-progressbar`, + + // vendor staff + getAllVendorStaffs: `${SERVER_URL}/dokan/v1/vendor-staff`, + getSingleVendorStaff: (staffId: string) => `${SERVER_URL}/dokan/v1/vendor-staff/${staffId}`, + createVendorStaff: `${SERVER_URL}/dokan/v1/vendor-staff`, + updateVendorStaff: (staffId: string) => `${SERVER_URL}/dokan/v1/vendor-staff/${staffId}`, + deleteVendorStaff: (staffId: string) => `${SERVER_URL}/dokan/v1/vendor-staff/${staffId}`, + getAllVendorStaffCapabilities: `${SERVER_URL}/dokan/v1/vendor-staff/capabilities`, + getVendorStaffCapabilities: (staffId: string) => `${SERVER_URL}/dokan/v1/vendor-staff/${staffId}/capabilities`, + updateVendorStaffCapabilities: (staffId: string) => `${SERVER_URL}/dokan/v1/vendor-staff/${staffId}/capabilities`, + + // v2 + + // rank math + rankMath: (productId: string) => `${SERVER_URL}/dokan/v2/rank-math/${productId}/store-current-editable-post`, + + // product duplicate + createDuplicateProduct: (productId: string) => `${SERVER_URL}/dokan/v2/products/${productId}/duplicate`, + + getAllProductsV2: `${SERVER_URL}/dokan/v2/products`, + getAllOrdersV2: `${SERVER_URL}/dokan/v2/products`, + + // product filter + getProductsFilterByData: `${SERVER_URL}/dokan/v2/products/filter-by-data`, + + // withdraw + getWithdrawSettings: `${SERVER_URL}/dokan/v2/withdraw/settings`, + getWithdrawSummary: `${SERVER_URL}/dokan/v2/withdraw/summary`, + getWithdrawDisbursementSettings: `${SERVER_URL}/dokan/v2/withdraw/disbursement`, + updateWithdrawDisbursementSettings: `${SERVER_URL}/dokan/v2/withdraw/disbursement`, + disableWithdrawDisbursement: `${SERVER_URL}/dokan/v2/withdraw/disbursement/disable`, + + // orders + // all orders & order notes from v1 also work with v2 + updateBatchOrders: `${SERVER_URL}/dokan/v2/orders/bulk-actions`, + + // order downloads + getAllOrderDownloads: (orderId: string) => `${SERVER_URL}/dokan/v2/orders/${orderId}/downloads`, + createOrderDownload: (orderId: string) => `${SERVER_URL}/dokan/v2/orders/${orderId}/downloads`, + deleteOrderDownload: (orderId: string) => `${SERVER_URL}/dokan/v2/orders/${orderId}/downloads`, + + // settings + getStoreSettings: `${SERVER_URL}/dokan/v2/settings`, + getSingleSettingGroup: (groupId: string) => `${SERVER_URL}/dokan/v2/settings/${groupId}`, + getSubSettingFromSingleSettingGroup: (groupId: string, subGroupId: string) => `${SERVER_URL}/dokan/v2/settings/${groupId}/${subGroupId}`, + getSubSubSettingFromSingleSettingGroup: (groupId: string, subGroupId: string, subSubSettingsId: string) => `${SERVER_URL}/dokan/v2/settings/${groupId}/${subGroupId}/${subSubSettingsId}`, + updateSingleSettingGroup: (groupId: string) => `${SERVER_URL}/dokan/v2/settings/${groupId}`, + updateSubSettingFromSingleSettingGroup: (groupId: string, subGroupId: string) => `${SERVER_URL}/dokan/v2/settings/${groupId}/${subGroupId}`, + updateSubSubSettingFromSingleSettingGroup: (groupId: string, subGroupId: string, subSubSettingsId: string) => `${SERVER_URL}/dokan/v2/settings/${groupId}/${subGroupId}/${subSubSettingsId}`, + + // spmv + getSpmvSettings: `${SERVER_URL}/dokan/v1/spmv-product/settings`, + getSpmvProducts: `${SERVER_URL}/dokan/v1/spmv-product/search`, + addToStore: `${SERVER_URL}/dokan/v1/spmv-product/add-to-store`, // post + + wc: { + // coupons + getAllCoupons: `${SERVER_URL}/wc/v3/coupons`, + getSingleCoupon: (couponId: string) => `${SERVER_URL}/wc/v3/coupons/${couponId}`, + createCoupon: `${SERVER_URL}/wc/v3/coupons`, + updateCoupon: (couponId: string) => `${SERVER_URL}/wc/v3/coupons/${couponId}`, + deleteCoupon: (couponId: string) => `${SERVER_URL}/wc/v3/coupons/${couponId}`, + updateBatchCoupons: `${SERVER_URL}/wc/v3/coupons/batch`, + + // customers + getAllCustomers: `${SERVER_URL}/wc/v3/customers`, + getSingleCustomer: (customerId: string) => `${SERVER_URL}/wc/v3/customers/${customerId}`, + createCustomer: `${SERVER_URL}/wc/v3/customers`, + updateCustomer: (customerId: string) => `${SERVER_URL}/wc/v3/customers/${customerId}`, + deleteCustomer: (customerId: string) => `${SERVER_URL}/wc/v3/customers/${customerId}`, + getCustomerDownloads: (customerId: string) => `${SERVER_URL}/wc/v3/customers/${customerId}/downloads`, + updateBatchCustomers: `${SERVER_URL}/wc/v3/customers/batch`, + + // orders + getAllOrders: `${SERVER_URL}/wc/v3/orders`, + getSingleOrder: (orderId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}`, + createOrder: `${SERVER_URL}/wc/v3/orders`, + updateOrder: (orderId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}`, + deleteOrder: (orderId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}`, + updateBatchOrders: `${SERVER_URL}/wc/v3/orders/batch`, + + // order notes + getAllOrderNotes: (orderId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/notes`, + getSingleOrderNote: (orderId: string, noteId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/notes/${noteId}`, + createOrderNote: (orderId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/notes`, + deleteOrderNote: (orderId: string, noteId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/notes/${noteId}`, + + // refunds + getAllRefunds: (orderId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/refunds`, + getSingleRefund: (orderId: string, refundId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/refunds/${refundId}`, + createRefund: (orderId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/refunds`, + deleteRefund: (orderId: string, refundId: string) => `${SERVER_URL}/wc/v3/orders/${orderId}/refunds/${refundId}`, + + // products + getAllProducts: `${SERVER_URL}/wc/v3/products`, + getSingleProduct: (productId: string) => `${SERVER_URL}/wc/v3/products/${productId}`, + createProduct: `${SERVER_URL}/wc/v3/products`, + updateProduct: (productId: string) => `${SERVER_URL}/wc/v3/products/${productId}`, + deleteProduct: (productId: string) => `${SERVER_URL}/wc/v3/products/${productId}`, + updateBatchProducts: `${SERVER_URL}/wc/v3/products/batch`, + + // product variations + getAllProductVariations: (productId: string) => `${SERVER_URL}/wc/v3/products/${productId}/variations`, + getSingleProductVariation: (productId: string, variationId: string) => `${SERVER_URL}/wc/v3/products/${productId}/variations/${variationId}`, + createProductVariation: (productId: string) => `${SERVER_URL}/wc/v3/products/${productId}/variations`, + updateProductVariation: (productId: string, variationId: string) => `${SERVER_URL}/wc/v3/products/${productId}/variations/${variationId}`, + deleteProductVariation: (productId: string, variationId: string) => `${SERVER_URL}/wc/v3/products/${productId}/variations/${variationId}`, + updateBatchProductVariations: (productId: string) => `${SERVER_URL}/wc/v3/products/${productId}/variations/batch`, + + // product attributes + getAllAttributes: `${SERVER_URL}/wc/v3/products/attributes`, + getSingleAttribute: (attributeId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}`, + createAttribute: `${SERVER_URL}/wc/v3/products/attributes`, + updateAttribute: (attributeId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}`, + deleteAttribute: (attributeId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}`, + updateBatchAttributes: `${SERVER_URL}/wc/v3/products/attributes/batch`, + + // product attribute terms + getAllAttributeTerms: (attributeId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}/terms`, + getSingleAttributeTerm: (attributeId: string, attributeTermId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}/terms/${attributeTermId}`, + createAttributeTerm: (attributeId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}/terms`, + updateAttributeTerm: (attributeId: string, attributeTermId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}/terms/${attributeTermId}`, + deleteAttributeTerm: (attributeId: string, attributeTermId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}/terms/${attributeTermId}`, + updateBatchAttributeTerms: (attributeId: string) => `${SERVER_URL}/wc/v3/products/attributes/${attributeId}/terms/batch`, + + // product categories + getAllCategories: `${SERVER_URL}/wc/v3/products/categories`, + getSingleCategory: (categoryId: string) => `${SERVER_URL}/wc/v3/products/categories/${categoryId}`, + createCategory: `${SERVER_URL}/wc/v3/products/categories`, + updateCategory: (categoryId: string) => `${SERVER_URL}/wc/v3/products/categories/${categoryId}`, + deleteCategory: (categoryId: string) => `${SERVER_URL}/wc/v3/products/categories/${categoryId}`, + updateBatchCategories: `${SERVER_URL}/wc/v3/products/categories/batch`, + + // product shipping class + getAllShippingClasses: `${SERVER_URL}/wc/v3/products/shipping_classes`, + getSingleShippingClass: (shippingClassId: string) => `${SERVER_URL}/wc/v3/products/shipping_classes/${shippingClassId}`, + createShippingClass: `${SERVER_URL}/wc/v3/products/shipping_classes`, + updateShippingClass: (shippingClassId: string) => `${SERVER_URL}/wc/v3/products/shipping_classes/${shippingClassId}`, + deleteShippingClass: (shippingClassId: string) => `${SERVER_URL}/wc/v3/products/shipping_classes/${shippingClassId}`, + updateBatchShippingClass: `${SERVER_URL}/wc/v3/products/shipping_classes/batch`, + + // product tags + getAllTags: `${SERVER_URL}/wc/v3/products/tags`, + getSingleTag: (tagId: string) => `${SERVER_URL}/wc/v3/products/tags/${tagId}`, + createTag: `${SERVER_URL}/wc/v3/products/tags`, + updateTag: (tagId: string) => `${SERVER_URL}/wc/v3/products/tags/${tagId}`, + deleteTag: (tagId: string) => `${SERVER_URL}/wc/v3/products/tags/${tagId}`, + updateBatchTag: `${SERVER_URL}/wc/v3/products/tags/batch`, + + // product reviews + getAllReviews: `${SERVER_URL}/wc/v3/products/reviews`, + getSingleReview: (reviewId: string) => `${SERVER_URL}/wc/v3/products/reviews/${reviewId}`, + createReview: `${SERVER_URL}/wc/v3/products/reviews`, + updateReview: (reviewId: string) => `${SERVER_URL}/wc/v3/products/reviews/${reviewId}`, + deleteReview: (reviewId: string) => `${SERVER_URL}/wc/v3/products/reviews/${reviewId}`, + updateBatchReview: `${SERVER_URL}/wc/v3/products/reviews/batch`, + + // reports + getAllReports: `${SERVER_URL}/wc/v3/reports`, + getSalesReport: `${SERVER_URL}/wc/v3/reports/sales`, + getTopSellersReport: `${SERVER_URL}/wc/v3/reports/top_sellers`, + getCouponsTotalsReport: `${SERVER_URL}/wc/v3/reports/coupons/totals`, + getCustomersTotalsReport: `${SERVER_URL}/wc/v3/reports/customers/totals`, + getOrdersTotalsReport: `${SERVER_URL}/wc/v3/reports/orders/totals`, + getProductsTotalsReport: `${SERVER_URL}/wc/v3/reports/products/totals`, + getReviewsTotalsReport: `${SERVER_URL}/wc/v3/reports/reviews/totals`, + + // tax rates + getAllTaxRates: `${SERVER_URL}/wc/v3/taxes`, + getSingleTaxRate: (taxId: string) => `${SERVER_URL}/wc/v3/taxes/${taxId}`, + createTaxRate: `${SERVER_URL}/wc/v3/taxes`, + updateTaxRate: (taxId: string) => `${SERVER_URL}/wc/v3/taxes/${taxId}`, + deleteTaxRate: (taxId: string) => `${SERVER_URL}/wc/v3/taxes/${taxId}`, + updateBatchTaxRates: `${SERVER_URL}/wc/v3/taxes/batch`, + + // tax classes + getAllTaxClasses: `${SERVER_URL}/wc/v3/taxes/classes`, + createTaxClass: `${SERVER_URL}/wc/v3/taxes/classes`, + deleteTaxClass: (slug: string) => `${SERVER_URL}/wc/v3/taxes/classes/${slug}`, + + // shipping zones + getAllShippingZones: `${SERVER_URL}/wc/v3/shipping/zones`, + getSingleShippingZone: (zoneId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}`, + createShippingZone: `${SERVER_URL}/wc/v3/shipping/zones`, + updateShippingZone: (zoneId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}`, + deleteShippingZone: (zoneId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}`, + // shipping zone locations + getAllShippingZoneLocations: (zoneId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}/locations`, + addShippingZoneLocation: (zoneId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}/locations`, + // shipping zone methods + getAllShippingZoneMethods: (zoneId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}/methods`, + getSingleShippingZoneMethod: (zoneId: string, methodId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}/methods/${methodId}`, + addShippingZoneMethod: (zoneId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}/methods`, + updateShippingZoneMethod: (zoneId: string, methodId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}/methods/${methodId}`, + deleteShippingZoneMethod: (zoneId: string, methodId: string) => `${SERVER_URL}/wc/v3/shipping/zones/${zoneId}/methods/${methodId}`, + // shipping methods + getAllShippingMethods: `${SERVER_URL}/wc/v3/shipping_methods`, + getSingleShippingMethod: (shippingId: string) => `${SERVER_URL}/wc/v3/shipping_methods/${shippingId}`, + + // payment gateways + getAllPaymentGateways: `${SERVER_URL}/wc/v3/payment_gateways`, + getSinglePaymentGateway: (paymentGatewayId: string) => `${SERVER_URL}/wc/v3/payment_gateways/${paymentGatewayId}`, + updatePaymentGateway: (paymentGatewayId: string) => `${SERVER_URL}/wc/v3/payment_gateways/${paymentGatewayId}`, + + // settings + getAllSettingsGroups: `${SERVER_URL}/wc/v3/settings`, + getAllSettingOptions: (groupId: string) => `${SERVER_URL}/wc/v3/settings/${groupId}`, + getSingleSettingOption: (groupId: string, optionId: string) => `${SERVER_URL}/wc/v3/settings/${groupId}/${optionId}`, + updateSettingOption: (groupId: string, optionId: string) => `${SERVER_URL}/wc/v3/settings/${groupId}/${optionId}`, + updateBatchSettingOptions: (groupId: string) => `${SERVER_URL}/wc/v3/settings/${groupId}/batch`, + + // system status + getAllSystemStatus: `${SERVER_URL}/wc/v3/system_status`, + + // data + getCurrentCurrency: `${SERVER_URL}/wc/v3/data/currencies/current`, + + booking: { + getAllBookableProducts: `${SERVER_URL}/wc-bookings/v1/products`, + getSingleBookableProduct: (productId: string) => `${SERVER_URL}/wc-bookings/v1/products/${productId}`, + createBookableProduct: `${SERVER_URL}/wc-bookings/v1/products`, + updateBookableProduct: (productId: string) => `${SERVER_URL}/wc-bookings/v1/products/${productId}`, + deleteBookableProduct: (productId: string) => `${SERVER_URL}/wc-bookings/v1/products/${productId}`, + updateBatchBookableProducts: `${SERVER_URL}/wc-bookings/v1/products/batch`, + getBookingsSlots: `${SERVER_URL}/wc-bookings/v1/products/slots`, + + // categories + getAllBookableProductCategories: `${SERVER_URL}/wc-bookings/v1/products/categories`, + getSingleBookableProductCategory: (categoryId: string) => `${SERVER_URL}/wc-bookings/v1/products/categories/${categoryId}`, + createBookableProductCategory: `${SERVER_URL}/wc-bookings/v1/products/categories`, + updateBookableProductCategory: (categoryId: string) => `${SERVER_URL}/wc-bookings/v1/products/categories/${categoryId}`, + deleteBookableProductCategory: (categoryId: string) => `${SERVER_URL}/wc-bookings/v1/products/categories/${categoryId}`, + updateBatchBookableProductsCategories: `${SERVER_URL}/wc-bookings/v1/products/categories/batch`, + + // resource + getAllBookableResources: `${SERVER_URL}/wc-bookings/v1/resources`, + getSingleBookableResource: (productId: string) => `${SERVER_URL}/wc-bookings/v1/resources/${productId}`, + createBookableResource: `${SERVER_URL}/wc-bookings/v1/resources`, + updateBookableResource: (productId: string) => `${SERVER_URL}/wc-bookings/v1/resources/${productId}`, + deleteBookableResource: (productId: string) => `${SERVER_URL}/wc-bookings/v1/resources/${productId}`, + updateBatchBookableResources: `${SERVER_URL}/wc-bookings/v1/resources/batch`, + + // bookings + getAllBookings: `${SERVER_URL}/wc-bookings/v1/bookings`, + getSingleBooking: (productId: string) => `${SERVER_URL}/wc-bookings/v1/bookings/${productId}`, + createBooking: `${SERVER_URL}/wc-bookings/v1/bookings`, + updateBooking: (productId: string) => `${SERVER_URL}/wc-bookings/v1/bookings/${productId}`, + deleteBooking: (productId: string) => `${SERVER_URL}/wc-bookings/v1/bookings/${productId}`, + updateBatchBookings: `${SERVER_URL}/wc-bookings/v1/bookings/batch`, + }, + + productAddons: { + getAllProductAddons: `${SERVER_URL}/wc-product-add-ons/v1/product-add-ons`, + getSingleProductAddon: (productId: string) => `${SERVER_URL}/wc-product-add-ons/v1/product-add-ons${productId}`, + createProductAddon: `${SERVER_URL}/wc-product-add-ons/v1/product-add-ons`, + updateProductAddon: (productId: string) => `${SERVER_URL}/wc-product-add-ons/v1/product-add-ons${productId}`, + deleteProductAddon: (productId: string) => `${SERVER_URL}/wc-product-add-ons/v1/product-add-ons${productId}`, + }, + }, + + wp: { + // todo : add all wp endpoints + // users + getAllUsers: `${SERVER_URL}/wp/v2/users`, + getCurrentUser: `${SERVER_URL}/wp/v2/users/me`, + getUserById: (userId: string) => `${SERVER_URL}/wp/v2/users/${userId}`, + createUser: `${SERVER_URL}/wp/v2/users`, + updateUser: (userId: string) => `${SERVER_URL}/wp/v2/users/${userId}`, + deleteUser: (userId: string) => `${SERVER_URL}/wp/v2/users/${userId}`, + + // plugins + getAllPlugins: `${SERVER_URL}/wp/v2/plugins`, + getSinglePlugin: (plugin: string) => `${SERVER_URL}/wp/v2/plugins/${plugin}`, + updatePlugin: (plugin: string) => `${SERVER_URL}/wp/v2/plugins/${plugin}`, + deletePlugin: (plugin: string) => `${SERVER_URL}/wp/v2/plugins/${plugin}`, + + // pages + getAllPages: `${SERVER_URL}/wp/v2/pages`, + getSinglePage: (pageId: string) => `${SERVER_URL}/wp/v2/pages/${pageId}`, + createPage: `${SERVER_URL}/wp/v2/pages`, + updatePage: (pageId: string) => `${SERVER_URL}/wp/v2/pages/${pageId}`, + deletePage: (pageId: string) => `${SERVER_URL}/wp/v2/pages/${pageId}`, + + // media + getAllMediaItems: `${SERVER_URL}/wp/v2/media`, + getSingleMediaItem: (mediaId: string) => `${SERVER_URL}/wp/v2/media/${mediaId}`, + createMediaItem: `${SERVER_URL}/wp/v2/media`, + updateMediaItem: (mediaId: string) => `${SERVER_URL}/wp/v2/media/${mediaId}`, + deleteMediaItem: (mediaId: string) => `${SERVER_URL}/wp/v2/media/${mediaId}`, + + // settings + getSiteSettings: `${SERVER_URL}/wp/v2/settings`, + setSiteSettings: `${SERVER_URL}/wp/v2/settings`, + + // posts + getAllPosts: `${SERVER_URL}/wp/v2/posts`, + getSinglePost: (postId: string) => `${SERVER_URL}/wp/v2/posts/${postId}`, + createPost: `${SERVER_URL}/wp/v2/pots/posts`, + createCustomPost: (postType: string) => `${SERVER_URL}/wp/v2/${postType}`, + updatePost: (postId: string) => `${SERVER_URL}/wp/v2/posts/${postId}`, + deletePost: (postId: string) => `${SERVER_URL}/wp/v2/posts/${postId}`, + }, +}; diff --git a/tests/pw/utils/apiUtils.ts b/tests/pw/utils/apiUtils.ts new file mode 100644 index 0000000000..7b58e996f2 --- /dev/null +++ b/tests/pw/utils/apiUtils.ts @@ -0,0 +1,1615 @@ +import { expect, type APIRequestContext, APIResponse, Request } from '@playwright/test'; +import { endPoints } from '@utils/apiEndPoints'; +import { payloads } from '@utils/payloads'; +import { helpers } from '@utils/helpers'; +import fs from 'fs'; +import { auth, user_api, taxRate, coupon_api, marketPlaceCoupon, reqOptions, headers, storageState, responseBody } from '@utils/interfaces'; + +const { VENDOR_ID, CUSTOMER_ID } = process.env; + +export class ApiUtils { + readonly request: APIRequestContext; + + constructor(request: APIRequestContext) { + this.request = request; + } + + /** + * Authentication methods + */ + + // get basic auth + getBasicAuth(user: user_api): string { + const basicAuth = 'Basic ' + Buffer.from(user.username + ':' + user.password).toString('base64'); + return basicAuth; + } + + /** + * request methods + */ + + // get request + async get(url: string, options?: reqOptions | undefined, ...args: any[]): Promise<[APIResponse, responseBody]> { + const assert = args.length ? Boolean(args[0]) : true; + const response = await this.request.get(url, options); + const responseBody = await this.getResponseBody(response, assert); + return [response, responseBody]; + } + + // post request + async post(url: string, options?: reqOptions | undefined, ...args: any[]): Promise<[APIResponse, responseBody]> { + const assert = args.length ? Boolean(args[0]) : true; + const response = await this.request.post(url, options); + const responseBody = await this.getResponseBody(response, assert); + return [response, responseBody]; + } + + // put request + async put(url: string, options?: reqOptions | undefined, ...args: any[]): Promise<[APIResponse, responseBody]> { + const assert = args.length ? Boolean(args[0]) : true; + const response = await this.request.put(url, options); + const responseBody = await this.getResponseBody(response, assert); + return [response, responseBody]; + } + + // patch request + async patch(url: string, options?: reqOptions | undefined, ...args: any[]): Promise<[APIResponse, responseBody]> { + const assert = args.length ? Boolean(args[0]) : true; + const response = await this.request.patch(url, options); + const responseBody = await this.getResponseBody(response, assert); + return [response, responseBody]; + } + + // delete request + async delete(url: string, options?: reqOptions | undefined, ...args: any[]): Promise<[APIResponse, responseBody]> { + const assert = args.length ? Boolean(args[0]) : true; + const response = await this.request.delete(url, options); + const responseBody = await this.getResponseBody(response, assert); + return [response, responseBody]; + } + + // fetch request + async fetch(urlOrRequest: string | Request, options?: reqOptions | undefined, ...args: any[]): Promise<[APIResponse, responseBody]> { + const assert = args.length ? Boolean(args[0]) : true; + const response = await this.request.fetch(urlOrRequest, options); + const responseBody = await this.getResponseBody(response, assert); + return [response, responseBody]; + } + + // head request + async head(url: string, options?: reqOptions | undefined): Promise { + const response = await this.request.head(url, options); + return response; + } + + // get storageState + async storageState(path?: string | undefined): Promise { + return await this.request.storageState({ path: path }); + } + + // dispose api context + async disposeApiRequestContext(): Promise { + await this.request.dispose(); + } + + // get responseBody + async getResponseBody(response: APIResponse, assert = true): Promise { + try { + assert && expect(response.ok()).toBeTruthy(); + const responseBody = response.status() !== 204 && (await response.json()); // 204 is for No Content + + // console log responseBody if response code is not between 200-299 + String(response.status())[0] != '2' && console.log('ResponseBody: ', responseBody); + return responseBody; + } catch (err: any) { + console.log('End-point: ', response.url()); + console.log('Status Code: ', response.status()); + console.log('Response text: ', await response.text()); + console.log('Error: ', err.message); // todo: showing playwright error message instead of api error message + } + } + + // get site headers + async getSiteHeaders(url: string): Promise { + const response = await this.head(url); + const headers = response.headers(); + return headers; + } + + /** + * dokan api utility methods + */ + + /** + * dummy data api methods + */ + + // import dummy data + async importDummyData(payload: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.importDummyData, { data: payload, headers: auth }); + return responseBody; + } + + // clear dummy data + async clearDummyData(auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.clearDummyData, { headers: auth }); + return responseBody; + } + + /** + * store api methods + */ + + // get all stores + async getAllStores(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllStores, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get single store + async getSingleStore(sellerId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getSingleStore(sellerId), { headers: auth }); + return responseBody; + } + + // get sellerId + async getSellerId(storeName?: string, auth?: auth): Promise { + // todo: apply multiple optional parameter + if (arguments.length === 1 && typeof storeName === 'object') { + auth = storeName as auth; + storeName = undefined; + } + + const allStores = await this.getAllStores(auth); + const sellerId = storeName ? allStores.find((o: { store_name: string }) => o.store_name.toLowerCase() === storeName!.toLowerCase())?.id : allStores[0]?.id; + return sellerId; + } + + // create store + async createStore(payload: any, auth?: auth): Promise<[responseBody, string, string]> { + const [response, responseBody] = await this.post(endPoints.createStore, { data: payload, headers: auth }, false); + let sellerId: string; + let storeName: string; + if (responseBody.code) { + expect(response.status()).toBe(500); + + // get store id if already exists + sellerId = await this.getSellerId(payload.store_name, auth); + storeName = payload.store_name; + + // update store if already exists + await this.updateStore(sellerId, payload, auth); + } else { + expect(response.ok()).toBeTruthy(); + sellerId = String(responseBody?.id); + storeName = String(responseBody?.store_name); + } + return [responseBody, sellerId, storeName]; + } + + // update store + async updateStore(storeId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.updateStore(storeId), { data: payload, headers: auth }); + return responseBody; + } + + // create store review + async createStoreReview(sellerId: string, payload: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.createStoreReview(sellerId), { data: payload, headers: auth }); + const reviewId = String(responseBody?.id); + return [responseBody, reviewId]; + } + + /** + * follow store methods + */ + + // follow unfollow store + async followUnfollowStore(sellerId: string, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.followUnfollowStore, { data: { vendor_id: Number(sellerId) }, headers: auth }); + return responseBody; + } + + /** + * product api methods + */ + + // get all products + async getAllProducts(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllProducts, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get productId + async getProductId(productName: string, auth?: auth): Promise { + // todo: apply multiple optional parameter + const allProducts = await this.getAllProducts(auth); + const productId = productName ? allProducts.find((o: { name: string }) => o.name.toLowerCase() === productName.toLowerCase())?.id : allProducts[0]?.id; + return productId; + } + + // create product + async createProduct(payload: object, auth?: auth): Promise<[responseBody, string, string]> { + const [, responseBody] = await this.post(endPoints.createProduct, { data: payload, headers: auth }); + const productId = String(responseBody?.id); + const productName = String(responseBody?.name); + return [responseBody, productId, productName]; + } + + // delete product + async deleteProduct(productId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.deleteProduct(productId), { headers: auth }); + return responseBody; + } + + // delete all products + async deleteAllProducts(productName: string, auth?: auth): Promise { + // todo: apply multiple optional parameter + const allProducts = await this.getAllProducts(auth); + if (!allProducts?.length) { + console.log('No product exists'); + return; + } + + let allProductIds: string[]; + if (productName) { + // get all product ids with same name + allProductIds = allProducts.filter((o: { name: unknown }) => o.name === productName).map((o: { id: unknown }) => o.id); + } else { + // get all product ids + allProductIds = allProducts.map((o: { id: unknown }) => o.id); + } + const [, responseBody] = await this.put(endPoints.wc.updateBatchProducts, { data: { delete: allProductIds }, headers: payloads.adminAuth }); + return responseBody; + } + + // get product exists or not + async checkProductExistence(productName: string, auth?: auth): Promise { + const allProducts = await this.getAllProducts(auth); + const res = allProducts.find((o: { name: string }) => o.name.toLowerCase() === productName.toLowerCase())?.id ?? false; + return res; + } + + /** + * product variation api methods + */ + + // get variationIds + async getVariationIds(productId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllProductVariations(productId), { headers: auth }); + const variationIds = responseBody.map((o: { id: unknown }) => o.id); + console.log(variationIds); + return variationIds; + } + + // create product variation + async createProductVariation(productId: string, payload: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.createProductVariation(productId), { data: payload, headers: auth }); + const variationId = String(responseBody?.id); + return [responseBody, variationId]; + } + + // get variationId + async createVariableProductWithVariation(attribute: object, attributeTerm: object, product: any, auth?: auth): Promise<[string, string]> { + const [, productId] = await this.createProduct(product, auth); + const [body, attributeId] = await this.createAttributeTerm(attribute, attributeTerm, auth); + const payload = { ...product, attributes: [{ id: attributeId, visible: true, variation: true, option: body.name }] }; // todo: need to fix + const [, variationId] = await this.createProductVariation(productId, payload, auth); + return [productId, variationId]; + } + + /** + * attribute api methods + */ + + // get all attributes + async getAllAttributes(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllAttributes, { headers: auth }); + return responseBody; + } + + // get single attribute + async getSingleAttribute(attributeId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getSingleAttribute(attributeId), { headers: auth }); + return responseBody; + } + + // get attributeId + async getAttributeId(auth?: auth): Promise { + const allAttributes = await this.getAllAttributes(auth); + const attributeId = allAttributes[0]?.id; + return attributeId; + } + + // create attribute + async createAttribute(payload: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.createAttribute, { data: payload, headers: auth }); + const attributeId = String(responseBody?.id); + return [responseBody, attributeId]; + } + + // update batch attributes + async updateBatchAttributes(action: string, allIds: string[], auth?: auth): Promise<[APIResponse, responseBody]> { + if (!allIds?.length) { + allIds = (await this.getAllAttributes(auth)).map((a: { id: unknown }) => a.id); + } + const [response, responseBody] = await this.post(endPoints.wc.updateBatchAttributes, { data: { [action]: allIds }, headers: auth }); + return [response, responseBody]; + } + + /** + * attribute term api methods + */ + + // get all attribute terms + async getAllAttributeTerms(attributeId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllAttributeTerms(attributeId), { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get single attribute term + async getSingleAttributeTerm(attributeId: string, attributeTermId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getSingleAttributeTerm(attributeId, attributeTermId), { headers: auth }); + return responseBody; + } + + // create attribute term + async createAttributeTerm(attribute: any, attributeTerm: object, auth?: auth): Promise<[responseBody, string, string]> { + let attributeId: string; + typeof attribute === 'object' ? ([, attributeId] = await this.createAttribute(attribute, auth)) : (attributeId = attribute); + const [, responseBody] = await this.post(endPoints.createAttributeTerm(attributeId), { data: attributeTerm, headers: auth }); + const attributeTermId = String(responseBody?.id); + return [responseBody, attributeId, attributeTermId]; + } + + /** + * coupon api methods + */ + + // get all coupons + async getAllCoupons(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllCoupons, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get couponId + async getCouponId(couponCode: string, auth?: auth): Promise { + // todo: apply multiple optional parameter + const allCoupons = await this.getAllCoupons(auth); + const couponId = couponCode ? allCoupons.find((o: { code: string }) => o.code.toLowerCase() === couponCode.toLowerCase())?.id : allCoupons[0]?.id; + return couponId; + } + + // create coupon + async createCoupon(productIds: string[], coupon: coupon_api, auth?: auth): Promise<[responseBody, string, string]> { + // create product if invalid productId exists + if (productIds.includes('undefined')) { + const [, productId] = await this.createProduct(payloads.createProduct(), auth); + productIds = [productId]; + } + const [response, responseBody] = await this.post(endPoints.createCoupon, { data: { ...coupon, product_ids: productIds }, headers: auth }, false); + let couponId: string; + let couponCode: string; + if (responseBody.code === 'woocommerce_rest_coupon_code_already_exists') { + expect(response.status()).toBe(400); + + // get coupon id if already exists + couponId = await this.getCouponId(coupon.code, auth); + couponCode = coupon.code; + + // update coupon if already exists + await this.updateCoupon(couponId, { ...coupon, product_ids: productIds }, auth); + } else { + expect(response.ok()).toBeTruthy(); + couponId = String(responseBody?.id); + couponCode = String(responseBody?.code); + } + return [responseBody, couponId, couponCode]; + } + + // update coupon + async updateCoupon(couponId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.updateCoupon(couponId), { data: payload, headers: auth }); + return responseBody; + } + + // get marketplace couponId + async getMarketPlaceCouponId(couponCode: string, auth?: auth): Promise { + // todo: apply multiple optional parameter + const [, allCoupons] = await this.get(endPoints.wc.getAllCoupons, { params: { per_page: 100 }, headers: auth }); + const couponId = couponCode ? allCoupons.find((o: { code: string }) => o.code.toLowerCase() === couponCode.toLowerCase())?.id : allCoupons[0]?.id; + return couponId; + } + + // create marketplace coupon + async createMarketPlaceCoupon(coupon: marketPlaceCoupon, auth?: auth): Promise<[responseBody, string, string]> { + const [response, responseBody] = await this.post(endPoints.wc.createCoupon, { data: coupon, headers: auth }, false); + let couponId: string; + let couponCode: string; + if (responseBody.code === 'woocommerce_rest_coupon_code_already_exists') { + expect(response.status()).toBe(400); + // get coupon id if already exists + couponId = await this.getMarketPlaceCouponId(coupon.code, auth); + couponCode = coupon.code; + + // update coupon if already exists + await this.updateCoupon(couponId, coupon, auth); + } else { + expect(response.ok()).toBeTruthy(); + couponId = String(responseBody?.id); + couponCode = String(responseBody?.code); + } + return [responseBody, couponId, couponCode]; + } + + // update marketplace coupon + async updateMarketPlaceCoupon(couponId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.wc.updateCoupon(couponId), { data: payload, headers: auth }); + return responseBody; + } + + /** + * withdraw api methods + */ + + // get balance and minimum withdraw limit + async getMinimumWithdrawLimit(auth?: auth): Promise<[string, string]> { + const [, responseBody] = await this.get(endPoints.getBalanceDetails, { headers: auth }); + const currentBalance = String(Math.abs(responseBody.current_balance)); + const minimumWithdrawLimit = String(Math.abs(responseBody.withdraw_limit)); + return [currentBalance, minimumWithdrawLimit]; + } + + // get all withdraws + async getAllWithdraws(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllWithdraws, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get all withdraws by status + async getAllWithdrawsByStatus(status: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllWithdraws, { params: { per_page: 100, status: status }, headers: auth }); + return responseBody; + } + + // get withdrawId + async getWithdrawId(auth?: auth): Promise { + const allWithdraws = await this.getAllWithdrawsByStatus('pending', auth); + const withdrawId = allWithdraws[0]?.id; + return withdrawId; + } + + // create withdraw + async createWithdraw(payload: object, auth?: auth): Promise<[responseBody, string]> { + const [response, responseBody] = await this.post(endPoints.createWithdraw, { data: payload, headers: auth }, false); + let withdrawId: string; + if (responseBody.code) { + expect(response.status()).toBe(400); + + // get withdraw id if already exists + withdrawId = await this.getWithdrawId(auth); + } else { + expect(response.ok()).toBeTruthy(); + withdrawId = String(responseBody?.id); + } + return [responseBody, withdrawId]; + } + + // cancel withdraw + async cancelWithdraw(withdrawId: string, auth?: auth): Promise { + if (!withdrawId) { + withdrawId = await this.getWithdrawId(auth); + if (!withdrawId) { + console.log('No withdraw id exists'); + return; + } + } + const [, responseBody] = await this.delete(endPoints.cancelWithdraw(withdrawId), { headers: payloads.adminAuth }); + return responseBody; + } + + /** + * order api methods + */ + + // get all orders + async getAllOrders(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllOrders, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get single order + async getSingleOrder(orderId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getSingleOrder(orderId), { headers: auth }); + return responseBody; + } + + // get orderId + async getOrderId(auth?: auth): Promise { + const allOrders = await this.getAllOrders(auth); + const orderId = allOrders[0]?.id; + return orderId; + } + + // update order status + async updateOrderStatus(orderId: string, orderStatus: string, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.updateOrder(orderId), { data: { status: orderStatus }, headers: auth }); + return responseBody; + } + + // get order key + async getOrderKey(orderId: string): Promise { + const [, responseBody] = await this.getSingleOrder(orderId, payloads.adminAuth); + const orderKey = responseBody?.order_key; + return orderKey; + } + + /** + * order notes api methods + */ + + // create order note + async createOrderNote(product: string | object, order: object | string, orderNote: object, auth?: auth): Promise<[responseBody, string, string]> { + let orderId: string; + typeof order === 'object' ? ([, , orderId] = await this.createOrder(product, order, auth)) : (orderId = order); + const [, responseBody] = await this.post(endPoints.createOrderNote(orderId), { data: orderNote, headers: auth }); + const orderNoteId = String(responseBody?.id); + return [responseBody, orderId, orderNoteId]; + } + + /** + * admin api methods + */ + + // get admin report summary + async getAdminReportSummary(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAdminReportSummary, { headers: auth }); + return responseBody; + } + + // get all order logs + async getAllOrderLogs(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAdminLogs, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get single order log + async getSingleOrderLog(orderId: string, auth?: auth) { + const allOrderLogs = await this.getAllOrderLogs(auth); + const singleOrderLog = allOrderLogs.find((o: { order_id: string }) => o.order_id.toLowerCase() === orderId.toLowerCase()); + return singleOrderLog; + } + + /** + * refund api methods + */ + + // get all refunds + async getAllRefunds(status: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllRefunds, { params: { per_page: 100, status: status }, headers: auth }); + return responseBody; + } + + // get refundId + async getRefundId(status: string, auth?: auth): Promise { + const allRefunds = await this.getAllRefunds(status, auth); + const refundId = allRefunds[0]?.id; + return refundId; + } + + /** + * dokan settings api methods + */ + + // get store settings + async getStoreSettings(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getSettings, { headers: auth }); + return responseBody; + } + + // set store settings + async setStoreSettings(payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.updateSettings, { data: payload, headers: auth }); + return responseBody; + } + + /** + * support ticket api methods + */ + + // get all support tickets + async getAllSupportTickets(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllSupportTickets, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get support ticket Id + async getSupportTicketId(auth?: auth): Promise<[string, string]> { + const allSupportTickets = await this.getAllSupportTickets(auth); + const supportTicketId = allSupportTickets[0]?.id; + const sellerId = allSupportTickets[0]?.vendor_id; + return [supportTicketId, sellerId]; + } + + // create support ticket + async createSupportTicket(payload: object): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.wp.createCustomPost('dokan_store_support'), { data: payload, headers: payloads.adminAuth }); + const supportTicketId = String(responseBody?.id); + return [responseBody, supportTicketId]; + } + + // create support ticket comment + async createSupportTicketComment(supportTicketId: string, payload: object, auth?: auth): Promise { + if (!supportTicketId) { + [supportTicketId] = await this.createSupportTicket({ ...payloads.createSupportTicket, author: CUSTOMER_ID, store_id: VENDOR_ID }); + } + const [, responseBody] = await this.post(endPoints.createSupportTicketComment(supportTicketId), { data: payload, headers: auth }); + return responseBody; + } + + // update support ticket status + async updateSupportTicketStatus(supportTicketId: string, status: string, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.updateSupportTicketStatus(supportTicketId), { data: { status }, headers: auth }); + return responseBody; + } + + // update support ticket email notification + async updateSupportTicketEmailNotification(supportTicketId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.updateSupportTicketEmailNotification(supportTicketId), { data: payload, headers: auth }); + return responseBody; + } + + /** + * reverse withdrawal api methods + */ + + // get all reverse withdrawal stores + async getAllReverseWithdrawalStores(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllReverseWithdrawalStores, { headers: auth }); + return responseBody; + } + + // get reverse withdrawal storeId + async getReverseWithdrawalStoreId(auth?: auth): Promise { + const allReverseWithdrawalStores = await this.getAllReverseWithdrawalStores(auth); + const reverseWithdrawalStoreId = allReverseWithdrawalStores[0]?.id; + return reverseWithdrawalStoreId; + } + + // get reverseWithdrawal payment productId + async getReverseWithdrawalProductId(auth?: auth): Promise { + const productId = await this.getProductId('Reverse Withdrawal Payment', auth); + return productId; + } + + /** + * module api methods + */ + + // get all modules + async getAllModules(params = {}, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllModules, { params: params, headers: auth }); + return responseBody; + } + + // get all moduleIds + async getAllModuleIds(params = {}, auth?: auth): Promise { + const allModules = await this.getAllModules(params, auth); + const allModuleIds = allModules.map((o: { id: unknown }) => o.id); + return allModuleIds; + } + + // get activate modules + async activateModules(moduleIds: string, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.activateModule, { data: { module: [moduleIds] }, headers: auth }); + return responseBody; + } + + // get deactivated modules + async deactivateModules(moduleIds: string, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.deactivateModule, { data: { module: [moduleIds] }, headers: auth }); + return responseBody; + } + + /** + * customers api methods [woocommerce endpoint used instead of request-for-quote/customer ] + */ + + // get all customers + async getAllCustomers(auth?: auth): Promise { + const [, responseBody1] = await this.get(endPoints.wc.getAllCustomers, { params: { per_page: 100 }, headers: auth }); + const [, responseBody2] = await this.get(endPoints.wc.getAllCustomers, { params: { per_page: 100, role: 'subscriber' }, headers: auth }); // todo: those customers who is currently subscriber: remove after dokan fix + const responseBody = [...responseBody1, ...responseBody2]; + return responseBody; + } + + // get customerId + async getCustomerId(username: string, auth?: auth): Promise { + // todo: apply multiple optional parameter + const allCustomers = await this.getAllCustomers(auth); + const customerId = username ? allCustomers.find((o: { username: string }) => o.username.toLowerCase() === username.toLowerCase())?.id : allCustomers[0]?.id; + return customerId; + } + + // create customer + async createCustomer(payload: any, auth?: auth): Promise<[responseBody, string]> { + const [response, responseBody] = await this.post(endPoints.wc.createCustomer, { data: payload, headers: auth }, false); + let customerId: string; + if (responseBody.code) { + expect(response.status()).toBe(400); + + // get customer id if already exists + customerId = await this.getCustomerId(payload.username, auth); + + // update customer if already exists + await this.updateCustomer(customerId, payload, auth); + } else { + expect(response.ok()).toBeTruthy(); + customerId = String(responseBody?.id); + } + return [responseBody, customerId]; + } + + // update customer + async updateCustomer(customerId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.wc.updateCustomer(customerId), { data: payload, headers: auth }); + return responseBody; + } + + // delete customer + async deleteCustomer(userId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.wc.deleteCustomer(userId), { headers: auth }); + return responseBody; + } + + /** + * wholesale customers api methods + */ + + // get all wholesale customers + async getAllWholesaleCustomers(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllWholesaleCustomers, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // create a wholesale customer + async createWholesaleCustomer(payload: string | object, auth?: auth): Promise<[responseBody, string]> { + let customerId: string; + typeof payload === 'object' ? ([, customerId] = await this.createCustomer(payload, auth)) : (customerId = payload); + const [, responseBody] = await this.post(endPoints.createWholesaleCustomer, { data: { id: String(customerId) }, headers: auth }); + return [responseBody, customerId]; + } + + /** + * product advertisement api methods + */ + + // get all product advertisements + async getAllProductAdvertisements(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllProductAdvertisements, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // create a product advertisement + async createProductAdvertisement(product: object, auth?: auth): Promise<[responseBody, string]> { + const [body, productId] = await this.createProduct(product, auth); + const sellerId = body.store.id; + const [, responseBody] = await this.post(endPoints.createProductAdvertisement, { data: { vendor_id: sellerId, product_id: productId }, headers: payloads.adminAuth }); + const productAdvertisementId = String(responseBody?.id); + return [responseBody, productAdvertisementId]; + } + + /** + * abuse report api methods + */ + + // get all abuse reports + async getAllAbuseReports(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllAbuseReports, { headers: auth }); + return responseBody; + } + + // get abuse report Id + async getAbuseReportId(auth?: auth): Promise { + const allAbuseReports = await this.getAllAbuseReports(auth); + const abuseReportId = allAbuseReports[0]?.id; + return abuseReportId; + } + + /** + * announcements api methods + */ + + // get all announcements + async getAllAnnouncements(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllAnnouncements, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // create announcement + async createAnnouncement(payload: object, auth?: auth): Promise<[responseBody, string, string]> { + const [, responseBody] = await this.post(endPoints.createAnnouncement, { data: payload, headers: auth }); + const announcementId = String(responseBody?.id); + const announcementTitle = String(responseBody?.title); + return [responseBody, announcementId, announcementTitle]; + } + + // delete announcement + async deleteAnnouncement(announcementId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.deleteAnnouncement(announcementId), { headers: auth }); + return responseBody; + } + + // update batch announcements + async updateBatchAnnouncements(action: string, allIds: string[], auth?: auth): Promise { + if (!allIds?.length) { + allIds = (await this.getAllAnnouncements(auth)).map((a: { id: unknown }) => a.id); + } + const [, responseBody] = await this.put(endPoints.updateBatchAnnouncements, { data: { [action]: allIds }, headers: auth }); + return responseBody; + } + + /** + * product reviews api methods + */ + + // get all product reviews + async getAllProductReviews(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllProductReviews, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get product review id + async getProductReviewId(auth?: auth): Promise { + const allProductReviews = await this.getAllProductReviews(auth); + const reviewId = allProductReviews[0]?.id; + return reviewId; + } + + /** + * store reviews api methods + */ + + // get all store reviews + async getAllStoreReviews(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllStoreReviews, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get store review id + async getStoreReviewId(auth?: auth): Promise { + const allStoreReviews = await this.getAllStoreReviews(auth); + const reviewId = allStoreReviews[0]?.id; + return reviewId; + } + + // delete store review + async deleteStoreReview(reviewId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.deleteStoreReview(reviewId), { headers: auth }); + return responseBody; + } + + // update batch store reviews + async updateBatchStoreReviews(action: string, allIds: string[], auth?: auth): Promise { + if (!allIds?.length) { + allIds = (await this.getAllStoreReviews(auth)).map((a: { id: unknown }) => a.id); + } + const [, responseBody] = await this.put(endPoints.updateBatchStoreReviews, { data: { [action]: allIds }, headers: auth }); + return responseBody; + } + + /** + * store categories api methods + */ + + // get all store categories + async getAllStoreCategories(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllStoreCategories, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get store category Id + async getStoreCategoryId(StoreCategoryName: string, auth?: auth): Promise { + // todo: apply multiple optional parameter + const allStoreCategories = await this.getAllStoreCategories(auth); + const storeCategoryId = StoreCategoryName ? allStoreCategories.find((o: { name: string }) => o.name.toLowerCase() === StoreCategoryName.toLowerCase())?.id : allStoreCategories[0]?.id; + return storeCategoryId; + } + + // create store category + async createStoreCategory(payload: object, auth?: auth): Promise<[responseBody, string, string]> { + const [, responseBody] = await this.post(endPoints.createStoreCategory, { data: payload, headers: auth }); + const categoryId = String(responseBody?.id); + const categoryName = String(responseBody?.name); + return [responseBody, categoryId, categoryName]; + } + + // get default store category + async getDefaultStoreCategory(auth?: auth): Promise<[responseBody, number]> { + const [, responseBody] = await this.get(endPoints.getDefaultStoreCategory, { headers: auth }); + const categoryId = responseBody?.id; + return [responseBody, categoryId]; + } + + // set default store category + async setDefaultStoreCategory(category: string | number, auth?: auth): Promise { + const categoryId = typeof category === 'string' ? await this.getStoreCategoryId(category, auth) : category; + const [, responseBody] = await this.put(endPoints.setDefaultStoreCategory, { data: { id: categoryId }, headers: auth }); + return responseBody; + } + + /** + * quote rules api methods + */ + + // get all quote rules + async getAllQuoteRules(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllQuoteRules, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // create quote rule + async createQuoteRule(payload: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.createQuoteRule, { data: payload, headers: auth }); + const quoteRuleId = String(responseBody?.id); + return [responseBody, quoteRuleId]; + } + + // delete quote rule + async deleteQuoteRule(quoteRuleId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.deleteQuoteRule(quoteRuleId), { headers: auth }); + return responseBody; + } + + // delete all quote rules + async deleteAllQuoteRules(auth?: auth): Promise { + const allQuoteRuleIds = (await this.getAllQuoteRules(auth)).map((o: { id: unknown }) => o.id); + if (!allQuoteRuleIds?.length) { + console.log('No quote rule exists'); + return; + } + const [, responseBody] = await this.put(endPoints.updateBatchQuoteRules, { data: { trash: allQuoteRuleIds }, headers: auth }); + return responseBody; + } + + /** + * quote requests api methods + */ + + // get all quote requests + async getAllQuoteRequests(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllQuoteRequests, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // create quote request + async createQuoteRequest(payload: object, auth?: auth): Promise<[responseBody, string, string]> { + const [, responseBody] = await this.post(endPoints.createQuoteRequest, { data: payload, headers: auth }); + const quoteId = String(responseBody[0]?.data?.id); + const quoteTitle = String(responseBody[0]?.data?.title); + return [responseBody, quoteId, quoteTitle]; + } + + // delete quote request + async deleteQuoteRequest(quoteRuleId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.deleteQuoteRequest(quoteRuleId), { headers: auth }); + return responseBody; + } + + // delete all quote requests + async deleteAllQuoteRequests(auth?: auth): Promise { + const allQuoteIds = (await this.getAllQuoteRequests(auth)).map((o: { id: unknown }) => o.id); + if (!allQuoteIds?.length) { + console.log('No quote request exists'); + return; + } + const [, responseBody] = await this.put(endPoints.updateBatchRequestQuotes, { data: { trash: allQuoteIds }, headers: auth }); + return responseBody; + } + + // convert quote to order + async convertQuoteToOrder(quoteId: string, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.convertRequestQuoteToOrder, { data: { status: 'converted', quote_id: quoteId }, headers: auth }); + return responseBody; + } + + /** + * order downloads api methods + */ + + // get all order download + async getAllOrderDownloads(orderId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllOrderDownloads(orderId), { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // create order download + async createOrderDownload(orderId: string, downloadableProducts: string[], auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.createOrderDownload(orderId), { data: { ids: downloadableProducts }, headers: auth }); + const downloadId = String(Object.keys(responseBody)[0]); + return [responseBody, downloadId]; + } + + /** + * seller badge api methods + */ + + // get all seller badges + async getAllSellerBadges(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllSellerBadges, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get seller badgeId + async getSellerBadgeId(eventType: string, auth?: auth): Promise { + const allBadges = await this.getAllSellerBadges(auth); + const badgeId = allBadges.find((o: { event_type: string }) => o.event_type.toLowerCase() === eventType.toLowerCase())?.id; + return badgeId; + } + + // create seller badge + async createSellerBadge(payload: any, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.createSellerBadge, { data: payload, headers: auth }, false); + const badgeId = responseBody.code === 'invalid-event-type' ? await this.getSellerBadgeId(payload.event_type, auth) : responseBody?.id; + return [responseBody, badgeId]; + } + + // update batch seller badges + async updateBatchSellerBadges(action: string, allIds: string[], auth?: auth): Promise { + if (!allIds?.length) { + allIds = (await this.getAllSellerBadges(auth)).map((a: { id: unknown }) => a.id); + } + const [, responseBody] = await this.put(endPoints.updateBatchSellerBadges, { data: { ids: allIds, action: action }, headers: auth }); + return responseBody; + } + + // delete seller badge + async deleteSellerBadge(badgeId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.deleteSellerBadge(badgeId), { headers: auth }); + return responseBody; + } + + // delete all seller badges + async deleteAllSellerBadges(auth?: auth): Promise { + const allBadges = await this.getAllSellerBadges(auth); + if (!allBadges?.length) { + console.log('No seller badge exists'); + return; + } + const allBadgeIds = allBadges.map((o: { id: unknown }) => o.id); + await this.updateBatchSellerBadges('delete', allBadgeIds, auth); + } + + /** + * vendor staff api methods + */ + + // get all vendor staffs + async getAllVendorStaffs(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.getAllVendorStaffs, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get staffId + async getStaffId(username: string, auth?: auth): Promise { + const allStaffs = await this.getAllVendorStaffs(auth); + const staffId = allStaffs.find((o: { user_login: string }) => o.user_login.toLowerCase() === username.toLowerCase())?.id; + return staffId; + } + + // create vendor staff + async createVendorStaff(payload: any, auth?: auth): Promise<[responseBody, string]> { + const [response, responseBody] = await this.post(endPoints.createVendorStaff, { data: payload, headers: auth }, false); + let staffId: string; + if (responseBody.code) { + expect(response.status()).toBe(500); + // get staff id if already exists + staffId = await this.getStaffId(payload.username, auth); + + // update staff if already exists + await this.updateStaff(staffId, payload, auth); + } else { + expect(response.ok()).toBeTruthy(); + staffId = String(responseBody?.ID); + } + return [responseBody, staffId]; + } + + // update staff + async updateStaff(staffId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.updateVendorStaff(staffId), { data: payload, headers: auth }); + return responseBody; + } + + /** + * spmv api methods + */ + + // add spmv product to store + async addSpmvProductToStore(productId: string, auth?: auth): Promise<[APIResponse, responseBody]> { + const [response, responseBody] = await this.post(endPoints.addToStore, { data: { product_id: productId }, headers: auth }, false); + + // todo: need to handle already cloned product, dokan issue: fatal error for requested with cloned product id + // if(responseBody.code){ + // expect(response.status()).toBe(500); + // } else { + // expect(response.ok()).toBeTruthy(); + // } + + return [response, responseBody]; + } + + /** + * wp api methods + */ + + // settings + + // get site settings + async getSiteSettings(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getSiteSettings, { headers: auth }); + return responseBody; + } + + // set site settings + async setSiteSettings(payload: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.wp.setSiteSettings, { data: payload, headers: auth }); + return responseBody; + } + + // wp users + + // get all users + async getAllUsers(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getAllUsers, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get user by role + async getAllUsersByRole(roles: string[], auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getAllUsers, { params: { per_page: 100, roles: roles }, headers: auth }); + return responseBody; + } + + // get current user + async getCurrentUser(auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.get(endPoints.wp.getCurrentUser, { headers: auth }); + const userId = String(responseBody?.id); + return [responseBody, userId]; + } + + // get user by-id + async getUserById(userId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getUserById(userId), { headers: auth }); + return responseBody; + } + + // create user + async createUser(payload: object, auth?: auth): Promise { + // administrator, customer, seller + const [, responseBody] = await this.post(endPoints.wp.createUser, { data: payload, headers: auth }); + return responseBody; + } + + // update user + async updateUser(userId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.wp.updateUser(userId), { data: payload, headers: auth }); + return responseBody; + } + + // delete user + async deleteUser(userId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.wp.deleteUser(userId), { headers: auth }); + return responseBody; + } + + // plugins + + // get all plugins + async getAllPlugins(params = {}, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getAllPlugins, { params: { ...params, per_page: 100 }, headers: auth }); + return responseBody; + } + + // get single plugin + async getSinglePlugin(plugin: string, auth?: auth): Promise<[responseBody, string, string]> { + const [response, responseBody] = await this.get(endPoints.wp.getSinglePlugin(plugin), { headers: auth }, false); + if (responseBody.code) { + expect(response.status()).toBe(404); + return [responseBody, plugin, 'not exists']; + } + const name = String(responseBody.name); + const status = String(responseBody.status); + return [responseBody, name, status]; + } + + // update plugin + async updatePlugin(plugin: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.wp.updatePlugin(plugin), { data: payload, headers: auth }); + return responseBody; + } + + // delete plugin + async deletePlugin(plugin: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.wp.deletePlugin(plugin), { headers: auth }); + return responseBody; + } + + // get plugin active or not + async checkPluginsExistence(plugins: string[], auth?: auth): Promise { + const existingPlugins = (await this.getAllPlugins({}, auth)).map((a: { plugin: string }) => a.plugin.split('/')[1]); + return helpers.isSubArray(existingPlugins, plugins); + } + + // get plugin active or not + async pluginsActiveOrNot(plugins: string[], auth?: auth): Promise { + const activePlugins = (await this.getAllPlugins({ status: 'active' }, auth)).map((a: { plugin: string }) => a.plugin.split('/')[1]); + return helpers.isSubArray(activePlugins, plugins); + } + + // media + + // upload media + async uploadMedia(filePath: string, mimeType: string, auth: auth): Promise<[responseBody, string]> { + const payload = { + headers: { + Accept: '*/*', + ContentType: 'multipart/form-data', + Authorization: auth.Authorization, + }, + multipart: { + file: { + name: String(filePath.split('/').pop()), + mimeType: mimeType, + buffer: fs.readFileSync(filePath), + }, + }, + }; + const [, responseBody] = await this.post(endPoints.wp.createMediaItem, payload); + const mediaId = String(responseBody?.id); + return [responseBody, mediaId]; + } + + // upload file + async uploadFile(filePath: string, auth: auth): Promise<[responseBody, string]> { + const payload = fs.readFileSync(filePath); + const headers = { + 'content-disposition': `attachment; filename=${String(filePath.split('/').pop())}`, + Authorization: auth.Authorization, + }; + const [, responseBody] = await this.post(endPoints.wp.createMediaItem, { data: payload, headers: headers }); + const mediaId = String(responseBody?.id); + return [responseBody, mediaId]; + } + + // get all mediaItems + async getAllMediaItems(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getAllMediaItems, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get mediaItemId + async getMediaItemId(auth?: auth): Promise { + const getAllMediaItems = await this.getAllMediaItems(auth); + const mediaId = getAllMediaItems[0]?.id; + return mediaId; + } + + // delete all media items + async deleteAllMediaItems(auth?: auth) { + const allMediaItems = await this.getAllMediaItems(auth); + if (!allMediaItems?.length) { + console.log('No media item exists'); + return; + } + const allMediaItemIds = allMediaItems.map((o: { id: unknown }) => o.id); + for (const mediaId of allMediaItemIds) { + await this.delete(endPoints.wp.deleteMediaItem(mediaId), { params: payloads.paramsForceDelete, headers: auth }); + } + } + + // create post + async createPost(payload: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.wp.createPost, { data: payload, headers: auth }); + return responseBody; + } + + // get all pages + async getAllPages(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getAllPages, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get single page + async getSinglePage(pageId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wp.getSinglePage(pageId), { headers: auth }); + return responseBody; + } + + // get pageId + async getPageId(pageSlug: string, auth?: auth): Promise { + const allPages = await this.getAllPages(auth); + const pageId = allPages.find((o: { slug: string }) => o.slug.toLowerCase() === pageSlug.toLowerCase())?.id; + return pageId; + } + + // create page + async createPage(payload: object, auth?: auth): Promise<[responseBody, string]> { + let pageId = await this.getPageId(helpers.slugify(payloads.tocPage.title), payloads.adminAuth); + let responseBody; + if (!pageId) { + [, responseBody] = await this.post(endPoints.wp.createPage, { data: payload, headers: auth }); + pageId = String(responseBody?.id); + } else { + responseBody = await this.getSinglePage(pageId, auth); + } + return [responseBody, pageId]; + } + + /** + * woocommerce api methods + */ + + // settings + + // get all woocommerce setting options + async getAllWcSettings(groupId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllSettingOptions(groupId), { headers: auth }); + return responseBody; + } + + // get single woocommerce setting options + async getSingleWcSettingOptions(groupId: string, optionId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getSingleSettingOption(groupId, optionId), { headers: auth }); + return responseBody; + } + + // update single woocommerce setting options + async updateSingleWcSettingOptions(groupId: string, optionId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.wc.updateSettingOption(groupId, optionId), { data: payload, headers: auth }); + return responseBody; + } + + // update batch woocommerce settings options + async updateBatchWcSettingsOptions(groupId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.wc.updateBatchSettingOptions(groupId), { data: payload, headers: auth }); + return responseBody; + } + + // reviews + + // create product review + async createProductReview(payload: string | object, review: object, auth?: auth): Promise<[responseBody, string, string]> { + let productId: string; + typeof payload === 'object' ? ([, productId] = await this.createProduct(payload, auth)) : (productId = payload); + const [, responseBody] = await this.post(endPoints.wc.createReview, { data: { ...review, product_id: productId }, headers: auth }); + const reviewId = String(responseBody?.id); + const reviewMessage = String(responseBody?.review); + return [responseBody, reviewId, reviewMessage]; + } + + // categories + + // get all categories + async getAllCategories(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllCategories, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + + // get single category + async getSingleCategory(categoryId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getSingleCategory(categoryId), { headers: auth }); + return responseBody; + } + + // get categoryId + async getCategoryId(categoryName: string, auth?: auth): Promise { + const allCategories = await this.getAllCategories(auth); + const categoryId = categoryName ? allCategories.find((o: { name: string }) => o.name === categoryName.toLowerCase())?.id : allCategories[0]?.id; + return categoryId; + } + + // create category + async createCategory(payload: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.wc.createCategory, { data: payload, headers: auth }); + const categoryId = String(responseBody?.id); + return [responseBody, categoryId]; + } + + // update category + async updateCategory(categoryId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.wc.updateCategory(categoryId), { data: payload, headers: auth }); + return responseBody; + } + + // delete category + async deleteCategory(categoryId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.wc.deleteCategory(categoryId), { headers: auth }); + return responseBody; + } + + // update batch categories + async updateBatchCategories(action: string, allIds: string[], auth?: auth): Promise<[APIResponse, responseBody]> { + if (!allIds?.length) { + allIds = (await this.getAllCategories(auth)).map((a: { id: unknown }) => a.id); + } + const [response, responseBody] = await this.post(endPoints.wc.updateBatchCategories, { data: { [action]: allIds }, headers: auth }); + return [response, responseBody]; + } + + // order + + // create order + async createOrder(product: string | object, orderPayload: any, auth?: auth): Promise<[APIResponse, responseBody, string, string]> { + let productId: string; + if (!product) { + [, productId] = await this.createProduct(payloads.createProduct(), auth); + } else { + typeof product === 'object' ? ([, productId] = await this.createProduct(product, auth)) : (productId = product); + } + const payload = orderPayload; + payload.line_items[0].product_id = productId; + const [response, responseBody] = await this.post(endPoints.wc.createOrder, { data: payload, headers: payloads.adminAuth }, false); + const orderId = String(responseBody?.id); + return [response, responseBody, orderId, productId]; + } + + // create complete order + async createOrderWithStatus(product: string | object, order: any, status: string, auth?: auth): Promise<[APIResponse, responseBody, string, string]> { + const [response, responseBody, orderId, productId] = await this.createOrder(product, order, auth); + await this.updateOrderStatus(orderId, status, auth); + return [response, responseBody, orderId, productId]; + } + + // refund + + // create refund + async createRefund(orderId: string, refund: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.wc.createRefund(orderId), { data: refund, headers: auth }); + const refundId = String(responseBody?.id); + return [responseBody, refundId]; + } + + // tax + + // get all tax rate + async getAllTaxRates(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllTaxRates, { headers: auth }); + return responseBody; + } + + // create tax rate + async createTaxRate(payload: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.wc.createTaxRate, { data: payload, headers: auth }); + return responseBody; + } + + // update batch tax rates + async updateBatchTaxRates(action: string, allIds: string[], auth?: auth): Promise { + if (!allIds?.length) { + allIds = (await this.getAllTaxRates(auth)).map((a: { id: unknown }) => a.id); + } + const [, responseBody] = await this.put(endPoints.wc.updateBatchTaxRates, { data: { [action]: allIds }, headers: auth }); + return responseBody; + } + + // setup tax + async setUpTaxRate(enableTaxPayload: object, taxPayload: taxRate, auth?: auth): Promise { + // enable tax rate + await this.updateBatchWcSettingsOptions('general', enableTaxPayload, auth); + + // delete previous tax rates + const allTaxRateIds = (await this.getAllTaxRates(auth)).map((o: { id: unknown }) => o.id); + if (allTaxRateIds.length) { + await this.updateBatchTaxRates('delete', allTaxRateIds, auth); + } + + // create tax rate + const taxRateResponse = await this.createTaxRate(taxPayload, auth); + expect(parseInt(taxRateResponse.rate)).toBe(parseInt(taxPayload.rate)); + return Number(taxPayload.rate); + } + + // shipping + + // get all shipping zones + async getAllShippingZones(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllShippingZones, { headers: auth }); + return responseBody; + } + + // get zoneId + async getZoneId(zoneName: string, auth?: auth): Promise { + const allZones = await this.getAllShippingZones(auth); + const zoneId = allZones.find((o: { name: string }) => o.name.toLowerCase() === zoneName.toLowerCase())?.id; + return zoneId; + } + + // create shipping zone + async createShippingZone(payload: object, auth?: auth): Promise<[responseBody, string]> { + const [, responseBody] = await this.post(endPoints.wc.createShippingZone, { data: payload, headers: auth }); + const shippingZoneId = String(responseBody?.id); + return [responseBody, shippingZoneId]; + } + + // delete shipping zone + async deleteShippingZone(zoneId: string, auth?: auth): Promise { + const [, responseBody] = await this.delete(endPoints.wc.deleteShippingZone(zoneId), { params: { force: true }, headers: auth }); + return responseBody; + } + + // get all shipping zone locations + async getAllShippingZoneLocations(zoneId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllShippingZoneLocations(zoneId), { headers: auth }); + return responseBody; + } + + // add shipping zone location + async addShippingZoneLocation(zoneId: string, zoneLocation: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.wc.addShippingZoneLocation(zoneId), { data: zoneLocation, headers: auth }); + return responseBody; + } + + // get all shipping zone methods + async getAllShippingZoneMethods(zoneId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllShippingZoneMethods(zoneId), { headers: auth }); + return responseBody; + } + + // add shipping zone method + async addShippingZoneMethod(zoneId: string, zoneMethod: object, auth?: auth): Promise { + const [, responseBody] = await this.post(endPoints.wc.addShippingZoneMethod(zoneId), { data: zoneMethod, headers: auth }); + return responseBody; + } + + // payment + + // get all payment gateway + async getAllPaymentGateways(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllPaymentGateways, { headers: auth }); + return responseBody; + } + + // get single payment gateway + async getSinglePaymentGateway(paymentGatewayId: string, auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getSinglePaymentGateway(paymentGatewayId), { headers: auth }); + return responseBody; + } + + // update payment gateway + async updatePaymentGateway(paymentGatewayId: string, payload: object, auth?: auth): Promise { + const [, responseBody] = await this.put(endPoints.wc.updatePaymentGateway(paymentGatewayId), { data: payload, headers: auth }); + return responseBody; + } + + /** + * woocommerce booking api methods + */ + + // create product + async createBookableProduct(payload: object, auth?: auth): Promise<[responseBody, string, string]> { + const [, responseBody] = await this.post(endPoints.wc.booking.createBookableProduct, { data: payload, headers: auth }); + const productId = String(responseBody?.id); + const productName = String(responseBody.name); + return [responseBody, productId, productName]; + } + + // get system status + async getSystemStatus(auth?: auth): Promise<[responseBody, object]> { + const [, responseBody] = await this.get(endPoints.wc.getAllSystemStatus, { headers: auth }); + let activePlugins = responseBody.active_plugins.map((a: { plugin: string; version: string }) => a.plugin.split('/')[0] + ' v' + a.version); + activePlugins.sort(); + const conditions = ['Basic-Auth', 'bookings', 'addons', 'auctions', 'subscriptions', 'ba', 'wa', 'wb', 'ws', 'wps']; + activePlugins = activePlugins.filter((e: string | string[]) => !conditions.some(el => e.includes(el))); + // activePlugins = activePlugins.slice(1, -4); + const compactInfo = { + wpVersion: 'WordPress Version: ' + responseBody?.environment.wp_version, + phpVersion: 'PHP Version: ' + responseBody?.environment.php_version, + mysqlVersion: 'MySql Version: ' + responseBody?.environment.mysql_version, + theme: 'Theme: ' + responseBody?.theme.name + ' v' + responseBody?.theme.version, + wpDebugMode: 'Debug Mode: ' + responseBody?.environment.wp_debug_mode, + activePlugins: activePlugins, + }; + return [responseBody, compactInfo]; + } +} diff --git a/tests/pw/utils/dbData.ts b/tests/pw/utils/dbData.ts new file mode 100644 index 0000000000..d433ce9d0a --- /dev/null +++ b/tests/pw/utils/dbData.ts @@ -0,0 +1,621 @@ +export const dbData = { + dokan: { + optionName: { + general: 'dokan_general', + selling: 'dokan_selling', + withdraw: 'dokan_withdraw', + reverseWithdraw: 'dokan_reverse_withdrawal', + page: 'dokan_pages', + appearance: 'dokan_appearance', + privacyPolicy: 'dokan_privacy', + colors: 'dokan_colors', + // liveSearch: 'dokan_live_search_setting', + storeSupport: 'dokan_store_support_setting', + // sellerVerification: 'dokan_verification', + // verificationSMSGateways: 'dokan_verification_sms_gateways', + emailVerification: 'dokan_email_verification', + // socialApi: 'dokan_social_api', + shippingStatus: 'dokan_shipping_status_setting', + quote: 'dokan_quote_settings', + // liveChat: 'dokan_live_chat', + rma: 'dokan_rma', + wholesale: 'dokan_wholesale', + euCompliance: 'dokan_germanized', + deliveryTime: 'dokan_delivery_time', + productAdvertising: 'dokan_product_advertisement', + geolocation: 'dokan_geolocation', + productReportAbuse: 'dokan_report_abuse', + spmv: 'dokan_spmv', + vendorSubscription: 'dokan_product_subscription', + // vendorAnalytics: + dokanActiveModules: 'dokan_pro_active_modules', + }, + + generalSettings: { + // site settings + site_options: '', + admin_access: 'on', // vendor edit product test needs it to disable + custom_store_url: 'store', + setup_wizard_logo_url: '', + setup_wizard_message: + '

    Thank you for choosing The Marketplace to power your online store! This quick setup wizard will help you configure the basic settings. It’s completely optional and shouldn’t take longer than two minutes.

    ', + disable_welcome_wizard: 'off', + global_digital_mode: 'sell_both', + enable_shipstation_logging: 'off', + data_clear_on_uninstall: 'off', + + // vendor store settings + vendor_store_options: '', + seller_enable_terms_and_conditions: 'on', + store_products_per_page: '12', + enabled_address_on_reg: 'off', + enable_tc_on_reg: 'on', + enable_single_seller_mode: 'off', + store_category_type: 'multiple', // none, multiple + }, + + sellingSettings: { + // commission + selling_capabilities: '', + commission_type: 'percentage', + admin_percentage: '10', + shipping_fee_recipient: 'seller', + tax_fee_recipient: 'seller', + shipping_tax_fee_recipient: 'seller', + automatic_process_api_refund: 'off', + + // vendor capabilities + additional_fee: '', + new_seller_enable_selling: 'on', + one_step_product_create: 'on', + disable_product_popup: 'off', + order_status_change: 'on', + dokan_any_category_selection: 'off', + product_status: 'publish', + vendor_duplicate_product: 'on', + product_category_style: 'single', + product_vendors_can_create_tags: 'on', + add_new_attribute: 'on', + discount_edit: { + 'order-discount': 'order-discount', + 'product-discount': 'product-discount', + }, + hide_customer_info: 'off', + seller_review_manage: 'on', + new_seller_enable_auction: 'on', + enable_guest_user_enquiry: 'on', + enable_min_max_quantity: 'on', + enable_min_max_amount: 'on', + disable_shipping_tab: 'off', + + // catalog mode + catalog_mode_settings: '', + catalog_mode_hide_add_to_cart_button: 'on', + catalog_mode_hide_product_price: 'on', + }, + + withdrawSettings: { + // withdraw settings + withdraw_methods: { + paypal: 'paypal', + bank: 'bank', + dokan_custom: 'dokan_custom', + skrill: 'skrill', + }, + withdraw_method_name: 'Bksh', + withdraw_method_type: 'Phone', + withdraw_limit: '5', + withdraw_order_status: { + 'wc-completed': 'wc-completed', + 'wc-processing': 'wc-processing', + }, + exclude_cod_payment: 'off', + withdraw_date_limit: '0', + hide_withdraw_option: 'off', + + // disbursement settings + disbursement_schedule_settings: '', + disbursement: { + manual: 'manual', + schedule: 'schedule', + }, + disbursement_schedule: { + quarterly: 'quarterly', + monthly: 'monthly', + biweekly: 'biweekly', + weekly: 'weekly', + }, + quarterly_schedule: { + month: 'march', + week: '1', + days: 'monday', + }, + monthly_schedule: { + week: '1', + days: 'monday', + }, + biweekly_schedule: { + week: '1', + days: 'monday', + }, + weekly_schedule: 'monday', + send_announcement_for_payment_change: 'false', + send_announcement_for_disbursement_schedule_change: 'false', + }, + + reverseWithdrawSettings: { + enabled: 'on', + payment_gateways: { + cod: 'cod', + }, + billing_type: 'by_amount', + reverse_balance_threshold: '10', + monthly_billing_day: '1', + due_period: '0', + failed_actions: { + enable_catalog_mode: 'enable_catalog_mode', + hide_withdraw_menu: 'hide_withdraw_menu', + status_inactive: 'status_inactive', + }, + display_notice: 'on', + send_announcement: 'on', + }, + + pageSettings: { + dashboard: '4', + store_listing: '5', + my_orders: '6', + reg_tc_page: '2', + }, + + appearanceSettings: { + appearance_options: '', + store_map: 'on', + map_api_source: 'google_maps', + gmap_api_key: process.env.GMAP, + mapbox_access_token: '', + recaptcha_validation_label: '', + contact_seller: 'on', + store_header_template: 'default', + store_banner_width: '625', + store_banner_height: '300', + store_open_close: 'on', + enable_theme_store_sidebar: 'off', + show_vendor_info: 'on', + hide_vendor_info: { + email: '', + phone: '', + address: '', + }, + }, + + privacyPolicySettings: { + enable_privacy: 'on', + privacy_page: '2', + privacy_policy: '

    Your personal data will be used to support your experience throughout this website, to manage access to your account, and for other purposes described in our [dokan_privacy_policy]

    ', + }, + + colorsSettings: { + store_color_pallete: { + value: 'default', + btn_text: '#FFFFFF', + btn_hover: '#DD3B0F', + btn_primary: '#F05025', + dash_nav_bg: '#1B233B', + dash_nav_text: '#CFCFCF', + pallete_status: 'template', + btn_hover_text: '#FFFFFF', + dash_active_link: '#F05025', + btn_hover_border: '#C83811', + btn_primary_border: '#DA502B', + dash_nav_active_text: '#FFFFFF', + color_options: { + 'color-1': '#1B233B', + 'color-2': '#F05025', + 'color-3': '#CFCFCF', + 'color-4': '#DD3B0F', + }, + }, + }, + + liveSearchSettings: { + live_search_option: 'suggestion_box', + }, + + storeSupportSettings: { + enabled_for_customer_order: 'on', + store_support_product_page: 'above_tab', + support_button_label: 'Get Support', + dokan_admin_email_notification: 'on', + }, + + sellerVerificationSettings: { + facebook_app_details: '', + twitter_app_details: '', + google_details: '', + linkedin_details: '', + fb_app_id: '', + fb_app_secret: '', + twitter_app_id: '', + twitter_app_secret: '', + google_app_id: '', + google_app_secret: '', + }, + + verificationSMSGatewaysSettings: { + sender_name: 'weDevs Team', + sms_text: 'Your verification code is: %CODE%', + sms_sent_msg: 'SMS sent. Please enter your verification code', + sms_sent_error: 'Unable to send sms. Contact admin', + active_gateway: '', + + // nexmo details + nexmo_details: '', + nexmo_username: '', + nexmo_pass: '', + + // twilio details + twilio_details: '', + }, + + emailVerificationSettings: { + enabled: 'off', + registration_notice: 'Please check your email and complete email verification to login.', + login_notice: 'Please check your email and complete email verification to login.', + }, + + socialAPISettings: { + section_title: '', + enabled: 'on', + facebook_details: '', + twitter_details: '', + google_details: '', + linkedin_details: '', + apple_details: '', + fb_app_id: '', + fb_app_secret: '', + twitter_app_id: '', + twitter_app_secret: '', + }, + + shippingStatusSettings: { + enabled: 'on', + shipping_status_provider: { + 'sp-dhl': 'sp-dhl', + 'sp-dpd': 'sp-dpd', + 'sp-fedex': 'sp-fedex', + 'sp-polish-shipping-providers': 'sp-polish-shipping-providers', + 'sp-ups': 'sp-ups', + 'sp-usps': 'sp-usps', + 'sp-other': 'sp-other', + }, + shipping_status_list: [ + { + id: 'ss_delivered', + value: 'Delivered', + must_use: 'true', + desc: '(This is must use item)', + }, + { + id: 'ss_cancelled', + value: 'Cancelled', + must_use: 'true', + desc: '(This is must use item)', + }, + { + id: 'ss_proceccing', + value: 'Processing', + }, + { + id: 'ss_ready_for_pickup', + value: 'Ready for pickup', + }, + { + id: 'ss_pickedup', + value: 'Pickedup', + }, + { + id: 'ss_on_the_way', + value: 'On the way', + }, + ], + }, + + quoteSettings: { + // quote settings + dokan_quote_settings: '', + enable_out_of_stock: 'on', + enable_ajax_add_to_quote: 'on', + redirect_to_quote_page: 'off', + + // quote attributes settings + quote_attributes_settings: '', + decrease_offered_price: '0', + enable_convert_to_order: 'off', + enable_quote_converter_display: 'off', + }, + + liveChatSettings: { + enable: 'off', + provider: 'messenger', + theme_color: '#0084FF', + app_id: '', + app_secret: '', + wa_opening_method: 'in_app', + wa_pre_filled_message: 'Hello {store_name}, I have an enquiry regarding your store at {store_url}', + chat_button_seller_page: 'on', + chat_button_product_page: 'above_tab', + }, + + rmaSettings: { + rma_order_status: 'wc-processing', + rma_enable_refund_request: 'on', + rma_enable_coupon_request: 'on', + rma_reasons: [ + { + id: 'defective', + value: 'Defective', + }, + { + id: 'wrong_product', + value: 'Wrong Product', + }, + { + id: 'other', + value: 'Other', + }, + ], + rma_policy: '

    Refund Policy

    ', + }, + + wholesaleSettings: { + wholesale_price_display: 'all_user', + display_price_in_shop_archieve: 'on', + need_approval_for_wholesale_customer: 'off', + }, + + euComplianceSettings: { + vendor_fields: { + dokan_company_name: 'dokan_company_name', + dokan_company_id_number: 'dokan_company_id_number', + dokan_vat_number: 'dokan_vat_number', + dokan_bank_name: 'dokan_bank_name', + dokan_bank_iban: 'dokan_bank_iban', + }, + vendor_registration: 'on', + customer_fields: { + billing_dokan_company_id_number: 'billing_dokan_company_id_number', + billing_dokan_vat_number: 'billing_dokan_vat_number', + billing_dokan_bank_name: 'billing_dokan_bank_name', + billing_dokan_bank_iban: 'billing_dokan_bank_iban', + }, + enabled_germanized: 'on', + override_invoice_number: 'on', + }, + + deliveryTimeSettings: { + allow_vendor_override_settings: 'on', + delivery_support: { + delivery: 'delivery', + 'store-pickup': 'store-pickup', + }, + delivery_date_label: 'Delivery Date', + preorder_date: 0, + time_slot_minutes: 30, + order_per_slot: 0, + delivery_box_info: 'This store needs %DAY% day(s) to process your delivery request', + selection_required: 'off', + delivery_day: '', + delivery_day_monday: { + delivery_status: 'monday', + opening_time: '12:00 am', + closing_time: '11:59 pm', + }, + delivery_day_tuesday: { + delivery_status: 'tuesday', + opening_time: '12:00 am', + closing_time: '11:59 pm', + }, + delivery_day_wednesday: { + delivery_status: 'wednesday', + opening_time: '12:00 am', + closing_time: '11:59 pm', + }, + delivery_day_thursday: { + delivery_status: 'thursday', + opening_time: '12:00 am', + closing_time: '11:59 pm', + }, + delivery_day_friday: { + delivery_status: 'friday', + opening_time: '12:00 am', + closing_time: '11:59 pm', + }, + delivery_day_saturday: { + delivery_status: 'saturday', + opening_time: '12:00 am', + closing_time: '11:59 pm', + }, + delivery_day_sunday: { + delivery_status: 'sunday', + opening_time: '12:00 am', + closing_time: '11:59 pm', + }, + }, + + productAdvertisingSettings: { + total_available_slot: '100', + expire_after_days: '10', + per_product_enabled: 'on', + cost: '20', + vendor_subscription_enabled: 'on', + featured: 'on', + catalog_priority: 'on', + hide_out_of_stock_items: 'on', + }, + + geolocationSettings: { + show_locations_map: 'top', + show_location_map_pages: 'all', + show_filters_before_locations_map: 'on', + show_product_location_in_wc_tab: 'on', + distance_unit: 'km', + distance_min: '0', + distance_max: '10', + map_zoom: '11', + location: { + latitude: '40.7127753', + longitude: '-74.0059728', + address: 'New York, NY, USA', + zoom: '10', + }, + }, + + productReportAbuseSettings: { + reported_by_logged_in_users_only: 'off', + abuse_reasons: [ + { + id: 'report_as_spam', + value: 'This content is spam', + }, + { + id: 'report_as_adult', + value: 'This content should marked as adult', + }, + { + id: 'report_as_abusive', + value: 'This content is abusive', + }, + { + id: 'report_as_violent', + value: 'This content is violent', + }, + { + id: 'report_as_risk_of_hurting', + value: 'This content suggests the author might be risk of hurting themselves', + }, + { + id: 'report_as_infringes_copyright', + value: 'This content infringes upon my copyright', + }, + { + id: 'report_as_contains_private_info', + value: 'This content contains my private information', + }, + { + id: 'other', + value: 'Other', + }, + { + id: 'this_product_is_fake', + value: 'This product is fake', + }, + ], + }, + + spmvSettings: { + enable_pricing: 'on', + sell_item_btn: 'Sell This Item', + available_vendor_list_title: 'Other Available Vendor', + available_vendor_list_position: 'below_tabs', + show_order: 'show_all', + }, + + vendorSubscriptionSettings: { + subscription_pack: '2', + enable_pricing: 'off', + enable_subscription_pack_in_reg: 'off', + notify_by_email: 'on', + no_of_days_before_mail: '1', + product_status_after_end: 'draft', + cancelling_email_subject: 'Subscription Package Cancel notification', + cancelling_email_body: 'Dear subscriber, Your subscription has expired. Please renew your package to continue using it.', + alert_email_subject: 'Subscription Ending Soon', + alert_email_body: 'Dear subscriber, Your subscription will be ending soon. Please renew your package in a timely', + }, + + // modules + modules: [ + 'booking', + 'color_scheme_customizer', + 'delivery_time', + 'elementor', + 'export_import', + 'follow_store', + 'geolocation', + 'germanized', + 'live_chat', + 'live_search', + 'moip', + 'dokan_paypal_ap', + 'paypal_marketplace', + 'product_addon', + 'product_enquiry', + 'report_abuse', + 'rma', + 'seller_vacation', + 'shipstation', + 'auction', + 'spmv', + 'store_reviews', + 'store_support', + 'stripe', + 'product_advertising', + 'product_subscription', + 'vendor_analytics', + 'vendor_staff', + 'vsp', + 'vendor_verification', + 'wholesale', + 'rank_math', + 'table_rate_shipping', + 'mangopay', + 'order_min_max', + 'razorpay', + 'seller_badge', + 'stripe_express', + 'request_for_quotation', + ], + + // abuse report + createAbuseReport: { + reason: 'This content is spam', + description: 'spam product', + }, + }, + + // wp + + optionName: { + activePlugins: 'active_plugins', + }, + + plugins: { + '0': 'Basic-Auth-master/basic-auth.php', + // '1':'woocommerce/woocommerce.php', + // '2':'dokan/dokan.php', + // '3':'dokan-pro/dokan-pro.php', + // '4':'woocommerce-bookings/woocommerce-bookings.php', + // '5':'woocommerce-product-addons/woocommerce-product-addons.php', + // '6':'woocommerce-simple-auctions/woocommerce-simple-auctions.php', + // '7':'woocommerce-subscriptions/woocommerce-subscriptions.php' + // curl --user admin:01dokan01 http://dokan5.test/wp-json + // curl --user admin:01dokan01 http://dokan5.test/wp-json/wp/v2/plugins + }, + + siteSettings: { + users_can_register: 1, + start_of_week: 1, + date_format: 'F j, Y', + time_format: 'g:i a', + permalink_structure: '/%postname%/', + default_role: 'subscriber', + timezone_string: 'Asia/Dhaka', + }, + + // woocommerce + + woocommerceSettings: { + woocommerce_enable_myaccount_registration: 'yes', + }, +}; diff --git a/tests/pw/utils/dbUtils.ts b/tests/pw/utils/dbUtils.ts new file mode 100644 index 0000000000..8334b670d0 --- /dev/null +++ b/tests/pw/utils/dbUtils.ts @@ -0,0 +1,125 @@ +import { expect } from '@playwright/test'; +import { MySqlConnection, DbContext } from 'mysqlconnector'; +import { serialize, unserialize } from 'php-serialize'; +import { dbData } from '@utils/dbData'; +import { helpers } from '@utils/helpers'; +const { DB_HOST_NAME, DB_USER_NAME, DB_USER_PASSWORD, DATABASE, DB_PORT, DB_PREFIX } = process.env; + +const mySql = new MySqlConnection({ + hostname: DB_HOST_NAME, + username: DB_USER_NAME, + password: DB_USER_PASSWORD, + db: DATABASE, + port: Number(DB_PORT), +}); + +const dbPrefix = DB_PREFIX; + +export const dbUtils = { + // execute db query + async dbQuery(query: string): Promise { + const dbContext: DbContext = new DbContext(mySql); + return await dbContext.inTransactionAsync(async dbContext => { + try { + const result = await dbContext.executeAsync(query); + const res = JSON.parse(JSON.stringify(result)); + expect(res).not.toHaveProperty('errno'); + return res; + } catch (err: unknown) { + // console.log('dbError:', err); + return err; + } + }); + }, + + // get max id + async getMaxId(columnName: string, tableName: string): Promise { + const querySelect = `SELECT MAX(${columnName}) as id FROM ${dbPrefix}_${tableName};`; + const res = await dbUtils.dbQuery(querySelect); + // console.log(res); + const id = res[0].id; + return id; + }, + + // 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}';`; + const res = await dbUtils.dbQuery(queryUpdate); + // console.log(res); + return res; + }, + + // get dokan settings + async getDokanSettings(optionName: string): Promise { + const querySelect = `Select option_value FROM ${dbPrefix}_options WHERE option_name = '${optionName}';`; + const res = await dbUtils.dbQuery(querySelect); + // console.log(res[0].option_value); + // console.log(unserialize(res[0].option_value)); + return unserialize(res[0].option_value); + }, + + // set dokan settings + async setDokanSettings(optionName: string, optionValue: object): Promise { + const queryInsert = `INSERT INTO ${dbPrefix}_options VALUES ( NULL, '${optionName}', '${serialize(optionValue)}', 'yes');`; + let res = await dbUtils.dbQuery(queryInsert); + if (res.code === 'ER_DUP_ENTRY') { + const queryUpdate = `UPDATE ${dbPrefix}_options SET option_value = '${serialize(optionValue)}' WHERE option_name = '${optionName}';`; + res = await dbUtils.dbQuery(queryUpdate); + } + // console.log(res); + return res; + }, + + // get selling info + async getSellingInfo(): Promise { + const res = await this.getDokanSettings(dbData.dokan.optionName.selling); + const commission = { + type: res.commission_type, + amount: res.admin_percentage, + additionalAmount: res.additional_fee, + }; + const feeRecipient = { + shippingFeeRecipient: res.shipping_fee_recipient, + taxFeeRecipient: res.tax_fee_recipient, + shippingTaxFeeRecipient: res.shipping_tax_fee_recipient, + }; + return [commission, feeRecipient]; + }, + + // create abuse report + async createAbuseReport(abuseReport: any, productId: string, vendorId: string, customerId: string): Promise { + const querySelect = `INSERT INTO ${dbPrefix}_dokan_report_abuse_reports (reason, product_id, vendor_id, customer_id, description, reported_at) VALUES ('${abuseReport.reason}', ${parseInt(productId)}, ${parseInt( + vendorId, + )}, ${parseInt(customerId)}, '${abuseReport.description}', '${helpers.currentDateTimeFullFormat}');`; + const res = await dbUtils.dbQuery(querySelect); + // console.log(res); + return res; + }, + + // create refund + async createRefund(responseBody: any): Promise<[any, string]> { + const refundId = (await this.getMaxId('id', 'dokan_refund')) + 1; + + const refund = { + id: refundId, + orderId: responseBody.id, + sellerId: responseBody.stores[0].id, + refundAmount: 20.5, + refundReason: 'test refund', + itemQtys: `{"${responseBody.line_items[0].id}": 1 }`, + itemTotals: `{"${responseBody.line_items[0].id}":"10.000000","${responseBody.shipping_lines[0].id}":"5.000000"}`, + itemTaxTotals: `{"${responseBody.line_items[0].id}":{"${responseBody.line_items[0].taxes[0].id}":5},"${responseBody.shipping_lines[0].id}":{"${responseBody.line_items[0].taxes[0].id}":0.5}}`, + restockItems: 1, + date: helpers.currentDateTimeFullFormat, + status: 0, // 0 for pending, 1 for completed + method: 0, + }; + // console.log('refund data:', refund); + const queryInsert = `INSERT INTO ${dbPrefix}_dokan_refund VALUES ( '${refund.id}', '${refund.orderId}', '${refund.sellerId}', ${refund.refundAmount}, '${refund.refundReason}', '${refund.itemQtys}', '${refund.itemTotals}', '${refund.itemTaxTotals}', '${refund.restockItems}', '${refund.date}', '${refund.status}', '${refund.method}' );`; + const res = await dbUtils.dbQuery(queryInsert); + // console.log(res); + return [res, refundId]; + }, +}; diff --git a/tests/pw/utils/gitTestSummary.ts b/tests/pw/utils/gitTestSummary.ts new file mode 100644 index 0000000000..cc144de5c3 --- /dev/null +++ b/tests/pw/utils/gitTestSummary.ts @@ -0,0 +1,55 @@ +const fs = require('fs'); +const { SHA, PR_NUMBER, SYSTEM_INFO, API_TEST_RESULT, E2E_TEST_RESULT } = process.env; + +const replace = obj => Object.keys(obj).forEach(key => (typeof obj[key] == 'object' ? replace(obj[key]) : (obj[key] = String(obj[key])))); +const readFile = filePath => (fs.existsSync(filePath) ? JSON.parse(fs.readFileSync(filePath, 'utf8')) : false); +const getTestResult = (suiteName, filePath) => { + const testResult = readFile(filePath); + if (!testResult) { + return []; + } + replace(testResult); + const testSummary = [suiteName, testResult.total_tests, testResult.passed, testResult.failed, testResult.flaky, testResult.skipped, testResult.suite_duration_formatted]; + return testSummary; +}; + +const addSummaryHeadingAndTable = core => { + const tableHeader = [ + { data: 'Test :test_tube:', header: true }, + { data: 'Total :bar_chart:', header: true }, + { data: 'Passed :white_check_mark:', header: true }, + { data: 'Failed :rotating_light:', header: true }, + { data: 'Flaky :construction:', header: true }, + { data: 'Skipped :next_track_button:', header: true }, + { data: 'Duration :alarm_clock:', header: true }, + ]; + const apiTesResult = getTestResult('API Tests', API_TEST_RESULT); + const e2eTesResult = getTestResult('E2E Tests', E2E_TEST_RESULT); + core.summary.addHeading('Tests Summary').addRaw(`Commit SHA: ${SHA}`).addBreak().addBreak().addTable([tableHeader, apiTesResult, e2eTesResult]); +}; + +const addList = core => { + const envInfo = readFile(SYSTEM_INFO); + if (!envInfo) { + return false; + } + const pluginList = core.summary.addList(envInfo.activePlugins).stringify(); + core.summary.clear(); + const pluginDetails = core.summary.addDetails('Plugins: ', pluginList).stringify(); + core.summary.clear(); + return core.summary.addList([envInfo.wpVersion, envInfo.phpVersion, envInfo.mysqlVersion, String(envInfo.wpDebugMode), envInfo.theme, pluginDetails]).stringify(); +}; + +const addSummaryFooter = (core, list) => { + core.summary.addBreak().addDetails('Test Environment Details: ', list); +}; + +module.exports = async ({ github, context, core }) => { + const plugins = addList(core); + await core.summary.clear(); + addSummaryHeadingAndTable(core); + plugins && addSummaryFooter(core, plugins); + const summary = core.summary.stringify(); + await core.summary.write(); + return summary; +}; diff --git a/tests/pw/utils/helpers.ts b/tests/pw/utils/helpers.ts new file mode 100644 index 0000000000..c7f9a2c13b --- /dev/null +++ b/tests/pw/utils/helpers.ts @@ -0,0 +1,267 @@ +// const open = require( 'open' ); +import fs from 'fs'; +import { Browser, BrowserContextOptions } from '@playwright/test'; + +export const helpers = { + // replace '_' to space & capitalize first letter of string + replaceAndCapitalize: (str: string) => + str + .replace('dokan', 'vendor') + .replace('_', ' ') + .replace(/^\w{1}/, letter => letter.toUpperCase()), + + // replace '_' to space & capitalize first letter of each word + replaceAndCapitalizeEachWord: (str: string) => str.replace('_', ' ').replace(/(^\w{1})|(\s+\w{1})/g, (letter: string) => letter.toUpperCase()), + + // capitalize + capitalize: (word: string) => word[0]?.toUpperCase() + word.substring(1).toLowerCase(), + + // returns a random number between min (inclusive) and max (exclusive) + getRandomArbitrary: (min: number, max: number) => Math.random() * (max - min) + min, + + // returns a random integer number between min (inclusive) and max (exclusive) + getRandomArbitraryInteger: (min: number, max: number) => Math.floor(Math.random() * (max - min) + min), + + // random number between 0 and 1000 + randomNumber: () => Math.floor(Math.random() * 1000), + + // random array element + randomItem: (arr: string | any[]) => arr[Math.floor(Math.random() * arr.length)], + + // remove array element + removeItem: (arr: any[], removeItem: any) => arr.filter(item => item !== removeItem), + + // get count in array + getCount: (array: any[], element: any) => array.filter(n => n === element).length, + + // is sub array + isSubArray: (parentArray: any[], subArray: any[]) => subArray.every(el => parentArray.includes(el)), + + // check if object is empty + isObjEmpty: (obj: object) => Object.keys(obj).length === 0, + + // opens the url in the default browser + openUrl: (url: string) => open(url), + + // opens test report in the default browser + openReport: () => open('playwright-report/html-report/index.html'), + + // string between two tags + stringBetweenTags: (str: string): string => { + const res = str.split(/

    (.*?)<\/p>/g); + return res[1] as string; + }, + + // escape regex + escapeRegex: (str: string): string => { + const escapePatten = /[.*+\-?^$|(){}[\]\\]/g; // Special Regex Characters: ., *, +,-, ?, ^, $, |, (, ), {, }, [, ], \, ], + return str.replace(escapePatten, '\\$&'); // $& means the whole matched string + }, + + // convert string to regex + stringToRegex: (str: string): RegExp => new RegExp(str), // todo: need to update, multiple cases unhandled + + // convert string to price format + price: (str: string): number => + parseFloat( + str + .replace(/[^\d\-.,\\s]/g, '') + .replace(/,/g, '.') + .replace(/\.(?=.*\.)/g, ''), + ), + + // price as string + priceString: (num: number, choice: string): string => (choice === 'US' ? Number(num).toLocaleString('es-US') : Number(num).toLocaleString('es-ES')), + + // remove dollar sign + removeCurrencySign: (str: string): string => str.replace(/[^\d\-.,\\s]/g, ''), + + // dateFormat // todo: remove all datetime , and update date to return date as required formate // also method to return as site date format + dateFormatFYJ: (date: string) => new Date(date).toLocaleDateString('en-CA', { year: 'numeric', month: 'long', day: 'numeric' }), + + // current year + currentYear: new Date().getFullYear(), + + // current day [2023-06-02] + currentDate: new Date().toLocaleDateString('en-CA'), + + // current day [August 22, 2023] + currentDateFJY: new Date().toLocaleDateString('en-CA', { year: 'numeric', month: 'long', day: 'numeric' }), + + // current date-time [2023-06-02 00:33] + currentDateTime: new Date().toLocaleString('en-CA', { year: 'numeric', month: 'numeric', day: 'numeric', hourCycle: 'h23', hour: 'numeric', minute: 'numeric' }).replace(',', ''), + + // current date-time [2023-06-02 00:46:11] + currentDateTimeFullFormat: new Date().toLocaleString('en-CA', { year: 'numeric', month: 'numeric', day: 'numeric', hourCycle: 'h23', hour: 'numeric', minute: 'numeric', second: 'numeric' }).replace(',', ''), + + currentDateTime2: () => new Date().toLocaleString('en-CA', { year: 'numeric', month: 'numeric', day: 'numeric', hourCycle: 'h23', hour: 'numeric', minute: 'numeric', second: 'numeric' }).replace(',', ''), + + // add two input days + addDays(date: string | number | Date | null, days: number, format: string): string { + const result = date ? new Date(date) : new Date(); + result.setDate(result.getDate() + days); + + if (format === 'full') { + // [2023-06-02, 00:33] + return result.toLocaleDateString('en-CA', { year: 'numeric', month: 'numeric', day: 'numeric', hourCycle: 'h23', hour: 'numeric', minute: 'numeric' }).replace(/,/g, ''); + } else if (format === 'complete') { + // [2023-06-02 00:46:11] + return result.toLocaleDateString('en-CA', { year: 'numeric', month: 'numeric', day: 'numeric', hourCycle: 'h23', hour: 'numeric', minute: 'numeric', second: 'numeric' }).replace(/,/g, ''); + } else { + // [2023-06-02] + return result.toLocaleDateString('en-CA'); + } + }, + + // future date + futureDate(date: string | number | Date | null, days: number): Date { + const result = date ? new Date(date) : new Date(); + result.setDate(result.getDate() + days); + return result; + }, + + // round to two decimal + roundToTwo(num: string | number) { + return Math.round((Number(num) + Number.EPSILON) * 100) / 100; + }, + + // calculate percentage + percentage(number: number, percentage: number) { + return this.roundToTwo(number * (percentage / 100)); + }, + + // calculate percentage + percentage1(number: number, percentage: number) { + return (number * (percentage / 100)).toFixed(2); + }, + + // subtotal + subtotal(price: number[], quantity: number[]) { + const subtotal = price.map((e, index) => e * quantity[index]!); + return subtotal.reduce((a, b) => a + b, 0); + }, + + // product tax + productTax(taxRate: number, subtotal: number) { + const productTax = this.percentage(subtotal, taxRate); + return this.roundToTwo(productTax); + }, + + // product tax + shippingTax(taxRate: number, shippingFee = 0) { + const shippingTax = this.percentage(shippingFee, taxRate); + return this.roundToTwo(shippingTax); + }, + + // order total + orderTotal(subtotal: number, productTax = 0, shippingTax = 0, shippingFee = 0) { + const orderTotal = Number(subtotal) + Number(productTax) + Number(shippingTax) + Number(shippingFee); + return this.roundToTwo(orderTotal); + }, + + // calculate admin commission + adminCommission(subTotal: number, commission: any, productTax = 0, shippingTax = 0, shippingFee = 0, gatewayFee = 0, feeRecipient: any, gatewayFeeGiver = 'seller') { + let subTotalCommission = 0; + + switch (commission.type) { + case 'percentage': + subTotalCommission = this.percentage(Number(subTotal), Number(commission.amount)); + break; + + case 'flat': + subTotalCommission = Number(commission.amount); + break; + + case 'combine': + subTotalCommission = this.percentage(Number(subTotal), Number(commission.amount)) + Number(commission.additionalAmount); + break; + + default: + break; + } + + productTax = feeRecipient.taxFeeRecipient === 'seller' ? 0 : productTax; + shippingTax = feeRecipient.shippingTaxFeeRecipient === 'seller' ? 0 : shippingTax; + shippingFee = feeRecipient.shippingFeeRecipient === 'seller' ? 0 : shippingFee; + gatewayFee = gatewayFeeGiver === 'seller' ? 0 : gatewayFee; + + const adminCommission = subTotalCommission - Number(gatewayFee) + Number(productTax) + Number(shippingTax) + Number(shippingFee); + return this.roundToTwo(adminCommission); + }, + + // calculate vendor earning + vendorEarning(subTotal: number, commission: number, productTax = 0, shippingTax = 0, shippingFee = 0, gatewayFee = 0, feeRecipient: any, gatewayFeeGiver = 'seller') { + productTax = feeRecipient.taxFeeRecipient !== 'seller' ? 0 : productTax; + shippingTax = feeRecipient.shippingTaxFeeRecipient !== 'seller' ? 0 : shippingTax; + shippingFee = feeRecipient.shippingFeeRecipient !== 'seller' ? 0 : shippingFee; + gatewayFee = gatewayFeeGiver !== 'seller' ? 0 : gatewayFee; + + const vendorEarning = Number(subTotal) - Number(commission) - Number(gatewayFee) + Number(productTax) + Number(shippingTax) + Number(shippingFee); + return this.roundToTwo(vendorEarning); + }, + + // string to slug + slugify(str: string) { + return ( + str + .toString() // Cast to string (optional) + .normalize('NFKD') // The normalize() using NFKD method returns the Unicode Normalization Form of a given string. + .replace(/[\u0300-\u036f]/g, '') + .toLowerCase() // Convert the string to lowercase letters + .trim() // Remove whitespace from both sides of a string (optional) + .replace(/\s+/g, '-') // Replace spaces with - + .replace(/[^\w-]+/g, '') // Remove all non-word chars + // .replace(/\_/g, '-') // Replace _ with - + .replace(/--+/g, '-') // Replace multiple - with single - + .replace(/-$/g, '') + ); // Remove trailing - + }, + + // create env + createEnvVariable(key: string, value: string) { + const content = '\n' + key + '=' + value; + fs.appendFile('.env', content, 'utf8', err => { + if (err) throw err; + }); + }, + + // check file existence + fileExists(filePath: string) { + return fs.existsSync(filePath); + }, + + // read file + readFile(filePath: string) { + return fs.readFileSync(filePath, 'utf8'); + }, + + readJson(filePath: string) { + return JSON.parse(this.readFile(filePath)); + }, + + // write file + writeFile(filePath: string, content: string) { + fs.writeFileSync(filePath, content, { encoding: 'utf8' }); + }, + + // append file + appendFile(filePath: string, content: string) { + fs.appendFileSync(filePath, content, { encoding: 'utf8' }); + }, + + // rename file + renameFile(newFilePath: string, oldFilePath: string) { + fs.renameSync(newFilePath, oldFilePath); + }, + + // append content to .env file + appendEnv(content: string) { + content += '\n'; + this.appendFile('.env', content); + }, + + async createPage(browser: Browser, options?: BrowserContextOptions | undefined) { + const browserContext = await browser.newContext(options); + return browserContext.newPage(); + }, +}; diff --git a/tests/pw/utils/interfaces.ts b/tests/pw/utils/interfaces.ts new file mode 100644 index 0000000000..aff0bf8dc8 --- /dev/null +++ b/tests/pw/utils/interfaces.ts @@ -0,0 +1,1756 @@ +import fs from 'fs'; + +export interface admin { + username: string; + password: string; +} + +export interface plugin { + plugins: string[]; + pluginSlugs: string[]; + dokanPro: string[]; + activeClass: string; +} + +export interface woocommerce { + saveSuccessMessage: string; +} + +export interface adminDashboard { + summary: { + sales: { this_month: string }; + earning: { this_month: string }; + vendors: { this_month: string; inactive: string }; + products: { this_month: string }; + withdraw: { pending: string }; + }; +} + +export interface bookings { + startDate: Date; + endDate: Date; +} + +export interface bookingResource { + resourceName: () => string; + name: string; + quantity: string; +} + +// Product +export interface product { + publishSuccessMessage: string; + draftUpdateSuccessMessage: string; + pendingProductUpdateSuccessMessage: string; + createUpdateSaveSuccessMessage: string; + + status: { + publish: string; + draft: string; + pending: string; + }; + + stockStatus: { + outOfStock: string; + }; + + tax: { + status: string; + taxClass: string; + }; + + type: { + simple: string; + variable: string; + simpleSubscription: string; + variableSubscription: string; + external: string; + vendorSubscription: string; + booking: string; + auction: string; + }; + + name: { + simple: () => string; + variable: () => string; + external: () => string; + grouped: () => string; + simpleSubscription: () => string; + variableSubscription: () => string; + dokanSubscription: { + nonRecurring: () => string; + length: 5; + casing: string; + }; + booking: () => string; + auction: () => string; + }; + + price: { + price_int: () => string; + price_random: () => string; + price_frac: () => string; + price_frac_comma: () => string; + auctionPrice: () => string; + price: () => string; + }; + + category: { + unCategorized: string; + clothings: string; + randomCategory1: () => string; + randomCategory: () => string; + categories: string; + }; + + store: { + adminStore: string; + vendorStore1: string; + }; + + attribute: { + attributeName: string; + attributeTerms: string[]; + }; + + simple: { + productType: string; + productName: () => string; + category: string; + regularPrice: () => string; + storeName: string; + status: string; + stockStatus: boolean; + editProduct: string; + }; + + variable: { + productType: string; + productName: () => string; + category: string; + regularPrice: () => string; + storeName: string; + status: string; + stockStatus: boolean; + attribute: string; + attributeTerms: string[]; + variations: { + linkAllVariation: string; + variableRegularPrice: string; + }; + saveSuccessMessage: string; + }; + + external: { + productType: string; + productName: () => string; + productUrl: string; + buttonText: string; + category: string; + regularPrice: () => string; + storeName: string; + status: string; + saveSuccessMessage: string; + }; + + simpleSubscription: { + productType: string; + productName: () => string; + category: string; + regularPrice: () => string; + subscriptionPrice: () => string; + subscriptionPeriodInterval: string; + subscriptionPeriod: string; + expireAfter: string; + subscriptionTrialLength: string; + subscriptionTrialPeriod: string; + storeName: string; + status: string; + saveSuccessMessage: string; + }; + + variableSubscription: { + productType: string; + productName: () => string; + category: string; + regularPrice: () => string; + subscriptionPrice: () => string; + subscriptionPeriodInterval: string; + subscriptionPeriod: string; + expireAfter: string; + subscriptionTrialLength: string; + subscriptionTrialPeriod: string; + storeName: string; + status: string; + attribute: string; + attributeTerms: string[]; + variations: { + linkAllVariation: string; + variableRegularPrice: string; + }; + saveSuccessMessage: string; + }; + + vendorSubscription: { + productType: string; + productName: () => string; + category: string; + regularPrice: () => string; + numberOfProducts: string; + packValidity: string; + advertisementSlot: string; + expireAfterDays: string; + storeName: string; + status: string; + }; + + booking: { + productName: () => string; + name: string; + productType: string; + category: string; + bookingDurationType: string; + bookingDuration: string; + bookingDurationMin: string; + bookingDurationMax: string; + bookingDurationUnit: string; + calendarDisplayMode: string; + maxBookingsPerBlock: string; + minimumBookingWindowIntoTheFutureDate: string; + minimumBookingWindowIntoTheFutureDateUnit: string; + maximumBookingWindowIntoTheFutureDate: string; + maximumBookingWindowIntoTheFutureDateUnit: string; + baseCost: string; + blockCost: string; + storeName: string; + saveSuccessMessage: string; + }; + + bookingResource: { + name: string; + quantity: string; + }; + + // Auction + auction: { + productName: () => string; + name: string; + productType: string; + category: string; + itemCondition: string; + auctionType: string; + regularPrice: () => string; + bidIncrement: () => string; + reservedPrice: () => string; + buyItNowPrice: () => string; + startDate: string; + endDate: string; + storeName: string; + saveSuccessMessage: string; + }; + + // Review + review: { + rating: string; + reviewMessage: () => string; + }; + + // Report + report: { + reportReason: string; + reportReasonDescription: string; + reportSubmitSuccessMessage: string; + + username: string; + password: string; + + guestName: () => string; + guestEmail: () => string; + }; + + // Enquiry + enquiry: { + enquiryDetails: string; + enquirySubmitSuccessMessage: string; + + guestName: () => string; + guestEmail: () => string; + }; +} + +// order +export interface order { + orderStatus: { + pending: string; + processing: string; + onhold: string; + completed: string; + cancelled: string; + refunded: string; + failed: string; + }; + + // Refund + requestWarranty: { + itemQuantity: string; + refundRequestType: string; + refundRequestReasons: string; + refundRequestDetails: string; + refundSubmitSuccessMessage: string; + }; +} + +export interface orderNote { + note: string; + noteType: string; +} + +export interface orderTrackingDetails { + shippingProvider: string; + trackingNumber: string; + dateShipped: string; +} + +export interface orderShipmentDetails { + shipmentOrderItem: string; + shipmentOrderItemQty: string; + shippingStatus: string; + shippingProvider: string; + dateShipped: string; + trackingNumber: string; + comments: string; +} + +// payment details +export interface paymentDetails { + strip: { + striptNon3D: string; + stript3D: string; + cardNumber: string; + expiryMonth: string; + expiryYear: string; + number: string; + expiryDate: string; + cvc: string; + }; + + mangopay: { + creditCard: string; + expiryMonth: string; + expiryYear: string; + cvc: string; + }; + + stripExpress: { + paymentMethod: string; + cardInfo: { + cardNumber: string; + expiryMonth: string; + expiryYear: string; + expiryDate: string; + cvc: string; + }; + }; +} + +// coupon +export interface coupon { + couponTitle: () => string; + title: string; + amount: () => string; + discountType: string; + description: string; + existingCouponErrorMessage: string; + editCoupon: string; +} + +// address +export interface address { + street1: string; + street2: string; + country: string; + countrySelectValue: string; + stateSelectValue: string; + city: string; + zipCode: string; + state: string; +} + +export interface wpSettings { + saveSuccessMessage: string; + general: { + timezone: string; + saveSuccessMessage: string; + }; + + permalink: { + customBaseInput: string; + saveSuccessMessage: string; + }; +} + +export interface tax { + taxRate: string; + enableTax: boolean; + saveSuccessMessage: string; +} + +export interface shipping { + enableShipping: string; + disableShipping: string; + shippingZone: string; + + shippingMethods: { + methods: string; + + flatRate: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + shippingCost: string; + }; + + freeShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + freeShippingRequires: string; + freeShippingMinimumOrderAmount: string; + }; + + localPickup: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + shippingCost: string; + }; + + tableRateShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + }; + + distanceRateShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + }; + + vendorShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + }; + }; + + shippingTaxStatus: string; + saveSuccessMessage: string; +} + +export interface deliveryTime { + date: string; +} + +export interface payment { + saveSuccessMessage: string; + + currency: { + dollar: string; + euro: string; + rupee: string; + + currencyOptions: { + thousandSeparator: string; + decimalSeparator: string; + numberOfDecimals: string; + }; + + saveSuccessMessage: string; + }; + + basicPayment: { + toggleEanbledClass: string; + toggleDisabledClass: string; + }; + + stripeConnect: { + title: string; + description: string; + displayNoticeInterval: string; + stripeCheckoutLocale: string; + testPublishableKey: string; + testSecretKey: string; + testClientId: string; + }; + + paypalMarketPlace: { + title: string; + description: string; + payPalMerchantId: string; + sandboxClientId: string; + sandBoxClientSecret: string; + payPalPartnerAttributionId: string; + disbursementMode: string; + paymentButtonType: string; + marketplaceLogoPath: string; + announcementInterval: string; + }; + + mangoPay: { + title: string; + description: string; + sandboxClientId: string; + sandBoxApiKey: string; + availableCreditCards: string; + availableDirectPaymentServices: string; + transferFunds: string; + typeOfVendors: string; + businessRequirement: string; + announcementInterval: string; + }; + + razorPay: { + title: string; + description: string; + testKeyId: string; + testKeySecret: string; + disbursementMode: string; + announcementInterval: string; + }; + + stripeExpress: { + title: string; + description: string; + testPublishableKey: string; + testSecretKey: string; + testWebhookSecret: string; + paymentMethods: { + card: string; + ideal: string; + }; + iDealBanks: string; + disbursementMode: string; + customerBankStatement: string; + paymentRequestButtonType: string; + paymentRequestButtonTheme: string; + paymentRequestButtonLocation: { + product: string; + cart: string; + }; + announcementInterval: string; + }; +} + +// Dokan Setup Wizard +export interface dokanSetupWizard { + vendorStoreURL: string; + shippingFeeRecipient: string; + taxFeeRecipient: string; + mapApiSource: string; + googleMapApiKey: string; + sellingProductTypes: string; + commissionType: string; + adminCommission: string; + minimumWithdrawLimit: string; +} + +// Vendor Setup Wizard +export interface vendorSetupWizard { + choice: boolean; + storeProductsPerPage: string; + street1: string; + street2: string; + country: string; + city: string; + zipCode: string; + state: string; + storeCategory: string; + mapLocation: string; + paypal: () => string; + bankAccountName: string; + bankAccountType: string; + bankAccountNumber: string; + bankName: string; + bankAddress: string; + bankRoutingNumber: string; + bankIban: string; + bankSwiftCode: string; + customPayment: string; + skrill: string; +} + +// user +export interface user { + username: () => string; + password: string; + + userDetails: { + emailDomain: string; + name: () => string; + firstName: () => string; + lastName: () => string; + email: () => string; + role: string; + }; +} + +// vendor +export interface vendor { + username: string; + password: string; + lastname: string; + storeName: string; + + vendorInfo: { + email: () => string; + // emailDomain: string; + emailDomain: string; + password: string; + password1: string; + firstName: () => string; + lastName: () => string; + userName: string; + shopName: () => string; + shopUrl: () => string; + companyName: string; + companyId: string; + vatNumber: string; + bankIban: string; + phoneNumber: string; + phone: string; + street1: string; + street2: string; + country: string; + countrySelectValue: string; + stateSelectValue: string; + city: string; + zipCode: string; + state: string; + accountName: string; + accountNumber: string; + bankName: string; + bankAddress: string; + routingNumber: string; + swiftCode: string; + iban: string; + role: string; + nanoid: string; + + // shop details + banner: string; + profilePicture: string; + storeName: string; + productsPerPage: string; + mapLocation: string; + termsAndConditions: string; + biography: string; + supportButtonText: string; + + openingClosingTime: { + days: string[]; + statusLite: string; + openingTime: string; + closingTime: string; + storeOpenNotice: string; + storeCloseNotice: string; + }; + + vacation: { + closingStyle: string; + + instantly: { + closingStyle: string; + vacationMessage: string; + }; + + datewise: { + vacationDayFrom: () => string; + vacationDayTo: (arg0: string) => string; + closingStyle: string; + vacationMessage: string; + }; + }; + + amountDiscount: { + minimumOrderAmount: string; + discountPercentage: string; + }; + + quantityDiscount: { + minimumQuantity: string; + discountPercentage: string; + }; + + minMax: { + minimumProductQuantity: string; + maximumProductQuantity: string; + minimumAmount: string; + maximumAmount: string; + category: string; + }; + + storeSettingsSaveSuccessMessage: string; + + socialProfileUrls: { + facebook: string; + twitter: string; + pinterest: string; + linkedin: string; + youtube: string; + instagram: string; + flickr: string; + }; + + payment: { + email: () => string; + bankAccountName: string; + bankAccountType: string; + bankAccountNumber: string; + bankName: string; + bankAddress: string; + bankRoutingNumber: string; + bankIban: string; + bankSwiftCode: string; + }; + + sendEmail: { + subject: string; + message: string; + }; + }; + + shipping: { + shippingPolicy: { + processingTime: string; + shippingPolicy: string; + refundPolicy: string; + saveSuccessMessage: string; + }; + + shippingZone: string; + shippingCountry: string; + methods: string; + + shippingMethod: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + shippingCost: string; + description: string; + calculationType: string; + shippingMethodSaveSuccessMessage: string; + zoneSaveSuccessMessage: string; + saveSuccessMessage: string; + + freeShippingRequires: string; + freeShippingMinimumOrderAmount: string; + + taxIncludedInShippingCosts: string; + handlingFee: string; + maximumShippingCost: string; + + handlingFeePerOrder: string; + minimumCostPerOrder: string; + maximumCostPerOrder: string; + + tableRateSaveSuccessMessage: string; + + transportationMode: string; + avoid: string; + distanceUnit: string; + street1: string; + street2: string; + city: string; + zipCode: string; + state: string; + country: string; + + distanceRateSaveSuccessMessage: string; + }; + + shippingMethods: { + flatRate: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + shippingCost: string; + description: string; + calculationType: string; + shippingMethodSaveSuccessMessage: string; + zoneSaveSuccessMessage: string; + saveSuccessMessage: string; + }; + + freeShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + freeShippingRequires: string; + freeShippingMinimumOrderAmount: string; + shippingMethodSaveSuccessMessage: string; + zoneSaveSuccessMessage: string; + saveSuccessMessage: string; + }; + + localPickup: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + shippingCost: string; + description: string; + shippingMethodSaveSuccessMessage: string; + zoneSaveSuccessMessage: string; + saveSuccessMessage: string; + }; + + tableRateShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + taxIncludedInShippingCosts: string; + handlingFee: string; + maximumShippingCost: string; + calculationType: string; + handlingFeePerOrder: string; + minimumCostPerOrder: string; + maximumCostPerOrder: string; + shippingMethodSaveSuccessMessage: string; + zoneSaveSuccessMessage: string; + saveSuccessMessage: string; + tableRateSaveSuccessMessage: string; + }; + + distanceRateShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + transportationMode: string; + avoid: string; + distanceUnit: string; + street1: string; + street2: string; + city: string; + zipCode: string; + state: string; + country: string; + shippingMethodSaveSuccessMessage: string; + zoneSaveSuccessMessage: string; + saveSuccessMessage: string; + distanceRateSaveSuccessMessage: string; + }; + + vendorShipping: { + shippingZone: string; + shippingCountry: string; + selectShippingMethod: string; + shippingMethod: string; + taxStatus: string; + }; + }; + + shippingTaxStatus: string; + saveSuccessMessage: string; + }; + + payment: { + methodName: string; + email: () => string; + bankAccountName: string; + bankAccountType: string; + bankAccountNumber: string; + bankName: string; + bankAddress: string; + bankRoutingNumber: string; + bankIban: string; + bankSwiftCode: string; + saveSuccessMessage: string; + }; + + verification: { + 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: { + deliveryBlockedBuffer: string; + timeSlot: string; + orderPerSlot: string; + days: string[]; + choice: string; + openingTime: string; + closingTime: string; + fullDay: string; + saveSuccessMessage: string; + }; + + shipStation: { + status: string; + }; + + socialProfileUrls: { + facebook: string; + twitter: string; + pinterest: string; + linkedin: string; + youtube: string; + instagram: string; + flickr: string; + saveSuccessMessage: string; + }; + + // Rma Settings + rma: { + label: string; + type: string; + rmaLength: string; + lengthValue: string; + lengthDuration: string; + refundPolicyHtmlBody: string; + saveSuccessMessage: string; + }; + + seo: { + seoTitle: string; + metaDescription: string; + metaKeywords: string; + facebookTitle: string; + facebookDescription: string; + twitterTitle: string; + twitterDescription: string; + }; + + withdraw: { + withdrawMethod: { + default: string; + paypal: string; + skrill: string; + custom: string; + }; + + defaultWithdrawMethod: { + paypal: string; + skrill: string; + bankTransfer: string; + }; + preferredPaymentMethod: string; + preferredSchedule: string; + currentBalance: string; + minimumWithdrawAmount: string; + reservedBalance: string; + scheduleMessageInitial: string; + }; + + // addon + addon: { + randomName: () => string; + name: string; + priority: string; + category: string; + type: string; + displayAs: string; + titleRequired: string; + formatTitle: string; + addDescription: string; + enterAnOption: string; + optionPriceType: string; + optionPriceInput: string; + saveSuccessMessage: string; + deleteSuccessMessage: string; + }; + + registrationErrorMessage: string; +} + +// staff +export interface staff { + firstName: string; + lastName: string; + // fullName: string; + email: string; + phone: string; + password: string; + // firstName: () => string; + // lastName: () => string; + // fullName: () => string; + // email: () => string; + // phone: () => string; + // password: string; +} + +// customer +export interface customer { + username: string; + password: string; + lastname: string; + + customerInfo: { + emailDomain: string; + email: () => string; + password: string; + password1: string; + firstName: () => string; + lastName: () => string; + role: string; + username: () => string; + shopName: () => string; + companyName: string; + companyId: string; + vatNumber: string; + bankIban: string; + phone: string; + street1: string; + street2: string; + country: string; + countrySelectValue: string; + stateSelectValue: string; + city: string; + zipCode: string; + state: string; + accountName: string; + accountNumber: string; + bankName: string; + bankAddress: string; + routingNumber: string; + swiftCode: string; + iban: string; + biography: string; + billing: { + firstName: string; + lastName: string; + companyName: string; + companyId: string; + vatNumber: string; + bankName: string; + bankIban: string; + street1: string; + street2: string; + city: string; + zipCode: string; + country: string; + state: string; + email: string; + phone: string; + }; + + shipping: { + firstName: string; + lastName: string; + companyName: string; + street1: string; + street2: string; + city: string; + zipCode: string; + country: string; + state: string; + phone: string; + }; + }; + + getSupport: { + subject: string; + message: string; + orderId: string; + supportSubmitSuccessMessage: string; + username: string; + userPassword: string; + }; + + supportTicket: { + message: () => string; + }; + + rma: { + sendMessage: string; + }; + + account: { + updateSuccessMessage: string; + }; + + follow: { + following: string; + }; + + address: { + addressChangeSuccessMessage: string; + }; + + registration: { + registrationErrorMessage: string; + }; +} + +// date +export interface date { + previousDate: string; + currentDate: string; + nextDay: string; + + dateRange: { + startDate: string; + endDate: string; + }; + + dateRangeFull: { + startDate: string; + endDate: string; + }; +} + +// store category +export interface storeCategory { + name: string; + description: string; +} + +// store review +export interface storeReview { + review: { + rating: string; + ratingByWidth: string; + title: string; + content: string; + }; + filter: { + byVendor: string; + }; +} + +export interface reverseWithdraw { + store: string; + transactionType: string; + product: string; + withdrawalBalanceType: string; + amount: string; + note: string; +} + +// // store support +// export interface storeSupport { + +// title: string; +// filter: { +// byCustomer: string; +// byVendor: string; +// } +// chatReply: { +// asAdmin: string; +// asVendor: string; +// } + +// } + +// request for quotation +export interface requestForQuotation { + userRole: { + administrator: string; + editor: string; + author: string; + contributor: string; + subscriber: string; + customer: string; + shopManager: string; + vendor: string; + vendorStaff: string; + wholesaleCustomer: string; + guest: string; + }; + + quoteRule: { + title: string; + userRole: string; + product: string; + category: string; + hidePrice: string; + hidePriceText: string; + hideAddToCartButton: string; + customButtonLabel: string; + order: string; + }; + + updateQuoteRule: { + title: string; + userRole: string; + product: string; + category: string; + hidePrice: string; + hidePriceText: string; + hideAddToCartButton: string; + customButtonLabel: string; + order: string; + }; + + trashedQuoteRule: { + title: string; + status: string; + }; + + quote: { + title: string; + user: string; + fullName: string; + email: string; + companyName: string; + phoneNumber: string; + product: string; + quantity: string; + offerPrice: string; + offerProductQuantity: string; + }; + + updateQuote: { + title: string; + user: string; + fullName: string; + email: string; + companyName: string; + phoneNumber: string; + product: string; + offerPrice: string; + offerProductQuantity: string; + }; + + trashedQuote: { + title: string; + status: string; + }; + + convertedQuote: { + title: string; + }; + + userQuote: { + productName: string; + offeredPrice: string; + quantity: string; + }; + + guest: { + fullName: string; + email: string; + companyName: string; + phoneNumber: string; + }; +} + +// seller badge +export interface sellerBadge { + eventName: { + // product related badges + productsPublished: string; + numberOfItemsSold: string; + featuredProducts: string; + trendingProduct: string; + + // seller related badges + featuredSeller: string; + exclusiveToPlatform: string; + verifiedSeller: string; + yearsActive: string; + + // Order Related Badges + numberOfOrders: string; + // Sale Amount Related Badges + saleAmount: string; + + // Customer Related Badges + customerReview: string; + storeSupportCount: string; + }; + + badgeName: string; + verificationMethod: string; + trendingProductPeriod: string; + trendingProductTopBestSellingProduct: string; + + startingLevelValue: string; + maxLevel: number; + + verifiedSellerMethod: { + idVerification: string; + companyVerification: string; + addressVerification: string; + phoneVerification: string; + socialProfiles: string; + }; + + badgeStatus: string; // published, draft +} + +// announcement +export interface announcement { + randomTitle: () => string; + title: string; + content: string; + receiver: string; + publishType: string; + scheduleDate: Date; +} + +export interface modules { + noModuleMessage: string; + modules: string[]; + modulesName: { + AuctionIntegration: string; + ColorSchemeCustomize: string; + DeliveryTime: string; + Elementor: string; + EUComplianceFields: string; + FollowStore: string; + }; + + moduleCategory: { + productManagement: string; + integration: string; + uiUx: string; + shipping: string; + storeManagement: string; + payment: string; + orderManagement: string; + vendorManagement: string; + }; + + layout: { + grid: string; + list: string; + }; +} + +// tools +export interface tools { + distanceMatrixApi: { + address1: string; + address2: string; + address3: string; + address4: string; + }; +} + +// product advertisement +export interface productAdvertisement { + advertisedProductStore: string; + advertisedProduct: string; + + filter: { + byStore: string; + createVia: { + admin: string; + order: string; + subscription: string; + freePurchase: string; + }; + }; +} + +// wholesale customers +export interface wholesale { + wholesaleRequestSendMessage: string; + becomeWholesaleCustomerSuccessMessage: string; + wholesaleCapabilityActivate: string; +} + +// dokan settings +export interface dokanSettings { + // General Settings + general: { + vendorStoreUrl: string; + setupWizardMessage: string; + sellingProductTypes: string; + storeProductPerPage: string; + storCategory: string; + saveSuccessMessage: string; + }; + + // Selling Options Settings + selling: { + commissionType: string; + adminCommission: string; + shippingFeeRecipient: string; + productTaxFeeRecipient: string; + shippingTaxFeeRecipient: string; + newProductStatus: string; + productCategorySelection: string; + saveSuccessMessage: string; + }; + + // Withdraw + withdraw: { + customMethodName: string; + customMethodType: string; + minimumWithdrawAmount: string; + withdrawThreshold: string; + quarterlyScheduleMonth: string; + quarterlyScheduleWeek: string; + quarterlyScheduleDay: string; + monthlyScheduleWeek: string; + monthlyScheduleDay: string; + biweeklyScheduleWeek: string; + biweeklyScheduleDay: string; + weeklyScheduleDay: string; + saveSuccessMessage: string; + }; + + // Reverse withdraw + reverseWithdraw: { + billingType: string; + reverseBalanceThreshold: string; + gracePeriod: string; + saveSuccessMessage: string; + }; + + // Pages + page: { + dashboard: string; + myOrders: string; + storeListing: string; + termsAndConditions: string; + saveSuccessMessage: string; + }; + + // Appearance + appearance: { + googleMapApiKey: string; + mapBoxApiKey: string; + storeBannerWidth: string; + storeBannerHeight: string; + saveSuccessMessage: string; + }; + + // privacy policy + privacyPolicy: { + privacyPage: string; + privacyPolicyContent: string; + saveSuccessMessage: string; + }; + + // colors + colors: { + paletteChoice: string; + colorPalette: string; + saveSuccessMessage: string; + }; + + // shipping status + shippingStatus: { + customShippingStatus: string; + saveSuccessMessage: string; + }; + + // quote + quote: { + decreaseOfferedPrice: string; + saveSuccessMessage: string; + }; + + // live search + liveSearch: { + liveSearchOption: string; + saveSuccessMessage: string; + }; + + // Store support + storeSupport: { + displayOnSingleProductPage: string; + supportButtonLabel: string; + saveSuccessMessage: string; + }; + + // Email verification + emailVerification: { + registrationNotice: string; + loginNotice: string; + saveSuccessMessage: string; + }; + + // Rma Settings + rma: { + orderStatus: string; + rmaReasons: string[]; + refundPolicyHtmlBody: string; + saveSuccessMessage: string; + }; + + // Wholesale + wholesale: { + whoCanSeeWholesalePrice: string; + saveSuccessMessage: string; + }; + + // EuCompliance + euCompliance: { + saveSuccessMessage: string; + }; + + // delivery time + deliveryTime: { + deliveryDateLabel: string; + deliveryBlockedBuffer: string; + deliveryBoxInfo: string; + days: string[]; + choice: string; + openingTime: string; + closingTime: string; + timeSlot: string; + orderPerSlot: string; + saveSuccessMessage: string; + }; + + // Product advertising + productAdvertising: { + noOfAvailableSlot: string; + expireAfterDays: string; + advertisementCost: string; + saveSuccessMessage: string; + }; + + // Geolocation Settings + geolocation: { + locationMapPosition: string; + showMap: string; + radiusSearchUnit: string; + radiusSearchMinimumDistance: string; + radiusSearchMaximumDistance: string; + mapZoomLevel: string; + defaultLocation: string; + saveSuccessMessage: string; + }; + + // Product report abuse + productReportAbuse: { + reasonsForAbuseReport: string; + saveSuccessMessage: string; + }; + + // Spmv Settings + spmv: { + sellItemButtonText: string; + availableVendorDisplayAreaTitle: string; + availableVendorSectionDisplayPosition: string; + showSpmvProducts: string; + saveSuccessMessage: string; + }; + + // Vendor Subscription Settings + vendorSubscription: { + displayPage: string; + noOfDays: string; + productStatus: string; + cancellingEmailSubject: string; + cancellingEmailBody: string; + alertEmailSubject: string; + alertEmailBody: string; + saveSuccessMessage: string; + }; +} + +// dokan license +export interface dokanLicense { + correctKey: string; + incorrectKey: string; +} + +// predefined test data +export interface predefined { + simpleProduct: { + product1: { + name: string; + productName: () => string; + }; + product2: string; + productFrac1: string; + productFrac2: string; + }; + + variableProduct: { + product1: string; + }; + + simpleSubscription: { + product1: string; + }; + + variableSubscription: { + product1: string; + }; + + externalProduct: { + product1: string; + }; + + auctionProduct: { + product1: string; + }; + + bookingProduct: { + product1: string; + }; + + saleProduct: { + product1: string; + }; + + vendorSubscription: { + nonRecurring: string; + }; + + coupon: { + couponCode: string; + }; + + vendorInfo: { + firstName: () => string; + lastName: () => string; + username: string; + shopName: string; + }; + + vendorStores: { + followFromShopPage: string; + followFromStorePage: string; + vendor1: string; + shopUrl: string; + }; + + customerInfo: { + firstName: () => string; + lastName: () => string; + username: () => string; + username1: string; + }; +} + +export interface storeShare { + name: string; + url: string; +} + +// install wordpress +export interface installWp { + // db info + dbHost: string; + dbUserName: string; + dbPassword: string; + dbName: string; + dbTablePrefix: string; + + // site info + siteTitle: string; + adminUserName: string; + adminPassword: string; + adminEmail: string; +} + +// api interfaces + +export interface auth { + [key: string]: string; + Authorization: string; +} + +export interface user_api { + username: string; + password: string; +} + +export interface taxRate { + // [key: string]: string | number | boolean | string []; + country: string; + state: string; + postcode: string; + city: string; + rate: string; + name: string; + priority: number; + compound: boolean; + shipping: boolean; + order: number; + class: string; + postcodes: string[]; + cities: string[]; +} + +export interface coupon_api { + code: string; + amount: string; + discount_type: string; + product_ids: number[]; + individual_use?: boolean; + meta_data?: { key: string; value: string }[]; +} + +export interface marketPlaceCoupon { + code: string; + amount: string; + discount_type: string; + individual_use?: boolean; + meta_data?: { key: string; value: string }[]; +} + +export interface reqOptions { + data?: any; + failOnStatusCode?: boolean | undefined; + form?: Record | undefined; + headers?: Record | undefined; + ignoreHTTPSErrors?: boolean | undefined; + maxRedirects?: number | undefined; + multipart?: Record | undefined; + params?: Record | undefined; + timeout?: number | undefined; +} + +export type headers = Record; + +export interface storageState { + cookies: { + name: string; + value: string; + domain: string; + path: string; + expires: number; + httpOnly: boolean; + secure: boolean; + sameSite: 'Strict' | 'Lax' | 'None'; + }[]; + origins: { + origin: string; + localStorage: { + name: string; + value: string; + }[]; + }[]; +} + +// eslint-disable-next-line @typescript-eslint/no-explicit-any +export type responseBody = any; diff --git a/tests/pw/utils/payloads.ts b/tests/pw/utils/payloads.ts new file mode 100644 index 0000000000..d277b89564 --- /dev/null +++ b/tests/pw/utils/payloads.ts @@ -0,0 +1,2976 @@ +import { faker } from '@faker-js/faker'; +import { helpers } from '@utils/helpers'; +import { dbData } from '@utils/dbData'; + +const basicAuth = (username: string, password: string) => 'Basic ' + Buffer.from(username + ':' + password).toString('base64'); + +export const payloads = { + // wp + createPost: { + title: 'Hello rk', + content: 'My Post Content.', + status: 'publish', + }, + + createMedia: { + title: 'avatar', + alt_text: 'avatar_img', + status: 'publish', + post: '1', + }, + + createPage: () => ({ + title: 'test-page_' + faker.string.nanoid(10), + status: 'publish', + }), + + tocPage: { + title: 'Terms And Conditions', + status: 'publish', + }, + + mediaAttributes: { + title: 'avatar', + caption: 'avatar_img', + description: 'avatar_img', + alt_text: 'avatar_img', + }, + + mimeTypes: { + csv: 'text/csv', + png: 'image/png', + jpeg: 'image/jpeg', + pdf: 'application/pdf', + txt: 'text/plain', + json: 'application/json', + xml: 'application/xml', + zip: 'application/zip', + }, + + // user auth + + adminAuth: { + Authorization: basicAuth(process.env.ADMIN, process.env.ADMIN_PASSWORD), + }, + + vendorAuth: { + Authorization: basicAuth(process.env.VENDOR, process.env.USER_PASSWORD), + }, + + vendor2Auth: { + Authorization: basicAuth(process.env.VENDOR2, process.env.USER_PASSWORD), + }, + + customerAuth: { + Authorization: basicAuth(process.env.CUSTOMER, process.env.USER_PASSWORD), + }, + + admin: { + username: process.env.ADMIN, + password: process.env.ADMIN_PASSWORD, + }, + + vendor: { + username: process.env.VENDOR, + password: process.env.USER_PASSWORD, + }, + + customer: { + username: process.env.CUSTOMER, + password: process.env.USER_PASSWORD, + }, + + setupStore: { + store_name: 'admin_store', + trusted: true, + enabled: true, + payment: { + paypal: { + 0: 'email', + email: 'paypal@g.c', + }, + }, + }, + + // product + + createProduct: () => ({ + name: faker.commerce.productName() + ' (Simple)', + type: 'simple', + regular_price: faker.finance.amount(100, 200, faker.helpers.arrayElement([0, 2])), + // regular_price: '114.15' , // failed for this price & 5% tax & 10% commission dokan .1 issue + status: 'publish', + categories: [ + { + // id: 48 + name: 'Uncategorized', + slug: 'uncategorized', + }, + ], + featured: true, + description: '

    test description

    ', + short_description: '

    test short description

    ', + meta_data: [ + { + key: '_dokan_geolocation_use_store_settings', + value: 'yes', + }, + { + key: 'dokan_geo_latitude', + value: '40.7127753', + }, + { + key: 'dokan_geo_longitude', + value: '-74.0059728', + }, + { + key: 'dokan_geo_public', + value: '1', + }, + { + key: 'dokan_geo_address', + value: 'New York, NY, USA', + }, + { + key: '_dokan_rma_override_product', + value: 'yes', + }, + { + key: '_dokan_rma_settings', + value: { + label: 'Warranty', + type: 'included_warranty', + policy: 'test refund policy', + reasons: ['defective'], + length: 'lifetime', + length_value: '', + length_duration: '', + addon_settings: [], + }, + }, + // { + // key : '_dokan_min_max_meta', + // value: { + // product_wise_activation: 'yes', + // min_quantity : 0, + // max_quantity : 0, + // min_amount : 0, + // max_amount : 0, + // _donot_count : 'no', + // ignore_from_cat : 'no' + // } + // }, + // { + // key : '_product_addons', + // value: [] + // }, + // { + // key : '_product_addons_exclude_global', + // value: '0' + // }, + // { + // key : '_per_product_admin_commission_type', + // value: 'flat' + // }, + // { + // key : '_per_product_admin_commission', + // value: '' + // }, + // { + // key : '_per_product_admin_additional_fee', + // value: '' + // }, + // { + // key : '_has_multi_vendor', + // value: '18' + // }, + // { + // key : '_dokan_catalog_mode', + // value: { + // hide_add_to_cart_button: 'off', + // hide_product_price : 'off' + // } + // }, + // { + // key : '_disable_shipping', + // value: 'no' + // }, + // { + // key : '_overwrite_shipping', + // value: 'no' + // }, + ], + }), + + // wholesale product + createWholesaleProduct: () => ({ + name: faker.commerce.productName() + ' (wholesale)', + type: 'simple', + regular_price: faker.finance.amount(100, 110, faker.helpers.arrayElement([0, 2])), + // regular_price: '114.15' , // failed for this price & 5% tax & 10% commission dokan .1 issue + status: 'publish', + categories: [ + { + // id: 48 + name: 'Uncategorized', + slug: 'uncategorized', + }, + ], + featured: true, + description: '

    test description

    ', + short_description: '

    test short description

    ', + meta_data: [ + { + key: '_dokan_wholesale_meta', + value: { + enable_wholesale: 'yes', + price: faker.finance.amount(90, 99, faker.helpers.arrayElement([0, 2])), + // price: '100', + quantity: '10', + }, + }, + ], + }), + + createVariableProduct: () => ({ + name: faker.commerce.productName() + ' (Variable)', + type: 'variable', + regular_price: faker.finance.amount(100, 200, faker.helpers.arrayElement([0, 2])), + status: 'publish', + categories: [ + { + // id: 48 + name: 'Uncategorized', + slug: 'uncategorized', + }, + ], + // attributes: [ + // { + // 'id' : 28, + // 'visible' : true, + // 'variation': true, + // 'options' : [ + // 'l', + // 'm', + // 's' + // ] + // } + // ], + }), + + createProductVariation: { + // id: '47', + regular_price: faker.finance.amount(100, 200, faker.helpers.arrayElement([0, 2])), + status: 'publish', + categories: [ + { + // id: 48 + name: 'Uncategorized', + slug: 'uncategorized', + }, + ], + attributes: [ + { + id: 18, + // name: 'size', + option: 'l', + }, + ], + }, + + batchProductVariation: { + id: '', + regular_price: '99.00', + }, + + createDownloadableProduct: () => ({ + name: faker.commerce.productName() + ' (Downloadable)', + type: 'simple', + downloadable: true, + regular_price: faker.finance.amount(100, 200, faker.helpers.arrayElement([0, 2])), + downloads: [], + // download_limit: 100, + // download_expiry: 100, + categories: [ + { + // id: 48 + }, + ], + }), + + createSimpleSubscriptionProduct: () => ({ + name: faker.commerce.productName() + ' (Subscription)', + type: 'subscription', + status: 'publish', + featured: true, + description: '

    test description

    \n', + short_description: '

    test short description

    \n', + price: '100', + regular_price: '100', + categories: [{}], + meta_data: [ + { + key: '_subscription_price', + value: '100', + }, + { + key: '_subscription_period_interval', // every 1st, 2nd, .. month + value: '1', + }, + { + key: '_subscription_period', + value: 'month', + }, + { + key: '_subscription_length', // expire after + value: '0', + }, + // { + // "key": "_subscription_trial_length", + // "value": "5" + // }, + // { + // "key": "_subscription_sign_up_fee", + // "value": "10" + // }, + // { + // "key": "_subscription_trial_period", + // "value": "day" + // }, + // { + // "key": "_subscription_one_time_shipping", + // "value": "no" + // }, + // { + // "key": "_subscription_payment_sync_date", + // "value": "0" + // } + ], + }), + + createBookableProduct: () => ({ + name: faker.commerce.productName() + ' (Bookable)', + status: 'publish', + featured: true, + description: '

    test description

    ', + short_description: '

    test short description

    ', + categories: [{}], + duration_type: 'customer', + duration_unit: 'day', + duration: 1, + min_duration: 1, + max_duration: 10, + calendar_display_mode: 'always_visible', + enable_range_picker: true, + requires_confirmations: false, + can_be_cancelled: false, + default_date_availability: 'available', + block_cost: 5, + cost: 10, + has_persons: false, + has_resources: false, + qty: 100, + // min_date_value : 10, + // min_date_unit : 'day', + // max_date_value : 11, + // max_date_unit : 'month' + }), + + createBookingResource: { + name: 'resource1', + qty: '1', + availability: [ + { + type: 'months', + bookable: 'yes', + priority: 1, + from: '1', + to: '12', + }, + ], + base_cost: 5, + block_cost: 6, + }, + + createAuctionProduct: () => ({ + name: faker.commerce.productName() + ' (Auction)', + type: 'auction', + status: 'publish', + featured: true, + description: 'test description', + short_description: 'test short description', + // regular_price : faker.finance.amount(200, 400, 2), + // price : '2232', + regular_price: '2232', + categories: [{}], + meta_data: [ + { + key: '_auction_item_condition', + value: 'new', + }, + { + key: '_auction_type', + value: 'normal', + }, + + { + key: '_auction_start_price', + value: '10', // faker.finance.amount(10, 20, 2), + }, + { + key: '_auction_bid_increment', + value: '20', + }, + { + key: '_auction_reserved_price', + value: '30', + }, + { + key: '_auction_dates_from', + value: helpers.currentDateTime, + }, + { + key: '_auction_dates_to', + value: helpers.addDays(helpers.currentDateTime, 20, 'full'), + }, + { + key: '_auction_has_started', + value: '1', + }, + + // { + // key : '_auction_bid_count', + // value: '0' + // }, + // { + // key : '_auction_proxy', + // value: '0' + // }, + // { + // key : '_auction_sealed', + // value: 'no' + // }, + // { + // key : '_auction_automatic_relist', + // value: 'no' + // }, + // { + // key : '_auction_relist_fail_time', + // value: '' + // }, + // { + // key : '_auction_relist_not_paid_time', + // value: '' + // }, + // { + // key : '_auction_relist_duration', + // value: '' + // }, + // { + // key : '_auction_extend_enable', + // value: 'no' + // }, + // { + // key : '_auction_last_activity', + // value: '1693755727' + // }, + ], + }), + + createProductAddons: () => ({ + name: 'Test Addons Group_1' + faker.string.nanoid(10), + priority: 1, + restrict_to_categories: [], + fields: [ + { + name: 'Test Add-on Title_' + faker.string.nanoid(10), + title_format: 'label', + description_enable: 1, + description: 'Test Add-on description', + type: 'multiple_choice', + display: 'select', + position: 0, + required: 0, + restrictions: 0, + restrictions_type: 'any_text', + adjust_price: 0, + price_type: 'flat_fee', + price: '', + min: 0, + max: 0, + options: [ + { + label: 'Option 1', + price: '30', + image: '', + price_type: 'flat_fee', + }, + ], + }, + ], + }), + + updateProduct: () => ({ regular_price: faker.finance.amount(100, 200, faker.helpers.arrayElement([0, 2])) }), + + updateProductVariation: () => ({ regular_price: faker.finance.amount(100, 200, faker.helpers.arrayElement([0, 2])) }), + + createProductReview: () => ({ + product_id: '', + // review : 'Test_review' + faker.string.nanoid(10), + review: 'Test_review_' + faker.string.nanoid(10), + reviewer: faker.person.fullName(), + reviewer_email: faker.internet.email(), + rating: faker.number.int({ min: 1, max: 5 }), + status: 'approved', // approved, hold, spam, unspam, trash, untrash + }), + + // product review + + updateReview: { + review: () => 'review_message_' + faker.string.nanoid(10), + rating: faker.number.int({ min: 1, max: 5 }), + name: 'customer1', + email: 'customer1@g.com', + verified: true, + }, + + // product category + + createCategory: { + name: 'Clothing', + }, + + updateCategory: { + name: 'Clothing', + }, + + // attribute + + updateBatchAttributesTemplate: () => ({ + id: '', + description: 'updated description (batch req)', + }), + + updateBatchAttributeTermsTemplate: () => ({ + id: '', + order_by: 'menu_order', + }), + + // coupon + + createCoupon: () => ({ + code: 'VC_' + faker.string.nanoid(10), + discount_type: faker.helpers.arrayElement(['percent', 'fixed_product']), + amount: faker.number.int({ min: 1, max: 10 }).toString(), + product_ids: [15], + individual_use: false, + meta_data: [ + { + key: 'apply_before_tax', + value: 'no', + }, + { + key: 'apply_new_products', + value: 'yes', + }, + { + key: 'show_on_store', + value: 'yes', + }, + ], + }), + + createCoupon1: { + code: 'c1_v1', + discount_type: 'percent', + amount: '10', + product_ids: [], + individual_use: false, + meta_data: [ + { + key: 'apply_before_tax', + value: 'no', + }, + { + key: 'apply_new_products', + value: 'yes', + }, + { + key: 'show_on_store', + value: 'yes', + }, + ], + }, + + createMarketPlaceCoupon: () => ({ + code: 'AC_' + faker.string.nanoid(10), + discount_type: faker.helpers.arrayElement(['percent', 'fixed_product', 'fixed_cart']), + amount: faker.number.int({ min: 1, max: 10 }).toString(), + individual_use: false, + meta_data: [ + { + key: 'admin_coupons_enabled_for_vendor', + value: 'yes', + }, + { + key: 'coupon_commissions_type', + value: 'default', + }, + { + key: 'admin_coupons_show_on_stores', + value: 'yes', + }, + { + key: 'admin_coupons_send_notify_to_vendors', // todo: doesn't work + value: 'yes', + }, + ], + }), + + updateCoupon: () => ({ amount: faker.number.int({ min: 1, max: 10 }).toString() }), + + // order + + updateOrder: { + status: 'wc-pending', + }, + + createOrder: { + payment_method: 'bacs', + payment_method_title: 'Direct Bank Transfer', + set_paid: true, + customer_id: 0, + billing: { + first_name: 'customer1', + last_name: 'c1', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + state: 'NY', + postcode: '10003', + country: 'US', + email: 'customer1@yopmail.com', + phone: '(555) 555-5555', + }, + + shipping: { + first_name: 'customer1', + last_name: 'c1', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + state: 'NY', + postcode: '10003', + country: 'US', + }, + + line_items: [ + { + product_id: '', + quantity: 1, + }, + ], + + shipping_lines: [ + { + method_id: 'flat_rate', + method_title: 'Flat Rate', + total: '10.00', + }, + ], + }, + + createOrderCod: { + payment_method: 'cod', + payment_method_title: 'Cash on delivery', + set_paid: true, + billing: { + first_name: 'customer1', + last_name: 'c1', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + state: 'NY', + postcode: '10003', + country: 'US', + email: 'customer1@yopmail.com', + phone: '(555) 555-5555', + }, + + shipping: { + first_name: 'customer1', + last_name: 'c1', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + state: 'NY', + postcode: '10003', + country: 'US', + }, + line_items: [ + { + product_id: '', + quantity: 10, + }, + ], + shipping_lines: [ + { + method_id: 'flat_rate', + method_title: 'Flat Rate', + total: '10.00', + }, + ], + }, + + createOrderNote: { + status: 'processing', + note: 'test order note', + }, + + createOrderNoteForCustomer: { + status: 'processing', + note: 'test order note' + faker.string.nanoid(10), + customer_note: 'true', + }, + + // refund + + createRefund: { + api_refund: false, + amount: '25', + reason: 'testing refund', + refunded_by: 3, + // line_items : [{ refund_total: 1 }], + }, + // withdraw + + createWithdraw: { + amount: '50', + notes: 'Withdraw notes', + method: 'paypal', + }, + + updateWithdraw: { + amount: '10', + notes: 'Withdraw notes', + method: 'paypal', + }, + + updateWithdrawDisbursementSettings: { + schedule: 'quarterly', + minimum: dbData.dokan.withdrawSettings.withdraw_limit, // should be equal to minimum limit + reserve: 0, + method: 'paypal', + }, + + // settings + + updateSettings: { + // store_name: 'vendorStore', + social: { + fb: 'http://dokan.test', + youtube: 'http://dokan.test', + twitter: 'http://dokan.test', + linkedin: 'http://dokan.test', + pinterest: 'http://dokan.test', + instagram: 'http://dokan.test', + flickr: 'http://dokan.test', + }, + payment: { + bank: { + ac_name: 'account name', + ac_type: 'personal', + ac_number: '1234567890', + bank_name: 'bank name', + bank_addr: 'bank address', + routing_number: '1234567890', + iban: '1234567890', + swift: '1234567890', + }, + paypal: { email: 'pay9pal@g.c' }, + }, + featured: true, + trusted: true, + enabled: true, + phone: '0123456789', + show_email: 'no', + address: { + street_1: 'abc street', + street_2: 'xyz street', + city: 'New York', + zip: '10003', + state: 'NY', + country: 'US', + location_name: 'Default', + }, + location: '40.7127753,-74.0059728', // NY + // location: '23.709921,90.407143', //dhaka + banner: '', + icon: '', + gravatar: '', + show_more_ptab: 'yes', + store_ppp: 12, + enable_tnc: 'off', + store_tnc: '', + show_min_order_discount: '', + store_seo: [], + dokan_store_time_enabled: 'no', + dokan_store_open_notice: 'Store is open', + dokan_store_close_notice: 'Store is closed', + dokan_store_time: { + monday: { status: 'close', opening_time: [], closing_time: [] }, + tuesday: { status: 'close', opening_time: [], closing_time: [] }, + wednesday: { status: 'close', opening_time: [], closing_time: [] }, + thursday: { status: 'close', opening_time: [], closing_time: [] }, + friday: { status: 'close', opening_time: [], closing_time: [] }, + saturday: { status: 'close', opening_time: [], closing_time: [] }, + sunday: { status: 'close', opening_time: [], closing_time: [] }, + }, + company_name: '', + vat_number: '', + company_id_number: '', + bank_name: '', + bank_iban: '', + profile_completion: { + closed_by_user: false, + phone: 10, + store_name: 10, + address: 10, + progress: 30, + next_todo: 'banner_val', + progress_vals: { + banner_val: 15, + profile_picture_val: 15, + store_name_val: 10, + address_val: 10, + phone_val: 10, + map_val: 15, + payment_method_val: 15, + social_val: [{}], + }, + }, + setting_minimum_order_amount: '', + setting_order_percentage: '', + find_address: 'Dhaka', + product_sections: { + advertised: 'no', + featured: 'no', + latest: 'no', + best_selling: 'no', + top_rated: 'no', + }, + order_min_max: { + enable_vendor_min_max_quantity: 'no', + min_quantity_to_order: '', + max_quantity_to_order: '', + vendor_min_max_products: [], + vendor_min_max_product_cat: [], + enable_vendor_min_max_amount: 'no', + min_amount_to_order: '', + max_amount_to_order: '', + }, + vendor_biography: '', + show_support_btn_product: 'yes', + support_btn_name: '', + show_support_btn: 'yes', + setting_go_vacation: 'no', + settings_closing_style: 'instantly', + setting_vacation_message: '', + seller_vacation_schedules: [], + vendor_store_location_pickup: { + multiple_store_location: 'no', + default_location_name: 'Default', + }, + store_locations: [], + }, + + // attribute + + createAttribute: () => ({ + name: 'Test_attribute_' + faker.string.alpha(8), + // slug : `pa_${payloads.createAttribute.name}`, + // type : 'select', + // order_by : 'menu_order', + // has_archives: false + }), + + updateAttribute: () => ({ name: 'Updated_Test_attribute_' + faker.string.alpha(5) }), + + createAttributeTerm: () => ({ name: 'Test_attributeTerm_' + faker.string.alpha(8) }), + + updateAttributeTerm: () => ({ name: 'Updated_Test_attributeTerm_' + faker.string.alpha(5) }), + + // user + + createUser: { + username: '', + first_name: '', + last_name: '', + email: '', + roles: '', + password: '', + }, + + // vendor + + createVendor: { + username: 'vendor2', + first_name: 'vendor2', + last_name: 'v2', + email: 'vendor2@yopmail.com', + roles: 'seller', + password: 'password', + }, + + // plugin + + updatePlugin: { + plugin: 'dokan/dokan', + status: 'active', + // status: 'inactive', + }, + + // site settings + + siteSettings: { + // title : 'dokan', + // description : 'Just another WordPress site', + // url : 'http://dokan.test', + // email : 'shashwata@wedevs.com', + timezone: 'Asia/Dhaka', + date_format: 'F j, Y', + time_format: 'g:i a', + start_of_week: 1, + language: '', + // use_smilies : true, + // default_category : 1, + // default_post_format : '0', + // posts_per_page : 10, + // show_on_front : 'posts', + // page_on_front : 0, + // page_for_posts : 0, + // default_ping_status : 'open', + // default_comment_status: 'open', + // site_logo : 0, + // site_icon : 0 + }, + + // shipping + + createShippingZone: { + name: 'US', + order: 0, + }, + + addShippingZoneLocation: [ + { + code: 'US', + type: 'country', + }, + ], + + addShippingMethodFlatRate: { + method_id: 'flat_rate', + }, + + addShippingMethodFreeShipping: { + method_id: 'free_shipping', + }, + + addShippingMethodLocalPickup: { + method_id: 'local_pickup', + }, + + addShippingMethodDokanTableRateShipping: { + method_id: 'dokan_table_rate_shipping', + }, + + addShippingMethodDokanDistanceRateShipping: { + method_id: 'dokan_distance_rate_shipping', + }, + + addShippingMethodDokanVendorShipping: { + method_id: 'dokan_vendor_shipping', + }, + + // woocommerce settings: general , products, tax, shipping, checkout, account + + // general + + general: { + update: [ + // store address + { + id: 'woocommerce_store_address', + // label: 'Address line 1', + value: 'abc street', + }, + { + id: 'woocommerce_store_address_2', + // label: 'Address line 2', + value: 'xyz street', + }, + { + id: 'woocommerce_store_city', + // label: 'City', + value: 'New York', + }, + { + id: 'woocommerce_default_country', + // label: 'Country / State', + value: 'US:NY', + }, + { + id: 'woocommerce_store_postcode', + // label: 'Postcode / ZIP', + value: '10006', + }, + + // general options + { + id: 'woocommerce_allowed_countries', + // label: 'Selling location(s)', + value: 'all', // 'all', 'all_except', 'specific' + }, + { + id: 'woocommerce_ship_to_countries', + // label: 'Shipping location(s)', + value: '', // '', 'specific', 'disabled' + }, + { + id: 'woocommerce_default_customer_address', + // label: 'Default customer location', + value: 'base', // '', 'base', 'geolocation', 'geolocation_ajax' + }, + { + id: 'woocommerce_calc_taxes', + // label: 'Enable taxes', + value: 'yes', + // value: 'no', + }, + { + id: 'woocommerce_enable_coupons', + // label: 'Enable coupons', + value: 'yes', + }, + + // currency options + { + id: 'woocommerce_currency', + // label: 'Currency', + value: 'USD', + }, + { + id: 'woocommerce_currency_pos', + // label: 'Currency position', + value: 'left', // 'left', 'right', 'left_space', 'right_space' + }, + { + id: 'woocommerce_price_thousand_sep', + // label: 'Thousand separator', + value: '.', + // value: '.', + }, + + { + id: 'woocommerce_price_decimal_sep', + // label: 'Decimal separator', + value: ',', + // value: ',', + }, + { + id: 'woocommerce_price_num_decimals', + // label: 'Number of decimals', + value: '2', + // value: '4', + }, + ], + }, + + // enable tax rate + enableTaxRate: { + update: [ + { + id: 'woocommerce_calc_taxes', + // label: 'Enable taxes', + value: 'yes', + // value: 'no', + }, + ], + }, + + // create tax rate + createTaxRate: { + country: '', + state: '', + postcode: '', + city: '', + rate: '5', + name: 'Tax', + priority: 1, + compound: false, + shipping: true, + order: 0, + class: 'standard', + postcodes: [], + cities: [], + }, + + // account + + account: { + update: [ + // Guest checkout + { + id: 'woocommerce_enable_guest_checkout', + // description: "Allow customers to place orders without an account", + value: 'yes', + }, + { + id: 'woocommerce_enable_checkout_login_reminder', + // description: "Allow customers to log into an existing account during checkout", + value: 'yes', + }, + + // Account creation + { + id: 'woocommerce_enable_signup_and_login_from_checkout', + // description: "Allow customers to create an account during checkout", + value: 'yes', + }, + // { + // id: 'woocommerce_enable_signup_from_checkout_for_subscriptions', + // description: "Allow subscription customers to create an account during checkout", + // value: 'yes', + // }, + { + id: 'woocommerce_enable_myaccount_registration', + // description: "Allow customers to create an account on the \"My account\" page", + value: 'yes', + }, + { + id: 'woocommerce_registration_generate_username', + // description: "When creating an account, automatically generate an account username for the customer based on their name, surname or email", + value: 'yes', + }, + { + id: 'woocommerce_registration_generate_password', + // description: 'When creating an account, send the new user a link to set their password', + value: 'no', + // value: 'yes', + }, + ], + }, + + // enable HPOS + advanced: { + update: [ + // High performance order storage (HPOS) + { + id: 'woocommerce_custom_orders_table_enabled', + // label: "Data storage for orders", + type: 'radio', + // "options": { + // "no": "WordPress post tables", + // "yes": "High performance order storage (new)" + // }, + value: 'no', + }, + { + id: 'woocommerce_custom_orders_table_data_sync_enabled', + // description: "Keep the posts and orders tables in sync (compatibility mode).", + value: 'no', + }, + ], + }, + + bcs: { + id: 'bacs', + // title: 'Direct bank transfer', + enabled: true, + // method_title: 'Direct bank transfer', + }, + + cheque: { + id: 'cheque', + // title: 'Check payments', + enabled: true, + // method_title: 'Check payments', + }, + cod: { + id: 'cod', + // title: 'Cash on delivery', + enabled: true, + // method_title: 'Cash on delivery', + }, + + stripeConnect: { + id: 'dokan-stripe-connect', + title: 'Dokan Credit card (Stripe)', + // description: 'Pay with your credit card via Stripe.', + enabled: true, + settings: [ + { + id: 'title', + // label: "Title", + // description: "This controls the title which the user sees during checkout.", + value: 'Dokan Credit card (Stripe)', + }, + { + id: 'allow_non_connected_sellers', + // label: "Allow ordering products from non-connected sellers", + // description: "If this is enable, customers can order products from non-connected sellers. The payment will send to admin Stripe account.", + value: 'yes', + }, + { + id: 'display_notice_to_non_connected_sellers', + // label: "If checked, non-connected sellers will receive announcement notice to connect their Stripe account. ", + // description: "If checked, non-connected sellers will receive announcement notice to connect their Stripe account once in a week.", + value: 'yes', + }, + { + id: 'display_notice_interval', + // label: "If Display Notice to Connect Seller", + // description: "If this is enabled and Dokan Stripe Connect is the only gateway available, non-connected sellers will receive announcement notice to connect their Stripe account once in a week.", + value: '7', + }, + { + id: 'enable_3d_secure', + // label: "Enable 3D Secure and Strong Customer Authentication", + // description: "Note: 3D Secure and SCA ready transaction is only supported when both your platform and the connected account (Vendor) are in the same region: both in Europe or both in the U.S.", + value: 'yes', + }, + { + id: 'seller_pays_the_processing_fee', + // label: "If activated, Sellers will pay the Stripe processing fee instead of Admin/Site Owner in 3DS mode.", + // description: "By default Admin/Site Owner pays the Stripe processing fee.", + value: 'yes', + }, + { + id: 'testmode', + // label: "Enable Test Mode", + // description: "Place the payment gateway in test mode using test API keys.", + value: 'yes', + }, + { + id: 'stripe_checkout', + // label: "Enable Stripe Checkout", + // description: "(This only works when 3D Secure and SCA is disabled) If enabled, this option shows a \"pay\" button and modal credit card form on the checkout, instead of credit card fields directly on the page.", + value: 'yes', + }, + { + id: 'stripe_checkout_locale', + // label: "Stripe Checkout locale", + // description: "Language to display in Stripe Checkout modal. Specify Auto to display Checkout in the user's preferred language, if available. English will be used by default.", + value: 'en', + // 'options': { + // 'auto': 'Auto', + // 'zh': 'Simplified Chinese', + // 'da': 'Danish', + // 'nl': 'Dutch', + // 'en': 'English', + // 'fi': 'Finnish', + // 'fr': 'French', + // 'de': 'German', + // 'it': 'Italian', + // 'ja': 'Japanese', + // 'no': 'Norwegian', + // 'es': 'Spanish', + // 'sv': 'Swedish' + // } + }, + { + id: 'stripe_checkout_image', + // label: "Checkout Image", + // description: "Optionally enter the URL to a 128x128px image of your brand or product. e.g. https://yoursite.com/wp-content/uploads/2013/09/yourimage.jpg", + value: '', + }, + { + id: 'stripe_checkout_label', + // label: "Checkout Button Label", + // description: "Optionally enter a Label for PAY button", + value: '', + }, + { + id: 'saved_cards', + // label: "Enable saved cards", + // description: "If enabled, users will be able to pay with a saved card during checkout. Card details are saved on Stripe servers, not on your store.", + value: 'yes', + }, + { + id: 'live-credentials-title', + // label: "Live credentials", + // description: "", + value: '', + }, + { + id: 'publishable_key', + // label: "Publishable Key", + // description: "Get your API keys from your stripe account.", + value: '', + }, + { + id: 'secret_key', + // label: "Secret Key", + // description: "Get your API keys from your stripe account.", + value: '', + }, + { + id: 'client_id', + // label: "Client ID", + // description: "Get your client ID from your stripe account, the Apps menu.", + value: '', + }, + { + id: 'test-credentials-title', + // label: "Test credentials", + // description: "", + type: 'title', + value: '', + }, + { + id: 'test_publishable_key', + // label: "Test Publishable Key", + // description: "Get your API keys from your stripe account.", + value: process.env.TEST_PUBLISH_KEY_STRIPE, + }, + { + id: 'test_secret_key', + // label: "Test Secret Key", + // description: "Get your API keys from your stripe account.", + value: process.env.TEST_SECRET_KEY_STRIPE, + }, + { + id: 'test_client_id', + // label: "Test Client ID", + // description: "Get your client ID from your stripe account, the Apps menu.", + value: process.env.CLIENT_ID_STRIPE, + }, + ], + }, + + payPal: { + id: 'dokan_paypal_marketplace', + title: 'PayPal Marketplace', + // description: null, + enabled: false, + settings: [ + { + id: 'shipping_tax_fee_recipient_notice', + // label: "Note", + // description: "For this payment gateway, Shipping Fee Recipient and Tax Fee Recipient will be set to Seller. Otherwise, in case of partial refund, you will not be able to refund shipping or tax fee from admin commission.", + value: '', + }, + { + id: 'title', + // label: "Title", + // description: "This controls the title which the user sees during checkout.", + value: 'PayPal Marketplace', + }, + { + id: 'partner_id', + // label: "PayPal Merchant ID/Partner ID", + // description: "To get Merchant ID goto Paypal Dashboard --> Account Settings --> Business Information section.", + value: '', + }, + { + id: 'api_details', + // label: "API credentials", + // description: "Your API credentials are a client ID and secret, which authenticate API requests from your account. You get these credentials from a REST API app in the Developer Dashboard. Visit this link for more information about getting your api details.", + value: '', + }, + { + id: 'test_mode', + // label: "Enable PayPal sandbox", + // description: "PayPal sandbox can be used to test payments. Sign up for a developer account here.", + value: 'no', + }, + { + id: 'app_user', + // label: "Client ID", + // description: "For this payment method your need an application credential", + value: '', + }, + { + id: 'app_pass', + // label: "Client Secret", + // description: "For this payment method your need an application credential", + value: '', + }, + { + id: 'test_app_user', + // label: "Sandbox Client ID", + // description: "For this system please sign up in developer account and get your application credential", + value: '', + }, + { + id: 'test_app_pass', + // label: "Sandbox Client Secret", + // description: "For this system please sign up in developer account and get your application credential", + value: '', + }, + { + id: 'bn_code', + // label: "PayPal Partner Attribution Id", + // description: "PayPal Partner Attribution ID will be given to you after you setup your PayPal Marketplace account. If you do not have any, default one will be used.", + value: 'weDevs_SP_Dokan', + }, + { + id: 'disbursement_mode', + // label: "Disbursement Mode", + // description: "Choose whether you wish to disburse funds to the vendors immediately or hold the funds. Holding funds gives you time to conduct additional vetting or enforce other platform-specific business logic.", + value: 'INSTANT', + // "options": { + // "INSTANT": "Immediate", + // "ON_ORDER_COMPLETE": "On Order Complete", + // "DELAYED": "Delayed" + // } + }, + { + id: 'disbursement_delay_period', + // label: "Disbursement Delay Period", + // description: "Specify after how many days funds will be disburse to corresponding vendor. Maximum holding period is 29 days. After 29 days, fund will be automatically disbursed to corresponding vendor.", + value: '7', + }, + { + id: 'button_type', + // label: "Payment Button Type", + // description: "Smart Payment Buttons type is recommended.", + value: 'smart', + // "options": { + // "smart": "Smart Payment Buttons", + // "standard": "Standard Button" + // } + }, + { + id: 'ucc_mode_notice', + // label: "Set up advanced credit and debit card payments", + // description: "Set up advanced payment options on your checkout page so your buyers can pay with debit and credit cards, PayPal, and alternative payment methods. Supported Countries: Australia, Canada, France, Italy, Spain, United States, United Kingdom", + value: '', + }, + { + id: 'ucc_mode', + // label: "Allow advanced credit and debit card payments", + // description: "", + value: 'no', + }, + { + id: 'marketplace_logo', + // label: "Marketplace Logo", + // description: "When vendors connect their PayPal account, they will see this logo upper right corner of the PayPal connect window", + value: 'http://dokan1.test/wp-content/plugins/dokan/assets/images/dokan-logo.png', + }, + { + id: 'display_notice_on_vendor_dashboard', + // label: "If checked, non-connected sellers will see a notice to connect their PayPal account on their vendor dashboard.", + // description: "If this is enabled, non-connected sellers will see a notice to connect their Paypal account on their vendor dashboard.", + value: 'no', + }, + { + id: 'display_notice_to_non_connected_sellers', + // label: "If checked, non-connected sellers will receive announcement notice to connect their PayPal account. ", + // description: "If this is enabled non-connected sellers will receive announcement notice to connect their Paypal account once in a week by default.", + value: 'no', + }, + { + id: 'display_notice_interval', + // label: "Send Announcement Interval", + // description: "If Send Announcement to Connect Seller setting is enabled, non-connected sellers will receive announcement notice to connect their PayPal account once in a week by default. You can control notice display interval from here.", + value: '7', + }, + { + id: 'webhook_message', + // label: "Webhook URL", + // description: "Webhook URL will be set automatically in your application settings with required events after you provide correct API information. You don't have to setup webhook url manually. Only make sure webhook url is available to https://dokan1.test/wc-api/dokan-paypal in your PayPal application settings.", + value: '', + }, + ], + }, + + mangoPay: { + id: 'dokan_mangopay', + title: 'MangoPay', + // description: null, + enabled: false, + settings: [ + { + id: 'title', + // label: 'title', + // description: 'This controls the title which the user sees during checkout.', + value: 'MangoPay', + }, + { + id: 'api_details', + // label: 'API Credentials', + // description: 'Your API credentials are a client ID and API key, which authenticate API requests from your account. You can collect these credentials from a REST API app in the Developer Dashboard. Visit this link for more information about getting your api details.', + value: '', + }, + { + id: 'sandbox_mode', + // label: 'Enable MangoPay sandbox', + // description: 'MangoPay sandbox can be used to test payments.', + value: 'yes', + }, + { + id: 'client_id', + // label: 'Client ID', + // description: 'Credential for the main MangoPay account', + value: '', + }, + { + id: 'api_key', + // label: 'API Key', + // description: 'Credential for the main MangoPay account', + value: '', + }, + { + id: 'sandbox_client_id', + // label: 'Sandbox Client ID', + // description: 'Credential for the MangoPay sandbox account', + value: process.env.SANDBOX_CLIENT_ID_MANGOPAY, + }, + { + id: 'sandbox_api_key', + // label: 'Sandbox API Key', + // description: 'Credential for the MangoPay sandbox account', + value: process.env.SANDBOX_API_KEY, + }, + { + id: 'payment_options', + // label: 'Payment Options', + // description: 'Configure the environment for payment to control how the customers will be able to pay.', + value: '', + }, + { + id: 'cards', + // label: 'Choose Available Credit Cards', + // description: 'Payment types marked with asterisk(*) needs to be activated for your account. Please contact MangoPay.', + value: ['CB_VISA_MASTERCARD', 'MAESTRO', 'BCMC', 'P24', 'DINERS', 'PAYLIB', 'IDEAL', 'MASTERPASS', 'BANK_WIRE'], + // "options": { + // "CB_VISA_MASTERCARD": "CB/Visa/Mastercard", + // "MAESTRO": "Maestro*", + // "BCMC": "Bancontact/Mister Cash", + // "P24": "Przelewy24*", + // "DINERS": "Diners*", + // "PAYLIB": "PayLib", + // "IDEAL": "iDeal*", + // "MASTERPASS": "MasterPass*", + // "BANK_WIRE": "Bankwire Direct*" + // } + }, + { + id: 'direct_pay', + // label: 'Choose Available Direct Payment Services', + // description: 'Payment types marked with asterisk(*) needs to be activated for your account. Please contact MangoPay.', + value: '', + // "options": { + // "SOFORT": "Sofort*", + // "GIROPAY": "Giropay*" + // } + }, + { + id: 'saved_cards', + // label: 'Enable saved cards', + // description: 'If enabled, customers will be able to save cards during checkout. Card data will be saved on MangoPay server, not on the store.', + value: 'yes', + }, + { + id: 'platform_fees', + // label: 'Platform Fees', + // description: 'MangoPay collects platform fees from the marketplace owner. That means, all platform fees will be collected from your commission. If you need information about the amount charged as platform fees, please see the pricing plan here. Also, if you want to know how the platform fees are collected, please read their documentation.', + value: '', + }, + { + id: 'fund_transfers', + // label: 'Fund Transfers and Payouts', + // description: 'Configure how and when you want to transfer/payout funds to the vendors.', + value: '', + }, + { + id: 'disburse_mode', + // label: 'Choose when you want to disburse funds to the vendors', + // description: 'You can choose when whether you want to transfer funds to vendors after the order is completed, or immediately after the payment is completed, or delay the transfer even if the order is processing or completed.', + value: 'ON_ORDER_PROCESSING', + // "options": { + // "ON_ORDER_PROCESSING": "On payment completed", + // "ON_ORDER_COMPLETED": "On order completed", + // "DELAYED": "Delayed" + // } + }, + { + id: 'disbursement_delay_period', + // label: 'Delay Period (Days)', + // description: 'Specify after how many days funds will be disburse to corresponding vendor. The funcds will be transferred to vendors after this period automatically', + value: '14', + }, + { + id: 'instant_payout', + // label: 'Enable instant payout mode', + // description: 'Enable instant payout so that the payout can be processed within 25 seconds, whereas, the standard payouts get processed within 48 hours. This feature is limited and requires some prerequisites to be fulfiled. Please check out the requirements here.', + value: 'yes', + }, + { + id: 'user_types', + // label: 'Types and Requirements of Vendors', + // description: 'Configure the types of vendors. It will define the types of vendors who are going to use the gateway. This way you can bound the types of vendors, according to which the verification process will be applied.', + value: '', + }, + { + id: 'default_vendor_status', + // label: 'Type of Vendors', + // description: 'All the vendors are bound to this type and they will be verified according to this. Choose \'Either\' if no restriction is needed.', + value: 'NATURAL', + // "options": { + // "NATURAL": "Individuals", + // "LEGAL": "Business", + // "EITHER": "Either" + // } + }, + { + id: 'default_business_type', + // label: 'Business Requirement', + // description: 'All the business are bound to this type and the verification process will be applied accordingly. Choose \'Any\' if no restriction is needed.', + value: 'ORGANIZATION', + // "options": { + // "ORGANIZATION": "Organizations", + // "SOLETRADER": "Soletraders", + // "BUSINESS": "Businesses", + // "EITHER": "Any" + // } + }, + { + id: 'advanced', + // label: 'Advanced Settings', + // description: 'Set up advanced settings to manage some extra options.', + value: '', + }, + { + id: 'notice_on_vendor_dashboard', + // label: 'If checked, non-connected sellers will see a notice to connect their MangoPay account on their vendor dashboard.', + // description: 'If this is enabled, non-connected sellers will see a notice to connect their MangoPay account on their vendor dashboard.', + value: 'yes', + }, + { + id: 'announcement_to_sellers', + // label: 'If checked, non-connected sellers will receive announcement notice to connect their MangoPay account. ', + // description: 'If this is enabled non-connected sellers will receive announcement notice to connect their MangoPay account.', + value: 'yes', + }, + { + id: 'notice_interval', + // label: 'Announcement Interval', + // description: 'If Send Announcement to Connect Seller setting is enabled, non-connected sellers will receive announcement notice to connect their MangoPay account once in a week by default. You can control notice display interval from here. The interval value will be considered in days.', + value: '7', + }, + ], + }, + + razorpay: { + id: 'dokan_razorpay', + title: 'Razorpay', + enabled: false, + settings: [ + { + id: 'title', + // label: title, + // description: 'This controls the title which the user sees during checkout.', + value: 'Razorpay', + }, + { + id: 'api_details', + // label: 'API credentials', + // description: 'Your API credentials are a API Key and secret, which authenticate API requests from your account. You get these credentials from a REST API app in the Developer Dashboard. Visit this link for more information about getting your api details.', + value: '', + }, + { + id: 'test_mode', + // label: 'Enable Razorpay sandbox', + // description: 'Razorpay sandbox can be used to test payments. Sign up for a developer account here.', + value: 'yes', + }, + { + id: 'key_id', + // label: 'Key ID', + // description: 'The key Id can be generated from Razorpay Dashboard --> Settings here.', + value: '', + }, + { + id: 'key_secret', + // label: 'Key Secret', + // description: 'The key secret can be generated from Razorpay Dashboard --> Settings here.', + value: '', + }, + { + id: 'test_key_id', + // label: 'Test Key ID', + // description: 'The Test key Id can be generated from Razorpay Dashboard --> Settings here.', + value: process.env.TEST_KEY_ID_RAZORPAY, + }, + { + id: 'test_key_secret', + // label: 'Test Key Secret', + // description: 'The Test key secret can be generated from Razorpay Dashboard --> Settings here.', + value: process.env.TEST_KEY_SECRET_RAZORPAY, + }, + { + id: 'enable_route_transfer', + // label: 'Enable Route Transfer', + // description: 'To make split payment enabled, you must Activate Route Transfer from Razorpay Dashboard here.', + value: '', + }, + { + id: 'disbursement_mode', + // label: 'Disbursement Mode', + // description: 'Choose whether you wish to disburse funds to the vendors immediately or hold the funds. Holding funds gives you time to conduct additional vetting or enforce other platform-specific business logic.', + value: 'INSTANT', + // "options": { + // "INSTANT": "Immediate", + // "ON_ORDER_COMPLETE": "On Order Complete", + // "DELAYED": "Delayed" + // } + }, + { + id: 'razorpay_disbursement_delay_period', + // label: 'Disbursement Delay Period', + // description: 'Specify after how many days funds will be disbursed to the corresponding vendor. No Maximum holding days. After given days, fund will be disbursed to corresponding vendor.', + value: '7', + }, + { + id: 'seller_pays_the_processing_fee', + // label: 'If unchecked, Admin/Site Owner will pay the Razorpay processing fee instead of Seller.', + // description: 'By default Seller pays the Razorpay processing fee.', + value: 'yes', + }, + { + id: 'display_notice_on_vendor_dashboard', + // label: 'If checked, non-connected sellers will see a notice to connect their Razorpay account on their vendor dashboard.', + // description: 'If this is enabled, non-connected sellers will see a notice to connect their Razorpay account on their vendor dashboard.', + value: 'no', + }, + { + id: 'display_notice_to_non_connected_sellers', + // label: 'If checked, non-connected sellers will receive announcement notice to connect their Razorpay account. ', + // description: 'If this is enabled non-connected sellers will receive announcement notice to connect their Razorpay account once in a week by default.', + value: 'no', + }, + { + id: 'display_notice_interval', + // label: 'Send Announcement Interval', + // description: 'If Send Announcement to Connect Seller setting is enabled, non-connected sellers will receive announcement notice to connect their Razorpay account once in a week by default. You can control notice display interval from here.', + value: '7', + }, + ], + }, + + stripeExpress: { + id: 'dokan_stripe_express', + title: 'Credit/Debit Card', + // description: 'Pay with credit/debit card', + enabled: false, + settings: [ + { + id: 'title', + // label: title, + // description: 'This controls the title which the user sees during checkout. This title will be shown only when multiple payment methods are enabled for Stripe Express', + value: 'Stripe Express', + }, + { + id: 'api_details', + // label: 'API Credentials', + // description: 'Your API credentials are a publishable key and a secret key, which authenticate API requests from your account. You can collect these credentials from a REST API app in the Developer Dashboard. Visit this link for more information about getting your api details.
    Note: Even if you enable test mode, please provide your live API keys as well. For some extra configurations for payment methods like Apple Pay and payment request buttons, live API keys are required even in test mode.', + value: '', + }, + { + id: 'testmode', + // label: 'Enable Stripe Test Mode', + // description: 'Stripe test mode can be used to test payments.', + value: 'yes', + }, + { + id: 'publishable_key', + // label: 'Publishable Key', + // description: 'Publishable key for Stripe', + value: '', + }, + { + id: 'secret_key', + // label: 'Secret Key', + // description: 'Secret key for Stripe', + value: '', + }, + { + id: 'test_publishable_key', + // label: 'Test Publishable Key', + // description: 'Test Publishable key for Stripe', + value: process.env.TEST_PUBLISH_KEY_STRIPE_EXPRESS, + }, + { + id: 'test_secret_key', + // label: 'Test Secret Key', + // description: 'Test Secret key for Stripe', + value: process.env.TEST_SECRET_KEY_STRIPE_EXPRESS, + }, + { + id: 'webhook', + // label: 'Webhook Endpoints', + // description: 'You must add the following webhook endpoint  https://dokan1.test/wc-api/dokan-stripe-express  to your Stripe account settings (if there isn\'t one already enabled). This will enable you to receive notifications on the charge statuses. The webhook endpoint will be attempted to be configured automatically on saving these admin settings. If it is not configured automatically, please register it manually.

    Warning: The most recent test webhook, received at 1970-01-01 06:00:00 +06:00, could not be processed. Reason: No error. (No test webhooks have been processed successfully since monitoring began at 2023-07-22 19:01:23 +06:00.)', + value: '', + }, + { + id: 'webhook_key', + // label: 'Webhook Secret', + // description: 'Get your webhook signing secret from the webhooks section in your stripe account.', + value: '', + }, + { + id: 'test_webhook_key', + // label: 'Test Webhook Secret', + // description: 'Get your webhook signing secret from the webhooks section in your stripe account.', + value: '', + }, + { + id: 'payment_options', + // label: 'Payment and Disbursement', + // description: 'Manage the payment and fund disbursements.', + value: '', + }, + { + id: 'enabled_payment_methods', + // label: 'Choose Payment Methods', + // description: 'Selected payment methods will be appeared on checkout if requiorements are fulfilled.', + value: ['card'], + // "options": { + // "card": "Credit/Debit Card", + // "ideal": "iDEAL" + // } + }, + { + id: 'sellers_pay_processing_fee', + // label: 'If activated, Sellers will pay the Stripe processing fee instead of Admin/Site Owner.', + // description: 'By default Admin/Site Owner pays the Stripe processing fee.', + value: 'yes', + }, + { + id: 'saved_cards', + // label: 'Enable payment via saved cards', + // description: 'If enabled, customers will be able to save cards during checkout. Card data will be saved on Stripe server, not on the store.', + value: 'yes', + }, + { + id: 'capture', + // label: 'Issue an authorization on checkout, and capture later', + // description: 'Only cards support manual capture. When enabled, all other payment methods will be hidden from checkout. Charge must be captured on the order details screen within 7 days of authorization, otherwise the authorization and order will be canceled.', + value: 'no', + }, + { + id: 'disburse_mode', + // label: 'Choose when you want to disburse funds to the vendors', + // description: 'You can choose when whether you want to transfer funds to vendors after the order is completed, or immediately after the payment is completed, or delay the transfer even if the order is processing or completed.', + value: 'ON_ORDER_PROCESSING', + // "options": { + // "ON_ORDER_PROCESSING": "On payment completed", + // "ON_ORDER_COMPLETED": "On order completed", + // "DELAYED": "Delayed" + // } + }, + { + id: 'disbursement_delay_period', + // label: 'Delay Period (Days)', + // description: 'Specify after how many days funds will be disburse to corresponding vendor. The funcds will be transferred to vendors after this period automatically', + value: '14', + }, + { + id: 'statement_descriptor', + // label: 'Customer Bank Statement', + // description: 'Enter the name your customers will see on their transactions. Use a recognizable name – e.g. the legal entity name or website address–to avoid potential disputes and chargebacks.', + value: '', + }, + { + id: 'appearance', + // label: 'Payment Element Appearance', + // description: 'Customize theme and appearance of Payment Element', + value: '', + }, + { + id: 'element_theme', + // label: 'Theme', + // description: 'Select the theme you would like to choose for Stripe element.', + value: 'stripe', + // "options": { + // "stripe": "Light", + // "flat": "Flat", + // "night": "Dark", + // "dark_blue": "Dark Blue", + // "none": "None" + // } + }, + { + id: 'payment_request_options', + // label: 'Payment Request Options (Apple Pay / Google Pay)', + // description: 'Enable payment via Apple Pay and Google Pay.
    By using Apple Pay, you agree to Stripe and Apple\'s terms of service. (Apple Pay domain verification is performed automatically in live mode; configuration can be found on the Stripe dashboard.)', + value: '', + }, + { + id: 'payment_request', + // label: 'Enable Payment Request Buttons. (Apple Pay/Google Pay)', + // description: 'If enabled, users will be able to pay using Apple Pay or Chrome Payment Request if supported by the browser. Depending on the web browser and wallet configurations, your customers will see either Apple Pay or Google Pay, but not both.', + value: 'yes', + }, + { + id: 'payment_request_button_type', + // label: 'Button Type', + // description: 'Select the button type you would like to show.', + value: 'default', + // "options": { + // "default": "Only Icon", + // "buy": "Buy", + // "donate": "Donate", + // "book": "Book" + // } + }, + { + id: 'payment_request_button_theme', + // label: 'Button Theme', + // description: 'Select the button theme you would like to show.', + value: 'dark', + // "options": { + // "dark": "Dark", + // "light": "Light", + // "light-outline": "Light-Outline" + // } + }, + { + id: 'payment_request_button_locations', + // label: 'Button Locations', + // description: 'Select where you would like Payment Request Buttons to be displayed', + value: ['product', 'cart'], + // "options": { + // "product": "Product", + // "cart": "Cart" + // } + }, + { + id: 'payment_request_button_size', + // label: 'Button Size', + // description: 'Select the size of the button.', + value: 'default', + // "options": { + // "default": "Default (40px)", + // "medium": "Medium (48px)", + // "large": "Large (56px)" + // } + }, + { + id: 'cross_border_transfer_options', + // label: 'Cross-border Transfers and Onboarding', + // description: 'Transfer options outside the marketplace\'s country under European Union or SEPA.', + value: '', + }, + { + id: 'cross_border_transfer', + // label: 'Enable onboarding for vendors outside the country/region of the marketplace inside EU and SEPA.', + // description: 'If enabled and if the marketplace is inside European Union or SEPA, vendors will be able to choose their country among the transfer supported countries during signing up. The available countries will be determined by Stripe based on the country of the marketplace.', + value: 'yes', + }, + { + id: 'restricted_countries', + // label: 'Restrict Countries/Regions', + // description: 'Select countries from where vendors will not be able to onboard.', + value: '', + }, + { + id: 'advanced', + // label: 'Advanced Settings', + // description: 'Set up advanced settings to manage some extra options.', + value: '', + }, + { + id: 'notice_on_vendor_dashboard', + // label: 'If checked, non-connected sellers will see a notice to sign up for a Stripe Express account on their vendor dashboard.', + // description: 'If this is enabled, non-connected sellers will see a notice to sign up for a Stripe Express account on their vendor dashboard.', + value: 'yes', + }, + { + id: 'announcement_to_sellers', + // label: 'If checked, non-connected sellers will receive announcement notice to sign up for a Stripe Express account. ', + // description: 'If this is enabled non-connected sellers will receive announcement notice to sign up for a Stripe Express account.', + value: 'yes', + }, + { + id: 'notice_interval', + // label: 'Announcement Interval', + // description: 'If Send Announcement to Connect Seller setting is enabled, non-connected sellers will receive announcement notice to sign up for a Stripe Express account once in a week by default. You can control notice display interval from here. The interval value will be considered in days.', + value: '7', + }, + { + id: 'debug', + // label: 'Enable logging', + // description: 'Log gateway events such as Webhook requests, Payment oprations etc. inside /Users/rk/Sites/dokan1/wp-content/uploads/wc-logs/dokan-2023-09-03-1a1ff23f40df3a5c66b67fcd8d3942ef.log. Note: this may log personal information. We recommend using this for debugging purposes only and deleting the logs when finished.', + value: 'yes', + }, + ], + }, + + // customer + + createCustomer: () => ({ + email: faker.internet.email(), + first_name: faker.person.firstName(), + last_name: faker.person.lastName(), + role: 'customer', + username: faker.person.firstName() + faker.string.nanoid(10), + password: String(process.env.USER_PASSWORD), + billing: { + first_name: 'customer1', + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + email: 'customer1@yopmail.com', + phone: '0123456789', + }, + shipping: { + first_name: 'customer1', + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + phone: '0123456789', + }, + }), + + updateCustomer: () => ({ + email: faker.internet.email(), + first_name: faker.person.firstName(), + last_name: faker.person.lastName(), + role: 'customer', + password: String(process.env.USER_PASSWORD), + billing: { + first_name: 'customer1', + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + email: 'customer1@yopmail.com', + phone: '0123456789', + }, + shipping: { + first_name: 'customer1', + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + phone: '0123456789', + }, + }), + + updateBatchCustomersTemplate: () => ({ + id: '', + billing: { + phone: '0123456789', + }, + }), + + // wholesale customer + + updateWholesaleCustomer: { + status: 'activate', // activate, deactivate, delete + }, + + deleteWholesaleCustomer: { + status: 'delete', + }, + + // create vendor staff + + staff: { + username: 'staff1', + first_name: 'staff1', + last_name: 's1', + email: 'staff1@email.c', + phone: '0123456789', + password: String(process.env.USER_PASSWORD), + }, + + createStaff: () => ({ + username: faker.person.firstName('male') + faker.string.nanoid(10), + first_name: faker.person.firstName('male'), + last_name: faker.person.lastName('male'), + phone: '0123456789', + email: faker.person.firstName('male') + '@email.com', + password: String(process.env.USER_PASSWORD), + }), + + updateStaff: () => ({ + // username: faker.person.firstName('male') + faker.string.nanoid(10), + first_name: faker.person.firstName('male'), + last_name: faker.person.lastName('male'), + phone: '0123456789', + email: faker.person.firstName('male') + '@email.com', + // password: String(process.env.USER_PASSWORD), // todo: fatal error exists dokan issue, for updating password + }), + + updateCapabilities: { + capabilities: [ + { + capability: 'dokan_view_sales_overview', + access: false, + }, + { + capability: 'dokan_view_sales_report_chart', + access: false, + }, + { + capability: 'dokan_view_announcement', + access: false, + }, + { + capability: 'dokan_view_order_report', + access: false, + }, + { + capability: 'dokan_view_product_status_report', + access: false, + }, + { + capability: 'dokan_add_product', + access: false, + }, + ], + }, + + // support ticket + createSupportTicket: { + author: 2, + title: 'test support ticket', + content: 'test support ticket message', + status: 'open', + comment_status: 'open', + meta: { + store_id: 8, + // order_id: '' + }, + }, + + createSupportTicketComment: { + replay: 'sp replay...1', + vendor_id: '1', + selected_user: 'admin', + }, + + updateSupportTicketStatus: { + status: 'close', + }, + + updateSupportTicketEmailNotification: { + notification: true, + }, + + updateBatchSupportTickets: { + close: [247, 248], + }, + + // module + + deactivateModule: { + module: ['booking'], + }, + + activateModule: { + module: ['booking'], + }, + + // announcement + + createAnnouncement: () => ({ + // title: 'test announcement title', + title: 'test announcement_' + faker.string.nanoid(10), + content: '

    This is announcement content

    ', + status: 'publish', + sender_type: 'all_seller', + }), + + updateAnnouncement: { + title: 'updated test announcement title', + content: '

    updated This is announcement content

    ', + status: 'publish', + sender_type: 'all_seller', + }, + + // product review + + updateProductReview: { + status: 'approved', + }, + + // store review + + updateStoreReview: { + title: 'Updated Test review title', + content: 'Updated Test review content', + status: 'publish', + }, + + // store category + + createStoreCategory: () => ({ name: 'Test_Store_Category' + faker.string.nanoid(10) }), + updateStoreCategory: () => ({ name: 'Update_Test_Store_Category' + faker.string.nanoid(10) }), + + // dummy data + + dummyData: { + vendor_products: [ + { + name: 'p1_d1', + type: 'simple', + status: 'publish', + regular_price: '10', + }, + { + name: 'p2_d1', + type: 'simple', + status: 'publish', + regular_price: '20', + }, + ], + vendor_data: { + email: 'dummystore1@yopmail.com', + password: String(process.env.USER_PASSWORD), + store_name: 'dummyStore1', + social: [], + payment: [], + phone: '0123456789', + show_email: 'no', + address: [], + location: '', + banner: '', + icon: '', + gravatar: '', + show_more_tpab: 'yes', + show_ppp: 12, + enable_tnc: 'off', + store_seo: [], + dokan_store_time: [], + enabled: 'yes', + trusted: 'yes', + }, + }, + + // store + + createStore: () => ({ + user_login: faker.person.firstName() + faker.string.nanoid(10), + user_pass: String(process.env.USER_PASSWORD), + role: 'seller', + email: faker.internet.email(), + store_name: faker.person.firstName() + '_store', + first_name: faker.person.firstName(), + last_name: faker.person.lastName(), + social: { + fb: 'http://dokan.test', + youtube: 'http://dokan.test', + twitter: 'http://dokan.test', + linkedin: 'http://dokan.test', + pinterest: 'http://dokan.test', + instagram: 'http://dokan.test', + flickr: 'http://dokan.test', + }, + phone: '0123456789', + show_email: false, + address: { + street_1: 'abc street', + street_2: 'xyz street', + city: 'New York', + zip: '10003', + state: 'NY', + country: 'US', + }, + location: '', + banner: '', + banner_id: 0, + gravatar: '', + gravatar_id: 0, + shop_url: '', + products_per_page: 12, + show_more_product_tab: true, + toc_enabled: false, + store_toc: '', + featured: true, + rating: { + rating: '0.00', + count: 1, + }, + enabled: true, + registered: '', + payment: { + paypal: { + 0: 'email', + email: 'paypal@g.c', + }, + bank: { + ac_name: 'account name', + ac_type: 'personal', + ac_number: '1234567', + bank_name: 'bank name', + bank_addr: 'bank address', + routing_number: '123456', + iban: '123456', + swift: '12345', + }, + stripe: false, + }, + trusted: true, + store_open_close: { + enabled: false, + time: [], + open_notice: 'Store is open', + close_notice: 'Store is closed', + }, + company_name: '', + vat_number: '', + company_id_number: '', + bank_name: '', + bank_iban: '', + categories: [ + { + id: 74, + name: 'Uncategorized', + slug: 'uncategorized', + }, + ], + admin_commission: '', + admin_additional_fee: '0.00', + admin_commission_type: 'flat', + }), + + updateStore: () => ({ + // email: faker.internet.email(), + // store_name: faker.person.firstName(), + // first_name: faker.person.firstName(), + // last_name: faker.person.lastName(), + social: { + fb: 'http://dokan.test', + youtube: 'http://dokan.test', + twitter: 'http://dokan.test', + linkedin: 'http://dokan.test', + pinterest: 'http://dokan.test', + instagram: 'http://dokan.test', + flickr: 'http://dokan.test', + }, + phone: '0123456789', + show_email: false, + address: { + street_1: 'abc street', + street_2: 'xyz street', + city: 'New York', + zip: '10003', + state: 'NY', + country: 'US', + }, + location: '', + banner: '', + banner_id: 0, + gravatar: '', + gravatar_id: 0, + shop_url: '', + products_per_page: 12, + show_more_product_tab: true, + toc_enabled: false, + store_toc: '', + featured: true, + rating: { + rating: '0.00', + count: 1, + }, + trusted: true, + enabled: true, + registered: '', + payment: { + paypal: { + 0: 'email', + email: 'paypal@g.c', + }, + bank: { + ac_name: 'account name', + ac_type: 'personal', + ac_number: '1234567', + bank_name: 'bank name', + bank_addr: 'bank address', + routing_number: '123456', + iban: '123456', + swift: '12345', + }, + stripe: false, + }, + store_open_close: { + enabled: false, + time: [], + open_notice: 'Store is open', + close_notice: 'Store is closed', + }, + company_name: '', + vat_number: '', + company_id_number: '', + bank_name: '', + bank_iban: '', + categories: [{}], + admin_commission: '', + admin_additional_fee: '0.00', + admin_commission_type: 'flat', + }), + + createStoreReview: { + title: 'Test store review', + content: 'Test store review content', + rating: 2, + // approved: true + }, + + updateStoreStatus: { + status: 'active', + }, + + clientContactStore: { + name: 'admin', + email: 'admin@g.c', + message: 'Test admin connect with vendor message', + }, + + adminEmailStore: { + subject: 'Test email sub', + body: 'Test email body', + }, + + createStore1: { + user_login: process.env.VENDOR, + user_pass: process.env.USER_PASSWORD, + user_nicename: process.env.VENDOR + 'store', + role: 'seller', + email: process.env.VENDOR + '@yopmail.com', + store_name: process.env.VENDOR + 'store', + first_name: process.env.VENDOR, + last_name: 'v1', + social: { + fb: 'http://dokan.test', + youtube: 'http://dokan.test', + twitter: 'http://dokan.test', + linkedin: 'http://dokan.test', + pinterest: 'http://dokan.test', + instagram: 'http://dokan.test', + flickr: 'http://dokan.test', + }, + phone: '0123456789', + show_email: true, // todo: doesn't work on lite + address: { + street_1: 'abc street', + street_2: 'xyz street', + city: 'New York', + zip: '10003', + state: 'NY', + country: 'US', + }, + location: '40.7127753,-74.0059728', + banner: 0, + banner_id: 0, + gravatar: 0, + gravatar_id: 0, + products_per_page: 12, + show_more_product_tab: true, + toc_enabled: true, // todo: doesn't work on lite + store_toc: 'test Vendor terms and conditions', + featured: true, + rating: { + rating: '4.00', // todo: doesn't work on lite + count: 1, + }, + enabled: true, + payment: { + paypal: { + 0: 'email', + email: 'paypal@g.c', + }, + bank: { + ac_name: 'account name', + ac_type: 'personal', + ac_number: '1234567', + bank_name: 'bank name', + bank_addr: 'bank address', + routing_number: '123456', + iban: '123456', + swift: '12345', + }, + stripe: false, + }, + trusted: true, + // store_open_close: { + // enabled: false, + // time: [], + // open_notice: 'Store is open', + // close_notice: 'Store is closed', + // }, + store_open_close: { + // todo: doesn't work on lite + enabled: true, + time: { + monday: { + status: 'open', // 'close' + opening_time: ['12:00 am'], // [] + closing_time: ['11:30 pm'], // [] + }, + tuesday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + wednesday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + thursday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + friday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + saturday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + sunday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + }, + open_notice: 'Store is open', + close_notice: 'Store is closed', + }, + company_name: '', + vat_number: '', + company_id_number: '', + bank_name: '', + bank_iban: '', + categories: [ + { + // id: 74, + // name: 'Uncategorized', + // slug: 'uncategorized' + }, + ], + admin_commission: '', + admin_additional_fee: '', + admin_commission_type: '', + }, + + createStore2: { + user_login: process.env.VENDOR2, + user_pass: process.env.USER_PASSWORD, + user_nicename: process.env.VENDOR2 + 'store', + role: 'seller', + email: process.env.VENDOR2 + '@yopmail.com', + store_name: process.env.VENDOR2 + 'store', + first_name: process.env.VENDOR2, + last_name: 'v1', + social: { + fb: 'http://dokan.test', + youtube: 'http://dokan.test', + twitter: 'http://dokan.test', + linkedin: 'http://dokan.test', + pinterest: 'http://dokan.test', + instagram: 'http://dokan.test', + flickr: 'http://dokan.test', + }, + phone: '0123456789', + show_email: true, // todo: doesn't work on lite + address: { + street_1: 'abc street', + street_2: 'xyz street', + city: 'New York', + zip: '10003', + state: 'NY', + country: 'US', + }, + location: '40.7127753,-74.0059728', + banner: 0, + banner_id: 0, + gravatar: 0, + gravatar_id: 0, + products_per_page: 12, + show_more_product_tab: true, + toc_enabled: true, // todo: doesn't work on lite + store_toc: 'test Vendor terms and conditions', + featured: true, + rating: { + rating: '4.00', // todo: doesn't work on lite + count: 1, + }, + enabled: true, + payment: { + paypal: { + 0: 'email', + email: 'paypal@g.c', + }, + bank: { + ac_name: 'account name', + ac_type: 'personal', + ac_number: '1234567', + bank_name: 'bank name', + bank_addr: 'bank address', + routing_number: '123456', + iban: '123456', + swift: '12345', + }, + stripe: false, + }, + trusted: true, + // store_open_close: { + // enabled: false, + // time: [], + // open_notice: 'Store is open', + // close_notice: 'Store is closed', + // }, + store_open_close: { + // todo: doesn't work on lite + enabled: true, + time: { + monday: { + status: 'open', // 'close' + opening_time: ['12:00 am'], // [] + closing_time: ['11:30 pm'], // [] + }, + tuesday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + wednesday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + thursday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + friday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + saturday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + sunday: { + status: 'open', + opening_time: ['12:00 am'], + closing_time: ['11:30 pm'], + }, + }, + open_notice: 'Store is open', + close_notice: 'Store is closed', + }, + company_name: '', + vat_number: '', + company_id_number: '', + bank_name: '', + bank_iban: '', + categories: [ + { + // id: 74, + // name: 'Uncategorized', + // slug: 'uncategorized' + }, + ], + admin_commission: '', + admin_additional_fee: '', + admin_commission_type: '', + }, + + createCustomer1: { + email: process.env.CUSTOMER + '@yopmail.com', + first_name: 'customer1', + last_name: 'c1', + role: 'customer', + username: process.env.CUSTOMER, + password: process.env.USER_PASSWORD, + billing: { + first_name: process.env.CUSTOMER, + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + email: process.env.CUSTOMER + '@yopmail.com', + phone: '0123456789', + }, + shipping: { + first_name: process.env.CUSTOMER, + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + phone: '0123456789', + }, + }, + + updateAddress: { + billing: { + first_name: faker.person.firstName(), + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + email: faker.person.firstName() + '@yopmail.com', + phone: '0123456789', + }, + shipping: { + first_name: faker.person.firstName(), + last_name: 'c1', + company: '', + address_1: 'abc street', + address_2: 'xyz street', + city: 'New York', + postcode: '10003', + country: 'US', + state: 'NY', + phone: '0123456789', + }, + }, + + // update password + updatePassword: { + password: String(process.env.USER_PASSWORD), + }, + + // quote rule + + createQuoteRule: () => ({ + rule_name: 'QR_' + faker.string.nanoid(10), + selected_user_role: ['customer', 'guest'], + category_ids: [], + product_ids: [], + hide_price: '1', + hide_price_text: 'Price is hidden', + hide_cart_button: 'replace', + button_text: 'Add to quote', + apply_on_all_product: '1', + rule_priority: '0', + status: 'publish', + }), + + updateQuoteRule: { + rule_name: 'updated_QR_' + faker.string.nanoid(10), + selected_user_role: ['customer'], + hide_price: '0', + hide_price_text: 'Price is covered', + hide_cart_button: 'keep_and_add_new', + button_text: ' To quote', + apply_on_all_product: '1', + }, + + // quote request + + createQuoteRequest: () => ({ + quote_title: 'QT_' + faker.string.nanoid(10), + // user_id: '', + customer_info: { + name_field: 'customer1', + email_field: 'customer1@yopmail.com', + company_field: 'c1', + phone_field: '0987654321', + }, + product_ids: [''], + offer_price: ['50'], + offer_product_quantity: ['10'], + status: 'pending', + }), + + updateRequestQuote: { + quote_title: 'updated_QT_' + faker.string.nanoid(10), + // user_id: '', + customer_info: { + name_field: 'customer1', + email_field: 'customer1@yopmail.com', + company_field: 'c1', + phone_field: '0987654321', + }, + product_ids: [''], + offer_price: ['30'], + offer_product_quantity: ['20'], + }, + + convertToOrder: { + quote_id: '', + status: 'converted', + }, + + // settings + updateSettingsGroup: { + items: [ + { + id: 'store_name', + value: 'adminStore1', + }, + { + id: 'phone', + value: '164877665544433', + }, + ], + }, + + updateSubSettingFromSingleSettingGroup: { + value: 'adminStore1', + }, + + updateSubSubSettingFromSingleSettingGroup: { + value: 'zzz street', + }, + + setDefaultAttribute: {}, + + filterParams: { + product_type: 'simple', + }, + + // seller badge + + createSellerBadgeFeatureProducts: { + event_type: 'featured_products', + badge_name: 'Featured Products', + badge_status: 'published', + levels: [ + { + level: 0, + level_condition: '', + level_data: '', + }, + ], + }, + + createSellerBadgeExclusiveToPlatform: { + event_type: 'exclusive_to_platform', + badge_name: 'Exclusive to Platform', + badge_status: 'published', + levels: [ + { + level: 0, + level_condition: '', + level_data: '', + }, + ], + }, + + createSellerBadgeProductsPublished: { + event_type: 'product_published', + badge_name: 'Products Published', + badge_status: 'published', + levels: [ + { + level_condition: '<', + level_data: '10', + }, + { + level_condition: '<', + level_data: '20', + }, + { + level_condition: '<', + level_data: '30', + }, + ], + }, + + updateSellerBadge: { + event_type: 'exclusive_to_platform', + badge_name: 'Exclusive to Platform', + badge_logo: 'http://dokan16.test/wp-content/plugins/dokan-pro/modules/seller-badge/assets/images/badges/sale-only-here.svg', + badge_status: 'draft', + levels: [ + { + level: 0, + level_condition: '', + level_data: '', + }, + ], + }, + + // reverse withdrawal + + amountToPay: { + amount: '10', + }, + + // spmv + + spmvSearch: { + search: '', + }, + + spmvAddToStore: { + product_id: '', + }, + + paramsReverseWithdrawalTransactions: { + 'trn_date[from]': `${helpers.currentYear}-01-01 00:00:00`, + 'trn_date[to]': `${helpers.currentYear}-12-31 00:00:00`, + vendor_id: '', + }, + + paramsDeleteStore: { + reassign: 0, + }, + + paramsGetOrdersWithDateRange: { + before: `${helpers.currentYear}-01-01`, + after: `${helpers.currentYear}-12-30`, + }, + + paramsDeleteStoreCategory: { + force: true, + }, + + paramsForceDelete: { + force: true, + }, + + paramsGetProductsWithPagination: { + per_page: '10', + page: '1', + }, +}; diff --git a/tests/pw/utils/sampleData/avatar.png b/tests/pw/utils/sampleData/avatar.png new file mode 100644 index 0000000000..a171172f5f Binary files /dev/null and b/tests/pw/utils/sampleData/avatar.png differ diff --git a/tests/pw/utils/sampleData/license.png b/tests/pw/utils/sampleData/license.png new file mode 100644 index 0000000000..a8e763a86e Binary files /dev/null and b/tests/pw/utils/sampleData/license.png differ diff --git a/tests/pw/utils/sampleData/products.csv b/tests/pw/utils/sampleData/products.csv new file mode 100644 index 0000000000..77e0e6316e --- /dev/null +++ b/tests/pw/utils/sampleData/products.csv @@ -0,0 +1,2 @@ +ID,Type,SKU,Name,Published,"Is featured?","Visibility in catalog","Short description",Description,"Date sale price starts","Date sale price ends","Tax status","Tax class","In stock?",Stock,"Low stock amount","Backorders allowed?","Sold individually?","Weight (kg)","Length (cm)","Width (cm)","Height (cm)","Allow customer reviews?","Purchase note","Sale price","Regular price",Categories,Tags,"Shipping class",Images,"Download limit","Download expiry days",Parent,"Grouped products",Upsells,Cross-sells,"External URL","Button text",Position,Apply_adjacent_buffer,Availability,Block_cost,Buffer_period,Calendar_display_mode,Cancel_limit_unit,Cancel_limit,Check_start_block_only,Cost,Default_date_availability,Display_cost,Duration_type,Duration_unit,Duration,Enable_range_picker,First_block_time,Has_person_cost_multiplier,Has_person_qty_multiplier,Has_person_types,Has_persons,Has_resources,Has_restricted_days,Max_date_unit,Max_date_value,Max_duration,Max_persons,Min_date_unit,Min_date_value,Min_duration,Min_persons,Person_types,Pricing,Qty,Requires_confirmation,Resource_label,Resource_base_costs,Resource_block_costs,Resource_ids,Resources_assignment,Restricted_days,User_can_cancel,"Meta: dokan_geo_latitude","Meta: dokan_geo_longitude","Meta: dokan_geo_public","Meta: dokan_geo_address" +438,simple,,p1_v1,1,0,visible,,,,,taxable,,1,,,0,0,,,,,1,,,100,Uncategorized,,,,,,,,,,,,0,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,40.7127753,'-74.0059728,1,"New York, NY, USA" diff --git a/tests/pw/utils/sampleData/products.xml b/tests/pw/utils/sampleData/products.xml new file mode 100644 index 0000000000..91cb906fcf --- /dev/null +++ b/tests/pw/utils/sampleData/products.xml @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + dokan1 + http://dokan1.test + + Tue, 01 Aug 2023 15:59:04 +0000 + en-US + 1.2 + http://dokan1.test + http://dokan1.test + + 1uncategorized + 18product_typeauction + 38store_categorycategory1 + 39store_categorycategory2 + 33product_catclothing + 7product_visibilityexclude-from-catalog + 6product_visibilityexclude-from-search + 5product_typeexternal + 8product_visibilityfeatured + 3product_typegrouped + 35pa_sizesl + 36pa_sizesm + 9product_visibilityoutofstock + 10product_visibilityrated-1 + 11product_visibilityrated-2 + 12product_visibilityrated-3 + 13product_visibilityrated-4 + 14product_visibilityrated-5 + 34pa_sizess + 40store_categorysc4 + 2product_typesimple + 16product_typesubscription + 43store_categorytest_store_categoryd2ca5d83-120a-4da6-9d5a-fe2de6bba9b7 + 42store_categorytest_store_categorye5852a0a-2001-4034-8f5a-20ac14f32206 + 41store_categorytest_store_categoryfd072bc0-7f92-41e4-8153-2b9468a303cb + 15product_catuncategorized + 37store_categoryuncategorized + 4product_typevariable + 17product_typevariable-subscription + + + + p1_v1 + http://dokan1.test/product/p1_v1/ + Tue, 01 Aug 2023 15:54:58 +0000 + + http://dokan1.test/product/p1_v1/ + + + + 438 + 2023-08-01 21:54:58 + 2023-08-01 15:54:58 + open + closed + p1_v1 + publish + 0 + 0 + product + + 0 + + + + _regular_price + + + + total_sales + + + + _tax_status + + + + _tax_class + + + + _manage_stock + + + + _backorders + + + + _sold_individually + + + + _virtual + + + + _downloadable + + + + _download_limit + + + + _download_expiry + + + + _stock + + + + _stock_status + + + + _wc_average_rating + + + + _wc_review_count + + + + _product_version + + + + _price + + + + chosen_product_cat + + + + dokan_geo_latitude + + + + dokan_geo_longitude + + + + dokan_geo_public + + + + dokan_geo_address + + + + _regular_price + + + + total_sales + + + + _tax_status + + + + _tax_class + + + + _manage_stock + + + + _backorders + + + + _sold_individually + + + + _virtual + + + + _downloadable + + + + _download_limit + + + + _download_expiry + + + + _stock + + + + _stock_status + + + + _wc_average_rating + + + + _wc_review_count + + + + _product_version + + + + _price + + + + chosen_product_cat + + + + dokan_geo_latitude + + + + dokan_geo_longitude + + + + dokan_geo_public + + + + dokan_geo_address + + + + + diff --git a/tests/pw/utils/summaryReporter.ts b/tests/pw/utils/summaryReporter.ts new file mode 100644 index 0000000000..353a3f4dd7 --- /dev/null +++ b/tests/pw/utils/summaryReporter.ts @@ -0,0 +1,93 @@ +import { FullConfig, FullResult, Reporter, Suite, TestCase, TestError, TestResult, TestStep } from '@playwright/test/reporter'; +import fs from 'fs'; +import path from 'path'; + +// todo: update custom reporter, add more features like duration, failed tests list + +type TestResults = { + [key: string]: string; +}; + +type TestOptions = { + outputFile?: string; +}; + +const getFormattedDuration = (milliseconds: number) => { + const hours = Math.floor(milliseconds / (1000 * 60 * 60)); + const min = Math.floor((milliseconds / (1000 * 60)) % 60); + const sec = Math.floor((milliseconds / 1000) % 60); + return `${hours < 1 ? '' : hours + 'h '}${min < 1 ? '' : min + 'm '}${sec < 1 ? '' : sec + 's'}`; +}; + +const summary = { + suite_name: '', + total_tests: 0, + passed: 0, + failed: 0, + flaky: 0, + skipped: 0, + suite_duration: 0, + suite_duration_formatted: '', +}; +export default class summaryReport implements Reporter { + private testResults: TestResults = {}; + private options: TestOptions = {}; + private startTime: number = 0; + private endTime: number = 0; + + constructor(options: TestOptions) { + if (options) { + this.options = options; + } + } + + onBegin(config: FullConfig, suite: Suite): void { + this.startTime = Date.now(); + summary.total_tests = suite.allTests().length; + } + + // onTestBegin(test: TestCase, result: TestResult): void {} + + // onStepBegin(test: TestCase, result: TestResult, step: TestStep): void {} + + // onStepEnd(test: TestCase, result: TestResult, step: TestStep): void {} + + // onStdOut(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void { + // console.log(chunk); + // } + + // onStdErr(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void {} + + // onError?(error: TestError): void { + // console.log(error); + // } + + onTestEnd(test: TestCase, result: TestResult): void { + this.testResults[test.id] = test.outcome(); + } + + onEnd(result: FullResult): void { + this.endTime = Date.now(); + summary.suite_duration = this.endTime - this.startTime; + summary.suite_duration_formatted = getFormattedDuration(summary.suite_duration); + + const results = [...Object.values(this.testResults)]; + summary.passed = results.filter(x => x === 'expected').length; + summary.failed = results.filter(x => x === 'unexpected').length; + summary.flaky = results.filter(x => x === 'flaky').length; + summary.skipped = results.filter(x => x === 'skipped').length; + // console.log(summary); + + // fs.writeFileSync('results.json', JSON.stringify(summary)); + + if (this.options.outputFile) { + const outputFile = this.options.outputFile; + if (!fs.existsSync(path.dirname(outputFile))) { + fs.mkdirSync(path.dirname(outputFile), { recursive: true }); + } + fs.writeFileSync(outputFile, JSON.stringify(summary)); + } else { + console.log(summary); + } + } +} diff --git a/tests/pw/utils/testData.ts b/tests/pw/utils/testData.ts new file mode 100644 index 0000000000..6ff9cbe438 --- /dev/null +++ b/tests/pw/utils/testData.ts @@ -0,0 +1,2016 @@ +import { faker } from '@faker-js/faker'; +import { helpers } from '@utils/helpers'; + +interface user { + username: string; + password: string; +} + +interface admin { + username: string; + password: string; +} + +export { admin, user }; + +export const data = { + // Generated test data + auth: { + adminAuthFile: 'playwright/.auth/adminStorageState.json', + vendorAuthFile: 'playwright/.auth/vendorStorageState.json', + customerAuthFile: 'playwright/.auth/customerStorageState.json', + + adminAuth: { + storageState: 'playwright/.auth/adminStorageState.json', + }, + + vendorAuth: { + storageState: 'playwright/.auth/vendorStorageState.json', + }, + + customerAuth: { + storageState: 'playwright/.auth/customerStorageState.json', + }, + + noAuth: { + storageState: { cookies: [], origins: [] }, + }, + }, + + // keyboard key + key: { + arrowDown: 'ArrowDown', + enter: 'Enter', + home: 'Home', + end: 'End', + }, + + plugin: { + pluginsLite: ['basic-auth', 'dokan', 'woocommerce'], + plugins: ['basic-auth', 'dokan', 'dokan-pro', 'woocommerce', 'woocommerce-bookings', 'woocommerce-product-addons', 'woocommerce-simple-auctions', 'woocommerce-subscriptions'], + dokanPro: ['dokan-pro'], + activeClass: 'active', + }, + + woocommerce: { + saveSuccessMessage: 'Your settings have been saved.', + }, + + // Product + product: { + publishSuccessMessage: 'Product published. ', + draftUpdateSuccessMessage: 'Product draft updated. ', + pendingProductUpdateSuccessMessage: 'Product updated. ', + createUpdateSaveSuccessMessage: 'Success! The product has been saved successfully. View Product →', + updateSuccessMessage: 'Product updated. ', + + status: { + publish: 'publish', + draft: 'draft', + pending: 'pending', + }, + + stockStatus: { + outOfStock: 'outofstock', + }, + + tax: { + status: 'taxable', // 'taxable', 'shipping', 'none' + taxClass: 'taxable', // 'taxable', 'reduced-rate', 'zero-rate' + }, + + type: { + simple: 'simple', + variable: 'variable', + simpleSubscription: 'subscription', + variableSubscription: 'variable-subscription', + external: 'external', + vendorSubscription: 'product_pack', + booking: 'booking', + auction: 'auction', + }, + + name: { + simple: () => faker.commerce.productName() + ' (Simple)', + variable: () => faker.commerce.productName() + ' (Variable)', + external: () => faker.commerce.productName() + ' (External)', + grouped: () => faker.commerce.productName() + ' (Grouped)', + simpleSubscription: () => faker.commerce.productName() + ' (Simple Subscription)', + variableSubscription: () => faker.commerce.productName() + ' (Variable Subscription)', + dokanSubscription: { + nonRecurring: () => + 'Dokan Subscription ' + + faker.helpers.arrayElement(['Gold', 'Silver', 'Platinum', 'Premium']) + + ' ' + + faker.string.alpha({ + length: 5, + casing: 'upper', + }) + + ' (Product Pack)', + }, + booking: () => faker.commerce.productName() + ' (Booking)', + auction: () => faker.commerce.productName() + ' (Auction)', + }, + + price: { + // price : faker.commerce.price(100, 200, 2), + // price : faker.number.int({ min: 1, max: 200, precision: 0.01 }), + // price : faker.finance.amount(1, 200, 2), + price_int: () => faker.finance.amount(100, 200, 0), + price_random: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([0, 2])), // 0 = no decimals, 2 = 2 decimals + price_frac: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])), + price_frac_comma: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + auctionPrice: () => faker.commerce.price({ min: 10, max: 100, dec: 0 }), + price: () => data.product.price.price_frac_comma(), + }, + + category: { + unCategorized: 'Uncategorized', + clothings: 'Clothings', + randomCategory1: () => faker.commerce.productAdjective(), + randomCategory: () => 'category_' + faker.string.alpha(5), + categories: faker.helpers.arrayElement(['Electronic Devices', 'Electronic Accessories', 'Men"s Fashion', 'Clothings', 'Women"s Fashion']), + }, + + store: { + adminStore: String(process.env.ADMIN) + 'store', + vendorStore1: String(process.env.VENDOR) + 'store', + }, + + attribute: { + size: { + attributeName: 'size', + attributeTerms: ['s', 'l', 'm'], + }, + + color: { + attributeName: 'color', + attributeTerms: ['red', 'blue', 'black', 'yellow', 'white'], + }, + + randomAttribute: () => ({ + attributeName: 'attribute_' + faker.string.alpha(5), + attributeTerms: ['attributeTerm_' + faker.string.alpha(5)], + }), + }, + + simple: { + productType: 'simple', + productName: () => faker.commerce.productName() + ' (Simple)', + category: 'Uncategorized', + regularPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + storeName: String(process.env.VENDOR) + 'store', + status: 'publish', + stockStatus: false, + editProduct: '', + }, + + variable: { + productType: 'variable', + productName: () => faker.commerce.productName() + ' (Variable)', + category: 'Uncategorized', + regularPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + storeName: String(process.env.VENDOR) + 'store', + status: 'publish', + stockStatus: false, + attribute: 'sizes', + attributeTerms: ['s', 'l', 'm'], + variations: { + linkAllVariation: 'link_all_variations', + variableRegularPrice: 'variable_regular_price', + }, + saveSuccessMessage: 'Success! The product has been saved successfully. View Product →', + }, + + external: { + productType: 'external', + productName: () => faker.commerce.productName() + ' (External)', + productUrl: '/product/p1_v1-simple/', + buttonText: 'Buy product', + category: 'Uncategorized', + regularPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + storeName: String(process.env.VENDOR) + 'store', + status: 'publish', + saveSuccessMessage: 'Success! The product has been saved successfully. View Product →', + }, + + simpleSubscription: { + productType: 'subscription', + productName: () => faker.commerce.productName() + ' (Simple Subscription)', + category: 'Uncategorized', + regularPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + subscriptionPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + subscriptionPeriodInterval: '1', // '0', '1', '2', '3', '4', '5', '6' + subscriptionPeriod: 'month', // 'day', 'week', 'month', 'year' + expireAfter: '0', // '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24' + subscriptionTrialLength: '0', + subscriptionTrialPeriod: 'day', // 'day', 'week', 'month', 'year' + storeName: String(process.env.VENDOR) + 'store', + status: 'publish', + saveSuccessMessage: 'Success! The product has been saved successfully. View Product →', + }, + + variableSubscription: { + productType: 'variable-subscription', + productName: () => faker.commerce.productName() + ' (Variable Subscription)', + category: 'Uncategorized', + regularPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + subscriptionPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + subscriptionPeriodInterval: '1', + subscriptionPeriod: 'month', + expireAfter: '0', + subscriptionTrialLength: '0', + subscriptionTrialPeriod: 'day', + storeName: String(process.env.VENDOR) + 'store', + status: 'publish', + attribute: 'sizes', + attributeTerms: ['s', 'l', 'm'], + variations: { + linkAllVariation: 'link_all_variations', + variableRegularPrice: 'variable_regular_price', + }, + saveSuccessMessage: 'Success! The product has been saved successfully. View Product →', + }, + + vendorSubscription: { + productType: 'product_pack', + productName: () => + 'Dokan Subscription ' + + faker.helpers.arrayElement(['Gold', 'Silver', 'Platinum', 'Premium']) + + ' ' + + faker.string.alpha({ + length: 5, + casing: 'upper', + }) + + ' (Product Pack)', + category: 'Uncategorized', + regularPrice: () => faker.finance.amount(100, 200, faker.helpers.arrayElement([1, 2])).replace('.', ','), + numberOfProducts: '-1', + packValidity: '0', + advertisementSlot: '-1', + expireAfterDays: '-1', + storeName: String(process.env.VENDOR) + 'store', + status: 'publish', + }, + + booking: { + productName: () => faker.commerce.productName() + ' (Booking)', + name: '', + productType: 'booking', + category: 'Uncategorized', + bookingDurationType: 'customer', // 'fixed', 'customer' + bookingDuration: '2', + bookingDurationMin: '1', + bookingDurationMax: '20', + bookingDurationUnit: 'day', // 'month', 'day', 'hour', 'minute' + calendarDisplayMode: 'always_visible', // '', 'always_visible' + maxBookingsPerBlock: '5', + minimumBookingWindowIntoTheFutureDate: '0', + minimumBookingWindowIntoTheFutureDateUnit: 'month', + maximumBookingWindowIntoTheFutureDate: '5', + maximumBookingWindowIntoTheFutureDateUnit: 'month', + baseCost: '20', + blockCost: '10', + storeName: String(process.env.VENDOR) + 'store', + saveSuccessMessage: 'Success! The product has been saved successfully.', + + resource: { + resourceName: () => 'Booking Resource_' + faker.string.nanoid(10), + name: '', + quantity: String(faker.number.int({ min: 1, max: 100 })), + }, + }, + + // Auction + auction: { + productName: () => faker.commerce.productName() + ' (Auction)', + name: '', + productType: 'auction', + category: 'Uncategorized', + itemCondition: 'new', // 'new', 'used' + auctionType: 'normal', // 'normal', 'reverse' + regularPrice: () => faker.finance.amount(10, 100, faker.helpers.arrayElement([1, 2])).replace('.', ','), + bidIncrement: () => faker.finance.amount(40, 50, faker.helpers.arrayElement([1, 2])).replace('.', ','), + reservedPrice: () => faker.finance.amount(400, 500, faker.helpers.arrayElement([1, 2])).replace('.', ','), + buyItNowPrice: () => faker.finance.amount(900, 1000, faker.helpers.arrayElement([1, 2])).replace('.', ','), + startDate: helpers.currentDateTime, + endDate: helpers.addDays(helpers.currentDateTime, 20, 'full'), + storeName: String(process.env.VENDOR) + 'store', + // saveSuccessMessage: '× Success! The product has been updated successfully. View Product →', + saveSuccessMessage: 'Success! The product has been updated successfully.', + }, + + // Review + review: { + rating: String(faker.number.int({ min: 1, max: 5 })), + reviewMessage: () => faker.string.nanoid(10), + }, + + // Report + report: { + reportReason: faker.helpers.arrayElement([ + 'This content is spam', + 'This content should marked as adult', + 'This content is abusive', + 'This content is violent', + 'This content suggests the author might be risk of hurting themselves', + 'This content infringes upon my copyright', + 'This content contains my private information', + 'Other', + ]), + reportReasonDescription: 'report reason description', + reportSubmitSuccessMessage: 'Your report has been submitted. Thank you for your response.', + + // non logged user + username: String(process.env.CUSTOMER), + password: String(process.env.USER_PASSWORD), + + // guest user + guestName: () => faker.person.firstName('male'), + guestEmail: () => faker.person.firstName('male') + '@email.com', + }, + + // Enquiry + enquiry: { + enquiryDetails: 'enquiry details', + enquirySubmitSuccessMessage: 'Email sent successfully!', + + // guest user + guestName: () => faker.person.firstName('male'), + guestEmail: () => faker.person.firstName('male') + '@email.com', + }, + }, + + // store + store: { + rating: faker.helpers.arrayElement(['width: 20%', 'width: 40%', 'width: 60%', 'width: 80%', 'width: 100%']), + reviewTitle: 'store review title', + reviewMessage: () => faker.string.nanoid(10), + }, + + // store list + storeList: { + sort: 'most_recent', + layout: { + grid: 'grid', + list: 'list', + }, + }, + + // order + order: { + orderStatus: { + pending: 'wc-pending', + processing: 'wc-processing', + onhold: 'wc-on-hold', + completed: 'wc-completed', + cancelled: 'wc-cancelled', + refunded: 'wc-refunded', + failed: 'wc-failed', + }, + }, + + // order Note + orderNote: { + customer: { + note: 'test order note', + noteType: 'Customer note', + }, + private: { + note: 'test private order note', + noteType: 'Private note', + }, + + note: () => 'test order note' + faker.string.nanoid(10), + }, + + // order Tracking Details + orderTrackingDetails: { + shippingProvider: 'test shipping provider', + trackingNumber: '1234567890', + dateShipped: helpers.currentDate, + }, + + // order Shipment Details + orderShipmentDetails: { + shipmentOrderItem: 'p1_v1 (simple)', + shipmentOrderItemQty: '1', + shippingStatus: 'ss_proceccing', // ss_delivered, ss_cancelled, ss_proceccing, ss_ready_for_pickup, ss_pickedup, ss_on_the_way + shippingProvider: 'sp-dhl', // sp-dhl, sp-dpd, sp-fedex, sp-polish-shipping-providers, sp-ups, sp-usps, sp-other + dateShipped: helpers.currentDate, + trackingNumber: '1234567890', + comments: 'test shipment comment', + }, + + rma: { + // requestWarranty + requestWarranty: { + itemQuantity: '1', + refundRequestType: 'refund', + refundRequestReasons: 'defective', + refundRequestDetails: 'I would like to return this product', + refundSubmitSuccessMessage: 'Request has been successfully submitted', + }, + }, + + paymentDetails: { + strip: { + striptNon3D: '4242424242424242', + stript3D: '4000002500003155', + cardNumber: '4242424242424242', + expiryMonth: '12', + expiryYear: '50', + number: '4000002500003155', + expiryDate: '1250', + cvc: '111', + }, + + mangopay: { + creditCard: '4972485830400049', + expiryMonth: '12', + expiryYear: '50', + cvc: '111', + }, + + stripExpress: { + paymentMethod: 'card', + cardInfo: { + cardNumber: '4242424242424242', + expiryMonth: '12', + expiryYear: '50', + expiryDate: '1250', // MMYY + cvc: '111', + }, + }, + }, + + // coupon + coupon: { + // title : () => 'VC_' + faker.string.alpha({ count: 5, casing: 'upper' },), + couponTitle: () => 'VC_' + faker.string.nanoid(10), + title: '', + amount: () => faker.number.int({ min: 1, max: 10 }).toString(), + discount_type: () => faker.helpers.arrayElement(['percent', 'fixed_product']), // percent, fixed_product, booking_person, sign_up_fee, sign_up_fee_percent, recurring_fee, recurring_percent + discountType: 'percent', + description: 'test Coupon description', + existingCouponErrorMessage: 'Coupon title already exists', + editCoupon: '', + }, + + // address + address: { + street1: 'abc street', + street2: 'xyz street', + country: 'United States (US)', + countrySelectValue: 'US', + stateSelectValue: 'NY', + city: 'New York', + zipCode: '10006', + state: 'New York', + }, + + wpSettings: { + saveSuccessMessage: 'Your settings have been saved.', + general: { + timezone: 'UTC+6', + saveSuccessMessage: 'Settings saved.', + }, + + permalink: { + customBaseInput: '/product/', + saveSuccessMessage: 'Permalink structure updated.', + }, + }, + + tax: { + taxRate: '5', + enableTax: true, + saveSuccessMessage: 'Your settings have been saved.', + }, + + shipping: { + enableShipping: 'Ship to all countries you sell to', + disableShipping: 'Disable shipping & shipping calculations', + shippingZone: 'US', + + shippingMethods: { + methods: faker.helpers.arrayElement(['flat_rate', 'free_shipping', 'local_pickup', 'dokan_table_rate_shipping', 'dokan_distance_rate_shipping', 'dokan_vendor_shipping']), + flatRate: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'flat_rate', + shippingMethod: 'Flat rate', + taxStatus: 'taxable', // 'none + shippingCost: '20', + }, + + freeShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'free_shipping', + shippingMethod: 'Free shipping', + freeShippingRequires: 'min_amount', // 'coupon', 'min_amount', 'either', 'both' + freeShippingMinimumOrderAmount: '200', + }, + + localPickup: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'local_pickup', + shippingMethod: 'Local pickup', + taxStatus: 'taxable', // 'none + shippingCost: '20', + }, + + tableRateShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'dokan_table_rate_shipping', + shippingMethod: 'Vendor Table Rate', + }, + + distanceRateShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'dokan_distance_rate_shipping', + shippingMethod: 'Vendor Distance Rate', + }, + + vendorShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'dokan_vendor_shipping', + shippingMethod: 'Vendor Shipping', + taxStatus: 'taxable', // 'none + }, + }, + + shippingTaxStatus: 'taxable', + saveSuccessMessage: 'Your settings have been saved.', + }, + + payment: { + saveSuccessMessage: 'Your settings have been saved.', + currency: { + dollar: 'United States (US) dollar ($)', + euro: 'Euro (€)', + rupee: 'Indian rupee (₹)', + currencyOptions: { + thousandSeparator: ',', + decimalSeparator: ',', + numberOfDecimals: '2', + }, + saveSuccessMessage: 'Your settings have been saved.', + }, + + basicPayment: { + toggleEanbledClass: 'woocommerce-input-toggle--enabled', + toggleDisabledClass: 'woocommerce-input-toggle--disabled', + }, + + stripeConnect: { + title: 'Dokan Credit card (Stripe)', + description: 'Pay with your credit card via Stripe.', + displayNoticeInterval: '7', + stripeCheckoutLocale: 'English', + testPublishableKey: 'pk_test_', + testSecretKey: 'sk_test_', + testClientId: 'ca_', + }, + + paypalMarketPlace: { + title: 'PayPal Marketplace', + description: "Pay via PayPal Marketplace you can pay with your credit card if you don't have a PayPal account", + payPalMerchantId: 'partner_', + sandboxClientId: 'client_', + sandBoxClientSecret: 'secret_', + payPalPartnerAttributionId: 'weDevs_SP_Dokan', + disbursementMode: 'Delayed', // 'Immediate', 'On Order Complete', 'Delayed' + paymentButtonType: 'Smart Payment Buttons', // 'Smart Payment Buttons', 'Standard Button' + marketplaceLogoPath: '/wp-content/plugins/dokan/assets/images/dokan-logo.png', + announcementInterval: '7', + }, + + mangoPay: { + title: 'MangoPay', + description: 'Pay via MangoPay', + sandboxClientId: 'client_', + sandBoxApiKey: 'secret_', + availableCreditCards: 'CB/Visa/Mastercard', // 'CB/Visa/Mastercard', 'Maestro*', 'Bancontact/Mister Cash', 'Przelewy24*', 'Diners*', 'PayLib', 'iDeal*', 'MasterPass*', 'Bankwire Direct*' + availableDirectPaymentServices: 'Sofort*', // 'Sofort*', 'Giropay*'], + transferFunds: 'On payment completed', // 'On payment completed', 'On order completed', 'Delayed' + typeOfVendors: 'Either', // 'Individuals', 'Business', 'Either' + businessRequirement: 'Any', // 'Organizations', 'Soletraders', 'Businesses', 'Any' + announcementInterval: '7', + }, + + razorPay: { + title: 'Razorpay', + description: 'Pay securely by Credit or Debit card or Internet Banking through Razorpay.', + testKeyId: 'rzp_test', + testKeySecret: 'rzp_test', + disbursementMode: 'Delayed', // 'Immediate', 'On Order Complete', 'Delayed' + announcementInterval: '7', + }, + + stripeExpress: { + title: 'Dokan Express Payment Methods', + description: 'Pay with your credit card via Stripe.', + testPublishableKey: 'pk_test_', + testSecretKey: 'sk_test_', + testWebhookSecret: 'webHook_test_', + paymentMethods: { + card: 'Credit/Debit Card', + ideal: 'iDEAL', + }, + iDealBanks: ['abn_amro', 'asn_bank', 'bunq', 'handelsbanken', 'ing', 'knab', 'rabobank', 'regiobank', 'revolut', 'sns_bank', 'triodos_bank', 'van_lanschot'], + disbursementMode: 'Delayed', // 'On payment completed', 'On order completed', 'Delayed' + customerBankStatement: 'Dokan', + paymentRequestButtonType: 'default', // 'default', 'buy', 'donate', 'book' + paymentRequestButtonTheme: 'dark', // 'dark', 'light', 'light-outline' + paymentRequestButtonLocation: { + product: 'Product', + cart: 'Cart', + }, + announcementInterval: '7,', + }, + }, + + // Dokan Setup Wizard + dokanSetupWizard: { + vendorStoreURL: 'store', + shippingFeeRecipient: 'seller', // 'seller', 'admin' + taxFeeRecipient: 'seller', // 'seller', 'admin' + mapApiSource: 'google_maps', // 'google_maps', 'mapbox' + googleMapApiKey: String(process.env.GMAP), + sellingProductTypes: 'sell_both', // 'physical', 'digital', 'sell_both', + commissionType: 'percentage', // 'flat','percentage' 'combine', + adminCommission: '10', + minimumWithdrawLimit: '5', + }, + + // Vendor Setup Wizard + vendorSetupWizard: { + choice: true, + storeProductsPerPage: '12', + street1: 'abc street', + street2: 'xyz street', + country: 'United States (US)', + city: 'New York', + zipCode: '10006', + state: 'New York', + storeCategory: 'Uncategorized', + mapLocation: 'New York', + paypal: () => faker.internet.email(), + bankAccountName: 'accountName', + bankAccountType: faker.helpers.arrayElement(['personal', 'business']), + bankAccountNumber: faker.string.alphanumeric(10), + bankName: 'bankName', + bankAddress: 'bankAddress', + bankRoutingNumber: faker.string.alphanumeric(10), + bankIban: faker.string.alphanumeric(10), + bankSwiftCode: faker.string.alphanumeric(10), + customPayment: '1234567890', + skrill: faker.internet.email(), + }, + + storeShare: { + facebook: 'facebook', + twitter: 'twitter', + linkedin: 'linkedin', + pinterest: 'pinterest', + }, + + subUrls: { + ajax: '/admin-ajax.php', + post: '/post.php', + gmap: '/maps/api', + + backend: { + login: 'wp-login.php', + adminLogin: 'wp-admin', + adminLogout: 'wp-login.php?action=logout', + adminDashboard: 'wp-admin', + user: 'wp-admin/user-edit.php', + setupWP: 'wp-admin/install.php', + general: 'wp-admin/options-general.php', + permalinks: 'wp-admin/options-permalink.php', + plugins: 'wp-admin/plugins.php', + + dokan: { + setupWizard: 'wp-admin/admin.php?page=dokan-setup', + dokan: 'wp-admin/admin.php?page=dokan#', + + // only lite + liteModules: 'wp-admin/admin.php?page=dokan#/pro-modules', + proFeatures: 'wp-admin/admin.php?page=dokan#/premium', + + // lite and pro + withdraw: 'wp-admin/admin.php?page=dokan#/withdraw?status=pending', + reverseWithdraws: 'wp-admin/admin.php?page=dokan#/reverse-withdrawal', + vendors: 'wp-admin/admin.php?page=dokan#/vendors', + vendorDetails: (vendorId: string) => `wp-admin/admin.php?page=dokan#/vendors/${vendorId}`, + storeCategories: 'wp-admin/admin.php?page=dokan#/store-categories', + abuseReports: 'wp-admin/admin.php?page=dokan#/abuse-reports', + storeReviews: 'wp-admin/admin.php?page=dokan#/store-reviews', + storeSupport: 'wp-admin/admin.php?page=dokan#/admin-store-support', + requestForQuote: 'wp-admin/admin.php?page=dokan#/request-for-quote', + requestForQuoteRules: 'wp-admin/admin.php?page=dokan#/request-for-quote/quote-rules', + sellerBadge: 'wp-admin/admin.php?page=dokan#/dokan-seller-badge', + announcements: 'wp-admin/admin.php?page=dokan#/announcement', + refunds: 'wp-admin/admin.php?page=dokan#/refund?status=pending', + reports: 'wp-admin/admin.php?page=dokan#/reports', + allLogs: 'wp-admin/admin.php?page=dokan#/reports?tab=logs', + modules: 'wp-admin/admin.php?page=dokan#/modules', + tools: 'wp-admin/admin.php?page=dokan#/tools', + verifications: 'wp-admin/admin.php?page=dokan-seller-verifications', + 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', + settings: 'wp-admin/admin.php?page=dokan#/settings', + license: 'wp-admin/admin.php?page=dokan_updates', + + // others + downloadOrderLogs: 'wp-admin/admin.php?download-order-log-csv', + subscribe: 'https://api.getwemail.io/v1/embed/subscribe', + }, + + wc: { + products: 'wp-admin/edit.php?post_type=product', + productDetails: (productId: string) => `wp-admin/post.php?post=${productId}&action=edit`, + addNewProducts: 'wp-admin/post-new.php?post_type=product', + addNewCategories: 'wp-admin/edit-tags.php?taxonomy=product_cat&post_type=product', + addNewAttributes: 'wp-admin/edit.php?post_type=product&page=product_attributes', + searchAttribute: 'wp-admin/admin-ajax.php?action=woocommerce_json_search_product_attributes', + term: 'wp-admin/admin-ajax.php?term', + taxonomyTerms: 'wp-admin/admin-ajax.php?action=woocommerce_json_search_taxonomy_terms', + taxonomy: 'wp-admin/edit-tags.php?taxonomy', + coupons: 'wp-admin/edit.php?post_type=shop_coupon', + addCoupon: 'wp-admin/post-new.php?post_type=shop_coupon', + orders: 'wp-admin/edit.php?post_type=shop_order', + settings: 'wp-admin/admin.php?page=wc-settings', + }, + }, + + frontend: { + // customer + myAccount: 'my-account', + myOrders: 'my-orders', + requestForQuote: 'request-quote', + requestedQuote: 'my-account/request-a-quote', + accountMigration: 'my-account/account-migration', + orderCancel: 'cart/?cancel_order', + orderAgain: 'cart/?order_again', + orderPay: 'checkout/order-pay', + orderReceived: 'checkout/order-received', + customerLogout: 'my-account/customer-logout', + + rmaRequests: 'my-account/rma-requests', + viewRmaRequests: 'my-account/view-rma-requests', + requestWarranty: 'my-account/request-warranty', + vendors: 'my-account/following', + supportTickets: 'my-account/support-tickets', + + productCustomerPage: 'product', + ordersCustomerPage: 'orders', + shop: 'shop', + shopSort: 'shop/?orderby', + storeListing: 'store-listing', + storeListingSort: 'store-listing/?stores_orderby', + cart: 'cart', + checkout: 'checkout', + addToCart: '?wc-ajax=add_to_cart', + applyCoupon: '?wc-ajax=apply_coupon', + removeCoupon: '?wc-ajax=remove_coupon', + placeOrder: '?wc-ajax=checkout', + billingAddress: 'my-account/edit-address/billing', + shippingAddress: 'my-account/edit-address/shipping', + shippingAddressCheckout: 'wc-ajax=update_order_review', + editAccountCustomer: 'my-account/edit-account', + becomeVendor: 'my-account/account-migration', + productDetails: (productName: string) => `product/${productName}`, + orderDetails: (orderId: string) => `my-account/view-order/${orderId}`, + orderReceivedDetails: (orderId: string, orderKey: string) => `checkout/order-received/${orderId}/?key=${orderKey}`, + vendorDetails: (storeName: string) => `store/${storeName}`, + storeReviews: (storeName: string) => `store/${storeName}/reviews`, + quoteDetails: (quotId: string) => `my-account/request-a-quote/${quotId}`, + supportTicketDetails: (ticketId: string) => `my-account/support-tickets/${ticketId}`, + productSubscriptionDetails: (subscriptionId: string) => `my-account/view-subscription/${subscriptionId}`, + + productReview: 'wp-comments-post.php', + submitSupport: 'wp-comments-post.php', + + // vendor dashboard + vDashboard: { + setupWizard: '?page=dokan-seller-setup', + dashboard: 'dashboard', + products: 'dashboard/products', + productSearch: 'products/?product_listing_search', + productAuction: 'dashboard/new-auction-product', + productBooking: 'dashboard/booking/new-product', + orders: 'dashboard/orders', + userSubscriptions: 'dashboard/user-subscription', + requestQuotes: 'dashboard/requested-quotes', + quoteDetails: (quotId: string) => `dashboard/requested-quotes/${quotId}`, + coupons: 'dashboard/coupons', + reports: 'dashboard/reports', + statement: 'dashboard/reports/?chart=sales_statement', + deliveryTime: 'dashboard/delivery-time-dashboard', + reviews: 'dashboard/reviews', + withdraw: 'dashboard/withdraw', + withdrawRequests: 'dashboard/withdraw-requests', + badges: 'dashboard/seller-badge', + reverseWithdrawal: 'dashboard/reverse-withdrawal', + returnRequest: 'dashboard/return-request', + staff: 'dashboard/staffs', + followers: 'dashboard/followers', + analytics: 'dashboard/analytics', + announcements: 'dashboard/announcement', + tools: 'dashboard/tools', + export: 'dashboard/tools/#export', + csvImport: 'dashboard/tools/csv-import', + csvExport: 'dashboard/tools/csv-export', + auction: 'dashboard/auction', + auctionActivity: 'dashboard/auction-activity', + booking: 'dashboard/booking', + addBooking: 'dashboard/booking/add-booking', + manageBooking: 'dashboard/booking/my-bookings', + bookingCalendar: 'dashboard/booking/calendar', + manageResources: 'dashboard/booking/resources', + storeSupport: 'dashboard/support', + spmv: 'dashboard/products-search', + settingsStore: 'dashboard/settings/store', + settingsAddon: 'dashboard/settings/product-addon', + settingsPayment: 'dashboard/settings/payment', + settingsVerification: 'dashboard/settings/verification', + settingsDeliveryTime: 'dashboard/settings/delivery-time', + settingsShipping: 'dashboard/settings/shipping', + settingsShipstation: 'dashboard/settings/shipstation', + settingsSocialProfile: 'dashboard/settings/social', + settingsRma: 'dashboard/settings/rma', + settingsSeo: 'dashboard/settings/seo', + editAccountVendor: 'dashboard/edit-account', + paypal: 'dashboard/settings/payment-manage-paypal', + bankTransfer: 'dashboard/settings/payment-manage-bank', + customPayment: 'dashboard/settings/payment-manage-dokan_custom', + skrill: 'dashboard/settings/payment-manage-skrill', + }, + }, + + api: { + dokan: { + products: 'dokan/v1/products', + stores: 'dokan/v1/stores', + storeCategories: 'dokan/v1/store-categories', + withdraws: 'dokan/v1/withdraw', + reverseWithdraws: 'dokan/v1/reverse-withdrawal', + abuseReports: 'dokan/v1/abuse-reports', + logs: 'dokan/v1/admin/logs', + announcements: 'dokan/v1/announcement', + dummyData: 'dokan/v1/dummy-data', + refunds: 'dokan/v1/refunds', + modules: 'dokan/v1/admin/modules', + storeReviews: 'dokan/v1/store-reviews', + productAdvertising: 'dokan/v1/product_adv', + wholesaleRegister: 'dokan/v1/wholesale/register', + wholesaleCustomers: 'dokan/v1/wholesale/customers', + storeSupport: 'dokan/v1/admin/support-ticket', + quotes: 'dokan/v1/request-for-quote', + quoteRules: 'dokan/v1/request-for-quote/quote-rule', + sellerBadge: 'dokan/v1/seller-badge', + sellerBadgeEvent: 'dokan/v1/seller-badge/events', + }, + + wc: { + wcProducts: 'wc/v3/products', + }, + }, + }, + + // user + user: { + username: () => faker.person.firstName('male'), + password: String(process.env.USER_PASSWORD), + + userDetails: { + emailDomain: '@email.com', + name: () => faker.person.firstName('male'), + firstName: () => faker.person.firstName('male'), + lastName: () => faker.person.lastName('male'), + // email: faker.internet.email(), + email: () => faker.person.firstName('male') + '@email.com', + role: 'customer', + }, + }, + + // admin + admin: { + username: String(process.env.ADMIN), + password: String(process.env.ADMIN_PASSWORD), + }, + + // vendor + vendor: { + username: String(process.env.VENDOR), + password: String(process.env.USER_PASSWORD), + lastname: (String(process.env.VENDOR)[0] as string) + String(process.env.VENDOR)[String(process.env.VENDOR).length - 1], + storeName: String(process.env.VENDOR) + 'store', + + vendorInfo: { + emailDomain: '@email.com', + // email : () => faker.internet.email(), + email: () => faker.person.firstName('male') + '@email.com', + password: String(process.env.USER_PASSWORD), + password1: String(process.env.USER_PASSWORD) + '1', + firstName: () => faker.person.firstName('male'), + lastName: () => faker.person.lastName('male'), + userName: faker.person.firstName('male'), + shopName: () => faker.company.name(), + shopUrl: () => faker.company.name(), + companyName: faker.company.name(), + companyId: faker.string.alphanumeric(5), + vatNumber: faker.string.alphanumeric(10), + bankIban: faker.finance.iban(), + phoneNumber: faker.phone.number('(###) ###-####'), + phone: '0123456789', + street1: 'abc street', + street2: 'xyz street', + country: 'United States (US)', + countrySelectValue: 'US', + stateSelectValue: 'NY', + city: 'New York', + zipCode: '10006', + state: 'New York', + accountName: 'accountName', + accountNumber: faker.string.alphanumeric(10), + bankName: 'bankName', + bankAddress: 'bankAddress', + routingNumber: faker.string.alphanumeric(10), + swiftCode: faker.string.alphanumeric(10), + iban: faker.string.alphanumeric(10), + role: 'seller', + nanoid: faker.string.nanoid(10), + + // shop details + banner: 'tests/e2e/utils/sampleData/banner.png', + profilePicture: 'tests/e2e/utils/sampleData/avatar.png', + storeName: String(process.env.VENDOR) + 'store', + productsPerPage: '12', + mapLocation: 'New York', + termsAndConditions: 'Vendor Terms and Conditions', + biography: 'Vendor biography', + supportButtonText: 'Get Support', + + account: { + updateSuccessMessage: 'Account details changed successfully.', + }, + + openingClosingTime: { + days: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'], + statusLite: 'open', // open, close + openingTime: '12:00 am', + closingTime: '11:30 pm', + storeOpenNotice: 'Store is open', + storeCloseNotice: 'Store is closed', + }, + + vacation: { + closingStyle: 'datewise', + + instantly: { + closingStyle: 'instantly', + vacationMessage: 'We are currently out of order', + }, + + datewise: { + vacationDayFrom: () => helpers.addDays(helpers.currentDate, helpers.getRandomArbitraryInteger(31, 100), 'compact'), + vacationDayTo: (from: string) => helpers.addDays(from, 31, 'compact'), + closingStyle: 'datewise', + vacationMessage: 'We are currently out of order', + }, + }, + + amountDiscount: { + minimumOrderAmount: '200', + discountPercentage: '10', + }, + + quantityDiscount: { + minimumQuantity: '10', + discountPercentage: '10', + }, + + minMax: { + minimumProductQuantity: '1', + maximumProductQuantity: '20', + minimumAmount: '10', + maximumAmount: '1000000', + category: 'Uncategorized', + }, + + storeSettingsSaveSuccessMessage: 'Your information has been saved successfully', + + socialProfileUrls: { + facebook: 'https://www.facebook.com/', + twitter: 'https://www.twitter.com/', + pinterest: 'https://www.pinterest.com/', + linkedin: 'https://www.linkedin.com/', + youtube: 'https://www.youtube.com/', + instagram: 'https://www.instagram.com/', + flickr: 'https://www.flickr.com/', + }, + + payment: { + // email: () => faker.internet.email(), + email: () => faker.person.firstName('male') + '@email.com', + bankAccountName: 'accountName', + bankAccountType: faker.helpers.arrayElement(['personal', 'business']), + bankAccountNumber: faker.string.alphanumeric(10), + bankName: 'bankName', + bankAddress: 'bankAddress', + bankRoutingNumber: faker.string.alphanumeric(10), + bankIban: faker.string.alphanumeric(10), + bankSwiftCode: faker.string.alphanumeric(10), + }, + + sendEmail: { + subject: 'test email subject', + message: 'test email message', + }, + }, + + shipping: { + shippingPolicy: { + processingTime: '3', // '1', '2', '3', '4', '5', '6', '7', '8', '9' + shippingPolicy: 'shipping policy', + refundPolicy: 'refund policy', + saveSuccessMessage: 'Settings save successfully', + }, + + shippingZone: 'US', + shippingCountry: 'United States (US)', + methods: faker.helpers.arrayElement(['flat_rate', 'free_shipping', 'local_pickup', 'dokan_table_rate_shipping', 'dokan_distance_rate_shipping']), + shippingMethods: { + flatRate: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'flat_rate', + shippingMethod: 'Flat Rate', + shippingMethodTitle: 'Flat Rate', + taxStatus: 'taxable', + shippingCost: '20', + description: 'Flat rate', + calculationType: 'class', // 'item', 'line', 'class', 'order' + shippingMethodSaveSuccessMessage: 'Shipping method added successfully', + zoneSaveSuccessMessage: 'Zone settings save successfully', + saveSuccessMessage: 'Zone settings save successfully', + }, + + freeShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'free_shipping', + shippingMethod: 'Free Shipping', + shippingMethodTitle: 'Free Shipping', + freeShippingRequires: 'min_amount', + freeShippingMinimumOrderAmount: '200', + shippingMethodSaveSuccessMessage: 'Shipping method added successfully', + zoneSaveSuccessMessage: 'Zone settings save successfully', + saveSuccessMessage: 'Zone settings save successfully', + }, + + localPickup: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'local_pickup', + shippingMethod: 'Local Pickup', + shippingMethodTitle: 'Local Pickup', + taxStatus: 'taxable', + shippingCost: '20', + description: 'Local Pickup', + shippingMethodSaveSuccessMessage: 'Shipping method added successfully', + zoneSaveSuccessMessage: 'Zone settings save successfully', + saveSuccessMessage: 'Zone settings save successfully', + }, + + tableRateShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'dokan_table_rate_shipping', + shippingMethod: 'Table Rate', + shippingMethodTitle: 'Table Rate', + taxStatus: 'taxable', + taxIncludedInShippingCosts: 'no', // 'yes', 'no' + handlingFee: '10', + maximumShippingCost: '200', + calculationType: 'item', + handlingFeePerOrder: '10', + minimumCostPerOrder: '10', + maximumCostPerOrder: '200', + shippingMethodSaveSuccessMessage: 'Shipping method added successfully', + zoneSaveSuccessMessage: 'Zone settings save successfully', + saveSuccessMessage: 'Zone settings save successfully', + tableRateSaveSuccessMessage: 'Table rates has been saved successfully!', + }, + + distanceRateShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'dokan_distance_rate_shipping', + shippingMethod: 'Distance Rate', + shippingMethodTitle: 'Distance Rate', + taxStatus: 'taxable', + transportationMode: 'driving', // 'driving', 'walking', 'Bicycling' + avoid: 'none', // 'none', 'tolls', 'highways', 'ferries' + distanceUnit: 'metric', // 'metric', 'imperial' + street1: 'abc street', + street2: 'xyz street', + city: 'New York', + zipCode: '10006', + state: 'New York', + country: 'United States (US)', + shippingMethodSaveSuccessMessage: 'Shipping method added successfully', + zoneSaveSuccessMessage: 'Zone settings save successfully', + saveSuccessMessage: 'Zone settings save successfully', + distanceRateSaveSuccessMessage: 'Distance rates has been saved successfully!', + }, + + vendorShipping: { + shippingZone: 'US', + shippingCountry: 'United States (US)', + selectShippingMethod: 'dokan_vendor_shipping', + shippingMethod: 'Vendor Shipping', + taxStatus: 'taxable', + }, + }, + + shippingTaxStatus: 'taxable', + saveSuccessMessage: 'Zone settings save successfully', + }, + + payment: { + methodName: '', + // email: () => faker.internet.email(), + email: () => faker.person.firstName('male') + '@email.com', + bankAccountName: 'accountName', + bankAccountType: faker.helpers.arrayElement(['personal', 'business']), + bankAccountNumber: faker.string.alphanumeric(10), + bankName: 'bankName', + bankAddress: 'bankAddress', + bankRoutingNumber: faker.string.alphanumeric(10), + bankIban: faker.string.alphanumeric(10), + bankSwiftCode: faker.string.alphanumeric(10), + saveSuccessMessage: 'Your information has been saved successfully', + }, + + verification: { + 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', + + deliveryTime: { + deliveryBlockedBuffer: '0', + timeSlot: '30', + orderPerSlot: '100', + days: ['monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'], + choice: 'full-day', + openingTime: '12:00 am', + closingTime: '11:30 pm', + fullDay: 'Full day', + saveSuccessMessage: 'Delivery settings has been saved successfully!', + }, + + shipStation: { + status: 'Processing', + }, + + socialProfileUrls: { + facebook: 'https://www.facebook.com/', + twitter: 'https://www.twitter.com/', + pinterest: 'https://www.pinterest.com/', + linkedin: 'https://www.linkedin.com/', + youtube: 'https://www.youtube.com/', + instagram: 'https://www.instagram.com/', + flickr: 'https://www.flickr.com/', + saveSuccessMessage: 'Your information has been saved successfully', + }, + + // Rma Settings + rma: { + label: 'Warranty', + type: 'included_warranty', // 'no_warranty', 'included_warranty', 'addon_warranty' + rmaLength: 'lifetime', // 'limited', 'lifetime' + lengthValue: '1', + lengthDuration: 'weeks', // 'days', 'weeks', 'months', 'years' + refundPolicyHtmlBody: 'Refund Policy Vendor', + saveSuccessMessage: 'Settings saved successfully', + }, + + seo: { + seoTitle: 'test seo title', + metaDescription: 'test meta description', + metaKeywords: 'test meta keywords', + facebookTitle: 'test facebook title', + facebookDescription: 'test facebook description', + twitterTitle: 'test twitter title', + twitterDescription: 'test twitter description', + }, + + withdraw: { + withdrawMethod: { + default: 'paypal', + paypal: 'Paypal', + skrill: 'Skrill', + custom: 'dokan_custom', + }, + + defaultWithdrawMethod: { + paypal: 'PayPal', + skrill: 'Skrill', + bankTransfer: 'Bank Transfer', + }, + + preferredPaymentMethod: 'paypal', + preferredSchedule: 'weekly', // monthly,quarterly, biweekly,weekly + currentBalance: '', + minimumWithdrawAmount: '5', // '0', '5', '10', '15', '50', '100', '200', '300', '500', '1000', '2000', '3000', '5000', '10000' + reservedBalance: '10', + scheduleMessageInitial: 'Please update your withdraw schedule selection to get payment automatically.', + }, + + // addon + addon: { + randomName: () => 'Addons Group_' + faker.string.nanoid(10), + randomTitle: () => 'Add-on Title_' + faker.string.nanoid(10), + name: 'Addons Group_', + priority: '10', + category: 'Uncategorized', + type: 'multiple_choice', // 'multiple_choice', 'checkbox', 'custom_text', 'custom_textarea', 'file_upload', 'custom_price', 'input_multiplier', 'heading' + displayAs: 'select', // 'select', 'radiobutton', 'images' + titleRequired: 'Add-on Title_', + formatTitle: 'label', // 'label', 'heading', 'hide' + addDescription: 'Add-on description', + enterAnOption: 'Option 1', + optionPriceType: 'flat_fee', // 'flat_fee', 'quantity_based', 'percentage_based' + optionPriceInput: '30', + saveSuccessMessage: 'Add-on saved successfully', + deleteSuccessMessage: 'Add-on deleted successfully', + }, + + registrationErrorMessage: 'Error: An account is already registered with your email address. Please log in.', + }, + + staff: () => ({ + // username: faker.person.firstName('male') + faker.string.nanoid(10), + firstName: faker.person.firstName('male'), + lastName: faker.person.lastName('male'), + email: faker.internet.email(), + phone: faker.phone.number('(###) ###-####'), + password: String(process.env.USER_PASSWORD), + }), + + // customer + customer: { + username: String(process.env.CUSTOMER), + password: String(process.env.USER_PASSWORD), + lastname: (String(process.env.CUSTOMER)[0] as string) + String(process.env.CUSTOMER)[String(process.env.CUSTOMER).length - 1], + + customerInfo: { + emailDomain: '@email.com', + // email: () => faker.internet.email(), + email: () => faker.person.firstName('male') + '@email.com', + password: String(process.env.USER_PASSWORD), + password1: String(process.env.USER_PASSWORD) + '1', + firstName: () => faker.person.firstName('male'), + lastName: () => faker.person.lastName('male'), + username: () => faker.person.firstName('male'), + shopName: () => faker.person.firstName('male') + 'store', + role: 'customer', + companyName: faker.company.name(), + companyId: faker.string.alphanumeric(5), + vatNumber: faker.string.alphanumeric(10), + bankName: 'bankName', + bankAddress: 'bankAddress', + bankIban: faker.finance.iban(), + phone: faker.phone.number('(###) ###-####'), + street1: 'abc street', + street2: 'xyz street', + country: 'United States (US)', + countrySelectValue: 'US', + stateSelectValue: 'NY', + city: 'New York', + zipCode: '10006', + state: 'New York', + accountName: 'accountName', + accountNumber: faker.string.alphanumeric(10), + routingNumber: faker.string.alphanumeric(10), + swiftCode: faker.string.alphanumeric(10), + iban: faker.string.alphanumeric(10), + biography: 'Customer biography', + billing: { + firstName: process.env.CUSTOMER, + lastName: 'c1', + companyName: faker.company.name(), + companyId: faker.string.alphanumeric(5), + vatNumber: faker.string.alphanumeric(10), + bankName: 'bankName', + bankIban: faker.finance.iban(), + street1: 'abc street', + street2: 'xyz street', + city: 'New York', + zipCode: '10003', + country: 'United States (US)', + state: 'New York', + email: process.env.CUSTOMER + '@yopmail.com', + phone: '0123456789', + }, + shipping: { + firstName: process.env.CUSTOMER, + lastName: 'c1', + companyName: faker.company.name(), + street1: 'abc street', + street2: 'xyz street', + city: 'New York', + zipCode: '10003', + country: 'United States (US)', + state: 'New York', + phone: '0123456789', + }, + }, + + getSupport: { + subject: 'get Support Subject', + message: 'get Support Message', + orderId: '', + supportSubmitSuccessMessage: 'Thank you. Your ticket has been submitted!', + username: String(process.env.CUSTOMER), + userPassword: String(process.env.USER_PASSWORD), + }, + + supportTicket: { + message: () => faker.string.nanoid(10), + }, + + rma: { + sendMessage: 'Message send successfully', + }, + + account: { + updateSuccessMessage: 'Account details changed successfully.', + }, + + follow: { + following: 'Following', + }, + + address: { + addressChangeSuccessMessage: 'Address changed successfully.', + }, + + registration: { + registrationErrorMessage: 'Error: An account is already registered with your email address. Please log in.', + }, + }, + + // date + date: { + previousDate: helpers.addDays(helpers.currentDate, -1, 'compact'), + currentDate: helpers.currentDate, + nextDay: helpers.addDays(helpers.currentDate, 1, 'compact'), + + // dateRange compact formate + dateRange: { + startDate: helpers.currentDate, + endDate: helpers.addDays(helpers.currentDate, 1, 'compact'), + }, + + // dateRange full format + dateRangeFull: { + startDate: helpers.currentDateTimeFullFormat, + endDate: helpers.addDays(helpers.currentDateTimeFullFormat, 1, 'complete'), + }, + }, + + // store category + storeCategory: () => ({ + name: 'test category_' + faker.string.nanoid(10), + description: 'test category description', + }), + + // store review + storeReview: { + review: () => ({ + rating: '4', + ratingByWidth: faker.helpers.arrayElement(['width: 20%', 'width: 40%', 'width: 60%', 'width: 80%', 'width: 100%']), + title: 'test title_' + faker.string.nanoid(10), + content: 'test content_' + faker.string.nanoid(10), + }), + filter: { + byVendor: String(process.env.VENDOR) + 'store', + }, + }, + + // store support + storeSupport: { + title: 'test support ticket', + + filter: { + byCustomer: String(process.env.CUSTOMER), + byVendor: String(process.env.VENDOR) + 'store', + }, + + chatReply: { + reply: 'chat reply' + faker.string.nanoid(10), + asAdmin: 'admin chat reply', + asVendor: 'vendor chat reply', + }, + }, + + // Reverse withdraw + reverseWithdraw: { + store: String(process.env.VENDOR) + 'store', + transactionType: 'manual_product', // manual_product, manual_order, other + product: 'p1_v1 (simple)', + withdrawalBalanceType: 'debit', // debit, credit + amount: '500', + note: 'test reverse withdraw note', + saveSuccessMessage: 'Reverse withdrawal created successfully.', + }, + + // request for quotation + requestForQuotation: { + userRole: { + administrator: 'administrator', + editor: 'editor', + author: 'author', + contributor: 'contributor', + subscriber: 'subscriber', + customer: 'customer', + shopManager: 'shop_manager', + vendor: 'seller', + vendorStaff: 'vendor_staff', + wholesaleCustomer: 'dokan_wholesale_customer', + guest: 'guest', + }, + + quoteRule: { + title: () => 'test rule_' + faker.string.nanoid(10), + userRole: 'customer', + product: 'p1_v1 (simple)', + category: 'Uncategorized', + hidePrice: '1', + hidePriceText: 'Price is hidden', + hideAddToCartButton: 'keep_and_add_new', // replace, keep_and_add_new + customButtonLabel: 'Add to quote', + order: '0', + }, + + trashedQuoteRule: { + title: 'trashed quote rule ', + status: 'trash', + }, + + quote: { + title: () => 'test quote_' + faker.string.nanoid(10), + user: 'customer1', // todo: update customer data via env and email domain + fullName: 'Jhon Doe', + email: 'customer1@g.com', + companyName: 'abc', + phoneNumber: '0123456789', + product: 'p1_v1 (simple)', + quantity: '5', + offerPrice: '80', + offerProductQuantity: '10', + }, + + trashedQuote: { + title: 'trashed quote', + status: 'trash', + }, + + convertedQuote: { + title: 'converted quote ' + faker.string.nanoid(10), + }, + + vendorUpdateQuote: { + productName: '', + offeredPrice: '80', + quantity: '20', + }, + + customerQuoteProduct: { + productName: '', + offeredPrice: '30', + quantity: '20', + }, + + guest: () => ({ + fullName: faker.person.fullName({ sex: 'male' }), + email: faker.person.firstName('male') + '@email.com', + companyName: faker.company.name(), + phoneNumber: faker.phone.number('(###) ###-####'), + }), + }, + + // seller badge + sellerBadge: { + eventName: { + // product related badges + productsPublished: 'Products Published', + numberOfItemsSold: 'Number of Items Sold', + featuredProducts: 'Featured Products', + trendingProduct: 'Trending Product', + + // seller related badges + featuredSeller: 'Featured Seller', + exclusiveToPlatform: 'Exclusive to Platform', + verifiedSeller: 'Verified Seller', + yearsActive: 'Years Active', + + // Order Related Badges + numberOfOrders: 'Number of Orders', + // Sale Amount Related Badges + saleAmount: 'Sale Amount', + + // Customer Related Badges + customerReview: 'Customer Review', + storeSupportCount: 'Store Support Count', + }, + + badgeName: '', + verificationMethod: '', + trendingProductPeriod: 'week', // week, month + trendingProductTopBestSellingProduct: '3', + + startingLevelValue: '1', + maxLevel: 5, + + verifiedSellerMethod: { + idVerification: 'id_verification', + companyVerification: 'company_verification', + addressVerification: 'address_verification', + phoneVerification: 'phone_verification', + socialProfiles: 'social_profiles', + }, + + badgeStatus: 'published', // published, draft + }, + + // announcement + announcement: { + receiverType: { + allVendors: 'all_seller', + selectedVendors: 'selected_seller', + enabledVendors: 'enabled_seller', + disabledVendors: 'disabled_seller', + featuredVendors: 'featured_seller', + }, + + randomTitle: () => 'test announcement_' + faker.string.nanoid(10), + title: 'test announcement title', + content: 'test announcement Content', + receiver: 'all_seller', + publishType: 'immediately', + scheduleDate: helpers.futureDate('', 10), + }, + + // modules + modules: { + noModuleMessage: 'No modules found.', + modules: [ + 'booking', + 'color_scheme_customizer', + 'delivery_time', + 'elementor', + 'export_import', + 'follow_store', + 'geolocation', + 'germanized', + 'live_chat', + 'live_search', + 'moip', + 'dokan_paypal_ap', + 'paypal_marketplace', + 'product_addon', + 'product_enquiry', + 'report_abuse', + 'rma', + 'seller_vacation', + 'shipstation', + 'auction', + 'spmv', + 'store_reviews', + 'stripe', + 'product_advertising', + 'product_subscription', + 'vendor_analytics', + 'vendor_staff', + 'vsp', + 'vendor_verification', + 'wholesale', + 'rank_math', + 'table_rate_shipping', + 'mangopay', + 'order_min_max', + 'razorpay', + 'seller_badge', + 'stripe_express', + 'request_for_quotation', + ], + + modulesName: { + AuctionIntegration: 'Auction Integration', + ColorSchemeCustomize: 'Color Scheme Customize', + DeliveryTime: 'Delivery Time', + Elementor: 'Elementor', + EUComplianceFields: 'EU Compliance Fields', + FollowStore: 'Follow Store', + }, + + moduleCategory: { + productManagement: 'Product Management', + integration: 'Integration', + uiUx: 'UI & UX', + shipping: 'Shipping', + storeManagement: 'Store Management', + payment: 'Payment', + orderManagement: 'Order Management', + vendorManagement: 'Vendor Management', + }, + + layout: { + grid: 'my-modules grid-view', + list: 'my-modules list-view', + }, + }, + + // tools + tools: { + distanceMatrixApi: { + address1: 'R9PG+W7 Dhaka', + address2: 'R9H7+HF Dhaka', + address3: 'P2J3+93 New York, USA', + address4: 'M2CP+FG New York, USA', + }, + }, + + // product advertisement + productAdvertisement: { + advertisedProductStore: String(process.env.VENDOR) + 'store', + advertisedProduct: 'p1_v1 (simple)', + + filter: { + byStore: String(process.env.VENDOR) + 'store', + createVia: { + admin: 'Admin', + order: 'Order', + subscription: 'Subscription', + freePurchase: 'Free Purchase', + }, + }, + }, + + // wholesale customers + wholesale: { + wholesaleRequestSendMessage: 'Your wholesale customer request send to the admin. Please wait for approval', + becomeWholesaleCustomerSuccessMessage: 'You are succefully converted as a wholesale customer', + wholesaleCapabilityActivate: 'Wholesale capability activate', + }, + + // dokan settings + dokanSettings: { + // General Settings + general: { + vendorStoreUrl: 'store', + setupWizardMessage: + 'Thank you for choosing The Marketplace to power your online store! This quick setup wizard will help you configure the basic settings. It\'s completely optional and shouldn\'t take longer than two minutes.', + sellingProductTypes: 'sell_both', // 'sell_both', 'sell_physical', 'sell_digital' + storeProductPerPage: '12', + storCategory: 'multiple', // 'none', 'single', 'multiple' + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Selling Options Settings + selling: { + commissionType: 'percentage', // 'flat', 'percentage', 'combine' + adminCommission: '10', + shippingFeeRecipient: 'seller', // 'seller', 'admin' + productTaxFeeRecipient: 'seller', // 'seller', 'admin' + shippingTaxFeeRecipient: 'seller', // 'seller', 'admin' + newProductStatus: 'publish', // 'publish', 'pending' + productCategorySelection: 'single', // 'single', 'multiple' + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Withdraw + withdraw: { + customMethodName: 'Bksh', + customMethodType: 'Phone', + minimumWithdrawAmount: '5', + withdrawThreshold: '0', + quarterlyScheduleMonth: 'march', // 'january', 'february', 'march' + quarterlyScheduleWeek: '1', // '1', '2', '3', 'L' + quarterlyScheduleDay: 'monday', // 'monday', 'tuesday', 'wednesday', 'thursday', 'friday' + monthlyScheduleWeek: '1', // '1', '2', '3', 'L' + monthlyScheduleDay: 'monday', // 'monday', 'tuesday', 'wednesday', 'thursday', 'friday' + biweeklyScheduleWeek: '1', // '1', '2' + biweeklyScheduleDay: 'monday', // 'saturday', 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday' + weeklyScheduleDay: 'monday', // 'saturday', 'sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday' + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Reverse withdraw + reverseWithdraw: { + billingType: 'by_amount', // 'by_month' + reverseBalanceThreshold: '21', + gracePeriod: '7', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Pages + page: { + dashboard: 'Dashboard', + myOrders: 'My Orders', + storeListing: 'Store List', + termsAndConditions: 'Terms And Conditions', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Appearance + appearance: { + googleMapApiKey: String(process.env.GMAP), + mapBoxApiKey: String(process.env.MAPBOX_API_KEY), + storeBannerWidth: '625', + storeBannerHeight: '300', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // privacy policy + privacyPolicy: { + privacyPage: '2', // '2', '3', '4', '5', '6', '7', '8', '9', '10' + privacyPolicyContent: 'Your personal data will be used to support your experience throughout this website, to manage access to your account, and for other purposes described in our [dokan_privacy_policy]', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // colors + colors: { + paletteChoice: 'pre-defined', + colorPalette: 'default', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // shipping status + shippingStatus: { + customShippingStatus: 'Test shipping status', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // quote + quote: { + decreaseOfferedPrice: '0', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // live search + liveSearch: { + liveSearchOption: 'suggestion_box', // suggestion_box, old_live_search + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Store support + storeSupport: { + displayOnSingleProductPage: 'above_tab', // 'above_tab', 'inside_tab', 'dont_show' + supportButtonLabel: 'Get Support', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Email verification + emailVerification: { + registrationNotice: 'Please check your email and complete email verification to login.', + loginNotice: 'Please check your email and complete email verification to login.', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Rma Settings + rma: { + orderStatus: 'wc-processing', // 'wc-pending', 'wc-processing', 'wc-on-hold', 'wc-completed', 'wc-cancelled', 'wc-refunded', 'wc-failed' + rmaReasons: ['Defective', 'Wrong Product', 'Other'], + refundPolicyHtmlBody: 'Refund Policy', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Wholesale + wholesale: { + whoCanSeeWholesalePrice: 'all_user', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // EuCompliance + euCompliance: { + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // delivery time + deliveryTime: { + deliveryDateLabel: 'Delivery Date', + deliveryBlockedBuffer: '0', + deliveryBoxInfo: 'This store needs %DAY% day(s) to process your delivery request', + days: ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'], + choice: 'full-day', + openingTime: '12:00 am', + closingTime: '11:30 pm', + timeSlot: '30', + orderPerSlot: '0', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Product advertising + productAdvertising: { + noOfAvailableSlot: '100', + expireAfterDays: '10', + advertisementCost: '15', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Geolocation Settings + geolocation: { + locationMapPosition: 'top', // 'top', 'left', 'right' + showMap: 'all', // 'all', 'store_listing', 'shop' + radiusSearchUnit: 'km', // 'km', 'miles' + radiusSearchMinimumDistance: '0', + radiusSearchMaximumDistance: '10', + mapZoomLevel: '11', + defaultLocation: 'New York', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Product report abuse + productReportAbuse: { + reasonsForAbuseReport: 'This product is fake', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Spmv Settings + spmv: { + sellItemButtonText: 'Sell This Item', + availableVendorDisplayAreaTitle: 'Other Available Vendor', + availableVendorSectionDisplayPosition: 'below_tabs', // 'below_tabs', 'inside_tabs', 'after_tabs' + showSpmvProducts: 'show_all', // 'show_all', 'min_price', 'max_price', 'top_rated_vendor' + saveSuccessMessage: 'Setting has been saved successfully.', + }, + + // Vendor Subscription Settings + vendorSubscription: { + displayPage: 'Sample Page', // '2', '4', '5', '6', '8', '9', '10', '11', '15', '-1' + noOfDays: '2', + productStatus: 'draft', // 'publish', 'pending', 'draft' + cancellingEmailSubject: 'Subscription Package Cancel notification', + cancellingEmailBody: 'Dear subscriber, Your subscription has expired. Please renew your package to continue using it.', + alertEmailSubject: 'Subscription Ending Soon', + alertEmailBody: 'Dear subscriber, Your subscription will be ending soon. Please renew your package in a timely', + saveSuccessMessage: 'Setting has been saved successfully.', + }, + }, + + // dokan license + dokanLicense: { + correctKey: String(process.env.LICENSE_KEY), + incorrectKey: 'ABC-123-DEF-456-GHI-789', + }, + + deliveryTime: { + date: helpers.currentDateFJY, + }, + + bookings: { + startDate: new Date(), + endDate: helpers.futureDate(new Date(), 5), // future date must be less than maximum duration + }, + + uniqueId: { + uuid: faker.string.uuid(), + nanoId: faker.string.nanoid(10), + }, + + // predefined test data + predefined: { + vendor2: { + simpleProduct: { + product1: { + name: 'p1_v2 (simple)', + productName: () => 'p1_v2 (simple)', + }, + }, + }, + + simpleProduct: { + product1: { + name: 'p1_v1 (simple)', + productName: () => 'p1_v1 (simple)', + }, + product2: 'p2_v1 (simple)', + productFrac1: 'p1_F1_v1 (simple)', + productFrac2: 'p2_F2_v1 (simple)', + }, + + variableProduct: { + product1: 'p1_v1 (variable)', + }, + + simpleSubscription: { + product1: 'sub1_v1 (simple subscription)', + }, + + variableSubscription: { + product1: 'p1_v1 (variable subscription)', + }, + + externalProduct: { + product1: 'p1_v1 (external/affiliate)', + }, + + auctionProduct: { + product1: 'p1_v1 (auction)', + }, + + bookingProduct: { + product1: 'p1_v1 (booking)', + }, + + saleProduct: { + product1: 'p1_v1 (sale)', + }, + + vendorSubscription: { + nonRecurring: 'Dokan_Subscription_Non_recurring', + }, + + coupon: { + couponCode: 'c1_v1', + }, + + spmv: { + productName: () => 'spmv_' + faker.string.nanoid(10), + product1: 'spmv_a1', + }, + + vendorInfo: { + firstName: () => 'vendor1', + lastName: () => 'v1', + username: 'vendor1', + shopName: String(process.env.VENDOR) + 'store', + }, + + vendorStores: { + followFromStoreListing: 'storeListing', + followFromSingleStore: 'singleStore', + vendor1: String(process.env.VENDOR) + 'store', + vendor1FullName: String(process.env.VENDOR) + ' ' + 'v1', + shopUrl: String(process.env.VENDOR) + 'store', + }, + + customerInfo: { + firstName: () => 'customer1', + lastName: () => 'c1', + username: () => 'customer1', + username1: 'customer1', + }, + }, + + // install wordpress + installWp: { + // db info + dbHost: process.env.DB_HOST_NAME, + dbUserName: process.env.DB_USER_NAME, + dbPassword: process.env.DB_USER_PASSWORD, + dbName: process.env.DATABASE, + dbTablePrefix: process.env.DB_PREFIX, + // site info + siteTitle: process.env.DATABASE, + adminUserName: process.env.ADMIN, + adminPassword: process.env.USER_PASSWORD, + adminEmail: 'shashwata@wedevs.com', + }, + + cssStyle: { + inlineBlock: 'display: inline-block;', + visibleStyle: 'visibility:visible;', + // style="visibility:visible;" + // style="display: block;" + // style="pointer-events: none;" + }, +}; diff --git a/webpack.config.js b/webpack.config.js index a02c4cb85f..ca2baa0bd1 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -26,7 +26,8 @@ const entryPoint = { './assets/src/js/product-editor.js', './assets/src/js/script.js', './assets/src/js/store-lists.js', - './assets/src/js/withdraw.js' + './assets/src/js/withdraw.js', + './assets/src/js/dokan-daterangepicker.js' ], 'login-form-popup': './assets/src/js/login-form-popup.js', 'dokan-maps-compat': './assets/src/js/dokan-maps-compat.js',