From 19ce59c2060610fcfdb7e5d4c4d00d97c317c3e7 Mon Sep 17 00:00:00 2001 From: shashwata Halder Date: Thu, 18 Jan 2024 12:19:47 +0600 Subject: [PATCH 01/11] Dokan e2e tests (#2148) * add zod api json validation * update test workflow * fix deprecated function * add pro plugin status * removed test.only * update testdata * update testdata * add json validation for admin spec * add coupon calculation test * update env var * ADD NEW SCHEMA * update schema * update schema, config, env * add coupon tests, fix flaky tests * update utility function * add reset site tests * update command * refactor setup project * add visual tests * resolved several todos * fix failed tests * removed console log * add new announcement api test * update env * update responsebody * update api tests * update yml * update order spec * fix customer id issue * update env * fix api issue * update yml * fix api errors * test_customer_ID * remove .only * test * update suite * update * update * update * update * update suite * update suite * update lite * update suite * update suite * update suite * up suite * update yml * update yml * update testdata * test * update config * update suite * update package.json * add global setup as project dependencies * removed global teardown * delete global setup files * add admin auth * test a test * update suite * test tests * test 2 * test 3 * test 4 * test 4 * test5 * test 6 * test 7 * test 8 * test 8 * test 10 * test 11 * test 12 * test13 * test 14 * test 15 * test 20 * test 22 * test 24 * test 25 * abc * update yml * yml * fsdf * fix minor issues * fix linting * fix bugs * update: add announcement notice test * update: add withdraw charge tests * fix: fix promotion test * test 1 * fix: update tests for wocommerce 8.3 * test 2 * update: update locators * update locator * add: add new tests * update: update coupon tests for wc 8.3 * update: global setup, fix: some tests * update: add inputs for workflow dispatch * update: add inputs for workflow dispatch * commented maxfailures * add schama validation for follow store api * update yml * update yml * update: add json schema validation * add: add schema validation for some tests * update: yml * fix locator issue * update versions * reverted pw version * fix locator * fix: fix all failed tests * update schema * fix syntax error * add: add withdraw charge tests * fix: abuse report test * fix: adaptive issue * fix: fix some tests * update config , might need te revert back * add: add new tests * add: add new tests * removed test.only * add : added new tests * fix withdraw test * add log * fix failed tests * fix some tests * update selector * fix lint * update locator * update packages * add: added product edit tests * add: add product tests * add: added new tests * fix: fix some payload data * skipped some tests * fixed a flaky tests * added licese tests * update yaml * fixed some tests --- .github/workflows/e2e_api_tests.yml | 28 +- tests/pw/README.MD | 4 +- tests/pw/api.config.ts | 24 +- tests/pw/e2e.config.ts | 28 +- tests/pw/package-lock.json | 551 ++++---- tests/pw/package.json | 24 +- tests/pw/pages/basePage.ts | 5 + tests/pw/pages/couponsPage.ts | 6 +- tests/pw/pages/customerPage.ts | 26 +- tests/pw/pages/licensePage.ts | 25 +- tests/pw/pages/modulesPage.ts | 14 +- tests/pw/pages/myOrdersPage.ts | 3 +- tests/pw/pages/pluginPage.ts | 49 + tests/pw/pages/privacyPolicyPage.ts | 42 + tests/pw/pages/productsPage.ts | 166 ++- tests/pw/pages/reportsPage.ts | 2 +- tests/pw/pages/selectors.ts | 269 ++-- tests/pw/pages/settingsPage.ts | 13 +- tests/pw/pages/storeAppearance.ts | 26 + tests/pw/pages/toolsPage.ts | 9 + tests/pw/pages/vendorAnalyticsPage.ts | 3 +- tests/pw/pages/vendorBookingPage.ts | 2 +- tests/pw/pages/vendorReportsPage.ts | 9 +- tests/pw/pages/withdrawsPage.ts | 3 +- tests/pw/tests/api/_coverage.teardown.ts | 2 +- .../api/{_env.setup.spec.ts => _env.setup.ts} | 32 +- tests/pw/tests/api/_env2.setup.spec.ts | 53 + tests/pw/tests/api/_resetSite.teardown.ts | 22 +- tests/pw/tests/api/abuseReports.spec.ts | 7 +- tests/pw/tests/api/announcements.spec.ts | 11 + tests/pw/tests/api/attributeTerms.spec.ts | 7 + tests/pw/tests/api/attributes.spec.ts | 11 +- tests/pw/tests/api/calculation.spec.ts | 4 +- tests/pw/tests/api/coupons.spec.ts | 6 + tests/pw/tests/api/customers.spec.ts | 7 + tests/pw/tests/api/dummyData.spec.ts | 4 + tests/pw/tests/api/followStores.spec.ts | 25 + tests/pw/tests/api/modules.spec.ts | 4 + tests/pw/tests/api/orders.spec.ts | 5 +- tests/pw/tests/api/quoteRequests.spec.ts | 2 +- tests/pw/tests/api/sellerBadge.spec.ts | 12 + tests/pw/tests/api/settings.spec.ts | 3 + tests/pw/tests/api/storeCategories.spec.ts | 8 + tests/pw/tests/api/supportTickets.spec.ts | 2 +- tests/pw/tests/api/withdraws.spec.ts | 2 - .../{_auth.setup.spec.ts => _auth.setup.ts} | 41 +- ...nvironment.setup.spec.ts => _env.setup.ts} | 148 +- tests/pw/tests/e2e/abuseReports.spec.ts | 2 +- tests/pw/tests/e2e/announcements.spec.ts | 4 +- tests/pw/tests/e2e/coupons.spec.ts | 4 +- tests/pw/tests/e2e/customer.spec.ts | 2 +- tests/pw/tests/e2e/emailVerification.spec.ts | 4 +- tests/pw/tests/e2e/followStore.spec.ts | 2 +- tests/pw/tests/e2e/license.spec.ts | 13 +- tests/pw/tests/e2e/myOrders.spec.ts | 4 +- tests/pw/tests/e2e/orders.spec.ts | 3 +- tests/pw/tests/e2e/plugin.spec.ts | 63 + tests/pw/tests/e2e/privacyPolicy.spec.ts | 49 + tests/pw/tests/e2e/productEnquiry.spec.ts | 2 +- tests/pw/tests/e2e/productReviews.spec.ts | 2 +- tests/pw/tests/e2e/products.spec.ts | 36 +- tests/pw/tests/e2e/refunds.spec.ts | 2 +- tests/pw/tests/e2e/reports.spec.ts | 2 +- tests/pw/tests/e2e/requestForQuotes.spec.ts | 2 +- tests/pw/tests/e2e/reverseWithdraws.spec.ts | 2 +- tests/pw/tests/e2e/settings.spec.ts | 3 +- tests/pw/tests/e2e/spmv.spec.ts | 2 +- tests/pw/tests/e2e/storeAppearance.spec.ts | 53 + tests/pw/tests/e2e/storeReviews.spec.ts | 2 +- tests/pw/tests/e2e/storeSupports.spec.ts | 2 +- tests/pw/tests/e2e/stores.spec.ts | 2 +- tests/pw/tests/e2e/tools.spec.ts | 6 +- tests/pw/tests/e2e/vendorAnalytics.spec.ts | 4 - tests/pw/tests/e2e/vendorAuction.spec.ts | 1 - tests/pw/tests/e2e/vendorBooking.spec.ts | 4 +- tests/pw/tests/e2e/vendorDeliveryTime.spec.ts | 4 +- .../pw/tests/e2e/vendorReturnRequest.spec.ts | 4 +- tests/pw/tests/e2e/withdraws.spec.ts | 4 +- tests/pw/types/environment.d.ts | 1 + tests/pw/types/global.d.ts | 1 + tests/pw/utils/apiUtils.ts | 15 +- tests/pw/utils/dbData.ts | 8 +- tests/pw/utils/helpers.ts | 10 +- tests/pw/utils/interfaces.ts | 99 +- tests/pw/utils/payloads.ts | 110 +- tests/pw/utils/pwMatchers.ts | 23 + tests/pw/utils/schemas.ts | 1246 +++++++++++++++-- tests/pw/utils/testData.ts | 127 +- 88 files changed, 2876 insertions(+), 802 deletions(-) create mode 100644 tests/pw/pages/pluginPage.ts create mode 100644 tests/pw/pages/privacyPolicyPage.ts create mode 100644 tests/pw/pages/storeAppearance.ts rename tests/pw/tests/api/{_env.setup.spec.ts => _env.setup.ts} (59%) create mode 100644 tests/pw/tests/api/_env2.setup.spec.ts rename tests/pw/tests/e2e/{_auth.setup.spec.ts => _auth.setup.ts} (63%) rename tests/pw/tests/e2e/{_environment.setup.spec.ts => _env.setup.ts} (75%) create mode 100644 tests/pw/tests/e2e/plugin.spec.ts create mode 100644 tests/pw/tests/e2e/privacyPolicy.spec.ts create mode 100644 tests/pw/tests/e2e/storeAppearance.spec.ts diff --git a/.github/workflows/e2e_api_tests.yml b/.github/workflows/e2e_api_tests.yml index e02e4e4533..624179b4d0 100644 --- a/.github/workflows/e2e_api_tests.yml +++ b/.github/workflows/e2e_api_tests.yml @@ -13,6 +13,15 @@ on: # workflow can be manually triggered workflow_dispatch: + inputs: + testsuite: + description: Choose which test suite to run + default: All + type: choice + options: + - E2E + - API + - All # Cancels all previous workflow runs for pull requests that have not completed. concurrency: @@ -69,8 +78,7 @@ jobs: - name: Composer install and build (Dokan-lite) if: success() run: | - composer install --no-dev - composer dump-autoload -o + composer install --no-dev -o - name: Npm install and build (Dokan-lite) if: success() @@ -150,17 +158,17 @@ jobs: cd tests/pw npm run pw:browser-with-deps - # Install only the OS dependencies if cache hit not needed - - name: Install Playwright OS dependencies - if: steps.playwright-cache.outputs.cache-hit == 'true' - run: | - cd tests/pw - npm run pw:deps-only + # # Install only the OS dependencies if cache hit not needed + # - name: Install Playwright OS dependencies + # if: steps.playwright-cache.outputs.cache-hit == 'true' + # run: | + # cd tests/pw + # npm run pw:deps-only # Run e2e tests - name: ๐Ÿงช Running the e2e tests id: e2e-test - if: success() + if: success() || ( success() && (github.event_name == 'workflow_dispatch' && (github.event.inputs.testsuite == 'E2E' || github.event.inputs.testsuite == 'All'))) timeout-minutes: 40 run: | cd tests/pw @@ -169,7 +177,7 @@ jobs: # Run API tests - name: ๐Ÿงช Running the api tests id: api-test - if: always() && steps.db-port.outcome == 'success' + if: always() && steps.db-port.outcome == 'success' || ( always() && steps.db-port.outcome == 'success' && (github.event_name == 'workflow_dispatch' && (github.event.inputs.testsuite == 'API' || github.event.inputs.testsuite == 'All'))) timeout-minutes: 5 run: | cd tests/pw diff --git a/tests/pw/README.MD b/tests/pw/README.MD index acea26dfa7..3f40bd27ce 100644 --- a/tests/pw/README.MD +++ b/tests/pw/README.MD @@ -120,13 +120,13 @@ GMAP=ABCD1234EFGH5678 [Google Maps API key] LICENSE_KEY=ABCD1234EFGH5678 [Dokan License key] DOKAN_PRO=true [Dokan pro active status] -# Playwright Configuration +# 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] NO_SETUP=true [Whether not to run setup tests before actual tests] [optional] -# Database Configuration +# 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] diff --git a/tests/pw/api.config.ts b/tests/pw/api.config.ts index 600a415aaa..89701c8e47 100644 --- a/tests/pw/api.config.ts +++ b/tests/pw/api.config.ts @@ -9,7 +9,7 @@ export default defineConfig({ // 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. */, + timeout: process.env.CI ? 10 * 1000 : 15 * 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 */, @@ -19,7 +19,7 @@ export default defineConfig({ 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 ? 4 : 4 /* Opt out of parallel tests on CI. */, - reportSlowTests: { max: 3, threshold: 10 } /* Whether to report slow test files. Pass null to disable this feature. */, + reportSlowTests: { max: 2, threshold: 10 } /* Whether to report slow test files. Pass null to disable this feature. */, reporter: process.env.CI ? [ ['github'], @@ -49,16 +49,16 @@ export default defineConfig({ // Api project // global_setup - { - name: 'global_setup', - testMatch: /global\.setup\.ts/, - }, + // { + // name: 'global_setup', + // testMatch: /global\.setup\.ts/, + // }, // api_setup { name: 'api_setup', - // testMatch: /.*\.setup\.ts/, - testMatch: /.*\.setup\.spec\.ts/, + testMatch: /.*\.setup\.ts/, + // testMatch: /.*\.setup\.spec\.ts/, }, // api_tests @@ -70,10 +70,10 @@ export default defineConfig({ }, // global_teardown - { - name: 'global_teardown', - testMatch: /global\.teardown\.ts/, - }, + // { + // name: 'global_teardown', + // testMatch: /global\.teardown\.ts/, + // }, ], }); diff --git a/tests/pw/e2e.config.ts b/tests/pw/e2e.config.ts index 8dd96be0fb..d3230d94db 100644 --- a/tests/pw/e2e.config.ts +++ b/tests/pw/e2e.config.ts @@ -7,11 +7,11 @@ export default defineConfig({ 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. */, + globalTimeout: process.env.CI ? 40 * (60 * 1000) : 40 * (60 * 1000) /* Maximum time in milliseconds the whole test suite can run */, + maxFailures: process.env.CI ? 40 : 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 ? 50 * 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();`*/, + timeout: 15 * 1000 /* Maximum time expect() should wait for the condition to be met. For example in `await expect(locator).toHaveText();`*/, toHaveScreenshot: { maxDiffPixelRatio: 0.2, maxDiffPixels: 500, @@ -23,8 +23,8 @@ export default defineConfig({ // 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. */, + workers: process.env.CI ? 4 : 1 /* Opt out of parallel tests on CI. */, + reportSlowTests: { max: 2, threshold: 25 } /* Whether to report slow test files. Pass null to disable this feature. */, reporter: process.env.CI ? [ ['github'], @@ -43,7 +43,7 @@ export default defineConfig({ 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). */, + actionTimeout: 20 * 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. */, @@ -62,28 +62,34 @@ export default defineConfig({ projects: [ // E2e project + // auth_setup + { + name: 'auth_setup', + // testMatch: /.*\.setup\.ts/, + testMatch: '_auth.setup.ts', + }, // e2e_setup { name: 'e2e_setup', // testMatch: /.*\.setup\.ts/, - testMatch: /.*\.setup\.spec\.ts/, + testMatch: '_env.setup.ts', + dependencies: process.env.NO_SETUP ? [] : ['auth_setup'] /* whether not to run setup tests before running actual tests */, }, // e2e_tests { name: 'e2e_tests', testMatch: /.*\.spec\.ts/, - // dependencies: process.env.NO_SETUP ? [] : ['e2e_setup'] /* whether not to run setup tests before running actual tests */, + dependencies: process.env.NO_SETUP ? [] : ['e2e_setup'] /* whether not to run setup tests before running actual tests */, }, // local site setup project { name: 'site_setup', testMatch: /.*\.install\.ts/, - // globalSetup: '', }, ], }); -expect.extend(customExpect); \ No newline at end of file +expect.extend(customExpect); diff --git a/tests/pw/package-lock.json b/tests/pw/package-lock.json index a99d8c7f61..56b102a98b 100644 --- a/tests/pw/package-lock.json +++ b/tests/pw/package-lock.json @@ -9,23 +9,23 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@faker-js/faker": "^8.2.0", - "@playwright/test": "^1.39.0", - "@wordpress/env": "^8.9.0", + "@faker-js/faker": "^8.3.1", + "@playwright/test": "1.38", + "@wordpress/env": "^9.0.0", "dotenv": "^16.3.1", - "mysqlconnector": "^2.0.1", + "mysqlconnector": "^2.0.5", "php-serialize": "^4.1.1", "zod": "^3.22.4" }, "devDependencies": { - "@typescript-eslint/eslint-plugin": "^6.8.0", - "@typescript-eslint/parser": "^6.8.0", - "eslint": "^8.51.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-playwright": "^0.17.0", - "npm-check-updates": "^16.14.6", - "prettier": "^3.0.3", - "typescript": "^5.2.2" + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-playwright": "^0.21.0", + "npm-check-updates": "^16.14.12", + "prettier": "^3.1.1", + "typescript": "^5.3.3" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -72,9 +72,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "dependencies": { "ajv": "^6.12.4", @@ -113,18 +113,18 @@ } }, "node_modules/@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, "node_modules/@faker-js/faker": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.2.0.tgz", - "integrity": "sha512-VacmzZqVxdWdf9y64lDOMZNDMM/FQdtM9IsaOPKOm2suYwEatb8VkdHqOzXcDnZbk7YDE2BmsJmy/2Hmkn563g==", + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.3.1.tgz", + "integrity": "sha512-FdgpFxY6V6rLZE9mmIBb9hM0xpfvQOSNOLnzolzKwsE1DH+gC7lEKV1p1IbR0lAYyvYd5a4u3qWJzowUkw1bIw==", "funding": [ { "type": "opencollective", @@ -137,12 +137,12 @@ } }, "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==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "dependencies": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" }, @@ -164,9 +164,9 @@ } }, "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "node_modules/@isaacs/cliui": { @@ -424,11 +424,11 @@ } }, "node_modules/@playwright/test": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", - "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", + "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.39.0" + "playwright": "1.38.1" }, "bin": { "playwright": "cli.js" @@ -594,9 +594,9 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, "node_modules/@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "node_modules/@types/keyv": { @@ -621,22 +621,22 @@ } }, "node_modules/@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", - "integrity": "sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", + "integrity": "sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.8.0", - "@typescript-eslint/type-utils": "6.8.0", - "@typescript-eslint/utils": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/type-utils": "6.18.1", + "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -662,15 +662,15 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.8.0.tgz", - "integrity": "sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", + "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.8.0", - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/typescript-estree": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4" }, "engines": { @@ -690,13 +690,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz", - "integrity": "sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", + "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0" + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -707,13 +707,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz", - "integrity": "sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz", + "integrity": "sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.8.0", - "@typescript-eslint/utils": "6.8.0", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/utils": "6.18.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" }, @@ -734,9 +734,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.8.0.tgz", - "integrity": "sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", + "integrity": "sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==", "dev": true, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -747,16 +747,17 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz", - "integrity": "sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz", + "integrity": "sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" }, @@ -773,18 +774,42 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/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/@typescript-eslint/typescript-estree/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/@typescript-eslint/utils": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.8.0.tgz", - "integrity": "sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz", + "integrity": "sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==", "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.8.0", - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/typescript-estree": "6.8.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", "semver": "^7.5.4" }, "engines": { @@ -799,12 +824,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz", - "integrity": "sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", + "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/types": "6.18.1", "eslint-visitor-keys": "^3.4.1" }, "engines": { @@ -815,14 +840,20 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "node_modules/@wordpress/env": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-8.9.0.tgz", - "integrity": "sha512-f3W1OMcUubZVC4OH9MTG2XE2OWwZH3Y2pKgrXSXP7rUiiCCIknotbUKtq7vF9uoUOB+f5kF2zGRRCJBu7n8PYg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-9.0.0.tgz", + "integrity": "sha512-Fyec0k5N7kaXVIpTnJ2zO/n3CIiq8cPDsUaFoLVKI+yv2cVuq1dSQyc1lLXB9Gu+SNvmfbq7nNVVmNfKgpAkrw==", "dependencies": { "chalk": "^4.0.0", "copy-dir": "^1.3.0", - "docker-compose": "^0.22.2", + "docker-compose": "^0.24.3", "extract-zip": "^1.6.7", "got": "^11.8.5", "inquirer": "^7.1.0", @@ -844,9 +875,9 @@ "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==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -1652,9 +1683,12 @@ } }, "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==", + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.3.tgz", + "integrity": "sha512-x3/QN3AIOMe7j2c8f/jcycizMft7dl8MluoB9OGPAYCyKHHiPUFqI9GjCcsU0kYy24vYKMCcfR6+5ZaEyQlrxg==", + "dependencies": { + "yaml": "^2.2.2" + }, "engines": { "node": ">= 6.0.0" } @@ -1787,18 +1821,19 @@ } }, "node_modules/eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -1841,9 +1876,9 @@ } }, "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==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, "bin": { "eslint-config-prettier": "bin/cli.js" @@ -1853,9 +1888,9 @@ } }, "node_modules/eslint-plugin-playwright": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.17.0.tgz", - "integrity": "sha512-5IABk90JcD96SkD9sr5V9RZHPdsZqBZYwlnRcTIcYmbxfxD2vtd9MQ2rPsTPLaMGKAPdfoyFaWARQElJCgYDuQ==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.21.0.tgz", + "integrity": "sha512-Y6qwguE9L6LB1JCsnPKaHbo+Z4X8/MngD82N0NkwiZ0ch0UVc4Oc2ZqmxanFxftIddnvwtNNlzUezglLlzUzKA==", "dev": true, "dependencies": { "globals": "^13.23.0" @@ -3439,9 +3474,9 @@ } }, "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==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/mysqlconnector/-/mysqlconnector-2.0.5.tgz", + "integrity": "sha512-SiHISVNxo+D3YLjdcdpOmCSdJGtgeBSdQEAr1l20jVLWgr17VAMRBdJe5udSQAqMTtzLRM/dF+OSO0ieYqK95w==", "dependencies": { "mysql": "2.18.1" } @@ -3572,9 +3607,9 @@ } }, "node_modules/npm-check-updates": { - "version": "16.14.6", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.6.tgz", - "integrity": "sha512-sJ6w4AmSDP7YzBXah94Ul2JhiIbjBDfx9XYgib15um2wtiQkOyjE7Lov3MNUSQ84Ry7T81mE4ynMbl/mGbK4HQ==", + "version": "16.14.12", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.12.tgz", + "integrity": "sha512-5FvqaDX8AqWWTDQFbBllgLwoRXTvzlqVIRSKl9Kg8bYZTfNwMnrp1Zlmb5e/ocf11UjPTc+ShBFjYQ7kg6FL0w==", "dev": true, "dependencies": { "chalk": "^5.3.0", @@ -4291,11 +4326,11 @@ } }, "node_modules/playwright": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", - "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", + "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.39.0" + "playwright-core": "1.38.1" }, "bin": { "playwright": "cli.js" @@ -4308,9 +4343,9 @@ } }, "node_modules/playwright-core": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", - "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==", + "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" }, @@ -4328,9 +4363,9 @@ } }, "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==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", "dev": true, "bin": { "prettier": "bin/prettier.cjs" @@ -4413,9 +4448,9 @@ } }, "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "engines": { "node": ">=6" @@ -5294,9 +5329,9 @@ } }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true, "bin": { "tsc": "bin/tsc", @@ -5673,6 +5708,14 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -5758,9 +5801,9 @@ "dev": true }, "@eslint/eslintrc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", - "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "requires": { "ajv": "^6.12.4", @@ -5792,23 +5835,23 @@ } }, "@eslint/js": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.51.0.tgz", - "integrity": "sha512-HxjQ8Qn+4SI3/AFv6sOrDB+g6PpUTDwSJiQqOrnneEk8L71161srI9gjzzZvYVbzHiVg/BvcH95+cK/zfIt4pg==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", "dev": true }, "@faker-js/faker": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.2.0.tgz", - "integrity": "sha512-VacmzZqVxdWdf9y64lDOMZNDMM/FQdtM9IsaOPKOm2suYwEatb8VkdHqOzXcDnZbk7YDE2BmsJmy/2Hmkn563g==" + "version": "8.3.1", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.3.1.tgz", + "integrity": "sha512-FdgpFxY6V6rLZE9mmIBb9hM0xpfvQOSNOLnzolzKwsE1DH+gC7lEKV1p1IbR0lAYyvYd5a4u3qWJzowUkw1bIw==" }, "@humanwhocodes/config-array": { - "version": "0.11.11", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", - "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", + "version": "0.11.13", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.13.tgz", + "integrity": "sha512-JSBDMiDKSzQVngfRjOdFXgFfklaXI4K9nLF49Auh21lmBWRLIK3+xTErTWD4KU54pb6coM6ESE7Awz/FNU3zgQ==", "dev": true, "requires": { - "@humanwhocodes/object-schema": "^1.2.1", + "@humanwhocodes/object-schema": "^2.0.1", "debug": "^4.1.1", "minimatch": "^3.0.5" } @@ -5820,9 +5863,9 @@ "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==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.1.tgz", + "integrity": "sha512-dvuCeX5fC9dXgJn9t+X5atfmgQAzUOWqS1254Gh0m6i8wKd10ebXkfNKiRK+1GWi/yTvvLDHpoxLr0xxxeslWw==", "dev": true }, "@isaacs/cliui": { @@ -6016,11 +6059,11 @@ "optional": true }, "@playwright/test": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", - "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", + "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.39.0" + "playwright": "1.38.1" } }, "@pnpm/config.env-replace": { @@ -6145,9 +6188,9 @@ "integrity": "sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==" }, "@types/json-schema": { - "version": "7.0.13", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.13.tgz", - "integrity": "sha512-RbSSoHliUbnXj3ny0CNFOoxrIDV6SUGyStHsvDqosw6CkdPV8TtWGlfecuK4ToyMEAql6pzNxgCFKanovUzlgQ==", + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, "@types/keyv": { @@ -6172,22 +6215,22 @@ } }, "@types/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-OxepLK9EuNEIPxWNME+C6WwbRAOOI2o2BaQEGzz5Lu2e4Z5eDnEo+/aVEDMIXywoJitJ7xWd641wrGLZdtwRyw==", + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", "dev": true }, "@typescript-eslint/eslint-plugin": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.8.0.tgz", - "integrity": "sha512-GosF4238Tkes2SHPQ1i8f6rMtG6zlKwMEB0abqSJ3Npvos+doIlc/ATG+vX1G9coDF3Ex78zM3heXHLyWEwLUw==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.18.1.tgz", + "integrity": "sha512-nISDRYnnIpk7VCFrGcu1rnZfM1Dh9LRHnfgdkjcbi/l7g16VYRri3TjXi9Ir4lOZSw5N/gnV/3H7jIPQ8Q4daA==", "dev": true, "requires": { "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.8.0", - "@typescript-eslint/type-utils": "6.8.0", - "@typescript-eslint/utils": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/type-utils": "6.18.1", + "@typescript-eslint/utils": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "graphemer": "^1.4.0", "ignore": "^5.2.4", @@ -6197,94 +6240,121 @@ } }, "@typescript-eslint/parser": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.8.0.tgz", - "integrity": "sha512-5tNs6Bw0j6BdWuP8Fx+VH4G9fEPDxnVI7yH1IAPkQH5RUtvKwRoqdecAPdQXv4rSOADAaz1LFBZvZG7VbXivSg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.18.1.tgz", + "integrity": "sha512-zct/MdJnVaRRNy9e84XnVtRv9Vf91/qqe+hZJtKanjojud4wAVy/7lXxJmMyX6X6J+xc6c//YEWvpeif8cAhWA==", "dev": true, "requires": { - "@typescript-eslint/scope-manager": "6.8.0", - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/typescript-estree": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4" } }, "@typescript-eslint/scope-manager": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.8.0.tgz", - "integrity": "sha512-xe0HNBVwCph7rak+ZHcFD6A+q50SMsFwcmfdjs9Kz4qDh5hWhaPhFjRs/SODEhroBI5Ruyvyz9LfwUJ624O40g==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz", + "integrity": "sha512-BgdBwXPFmZzaZUuw6wKiHKIovms97a7eTImjkXCZE04TGHysG+0hDQPmygyvgtkoB/aOQwSM/nWv3LzrOIQOBw==", "dev": true, "requires": { - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0" + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1" } }, "@typescript-eslint/type-utils": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.8.0.tgz", - "integrity": "sha512-RYOJdlkTJIXW7GSldUIHqc/Hkto8E+fZN96dMIFhuTJcQwdRoGN2rEWA8U6oXbLo0qufH7NPElUb+MceHtz54g==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz", + "integrity": "sha512-wyOSKhuzHeU/5pcRDP2G2Ndci+4g653V43gXTpt4nbyoIOAASkGDA9JIAgbQCdCkcr1MvpSYWzxTz0olCn8+/Q==", "dev": true, "requires": { - "@typescript-eslint/typescript-estree": "6.8.0", - "@typescript-eslint/utils": "6.8.0", + "@typescript-eslint/typescript-estree": "6.18.1", + "@typescript-eslint/utils": "6.18.1", "debug": "^4.3.4", "ts-api-utils": "^1.0.1" } }, "@typescript-eslint/types": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.8.0.tgz", - "integrity": "sha512-p5qOxSum7W3k+llc7owEStXlGmSl8FcGvhYt8Vjy7FqEnmkCVlM3P57XQEGj58oqaBWDQXbJDZxwUWMS/EAPNQ==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz", + "integrity": "sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw==", "dev": true }, "@typescript-eslint/typescript-estree": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.8.0.tgz", - "integrity": "sha512-ISgV0lQ8XgW+mvv5My/+iTUdRmGspducmQcDw5JxznasXNnZn3SKNrTRuMsEXv+V/O+Lw9AGcQCfVaOPCAk/Zg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz", + "integrity": "sha512-fv9B94UAhywPRhUeeV/v+3SBDvcPiLxRZJw/xZeeGgRLQZ6rLMG+8krrJUyIf6s1ecWTzlsbp0rlw7n9sjufHA==", "dev": true, "requires": { - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/visitor-keys": "6.8.0", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/visitor-keys": "6.18.1", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", + "minimatch": "9.0.3", "semver": "^7.5.4", "ts-api-utils": "^1.0.1" + }, + "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" + } + } } }, "@typescript-eslint/utils": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.8.0.tgz", - "integrity": "sha512-dKs1itdE2qFG4jr0dlYLQVppqTE+Itt7GmIf/vX6CSvsW+3ov8PbWauVKyyfNngokhIO9sKZeRGCUo1+N7U98Q==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz", + "integrity": "sha512-zZmTuVZvD1wpoceHvoQpOiewmWu3uP9FuTWo8vqpy2ffsmfCE8mklRPi+vmnIYAIk9t/4kOThri2QCDgor+OpQ==", "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.8.0", - "@typescript-eslint/types": "6.8.0", - "@typescript-eslint/typescript-estree": "6.8.0", + "@typescript-eslint/scope-manager": "6.18.1", + "@typescript-eslint/types": "6.18.1", + "@typescript-eslint/typescript-estree": "6.18.1", "semver": "^7.5.4" } }, "@typescript-eslint/visitor-keys": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.8.0.tgz", - "integrity": "sha512-oqAnbA7c+pgOhW2OhGvxm0t1BULX5peQI/rLsNDpGM78EebV3C9IGbX5HNZabuZ6UQrYveCLjKo8Iy/lLlBkkg==", + "version": "6.18.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.18.1.tgz", + "integrity": "sha512-/kvt0C5lRqGoCfsbmm7/CwMqoSkY3zzHLIjdhHZQW3VFrnz7ATecOHR7nb7V+xn4286MBxfnQfQhAmCI0u+bJA==", "dev": true, "requires": { - "@typescript-eslint/types": "6.8.0", + "@typescript-eslint/types": "6.18.1", "eslint-visitor-keys": "^3.4.1" } }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, "@wordpress/env": { - "version": "8.9.0", - "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-8.9.0.tgz", - "integrity": "sha512-f3W1OMcUubZVC4OH9MTG2XE2OWwZH3Y2pKgrXSXP7rUiiCCIknotbUKtq7vF9uoUOB+f5kF2zGRRCJBu7n8PYg==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@wordpress/env/-/env-9.0.0.tgz", + "integrity": "sha512-Fyec0k5N7kaXVIpTnJ2zO/n3CIiq8cPDsUaFoLVKI+yv2cVuq1dSQyc1lLXB9Gu+SNvmfbq7nNVVmNfKgpAkrw==", "requires": { "chalk": "^4.0.0", "copy-dir": "^1.3.0", - "docker-compose": "^0.22.2", + "docker-compose": "^0.24.3", "extract-zip": "^1.6.7", "got": "^11.8.5", "inquirer": "^7.1.0", @@ -6303,9 +6373,9 @@ "dev": true }, "acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", + "integrity": "sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==", "dev": true }, "acorn-jsx": { @@ -6884,9 +6954,12 @@ } }, "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==" + "version": "0.24.3", + "resolved": "https://registry.npmjs.org/docker-compose/-/docker-compose-0.24.3.tgz", + "integrity": "sha512-x3/QN3AIOMe7j2c8f/jcycizMft7dl8MluoB9OGPAYCyKHHiPUFqI9GjCcsU0kYy24vYKMCcfR6+5ZaEyQlrxg==", + "requires": { + "yaml": "^2.2.2" + } }, "doctrine": { "version": "3.0.0", @@ -6982,18 +7055,19 @@ "dev": true }, "eslint": { - "version": "8.51.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.51.0.tgz", - "integrity": "sha512-2WuxRZBrlwnXi+/vFSJyjMqrNjtJqiasMzehF0shoLaW7DzS3/9Yvrmq5JiT66+pNjiX4UBnLDiKHcWAr/OInA==", + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", "dev": true, "requires": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.2", - "@eslint/js": "8.51.0", - "@humanwhocodes/config-array": "^0.11.11", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", "@humanwhocodes/module-importer": "^1.0.1", "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", "ajv": "^6.12.4", "chalk": "^4.0.0", "cross-spawn": "^7.0.2", @@ -7044,16 +7118,16 @@ } }, "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==", + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", "dev": true, "requires": {} }, "eslint-plugin-playwright": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.17.0.tgz", - "integrity": "sha512-5IABk90JcD96SkD9sr5V9RZHPdsZqBZYwlnRcTIcYmbxfxD2vtd9MQ2rPsTPLaMGKAPdfoyFaWARQElJCgYDuQ==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-playwright/-/eslint-plugin-playwright-0.21.0.tgz", + "integrity": "sha512-Y6qwguE9L6LB1JCsnPKaHbo+Z4X8/MngD82N0NkwiZ0ch0UVc4Oc2ZqmxanFxftIddnvwtNNlzUezglLlzUzKA==", "dev": true, "requires": { "globals": "^13.23.0" @@ -8244,9 +8318,9 @@ } }, "mysqlconnector": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mysqlconnector/-/mysqlconnector-2.0.1.tgz", - "integrity": "sha512-yr00AuY4IpBIG0cIk1LrwJIUr+1LM2fnH13WFTHV6sTb4ATfI4/ZnEMy3Zb+dVii8TcUGZVbS+jM0wOv3GYupg==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/mysqlconnector/-/mysqlconnector-2.0.5.tgz", + "integrity": "sha512-SiHISVNxo+D3YLjdcdpOmCSdJGtgeBSdQEAr1l20jVLWgr17VAMRBdJe5udSQAqMTtzLRM/dF+OSO0ieYqK95w==", "requires": { "mysql": "2.18.1" } @@ -8345,9 +8419,9 @@ } }, "npm-check-updates": { - "version": "16.14.6", - "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.6.tgz", - "integrity": "sha512-sJ6w4AmSDP7YzBXah94Ul2JhiIbjBDfx9XYgib15um2wtiQkOyjE7Lov3MNUSQ84Ry7T81mE4ynMbl/mGbK4HQ==", + "version": "16.14.12", + "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-16.14.12.tgz", + "integrity": "sha512-5FvqaDX8AqWWTDQFbBllgLwoRXTvzlqVIRSKl9Kg8bYZTfNwMnrp1Zlmb5e/ocf11UjPTc+ShBFjYQ7kg6FL0w==", "dev": true, "requires": { "chalk": "^5.3.0", @@ -8851,18 +8925,18 @@ "dev": true }, "playwright": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", - "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", + "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.39.0" + "playwright-core": "1.38.1" } }, "playwright-core": { - "version": "1.39.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", - "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==" + "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", @@ -8871,9 +8945,9 @@ "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==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", "dev": true }, "proc-log": { @@ -8935,9 +9009,9 @@ } }, "punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true }, "pupa": { @@ -9589,9 +9663,9 @@ } }, "typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "dev": true }, "unique-filename": { @@ -9863,6 +9937,11 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==" + }, "yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/tests/pw/package.json b/tests/pw/package.json index 191b9a28e5..7599202537 100644 --- a/tests/pw/package.json +++ b/tests/pw/package.json @@ -51,21 +51,21 @@ "author": "", "license": "ISC", "devDependencies": { - "@typescript-eslint/eslint-plugin": "^6.8.0", - "@typescript-eslint/parser": "^6.8.0", - "eslint": "^8.51.0", - "eslint-config-prettier": "^9.0.0", - "eslint-plugin-playwright": "^0.17.0", - "npm-check-updates": "^16.14.6", - "prettier": "^3.0.3", - "typescript": "^5.2.2" + "@typescript-eslint/eslint-plugin": "^6.18.1", + "@typescript-eslint/parser": "^6.18.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-playwright": "^0.21.0", + "npm-check-updates": "^16.14.12", + "prettier": "^3.1.1", + "typescript": "^5.3.3" }, "dependencies": { - "@faker-js/faker": "^8.2.0", - "@playwright/test": "^1.39.0", - "@wordpress/env": "^8.9.0", + "@faker-js/faker": "^8.3.1", + "@playwright/test": "1.38", + "@wordpress/env": "^9.0.0", "dotenv": "^16.3.1", - "mysqlconnector": "^2.0.1", + "mysqlconnector": "^2.0.5", "php-serialize": "^4.1.1", "zod": "^3.22.4" } diff --git a/tests/pw/pages/basePage.ts b/tests/pw/pages/basePage.ts index f9699ebf40..4e39261e21 100644 --- a/tests/pw/pages/basePage.ts +++ b/tests/pw/pages/basePage.ts @@ -1320,6 +1320,11 @@ export class BasePage { await expect(this.page.locator(selector)).toBeVisible(); } + // assert checkbox to be checked + async toBeChecked(selector: string) { + await expect(this.page.locator(selector)).toBeChecked(); + } + // assert element to contain text async toContainText(selector: string, text: string) { await expect(this.page.locator(selector)).toContainText(text); diff --git a/tests/pw/pages/couponsPage.ts b/tests/pw/pages/couponsPage.ts index ed3b126787..d3455e7970 100644 --- a/tests/pw/pages/couponsPage.ts +++ b/tests/pw/pages/couponsPage.ts @@ -15,9 +15,10 @@ export class CouponsPage extends AdminPage { // add marketplace coupon async addMarketplaceCoupon(coupon: coupon) { - await this.goIfNotThere(data.subUrls.backend.wc.coupons); + // await this.goIfNotThere(data.subUrls.backend.wc.coupons); + await this.goIfNotThere(data.subUrls.backend.wc.addCoupon); - await this.clickAndWaitForResponse(data.subUrls.backend.wc.addCoupon, selector.admin.marketing.addCoupon); + // await this.clickAndWaitForResponse(data.subUrls.backend.wc.addCoupon, selector.admin.marketing.addCoupon); // blocked by woocommer setup div 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); @@ -27,6 +28,7 @@ export class CouponsPage extends AdminPage { 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.scrollToTop(); await this.clickAndWaitForResponseAndLoadState(data.subUrls.post, selector.admin.marketing.addNewCoupon.publish); await this.toContainText(selector.admin.marketing.addNewCoupon.publishSuccessMessage, 'Coupon updated.'); } diff --git a/tests/pw/pages/customerPage.ts b/tests/pw/pages/customerPage.ts index 9ddd89573c..321ca8f539 100644 --- a/tests/pw/pages/customerPage.ts +++ b/tests/pw/pages/customerPage.ts @@ -250,36 +250,32 @@ export class CustomerPage extends BasePage { // clear cart async clearCart(): Promise { await this.goToCart(); - const cartProductIsVisible = await this.isVisible(selector.customer.cCart.removeFirstItem); - if (cartProductIsVisible) { + const emptyCart = await this.isVisible(selector.customer.cCart.cartEmptyMessage); + if (!emptyCart) { await this.clickAndWaitForResponseAndLoadState(data.subUrls.api.wc.store, selector.customer.cCart.removeFirstItem, 207); - // await this.toContainText(selector.customer.cWooSelector.wooCommerceSuccessMessage, 'removed. Undo?'); //todo: remove in future 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.typeAndWaitForResponse(data.subUrls.api.wc.store, selector.customer.cCart.quantity(productName), quantity, 207); await this.toHaveValue(selector.customer.cCart.quantity(productName), quantity); } // apply coupon - async applyCoupon(couponTitle: string): Promise { + async applyCoupon(couponCode: string): Promise { await this.goToCart(); - const couponIsApplied = await this.isVisible(selector.customer.cCart.removeCoupon(couponTitle)); + const couponIsApplied = await this.isVisible(selector.customer.cCart.removeCoupon(couponCode)); 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.clickAndWaitForResponse(data.subUrls.api.wc.store, selector.customer.cCart.removeCoupon(couponCode), 207); + await this.toContainText(selector.customer.cWooSelector.wooCommerceNoriceBannerContent, `Coupon code "${couponCode}" has been removed from your cart.`); } - 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.'); + await this.click(selector.customer.cCart.addCoupon); + await this.clearAndType(selector.customer.cCart.couponCode, couponCode); + await this.clickAndWaitForResponse(data.subUrls.api.wc.store, selector.customer.cCart.applyCoupon, 207); + await this.toContainText(selector.customer.cWooSelector.wooCommerceNoriceBannerContent, `Coupon code "${couponCode}" has been applied to your cart.`); } // add billing address in checkout diff --git a/tests/pw/pages/licensePage.ts b/tests/pw/pages/licensePage.ts index 6ba1af7c47..0b1c21eada 100644 --- a/tests/pw/pages/licensePage.ts +++ b/tests/pw/pages/licensePage.ts @@ -24,12 +24,27 @@ export class LicensePage extends AdminPage { // 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 + const alreadyActivated = await this.isVisible(selector.admin.dokan.license.deactivateLicense); + if (!alreadyActivated) { + 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') { + await this.toContainText(selector.admin.dokan.license.successNotice, 'License activated successfully.'); + await this.toBeVisible(selector.admin.dokan.license.activateLicenseInfo); + await this.toBeVisible(selector.admin.dokan.license.refreshLicense); + } else { + await this.toContainText(selector.admin.dokan.license.errorNotice, 'Invalid License Key'); + } } else { - await this.toContainText(selector.admin.dokan.license.errorNotice, 'Invalid License Key'); + console.log('License already activated!!'); } } + + // deactivate license + async deactivateLicense() { + await this.goIfNotThere(data.subUrls.backend.dokan.license); + await this.clickAndWaitForResponse(data.subUrls.backend.dokan.license, selector.admin.dokan.license.deactivateLicense); + await this.toContainText(selector.admin.dokan.license.successNotice, 'License deactivated successfully.'); + await this.notToBeVisible(selector.admin.dokan.license.refreshLicense); + } } diff --git a/tests/pw/pages/modulesPage.ts b/tests/pw/pages/modulesPage.ts index d63faeda35..161159d2c7 100644 --- a/tests/pw/pages/modulesPage.ts +++ b/tests/pw/pages/modulesPage.ts @@ -33,12 +33,12 @@ export class ModulesPage extends AdminPage { 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.moduleCard, 38); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleIcon, 38); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCheckbox, 38); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleName, 38); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleDescription, 38); + await this.toHaveCount(selector.admin.dokan.modules.pro.moduleActivationSwitch, 38); await this.toHaveCount(selector.admin.dokan.modules.pro.moduleDocs, 38); await this.toHaveCount(selector.admin.dokan.modules.pro.moduleVideos, 17); @@ -48,7 +48,7 @@ export class ModulesPage extends AdminPage { 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.payment, 6); await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.orderManagement, 2); await this.toHaveCount(selector.admin.dokan.modules.pro.moduleCategoryTypes.vendorManagement, 1); } diff --git a/tests/pw/pages/myOrdersPage.ts b/tests/pw/pages/myOrdersPage.ts index 10a3b19e59..20152639a9 100644 --- a/tests/pw/pages/myOrdersPage.ts +++ b/tests/pw/pages/myOrdersPage.ts @@ -35,8 +35,7 @@ export class MyOrdersPage extends CustomerPage { // view order details async viewOrderDetails(orderId: string) { - // await this.goIfNotThere(data.subUrls.frontend.orderDetails(orderId)); - await this.goto(data.subUrls.frontend.orderDetails(orderId)); + await this.goIfNotThere(data.subUrls.frontend.orderDetails(orderId)); // order details are visible await this.multipleElementVisible(selector.customer.cOrderDetails.orderDetails); diff --git a/tests/pw/pages/pluginPage.ts b/tests/pw/pages/pluginPage.ts new file mode 100644 index 0000000000..1d6d2cf5aa --- /dev/null +++ b/tests/pw/pages/pluginPage.ts @@ -0,0 +1,49 @@ +import { Page } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { selector } from '@pages/selectors'; +import { data } from '@utils/testData'; +import { helpers } from '@utils/helpers'; + +export class PluginPage extends BasePage { + constructor(page: Page) { + super(page); + } + + // navigation + + async goToPlugins() { + await this.goIfNotThere(data.subUrls.backend.plugins); + } + + // activate plugin + async activatePlugin(plugin: string) { + await this.goToPlugins(); + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.backend.activatePlugin, selector.admin.plugins.activatePlugin(plugin), 302); + await this.toBeVisible(selector.admin.plugins.deactivatePlugin(plugin)); + } + + // deactivate plugin [only work for plugins which doesn't have deactivation popup] + async deactivatePlugin(plugin: string) { + await this.goToPlugins(); + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.backend.deactivatePlugin, selector.admin.plugins.deactivatePlugin(plugin), 302); + await this.toBeVisible(selector.admin.plugins.activatePlugin(plugin)); + } + + // deactivate dokan plugin + async deactivateDokanPlugin(plugin: string, submitReason: boolean) { + await this.goToPlugins(); + await this.click(selector.admin.plugins.deactivatePlugin(plugin)); + const isDeactivateModalVisible = await this.isVisible(selector.admin.plugins.deactivateReason.deactivateReasonModal(plugin)); + console.log(isDeactivateModalVisible); + + if (isDeactivateModalVisible) { + if (submitReason) { + await this.click(selector.admin.plugins.deactivateReason.reason(helpers.getRandomNumber(1, 7))); + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.backend.deactivatePlugin, selector.admin.plugins.deactivateReason.submitAndDeactivate, 302); + } else { + await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.backend.deactivatePlugin, selector.admin.plugins.deactivateReason.skipAndDeactivate, 302); + } + await this.toBeVisible(selector.admin.plugins.activatePlugin(plugin)); + } + } +} diff --git a/tests/pw/pages/privacyPolicyPage.ts b/tests/pw/pages/privacyPolicyPage.ts new file mode 100644 index 0000000000..6fd3d60df5 --- /dev/null +++ b/tests/pw/pages/privacyPolicyPage.ts @@ -0,0 +1,42 @@ +import { Page } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; +import { storeContactData } from '@utils/interfaces'; + +export class PrivacyPolicy extends BasePage { + constructor(page: Page) { + super(page); + } + + // contact vendor + async contactVendor(storeName: string, storeContactData: storeContactData) { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.clearAndType(selector.customer.cSingleStore.storeContactForm.name, storeContactData.name); + await this.clearAndType(selector.customer.cSingleStore.storeContactForm.email, storeContactData.email); + await this.clearAndType(selector.customer.cSingleStore.storeContactForm.message, storeContactData.message); + await this.clickAndAcceptAndWaitForResponse(data.subUrls.ajax, selector.customer.cSingleStore.storeContactForm.sendMessage); + await this.toContainText(selector.customer.cSingleStore.storeContactForm.successMessage, 'Email sent successfully!'); + } + + // go to privacy policy + async goToPrivacyPolicy(storeName: string) { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + // ensure page suppose to open on new tab + await this.toHaveAttribute(selector.customer.cSingleStore.storeContactForm.privacyPolicyLink, 'target', '_blank'); + // force page to open on same tab + await this.setAttributeValue(selector.customer.cSingleStore.storeContactForm.privacyPolicyLink, 'target', '_self'); + await this.clickAndWaitForUrl(helpers.stringToRegex('privacy-policy'), selector.customer.cSingleStore.storeContactForm.privacyPolicyLink); + } + + async disablePrivacyPolicy(storeName: string) { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.notToBeVisible(selector.customer.cSingleStore.storeContactForm.privacyPolicy); + } + + async disableStoreContactForm(storeName: string) { + await this.goto(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.notToBeVisible(selector.customer.cSingleStore.storeContactForm.storeContactForm); + } +} diff --git a/tests/pw/pages/productsPage.ts b/tests/pw/pages/productsPage.ts index 293fa96c1d..e45236beed 100644 --- a/tests/pw/pages/productsPage.ts +++ b/tests/pw/pages/productsPage.ts @@ -286,8 +286,7 @@ export class ProductsPage extends AdminPage { // products // vendor add product - async addProduct(product: product['simple'] | product['variable'] | product['simpleSubscription'] | product['external']): Promise { - const productName = product.productName(); + async addProduct(productName: string): Promise { 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); @@ -296,12 +295,13 @@ export class ProductsPage extends AdminPage { // vendor add simple product async vendorAddSimpleProduct(product: product['simple'] | product['variable'] | product['simpleSubscription'] | product['external'], productPopup = false): Promise { const productName = product.productName(); + const productPrice = product.regularPrice(); 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.clearAndType(selector.vendor.product.create.productPrice, productPrice); // await this.addProductCategory(product.category); await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.vendor.product.create.createProduct); @@ -310,17 +310,63 @@ export class ProductsPage extends AdminPage { } 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.clearAndType(selector.vendor.product.edit.price, productPrice); // 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. '); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + await this.toHaveValue(selector.vendor.product.create.productPrice, productPrice); } } + // vendor add downloadble product + async vendorAddDownloadableProduct(product: product['downloadable'], productPopup = false): Promise { + const productName = product.productName(); + const productPrice = product.regularPrice(); + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(productName); + await this.clearAndType(selector.vendor.product.create.productPrice, productPrice); + await this.check(selector.vendor.product.edit.downloadable); + // await this.addProductCategory(product.category); + + await this.click(selector.vendor.product.downloadableOptions.addFile); + await this.clearAndType(selector.vendor.product.downloadableOptions.fileName, product.downloadableOptions.fileName); + await this.click(selector.vendor.product.downloadableOptions.chooseFile); + await this.uploadMedia(product.downloadableOptions.fileUrl); + await this.clearAndType(selector.vendor.product.downloadableOptions.downloadLimit, product.downloadableOptions.downloadLimit); + await this.clearAndType(selector.vendor.product.downloadableOptions.downloadExpiry, product.downloadableOptions.downloadExpiry); + + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + await this.toHaveValue(selector.vendor.product.create.productPrice, productPrice); + await this.toBeChecked(selector.vendor.product.edit.downloadable); + await this.toHaveValue(selector.vendor.product.downloadableOptions.fileName, product.downloadableOptions.fileName); + await this.toHaveValue(selector.vendor.product.downloadableOptions.downloadLimit, product.downloadableOptions.downloadLimit); + await this.toHaveValue(selector.vendor.product.downloadableOptions.downloadExpiry, product.downloadableOptions.downloadExpiry); + } + + // vendor add vitual product + async vendorAddVirtualProduct(product: product['simple'], productPopup = false): Promise { + const productName = product.productName(); + const productPrice = product.regularPrice(); + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(productName); + await this.clearAndType(selector.vendor.product.create.productPrice, productPrice); + await this.check(selector.vendor.product.edit.virtual); + // await this.addProductCategory(product.category); + + await this.clickAndWaitForResponse(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, product.saveSuccessMessage); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + await this.toHaveValue(selector.vendor.product.create.productPrice, productPrice); + await this.toBeChecked(selector.vendor.product.edit.virtual); + await this.notToBeVisible(selector.vendor.product.shipping.shippingContainer); + } + // vendor add variable product async vendorAddVariableProduct(product: product['variable'], productPopup = false): Promise { - productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + const productName = product.productName(); + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(productName); // edit product await this.selectByValue(selector.vendor.product.edit.productType, product.productType); @@ -340,11 +386,13 @@ export class ProductsPage extends AdminPage { 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); + await this.toHaveValue(selector.vendor.product.edit.title, productName); } // vendor add simple subscription product async vendorAddSimpleSubscription(product: product['simpleSubscription'], productPopup = false): Promise { - productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + const productName = product.productName(); + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(productName); // edit product await this.selectByValue(selector.vendor.product.edit.productType, product.productType); await this.type(selector.vendor.product.edit.subscriptionPrice, product.subscriptionPrice()); @@ -355,11 +403,14 @@ export class ProductsPage extends AdminPage { 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); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + //todo: add more assettions } // vendor add variable subscription product async vendorAddVariableSubscription(product: product['variableSubscription'], productPopup = false): Promise { - productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + const productName = product.productName(); + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(productName); // edit product await this.selectByValue(selector.vendor.product.edit.productType, product.productType); // add variation @@ -378,11 +429,14 @@ export class ProductsPage extends AdminPage { 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); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + //todo: add more assettions } // vendor add external product async vendorAddExternalProduct(product: product['external'], productPopup = false): Promise { - productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(product); + const productName = product.productName(); + productPopup ? await this.vendorAddSimpleProduct(product, productPopup) : await this.addProduct(productName); // edit product await this.selectByValue(selector.vendor.product.edit.productType, product.productType); await this.type(selector.vendor.product.edit.productUrl, this.getBaseUrl() + product.productUrl); @@ -390,6 +444,8 @@ export class ProductsPage extends AdminPage { 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); + await this.toHaveValue(selector.vendor.product.edit.title, productName); + //todo: add more assettions } // go to product edit @@ -502,18 +558,29 @@ export class ProductsPage extends AdminPage { // product edit + // add product description + async addProductDescription(productName: string, description: product['productInfo']['description']): Promise { + await this.goToProductEdit(productName); + await this.typeFrameSelector(selector.vendor.product.shortDescription.shortDescriptionIframe, selector.vendor.product.shortDescription.shortDescriptionHtmlBody, description.shortDescription); + await this.typeFrameSelector(selector.vendor.product.description.descriptionIframe, selector.vendor.product.description.descriptionHtmlBody, description.description); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + // todo: add more assertions + } + // add product quantity discount - async addProductQuantityDiscount(productName: string, quantityDiscount: vendor['vendorInfo']['quantityDiscount']): Promise { + async addProductQuantityDiscount(productName: string, quantityDiscount: product['productInfo']['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); + // todo: add more assertions } - // vendor add product rma settings - async addProductRmaSettings(productName: string, rma: vendor['rma']): Promise { + // vendor add product rma options + async addProductRmaOptions(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); @@ -530,6 +597,67 @@ export class ProductsPage extends AdminPage { } await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + //todo: add more assertions + } + + // add product Wholesale options + async addProductWholesaleOptions(productName: string, wholesaleOption: product['productInfo']['wholesaleOption']): Promise { + await this.goToProductEdit(productName); + await this.check(selector.vendor.product.wholesale.enableWholeSaleForThisProduct); + await this.clearAndType(selector.vendor.product.wholesale.wholesalePrice, wholesaleOption.wholesalePrice); + await this.clearAndType(selector.vendor.product.wholesale.minimumQuantityForWholesale, wholesaleOption.minimumWholesaleQuantity); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + await this.toHaveValue(selector.vendor.product.wholesale.wholesalePrice, wholesaleOption.wholesalePrice); + await this.toHaveValue(selector.vendor.product.wholesale.minimumQuantityForWholesale, wholesaleOption.minimumWholesaleQuantity); + } + + // add product min-max options + async addProductMinMaxOptions(productName: string, minMaxOption: product['productInfo']['minMax']): Promise { + await this.goToProductEdit(productName); + await this.check(selector.vendor.product.minMax.enableMinMaxRulesThisProduct); + await this.clearAndType(selector.vendor.product.minMax.minimumQuantity, minMaxOption.minimumProductQuantity); + await this.clearAndType(selector.vendor.product.minMax.maximumQuantity, minMaxOption.maximumProductQuantity); + await this.clearAndType(selector.vendor.product.minMax.minimumAmount, minMaxOption.minimumAmount); + await this.clearAndType(selector.vendor.product.minMax.maximumAmount, minMaxOption.maximumAmount); + await this.check(selector.vendor.product.minMax.orderRulesDoNotCount); + await this.check(selector.vendor.product.minMax.categoryRulesExclude); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + await this.toBeChecked(selector.vendor.product.minMax.enableMinMaxRulesThisProduct); + await this.toHaveValue(selector.vendor.product.minMax.minimumQuantity, minMaxOption.minimumProductQuantity); + await this.toHaveValue(selector.vendor.product.minMax.maximumQuantity, minMaxOption.maximumProductQuantity); + await this.toHaveValue(selector.vendor.product.minMax.minimumAmount, minMaxOption.minimumAmount); + await this.toHaveValue(selector.vendor.product.minMax.maximumAmount, minMaxOption.maximumAmount); + await this.toBeChecked(selector.vendor.product.minMax.orderRulesDoNotCount); + await this.toBeChecked(selector.vendor.product.minMax.categoryRulesExclude); + } + + // add product other (product status, visibility, purchase note, reviews) options + async addProductOtherOptions(productName: string, otherOption: product['productInfo']['otherOptions']): Promise { + await this.goToProductEdit(productName); + await this.selectByValue(selector.vendor.product.otherOptions.productStatus, otherOption.productStatus); + await this.selectByValue(selector.vendor.product.otherOptions.visibility, otherOption.visibility); + await this.clearAndType(selector.vendor.product.otherOptions.purchaseNote, otherOption.purchaseNote); + await this.check(selector.vendor.product.otherOptions.enableProductReviews); + + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + //todo: add more assertion + await this.toHaveValue(selector.vendor.product.otherOptions.purchaseNote, otherOption.purchaseNote); + await this.toBeChecked(selector.vendor.product.otherOptions.enableProductReviews); + } + + // add product description + async addCatalogMode(productName: string): Promise { + await this.goToProductEdit(productName); + await this.check(selector.vendor.product.catalogMode.removeAddToCart); + await this.check(selector.vendor.product.catalogMode.hideProductPrice); + await this.clickAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.saveProduct, 302); + await this.toContainText(selector.vendor.product.updatedSuccessMessage, data.product.createUpdateSaveSuccessMessage); + await this.toBeChecked(selector.vendor.product.catalogMode.removeAddToCart); + await this.toBeChecked(selector.vendor.product.catalogMode.hideProductPrice); } // quick edit product @@ -549,7 +677,7 @@ export class ProductsPage extends AdminPage { 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'); + await this.toContainText(selector.vendor.product.dokanSuccessMessage, 'Product successfully duplicated'); } // permanently delete product @@ -586,4 +714,18 @@ export class ProductsPage extends AdminPage { await this.clickAndAcceptAndWaitForResponseAndLoadState(data.subUrls.frontend.vDashboard.products, selector.vendor.product.bulkActions.applyAction); } + + // 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/reportsPage.ts b/tests/pw/pages/reportsPage.ts index f3ac432a3b..c56559bcc9 100644 --- a/tests/pw/pages/reportsPage.ts +++ b/tests/pw/pages/reportsPage.ts @@ -21,7 +21,7 @@ export class ReportsPage extends AdminPage { await this.multipleElementVisible(selector.admin.dokan.reports.reports.filterMenus); // calendar input is visible - await this.multipleElementVisible(selector.admin.dokan.reports.reports.calendar); + await this.toBeVisible(selector.admin.dokan.reports.reports.calendar); // show button is visible await this.toBeVisible(selector.admin.dokan.reports.reports.show); diff --git a/tests/pw/pages/selectors.ts b/tests/pw/pages/selectors.ts index f5617dfb4f..f9bc95148e 100644 --- a/tests/pw/pages/selectors.ts +++ b/tests/pw/pages/selectors.ts @@ -151,6 +151,13 @@ export const selector = { spam: '//li[@class="spam"]', trash: '//li[@class="trash"]', }, + + // widgets + widgets: { + listView: 'button.edit-widgets-header-toolbar__list-view-toggle', + dokanStoreSidebar: '//span[text()="Dokan Store Sidebar"]/../../..//span[@class="block-editor-list-view__expander"]', + }, + // EmailLog emailLog: { // Menus @@ -1255,10 +1262,7 @@ export const selector = { }, // 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]', - }, + calendar: 'div.report-date-range', // show show: '//button[normalize-space()="Show"]', @@ -1462,6 +1466,13 @@ export const selector = { reBuild: '//a[normalize-space()="Re-build"]', }, + // Regenerate Order commission + regenerateOrderCommission: { + regenerateOrderSyncTable: '//span[normalize-space()="Regenerate Order Commission"]/../../..', + collapsibleButton: '//span[normalize-space()="Regenerate Order Commission"]/../../..//button', + regenerate: '//span[normalize-space()="Regenerate Order Commission"]/../../..//a[normalize-space()="Regenerate"]', + }, + // Check for Duplicate Orders checkForDuplicateOrders: { checkForDuplicateOrders: '//span[normalize-space()="Check for Duplicate Orders"]/../../..', @@ -1480,7 +1491,7 @@ export const selector = { 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"]', + regenerate: '//span[normalize-space()="Regenerate Variable Product Variations Author IDs"]/../../..//a[normalize-space()="Regenerate"]', }, // Import Dummy Data @@ -1818,7 +1829,7 @@ export const selector = { 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"]', + productDiscount: '//div[contains(text(),"Product Quantity Discount")]//label[@class="switch tips"]', hideCustomerInfo: '.hide_customer_info .switch', vendorProductReviewStatusChange: '.seller_review_manage .switch', @@ -1845,6 +1856,15 @@ export const selector = { withdrawMethodsSkrill: '//div[contains(text(),"Skrill")]//label', customMethodName: '#dokan_withdraw\\[withdraw_method_name\\]', customMethodType: '#dokan_withdraw\\[withdraw_method_type\\]', + // withdraw charge + payPalChargePercentage: '//h4[@class="field_heading" and text()="PayPal"]/../..//input[@id="percentage-val-id"]', + payPalChargeFixed: '//h4[@class="field_heading" and text()="PayPal"]/../..//input[@id="fixed-val-id"]', + bankTransferChargePercentage: '//h4[@class="field_heading" and text()="Bank Transfer"]/../..//input[@id="percentage-val-id"]', + bankTransferChargeFixed: '//h4[@class="field_heading" and text()="Bank Transfer"]/../..//input[@id="fixed-val-id"]', + skrillChargePercentage: '//h4[@class="field_heading" and text()="Skrill"]/../..//input[@id="percentage-val-id"]', + skrillChargeFixed: '//h4[@class="field_heading" and text()="Skrill"]/../..//input[@id="fixed-val-id"]', + customChargePercentage: '//h4[@class="field_heading" and text()="Custom"]/../..//input[@id="percentage-val-id"]', + custompayPalChargeFixed: '//h4[@class="field_heading" and text()="Custom"]/../..//input[@id="fixed-val-id"]', minimumWithdrawAmount: '#dokan_withdraw\\[withdraw_limit\\]', orderStatusForWithdrawCompleted: '//div[contains(text(),"Completed")]//label', orderStatusForWithdrawProcessing: '//div[contains(text(),"Processing")]//label', @@ -2222,7 +2242,13 @@ export const selector = { licenseKeyInput: '.license-input-fields .license-input-key input', activateLicense: '//button[contains(text(),"Activate License")]', }, - errorNotice: '.notice-error.appsero-license-section', + + deactivateLicense: 'button.deactive-button', + refreshLicense: 'button.appsero-license-refresh-button', + activateLicenseInfo: 'div.active-license-info', + + successNotice: 'div.notice-success.appsero-license-section', + errorNotice: 'div.notice-error.appsero-license-section', }, // Dokan Setup Wizard @@ -2596,7 +2622,7 @@ export const selector = { bookingCosts: '.bookings_pricing_options a', // General - regularPrice: '#\\_regular_price', + regularPrice: 'div#general_product_data input#\\_regular_price', salePrice: '#\\_sale_price', salePriceDateFrom: '#\\_sale_price_dates_from', salePriceDateTo: '#\\_sale_price_dates_to', @@ -2866,8 +2892,16 @@ export const selector = { uploadPlugin: '.upload', chooseFile: '#pluginzip', installNow: '#install-plugin-submit', - activatePlugin: '.button.button-primary', - activateCustomPlugin: (plugin: string) => `//strong[normalize-space()="${plugin}"]/..//div//span[@class="activate"]`, + activatePlugin: (plugin: string) => `a#activate-${plugin}`, + deactivatePlugin: (plugin: string) => `a#deactivate-${plugin}`, + + deactivateReason: { + deactivateReasonModal: (plugin: string) => `div#${plugin}-wd-dr-modal`, + reason: (reasonNumber: number) => `//div[contains(@class, 'wd-dr-modal')]//ul[@class="wd-de-reasons"]//li[${reasonNumber}]`, + skipAndDeactivate: `div.wd-dr-modal div.wd-dr-modal-footer a.dont-bother-me`, + cancel: `div.wd-dr-modal div.wd-dr-modal-footer button.wd-dr-cancel-modal`, + submitAndDeactivate: `div.wd-dr-modal div.wd-dr-modal-footer button.wd-dr-submit-modal`, + }, }, // Users @@ -3325,7 +3359,7 @@ export const selector = { // Product Sub Options numberOfRowsFound: '#dokan-product-list-table tbody tr', productCell: (productName: string) => `//a[contains(text(),'${productName}')]/../..`, - productLink: (productName: string) => `//a[contains(text(),'${productName}')]`, + productLink: (productName: string) => `//strong//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')]`, @@ -3413,67 +3447,79 @@ export const selector = { signUpFee: '#\\_subscription_sign_up_fee', subscriptionTrialLength: '#\\_subscription_trial_length', subscriptionTrialPeriod: '#\\_subscription_trial_period', + }, + // Short Description + shortDescription: { + shortDescriptionIframe: '.dokan-product-short-description iframe', + shortDescriptionHtmlBody: '#tinymce', + }, - // Short Description - shortDescription: { - shortDescriptionIframe: '.dokan-product-short-description iframe', - shortDescriptionHtmlBody: '#tinymce', - }, + // Description + description: { + descriptionIframe: '.dokan-product-description iframe', + descriptionHtmlBody: '#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', + }, - // 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', - }, + // Downloadable options + downloadableOptions: { + addFile: 'a.insert-file-row.dokan-btn', + addDownloadableFiles: '.insert', + fileName: 'input[placeholder="File Name"]', + fileUrl: 'input[placeholder="https://"]', + chooseFile: 'a.upload_file_button', + deleteFile: 'a.dokan-product-delete', + downloadLimit: '#\\_download_limit', + downloadExpiry: '#\\_download_expiry', + }, - // 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', - }, + // 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: { + shippingContainer: 'div.dokan-shipping-container.hide_if_virtual', thisProductRequiresShipping: '#\\_disable_shipping', weight: '#\\_weight', length: '#\\_length', @@ -3552,20 +3598,22 @@ export const selector = { // Min-Max Options minMax: { - enableMinMaxRulesThisProduct: '#product_wise_activation', - minimumQuantity: '#min_quantity', - maximumQuantity: '#max_quantity', - minimumAmount: '#min_amount', - maximumAmount: '#max_amount', + enableMinMaxRulesThisProduct: 'input#product_wise_activation', + minimumQuantity: 'input#min_quantity', + maximumQuantity: 'input#max_quantity', + minimumAmount: 'input#min_amount', + maximumAmount: 'input#max_amount', orderRulesDoNotCount: '#\\_donot_count', categoryRulesExclude: '#ignore_from_cat', }, // Other Options - productStatus: '#post_status', - visibility: '#\\_visibility', - purchaseNote: '#\\_purchase_note', - enableProductReviews: '#\\_enable_reviews', + otherOptions: { + productStatus: '#post_status', + visibility: '#\\_visibility', + purchaseNote: '#\\_purchase_note', + enableProductReviews: '#\\_enable_reviews', + }, // Advertise Product advertisement: { @@ -3575,6 +3623,12 @@ export const selector = { cancelAdvertiseThisProduct: '.swal2-cancel', }, + // catalog mode + catalogMode: { + removeAddToCart: '#catalog_mode_hide_add_to_cart_button', + hideProductPrice: '#catalog_mode_hide_product_price', + }, + // Save Product saveProduct: '.dokan-btn-lg', updatedSuccessMessage: '.dokan-message', @@ -3589,7 +3643,7 @@ export const selector = { cancelAction: '.swal2-actions .swal2-cancel', successMessage: '.swal2-actions .swal2-confirm', dokanMessage: '.dokan-message', - dokanSuccessMessage: '.dokan-alert.dokan-alert-success', + dokanSuccessMessage: '.dokan-alert.dokan-alert-success strong', }, // Orders @@ -3897,7 +3951,7 @@ export const selector = { approveThisQuote: 'button[name="approved_by_vendor_button"]', convertToOrder: 'button[name="dokan_convert_to_order_customer"]', - message: '.woocommerce-message', + message: '.woocommerce .is-success', }, }, @@ -3987,8 +4041,9 @@ export const selector = { // date picker datePicker: { - from: '#from', - to: '#to', + dateRangePickerinput: 'input.dokan-daterangepicker', + dateRangePickerFromInputHidden: 'input.dokan-daterangepicker-start-date', + dateRangePickerToInputHidden: 'input.dokan-daterangepicker-end-date', show: 'input[value="Show"]', }, @@ -4570,7 +4625,7 @@ export const selector = { confirmDelete: '.swal2-confirm', cancelDelete: '.swal2-cancel', - dokanSuccessMessage: '.dokan-alert.dokan-alert-success', + dokanSuccessMessage: '.dokan-alert.dokan-alert-success strong', // Create Booking Product booking: { @@ -4777,7 +4832,7 @@ export const selector = { addBooking: 'input[value="Add Booking"][type="submit"]', - successMessage: '.woocommerce-message', + successMessage: '.woocommerce .is-success', }, // Manage Booking @@ -4875,12 +4930,13 @@ export const selector = { }, datePicker: { - from: '#from', - to: '#to', + dateRangePickerinput: 'input.dokan-daterangepicker', + dateRangePickerFromInputHidden: 'input.dokan-daterangepicker-start-date', + dateRangePickerToInputHidden: 'input.dokan-daterangepicker-end-date', show: 'input[value="Show"]', }, - noAnalyticsFound: '//div[contains(text(), "There is no analytics found for your store.")]', + noAnalyticsFound: '//div[@class="tab-pane active" and normalize-space()="There is no analytics found for your store."]', }, // Announcements @@ -5064,8 +5120,8 @@ export const selector = { productDescriptionHtmlBody: '#tinymce', // Add Auction - addAuctionProduct: 'input[value="Add auction Product"]', - updateAuctionProduct: 'input[value="Update Product"]', + addAuctionProduct: '//input[@name="update_auction_product"]', + updateAuctionProduct: '//input[@name="update_auction_product"]', }, viewAuction: { @@ -6081,7 +6137,7 @@ export const selector = { billingEmailAddress: '#billing_email', billingSaveAddress: '//button[@name="save_address"]', // Success Message - successMessage: '.woocommerce-message', + successMessage: '.woocommerce .is-success', }, // Shipping Address @@ -6105,7 +6161,7 @@ export const selector = { shippingSaveAddress: '//button[@name="save_address"]', // Success Message - successMessage: '.woocommerce-message', + successMessage: '.woocommerce .is-success', }, }, @@ -6630,7 +6686,7 @@ export const selector = { storeInfo: '.dokan-store-info', storeAddress: '.dokan-store-address', storePhone: '.dokan-store-phone', - // storeEmail: '.dokan-store-email', + storeEmail: '.dokan-store-email', // storeRating: '.dokan-store-rating', // storeOpenClose: '.dokan-store-open-close', storeSocial: '.store-social', @@ -6706,7 +6762,6 @@ export const selector = { 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', @@ -6753,6 +6808,19 @@ export const selector = { couponCode: '..coupon-code', coupon: (code: string) => `//span[@class="coupon-code"]//strong[normalize-space()="${code}"]`, }, + + storeContactForm: { + storeContactForm: '#dokan-form-contact-seller', + name: '//form[@id="dokan-form-contact-seller"]//input[@placeholder="Your Name"]', + email: '//form[@id="dokan-form-contact-seller"]//input[@placeholder="you@example.com"]', + message: '//form[@id="dokan-form-contact-seller"]//textarea[@name="message"]', + sendMessage: 'input[name="store_message_send"]', + successMessage: 'div.alert.alert-success', + privacyPolicy: 'div.dokan-privacy-policy-text p', + privacyPolicyLink: 'a.dokan-privacy-policy-link', + }, + storeMap: 'div#dokan-store-location', + storeOpenCloseTime: 'div.dokan-store-open-close', }, cMyOrders: { @@ -6833,7 +6901,7 @@ export const selector = { phoneNumber: 'input[name="phone_field"]', }, - message: '.woocommerce-message', + message: '.woocommerce .is-success', }, // requested quote @@ -6905,7 +6973,7 @@ export const selector = { updateQuote: 'button[name="dokan_update_quote"]', - message: '.woocommerce-message', + message: '.woocommerce .is-success', }, }, }, @@ -6925,12 +6993,12 @@ export const selector = { // Edit Cart cartItem: (productName: string) => `//tr[@class='wc-block-cart-items__row']//a[@class= 'wc-block-components-product-name' and 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"]', + removeItem: (productName: string) => `//a[contains(text(),'${productName}')]/..//button[@class='wc-block-cart-item__remove-link']`, + quantity: (productName: string) => `//a[contains(text(),'${productName}')]/..//input[@class='wc-block-components-quantity-selector__input']`, + addCoupon: 'a[aria-label="Add a coupon"]', + couponCode: 'form#wc-block-components-totals-coupon__form input', + applyCoupon: 'form#wc-block-components-totals-coupon__form button', + removeCoupon: (couponCode: string) => `//span[contains(text(), '${couponCode.toLowerCase()}')]/..//button`, cartDetails: { cartTotal: 'tr.cart-subtotal span.woocommerce-Price-amount.amount', @@ -6944,7 +7012,10 @@ export const selector = { vendorShippingMethod: (shippingMethod: string) => `//label[contains(text(),'${shippingMethod}')]/..//input`, // For Unique Shipping Method // Proceed to Checkout - proceedToCheckout: '.checkout-button.button.wc-forward, .wp-block-woocommerce-proceed-to-checkout-block a', + // proceedToCheckout: '.checkout-button.button.wc-forward, .wp-block-woocommerce-proceed-to-checkout-block a', //todo: remove in future + // proceedToCheckout: 'div.wc-block-cart__submit-container a.wc-block-cart__submit-button', + proceedToCheckout: '//a[.="Proceed to Checkout"]', + // proceedToCheckout: '//span[contains (text(), "Proceed to Checkout")]/..', // Remove All Item productCrossIcon: '.product-remove a', @@ -7038,7 +7109,9 @@ export const selector = { stripeExpress: '.wc_payment_method.payment_method_dokan_stripe_express label', // Place Order - placeOrder: '#place_order, div.wc-block-checkout__actions_row button.wc-block-components-checkout-place-order-button', + placeOrder: '#place_order, button.wc-block-components-checkout-place-order-button', + // placeOrder: '//button[contains(@class,"wc-block-components-checkout-place-order-button")]', + // placeOrder: '//button[contains(@class,"components-button wc-block-components-button")]', }, cPayWithStripe: { @@ -7214,6 +7287,8 @@ export const selector = { wooCommerceSuccessMessage: '.woocommerce .is-success', wooCommerceError: '.woocommerce .is-error', wooCommerceInfo: '.woocommerce .is-info', + wooCommerceNoriceBanner: 'div.wc-block-components-notice-banner.is-info', // todo: .is-info might not be needed + wooCommerceNoriceBannerContent: 'div.wc-block-components-notice-banner__content', }, }, }; diff --git a/tests/pw/pages/settingsPage.ts b/tests/pw/pages/settingsPage.ts index 979d2bbcef..d7003e7a7f 100644 --- a/tests/pw/pages/settingsPage.ts +++ b/tests/pw/pages/settingsPage.ts @@ -130,9 +130,20 @@ export class SettingsPage extends AdminPage { await this.clearAndType(selector.admin.dokan.settings.withdraw.customMethodName, withdraw.customMethodName); await this.clearAndType(selector.admin.dokan.settings.withdraw.customMethodType, withdraw.customMethodType); } + // Withdraw Charge + await this.clearAndType(selector.admin.dokan.settings.withdraw.payPalChargePercentage, withdraw.charge.paypal); + await this.clearAndType(selector.admin.dokan.settings.withdraw.bankTransferChargeFixed, withdraw.charge.bank); + if (DOKAN_PRO) { + await this.clearAndType(selector.admin.dokan.settings.withdraw.skrillChargePercentage, withdraw.charge.skrill); + await this.clearAndType(selector.admin.dokan.settings.withdraw.customChargePercentage, withdraw.charge.custom); + } + 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); + + // Withdraw Charge + if (DOKAN_PRO) { await this.clearAndType(selector.admin.dokan.settings.withdraw.withdrawThreshold, withdraw.withdrawThreshold); @@ -162,7 +173,7 @@ export class SettingsPage extends AdminPage { // save settings await this.clickAndWaitForResponseAndLoadState(data.subUrls.ajax, selector.admin.dokan.settings.withdraw.withdrawSaveChanges); - await this.toContainText(selector.admin.dokan.settings.dokanUpdateSuccessMessage, withdraw.saveSuccessMessage); + await this.toHaveValue(selector.admin.dokan.settings.withdraw.minimumWithdrawAmount, withdraw.minimumWithdrawAmount); } // Admin Set Dokan Reverse Withdraw Settings diff --git a/tests/pw/pages/storeAppearance.ts b/tests/pw/pages/storeAppearance.ts new file mode 100644 index 0000000000..fa54667819 --- /dev/null +++ b/tests/pw/pages/storeAppearance.ts @@ -0,0 +1,26 @@ +import { Page } from '@playwright/test'; +import { BasePage } from '@pages/basePage'; +import { selector } from '@pages/selectors'; +import { helpers } from '@utils/helpers'; +import { data } from '@utils/testData'; + +export class StoreAppearance extends BasePage { + constructor(page: Page) { + super(page); + } + + async disableMapOnStoreSidebar(storeName: string) { + await this.goIfNotThere(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.notToBeVisible(selector.customer.cSingleStore.storeMap); + } + + async disableStoreOpenCloseTimeOnStoreSidebar(storeName: string) { + await this.goto(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.notToBeVisible(selector.customer.cSingleStore.storeOpenCloseTime); + } + + async disableVendorInfoOnSingleStorePage(storeName: string) { + await this.goto(data.subUrls.frontend.vendorDetails(helpers.slugify(storeName))); + await this.notToBeVisible(selector.customer.cSingleStore.storeOpenCloseTime); + } +} diff --git a/tests/pw/pages/toolsPage.ts b/tests/pw/pages/toolsPage.ts index 67aaf4f0e9..d8a241f96e 100644 --- a/tests/pw/pages/toolsPage.ts +++ b/tests/pw/pages/toolsPage.ts @@ -21,6 +21,9 @@ export class ToolsPage extends AdminPage { // Page Installation elements are visible await this.multipleElementVisible(selector.admin.dokan.tools.pageInstallation); + // Check For Regenerate Order commission are visible + await this.multipleElementVisible(selector.admin.dokan.tools.regenerateOrderCommission); + // Check For Duplicate Orders are visible await this.multipleElementVisible(selector.admin.dokan.tools.checkForDuplicateOrders); @@ -49,6 +52,12 @@ export class ToolsPage extends AdminPage { // await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.dokan.tools.pageInstallation.allPagesCreated); } + // regenerate variable product variations author IDs + async regenerateOrderCommission() { + await this.goIfNotThere(data.subUrls.backend.dokan.tools); + await this.clickAndWaitForResponse(data.subUrls.ajax, selector.admin.dokan.tools.regenerateOrderCommission.regenerate); + } + // check for duplicate order async checkForDuplicateOrders() { await this.goIfNotThere(data.subUrls.backend.dokan.tools); diff --git a/tests/pw/pages/vendorAnalyticsPage.ts b/tests/pw/pages/vendorAnalyticsPage.ts index 522da36a33..b474cdc504 100644 --- a/tests/pw/pages/vendorAnalyticsPage.ts +++ b/tests/pw/pages/vendorAnalyticsPage.ts @@ -21,7 +21,8 @@ export class VendorAnalyticsPage extends VendorPage { await this.multipleElementVisible(selector.vendor.vAnalytics.menus); // date-picker elements are visible - await this.multipleElementVisible(selector.vendor.vAnalytics.datePicker); + const { dateRangePickerinput, show } = selector.vendor.vAnalytics.datePicker; + await this.multipleElementVisible({ dateRangePickerinput, show }); await this.clickAndWaitForLoadState(selector.vendor.vAnalytics.menus.topPages); await this.toBeVisible(selector.vendor.vAnalytics.noAnalyticsFound); diff --git a/tests/pw/pages/vendorBookingPage.ts b/tests/pw/pages/vendorBookingPage.ts index 7f3d895e89..1053c1bc92 100644 --- a/tests/pw/pages/vendorBookingPage.ts +++ b/tests/pw/pages/vendorBookingPage.ts @@ -231,7 +231,7 @@ export class BookingPage extends VendorPage { 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'); + await this.toContainText(selector.vendor.vBooking.dokanSuccessMessage, 'Product successfully duplicated'); } // delete booking product diff --git a/tests/pw/pages/vendorReportsPage.ts b/tests/pw/pages/vendorReportsPage.ts index eece465c1b..761c714109 100644 --- a/tests/pw/pages/vendorReportsPage.ts +++ b/tests/pw/pages/vendorReportsPage.ts @@ -25,15 +25,14 @@ export class VendorReportsPage extends VendorPage { 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); + const { dateRangePickerinput, show } = selector.vendor.vAnalytics.datePicker; + await this.multipleElementVisible({ dateRangePickerinput, show }); // top selling table elements are visible await this.multipleElementVisible(selector.vendor.vReports.topSelling.table); @@ -41,7 +40,7 @@ export class VendorReportsPage extends VendorPage { await this.clickAndWaitForLoadState(selector.vendor.vReports.menus.topEarning); // date picker elements are visible - await this.multipleElementVisible(selector.vendor.vReports.datePicker); + await this.multipleElementVisible({ dateRangePickerinput, show }); // top earning table elements are visible await this.multipleElementVisible(selector.vendor.vReports.topEarning.table); @@ -49,7 +48,7 @@ export class VendorReportsPage extends VendorPage { await this.clickAndWaitForLoadState(selector.vendor.vReports.menus.statement); // date picker elements are visible - await this.multipleElementVisible(selector.vendor.vReports.datePicker); + await this.multipleElementVisible({ dateRangePickerinput, show }); // statement table elements are visible await this.multipleElementVisible(selector.vendor.vReports.statement.table); diff --git a/tests/pw/pages/withdrawsPage.ts b/tests/pw/pages/withdrawsPage.ts index e0e826fd80..d972f99b7e 100644 --- a/tests/pw/pages/withdrawsPage.ts +++ b/tests/pw/pages/withdrawsPage.ts @@ -37,7 +37,8 @@ export class WithdrawsPage extends AdminPage { // filter withdraws async filterWithdraws(input: string, action: string): Promise { - await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); + await this.goto(data.subUrls.backend.dokan.withdraw); + // await this.goIfNotThere(data.subUrls.backend.dokan.withdraw); await this.click(selector.admin.dokan.withdraw.filters.clearFilter); switch (action) { diff --git a/tests/pw/tests/api/_coverage.teardown.ts b/tests/pw/tests/api/_coverage.teardown.ts index 71a0d48daf..478db8a5d7 100644 --- a/tests/pw/tests/api/_coverage.teardown.ts +++ b/tests/pw/tests/api/_coverage.teardown.ts @@ -11,7 +11,7 @@ test.describe('get api test coverage', () => { apiUtils = new ApiUtils(request); }); - test('get coverage ', async () => { + 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); diff --git a/tests/pw/tests/api/_env.setup.spec.ts b/tests/pw/tests/api/_env.setup.ts similarity index 59% rename from tests/pw/tests/api/_env.setup.spec.ts rename to tests/pw/tests/api/_env.setup.ts index 62b17a70a6..898b2d8e41 100644 --- a/tests/pw/tests/api/_env.setup.spec.ts +++ b/tests/pw/tests/api/_env.setup.ts @@ -5,6 +5,9 @@ import { payloads } from '@utils/payloads'; import { helpers } from '@utils/helpers'; import { dbUtils } from '@utils/dbUtils'; import { dbData } from '@utils/dbData'; +import { data } from '@utils/testData'; + +// const { BASE_URL } = process.env; setup.describe('setup test environment', () => { let apiUtils: ApiUtils; @@ -13,6 +16,18 @@ setup.describe('setup test environment', () => { apiUtils = new ApiUtils(request); }); + // setup.skip('get server url @lite', async ({ request }) => { + // const apiUtils = new ApiUtils(request); + // const headers = await apiUtils.getSiteHeaders(BASE_URL); + // if (headers.link) { + // const serverUrl = headers.link.includes('rest_route') ? BASE_URL + '/?rest_route=' : BASE_URL + '/wp-json'; + // console.log('ServerUrl:', serverUrl); + // process.env.SERVER_URL = serverUrl; + // } else { + // console.log("Headers link doesn't exists"); + // } + // }); + setup('setup store settings @lite', async () => { const [response] = await apiUtils.put(endPoints.updateSettings, { data: payloads.setupStore }); expect(response.ok()).toBeTruthy(); @@ -21,13 +36,22 @@ setup.describe('setup test environment', () => { setup('create customer @lite', async () => { const [, customerId] = await apiUtils.createCustomer(payloads.createCustomer1, payloads.adminAuth); console.log('CUSTOMER_ID:', customerId); - (global as any).CUSTOMER_ID = customerId; + process.env.CUSTOMER_ID = customerId; + helpers.appendEnv(`CUSTOMER_ID=${customerId}`); // for local testing }); setup('create vendor @lite', async () => { const [, sellerId] = await apiUtils.createStore(payloads.createStore1, payloads.adminAuth); console.log('VENDOR_ID:', sellerId); - (global as any).VENDOR_ID = sellerId; + process.env.VENDOR_ID = sellerId; + helpers.appendEnv(`VENDOR_ID=${sellerId}`); // for local testing + }); + + setup('add vendor2 @lite', async () => { + const [, sellerId] = await apiUtils.createStore(payloads.createStore2, payloads.adminAuth); + console.log('VENDOR2_ID:', sellerId); + process.env.VENDOR2_ID = sellerId; + helpers.appendEnv(`VENDOR2_ID=${sellerId}`); // for local testing }); setup('set dokan general settings @lite', async () => { @@ -47,7 +71,7 @@ setup.describe('setup test environment', () => { }); setup('get test environment info @lite', async () => { - const [, summaryInfo] = await apiUtils.getSystemStatus(); - helpers.writeFile('playwright/systemInfo.json', JSON.stringify(summaryInfo)); + const [, systemInfo] = await apiUtils.getSystemStatus(payloads.adminAuth); + helpers.writeFile(data.systemInfo, JSON.stringify(systemInfo)); }); }); diff --git a/tests/pw/tests/api/_env2.setup.spec.ts b/tests/pw/tests/api/_env2.setup.spec.ts new file mode 100644 index 0000000000..eacaeb4119 --- /dev/null +++ b/tests/pw/tests/api/_env2.setup.spec.ts @@ -0,0 +1,53 @@ +// import { test as setup, expect, Page } from '@playwright/test'; +// import { LoginPage } from '@pages/loginPage'; +// import { ProductAdvertisingPage } from '@pages/productAdvertisingPage'; +// import { ReverseWithdrawsPage } from '@pages/reverseWithdrawsPage'; +// import { ApiUtils } from '@utils/apiUtils'; +// import { payloads } from '@utils/payloads'; +// import { data } from '@utils/testData'; + +// 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.describe('setup dokan settings e2e', () => { +// let productAdvertisingPage: ProductAdvertisingPage; +// let reverseWithdrawsPage: ReverseWithdrawsPage; +// 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); + +// apiUtils = new ApiUtils(request); +// }); + +// setup.afterAll(async () => { +// await aPage.close(); +// await vPage.close(); +// }); + +// 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('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(); +// }); +// }); diff --git a/tests/pw/tests/api/_resetSite.teardown.ts b/tests/pw/tests/api/_resetSite.teardown.ts index 186dc832f2..29778c4a98 100644 --- a/tests/pw/tests/api/_resetSite.teardown.ts +++ b/tests/pw/tests/api/_resetSite.teardown.ts @@ -6,13 +6,17 @@ import { payloads } from '@utils/payloads'; // import { dbData } from '@utils/dbData'; // import { helpers } from '@utils/helpers'; -test.describe(' test environment', () => { +test.describe('test environment', () => { let apiUtils: ApiUtils; test.beforeAll(async ({ request }) => { apiUtils = new ApiUtils(request); }); + test('delete all media items @lite', async () => { + await apiUtils.deleteAllMediaItems(payloads.adminAuth); + }); + test('delete all products @lite', async () => { await apiUtils.deleteAllProducts('', payloads.adminAuth); }); @@ -24,4 +28,20 @@ test.describe(' test environment', () => { test('delete all customers @lite', async () => { await apiUtils.deleteAllCustomers(payloads.adminAuth); }); + + test('delete all seller badges @lite', async () => { + await apiUtils.deleteAllSellerBadges(); + }); + + test('delete all RFQ Rules @lite', async () => { + await apiUtils.deleteAllQuoteRules(payloads.adminAuth); + }); + + test('delete all Request Quotes @lite', async () => { + await apiUtils.deleteAllQuoteRequests(payloads.adminAuth); + }); + + //todo: delete all announcements + //todo: delete all support tickets + //todo: delete all abuse reports tickets }); diff --git a/tests/pw/tests/api/abuseReports.spec.ts b/tests/pw/tests/api/abuseReports.spec.ts index f715e99755..95d3319c8f 100644 --- a/tests/pw/tests/api/abuseReports.spec.ts +++ b/tests/pw/tests/api/abuseReports.spec.ts @@ -9,8 +9,9 @@ import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; import { dbUtils } from '@utils/dbUtils'; import { dbData } from '@utils/dbData'; +import { schemas } from '@utils/schemas'; -const { VENDOR_ID, CUSTOMER_ID } = global as any; +const { VENDOR_ID, CUSTOMER_ID } = process.env; test.describe('abuse report api test', () => { let apiUtils: ApiUtils; @@ -26,12 +27,14 @@ test.describe('abuse report api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllAbuseReportReasons); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.abuseReportsSchema.abuseReportReasonsSchema); }); test('get all abuse reports @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllAbuseReports); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.abuseReportsSchema.abuseReportsSchema); }); test('delete a abuse report @pro', async () => { @@ -39,6 +42,7 @@ test.describe('abuse report api test', () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteAbuseReport(abuseReportId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.abuseReportsSchema.abuseReportSchema); }); test('delete batch abuse reports @pro', async () => { @@ -46,5 +50,6 @@ test.describe('abuse report api test', () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteBatchAbuseReports, { data: { items: allAbuseReportIds } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.abuseReportsSchema.abuseReportsSchema); }); }); diff --git a/tests/pw/tests/api/announcements.spec.ts b/tests/pw/tests/api/announcements.spec.ts index 4f9844de60..d5ed5f5a72 100644 --- a/tests/pw/tests/api/announcements.spec.ts +++ b/tests/pw/tests/api/announcements.spec.ts @@ -10,6 +10,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('announcements api test', () => { let apiUtils: ApiUtils; @@ -26,36 +27,42 @@ test.describe('announcements api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllAnnouncements); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementsSchema); }); test('get single announcement @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleAnnouncement(announcementId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementSchema); }); test('create an announcement @pro', async () => { const [response, responseBody] = await apiUtils.post(endPoints.createAnnouncement, { data: payloads.createAnnouncement() }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementSchema); }); test('update an announcement @pro', async () => { const [response, responseBody] = await apiUtils.post(endPoints.updateAnnouncement(announcementId), { data: payloads.updateAnnouncement }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementSchema); }); test('trash an announcement @pro', async () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteAnnouncement(announcementId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementSchema); }); test('restore a trashed announcement @pro', async () => { const [response, responseBody] = await apiUtils.put(endPoints.restoreDeletedAnnouncement(announcementId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementSchema); }); test('update batch announcements @pro', async () => { @@ -63,6 +70,7 @@ test.describe('announcements api test', () => { const [response, responseBody] = await apiUtils.put(endPoints.updateBatchAnnouncements, { data: { trash: allAnnouncementIds } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.batchUpdateAnnouncementsSchema); // restore all announcements await apiUtils.updateBatchAnnouncements('restore', allAnnouncementIds); @@ -74,17 +82,20 @@ test.describe('announcements api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleAnnouncementNotice(announcementNoticeId), { headers: payloads.vendorAuth }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementNoticeSchema); }); test('update an announcement notice @pro', async () => { const [response, responseBody] = await apiUtils.post(endPoints.updateAnnouncementNotice(announcementNoticeId), { data: payloads.updateAnnouncementNotice, headers: payloads.vendorAuth }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.announcementNoticeSchema); }); test('delete an announcement notice @pro', async () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteAnnouncementNotice(announcementNoticeId), { headers: payloads.vendorAuth }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.announcementsSchema.deleteAnnouncementNoticeSchema); }); }); diff --git a/tests/pw/tests/api/attributeTerms.spec.ts b/tests/pw/tests/api/attributeTerms.spec.ts index 0c4f6661ae..ae5296e01b 100644 --- a/tests/pw/tests/api/attributeTerms.spec.ts +++ b/tests/pw/tests/api/attributeTerms.spec.ts @@ -9,6 +9,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('attribute term api test', () => { let apiUtils: ApiUtils; @@ -24,30 +25,35 @@ test.describe('attribute term api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllAttributeTerms(attributeId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributeTeermsSchema.attributeTermsSchema); }); test('get single attribute term @lite', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleAttributeTerm(attributeId, attributeTermId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributeTeermsSchema.attributeTermSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.attributeTeermsSchema.attributeTermSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.attributeTeermsSchema.attributeTermSchema); }); test('delete an attribute term @lite', async () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteAttributeTerm(attributeId, attributeTermId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributeTeermsSchema.attributeTermSchema); }); test('update batch attribute terms @lite', async () => { @@ -61,5 +67,6 @@ test.describe('attribute term api test', () => { const [response, responseBody] = await apiUtils.put(endPoints.updateBatchAttributeTerms(attributeId), { data: { update: batchAttributeTerms } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributeTeermsSchema.batchupdateAttributesSchema); }); }); diff --git a/tests/pw/tests/api/attributes.spec.ts b/tests/pw/tests/api/attributes.spec.ts index 3f95ae64c8..791f671fe4 100644 --- a/tests/pw/tests/api/attributes.spec.ts +++ b/tests/pw/tests/api/attributes.spec.ts @@ -11,6 +11,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('attribute api test', () => { let apiUtils: ApiUtils; @@ -18,7 +19,7 @@ test.describe('attribute api test', () => { let attributeId: string; let attribute: any; let attributeTerm: any; - let attributeTermId: string; + let attributeTermId: string; //todo: why attributetermId is needed here test.beforeAll(async ({ request }) => { apiUtils = new ApiUtils(request); @@ -31,12 +32,14 @@ test.describe('attribute api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllAttributes); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.attributesSchema); }); test('get single attribute @lite', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleAttribute(attributeId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.attributeSchema); }); test('create an attribute @lite', async () => { @@ -44,18 +47,21 @@ test.describe('attribute api test', () => { expect(response.status()).toBe(201); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.attributeSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.attributeSchema); }); test('delete an attribute @lite', async () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteAttribute(attributeId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.attributeSchema); }); test('update batch attributes @lite', async () => { @@ -69,6 +75,7 @@ test.describe('attribute api test', () => { const [response, responseBody] = await apiUtils.put(endPoints.batchUpdateAttributes, { data: { update: batchAttributes } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.batchupdateAttributesSchema); }); test('set default attribute @lite', async () => { @@ -81,6 +88,7 @@ test.describe('attribute api test', () => { const [response, responseBody] = await apiUtils.put(endPoints.setDefaultAttribute(productId), { data: { attributes: [payload] } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.setDefaultAttributeSchema); }); test('update product attribute @lite', async () => { @@ -108,5 +116,6 @@ test.describe('attribute api test', () => { const [response, responseBody] = await apiUtils.post(endPoints.updateProductAttribute(productId), { data: payload }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.attributesSchema.updateProductAttributeSchema); }); }); diff --git a/tests/pw/tests/api/calculation.spec.ts b/tests/pw/tests/api/calculation.spec.ts index a19a97bf63..00940cfc3e 100644 --- a/tests/pw/tests/api/calculation.spec.ts +++ b/tests/pw/tests/api/calculation.spec.ts @@ -7,7 +7,7 @@ import { commission, feeRecipient } from '@utils/interfaces'; // test.use({ extraHTTPHeaders: { Authorization: payloads.adminAuth.Authorization } }); -test.describe('calculation test', () => { +test.describe.skip('calculation test', () => { let apiUtils: ApiUtils; let taxRate: number; let commission: commission; @@ -73,7 +73,7 @@ test.describe('calculation test', () => { }); }); -test.describe(' Marketplace Coupon calculation test', () => { +test.describe.skip('Marketplace Coupon calculation test', () => { let apiUtils: ApiUtils; let taxRate: number = 5; let commission: commission; diff --git a/tests/pw/tests/api/coupons.spec.ts b/tests/pw/tests/api/coupons.spec.ts index 326123aa43..ef042f91c9 100644 --- a/tests/pw/tests/api/coupons.spec.ts +++ b/tests/pw/tests/api/coupons.spec.ts @@ -8,6 +8,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('coupon api test', () => { let apiUtils: ApiUtils; @@ -24,29 +25,34 @@ test.describe('coupon api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllCoupons); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.couponsSchema.couponsSchema); }); test('get single coupon @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleCoupon(couponId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.couponsSchema.couponSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.couponsSchema.couponSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.couponsSchema.couponSchema); }); test('delete a coupon @pro', async () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteCoupon(couponId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.couponsSchema.couponSchema); }); }); diff --git a/tests/pw/tests/api/customers.spec.ts b/tests/pw/tests/api/customers.spec.ts index fa3ca036bb..991d63de9f 100644 --- a/tests/pw/tests/api/customers.spec.ts +++ b/tests/pw/tests/api/customers.spec.ts @@ -9,6 +9,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('customers api test', () => { let apiUtils: ApiUtils; @@ -23,12 +24,14 @@ test.describe('customers api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllCustomers); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.customersSchema.customersSchema); }); test('get single customer @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleCustomer(customerId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.customersSchema.customerSchema); }); test('create a customer @pro', async () => { @@ -36,18 +39,21 @@ test.describe('customers api test', () => { expect(response.status()).toBe(201); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.customersSchema.customerSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.customersSchema.customerSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.customersSchema.customerSchema); }); test('update batch customers @pro', async () => { @@ -61,5 +67,6 @@ test.describe('customers api test', () => { const [response, responseBody] = await apiUtils.put(endPoints.updateBatchCustomers, { data: { update: batchCustomers } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.customersSchema.batchupdateCustomersSchema); }); }); diff --git a/tests/pw/tests/api/dummyData.spec.ts b/tests/pw/tests/api/dummyData.spec.ts index d1d7ea86fa..14ac36bd7e 100644 --- a/tests/pw/tests/api/dummyData.spec.ts +++ b/tests/pw/tests/api/dummyData.spec.ts @@ -6,6 +6,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('dummy Data api test', () => { let apiUtils: ApiUtils; @@ -18,17 +19,20 @@ test.describe('dummy Data api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getDummyDataStatus); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.dummyDataSchema.dummyDataStatusSchema); }); test('import dummy data @lite', async () => { const [response, responseBody] = await apiUtils.post(endPoints.importDummyData, { data: payloads.dummyData }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.dummyDataSchema.importdummyDataSchema); }); test('clear dummy data @lite', async () => { const [response, responseBody] = await apiUtils.delete(endPoints.clearDummyData); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.dummyDataSchema.cleardummyDataClearSchema); }); }); diff --git a/tests/pw/tests/api/followStores.spec.ts b/tests/pw/tests/api/followStores.spec.ts index e2252eefc4..a157a48349 100644 --- a/tests/pw/tests/api/followStores.spec.ts +++ b/tests/pw/tests/api/followStores.spec.ts @@ -5,6 +5,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; +import { schemas } from '@utils/schemas'; // import { payloads } from '@utils/payloads'; test.describe('follow store api test', () => { @@ -20,19 +21,43 @@ test.describe('follow store api test', () => { test('get store follow status @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getStoreFollowStatus, { params: { vendor_id: sellerId } }); + const headers = response.headers(); + expect(headers['content-type']).toBe('application/json; charset=UTF-8'); + expect(headers['x-content-type-options']).toBe('nosniff'); + expect(headers['access-control-expose-headers']).toBe('X-WP-Total, X-WP-TotalPages, Link'); + expect(headers['access-control-allow-headers']).toBe('Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type'); + expect(headers['allow']).toBe('GET, POST'); + expect(response.statusText()).toBe('OK'); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.followStoresSchema.followstatusSchema); }); test('follow-unfollow a store @pro', async () => { const [response, responseBody] = await apiUtils.post(endPoints.followUnfollowStore, { data: { vendor_id: Number(sellerId) } }); + const headers = response.headers(); + expect(headers['content-type']).toBe('application/json; charset=UTF-8'); + expect(headers['x-content-type-options']).toBe('nosniff'); + expect(headers['access-control-expose-headers']).toBe('X-WP-Total, X-WP-TotalPages, Link'); + expect(headers['access-control-allow-headers']).toBe('Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type'); + expect(headers['allow']).toBe('GET, POST'); + expect(response.statusText()).toBe('OK'); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.followStoresSchema.followUnfollowSchema); }); test('get followers @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getFollowers); + const headers = response.headers(); + expect(headers['content-type']).toBe('application/json; charset=UTF-8'); + expect(headers['x-content-type-options']).toBe('nosniff'); + expect(headers['access-control-expose-headers']).toBe('X-WP-Total, X-WP-TotalPages, Link'); + expect(headers['access-control-allow-headers']).toBe('Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type'); + expect(headers['allow']).toBe('GET'); + expect(response.statusText()).toBe('OK'); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.followStoresSchema.followersSchema); }); }); diff --git a/tests/pw/tests/api/modules.spec.ts b/tests/pw/tests/api/modules.spec.ts index f45254fb3c..135fd70e78 100644 --- a/tests/pw/tests/api/modules.spec.ts +++ b/tests/pw/tests/api/modules.spec.ts @@ -6,6 +6,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { helpers } from '@utils/helpers'; +import { schemas } from '@utils/schemas'; test.describe('modules api test', () => { let apiUtils: ApiUtils; @@ -20,12 +21,14 @@ test.describe('modules api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllModules); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.modulesSchema); }); test('deactivate a module @pro', async () => { const [response, responseBody] = await apiUtils.put(endPoints.deactivateModule, { data: { module: [randomModule] } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.modulesSchema); // reactivate module // await apiUtils.activateModules(randomModule) @@ -35,5 +38,6 @@ test.describe('modules api test', () => { const [response, responseBody] = await apiUtils.put(endPoints.activateModule, { data: { module: [randomModule] } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.modulesSchema); }); }); diff --git a/tests/pw/tests/api/orders.spec.ts b/tests/pw/tests/api/orders.spec.ts index 12a02feda5..939d39fb4e 100644 --- a/tests/pw/tests/api/orders.spec.ts +++ b/tests/pw/tests/api/orders.spec.ts @@ -44,7 +44,7 @@ for (const version of versions) { }); test('get single order @lite', async () => { - const [response, responseBody] = await apiUtils.get(endPoints.getSingleOrder(orderId).replace('v1', version), { headers: payloads.adminAuth }); + const [response, responseBody] = await apiUtils.get(endPoints.getSingleOrder(orderId).replace('v1', version)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); }); @@ -57,7 +57,8 @@ for (const version of versions) { }); } -test('update batch orders @v2 @lite', async () => { +test('update batch orders @v2 @lite', async ({ request }) => { + apiUtils = new ApiUtils(request); 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(); diff --git a/tests/pw/tests/api/quoteRequests.spec.ts b/tests/pw/tests/api/quoteRequests.spec.ts index 19f720e3b6..c68ff6c700 100644 --- a/tests/pw/tests/api/quoteRequests.spec.ts +++ b/tests/pw/tests/api/quoteRequests.spec.ts @@ -66,7 +66,7 @@ test.describe('request quote api test', () => { expect(responseBody).toBeTruthy(); }); - test('update batch request quote @pro ', async () => { + 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(); diff --git a/tests/pw/tests/api/sellerBadge.spec.ts b/tests/pw/tests/api/sellerBadge.spec.ts index 6d31b9c4a1..bc4885ba00 100644 --- a/tests/pw/tests/api/sellerBadge.spec.ts +++ b/tests/pw/tests/api/sellerBadge.spec.ts @@ -14,6 +14,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('seller badge api test', () => { let apiUtils: ApiUtils; @@ -32,60 +33,70 @@ test.describe('seller badge api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getVerifiedSellerVerificationTypes); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.verificationTypesSchema); }); test('get all seller badge events @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllSellerBadgeEvents); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgeEventsSchema); }); test('get all seller badges @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllSellerBadges); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgesSchema); }); test('get single seller badge @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleSellerBadge(badgeId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgeSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgesSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgeSeenSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgeCreateUpdateSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgeCreateUpdateSchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.badgeCreateUpdateSchema); }); test('delete a seller badge @pro', async () => { const [response, responseBody] = await apiUtils.delete(endPoints.deleteSellerBadge(badgeId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.deleteBadgeSchema); }); test('update batch seller badges @pro', async () => { @@ -93,5 +104,6 @@ test.describe('seller badge api test', () => { const [response, responseBody] = await apiUtils.put(endPoints.updateBatchSellerBadges, { data: { ids: allBadgeIds, action: 'draft' } }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.sellerBadgeSchema.batchUpdateBadgesSchema); }); }); diff --git a/tests/pw/tests/api/settings.spec.ts b/tests/pw/tests/api/settings.spec.ts index 4587873762..84ebeaf304 100644 --- a/tests/pw/tests/api/settings.spec.ts +++ b/tests/pw/tests/api/settings.spec.ts @@ -5,6 +5,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('settings api test', () => { let apiUtils: ApiUtils; @@ -17,11 +18,13 @@ test.describe('settings api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getSettings); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + // expect(responseBody).toMatchSchema(schemas.settingsSchema.storeSettingsSchema); }); test('update settings @lite', async () => { const [response, responseBody] = await apiUtils.put(endPoints.updateSettings, { data: payloads.updateSettings }); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + // expect(responseBody).toMatchSchema(schemas.settingsSchema.setStoreSchema); }); }); diff --git a/tests/pw/tests/api/storeCategories.spec.ts b/tests/pw/tests/api/storeCategories.spec.ts index 83ff1f7d8e..158315529b 100644 --- a/tests/pw/tests/api/storeCategories.spec.ts +++ b/tests/pw/tests/api/storeCategories.spec.ts @@ -10,6 +10,7 @@ import { test, expect } from '@playwright/test'; import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; +import { schemas } from '@utils/schemas'; test.describe('store categories api test', () => { let apiUtils: ApiUtils; @@ -24,12 +25,14 @@ test.describe('store categories api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getDefaultStoreCategory); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.storeCategoriesSchema.storyCategorySchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.storeCategoriesSchema.storyCategorySchema); // restore default store category await apiUtils.setDefaultStoreCategory('Uncategorized', payloads.adminAuth); @@ -39,12 +42,14 @@ test.describe('store categories api test', () => { const [response, responseBody] = await apiUtils.get(endPoints.getAllStoreCategories); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.storeCategoriesSchema.storeCategoriesSchema); }); test('get single store category @pro', async () => { const [response, responseBody] = await apiUtils.get(endPoints.getSingleStoreCategory(categoryId)); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.storeCategoriesSchema.storyCategorySchema); }); test('create a store category @pro', async () => { @@ -52,17 +57,20 @@ test.describe('store categories api test', () => { expect(response.status()).toBe(201); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); + expect(responseBody).toMatchSchema(schemas.storeCategoriesSchema.storyCategorySchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.storeCategoriesSchema.storyCategorySchema); }); 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(); + expect(responseBody).toMatchSchema(schemas.storeCategoriesSchema.deleteStoryCategorySchema); }); }); diff --git a/tests/pw/tests/api/supportTickets.spec.ts b/tests/pw/tests/api/supportTickets.spec.ts index c620f04051..2f7347ecaa 100644 --- a/tests/pw/tests/api/supportTickets.spec.ts +++ b/tests/pw/tests/api/supportTickets.spec.ts @@ -12,7 +12,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { endPoints } from '@utils/apiEndPoints'; import { payloads } from '@utils/payloads'; -const { VENDOR_ID, CUSTOMER_ID } = global as any; +const { VENDOR_ID, CUSTOMER_ID } = process.env; test.describe('support ticket api test', () => { let apiUtils: ApiUtils; diff --git a/tests/pw/tests/api/withdraws.spec.ts b/tests/pw/tests/api/withdraws.spec.ts index a94740fad9..53e1b1b152 100644 --- a/tests/pw/tests/api/withdraws.spec.ts +++ b/tests/pw/tests/api/withdraws.spec.ts @@ -86,14 +86,12 @@ test.describe('withdraw api test', () => { }); test('get all withdraw method charges @lite', async () => { - test.skip(true, 'feature not merged yet'); const [response, responseBody] = await apiUtils.get(endPoints.getAllWithdrawMethodCharges); expect(response.ok()).toBeTruthy(); expect(responseBody).toBeTruthy(); }); test('get withdraw charge details @lite', async () => { - test.skip(true, 'feature not merged yet'); const [response, responseBody] = await apiUtils.get(endPoints.getWithdrawCharge, { params: payloads.withdrawCharge }); 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.ts similarity index 63% rename from tests/pw/tests/e2e/_auth.setup.spec.ts rename to tests/pw/tests/e2e/_auth.setup.ts index 549406d79a..0e69507a01 100644 --- a/tests/pw/tests/e2e/_auth.setup.spec.ts +++ b/tests/pw/tests/e2e/_auth.setup.ts @@ -1,31 +1,44 @@ import { test as setup, expect } from '@playwright/test'; import { LoginPage } from '@pages/loginPage'; -import { WpPage } from '@pages/wpPage'; +// import { WpPage } from '@pages/wpPage'; import { ApiUtils } from '@utils/apiUtils'; -import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; +import { data } from '@utils/testData'; import { helpers } from '@utils/helpers'; const { DOKAN_PRO } = process.env; setup.describe('authenticate users & set permalink', () => { + // setup.skip('get server url @lite', async ({ request }) => { + // const apiUtils = new ApiUtils(request); + // const headers = await apiUtils.getSiteHeaders(BASE_URL); + // if (headers.link) { + // const serverUrl = headers.link.includes('rest_route') ? BASE_URL + '/?rest_route=' : BASE_URL + '/wp-json'; + // console.log('ServerUrl:', serverUrl); + // process.env.SERVER_URL = serverUrl; + // } else { + // console.log("Headers link doesn't exists"); + // } + // }); + 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); - }); + // 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); + // }); setup('add customer1 @lite', async ({ request }) => { const apiUtils = new ApiUtils(request); const [, customerId] = await apiUtils.createCustomer(payloads.createCustomer1, payloads.adminAuth); console.log('CUSTOMER_ID:', customerId); - (global as any).CUSTOMER_ID = customerId; + process.env.CUSTOMER_ID = customerId; + helpers.appendEnv(`CUSTOMER_ID=${customerId}`); // for local testing }); setup('add vendor1 @lite', async ({ request }) => { @@ -33,7 +46,8 @@ setup.describe('authenticate users & set permalink', () => { const [, sellerId] = await apiUtils.createStore(payloads.createStore1, payloads.adminAuth); await apiUtils.updateCustomer(sellerId, payloads.updateAddress, payloads.adminAuth); console.log('VENDOR_ID:', sellerId); - (global as any).VENDOR_ID = sellerId; + process.env.VENDOR_ID = sellerId; + helpers.appendEnv(`VENDOR_ID=${sellerId}`); // for local testing }); setup('add vendor2 @lite', async ({ request }) => { @@ -41,7 +55,8 @@ setup.describe('authenticate users & set permalink', () => { const [, sellerId] = await apiUtils.createStore(payloads.createStore2, payloads.adminAuth); await apiUtils.updateCustomer(sellerId, payloads.updateAddress, payloads.adminAuth); console.log('VENDOR2_ID:', sellerId); - (global as any).VENDOR2_ID = sellerId; + process.env.VENDOR2_ID = sellerId; + helpers.appendEnv(`VENDOR2_ID=${sellerId}`); // for local testing }); setup('authenticate customer @lite', async ({ page }) => { @@ -65,7 +80,7 @@ setup.describe('authenticate users & set permalink', () => { setup('get test environment info @lite', async ({ request }) => { const apiUtils = new ApiUtils(request); - const [, summaryInfo] = await apiUtils.getSystemStatus(payloads.adminAuth); - helpers.writeFile('playwright/systemInfo.json', JSON.stringify(summaryInfo)); + const [, systemInfo] = await apiUtils.getSystemStatus(payloads.adminAuth); + helpers.writeFile(data.systemInfo, JSON.stringify(systemInfo)); }); }); diff --git a/tests/pw/tests/e2e/_environment.setup.spec.ts b/tests/pw/tests/e2e/_env.setup.ts similarity index 75% rename from tests/pw/tests/e2e/_environment.setup.spec.ts rename to tests/pw/tests/e2e/_env.setup.ts index 85b63867d6..702ac9df51 100644 --- a/tests/pw/tests/e2e/_environment.setup.spec.ts +++ b/tests/pw/tests/e2e/_env.setup.ts @@ -7,10 +7,9 @@ import { payloads } from '@utils/payloads'; import { dbUtils } from '@utils/dbUtils'; import { dbData } from '@utils/dbData'; import { data } from '@utils/testData'; -// import { helpers } from '@utils/helpers'; +import { helpers } from '@utils/helpers'; -const { DOKAN_PRO } = process.env; -const { CUSTOMER_ID, HPOS } = global as any; +const { DOKAN_PRO, CUSTOMER_ID, HPOS } = process.env; setup.describe('setup site & woocommerce & user settings', () => { setup.use({ extraHTTPHeaders: { Authorization: payloads.adminAuth.Authorization } }); @@ -25,12 +24,6 @@ setup.describe('setup site & woocommerce & user settings', () => { 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 () => { @@ -38,12 +31,6 @@ setup.describe('setup site & woocommerce & user settings', () => { 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); @@ -107,7 +94,14 @@ setup.describe('setup site & woocommerce & user settings', () => { await apiUtils.createAttributeTerm(attributeId, { name: 'm' }); }); + setup('check active dokan modules @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); + const activeModules = await apiUtils.getAllModuleIds({ status: 'active' }); + expect(activeModules).toEqual(expect.arrayContaining(data.modules.modules)); + }); + setup('disable simple-auction ajax bid check @pro', async () => { + setup.skip(!process.env.CI || !DOKAN_PRO, 'skip on local'); const [, , status] = await apiUtils.getSinglePlugin('wa/woocommerce-simple-auctions', payloads.adminAuth); status === 'active' && (await dbUtils.updateWpOptionTable('simple_auctions_live_check', 'no')); }); @@ -130,8 +124,9 @@ setup.describe('setup user settings', () => { // create store product const product = { ...payloads.createProduct(), name: data.predefined.simpleProduct.product1.name }; const [, productId] = await apiUtils.createProduct(product, payloads.vendorAuth); - (global as any).PRODUCT_ID = productId; - // helpers.writeEnvJson('PRODUCT_ID', productId); + console.log('PRODUCT_ID', productId); + process.env.PRODUCT_ID = productId; + helpers.appendEnv(`PRODUCT_ID=${productId}`); // for local testing }); setup('add vendor2 product @lite', async () => { @@ -141,26 +136,27 @@ setup.describe('setup user settings', () => { // create store product const product = { ...payloads.createProduct(), name: data.predefined.vendor2.simpleProduct.product1.name }; const [, productId] = await apiUtils.createProduct(product, payloads.vendor2Auth); - (global as any).V2_PRODUCT_ID = productId; - // helpers.writeEnvJson('V2_PRODUCT_ID', productId); + console.log('V2_PRODUCT_ID:', productId); + process.env.V2_PRODUCT_ID = productId; + helpers.appendEnv(`V2_PRODUCT_ID=${productId}`); // for local testing }); setup('add vendor coupon @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); // 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.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 () => { + setup.skip('add test vendor orders @lite', async () => { await apiUtils.createOrder(payloads.createProduct(), { ...payloads.createOrder, customer_id: CUSTOMER_ID }, payloads.vendorAuth); }); }); @@ -200,58 +196,73 @@ setup.describe('setup dokan settings', () => { }); setup('admin set dokan privacy policy settings @lite', async () => { + const [, pageId] = await apiUtils.createPage(payloads.privacyPolicyPage, payloads.adminAuth); + dbData.dokan.privacyPolicySettings.privacy_page = String(pageId); await dbUtils.setDokanSettings(dbData.dokan.optionName.privacyPolicy, dbData.dokan.privacyPolicySettings); }); setup('admin set dokan color settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.colors, dbData.dokan.colorsSettings); }); setup('admin set dokan store support settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.storeSupport, dbData.dokan.storeSupportSettings); }); setup('admin set dokan shipping status settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.shippingStatus, dbData.dokan.shippingStatusSettings); }); setup('admin set dokan quote settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.quote, dbData.dokan.quoteSettings); }); setup('admin set dokan rma settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.rma, dbData.dokan.rmaSettings); }); setup('admin set dokan wholesale settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.wholesale, dbData.dokan.wholesaleSettings); }); setup('admin set dokan eu compliance settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.euCompliance, dbData.dokan.euComplianceSettings); }); setup('admin set dokan delivery time settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.deliveryTime, dbData.dokan.deliveryTimeSettings); }); setup('admin set dokan product advertising settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.productAdvertising, dbData.dokan.productAdvertisingSettings); }); setup('admin set dokan geolocation settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.geolocation, dbData.dokan.geolocationSettings); }); setup('admin set dokan product report abuse settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.productReportAbuse, dbData.dokan.productReportAbuseSettings); }); setup('admin set dokan spmv settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.spmv, dbData.dokan.spmvSettings); }); setup('admin set dokan vendor subscription settings @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await dbUtils.setDokanSettings(dbData.dokan.optionName.vendorSubscription, dbData.dokan.vendorSubscriptionSettings); }); }); @@ -291,10 +302,12 @@ setup.describe('setup dokan settings e2e', () => { }); setup('recreate product advertisement payment product via settings save @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); await productAdvertisingPage.recreateProductAdvertisementPaymentViaSettingsSave(); }); setup('product advertisement payment product exists @pro', async () => { + setup.skip(!DOKAN_PRO, 'skip on lite'); const product = await apiUtils.checkProductExistence('Product Advertisement Payment', payloads.adminAuth); expect(product).toBeTruthy(); }); @@ -302,83 +315,4 @@ setup.describe('setup dokan settings e2e', () => { 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/abuseReports.spec.ts b/tests/pw/tests/e2e/abuseReports.spec.ts index a7e7d5890f..c2361509c6 100644 --- a/tests/pw/tests/e2e/abuseReports.spec.ts +++ b/tests/pw/tests/e2e/abuseReports.spec.ts @@ -6,7 +6,7 @@ import { data } from '@utils/testData'; import { dbData } from '@utils/dbData'; import { payloads } from '@utils/payloads'; -const { VENDOR_ID, CUSTOMER_ID } = global as any; +const { VENDOR_ID, CUSTOMER_ID } = process.env; test.describe('Abuse report test', () => { let admin: AbuseReportsPage; diff --git a/tests/pw/tests/e2e/announcements.spec.ts b/tests/pw/tests/e2e/announcements.spec.ts index 2f7f634a1b..fd0bbf5213 100644 --- a/tests/pw/tests/e2e/announcements.spec.ts +++ b/tests/pw/tests/e2e/announcements.spec.ts @@ -45,13 +45,13 @@ test.describe('Announcements test', () => { test('admin can restore announcement @pro', async () => { const [, announcementId, announcementTitle] = await apiUtils.createAnnouncement(payloads.createAnnouncement(), payloads.adminAuth); - await apiUtils.deleteAnnouncement(announcementId,payloads.adminAuth); + await apiUtils.deleteAnnouncement(announcementId, payloads.adminAuth); await admin.updateAnnouncement(announcementTitle, 'restore'); }); test('admin can permanently delete announcement @pro', async () => { const [, announcementId, announcementTitle] = await apiUtils.createAnnouncement(payloads.createAnnouncement(), payloads.adminAuth); - await apiUtils.deleteAnnouncement(announcementId,payloads.adminAuth); + await apiUtils.deleteAnnouncement(announcementId, payloads.adminAuth); await admin.updateAnnouncement(announcementTitle, 'permanently-delete'); }); diff --git a/tests/pw/tests/e2e/coupons.spec.ts b/tests/pw/tests/e2e/coupons.spec.ts index 86784d7df6..e54c1ccdcc 100644 --- a/tests/pw/tests/e2e/coupons.spec.ts +++ b/tests/pw/tests/e2e/coupons.spec.ts @@ -4,7 +4,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { PRODUCT_ID } = global as any; +const { PRODUCT_ID } = process.env; test.describe('Coupons test', () => { let admin: CouponsPage; @@ -34,7 +34,7 @@ test.describe('Coupons test', () => { }); test.afterAll(async () => { - await aPage.close(); // todo: close multiple pages to base page + await aPage.close(); await vPage.close(); await cPage.close(); }); diff --git a/tests/pw/tests/e2e/customer.spec.ts b/tests/pw/tests/e2e/customer.spec.ts index 9e6c93edf3..b35f563415 100644 --- a/tests/pw/tests/e2e/customer.spec.ts +++ b/tests/pw/tests/e2e/customer.spec.ts @@ -49,7 +49,7 @@ test.describe('Customer functionality test', () => { // let apiUtils: ApiUtils; test.beforeAll(async ({ browser }) => { - customerContext = await browser.newContext({ storageState: data.auth.customerAuthFile }); + customerContext = await browser.newContext(data.auth.customerAuth); cPage = await customerContext.newPage(); customer = new CustomerPage(cPage); // apiUtils = new ApiUtils(request); diff --git a/tests/pw/tests/e2e/emailVerification.spec.ts b/tests/pw/tests/e2e/emailVerification.spec.ts index 71c27b167e..69193e7815 100644 --- a/tests/pw/tests/e2e/emailVerification.spec.ts +++ b/tests/pw/tests/e2e/emailVerification.spec.ts @@ -22,11 +22,11 @@ test.describe('Email verifications test', () => { await uPage.close(); }); - test('user can see registration notice (2-step authentication) while registering as customer @pro ', async () => { + 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 () => { + 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 index 7d43927e6d..14a24cc5dd 100644 --- a/tests/pw/tests/e2e/followStore.spec.ts +++ b/tests/pw/tests/e2e/followStore.spec.ts @@ -46,7 +46,7 @@ test.describe('Follow stores functionality test', () => { await vendor.vendorFollowersRenderProperly(); }); - test('vendor can view followers @pro ', async () => { + test('vendor can view followers @pro', async () => { await vendor.vendorViewFollowers(); }); }); diff --git a/tests/pw/tests/e2e/license.spec.ts b/tests/pw/tests/e2e/license.spec.ts index f6293a12f0..b4a155e94d 100644 --- a/tests/pw/tests/e2e/license.spec.ts +++ b/tests/pw/tests/e2e/license.spec.ts @@ -20,11 +20,16 @@ test.describe('License test', () => { 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'); }); + + test('admin can activate license @pro', async () => { + await admin.activateLicense(data.dokanLicense.correctKey); + }); + + test('admin can deactivate license @pro', async () => { + await admin.activateLicense(data.dokanLicense.correctKey); + await admin.deactivateLicense(); + }); }); diff --git a/tests/pw/tests/e2e/myOrders.spec.ts b/tests/pw/tests/e2e/myOrders.spec.ts index 1199296588..bc54afed3c 100644 --- a/tests/pw/tests/e2e/myOrders.spec.ts +++ b/tests/pw/tests/e2e/myOrders.spec.ts @@ -4,7 +4,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { CUSTOMER_ID, PRODUCT_ID } = global as any; +const { CUSTOMER_ID, PRODUCT_ID } = process.env; test.describe('My orders functionality test', () => { let customer: MyOrdersPage; @@ -47,7 +47,7 @@ test.describe('My orders functionality test', () => { await customer.cancelPendingOrder(orderId); }); - test('customer can order again @lite', async () => { + test.skip('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 index 1a01430db7..ba6d0d4552 100644 --- a/tests/pw/tests/e2e/orders.spec.ts +++ b/tests/pw/tests/e2e/orders.spec.ts @@ -6,8 +6,7 @@ import { payloads } from '@utils/payloads'; import { dbUtils } from '@utils/dbUtils'; import { dbData } from '@utils/dbData'; -const { DOKAN_PRO } = process.env; -const { CUSTOMER_ID, PRODUCT_ID } = global as any; +const { DOKAN_PRO, CUSTOMER_ID, PRODUCT_ID } = process.env; test.describe('Order functionality test', () => { let vendor: OrdersPage; diff --git a/tests/pw/tests/e2e/plugin.spec.ts b/tests/pw/tests/e2e/plugin.spec.ts new file mode 100644 index 0000000000..863b45a815 --- /dev/null +++ b/tests/pw/tests/e2e/plugin.spec.ts @@ -0,0 +1,63 @@ +import { test, Page } from '@playwright/test'; +import { PluginPage } from '@pages/pluginPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { data } from '@utils/testData'; +import { payloads } from '@utils/payloads'; + +test.describe.skip('Plugin functionality test', () => { + let pluginPage: PluginPage; + let aPage: Page; + let apiUtils: ApiUtils; + + test.beforeAll(async ({ browser, request }) => { + const adminContext = await browser.newContext(data.auth.adminAuth); + aPage = await adminContext.newPage(); + pluginPage = new PluginPage(aPage); + + apiUtils = new ApiUtils(request); + }); + + test.afterAll(async () => { + await aPage.close(); + }); + + //todo: install plugin + + test('Activate dokan lite plugin @lite', async () => { + await apiUtils.updatePlugin('dokan/dokan', { status: 'inactive' }, payloads.adminAuth); + await pluginPage.activatePlugin(data.plugin.pluginName.dokanlite); + }); + + test('Deactivate dokan lite plugin @lite', async () => { + await apiUtils.updatePlugin('dokan/dokan', { status: 'active' }, payloads.adminAuth); + await pluginPage.deactivateDokanPlugin(data.plugin.pluginName.dokanlite, false); + }); + + test('Deactivate dokan lite plugin with deactivate reason @lite', async () => { + await apiUtils.updatePlugin('dokan/dokan', { status: 'active' }, payloads.adminAuth); + await pluginPage.deactivateDokanPlugin(data.plugin.pluginName.dokanlite, true); + }); + + test('Activate dokan pro plugin @pro', async () => { + await apiUtils.updatePlugin('dokan-pro/dokan-pro', { status: 'inactive' }, payloads.adminAuth); + await pluginPage.activatePlugin(data.plugin.pluginName.dokanPro); + }); + + test('Deactivate dokan pro plugin @pro', async () => { + await apiUtils.updatePlugin('dokan-pro/dokan-pro', { status: 'active' }, payloads.adminAuth); + await pluginPage.deactivateDokanPlugin(data.plugin.pluginName.dokanPro, false); + }); + + test('Deactivate dokan pro plugin with deactivate reason @pro', async () => { + await apiUtils.updatePlugin('dokan-pro/dokan-pro', { status: 'active' }, payloads.adminAuth); + await pluginPage.deactivateDokanPlugin(data.plugin.pluginName.dokanPro, true); + }); + + // test('Delete dokan lite plugin @lite', async ( ) => { + // await pluginPage.activatePlugin(data.plugin.dokanLite); + // }); + + // test('Delete dokan pro plugin @pro', async ( ) => { + // await pluginPage.activatePlugin(data.plugin.dokanLite); + // }); +}); diff --git a/tests/pw/tests/e2e/privacyPolicy.spec.ts b/tests/pw/tests/e2e/privacyPolicy.spec.ts new file mode 100644 index 0000000000..17c565d152 --- /dev/null +++ b/tests/pw/tests/e2e/privacyPolicy.spec.ts @@ -0,0 +1,49 @@ +import { test, Page } from '@playwright/test'; +import { PrivacyPolicy } from '@pages/privacyPolicyPage'; +import { CustomerPage } from '@pages/customerPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { dbData } from '@utils/dbData'; + +test.describe.skip('Privacy Policy & Store Contact form test', () => { + let customer: PrivacyPolicy; + let customerPage: CustomerPage; + let cPage: Page; + let apiUtils: ApiUtils; + let privacyPolicySettings: object; + + test.beforeAll(async ({ browser, request }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customerPage = new CustomerPage(cPage); + customer = new PrivacyPolicy(cPage); + + apiUtils = new ApiUtils(request); + privacyPolicySettings = await dbUtils.getDokanSettings(dbData.dokan.optionName.privacyPolicy); + }); + + test.afterAll(async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.privacyPolicy, { ...privacyPolicySettings, enable_privacy: 'on' }); + await dbUtils.setDokanSettings(dbData.dokan.optionName.appearance, dbData.dokan.appearanceSettings); + await cPage.close(); + }); + + test('customer can contact vendor @lite', async () => { + await customer.contactVendor(data.predefined.vendorStores.vendor1, data.storeContactData); + }); + + test('customer can navigate to dokan privacy policy @lite', async () => { + await customer.goToPrivacyPolicy(data.predefined.vendorStores.vendor1); + }); + + test('privacy policy is disabled on store contact form @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.privacyPolicy, { ...privacyPolicySettings, enable_privacy: 'off' }); + await customer.disablePrivacyPolicy(data.predefined.vendorStores.vendor1); + }); + + test('store contact form is disabled on store sidebar @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.appearance, { ...dbData.dokan.appearanceSettings, contact_seller: 'off' }); + await customer.disableStoreContactForm(data.predefined.vendorStores.vendor1); + }); +}); diff --git a/tests/pw/tests/e2e/productEnquiry.spec.ts b/tests/pw/tests/e2e/productEnquiry.spec.ts index 2040dce80a..f494585c12 100644 --- a/tests/pw/tests/e2e/productEnquiry.spec.ts +++ b/tests/pw/tests/e2e/productEnquiry.spec.ts @@ -6,7 +6,7 @@ import { data } from '@utils/testData'; import { dbData } from '@utils/dbData'; import { payloads } from '@utils/payloads'; -const { VENDOR_ID, CUSTOMER_ID } = global as any; +const { VENDOR_ID, CUSTOMER_ID } = process.env; test.describe('Product Enquiry test', () => { // let admin: ProductEnquiryPage; diff --git a/tests/pw/tests/e2e/productReviews.spec.ts b/tests/pw/tests/e2e/productReviews.spec.ts index b28ec736d2..8969c77b99 100644 --- a/tests/pw/tests/e2e/productReviews.spec.ts +++ b/tests/pw/tests/e2e/productReviews.spec.ts @@ -4,7 +4,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { PRODUCT_ID } = global as any; +const { PRODUCT_ID } = process.env; test.describe('Product Reviews test', () => { let vendor: ProductReviewsPage; diff --git a/tests/pw/tests/e2e/products.spec.ts b/tests/pw/tests/e2e/products.spec.ts index 81bd68761d..44c9746d06 100644 --- a/tests/pw/tests/e2e/products.spec.ts +++ b/tests/pw/tests/e2e/products.spec.ts @@ -85,7 +85,15 @@ test.describe('Product functionality test', () => { await vendor.vendorAddExternalProduct(data.product.external, false); }); - test('vendor can add product product category @lite', async () => { + test('vendor can add downloadable product @lite', async () => { + await vendor.vendorAddDownloadableProduct(data.product.downloadable, false); + }); + + test('vendor can add virtual product @lite', async () => { + await vendor.vendorAddVirtualProduct(data.product.virtual, false); + }); + + test('vendor can add product category @lite', async () => { await vendor.vendorAddProductCategory(data.predefined.simpleProduct.product1.name, data.product.category.unCategorized); }); @@ -133,12 +141,32 @@ test.describe('Product functionality test', () => { await vendor.quickEditProduct({ ...data.product.simple, editProduct: productName }); }); + test('vendor can add product description @lite', async () => { + await vendor.addProductDescription(productName, data.product.productInfo.description); + }); + // test('vendor can add product quantity discount @pro', async ( ) => { - // await vendor.addProductQuantityDiscount(data.predefined.simpleProduct.product1.name, data.vendor.vendorInfo.quantityDiscount); + // await vendor.addProductQuantityDiscount(data.predefined.simpleProduct.product1.name, data.product.productInfo.quantityDiscount); // }); - test('vendor can add product rma settings @pro', async () => { - await vendor.addProductRmaSettings(data.predefined.simpleProduct.product1.name, data.vendor.rma); + test('vendor can add product rma options @pro', async () => { + await vendor.addProductRmaOptions(productName, data.vendor.rma); + }); + + test('vendor can add product wholesale options @pro', async () => { + await vendor.addProductWholesaleOptions(productName, data.product.productInfo.wholesaleOption); + }); + + test.skip('vendor can add product min-max options @pro', async () => { + await vendor.addProductMinMaxOptions(productName, data.product.productInfo.minMax); + }); + + test('vendor can add product other options @lite', async () => { + await vendor.addProductOtherOptions(productName, data.product.productInfo.otherOptions); + }); + + test.skip('vendor can add catalog mode @lite', async () => { + await vendor.addCatalogMode(productName); }); // todo: add more product edit tests -> discount, wholesale, advertising diff --git a/tests/pw/tests/e2e/refunds.spec.ts b/tests/pw/tests/e2e/refunds.spec.ts index a97eae8983..bc9592e771 100644 --- a/tests/pw/tests/e2e/refunds.spec.ts +++ b/tests/pw/tests/e2e/refunds.spec.ts @@ -5,7 +5,7 @@ import { dbUtils } from '@utils/dbUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { CUSTOMER_ID, PRODUCT_ID } = global as any; +const { CUSTOMER_ID, PRODUCT_ID } = process.env; test.describe('Refunds test', () => { let admin: RefundsPage; diff --git a/tests/pw/tests/e2e/reports.spec.ts b/tests/pw/tests/e2e/reports.spec.ts index 75b758cfa0..0da8f57bda 100644 --- a/tests/pw/tests/e2e/reports.spec.ts +++ b/tests/pw/tests/e2e/reports.spec.ts @@ -4,7 +4,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { PRODUCT_ID } = global as any; +const { PRODUCT_ID } = process.env; test.describe('Reports test', () => { let admin: ReportsPage; diff --git a/tests/pw/tests/e2e/requestForQuotes.spec.ts b/tests/pw/tests/e2e/requestForQuotes.spec.ts index 38d4570f00..d8d4ee73bf 100644 --- a/tests/pw/tests/e2e/requestForQuotes.spec.ts +++ b/tests/pw/tests/e2e/requestForQuotes.spec.ts @@ -4,7 +4,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { CUSTOMER_ID } = global as any; +const { CUSTOMER_ID } = process.env; test.describe('Request for quotation test admin', () => { let admin: RequestForQuotationsPage; diff --git a/tests/pw/tests/e2e/reverseWithdraws.spec.ts b/tests/pw/tests/e2e/reverseWithdraws.spec.ts index 06cfa71e90..353e133fcb 100644 --- a/tests/pw/tests/e2e/reverseWithdraws.spec.ts +++ b/tests/pw/tests/e2e/reverseWithdraws.spec.ts @@ -7,7 +7,7 @@ import { payloads } from '@utils/payloads'; import { dbUtils } from '@utils/dbUtils'; import { dbData } from '@utils/dbData'; -const { PRODUCT_ID } = global as any; +const { PRODUCT_ID } = process.env; test.describe('Reverse withdraw test', () => { let admin: ReverseWithdrawsPage; diff --git a/tests/pw/tests/e2e/settings.spec.ts b/tests/pw/tests/e2e/settings.spec.ts index 351e842396..3cfde1dc43 100644 --- a/tests/pw/tests/e2e/settings.spec.ts +++ b/tests/pw/tests/e2e/settings.spec.ts @@ -57,7 +57,8 @@ test.describe('Settings test', () => { }); test('admin can set dokan privacy policy settings @lite', async () => { - await settingsPage.setDokanPrivacyPolicySettings(data.dokanSettings.privacyPolicy); + const privacyPolicySettings = await dbUtils.getDokanSettings(dbData.dokan.optionName.privacyPolicy); + await settingsPage.setDokanPrivacyPolicySettings({ ...data.dokanSettings.privacyPolicy, privacyPage: privacyPolicySettings.privacyPage }); }); test('admin can set dokan color settings @pro', async () => { diff --git a/tests/pw/tests/e2e/spmv.spec.ts b/tests/pw/tests/e2e/spmv.spec.ts index dbe4f1c735..da62206f31 100644 --- a/tests/pw/tests/e2e/spmv.spec.ts +++ b/tests/pw/tests/e2e/spmv.spec.ts @@ -52,7 +52,7 @@ test.describe('Vendor SPMV test', () => { await vendor.vendorSpmvRenderProperly(); }); - test('vendor can search similar product on spmv page @pro ', async () => { + test('vendor can search similar product on spmv page @pro', async () => { await vendor.searchSimilarProduct(productName, 'spmv'); }); diff --git a/tests/pw/tests/e2e/storeAppearance.spec.ts b/tests/pw/tests/e2e/storeAppearance.spec.ts new file mode 100644 index 0000000000..cc2e2409d1 --- /dev/null +++ b/tests/pw/tests/e2e/storeAppearance.spec.ts @@ -0,0 +1,53 @@ +import { test, Page } from '@playwright/test'; +import { StoreAppearance } from '@pages/storeAppearance'; +import { CustomerPage } from '@pages/customerPage'; +import { ApiUtils } from '@utils/apiUtils'; +import { dbUtils } from '@utils/dbUtils'; +import { data } from '@utils/testData'; +import { dbData } from '@utils/dbData'; + +test.describe.skip('Store Appearance test', () => { + let customer: StoreAppearance; + let customerPage: CustomerPage; + let cPage: Page; + let apiUtils: ApiUtils; + let privacyPolicySettings: object; + + // todo: need to remove default dokan store sidebar content + + test.beforeAll(async ({ browser, request }) => { + const customerContext = await browser.newContext(data.auth.customerAuth); + cPage = await customerContext.newPage(); + customerPage = new CustomerPage(cPage); + customer = new StoreAppearance(cPage); + + apiUtils = new ApiUtils(request); + privacyPolicySettings = await dbUtils.getDokanSettings(dbData.dokan.optionName.privacyPolicy); + }); + + test.afterAll(async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.appearance, dbData.dokan.appearanceSettings); + await cPage.close(); + }); + + test('store map is disabled on store sidebar @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.appearance, { ...dbData.dokan.appearanceSettings, store_map: 'off' }); + await customer.disableMapOnStoreSidebar(data.predefined.vendorStores.vendor1); + }); + + test('store open-close time is disabled store sidebar @lite', async () => { + await dbUtils.setDokanSettings(dbData.dokan.optionName.appearance, { ...dbData.dokan.appearanceSettings, store_open_close: 'off' }); + await customer.disableStoreOpenCloseTimeOnStoreSidebar(data.predefined.vendorStores.vendor1); + }); + + test.skip('vendor info is disabled on single store page @lite', async () => { + // todo: need to fix + console.log(await dbUtils.getDokanSettings(dbData.dokan.optionName.appearance)); + await dbUtils.setDokanSettings(dbData.dokan.optionName.appearance, { + ...dbData.dokan.appearanceSettings, + hide_vendor_info: { email: 'email', phone: 'phone', address: 'address' }, + }); + console.log(await dbUtils.getDokanSettings(dbData.dokan.optionName.appearance)); + await customer.disableVendorInfoOnSingleStorePage(data.predefined.vendorStores.vendor1); + }); +}); diff --git a/tests/pw/tests/e2e/storeReviews.spec.ts b/tests/pw/tests/e2e/storeReviews.spec.ts index 6ddea83282..4e4732aa97 100644 --- a/tests/pw/tests/e2e/storeReviews.spec.ts +++ b/tests/pw/tests/e2e/storeReviews.spec.ts @@ -4,7 +4,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { VENDOR_ID } = global as any; +const { VENDOR_ID } = process.env; test.describe('Store Reviews test', () => { let admin: StoreReviewsPage; diff --git a/tests/pw/tests/e2e/storeSupports.spec.ts b/tests/pw/tests/e2e/storeSupports.spec.ts index 037248cc9b..0eea0deb5d 100644 --- a/tests/pw/tests/e2e/storeSupports.spec.ts +++ b/tests/pw/tests/e2e/storeSupports.spec.ts @@ -5,7 +5,7 @@ import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; import { responseBody } from '@utils/interfaces'; -const { VENDOR_ID, CUSTOMER_ID, PRODUCT_ID } = global as any; +const { VENDOR_ID, CUSTOMER_ID, PRODUCT_ID } = process.env; test.describe('Store Support test (admin)', () => { let admin: StoreSupportsPage; diff --git a/tests/pw/tests/e2e/stores.spec.ts b/tests/pw/tests/e2e/stores.spec.ts index 44616ffa4a..836e0b6d42 100644 --- a/tests/pw/tests/e2e/stores.spec.ts +++ b/tests/pw/tests/e2e/stores.spec.ts @@ -4,7 +4,7 @@ import { StoresPage } from '@pages/storesPage'; import { data } from '@utils/testData'; // import { payloads } from '@utils/payloads'; -const { VENDOR_ID } = global as any; +const { VENDOR_ID } = process.env; test.describe('Stores test', () => { let admin: StoresPage; diff --git a/tests/pw/tests/e2e/tools.spec.ts b/tests/pw/tests/e2e/tools.spec.ts index 26db4fd507..fbc1367c29 100644 --- a/tests/pw/tests/e2e/tools.spec.ts +++ b/tests/pw/tests/e2e/tools.spec.ts @@ -25,10 +25,14 @@ test.describe('Tools test', () => { await admin.adminToolsRenderProperly(); }); - test('admin can perform dokan page Installation @pro', async () => { + test.skip('admin can perform dokan page Installation @pro', async () => { await admin.dokanPageInstallation(); }); + test('admin can regenerate order commission @pro', async () => { + await admin.regenerateOrderCommission(); + }); + test('admin can check for duplicate orders @pro', async () => { await admin.checkForDuplicateOrders(); }); diff --git a/tests/pw/tests/e2e/vendorAnalytics.spec.ts b/tests/pw/tests/e2e/vendorAnalytics.spec.ts index 4f1dda164a..925dbd8395 100644 --- a/tests/pw/tests/e2e/vendorAnalytics.spec.ts +++ b/tests/pw/tests/e2e/vendorAnalytics.spec.ts @@ -1,8 +1,6 @@ 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; @@ -13,8 +11,6 @@ test.describe('Vendor analytics test', () => { const vendorContext = await browser.newContext(data.auth.vendorAuth); vPage = await vendorContext.newPage(); vendor = new VendorAnalyticsPage(vPage); - - // apiUtils = new ApiUtils(request); }); test.afterAll(async () => { diff --git a/tests/pw/tests/e2e/vendorAuction.spec.ts b/tests/pw/tests/e2e/vendorAuction.spec.ts index 8430cd9aa3..c1b86b233f 100644 --- a/tests/pw/tests/e2e/vendorAuction.spec.ts +++ b/tests/pw/tests/e2e/vendorAuction.spec.ts @@ -27,7 +27,6 @@ test.describe('Auction Product test', () => { apiUtils = new ApiUtils(request); [, , auctionProductName] = await apiUtils.createProduct(payloads.createAuctionProduct(), payloads.vendorAuth); - await customer.bidAuctionProduct(auctionProductName); }); diff --git a/tests/pw/tests/e2e/vendorBooking.spec.ts b/tests/pw/tests/e2e/vendorBooking.spec.ts index b5dbf4d652..1476287faa 100644 --- a/tests/pw/tests/e2e/vendorBooking.spec.ts +++ b/tests/pw/tests/e2e/vendorBooking.spec.ts @@ -28,7 +28,6 @@ test.describe('Booking Product test', () => { apiUtils = new ApiUtils(request); [, , bookableProductName] = await apiUtils.createBookableProduct(payloads.createBookableProduct(), payloads.vendorAuth); - await vendor.addBookingResource(bookingResourceName); // todo: convert with api or db }); @@ -121,7 +120,8 @@ test.describe('Booking Product test', () => { await vendor.addBooking(bookableProductName, data.bookings, data.customer.username); }); - test('customer can buy bookable product @pro', async () => { + test.skip('customer can buy bookable product @pro', async () => { + // todo: customer storage state gets reset somehow (from previous tests) await customer.buyBookableProduct(bookableProductName, data.bookings); }); diff --git a/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts b/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts index e906b798a0..9431b4fa0d 100644 --- a/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts +++ b/tests/pw/tests/e2e/vendorDeliveryTime.spec.ts @@ -49,12 +49,12 @@ test.describe('Vendor delivery time test', () => { await vendor.updateCalendarView('week'); }); - test('customer can buy product with delivery time @pro', async () => { + test.skip('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 () => { + test.skip('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/vendorReturnRequest.spec.ts b/tests/pw/tests/e2e/vendorReturnRequest.spec.ts index 5d971dc25d..250adcc34d 100644 --- a/tests/pw/tests/e2e/vendorReturnRequest.spec.ts +++ b/tests/pw/tests/e2e/vendorReturnRequest.spec.ts @@ -6,9 +6,9 @@ import { OrdersPage } from '@pages/ordersPage'; import { data } from '@utils/testData'; // import { payloads } from '@utils/payloads'; -// const { CUSTOMER_ID, PRODUCT_ID } = global as any; +// const { CUSTOMER_ID, PRODUCT_ID } = process.env; -test.describe('Vendor RMA test', () => { +test.describe.skip('Vendor RMA test', () => { let vendor: VendorReturnRequestPage; let vendor1: OrdersPage; let customer: VendorReturnRequestPage; diff --git a/tests/pw/tests/e2e/withdraws.spec.ts b/tests/pw/tests/e2e/withdraws.spec.ts index 5a6c842230..1c7ce15934 100644 --- a/tests/pw/tests/e2e/withdraws.spec.ts +++ b/tests/pw/tests/e2e/withdraws.spec.ts @@ -4,7 +4,7 @@ import { ApiUtils } from '@utils/apiUtils'; import { data } from '@utils/testData'; import { payloads } from '@utils/payloads'; -const { PRODUCT_ID } = global as any; +const { PRODUCT_ID } = process.env; test.describe('Withdraw test', () => { let admin: WithdrawsPage; @@ -83,7 +83,7 @@ test.describe('Withdraw test', () => { await vendor.vendorWithdrawRequestsRenderProperly(); }); - test('vendor can request withdraw @lite', async () => { + test.skip('vendor can request withdraw @lite', async () => { await apiUtils.cancelWithdraw('', payloads.vendorAuth); await vendor.requestWithdraw({ ...data.vendor.withdraw, minimumWithdrawAmount: minimumWithdrawLimit, currentBalance: currentBalance }); }); diff --git a/tests/pw/types/environment.d.ts b/tests/pw/types/environment.d.ts index 8659df1942..de27faeb8b 100644 --- a/tests/pw/types/environment.d.ts +++ b/tests/pw/types/environment.d.ts @@ -17,6 +17,7 @@ declare global { PRODUCT_ID: string; V2_PRODUCT_ID: string; GMAP: string; + LICENSE_KEY: string; DOKAN_PRO: string; BASE_URL: string; QUERY: string; diff --git a/tests/pw/types/global.d.ts b/tests/pw/types/global.d.ts index fa99c1ee70..80d8680c65 100644 --- a/tests/pw/types/global.d.ts +++ b/tests/pw/types/global.d.ts @@ -5,6 +5,7 @@ declare global { interface Matchers { toMatchSchema(schema: ZodTypeAny): Promise; toBeWithinRange(a: number, b: number): R; + toBeSecureHeader(): R; } } } diff --git a/tests/pw/utils/apiUtils.ts b/tests/pw/utils/apiUtils.ts index 68ce40644a..cc757090ea 100644 --- a/tests/pw/utils/apiUtils.ts +++ b/tests/pw/utils/apiUtils.ts @@ -4,7 +4,8 @@ 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 } = global as any; + +const { VENDOR_ID, CUSTOMER_ID } = process.env; export class ApiUtils { readonly request: APIRequestContext; @@ -408,9 +409,9 @@ export class ApiUtils { } // create coupon - async createCoupon(productIds: string[], coupon: coupon_api, auth?: auth): Promise<[responseBody, string, string]> { + async createCoupon(productIds: (string | undefined)[], coupon: coupon_api, auth?: auth): Promise<[responseBody, string, string]> { // create product if invalid productId exists - if (productIds.includes('undefined')) { + if (productIds.includes(undefined)) { const [, productId] = await this.createProduct(payloads.createProduct(), auth); productIds = [productId]; } @@ -543,7 +544,7 @@ export class ApiUtils { * order api methods */ - // get all orders + // get all orders [of a vendor] async getAllOrders(auth?: auth): Promise { const [, responseBody] = await this.get(endPoints.getAllOrders, { params: { per_page: 100 }, headers: auth }); return responseBody; @@ -1510,6 +1511,12 @@ export class ApiUtils { // order + // get all site orders + async getAllOrdersSite(auth?: auth): Promise { + const [, responseBody] = await this.get(endPoints.wc.getAllOrders, { params: { per_page: 100 }, headers: auth }); + return responseBody; + } + // create order async createOrder(product: string | object, orderPayload: any, auth?: auth): Promise<[APIResponse, responseBody, string, string]> { let productId: string; diff --git a/tests/pw/utils/dbData.ts b/tests/pw/utils/dbData.ts index 5da23db02c..c5b67a7285 100644 --- a/tests/pw/utils/dbData.ts +++ b/tests/pw/utils/dbData.ts @@ -112,11 +112,11 @@ export const dbData = { withdraw_charges: { paypal: { fixed: '0', - percentage: '0', + percentage: '5', }, bank: { - fixed: '0', - percentage: '0', + fixed: '5', + percentage: '', }, skrill: { fixed: '0', @@ -127,7 +127,7 @@ export const dbData = { percentage: '0', }, }, - withdraw_limit: '5', + withdraw_limit: '10', withdraw_order_status: { 'wc-completed': 'wc-completed', 'wc-processing': 'wc-processing', diff --git a/tests/pw/utils/helpers.ts b/tests/pw/utils/helpers.ts index 89ff4227df..83fb0ef9ac 100644 --- a/tests/pw/utils/helpers.ts +++ b/tests/pw/utils/helpers.ts @@ -1,6 +1,6 @@ // const open = require( 'open' ); import fs from 'fs'; -import { Browser, BrowserContextOptions } from '@playwright/test'; +import { Browser, BrowserContextOptions, Page } from '@playwright/test'; export const helpers = { // replace '_' to space & capitalize first letter of string @@ -22,6 +22,8 @@ export const helpers = { // returns a random integer number between min (inclusive) and max (exclusive) getRandomArbitraryInteger: (min: number, max: number) => Math.floor(Math.random() * (max - min) + min), + getRandomNumber: (min: number, max: number) => Math.floor(Math.random() * (max - min + 1)) + min, + // random number between 0 and 1000 randomNumber: () => Math.floor(Math.random() * 1000), @@ -346,4 +348,10 @@ export const helpers = { const browserContext = await browser.newContext(options); return browserContext.newPage(); }, + + async closePages(pages: Page[]): Promise { + for (const page of pages) { + await page.close(); + } + }, }; diff --git a/tests/pw/utils/interfaces.ts b/tests/pw/utils/interfaces.ts index 263523ff21..04f9bdaab7 100644 --- a/tests/pw/utils/interfaces.ts +++ b/tests/pw/utils/interfaces.ts @@ -122,6 +122,26 @@ export interface product { status: string; stockStatus: boolean; editProduct: string; + saveSuccessMessage: string; + }; + + downloadable: { + productType: string; + productName: () => string; + category: string; + regularPrice: () => string; + storeName: string; + status: string; + stockStatus: boolean; + editProduct: string; + saveSuccessMessage: string; + + downloadableOptions: { + fileName: string; + fileUrl: string; + downloadLimit: string; + downloadExpiry: string; + }; }; variable: { @@ -276,6 +296,42 @@ export interface product { guestName: () => string; guestEmail: () => string; }; + + productInfo: { + description: { + shortDescription: string; + description: string; + }; + + amountDiscount: { + minimumOrderAmount: string; + discountPercentage: string; + }; + + quantityDiscount: { + minimumQuantity: string; + discountPercentage: string; + }; + + wholesaleOption: { + wholesalePrice: string; + minimumWholesaleQuantity: string; + }; + + minMax: { + minimumProductQuantity: string; + maximumProductQuantity: string; + minimumAmount: string; + maximumAmount: string; + category: string; + }; + + otherOptions: { + productStatus: string; + visibility: string; + purchaseNote: string; + }; + }; } // order @@ -681,24 +737,6 @@ export interface vendor { }; }; - amountDiscount: { - minimumOrderAmount: string; - discountPercentage: string; - }; - - quantityDiscount: { - minimumQuantity: string; - discountPercentage: string; - }; - - minMax: { - minimumProductQuantity: string; - maximumProductQuantity: string; - minimumAmount: string; - maximumAmount: string; - category: string; - }; - storeSettingsSaveSuccessMessage: string; socialProfileUrls: { @@ -727,6 +765,19 @@ export interface vendor { subject: string; message: string; }; + + amountDiscount: { + minimumOrderAmount: string; + discountPercentage: string; + }; + + minMax: { + minimumProductQuantity: string; + maximumProductQuantity: string; + minimumAmount: string; + maximumAmount: string; + category: string; + }; }; shipping: { @@ -1409,6 +1460,12 @@ export interface dokanSettings { withdraw: { customMethodName: string; customMethodType: string; + charge: { + paypal: string; + bank: string; + skrill: string; + custom: string; + }; minimumWithdrawAmount: string; withdrawThreshold: string; quarterlyScheduleMonth: string; @@ -1766,3 +1823,9 @@ export interface feeRecipient { taxFeeRecipient: string; shippingTaxFeeRecipient: string; } + +export interface storeContactData { + name: string; + email: string; + message: string; +} diff --git a/tests/pw/utils/payloads.ts b/tests/pw/utils/payloads.ts index aa5cdd9ad2..9bd6244bbd 100644 --- a/tests/pw/utils/payloads.ts +++ b/tests/pw/utils/payloads.ts @@ -24,6 +24,12 @@ export const payloads = { status: 'publish', }), + privacyPolicyPage: { + title: 'Privacy Policy', + content: 'This Privacy Policy describes how we collect, use, and disclose your personal information in connection with your use of our product.', + status: 'publish', + }, + tocPage: { title: 'Terms And Conditions', status: 'publish', @@ -2487,7 +2493,7 @@ export const payloads = { flickr: 'http://dokan.test', }, phone: '0123456789', - show_email: true, // todo: doesn't work on lite + show_email: 'yes', address: { street_1: 'abc street', street_2: 'xyz street', @@ -2503,17 +2509,16 @@ export const payloads = { 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, - }, + enable_tnc: 'on', + store_tnc: 'test Vendor terms and conditions', + featured: 'yes', + // rating: { + // rating: '4.00', // todo: doesn't work on lite [might not implemented on lite] + // count: 1, + // }, enabled: true, payment: { paypal: { - 0: 'email', email: 'paypal@g.c', }, bank: { @@ -2526,7 +2531,6 @@ export const payloads = { iban: '123456', swift: '12345', }, - stripe: false, }, trusted: true, // store_open_close: { @@ -2535,49 +2539,49 @@ export const payloads = { // 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', - }, + // store_open_close: { + // // todo: isn't implemented on dokan create store api + // enabled: 'yes', // todo: + // 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: '', diff --git a/tests/pw/utils/pwMatchers.ts b/tests/pw/utils/pwMatchers.ts index 3ff23bb7a0..9b52cae244 100644 --- a/tests/pw/utils/pwMatchers.ts +++ b/tests/pw/utils/pwMatchers.ts @@ -1,3 +1,4 @@ +import { APIResponse } from '@playwright/test'; import { ZodTypeAny } from 'zod'; export const customMatchers = { @@ -16,6 +17,27 @@ export const customMatchers = { } }, + toBeSecureHeader(headers: any) { + // todo: implement this + // let pass; + // pass = headers['content-type'] === 'application/json; charset=UTF-8'; + // pass = headers['x-content-type-options'] === 'nosniff'; + // pass = headers['access-control-expose-headers'] === 'X-WP-Total, X-WP-TotalPages, Link'; + // pass = headers['access-control-allow-headers'] === 'Authorization, X-WP-Nonce, Content-Disposition, Content-MD5, Content-Type'; + // pass = headers['allow'] === 'GET, POST, df'; + // if (pass) { + // return { + // message: () => 'passed', + // pass: true, + // }; + // } else { + // return { + // message: () => 'failed', + // pass: false, + // }; + // } + }, + toBeWithinRange(received: number, floor: number, ceiling: number) { const pass = received >= floor && received <= ceiling; if (pass) { @@ -34,6 +56,7 @@ export const customMatchers = { export const customExpect = { toMatchSchema: customMatchers.toMatchSchema, + toBeSecureHeader: customMatchers.toBeSecureHeader, toBeWithinRange: customMatchers.toBeWithinRange, }; diff --git a/tests/pw/utils/schemas.ts b/tests/pw/utils/schemas.ts index dd7b31f60f..079c08a979 100644 --- a/tests/pw/utils/schemas.ts +++ b/tests/pw/utils/schemas.ts @@ -1,5 +1,326 @@ import { z } from 'zod'; +const verificationTypeSchema = z.object({ + id: z.string(), + title: z.string(), + disabled: z.boolean(), +}); + +const badgeEventSchema = z.object({ + id: z.string(), + title: z.string(), + description: z.string(), + condition_text: z.object({ + prefix: z.string(), + suffix: z.string(), + type: z.string(), + }), + hover_text: z.string(), + group: z.object({ + key: z.string(), + title: z.string(), + type: z.string().optional(), + }), + has_multiple_levels: z.boolean(), + badge_logo: z.string().url(), + badge_logo_raw: z.string(), + input_group_icon: z.object({ + condition: z.string(), + data: z.string(), + }), + status: z.string(), + created: z.boolean(), +}); + +const badgeSchema = z.object({ + id: z.number(), + badge_name: z.string(), + badge_logo: z.string().url(), + badge_logo_raw: z.string(), + default_logo: z.string(), + formatted_default_logo: z.string().url(), + event_type: z.string(), + formatted_hover_text: z.string(), + event: badgeEventSchema, + badge_status: z.string(), + formatted_badge_status: z.string(), + level_count: z.number(), + vendor_count: z.number(), + acquired_level_count: z.number(), + created_by: z.number(), + created_at: z.string(), + levels: z.array(z.any()), // Adjust this based on the actual structure of levels + _links: z.object({ + self: z.array( + z.object({ + href: z.string().url(), + }), + ), + collection: z.array( + z.object({ + href: z.string().url(), + }), + ), + }), +}); + +const badgeCreateUpdateSchema = z.object({ + id: z.number(), + action: z.enum(['insert', 'update']), +}); + +// store settings +const socialSchema = z.object({ + fb: z.string().url(), + youtube: z.string().url(), + twitter: z.string().url(), + linkedin: z.string().url(), + pinterest: z.string().url(), + instagram: z.string().url(), + flickr: z.string().url(), +}); + +const paypalSchema = z.object({ + email: z.string().email(), +}); + +const bankSchema = z.object({ + ac_name: z.string(), + ac_type: z.string(), + ac_number: z.string(), + bank_name: z.string(), + bank_addr: z.string(), + routing_number: z.string(), + iban: z.string(), + swift: z.string(), +}); + +const skrillSchema = z.object({ + email: z.string().email(), +}); + +const paymentSchema = z.object({ + paypal: paypalSchema, + bank: bankSchema, + stripe: z.boolean(), + skrill: skrillSchema, +}); + +const addressSchema = z.object({ + street_1: z.string(), + street_2: z.string(), + city: z.string(), + zip: z.string(), + country: z.string(), + state: z.string(), +}); + +const timeSchema = z.object({ + status: z.string(), + opening_time: z.array(z.string()), + closing_time: z.array(z.string()), +}); + +const storeTimeSchema = z.object({ + monday: timeSchema, + tuesday: timeSchema, + wednesday: timeSchema, + thursday: timeSchema, + friday: timeSchema, + saturday: timeSchema, + sunday: timeSchema, +}); + +const catalogModeSchema = z.object({ + hide_add_to_cart_button: z.string(), + hide_product_price: z.string(), + request_a_quote_enabled: z.string(), +}); + +const orderMinMaxSchema = z.object({ + enable_vendor_min_max_quantity: z.string(), + min_quantity_to_order: z.string(), + max_quantity_to_order: z.string(), + vendor_min_max_products: z.array(z.any()), // Adjust this based on the actual structure + vendor_min_max_product_cat: z.array(z.any()), // Adjust this based on the actual structure + enable_vendor_min_max_amount: z.string(), + min_amount_to_order: z.string(), + max_amount_to_order: z.string(), +}); + +const categorySchema = z.object({ + term_id: z.number(), + name: z.string(), + slug: z.string(), + term_group: z.number(), + term_taxonomy_id: z.number(), + taxonomy: z.string(), + description: z.string(), + parent: z.number(), + count: z.number(), + filter: z.string(), +}); + +const vendorStoreLocationPickupSchema = z.object({ + multiple_store_location: z.string(), +}); + +const bankPaymentRequiredFieldsSchema = z.object({ + ac_name: z.string(), + ac_type: z.string(), + ac_number: z.string(), + routing_number: z.string(), +}); + +const activePaymentMethodsSchema = z.object({ + paypal: z.string(), + bank: z.string(), +}); + +const profileCompletionSchema = z.object({ + closed_by_user: z.boolean(), + phone: z.number(), + store_name: z.number(), + address: z.number(), + location: z.number(), + Bank: z.number(), + paypal: z.number(), + skrill: z.number(), + fb: z.number(), + youtube: z.number(), + twitter: z.number(), + linkedin: z.number(), + next_todo: z.string(), + progress: z.number(), + progress_vals: z.object({ + banner_val: z.number(), + profile_picture_val: z.number(), + store_name_val: z.number(), + address_val: z.number(), + phone_val: z.number(), + map_val: z.number(), + payment_method_val: z.number(), + social_val: z.object({ + fb: z.number(), + twitter: z.number(), + youtube: z.number(), + linkedin: z.number(), + }), + }), +}); + +const ratingSchema = z.object({ + rating: z.string(), + count: z.number(), +}); + +const linksSchema = z.object({ + self: z.array( + z.object({ + href: z.string().url(), + }), + ), + collection: z.array( + z.object({ + href: z.string().url(), + }), + ), +}); + +const storyCategorySchema = z.object({ + id: z.number(), + count: z.number(), + description: z.string(), + link: z.string().url(), + name: z.string(), + slug: z.string(), + taxonomy: z.string(), + meta: z.array(z.any()), // Adjust this based on the actual structure + _links: linksSchema, +}); + +const storeReviewSchema1 = z.object({ + id: z.number(), + author: z.object({ + id: z.number(), + name: z.string(), + email: z.string().email(), + url: z.union([z.string().url(), z.literal('')]), + avatar: z.string().url(), + }), + title: z.string(), + content: z.string(), + permalink: z.string().nullable(), + product_id: z.number().nullable(), + approved: z.boolean(), + date: z.string(), // You might want to use z.date() if you want to enforce a date format + rating: z.number(), +}); + +const storeReviewSchema = z.object({ + id: z.number(), + title: z.string(), + content: z.string(), + status: z.string(), + created_at: z.coerce.date(), + customer: z.object({ + id: z.number(), + first_name: z.string(), + last_name: z.string(), + email: z.string().email(), + display_name: z.string(), + }), + vendor: z.object({ + id: z.number(), + first_name: z.string(), + last_name: z.string(), + shop_name: z.string(), + shop_url: z.string().url(), + avatar: z.string().url(), + banner: z.string(), + }), + rating: z.number(), + _links: linksSchema, +}); + +const supportTicketSchema = z.object({ + ID: z.number(), + post_author: z.string(), + post_date: z.coerce.date(), + post_date_gmt: z.coerce.date(), + post_content: z.string(), + post_title: z.string(), + post_excerpt: z.string(), + post_status: z.string(), + comment_status: z.string(), + ping_status: z.string(), + post_password: z.string(), + post_name: z.string(), + to_ping: z.string(), + pinged: z.string(), + post_modified: z.coerce.date(), + post_modified_gmt: z.coerce.date(), + post_content_filtered: z.string(), + post_parent: z.number(), + guid: z.string().url(), + menu_order: z.number(), + post_type: z.string(), + post_mime_type: z.string(), + comment_count: z.string(), + filter: z.string(), + vendor_name: z.string(), + customer_name: z.string(), + vendor_id: z.string(), + store_url: z.string().url(), + ticket_date: z.string(), + reading: z.string(), + ancestors: z.array(z.any()), // Adjust this based on the actual structure + page_template: z.string(), + post_category: z.array(z.any()), // Adjust this based on the actual structure + tags_input: z.array(z.any()), // Adjust this based on the actual structure + _links: linksSchema, +}); + export const schemas = { abuseReportsSchema: { abuseReportReasonsSchema: z.array( @@ -9,32 +330,55 @@ export const schemas = { }), ), - abuseReportSchema: z.array( + abuseReportSchema: z.object({ + id: z.number(), + reason: z.string(), + product: z.object({ + id: z.number(), + title: z.string(), + admin_url: z.string().url(), + }), + vendor: z.object({ + id: z.number(), + name: z.string(), + admin_url: z.string().url(), + }), + reported_by: z + .object({ + id: z.number(), + name: z.string(), + email: z.string().email(), + admin_url: z.string().url(), + }) + .nullable(), + description: z.string(), + reported_at: z.coerce.date(), + }), + + abuseReportsSchema: z.array( z.object({ id: z.number(), reason: z.string(), product: z.object({ id: z.number(), title: z.string(), - admin_url: z.string().url(), + admin_url: z.string().url().nullable(), }), vendor: z.object({ id: z.number(), name: z.string(), - admin_url: z.string().url(), + admin_url: z.string().url().nullable(), }), reported_by: z.object({ id: z.number(), name: z.string(), email: z.string().email(), - admin_url: z.string().url(), + admin_url: z.string().url().nullable(), }), description: z.string(), - reported_at: z.string(), //todo add date format + reported_at: z.coerce.date(), }), ), - - // abuseReportsSchema: z.array(schemas.abuseReportsSchema.abuseReportsSchema), }, admin: { @@ -208,7 +552,7 @@ export const schemas = { //adminExportLogsSchema adminExportLogsSchema: z.object({ - step: z.number(), + step: z.string().or(z.number()), percentage: z.number(), columns: z.object({ order_id: z.string(), @@ -231,52 +575,231 @@ export const schemas = { announcementsSchema: { announcementSchema: z.object({ id: z.number(), + notice_id: z.number(), + vendor_id: z.number(), title: z.string(), content: z.string(), - status: z.string(), - created_at: z.string(), - sender_type: z.string(), - sender_ids: z.array( + status: z.enum(['all', 'publish', 'pending', 'draft', 'future', 'trash']), + read_status: z.enum(['read', 'unread', '']), + date: z.string(), + date_gmt: z.string(), + human_readable_date: z.string(), + announcement_sellers: z.array( z.object({ - id: z.number(), + id: z.string(), name: z.string(), shop_name: z.string(), + email: z.string().email(), }), ), + announcement_type: z.string(), _links: z.object({ - self: z.array( + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), + }), + }), + + announcementsSchema: z.array( + z.object({ + id: z.number(), + notice_id: z.number(), + vendor_id: z.number(), + title: z.string(), + content: z.string(), + status: z.enum(['all', 'publish', 'pending', 'draft', 'future', 'trash']), + read_status: z.enum(['read', 'unread', '']), + date: z.coerce.date(), + date_gmt: z.coerce.date(), + human_readable_date: z.string(), + announcement_sellers: z.array( z.object({ - href: z.string(), + id: z.string().or(z.number()), + name: z.string(), + shop_name: z.string(), + email: z.string().email(), }), ), - collection: z.array( + announcement_type: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), + }), + }), + ), + + batchUpdateAnnouncementsSchema: z.object({ + success: z.boolean(), + }), + + announcementNoticeSchema: z.object({ + id: z.number(), + notice_id: z.number(), + vendor_id: z.number(), + title: z.string(), + content: z.string(), + status: z.string(), + read_status: z.string(), + date: z.coerce.date(), + date_gmt: z.coerce.date(), + human_readable_date: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), + }), + }), + + deleteAnnouncementNoticeSchema: z.object({ + success: z.boolean(), + }), + }, + + attributesSchema: { + attributeSchema: z.object({ + id: z.number(), + name: z.string(), + slug: z.string(), + type: z.enum(['select']), + order_by: z.enum(['menu_order', 'name', 'name_num', 'id']), + has_archives: z.boolean(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + + attributesSchema: z.array( + z.object({ + id: z.number(), + name: z.string(), + slug: z.string(), + type: z.enum(['select']), + order_by: z.enum(['menu_order', 'name', 'name_num', 'id']), + has_archives: z.boolean(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + ), + + batchupdateAttributesSchema: z.object({ + create: z + .array( z.object({ - href: z.string(), + id: z.number(), + name: z.string(), + slug: z.string(), + type: z.enum(['select']), + order_by: z.enum(['menu_order', 'name', 'name_num', 'id']), + has_archives: z.boolean(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), }), - ), + ) + .optional(), + update: z + .array( + z.object({ + id: z.number(), + name: z.string(), + slug: z.string(), + type: z.enum(['select']), + order_by: z.enum(['menu_order', 'name', 'name_num', 'id']), + has_archives: z.boolean(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + ) + .optional(), + delete: z + .array( + z.object({ + id: z.number(), + name: z.string(), + slug: z.string(), + type: z.enum(['select']), + order_by: z.enum(['menu_order', 'name', 'name_num', 'id']), + has_archives: z.boolean(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + ) + .optional(), + }), + + setDefaultAttributeSchema: z.boolean(), + updateProductAttributeSchema: z.boolean(), + }, + + attributeTeermsSchema: { + attributeTermSchema: z.object({ + id: z.number(), + name: z.string(), + slug: z.string(), + description: z.string(), + menu_order: z.number(), + count: z.number(), + _links: z.object({ + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), }), }), + + attributeTermsSchema: z.array( + z.object({ + id: z.number(), + name: z.string(), + slug: z.string(), + description: z.string(), + menu_order: z.number(), + count: z.number(), + _links: z.object({ + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), + }), + }), + ), + + batchupdateAttributesSchema: z.object({ + update: z.array( + z.object({ + id: z.number(), + name: z.string(), + slug: z.string(), + description: z.string(), + menu_order: z.number(), + count: z.number(), + _links: z.object({ + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), + }), + }), + ), + }), }, - attributesSchema: {}, //TODO: - attributeTeermsSchema: {}, //TODO: couponsSchema: { - //todo: this schema might be sufficient for all couponSchema: z.object({ id: z.number(), code: z.string(), amount: z.string(), - date_created: z.string(), //todo add date format - date_created_gmt: z.string(), - date_modified: z.string(), - date_modified_gmt: z.string(), + date_created: z.coerce.date(), + date_created_gmt: z.coerce.date(), + date_modified: z.coerce.date(), + date_modified_gmt: z.coerce.date(), discount_type: z.string(), description: z.string(), date_expires: z.nullable(z.string()), date_expires_gmt: z.nullable(z.string()), usage_count: z.number(), individual_use: z.boolean(), - product_ids: z.array(z.string()), + product_ids: z.array(z.number()), excluded_product_ids: z.array(z.string()), usage_limit: z.nullable(z.number()), usage_limit_per_user: z.nullable(z.number()), @@ -309,33 +832,416 @@ export const schemas = { ), }), }), + + couponsSchema: z.array( + z.object({ + id: z.number(), + code: z.string(), + amount: z.string(), + date_created: z.coerce.date(), + date_created_gmt: z.coerce.date(), + date_modified: z.coerce.date(), + date_modified_gmt: z.coerce.date(), + discount_type: z.string(), + description: z.string(), + date_expires: z.nullable(z.string()), + date_expires_gmt: z.nullable(z.string()), + usage_count: z.number(), + individual_use: z.boolean(), + product_ids: z.array(z.number()), + excluded_product_ids: z.array(z.string()), + usage_limit: z.nullable(z.number()), + usage_limit_per_user: z.nullable(z.number()), + limit_usage_to_x_items: z.nullable(z.number()), + free_shipping: z.boolean(), + product_categories: z.array(z.string()), + excluded_product_categories: z.array(z.string()), + exclude_sale_items: z.boolean(), + minimum_amount: z.string(), + maximum_amount: z.string(), + email_restrictions: z.array(z.string()), + used_by: z.array(z.string()), + meta_data: z.array( + z.object({ + id: z.number(), + key: z.string(), + value: z.string(), + }), + ), + _links: z.object({ + self: z.array( + z.object({ + href: z.string().url(), + }), + ), + collection: z.array( + z.object({ + href: z.string().url(), + }), + ), + }), + }), + ), }, - customersSchema: {}, //TODO: - dokanEndpointsSchema: {}, //TODO: + customersSchema: { + customerSchema: z.object({ + id: z.number(), + date_created: z.string(), + date_created_gmt: z.string(), + date_modified: z.string(), + date_modified_gmt: z.string(), + email: z.string().email(), + first_name: z.string(), + last_name: z.string(), + role: z.string(), + username: z.string(), + billing: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + email: z.union([z.string().email(), z.literal('')]), + phone: z.string(), + }) + .optional(), + shipping: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + phone: z.string(), + }) + .optional(), + is_paying_customer: z.boolean(), + avatar_url: z.string().url(), + meta_data: z.array( + z.object({ + id: z.number(), + key: z.string(), + value: z.unknown(), + }), + ), + orders_count: z.number(), + total_spent: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + + customersSchema: z.array( + z.object({ + id: z.number(), + date_created: z.string(), + date_created_gmt: z.string(), + date_modified: z.string(), + date_modified_gmt: z.string(), + email: z.string().email(), + first_name: z.string(), + last_name: z.string(), + role: z.string(), + username: z.string(), + billing: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + email: z.union([z.string().email(), z.literal('')]), + phone: z.string(), + }) + .optional(), + shipping: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + phone: z.string(), + }) + .optional(), + is_paying_customer: z.boolean(), + avatar_url: z.string().url(), + meta_data: z.array( + z.object({ + id: z.number(), + key: z.string(), + value: z.unknown(), + }), + ), + orders_count: z.number(), + total_spent: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + ), + + batchupdateCustomersSchema: z.object({ + create: z + .array( + z.object({ + id: z.number(), + date_created: z.string(), + date_created_gmt: z.string(), + date_modified: z.string(), + date_modified_gmt: z.string(), + email: z.string().email(), + first_name: z.string(), + last_name: z.string(), + role: z.string(), + username: z.string(), + billing: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + email: z.union([z.string().email(), z.literal('')]), + phone: z.string(), + }) + .optional(), + shipping: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + phone: z.string(), + }) + .optional(), + is_paying_customer: z.boolean(), + avatar_url: z.string().url(), + meta_data: z.array( + z.object({ + id: z.number(), + key: z.string(), + value: z.unknown(), + }), + ), + orders_count: z.number(), + total_spent: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + ) + .optional(), + update: z + .array( + z.object({ + id: z.number(), + date_created: z.string(), + date_created_gmt: z.string(), + date_modified: z.string(), + date_modified_gmt: z.string(), + email: z.string().email(), + first_name: z.string(), + last_name: z.string(), + role: z.string(), + username: z.string(), + billing: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + email: z.union([z.string().email(), z.literal('')]), + phone: z.string(), + }) + .optional(), + shipping: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + phone: z.string(), + }) + .optional(), + is_paying_customer: z.boolean(), + avatar_url: z.string().url(), + meta_data: z.array( + z.object({ + id: z.number(), + key: z.string(), + value: z.unknown(), + }), + ), + orders_count: z.number(), + total_spent: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + ) + .optional(), + delete: z + .array( + z.object({ + id: z.number(), + date_created: z.string(), + date_created_gmt: z.string(), + date_modified: z.string(), + date_modified_gmt: z.string(), + email: z.string().email(), + first_name: z.string(), + last_name: z.string(), + role: z.string(), + username: z.string(), + billing: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + email: z.union([z.string().email(), z.literal('')]), + phone: z.string(), + }) + .optional(), + shipping: z + .object({ + first_name: z.string(), + last_name: z.string(), + company: z.string(), + address_1: z.string(), + address_2: z.string(), + city: z.string(), + postcode: z.string(), + country: z.string(), + state: z.string(), + phone: z.string(), + }) + .optional(), + is_paying_customer: z.boolean(), + avatar_url: z.string().url(), + meta_data: z.array( + z.object({ + id: z.number(), + key: z.string(), + value: z.unknown(), + }), + ), + orders_count: z.number(), + total_spent: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string().url() })), + collection: z.array(z.object({ href: z.string().url() })), + }), + }), + ) + .optional(), + }), + }, - dummyDataSchema: {}, //TODO: + dummyDataSchema: { + dummyDataStatusSchema: z.object({ + import_status: z.enum(['yes', 'no']), + }), + importdummyDataSchema: z.object({ + result: z.object({ + imported: z.array(z.number()), + failed: z.array(z.unknown()), + updated: z.array(z.unknown()), + skipped: z.array(z.unknown()), + }), + vendor_index: z.number(), + }), + cleardummyDataClearSchema: z.object({ + message: z.string(), + }), + }, - followStoresSchema: {}, //TODO: + followStoresSchema: { + followstatusSchema: z.object({ + status: z.boolean(), + }), + followUnfollowSchema: z.object({ + status: z.enum(['following', 'unfollowed']), + }), + followersSchema: z.array( + z.object({ + id: z.number(), + first_name: z.string(), + last_name: z.string(), + full_name: z.string(), + avatar_url: z.string().url(), + avatar_url_2x: z.string().url(), + followed_at: z.coerce.date(), + formatted_followed_at: z.string(), + }), + ), + }, - modulesSchema: { - //todo: this schema might be sufficient for all - modulesSchema: z.object({ + modulesSchema: z.array( + z.object({ id: z.string(), name: z.string(), description: z.string(), thumbnail: z.string().url(), - plan: z.enum(['starter', 'liquidweb', 'professional', 'business', 'enterprise']), + plan: z.array(z.string()), active: z.boolean(), available: z.boolean(), - doc_id: z.string().nullable(), + doc_id: z.union([z.string(), z.number()]).nullable(), doc_link: z.string().nullable(), mod_link: z.string().nullable(), pre_requisites: z.string().nullable(), categories: z.array(z.string()).nullable(), video_id: z.string().nullable(), }), - }, + ), + orderDownloadsSchema: {}, //TODO: orderNotesSchema: {}, //TODO: @@ -358,7 +1264,48 @@ export const schemas = { quoteRequestsSchema: {}, //TODO: - quoteRulesSchema: {}, //TODO: + quoteRulesSchema: { + quoteRuleSchema: z.object({ + id: z.string(), + rule_name: z.string(), + selected_user_role: z.array(z.string()), + category_ids: z.array(z.string()), //TODO: need to update + product_categories: z.array(z.string()), //TODO: need to update + product_ids: z.string(), + hide_price: z.string(), + hide_cart_button: z.string(), + button_text: z.string(), + apply_on_all_product: z.string(), + rule_priority: z.string(), + status: z.string(), + created_at: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), + }), + }), + quoteRulesSchema: z.array( + z.object({ + id: z.string(), + rule_name: z.string(), + selected_user_role: z.array(z.string()), + category_ids: z.array(z.string()), //TODO: need to update + product_categories: z.array(z.string()), //TODO: need to update + product_ids: z.string(), + hide_price: z.string(), + hide_cart_button: z.string(), + button_text: z.string(), + apply_on_all_product: z.string(), + rule_priority: z.string(), + status: z.string(), + created_at: z.string(), + _links: z.object({ + self: z.array(z.object({ href: z.string() })), + collection: z.array(z.object({ href: z.string() })), + }), + }), + ), + }, rankMathSchema: {}, //TODO: @@ -370,9 +1317,111 @@ export const schemas = { rolesSchema: {}, //TODO: - sellerBadgeSchema: {}, //TODO: + sellerBadgeSchema: { + verificationTypesSchema: z.object({ + id_verification: verificationTypeSchema, + company_verification: verificationTypeSchema, + address_verification: verificationTypeSchema, + phone_verification: verificationTypeSchema, + social_profiles: verificationTypeSchema, + }), + + badgeEventsSchema: z.array(badgeEventSchema), + + badgeSchema: badgeSchema, + + badgesSchema: z.array(badgeSchema), + + badgeSeenSchema: z.boolean(), + + badgeCreateUpdateSchema: badgeCreateUpdateSchema, + + deleteBadgeSchema: z.object({ + deleted: z.boolean(), + }), + + batchUpdateBadgesSchema: z.array(badgeCreateUpdateSchema), + }, + + settingsSchema: { + storeSettingsSchema: z.object({ + store_name: z.string(), + social: socialSchema, + payment: paymentSchema, + phone: z.string(), + show_email: z.string(), + address: addressSchema, + location: z.string(), + banner: z.number(), + icon: z.string(), + gravatar: z.number(), + enable_tnc: z.string(), + store_tnc: z.string(), + show_min_order_discount: z.string(), + store_seo: z.array(z.any()), // Adjust this based on the actual structure + dokan_store_time_enabled: z.string(), + dokan_store_open_notice: z.string(), + dokan_store_close_notice: z.string(), + dokan_store_time: storeTimeSchema, + sale_only_here: z.boolean(), + company_name: z.string(), + vat_number: z.string(), + company_id_number: z.string(), + bank_name: z.string(), + bank_iban: z.string(), + profile_completion: profileCompletionSchema, + find_address: z.string(), + catalog_mode: catalogModeSchema, + order_min_max: orderMinMaxSchema, + categories: z.array(categorySchema), + vendor_biography: z.string(), + show_support_btn_product: z.string(), + support_btn_name: z.string(), + show_support_btn: z.string(), + setting_go_vacation: z.string(), + settings_closing_style: z.string(), + setting_vacation_message: z.string(), + seller_vacation_schedules: z.array(z.any()), // Adjust this based on the actual structure + vendor_store_location_pickup: vendorStoreLocationPickupSchema, + bank_payment_required_fields: bankPaymentRequiredFieldsSchema, + active_payment_methods: activePaymentMethodsSchema, + }), - settingsSchema: {}, //TODO: + setStoreSchema: z.object({ + id: z.number(), + store_name: z.string(), + first_name: z.string(), + last_name: z.string(), + email: z.string().email(), + social: socialSchema, + phone: z.string(), + show_email: z.boolean(), + address: addressSchema, + location: z.string(), + banner: z.string(), + banner_id: z.number(), + gravatar: z.string(), + gravatar_id: z.number(), + shop_url: z.string().url(), + toc_enabled: z.boolean(), + store_toc: z.string(), + featured: z.boolean(), + rating: ratingSchema, + enabled: z.boolean(), + registered: z.string(), + payment: paymentSchema, + trusted: z.boolean(), + store_open_close: timeSchema, + sale_only_here: z.boolean(), + company_name: z.string(), + vat_number: z.string(), + company_id_number: z.string(), + bank_name: z.string(), + bank_iban: z.string(), + categories: z.array(categorySchema), + _links: linksSchema, + }), + }, settingsGroupSchema: {}, //TODO: @@ -404,13 +1453,39 @@ export const schemas = { }), }, - storeCategoriesSchema: {}, //TODO: + storeCategoriesSchema: { + storyCategorySchema: storyCategorySchema, + storeCategoriesSchema: z.array(storyCategorySchema), + deleteStoryCategorySchema: z.object({ + deleted: z.boolean(), + previous: storyCategorySchema.omit({ _links: true }), + }), + }, - storeReviewsSchema: {}, //TODO: + storeReviewsSchema: { + storeReviewSchema1: storeReviewSchema1, + storeReviewsSchema1: z.array(storeReviewSchema1), + storeReviewSchema: storeReviewSchema, + storeReviewsSchema: z.array(storeReviewSchema), + batchUpdateBadgesSchema: z.boolean(), + }, storesSchema: {}, //TODO: - supportTicketsSchema: {}, //TODO: + supportTicketsSchema: { + supportTicketCustomerSchema: z.array( + z.object({ + ID: z.string(), + display_name: z.string(), + }), + ), + supportTicketSchema: supportTicketSchema, + supportTicketsSchema: z.array(supportTicketSchema), + + batchUpdateSupportTicketSchema: z.object({ + closed: z.array(z.number()), + }), + }, vendorDashboardSchema: {}, //TODO: @@ -559,7 +1634,6 @@ export const schemas = { }), staffCapabilities: z.object({ - ID: z.string(), user_login: z.string(), user_nicename: z.string(), user_email: z.string(), @@ -573,48 +1647,50 @@ export const schemas = { last_name: z.string(), registered_at: z.string(), avatar: z.string(), - capabilities: z.object({ - read: z.boolean(), - vendor_staff: z.boolean(), - dokandar: z.boolean(), - delete_pages: z.boolean(), - publish_posts: z.boolean(), - edit_posts: z.boolean(), - delete_published_posts: z.boolean(), - edit_published_posts: z.boolean(), - delete_posts: z.boolean(), - manage_categories: z.boolean(), - moderate_comments: z.boolean(), - upload_files: z.boolean(), - edit_shop_orders: z.boolean(), - edit_product: z.boolean(), - dokan_view_sales_overview: z.boolean(), - dokan_view_sales_report_chart: z.boolean(), - dokan_view_announcement: z.boolean(), - dokan_view_order_report: z.boolean(), - dokan_view_review_reports: z.boolean(), - dokan_view_product_status_report: z.boolean(), - dokan_add_product: z.boolean(), - dokan_edit_product: z.boolean(), - dokan_delete_product: z.boolean(), - dokan_view_product: z.boolean(), - dokan_duplicate_product: z.boolean(), - dokan_import_product: z.boolean(), - dokan_export_product: z.boolean(), - dokan_view_order: z.boolean(), - dokan_manage_order: z.boolean(), - dokan_manage_order_note: z.boolean(), - dokan_manage_reviews: z.boolean(), - dokan_view_overview_menu: z.boolean(), - dokan_view_product_menu: z.boolean(), - dokan_view_order_menu: z.boolean(), - dokan_view_review_menu: z.boolean(), - dokan_view_store_settings_menu: z.boolean(), - dokan_view_store_shipping_menu: z.boolean(), - dokan_view_store_social_menu: z.boolean(), - dokan_view_store_seo_menu: z.boolean(), - dokan_export_order: z.boolean(), - }), + capabilities: z + .object({ + read: z.boolean(), + vendor_staff: z.boolean(), + dokandar: z.boolean(), + delete_pages: z.boolean(), + publish_posts: z.boolean(), + edit_posts: z.boolean(), + delete_published_posts: z.boolean(), + edit_published_posts: z.boolean(), + delete_posts: z.boolean(), + manage_categories: z.boolean(), + moderate_comments: z.boolean(), + upload_files: z.boolean(), + edit_shop_orders: z.boolean(), + edit_product: z.boolean(), + dokan_view_sales_overview: z.boolean(), + dokan_view_sales_report_chart: z.boolean(), + dokan_view_announcement: z.boolean(), + dokan_view_order_report: z.boolean(), + dokan_view_review_reports: z.boolean(), + dokan_view_product_status_report: z.boolean(), + dokan_add_product: z.boolean(), + dokan_edit_product: z.boolean(), + dokan_delete_product: z.boolean(), + dokan_view_product: z.boolean(), + dokan_duplicate_product: z.boolean(), + dokan_import_product: z.boolean(), + dokan_export_product: z.boolean(), + dokan_view_order: z.boolean(), + dokan_manage_order: z.boolean(), + dokan_manage_order_note: z.boolean(), + dokan_manage_reviews: z.boolean(), + dokan_view_overview_menu: z.boolean(), + dokan_view_product_menu: z.boolean(), + dokan_view_order_menu: z.boolean(), + dokan_view_review_menu: z.boolean(), + dokan_view_store_settings_menu: z.boolean(), + dokan_view_store_shipping_menu: z.boolean(), + dokan_view_store_social_menu: z.boolean(), + dokan_view_store_seo_menu: z.boolean(), + dokan_export_order: z.boolean(), + }) + .optional(), }), updateCapabilities: z.object({ diff --git a/tests/pw/utils/testData.ts b/tests/pw/utils/testData.ts index d764759b42..563c655918 100644 --- a/tests/pw/utils/testData.ts +++ b/tests/pw/utils/testData.ts @@ -29,6 +29,8 @@ export const data = { DB_PREFIX: process.env.DB_PREFIX, }, + systemInfo: 'playwright/systemInfo.json', + auth: { adminAuthFile: 'playwright/.auth/adminStorageState.json', vendorAuthFile: 'playwright/.auth/vendorStorageState.json', @@ -64,6 +66,10 @@ export const data = { plugins: ['basic-auth', 'dokan', 'dokan-pro', 'woocommerce', 'woocommerce-bookings', 'woocommerce-product-addons', 'woocommerce-simple-auctions', 'woocommerce-subscriptions'], dokanPro: ['dokan-pro'], activeClass: 'active', + pluginName: { + dokanlite: 'dokan-lite', + dokanPro: 'dokan-pro', + }, }, woocommerce: { @@ -75,7 +81,7 @@ export const data = { publishSuccessMessage: 'Product published. ', draftUpdateSuccessMessage: 'Product draft updated. ', pendingProductUpdateSuccessMessage: 'Product updated. ', - createUpdateSaveSuccessMessage: 'Success! The product has been saved successfully. View Product โ†’', + createUpdateSaveSuccessMessage: 'Success! The product has been saved successfully.', updateSuccessMessage: 'Product updated. ', status: { @@ -177,6 +183,38 @@ export const data = { status: 'publish', stockStatus: false, editProduct: '', + saveSuccessMessage: 'Success! The product has been saved successfully. View Product โ†’', + }, + + downloadable: { + productType: 'simple', + productName: () => faker.commerce.productName() + ' (Downadable)', + 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: '', + saveSuccessMessage: 'Success! The product has been saved successfully. View Product โ†’', + + downloadableOptions: { + fileName: 'avatar', + fileUrl: 'utils/sampleData/avatar.png', + downloadLimit: '200', + downloadExpiry: '361', + }, + }, + + virtual: { + productType: 'simple', + productName: () => faker.commerce.productName() + ' (Virtual)', + 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: '', + saveSuccessMessage: 'Success! The product has been saved successfully. View Product โ†’', }, variable: { @@ -353,6 +391,42 @@ export const data = { guestName: () => faker.person.firstName('male'), guestEmail: () => faker.person.firstName('male') + '@email.com', }, + + productInfo: { + description: { + shortDescription: 'test short description', + description: 'test long description', + }, + + amountDiscount: { + minimumOrderAmount: '200', + discountPercentage: '10', + }, + + quantityDiscount: { + minimumQuantity: '10', + discountPercentage: '10', + }, + + wholesaleOption: { + wholesalePrice: '90', + minimumWholesaleQuantity: '10', + }, + + minMax: { + minimumProductQuantity: '1', + maximumProductQuantity: '20', + minimumAmount: '10', + maximumAmount: '1000000', + category: 'Uncategorized', + }, + + otherOptions: { + productStatus: 'draft', // publish, + visibility: 'hidden', // visible, catalog, search, hidden + purchaseNote: 'test purchase note', + }, + }, }, // store @@ -710,6 +784,9 @@ export const data = { general: 'wp-admin/options-general.php', permalinks: 'wp-admin/options-permalink.php', plugins: 'wp-admin/plugins.php', + activatePlugin: 'wp-admin/plugins.php?action=activate', + deactivatePlugin: 'wp-admin/plugins.php?action=deactivate', + widgets: 'wp-admin/widgets.php', dokan: { setupWizard: 'wp-admin/admin.php?page=dokan-setup', @@ -820,7 +897,7 @@ export const data = { dashboard: 'dashboard', products: 'dashboard/products', productSearch: 'products/?product_listing_search', - productAuction: 'dashboard/new-auction-product', + productAuction: 'dashboard/auction', productBooking: 'dashboard/booking/new-product', orders: 'dashboard/orders', userSubscriptions: 'dashboard/user-subscription', @@ -897,7 +974,7 @@ export const data = { wc: { wcProducts: 'wc/v3/products', - store: 'wc/store' + store: 'wc/store', }, }, }, @@ -1005,24 +1082,6 @@ export const data = { }, }, - 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: { @@ -1052,6 +1111,19 @@ export const data = { subject: 'test email subject', message: 'test email message', }, + + amountDiscount: { + minimumOrderAmount: '200', + discountPercentage: '10', + }, + + minMax: { + minimumProductQuantity: '1', + maximumProductQuantity: '20', + minimumAmount: '10', + maximumAmount: '1000000', + category: 'Uncategorized', + }, }, shipping: { @@ -1618,7 +1690,6 @@ export const data = { 'live_chat', 'live_search', 'moip', - 'dokan_paypal_ap', 'paypal_marketplace', 'product_addon', 'product_enquiry', @@ -1735,6 +1806,12 @@ export const data = { withdraw: { customMethodName: 'Bksh', customMethodType: 'Phone', + charge: { + paypal: '5', + bank: '5', + skrill: '5', + custom: '5', + }, minimumWithdrawAmount: '5', withdrawThreshold: '0', quarterlyScheduleMonth: 'march', // 'january', 'february', 'march' @@ -1901,6 +1978,12 @@ export const data = { }, }, + storeContactData: { + name: String(process.env.CUSTOMER), + email: String(process.env.CUSTOMER) + '@yopmail.com', + message: 'Test Message', + }, + // dokan license dokanLicense: { correctKey: String(process.env.LICENSE_KEY), From ee9b72b250f8e344f5f0fe0e246247f807ed720a Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 08:46:52 +0600 Subject: [PATCH 02/11] fix: Product Creation support for vendor staff and Catalog Mode (#2086) * fix: Product Creation support for vendor staff * fix: Product Creation support for Catalog Mode --- includes/CatalogMode/Dashboard/Products.php | 1 + templates/products/edit-product-single.php | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/includes/CatalogMode/Dashboard/Products.php b/includes/CatalogMode/Dashboard/Products.php index d5f4afaffe..bf84cf9d0e 100644 --- a/includes/CatalogMode/Dashboard/Products.php +++ b/includes/CatalogMode/Dashboard/Products.php @@ -30,6 +30,7 @@ public function __construct() { add_action( 'dokan_product_edit_after_options', [ $this, 'render_product_section' ], 99, 1 ); // save catalog mode section data add_action( 'dokan_product_updated', [ $this, 'save_catalog_mode_data' ], 13 ); + add_action( 'dokan_new_product_added', [ $this, 'save_catalog_mode_data' ], 13 ); } /** diff --git a/templates/products/edit-product-single.php b/templates/products/edit-product-single.php index 049cd14de0..c5e0a6d065 100755 --- a/templates/products/edit-product-single.php +++ b/templates/products/edit-product-single.php @@ -50,7 +50,14 @@ $product->set_name( $post_title ); $product->set_status( $post_status ); - $post_id = $product->save(); + $post_id = $product->save(); + wp_update_post( + [ + 'ID' => $post_id, + 'post_author' => dokan_get_current_user_id(), + ] + ); + $post = get_post( $post_id ); $from_shortcode = true; $new_product = true; From 5daa04a6bbe2f018811056f0f6c549b3fadfc76c Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 08:51:11 +0600 Subject: [PATCH 03/11] fix: Order creation Support WC Block Checkout (#2101) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: Order creation Support WC Block Checkout * update: `cart_checkout_blocks` compatibility declared * ๐Ÿ“ docs(functions-rest-api.php): update method comment to improve clarity and accuracy ๐Ÿ†• feat(functions-rest-api.php): add new method `dokan_rest_validate_order_id` to verify an order id in rest api validate callback --------- Co-authored-by: Nurul Umbhiya --- dokan.php | 2 +- includes/Order/Hooks.php | 2 ++ includes/Order/Manager.php | 8 ++++++- includes/Order/functions.php | 8 ++++++- includes/functions-rest-api.php | 41 ++++++++++++++++++++++++++++++++- 5 files changed, 57 insertions(+), 4 deletions(-) diff --git a/dokan.php b/dokan.php index 2107651a56..c5b84e57db 100755 --- a/dokan.php +++ b/dokan.php @@ -291,7 +291,7 @@ private function define( $name, $value ) { public function declare_woocommerce_feature_compatibility() { if ( class_exists( \Automattic\WooCommerce\Utilities\FeaturesUtil::class ) ) { \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true ); - \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', __FILE__, false ); + \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'cart_checkout_blocks', __FILE__, true ); } } diff --git a/includes/Order/Hooks.php b/includes/Order/Hooks.php index b5a25e66dd..22597eb98a 100644 --- a/includes/Order/Hooks.php +++ b/includes/Order/Hooks.php @@ -36,9 +36,11 @@ public function __construct() { // create sub-orders add_action( 'woocommerce_checkout_update_order_meta', [ $this, 'split_vendor_orders' ] ); + add_action( 'woocommerce_store_api_checkout_update_order_meta', [ $this, 'split_vendor_orders' ] ); // order table synced for WooCommerce update order meta add_action( 'woocommerce_checkout_update_order_meta', 'dokan_sync_insert_order', 20 ); + add_action( 'woocommerce_store_api_checkout_update_order_meta', 'dokan_sync_insert_order', 20 ); // order table synced for dokan update order meta add_action( 'dokan_checkout_update_order_meta', 'dokan_sync_insert_order' ); diff --git a/includes/Order/Manager.php b/includes/Order/Manager.php index 4616ef60fb..f9997245f4 100644 --- a/includes/Order/Manager.php +++ b/includes/Order/Manager.php @@ -881,7 +881,13 @@ function ( $item ) { * @return void */ public function maybe_split_orders( $parent_order_id, $force_create = false ) { - $parent_order = $this->get( $parent_order_id ); + if ( is_a( $parent_order_id, 'WC_Order' ) ) { + $parent_order = $parent_order_id; + $parent_order_id = $parent_order->get_id(); + } else { + $parent_order = $this->get( $parent_order_id ); + } + if ( ! $parent_order ) { //dokan_log( sprintf( 'Invalid Order ID #%d found. Skipping from here.', $parent_order_id ) ); return; diff --git a/includes/Order/functions.php b/includes/Order/functions.php index f3dbbed329..6ddde73040 100644 --- a/includes/Order/functions.php +++ b/includes/Order/functions.php @@ -215,7 +215,13 @@ function dokan_delete_sync_duplicate_order( $order_id, $seller_id ) { function dokan_sync_insert_order( $order_id ) { global $wpdb; - $order = wc_get_order( $order_id ); + if ( is_a( $order_id, 'WC_Order' ) ) { + $order = $order_id; + $order_id = $order->get_id(); + } else { + $order = wc_get_order( $order_id ); + } + if ( ! $order || $order instanceof WC_Subscription ) { return; } diff --git a/includes/functions-rest-api.php b/includes/functions-rest-api.php index ea846b4c45..8e8a93e159 100644 --- a/includes/functions-rest-api.php +++ b/includes/functions-rest-api.php @@ -1,7 +1,7 @@ 400 ] ); } } + +if ( ! function_exists( 'dokan_rest_validate_order_id' ) ) { + /** + * This method will verify an order id, will be used only with rest api validate callback + * + * @since DOKAN_SINCE + * + * @param $value + * @param $request WP_REST_Request + * @param $key + * + * @return bool|WP_Error + */ + function dokan_rest_validate_order_id( $value, $request, $key ) { + $attributes = $request->get_attributes(); + + if ( isset( $attributes['args'][ $key ] ) ) { + $argument = $attributes['args'][ $key ]; + // Check to make sure our argument is an int. + if ( 'integer' === $argument['type'] && ! is_numeric( $value ) ) { + // translators: 1) argument name, 2) argument value + return new WP_Error( 'rest_invalid_param', sprintf( esc_html__( '%1$s is not of type %2$s', 'dokan-lite' ), $key, 'integer' ), [ 'status' => 400 ] ); + } + } else { + // this code won't execute because we have specified this argument as required. + // if we reused this validation callback and did not have required args then this would fire. + // translators: 1) argument name + return new WP_Error( 'rest_invalid_param', sprintf( esc_html__( '%s was not registered as a request argument.', 'dokan-lite' ), $key ), [ 'status' => 400 ] ); + } + + $order = wc_get_order( (int) $value ); + if ( $order ) { + return true; + } + + // translators: 1) rest api endpoint key name + return new WP_Error( 'rest_invalid_param', sprintf( esc_html__( 'No store found with given store id', 'dokan-lite' ), $key ), [ 'status' => 400 ] ); + } +} From e4fa6857a30415e932bcaaa10790a61f23b77462 Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 08:52:25 +0600 Subject: [PATCH 04/11] fix: Issue in displaying vendor map address on store listing page after setup wizard configuration (#2126) --- includes/Vendor/SetupWizard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/Vendor/SetupWizard.php b/includes/Vendor/SetupWizard.php index ef168e82ce..c3dbe32703 100644 --- a/includes/Vendor/SetupWizard.php +++ b/includes/Vendor/SetupWizard.php @@ -402,7 +402,7 @@ public function dokan_setup_store_save() { } update_user_meta( $this->store_id, 'dokan_profile_settings', $dokan_settings ); - + do_action( 'dokan_store_profile_saved', $this->store_id, $dokan_settings ); do_action( 'dokan_seller_wizard_store_field_save', $this ); wp_safe_redirect( esc_url_raw( $this->get_next_step_link() ) ); From adc15877e5de623502f988b073b32e50dcc05b76 Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 08:54:58 +0600 Subject: [PATCH 05/11] fix: Several functionalities on the Vendor Dashboard, such as live product updates for pending orders, are not functioning correctly (#2128) --- includes/Dashboard/Templates/Dashboard.php | 83 ++++++++++++++++++++-- includes/functions.php | 18 +++++ templates/dashboard/orders-widget.php | 20 ++++-- templates/dashboard/products-widget.php | 14 ++-- 4 files changed, 120 insertions(+), 15 deletions(-) diff --git a/includes/Dashboard/Templates/Dashboard.php b/includes/Dashboard/Templates/Dashboard.php index 4e303b30a8..11861d956a 100644 --- a/includes/Dashboard/Templates/Dashboard.php +++ b/includes/Dashboard/Templates/Dashboard.php @@ -122,11 +122,62 @@ public function get_orders_widgets() { ], ]; + $nonce = wp_create_nonce( 'seller-order-filter-nonce' ); + $order_url = dokan_get_navigation_url( 'orders' ); + $completed_url = add_query_arg( + [ + 'order_status' => 'wc-completed', + 'seller_order_filter_nonce' => $nonce, + ], + $order_url + ); + $pending_url = add_query_arg( + [ + 'order_status' => 'wc-pending', + 'seller_order_filter_nonce' => $nonce, + ], + $order_url + ); + $processing_url = add_query_arg( + [ + 'order_status' => 'wc-processing', + 'seller_order_filter_nonce' => $nonce, + ], + $order_url + ); + $cancelled_url = add_query_arg( + [ + 'order_status' => 'wc-cancelled', + 'seller_order_filter_nonce' => $nonce, + ], + $order_url + ); + $refunded_url = add_query_arg( + [ + 'order_status' => 'wc-refunded', + 'seller_order_filter_nonce' => $nonce, + ], + $order_url + ); + $on_hold_url = add_query_arg( + [ + 'order_status' => 'wc-on-hold', + 'seller_order_filter_nonce' => $nonce, + ], + $order_url + ); + dokan_get_template_part( 'dashboard/orders-widget', '', [ - 'order_data' => $order_data, - 'orders_count' => $this->orders_count, - 'orders_url' => dokan_get_navigation_url( 'orders' ), + 'order_data' => $order_data, + 'orders_count' => $this->orders_count, + 'orders_url' => $order_url, + 'completed_url' => $completed_url, + 'pending_url' => $pending_url, + 'processing_url' => $processing_url, + 'cancelled_url' => $cancelled_url, + 'refunded_url' => $refunded_url, + 'on_hold_url' => $on_hold_url, ] ); } @@ -142,11 +193,33 @@ public function get_products_widgets() { if ( ! current_user_can( 'dokan_view_product_status_report' ) ) { return; } - + $nonce = wp_create_nonce( 'product_listing_filter' ); + $product_url = dokan_get_navigation_url( 'products' ); + $online_url = add_query_arg( + [ + 'post_status' => 'publish', + '_product_listing_filter_nonce' => $nonce, + ], $product_url + ); + $draft_url = add_query_arg( + [ + 'post_status' => 'draft', + '_product_listing_filter_nonce' => $nonce, + ], $product_url + ); + $pending_url = add_query_arg( + [ + 'post_status' => 'pending', + '_product_listing_filter_nonce' => $nonce, + ], $product_url + ); dokan_get_template_part( 'dashboard/products-widget', '', [ 'post_counts' => $this->get_post_counts(), - 'products_url' => dokan_get_navigation_url( 'products' ), + 'products_url' => $product_url, + 'online_url' => $online_url, + 'draft_url' => $draft_url, + 'pending_url' => $pending_url, ] ); } diff --git a/includes/functions.php b/includes/functions.php index d39da0a525..39df1c285f 100755 --- a/includes/functions.php +++ b/includes/functions.php @@ -4352,3 +4352,21 @@ function dokan_user_update_to_seller( $user, $data ) { do_action( 'dokan_new_seller_created', $user_id, $vendor->get_shop_info() ); } } + +/** + * Get new product creation URL. + * + * @since DOKAN_SINCE + * + * @return false|string + */ +function dokan_get_new_product_url() { + $one_step_product_create = 'on' === dokan_get_option( 'one_step_product_create', 'dokan_selling', 'on' ); + + return $one_step_product_create ? dokan_edit_product_url( 0, true ) : add_query_arg( + [ + '_dokan_add_product_nonce' => wp_create_nonce( 'dokan_add_product_nonce' ), + ], + dokan_get_navigation_url( 'new-product' ) + ); +} diff --git a/templates/dashboard/orders-widget.php b/templates/dashboard/orders-widget.php index f1f38a8ca5..6d70768506 100644 --- a/templates/dashboard/orders-widget.php +++ b/templates/dashboard/orders-widget.php @@ -6,6 +6,14 @@ * * @since 2.4 * + * @var string $orders_url Order Url. + * @var string $completed_url Completed Order Url. + * @var string $pending_url Pending Order Url. + * @var string $processing_url Processing Order Url. + * @var string $cancelled_url Cancelled Order Url. + * @var string $refunded_url Refunded Order Url. + * @var string $on_hold_url On Hold Order Url. + * * @package dokan */ ?> @@ -21,32 +29,32 @@
  • - + {'wc-completed'}, 0 ) ); ?>
  • - + {'wc-pending'}, 0 ) ); ?>
  • - + {'wc-processing'}, 0 ) ); ?>
  • - + {'wc-cancelled'}, 0 ) ); ?>
  • - + {'wc-refunded'}, 0 ) ); ?>
  • - + {'wc-on-hold'}, 0 ) ); ?>
  • diff --git a/templates/dashboard/products-widget.php b/templates/dashboard/products-widget.php index fd67ca19f4..7321bd1cb2 100644 --- a/templates/dashboard/products-widget.php +++ b/templates/dashboard/products-widget.php @@ -7,6 +7,12 @@ * * @since 2.4 * + * @var object $post_counts All product status count. + * @var string $products_url All product listing url. + * @var string $online_url Online product listing url. + * @var string $draft_url Draft product listing url. + * @var string $pending_url Pending product listing url. + * * @package dokan */ ?> @@ -16,7 +22,7 @@ - + @@ -27,17 +33,17 @@
  • - + publish ); ?>
  • - + draft ); ?>
  • - + pending ); ?>
  • From f784b525983455d02b5da71ab7754b3a10c5f09a Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 09:13:19 +0600 Subject: [PATCH 06/11] fix: The indication of whether the store is available or not is absent on the vendor migration form (#2129) --- includes/Frontend/MyAccount/BecomeAVendor.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/includes/Frontend/MyAccount/BecomeAVendor.php b/includes/Frontend/MyAccount/BecomeAVendor.php index f29e6bccf0..60506c5a15 100644 --- a/includes/Frontend/MyAccount/BecomeAVendor.php +++ b/includes/Frontend/MyAccount/BecomeAVendor.php @@ -176,6 +176,8 @@ public function load_customer_to_vendor_update_template() { return; } + wp_enqueue_script( 'dokan-vendor-registration' ); + $data = [ 'user_id' => $user_id, 'first_name' => get_user_meta( $user_id, 'first_name', true ), From 24339b943ec1dc6c414dfd84574973dc7330353e Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 09:15:05 +0600 Subject: [PATCH 07/11] fix: When a customer buys digital and physical products from different vendors, shipping charges are applied separately to each vendor (#2130) --- includes/Shipping/Hooks.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/includes/Shipping/Hooks.php b/includes/Shipping/Hooks.php index 923fbe2ba5..22b29436e7 100644 --- a/includes/Shipping/Hooks.php +++ b/includes/Shipping/Hooks.php @@ -43,6 +43,9 @@ public function split_shipping_packages( $packages ) { $packages = []; foreach ( $cart_content as $key => $item ) { + if ( $item['data']->is_virtual() ) { + continue; + } $post_author = get_post_field( 'post_author', $item['data']->get_id() ); $seller_pack[ $post_author ][ $key ] = $item; From 3c6bb3ff1503b7cc4564599e8d3df21df5312735 Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 09:16:41 +0600 Subject: [PATCH 08/11] fix: Translation-Related Issues with Specific Menu Items in Vendor Dashboard (#2137) --- includes/template-tags.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/template-tags.php b/includes/template-tags.php index ad81fec13a..4b8b595032 100755 --- a/includes/template-tags.php +++ b/includes/template-tags.php @@ -580,7 +580,7 @@ function dokan_dashboard_nav( $active_menu = '' ) { * * @param string $menu_key */ - $filtered_key = apply_filters( 'dokan_dashboard_nav_menu_key', $key ); + $filtered_key = rawurlencode_deep( apply_filters( 'dokan_dashboard_nav_menu_key', $key ) ); $class = $active_menu === $filtered_key || 0 === stripos( $active_menu, $filtered_key ) ? 'active ' . $key : $key; // checking starts with the key $title = isset( $item['title'] ) ? $item['title'] : __( 'No title', 'dokan-lite' ); @@ -602,7 +602,7 @@ function dokan_dashboard_nav( $active_menu = '' ) { * @param string $submenu_key * @param string $menu_key */ - $filtered_subkey = apply_filters( 'dokan_dashboard_nav_submenu_key', $sub_key, $key ); + $filtered_subkey = rawurlencode_deep( apply_filters( 'dokan_dashboard_nav_submenu_key', $sub_key, $key ) ); $submenu_class = $active_submenu === $filtered_subkey || 0 === stripos( $active_submenu, $filtered_subkey ) ? "current $sub_key" : $sub_key; From 294befa456d0d9dfbd8ce0dc9e9ea1beaf0e4537 Mon Sep 17 00:00:00 2001 From: Shazahanul Islam Shohag Date: Tue, 23 Jan 2024 09:42:11 +0600 Subject: [PATCH 09/11] fix: Translation-Related Issues with daterange picker and SweetAlert (#2139) * fix: Translation-Related Issues with dateramge picker * fix: Translation-Related Issues with Dokan Sweetallert --- assets/src/js/dokan-daterangepicker.js | 2 +- assets/src/js/helper.js | 1 + includes/Assets.php | 7 +++++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/assets/src/js/dokan-daterangepicker.js b/assets/src/js/dokan-daterangepicker.js index fdc8b22e93..4529055058 100644 --- a/assets/src/js/dokan-daterangepicker.js +++ b/assets/src/js/dokan-daterangepicker.js @@ -4,7 +4,7 @@ // Set date range data. let localeData = { format : dokan_get_daterange_picker_format(), - ...dokan_helper.locale + ...dokan_helper.daterange_picker_local }; // Date range picker handler. diff --git a/assets/src/js/helper.js b/assets/src/js/helper.js index 7a128025dd..d0d2c5ea41 100644 --- a/assets/src/js/helper.js +++ b/assets/src/js/helper.js @@ -262,6 +262,7 @@ showCancelButton : true, confirmButtonColor:'#28a745', cancelButtonColor :'#dc3545', + ...dokan_helper.sweetalert_local }; const args = { ...defaults, ...options }; diff --git a/includes/Assets.php b/includes/Assets.php index f6842b1690..e91c9793b6 100644 --- a/includes/Assets.php +++ b/includes/Assets.php @@ -757,6 +757,13 @@ public function load_dokan_global_scripts() { __( 'December', 'dokan-lite' ), ], ], + 'sweetalert_local' => [ + 'cancelButtonText' => __( 'Cancel', 'dokan-lite' ), + 'closeButtonText' => __( 'Close', 'dokan-lite' ), + 'confirmButtonText' => __( 'OK', 'dokan-lite' ), + 'denyButtonText' => __( 'No', 'dokan-lite' ), + 'closeButtonAriaLabel' => __( 'Close this dialog', 'dokan-lite' ), + ], ] ); From 5407efb4313d08be4c57a8bfc7f627836c26e2f9 Mon Sep 17 00:00:00 2001 From: Nurul Umbhiya Date: Tue, 23 Jan 2024 12:21:20 +0600 Subject: [PATCH 10/11] =?UTF-8?q?=F0=9F=93=A6=20chore(composer.json):=20up?= =?UTF-8?q?date=20appsero/client=20dependency=20to=20version=20v2.0.1=20fo?= =?UTF-8?q?r=20compatibility=20and=20bug=20fixes=20=F0=9F=93=A6=20chore(pa?= =?UTF-8?q?ckage.json):=20add=20release:dev=20script=20to=20run=20necessar?= =?UTF-8?q?y=20tasks=20for=20development=20release?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- composer.json | 2 +- composer.lock | 46 +++++++++++++++++++++++----------------------- package.json | 3 ++- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/composer.json b/composer.json index bbfb2f81ee..167c269d29 100644 --- a/composer.json +++ b/composer.json @@ -12,7 +12,7 @@ "minimum-stability": "dev", "require": { "php": ">=7.4", - "appsero/client": "^v1.4.0", + "appsero/client": "^v2.0.1", "jakeasmith/http_build_url": "^1" }, "require-dev": { diff --git a/composer.lock b/composer.lock index acade28223..64fa042447 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c2a9df22d67a08d96f9896580e526200", + "content-hash": "b7c36dca126f9ba3110cb4dc269fedad", "packages": [ { "name": "appsero/client", - "version": "v1.4.0", + "version": "v2.0.1", "source": { "type": "git", "url": "https://github.com/Appsero/client.git", - "reference": "43289d79f1d55de687f667b17a2834b986cc7b6e" + "reference": "b87e7593c6295748e88cdbfc92a638c8a73462ce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/Appsero/client/zipball/43289d79f1d55de687f667b17a2834b986cc7b6e", - "reference": "43289d79f1d55de687f667b17a2834b986cc7b6e", + "url": "https://api.github.com/repos/Appsero/client/zipball/b87e7593c6295748e88cdbfc92a638c8a73462ce", + "reference": "b87e7593c6295748e88cdbfc92a638c8a73462ce", "shasum": "" }, "require": { @@ -56,9 +56,9 @@ ], "support": { "issues": "https://github.com/Appsero/client/issues", - "source": "https://github.com/Appsero/client/tree/v1.4.0" + "source": "https://github.com/Appsero/client/tree/v2.0.1" }, - "time": "2024-01-08T11:38:14+00:00" + "time": "2024-01-16T11:20:48+00:00" }, { "name": "jakeasmith/http_build_url", @@ -311,12 +311,12 @@ "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "ff095c3c65c144f32a811685a81195c4df53fb99" + "reference": "ce019e9ad711e31ee87c2c4c72e538b5240970c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ff095c3c65c144f32a811685a81195c4df53fb99", - "reference": "ff095c3c65c144f32a811685a81195c4df53fb99", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ce019e9ad711e31ee87c2c4c72e538b5240970c3", + "reference": "ce019e9ad711e31ee87c2c4c72e538b5240970c3", "shasum": "" }, "require": { @@ -362,7 +362,7 @@ "issues": "https://github.com/nikic/PHP-Parser/issues", "source": "https://github.com/nikic/PHP-Parser/tree/master" }, - "time": "2024-01-10T19:34:09+00:00" + "time": "2024-01-14T09:02:54+00:00" }, { "name": "phar-io/manifest", @@ -744,12 +744,12 @@ "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHPCSUtils.git", - "reference": "da4c4da18b430eacdc6a6016009475951f9b1434" + "reference": "26dcb893d86fbe90ab2a8abd7b08a3fda3602237" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/da4c4da18b430eacdc6a6016009475951f9b1434", - "reference": "da4c4da18b430eacdc6a6016009475951f9b1434", + "url": "https://api.github.com/repos/PHPCSStandards/PHPCSUtils/zipball/26dcb893d86fbe90ab2a8abd7b08a3fda3602237", + "reference": "26dcb893d86fbe90ab2a8abd7b08a3fda3602237", "shasum": "" }, "require": { @@ -825,7 +825,7 @@ "type": "open_collective" } ], - "time": "2024-01-02T16:59:15+00:00" + "time": "2024-01-15T05:03:54+00:00" }, { "name": "phpunit/php-code-coverage", @@ -1152,12 +1152,12 @@ "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "241c4aa189ef1f3b7608de2da5510a59f1d22a01" + "reference": "4c1997c21fb0e29198b7b83be49d460df2571d79" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/241c4aa189ef1f3b7608de2da5510a59f1d22a01", - "reference": "241c4aa189ef1f3b7608de2da5510a59f1d22a01", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4c1997c21fb0e29198b7b83be49d460df2571d79", + "reference": "4c1997c21fb0e29198b7b83be49d460df2571d79", "shasum": "" }, "require": { @@ -1247,7 +1247,7 @@ "type": "tidelift" } ], - "time": "2024-01-07T09:57:50+00:00" + "time": "2024-01-21T09:34:47+00:00" }, { "name": "sebastian/cli-parser", @@ -2219,12 +2219,12 @@ "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "364cc7269d54dc4c862d1a41318764c86e43710d" + "reference": "e0e03f05662f5035923abebc90f85abaf5efdb3f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/364cc7269d54dc4c862d1a41318764c86e43710d", - "reference": "364cc7269d54dc4c862d1a41318764c86e43710d", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/e0e03f05662f5035923abebc90f85abaf5efdb3f", + "reference": "e0e03f05662f5035923abebc90f85abaf5efdb3f", "shasum": "" }, "require": { @@ -2292,7 +2292,7 @@ "type": "open_collective" } ], - "time": "2024-01-10T13:52:25+00:00" + "time": "2024-01-22T23:39:52+00:00" }, { "name": "tareq1988/wp-php-cs-fixer", diff --git a/package.json b/package.json index 907a2fd800..c3602e30c7 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ "format": "wp-scripts format", "lint:css": "wp-scripts lint-style", "lint:js": "wp-scripts lint-js", - "release": "npm run readme && npm run build && npm run clean-files && npm run makepot && npm run version && npm run zip" + "release": "npm run install && npm run readme && npm run build && npm run clean-files && npm run makepot && npm run version && npm run zip", + "release:dev": "npm run install && npm run build && npm run clean-files && npm run makepot && npm run zip" }, "devDependencies": { "@wordpress/scripts": "^26.18.0", From 8cf0566aa9b36bdaf20ddf9cb6af5bfa3118e0b1 Mon Sep 17 00:00:00 2001 From: Nurul Umbhiya Date: Tue, 23 Jan 2024 12:22:33 +0600 Subject: [PATCH 11/11] =?UTF-8?q?=F0=9F=94=A7=20chore(package.json):=20fix?= =?UTF-8?q?=20typo=20in=20release=20and=20release:dev=20scripts=20to=20cor?= =?UTF-8?q?rectly=20run=20npm=20install=20before=20other=20commands?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c3602e30c7..1caaff6a0f 100644 --- a/package.json +++ b/package.json @@ -18,8 +18,8 @@ "format": "wp-scripts format", "lint:css": "wp-scripts lint-style", "lint:js": "wp-scripts lint-js", - "release": "npm run install && npm run readme && npm run build && npm run clean-files && npm run makepot && npm run version && npm run zip", - "release:dev": "npm run install && npm run build && npm run clean-files && npm run makepot && npm run zip" + "release": "npm install && npm run readme && npm run build && npm run clean-files && npm run makepot && npm run version && npm run zip", + "release:dev": "npm install && npm run build && npm run clean-files && npm run makepot && npm run zip" }, "devDependencies": { "@wordpress/scripts": "^26.18.0",