diff --git a/.github/workflows/build-release-zip-file.yml b/.github/workflows/build-release-zip-file.yml
index 94ae898d2a6..c6189b41c80 100644
--- a/.github/workflows/build-release-zip-file.yml
+++ b/.github/workflows/build-release-zip-file.yml
@@ -31,7 +31,7 @@ jobs:
run: unzip plugins/woocommerce/woocommerce.zip -d zipfile
- name: Upload the zip file as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
diff --git a/.github/workflows/nightly-builds.yml b/.github/workflows/nightly-builds.yml
index 6a3e22fa123..71ce84bf288 100644
--- a/.github/workflows/nightly-builds.yml
+++ b/.github/workflows/nightly-builds.yml
@@ -4,23 +4,25 @@ on:
- cron: '0 0 * * *' # Run at 12 AM UTC.
workflow_dispatch:
-permissions: {}
+env:
+ SOURCE_REF: trunk
+ TARGET_REF: nightly
+ RELEASE_ID: 25945111
+
+permissions: { }
jobs:
build:
if: github.repository_owner == 'woocommerce'
name: Nightly builds
- strategy:
- fail-fast: false
- matrix:
- build: [trunk]
+
runs-on: ubuntu-20.04
permissions:
contents: write
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
- ref: ${{ matrix.build }}
+ ref: ${{ env.SOURCE_REF }}
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
@@ -31,26 +33,31 @@ jobs:
working-directory: plugins/woocommerce
run: bash bin/build-zip.sh
- - name: Deploy nightly build
- uses: WebFreak001/deploy-nightly@v1.1.0
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ - name: Upload nightly build
+ uses: WebFreak001/deploy-nightly@46ecbabd7fad70d3e7d2c97fe8cd54e7a52e215b #v3.2.0
with:
- upload_url: https://uploads.github.com/repos/${{ github.repository }}/releases/25945111/assets{?name,label}
- release_id: 25945111
+ token: ${{ secrets.GITHUB_TOKEN }}
+ upload_url: https://uploads.github.com/repos/${{ github.repository }}/releases/${{ env.RELEASE_ID }}/assets{?name,label}
+ release_id: ${{ env.RELEASE_ID }}
asset_path: plugins/woocommerce/woocommerce.zip
- asset_name: woocommerce-${{ matrix.build }}-nightly.zip
+ asset_name: woocommerce-${{ env.SOURCE_REF }}-nightly.zip
asset_content_type: application/zip
max_releases: 1
- update:
- name: Update nightly tag commit ref
- runs-on: ubuntu-20.04
- permissions:
- contents: write
- steps:
- - name: Update nightly tag
- uses: richardsimko/github-tag-action@v1.0.5
+
+ - name: Update nightly tag commit ref
+ uses: actions/github-script@v7
with:
- tag_name: nightly
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ github-token: ${{ secrets.GITHUB_TOKEN }}
+ script: |
+ const sourceRef = process.env.SOURCE_REF;
+ const targetRef = process.env.TARGET_REF;
+ const branchData = await github.rest.repos.getBranch({
+ ...context.repo,
+ branch: sourceRef,
+ });
+
+ await github.rest.git.updateRef({
+ ...context.repo,
+ ref: `tags/${ targetRef }`,
+ sha: branchData.data.commit.sha,
+ });
diff --git a/.github/workflows/pr-assess-performance.yml b/.github/workflows/pr-assess-performance.yml
new file mode 100644
index 00000000000..b22c1719cd2
--- /dev/null
+++ b/.github/workflows/pr-assess-performance.yml
@@ -0,0 +1,102 @@
+name: Performance metrics
+
+on:
+ pull_request:
+ paths:
+ - 'plugins/woocommerce/composer.*'
+ - 'plugins/woocommerce/client/admin/config/**'
+ - 'plugins/woocommerce/includes/**'
+ - 'plugins/woocommerce/lib/**'
+ - 'plugins/woocommerce/patterns/**'
+ - 'plugins/woocommerce/src/**'
+ - 'plugins/woocommerce/templates/**'
+ - 'plugins/woocommerce/tests/metrics/**'
+ - 'plugins/woocommerce/.wp-env.json'
+ - '.github/workflows/pr-assess-performance.yml'
+
+concurrency:
+ group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
+ cancel-in-progress: true
+
+env:
+ WP_ARTIFACTS_PATH: ${{ github.workspace }}/tools/compare-perf/artifacts/
+
+jobs:
+ benchmark:
+ name: Evaluate performance metrics
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ name: Checkout (${{ github.event_name == 'pull_request' && github.head_ref || github.sha }})
+ with:
+ fetch-depth: 0
+
+ - uses: ./.github/actions/setup-woocommerce-monorepo
+ name: Install Monorepo
+ with:
+ install: '@woocommerce/plugin-woocommerce...'
+ build: '@woocommerce/plugin-woocommerce'
+ build-type: 'full'
+ pull-playwright-cache: true
+ pull-package-deps: '@woocommerce/plugin-woocommerce'
+
+ #TODO: Inject WordPress version as per plugin requirements (relying to defaults currently).
+ - name: Start Test Environment
+ run: |
+ pnpm --filter="@woocommerce/plugin-woocommerce" test:e2e:install &
+ pnpm --filter="@woocommerce/plugin-woocommerce" env:test
+
+ # TODO: cache results if pushed to trunk
+ - name: Measure performance (@${{ github.sha }})
+ run: |
+ RESULTS_ID="editor_${{ github.sha }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics editor
+ RESULTS_ID="product-editor_${{ github.sha }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics product-editor
+
+ # In alignment with .github/workflows/scripts/run-metrics.sh, we should checkout 3d7d7f02017383937f1a4158d433d0e5d44b3dc9
+ # as baseline. But to avoid switching branches in 'Analyze results' step, we pick 55f855a2e6d769b5ae44305b2772eb30d3e721df
+ # which introduced reporting mode for the perf utility.
+ - name: Checkout (55f855a2e6d769b5ae44305b2772eb30d3e721df@trunk, further references as 'baseline')
+ run: |
+ git reset --hard && git checkout 55f855a2e6d769b5ae44305b2772eb30d3e721df
+ echo "WC_TRUNK_SHA=55f855a2e6d769b5ae44305b2772eb30d3e721df" >> $GITHUB_ENV
+
+ # Artifacts download/upload would be more reliable, but we couldn't make it working...
+ - uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319
+ name: Cache measurements (baseline)
+ with:
+ path: tools/compare-perf/artifacts/*_${{ env.WC_TRUNK_SHA }}_*
+ key: ${{ runner.os }}-woocommerce-performance-measures-${{ env.WC_TRUNK_SHA }}
+
+ - name: Verify cached measurements (baseline)
+ run: |
+ if test -n "$(find tools/compare-perf/artifacts/ -maxdepth 1 -name '*_${{ env.WC_TRUNK_SHA }}_*' -print -quit)"
+ then
+ echo "WC_MEASURE_BASELINE=no" >> $GITHUB_ENV
+ else
+ ls -l tools/compare-perf/artifacts/
+ echo "Triggering baseline benchmarking"
+ echo "WC_MEASURE_BASELINE=yes" >> $GITHUB_ENV
+ fi
+
+ - name: Build (baseline)
+ if: ${{ env.WC_MEASURE_BASELINE == 'yes' }}
+ run: |
+ git clean -n -d -X ./packages ./plugins | grep -v vendor | grep -v node_modules | sed -e 's/Would remove //g' | tr '\n' '\0' | xargs -0 rm -r
+ pnpm install --filter='@woocommerce/plugin-woocommerce...' --frozen-lockfile --config.dedupe-peer-dependents=false
+ pnpm --filter='@woocommerce/plugin-woocommerce' build
+
+ #TODO: is baseline Wordpress version changes, restart environment targeting it.
+
+ - name: Measure performance (@${{ env.WC_TRUNK_SHA }})
+ if: ${{ env.WC_MEASURE_BASELINE == 'yes' }}
+ run: |
+ RESULTS_ID="editor_${{ env.WC_TRUNK_SHA }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics editor
+ RESULTS_ID="product-editor_${{ env.WC_TRUNK_SHA }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics product-editor
+
+ - name: Analyze results
+ run: |
+ pnpm install --filter='compare-perf...' --frozen-lockfile --config.dedupe-peer-dependents=false
+ pnpm --filter="compare-perf" run compare compare-performance ${{ github.sha }} ${{ env.WC_TRUNK_SHA }} --tests-branch ${{ github.sha }} --skip-benchmarking
+
+ # TODO: Publish to CodeVitals (see .github/workflows/scripts/run-metrics.sh) if pushed to trunk
diff --git a/.github/workflows/release-code-freeze.yml b/.github/workflows/release-code-freeze.yml
index 633000a1801..68a6304ee93 100644
--- a/.github/workflows/release-code-freeze.yml
+++ b/.github/workflows/release-code-freeze.yml
@@ -186,7 +186,7 @@ jobs:
run: bash bin/build-zip.sh
- name: Upload the zip file as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -216,7 +216,7 @@ jobs:
run: bash bin/build-zip.sh
- name: Upload the zip file as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -231,7 +231,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayMonthlyFreeze == 'yes' }}
steps:
- id: download
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -279,7 +279,7 @@ jobs:
working-directory: tools/monorepo-utils
- id: download
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -300,7 +300,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayAcceleratedFreeze == 'yes' }}
steps:
- id: download
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -348,7 +348,7 @@ jobs:
working-directory: tools/monorepo-utils
- id: download
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -369,7 +369,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayMonthlyFreeze == 'yes' }}
steps:
- id: download
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -380,7 +380,7 @@ jobs:
run: unzip ${{ steps.download.outputs.download-path }}/woocommerce.zip -d zipfile
- name: Upload the zip file as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -395,7 +395,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayAcceleratedFreeze == 'yes' }}
steps:
- id: download
- uses: actions/download-artifact@v3
+ uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@@ -406,7 +406,7 @@ jobs:
run: unzip ${{ steps.download.outputs.download-path }}/woocommerce.zip -d zipfile
- name: Upload the zip file as an artifact
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
diff --git a/.github/workflows/storybook-pages.yml b/.github/workflows/storybook-pages.yml
index 0e84b6df80f..1aea3190d65 100644
--- a/.github/workflows/storybook-pages.yml
+++ b/.github/workflows/storybook-pages.yml
@@ -1,6 +1,8 @@
name: Storybook GitHub Pages
on:
+ schedule:
+ - cron: '30 2 * * *'
workflow_dispatch:
permissions:
diff --git a/.husky/post-checkout b/.husky/post-checkout
new file mode 100755
index 00000000000..1485ab1707b
--- /dev/null
+++ b/.husky/post-checkout
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+. "$(dirname "$0")/_/husky.sh"
+
+# The hook documentation: https://git-scm.com/docs/githooks.html#_post_checkout
+CHECKOUT_TYPE=$3
+HEAD_NEW=$2
+HEAD_PREVIOUS=$1
+
+whiteColoured='\033[0m'
+orangeColoured='\033[1;33m'
+
+# '1' is a branch checkout
+if [ "$CHECKOUT_TYPE" = '1' ]; then
+ # Prompt about pnpm versions mismatch when switching between branches.
+ currentPnpmVersion=$( ( command -v pnpm > /dev/null && pnpm -v 2>/dev/null ) || echo 'n/a' )
+ targetPnpmVersion=$( grep packageManager package.json | sed -nr 's/.+packageManager.+pnpm@([[:digit:].]+).+/\1/p' )
+ if [ "$currentPnpmVersion" != "$targetPnpmVersion" ]; then
+ printf "${orangeColoured}pnpm versions mismatch: in use '$currentPnpmVersion', needed '$targetPnpmVersion'. If you are working on something in this branch, here are some hints on how to solve this:\n"
+ printf "${orangeColoured}* actualize environment: 'nvm use && pnpm -v' (the most common case)\n"
+ printf "${orangeColoured}* install: 'npm install -g pnpm@$targetPnpmVersion'\n"
+ fi
+
+ # Auto-refresh dependencies when switching between branches.
+ changedManifests=$( ( git diff --name-only $HEAD_NEW $HEAD_PREVIOUS | grep -E '(package.json|pnpm-lock.yaml|pnpm-workspace.yaml|composer.json|composer.lock)$' ) || echo '' )
+ if [ -n "$changedManifests" ]; then
+ printf "${whiteColoured}The following file(s) in the new branch differs from the original one, dependencies might need to be refreshed:\n"
+ printf "${whiteColoured} %s\n" $changedManifests
+ printf "${orangeColoured}If you are working on something in this branch, ensure to refresh dependencies with 'pnpm install --frozen-lockfile'\n"
+ fi
+fi
diff --git a/.husky/post-merge b/.husky/post-merge
index 7ff64bebced..bc022e8fede 100755
--- a/.husky/post-merge
+++ b/.husky/post-merge
@@ -1,6 +1,8 @@
#!/usr/bin/env bash
. "$(dirname "$0")/_/husky.sh"
+# The hook documentation: https://git-scm.com/docs/githooks.html#_post_merge
+
changedManifests=$( ( git diff --name-only HEAD ORIG_HEAD | grep -E '(package.json|pnpm-lock.yaml|pnpm-workspace.yaml|composer.json|composer.lock)$' ) || echo '' )
if [ -n "$changedManifests" ]; then
printf "It was a change in the following file(s) - refreshing dependencies:\n"
diff --git a/.markdownlint.json b/.markdownlint.json
index 5e29a079a84..4a2dd1c3ec4 100644
--- a/.markdownlint.json
+++ b/.markdownlint.json
@@ -3,8 +3,8 @@
"MD003": { "style": "atx" },
"MD007": { "indent": 4 },
"MD013": { "line_length": 9999 },
- "MD024": { "allow_different_nesting": true },
- "MD033": { "allowed_elements": ["video"] },
+ "MD024": { "siblings_only": true },
+ "MD033": { "allowed_elements": [ "video" ] },
"no-hard-tabs": false,
"whitespace": false
}
diff --git a/.npmrc b/.npmrc
index 9d43c15d3cc..a140ea6b576 100644
--- a/.npmrc
+++ b/.npmrc
@@ -1,3 +1,5 @@
; adding this as npm 7 automatically installs peer dependencies but pnpm does not
auto-install-peers=true
strict-peer-dependencies=false
+; See https://github.com/pnpm/pnpm/pull/8363 (we adding the setting now, to not miss when migrating to pnpm 9.7+)
+manage-package-manager-versions=true
diff --git a/CODEOWNERS b/CODEOWNERS
index 614fa2f46be..532335b71de 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1 +1,14 @@
-/.github/ @woocommerce/atlas
+# Monorepo CI and package managers manifests.
+/.github/ @woocommerce/flux
+**/composer.json @woocommerce/flux
+**/package.json @woocommerce/flux
+
+# Monorepo tooling folders.
+/bin/ @woocommerce/flux
+/tools/ @woocommerce/flux
+/packages/js/eslint-plugin/ @woocommerce/flux
+/packages/js/dependency-extraction-webpack-plugin/ @woocommerce/flux
+
+# Files in root of repository
+/.* @woocommerce/flux
+/*.* @woocommerce/flux
diff --git a/README.md b/README.md
index a0dc78caa81..4ff249daa69 100644
--- a/README.md
+++ b/README.md
@@ -20,8 +20,8 @@ To get up and running within the WooCommerce Monorepo, you will need to make sur
Once you've installed all of the prerequisites, you can run the following commands to get everything working.
```bash
-# Ensure that you're using the correct version of Node
-nvm use
+# Ensure that correct version of Node is installed and being used
+nvm install
# Install the PHP and Composer dependencies for all of the plugins, packages, and tools
pnpm install
# Build all of the plugins, packages, and tools in the monorepo
diff --git a/changelog.txt b/changelog.txt
index e34b03260d4..2ba165e2bdc 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,5 +1,245 @@
== Changelog ==
+= 9.3.1 2024-09-12 =
+
+* Tweak - Disable remote logging feature by default [#51312](https://github.com/woocommerce/woocommerce/pull/51312)
+
+= 9.3.0 2024-09-10 =
+
+**WooCommerce**
+
+* Enhancement - Add query params masking to remote logger [#51108](https://github.com/woocommerce/woocommerce/pull/51108)
+* Update - Added more paths to remote logger query param whitelist [#51108](https://github.com/woocommerce/woocommerce/pull/51108)
+* Fix - Revert update to React 18 in Checkout block. [#51289](https://github.com/woocommerce/woocommerce/pull/51289)
+* Fix - Add check to ensure themes API is safe [#51081](https://github.com/woocommerce/woocommerce/pull/51081)
+* Fix - CYS - Remove usage of `prepare_item_for_response` function in `Images` endpoint. [#50923](https://github.com/woocommerce/woocommerce/pull/50923)
+* Fix - Add ability for a screen reader to announce the current tab on a single product page. [#50373](https://github.com/woocommerce/woocommerce/pull/50373)
+* Fix - Add a label to the product pagination for the woocommerce pagination [#49924](https://github.com/woocommerce/woocommerce/pull/49924)
+* Fix - Add aria-current to the current link in My Account side nav [#49800](https://github.com/woocommerce/woocommerce/pull/49800)
+* Fix - Add aria-label on View order button to aid in accessibility for screen readers [#49424](https://github.com/woocommerce/woocommerce/pull/49424)
+* Fix - Add CSS outline for site visibility badge keyboard accessibility [#50794](https://github.com/woocommerce/woocommerce/pull/50794)
+* Fix - Add scope attribute and aria-label to the product attributes table [#49768](https://github.com/woocommerce/woocommerce/pull/49768)
+* Fix - Add to Cart with Options - Fix translation when used inside the Single Product block. [#50628](https://github.com/woocommerce/woocommerce/pull/50628)
+* Fix - Allow verified parameter to be set by REST API request [#50525](https://github.com/woocommerce/woocommerce/pull/50525)
+* Fix - Avoid PHP warnings if `add-to-cart.php` template does not pass `aria-describedby_text` [#48969](https://github.com/woocommerce/woocommerce/pull/48969)
+* Fix - Cart block: Strip HTML tags and decode HTML entities in quantity change notifications. [#50541](https://github.com/woocommerce/woocommerce/pull/50541)
+* Fix - Changed from using React.render to React.createRoot for marketing coupons as it has been deprecated since React 18 [#48832](https://github.com/woocommerce/woocommerce/pull/48832)
+* Fix - Changed from using React.render to React.createRoot for payment methods promotion, shipping settings region zone as it has been deprecated since React 18 [#48835](https://github.com/woocommerce/woocommerce/pull/48835)
+* Fix - Changed from using React.render to React.createRoot for print shipping banner as it has been deprecated since React 18 [#48831](https://github.com/woocommerce/woocommerce/pull/48831)
+* Fix - Changed from using React.render to React.createRoot for product-usage-notice-modal as it has been deprecated since React 18 [#50765](https://github.com/woocommerce/woocommerce/pull/50765)
+* Fix - Changed from using React.render to React.createRoot for wc addon tour as it has been deprecated since React 18 [#48833](https://github.com/woocommerce/woocommerce/pull/48833)
+* Fix - Changed from using React.render to React.createRoot for WCAdmin uses as it has been deprecated since React 18 [#48785](https://github.com/woocommerce/woocommerce/pull/48785)
+* Fix - Changed instances of prime marks inappropriately used when apostrophes are supposed to be used for some parts of WC Admin JS/TS/TSX files [#50776](https://github.com/woocommerce/woocommerce/pull/50776)
+* Fix - Clear product unique ID (`global_unique_id`) when duplicating products. [#50629](https://github.com/woocommerce/woocommerce/pull/50629)
+* Fix - Compatibility Layer: fix 'woocommerce_before_single_product_summary' hook position. [#50392](https://github.com/woocommerce/woocommerce/pull/50392)
+* Fix - CYS - Improve the error when a request fails due to permissions [#50211](https://github.com/woocommerce/woocommerce/pull/50211)
+* Fix - CYS - Update the "show_on_front" setting to "posts" to avoid overriding the "page" template. [#50083](https://github.com/woocommerce/woocommerce/pull/50083)
+* Fix - CYS: disable zoom out on fonts/color pairs iframe [#50498](https://github.com/woocommerce/woocommerce/pull/50498)
+* Fix - CYS: Fix auto scroll when a new block is added. [#50431](https://github.com/woocommerce/woocommerce/pull/50431)
+* Fix - CYS: Improve opt in flow [#50529](https://github.com/woocommerce/woocommerce/pull/50529)
+* Fix - Display address card for virtual products if shopper's address is known [#50127](https://github.com/woocommerce/woocommerce/pull/50127)
+* Fix - Enable skipped E2E tests for attributes #50143 [#50143](https://github.com/woocommerce/woocommerce/pull/50143)
+* Fix - Ensure coupon errors are visible on block checkout when invalid coupons are removed. [#50412](https://github.com/woocommerce/woocommerce/pull/50412)
+* Fix - Ensure low and no stock email notification routine is triggered whenever product stock changes [#49583](https://github.com/woocommerce/woocommerce/pull/49583)
+* Fix - Ensure session object is initialized before attempting to get chosen shipping methods [#50774](https://github.com/woocommerce/woocommerce/pull/50774)
+* Fix - Ensure that the orders REST endpoint behaves the same as the UI when updating an order to remove a line item. [#50606](https://github.com/woocommerce/woocommerce/pull/50606)
+* Fix - Featured Product: Fix variable product Selection dropdown #50633 [#50633](https://github.com/woocommerce/woocommerce/pull/50633)
+* Fix - Fix "Product Meta" translations - Register the block server side. [#50625](https://github.com/woocommerce/woocommerce/pull/50625)
+* Fix - Fix: ensure the global product object is always ready for compatibility layer by disabling default render routine of Product Templates inner blocks. [#49971](https://github.com/woocommerce/woocommerce/pull/49971)
+* Fix - Fix activating the installed subscription when the user has multiple active licenses for the same product. [#49803](https://github.com/woocommerce/woocommerce/pull/49803)
+* Fix - Fix address heading level on My Account page. [#49764](https://github.com/woocommerce/woocommerce/pull/49764)
+* Fix - Fix an admin bar CSS positioning bug in WordPress.com on mobile [#50709](https://github.com/woocommerce/woocommerce/pull/50709)
+* Fix - Fix cart shortcode updates when not used on the main cart page. [#50524](https://github.com/woocommerce/woocommerce/pull/50524)
+* Fix - Fix core profiler checkbox vertical alignment and border color [#50151](https://github.com/woocommerce/woocommerce/pull/50151)
+* Fix - Fix core profiler set up my store button and TOS are too close to each other [#50579](https://github.com/woocommerce/woocommerce/pull/50579)
+* Fix - Fix e2e Google for WooCommerce strict mode violation error [#50189](https://github.com/woocommerce/woocommerce/pull/50189)
+* Fix - Fixed Core Profiler's sticky footer button problem [#50727](https://github.com/woocommerce/woocommerce/pull/50727)
+* Fix - Fixed placeholders in the classic cart shipping calculator to update with country selection. [#49684](https://github.com/woocommerce/woocommerce/pull/49684)
+* Fix - Fixes a bug where some express payment buttons weren't being rendered correctly [#49304](https://github.com/woocommerce/woocommerce/pull/49304)
+* Fix - Fix extensionCartUpdates to surface generic error messages, and include documentation for the error handling. [#49762](https://github.com/woocommerce/woocommerce/pull/49762)
+* Fix - Fix focus order on checkout block page. [#49649](https://github.com/woocommerce/woocommerce/pull/49649)
+* Fix - Fix navigation badge decreases when installing extension in "Grow your business task" [#50584](https://github.com/woocommerce/woocommerce/pull/50584)
+* Fix - Fix page titles of the cart and checkout page when using blocks and FSE themes. [#49986](https://github.com/woocommerce/woocommerce/pull/49986)
+* Fix - Fix rescheduling of actions that are blocked by other delayed actions [#50082](https://github.com/woocommerce/woocommerce/pull/50082)
+* Fix - Fix the "Add payment methods" link in LYS congrat screen redirects to a blank page [#50609](https://github.com/woocommerce/woocommerce/pull/50609)
+* Fix - Fix translation - Avoid registering blocks in the wrong context. [#50615](https://github.com/woocommerce/woocommerce/pull/50615)
+* Fix - Fix `Product meta` console error. [#50680](https://github.com/woocommerce/woocommerce/pull/50680)
+* Fix - Fix `store-title` endpoint - Pass default value to `get_option`. [#50673](https://github.com/woocommerce/woocommerce/pull/50673)
+* Fix - Hide save changes button in main payments screen [#50064](https://github.com/woocommerce/woocommerce/pull/50064)
+* Fix - In Remote Specs, treat empty arrays as valid cached values so individual engines can return default values. [#50521](https://github.com/woocommerce/woocommerce/pull/50521)
+* Fix - Keep focus on shipping option input once selected [#49360](https://github.com/woocommerce/woocommerce/pull/49360)
+* Fix - Make the matching variations alert a live region [#50132](https://github.com/woocommerce/woocommerce/pull/50132)
+* Fix - Only count published products in productCount [#50503](https://github.com/woocommerce/woocommerce/pull/50503)
+* Fix - Prevent fatal error if NULL is provided in array_search under Jetpack Stats [#50696](https://github.com/woocommerce/woocommerce/pull/50696)
+* Fix - Prevent Store API orders being placed with empty state [#50028](https://github.com/woocommerce/woocommerce/pull/50028)
+* Fix - Prevent sync-on-read from affecting results of HPOS diff CLI tool. [#49726](https://github.com/woocommerce/woocommerce/pull/49726)
+* Fix - Product Collection: Fix max price query to include prices less or equal to the given max value. [#49917](https://github.com/woocommerce/woocommerce/pull/49917)
+* Fix - Product Collection: fix the preview if used in Products by specific Category or Tag [#49889](https://github.com/woocommerce/woocommerce/pull/49889)
+* Fix - Product Price block: prevent price amounts from breaking into multiple lines [#50660](https://github.com/woocommerce/woocommerce/pull/50660)
+* Fix - Properly detect active plugins in multisite WP installations. [#50417](https://github.com/woocommerce/woocommerce/pull/50417)
+* Fix - Reduce error noise in the user profile screen, by removing the requirement for custom fields to have a class attribute. [#48079](https://github.com/woocommerce/woocommerce/pull/48079)
+* Fix - Remove Active Shipping Zones check for displaying shipping calculator on the Cart Page. [#49214](https://github.com/woocommerce/woocommerce/pull/49214)
+* Fix - Single product block - Fix translation for title and description in edit mode. [#50599](https://github.com/woocommerce/woocommerce/pull/50599)
+* Fix - Store API: Do not resume pending orders--create a new order instead [#50531](https://github.com/woocommerce/woocommerce/pull/50531)
+* Fix - Transform labels in shipping zone region selector to decode html entities [#50694](https://github.com/woocommerce/woocommerce/pull/50694)
+* Fix - Treat post_type=product as a shop page. [#50567](https://github.com/woocommerce/woocommerce/pull/50567)
+* Fix - Update product order status colors to ensure accessible color contrasts [#49934](https://github.com/woocommerce/woocommerce/pull/49934)
+* Add - Add an additional field for the email settings that sets the footer text color [#49648](https://github.com/woocommerce/woocommerce/pull/49648)
+* Add - Add blueprint behind a feature flag for testing purposes. [#49763](https://github.com/woocommerce/woocommerce/pull/49763)
+* Add - Add field for the email footer text color [#49648](https://github.com/woocommerce/woocommerce/pull/49648)
+* Add - Add function to clear system status theme info cache [#50803](https://github.com/woocommerce/woocommerce/pull/50803)
+* Add - Add methods required by extensions to control product feature usage based on subscription status. [#50218](https://github.com/woocommerce/woocommerce/pull/50218)
+* Add - Add parameter to avoid attempting to create the logs directory if it doesn't exist [#49766](https://github.com/woocommerce/woocommerce/pull/49766)
+* Add - Add Pattern button to no blocks view on the CYS assembler [#49981](https://github.com/woocommerce/woocommerce/pull/49981)
+* Add - Add reactified main payments screen [#49972](https://github.com/woocommerce/woocommerce/pull/49972)
+* Add - Add reactify-classic-payments-settings feature flag [#49966](https://github.com/woocommerce/woocommerce/pull/49966)
+* Add - Add tracks for WordPress Importer/Export pages. [#50769](https://github.com/woocommerce/woocommerce/pull/50769)
+* Add - Add `FilteredGetDataTrait`, `OrderAwareControllerTrait`, and `StatsDataStoreTrait` for extension developers to reuse while creating custom Analytics [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
+* Add - Implement server-side remote error logging [#49599](https://github.com/woocommerce/woocommerce/pull/49599)
+* Add - Inform screen reader users when mini cart updates [#48295](https://github.com/woocommerce/woocommerce/pull/48295)
+* Add - Integrate JS remote logging package in WooCommerce Admin [#50134](https://github.com/woocommerce/woocommerce/pull/50134)
+* Add - Product Collection: emit the JS event when PC block is rendered [#50166](https://github.com/woocommerce/woocommerce/pull/50166)
+* Add - Product Collection: Enable Context-Aware Previews by Adding `usesReference` to `registerProductCollection` [#49796](https://github.com/woocommerce/woocommerce/pull/49796)
+* Add - Track frequency of unhandled JS errors with MC Stats [#50155](https://github.com/woocommerce/woocommerce/pull/50155)
+* Add - Use MC Stats for PHP fatal error counting [#49658](https://github.com/woocommerce/woocommerce/pull/49658)
+* Add - [E2E tests]: Add product description using the block editor #50232 [#50232](https://github.com/woocommerce/woocommerce/pull/50232)
+* Update - Update WooCommerce Shipping Promo Banner to install the latest version of WooCommerce Shipping instead of WCS&T. [#50970](https://github.com/woocommerce/woocommerce/pull/50970)
+* Update - Add abbreviations for fields GTIN, UPC, EAN, OR ISBN [#50042](https://github.com/woocommerce/woocommerce/pull/50042)
+* Update - Add additional fields to new product editor e2e tests. [#50241](https://github.com/woocommerce/woocommerce/pull/50241)
+* Update - Add confirmation prompt for site visibility settings when changing from live to coming soon mode [#50759](https://github.com/woocommerce/woocommerce/pull/50759)
+* Update - Add pattern validation for global_unique_id [#50501](https://github.com/woocommerce/woocommerce/pull/50501)
+* Update - Add remote logger as a log handler to wc logger [#50430](https://github.com/woocommerce/woocommerce/pull/50430)
+* Update - Add request_uri prop to remote logging data [#50671](https://github.com/woocommerce/woocommerce/pull/50671)
+* Update - Add woocommerce_coming_soon option for all sites [#50581](https://github.com/woocommerce/woocommerce/pull/50581)
+* Update - Comment: Fix typos in documentation. [#50282](https://github.com/woocommerce/woocommerce/pull/50282)
+* Update - CYS - Add tests for the Full Composability feature. [#49748](https://github.com/woocommerce/woocommerce/pull/49748)
+* Update - CYS - Run appropriate tests depending on the WordPress version. [#50016](https://github.com/woocommerce/woocommerce/pull/50016)
+* Update - CYS - Update icon and text colors in the assembler. [#50478](https://github.com/woocommerce/woocommerce/pull/50478)
+* Update - CYS: Improve opt-in flow fonts. [#50086](https://github.com/woocommerce/woocommerce/pull/50086)
+* Update - CYS: Improve opt-in flow patterns. [#50080](https://github.com/woocommerce/woocommerce/pull/50080)
+* Update - CYS: Improve tracking survey [#50196](https://github.com/woocommerce/woocommerce/pull/50196)
+* Update - CYS: Improve tracking survey [#50354](https://github.com/woocommerce/woocommerce/pull/50354)
+* Update - CYS: Update the tracking URL to the external Fiverr link in sidebar of the **Add your logo** screen. [#50753](https://github.com/woocommerce/woocommerce/pull/50753)
+* Update - Enable remote logging feature flag [#50351](https://github.com/woocommerce/woocommerce/pull/50351)
+* Update - feat: add `aria-required` attributes to WC form fields [#48371](https://github.com/woocommerce/woocommerce/pull/48371)
+* Update - Fixed log-out link behavior so that redirects work, and so that security nonces are automatically added to link in navigation menus. [#49605](https://github.com/woocommerce/woocommerce/pull/49605)
+* Update - Migrate LYS user meta [#50664](https://github.com/woocommerce/woocommerce/pull/50664)
+* Update - Move marketing task to things to do next task list [#50487](https://github.com/woocommerce/woocommerce/pull/50487)
+* Update - Move site visibility badge to admin bar. [#50775](https://github.com/woocommerce/woocommerce/pull/50775)
+* Update - Remove "Need help?" modal from onboarding [#47812](https://github.com/woocommerce/woocommerce/pull/47812)
+* Update - Remove all links from the CYS sidebars [#50414](https://github.com/woocommerce/woocommerce/pull/50414)
+* Update - Remove remote API call from marketing task [#50479](https://github.com/woocommerce/woocommerce/pull/50479)
+* Update - Remove WooCommerce Navigation client side feature and deprecate PHP classes. [#50190](https://github.com/woocommerce/woocommerce/pull/50190)
+* Update - Renamed columns inside In-App Marketplace > My subscriptions and added action to turn auto-renewal on for a subscription [#49985](https://github.com/woocommerce/woocommerce/pull/49985)
+* Update - Rename woocommerce_is_store_page to woocommerce_is_extension_store_page [#50771](https://github.com/woocommerce/woocommerce/pull/50771)
+* Update - Reverting the new `buttonAttributes` API. This will be included in a later release [#50763](https://github.com/woocommerce/woocommerce/pull/50763)
+* Update - Revert the Zoom Out feature for the CYS experience [#50535](https://github.com/woocommerce/woocommerce/pull/50535)
+* Update - Show expiring and expired notices to active and unconnected subscriptions [#50383](https://github.com/woocommerce/woocommerce/pull/50383)
+* Update - Store API: Remove the need for nonces when using cart tokens. Remove deprecated X-WC-Store-API-Nonce header. [#50025](https://github.com/woocommerce/woocommerce/pull/50025)
+* Update - Strip HTML tags from aria-label in wc_help_tip function [#50103](https://github.com/woocommerce/woocommerce/pull/50103)
+* Update - Text adjustments on shipping zones settings page [#50136](https://github.com/woocommerce/woocommerce/pull/50136)
+* Update - Update AdditionalPayments task to use default payment gateways [#50674](https://github.com/woocommerce/woocommerce/pull/50674)
+* Update - Update add product task button section UI [#50580](https://github.com/woocommerce/woocommerce/pull/50580)
+* Update - Update all blocks to use API Version 3. [#48720](https://github.com/woocommerce/woocommerce/pull/48720)
+* Update - Update Blueprint settings layout. [#50724](https://github.com/woocommerce/woocommerce/pull/50724)
+* Update - Update core profiler continue button container on extension screen [#50582](https://github.com/woocommerce/woocommerce/pull/50582)
+* Update - Update Store Alert actions to have unique keys. [#50424](https://github.com/woocommerce/woocommerce/pull/50424)
+* Update - Update WooCommercePayments task is_supported to use default suggestions [#50585](https://github.com/woocommerce/woocommerce/pull/50585)
+* Update - Enhance CSV path and upload handling in product import [#51344](https://github.com/woocommerce/woocommerce/pull/51344)
+* Dev - Execute test env setup on host instead of wp-env container [#51021](https://github.com/woocommerce/woocommerce/pull/51021)
+* Dev - Added code docs with examples to the Analytics classes [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
+* Dev - Add lost password e2e tests [#50611](https://github.com/woocommerce/woocommerce/pull/50611)
+* Dev - Add unit tests for the product_add_publish track. [#49916](https://github.com/woocommerce/woocommerce/pull/49916)
+* Dev - CI: introduce PHPUnit tests sharding. [#50084](https://github.com/woocommerce/woocommerce/pull/50084)
+* Dev - CI: minor speed boost of wp-env startup. [#50445](https://github.com/woocommerce/woocommerce/pull/50445)
+* Dev - CI: speedup assets size verification job execution time. [#50178](https://github.com/woocommerce/woocommerce/pull/50178)
+* Dev - CI: Use a single shard when re-running failed tests in CI [#50492](https://github.com/woocommerce/woocommerce/pull/50492)
+* Dev - CI config: update changes list to include more paths [#50399](https://github.com/woocommerce/woocommerce/pull/50399)
+* Dev - Clean up unused images [#50516](https://github.com/woocommerce/woocommerce/pull/50516)
+* Dev - CYS - Document possible Intro pages [#50171](https://github.com/woocommerce/woocommerce/pull/50171)
+* Dev - CYS - Move the "ai/patterns" endpoint to woocommerce admin API. [#50372](https://github.com/woocommerce/woocommerce/pull/50372)
+* Dev - CYS - Move the "ai/store-info" endpoint to woocommerce admin API [#50363](https://github.com/woocommerce/woocommerce/pull/50363)
+* Dev - CYS - Move the ai/business-description endpoint to woocommerce admin API [#50359](https://github.com/woocommerce/woocommerce/pull/50359)
+* Dev - CYS - Move the ai/store-title endpoint to woocommerce admin API [#50352](https://github.com/woocommerce/woocommerce/pull/50352)
+* Dev - CYS - Move the `ai/images` endpoint to woocommerce admin API [#50365](https://github.com/woocommerce/woocommerce/pull/50365)
+* Dev - CYS - Move the `ai/product` endpoint to woocommerce admin API. [#50393](https://github.com/woocommerce/woocommerce/pull/50393)
+* Dev - CYS: add E2E tests for fonts installation. [#50210](https://github.com/woocommerce/woocommerce/pull/50210)
+* Dev - E2E tests: add a flaky test reporter for Core e2e tests [#50259](https://github.com/woocommerce/woocommerce/pull/50259)
+* Dev - E2E tests: add an option to skip the env setup script running before test execution [#50620](https://github.com/woocommerce/woocommerce/pull/50620)
+* Dev - E2E tests: add buildkite-test-collector for blocks e2e tests [#50642](https://github.com/woocommerce/woocommerce/pull/50642)
+* Dev - E2E tests: add environment reporter [#49988](https://github.com/woocommerce/woocommerce/pull/49988)
+* Dev - E2E tests: add hpos-disabled env and tagged tests with hpos tag [#50448](https://github.com/woocommerce/woocommerce/pull/50448)
+* Dev - E2E tests: fixed broken logo picker tests [#50473](https://github.com/woocommerce/woocommerce/pull/50473)
+* Dev - E2E tests: fix flakiness in page-loads customer page test [#50559](https://github.com/woocommerce/woocommerce/pull/50559)
+* Dev - E2E tests: fix flakiness in product attributes test [#50485](https://github.com/woocommerce/woocommerce/pull/50485)
+* Dev - E2E tests: removed Github reporter [#50256](https://github.com/woocommerce/woocommerce/pull/50256)
+* Dev - E2E tests: Removed unnecessary pause in the test [#50043](https://github.com/woocommerce/woocommerce/pull/50043)
+* Dev - E2E tests for verifying approve, spam and reply to product reviews. [#50060](https://github.com/woocommerce/woocommerce/pull/50060)
+* Dev - Fix E2E tests SKU field id #49729 [#49729](https://github.com/woocommerce/woocommerce/pull/49729)
+* Dev - Fixes a flaky product variations e2e test [#50807](https://github.com/woocommerce/woocommerce/pull/50807)
+* Dev - Fix Metrics CI job [#50214](https://github.com/woocommerce/woocommerce/pull/50214)
+* Dev - Fix optional param in PHPdoc for `WC_Admin_Marketplace_Promotions` to generate code-reference w/o warnings [#50732](https://github.com/woocommerce/woocommerce/pull/50732)
+* Dev - Fix the Metrics job by adding a missing NVM install step [#50482](https://github.com/woocommerce/woocommerce/pull/50482)
+* Dev - Make the Metrics tests use utilities provided by the updated @wordpress/e2e-test-utils-playwright package. [#50626](https://github.com/woocommerce/woocommerce/pull/50626)
+* Dev - Mark ReportTable tableData prop as not required [#50816](https://github.com/woocommerce/woocommerce/pull/50816)
+* Dev - Monorepo: enable new linting rules for PHP (PSR-4 naming, Strict types declaration). [#49438](https://github.com/woocommerce/woocommerce/pull/49438)
+* Dev - Monorepo: tweak Webpack loaders paths filtering for better build perfromance. [#49714](https://github.com/woocommerce/woocommerce/pull/49714)
+* Dev - move block theme docs to docs site folder [#50638](https://github.com/woocommerce/woocommerce/pull/50638)
+* Dev - move part of checkout docs to main docs folder [#49984](https://github.com/woocommerce/woocommerce/pull/49984)
+* Dev - Move `ReportError` to `@woocommerce/components` as `AnalyticsError` [#50108](https://github.com/woocommerce/woocommerce/pull/50108)
+* Dev - moving product collection docs to main docs folder [#50368](https://github.com/woocommerce/woocommerce/pull/50368)
+* Dev - Reduce duplicated code in Analytics controllers, unify their behavior and API. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
+* Dev - Reduce the amount of duplicated code in Analytics `DataStore`s. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
+* Dev - Removed defaultProps from React functional components since they will be deprecated for React 19 [#50266](https://github.com/woocommerce/woocommerce/pull/50266)
+* Dev - Removed directive to disable woocommerce_coming_soon in e2e tests so that we get better test coverage [#50344](https://github.com/woocommerce/woocommerce/pull/50344)
+* Dev - Render a React placeholder for offline and WooCommerce Payments settings sections [#50008](https://github.com/woocommerce/woocommerce/pull/50008)
+* Dev - Replace `Automattic\WooCommerce\Admin\API\Reports\*\Query` classes with a single `GenericQuery` class. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
+* Dev - Switch `render()` to `createRoot().render()` to use React 18 features. [#48843](https://github.com/woocommerce/woocommerce/pull/48843)
+* Dev - Tests: moved api core tests as a suite in e2e-pw [#50024](https://github.com/woocommerce/woocommerce/pull/50024)
+* Dev - Tweak the lost password e2e logic [#50666](https://github.com/woocommerce/woocommerce/pull/50666)
+* Dev - Update @wordpress/e2e-test-utils-playwright core dependency to wp-6.6 [#50274](https://github.com/woocommerce/woocommerce/pull/50274)
+* Dev - Updated e2e tests docs to clarify the use of environments [#50530](https://github.com/woocommerce/woocommerce/pull/50530)
+* Dev - Updated the workflow prompting for testing instructions to only run once (preventing double comments) [#50034](https://github.com/woocommerce/woocommerce/pull/50034)
+* Dev - Update E2E tests for linked list and variation creation with new component changes. [#50128](https://github.com/woocommerce/woocommerce/pull/50128)
+* Dev - Update lys e2e tests to test with both classic and block themes [#50657](https://github.com/woocommerce/woocommerce/pull/50657)
+* Dev - Update Playwright to 1.46.1 from 1.45.1 [#50772](https://github.com/woocommerce/woocommerce/pull/50772)
+* Dev - Update WP version to 6.6 in Blocks wp-env config. [#49704](https://github.com/woocommerce/woocommerce/pull/49704)
+* Dev - Use stricter text selector on test [#50848](https://github.com/woocommerce/woocommerce/pull/50848)
+* Dev - [Filter Products by Price]: Update view when changing the min/max value #50651 [#50651](https://github.com/woocommerce/woocommerce/pull/50651)
+* Tweak - Disable remote logging feature by default [#51312](https://github.com/woocommerce/woocommerce/pull/51312)
+* Tweak - Add GTIN in structured data [#50087](https://github.com/woocommerce/woocommerce/pull/50087)
+* Tweak - Add link to title, remove link from a description, minor copy changes to site visibility settings page [#50781](https://github.com/woocommerce/woocommerce/pull/50781)
+* Tweak - Add the `woocommerce_should_clear_cart_after_payment` filter to influence whether the cart should be cleared after payment. [#44515](https://github.com/woocommerce/woocommerce/pull/44515)
+* Tweak - allows the quantity selector on block cart page to render as readonly when editable is false [#49450](https://github.com/woocommerce/woocommerce/pull/49450)
+* Tweak - Bump Jetpack COnnection, Jetpack Constants and a8c MC Stats [#50471](https://github.com/woocommerce/woocommerce/pull/50471)
+* Tweak - Extract the checkbox list option logic into its own component [#50566](https://github.com/woocommerce/woocommerce/pull/50566)
+* Tweak - Make `geolocation_ajax_get_location_hash` case-insensitive, to reduce the number of cache misses. [#45439](https://github.com/woocommerce/woocommerce/pull/45439)
+* Tweak - Optimize large image files [#50517](https://github.com/woocommerce/woocommerce/pull/50517)
+* Tweak - Product Collection: fix the PHP deprecated warning [#50661](https://github.com/woocommerce/woocommerce/pull/50661)
+* Tweak - Reduce core profiler sticky footer height [#50788](https://github.com/woocommerce/woocommerce/pull/50788)
+* Tweak - Remove colon from product data meta box checkboxes [#50619](https://github.com/woocommerce/woocommerce/pull/50619)
+* Tweak - Remove the code related to the automatic Products (Beta) -> Product Collection upgrade. [#50440](https://github.com/woocommerce/woocommerce/pull/50440)
+* Tweak - Set timeout to 2 seconds for helper product-usage-notice-rules endpoint request [#50821](https://github.com/woocommerce/woocommerce/pull/50821)
+* Tweak - Update size of site visibility badge. [#50792](https://github.com/woocommerce/woocommerce/pull/50792)
+* Tweak - Vertically center product meta elements [#50826](https://github.com/woocommerce/woocommerce/pull/50826)
+* Performance - Cache order dates in options for performance. [#50066](https://github.com/woocommerce/woocommerce/pull/50066)
+* Performance - Compress pattern placeholder image assets [#50405](https://github.com/woocommerce/woocommerce/pull/50405)
+* Performance - Improve performance of maybe_assign_default_product_cat by only dropping cache and term recounting if changes were made in the database [#50006](https://github.com/woocommerce/woocommerce/pull/50006)
+* Performance - Improve setup_tasks_remaining performance [#50655](https://github.com/woocommerce/woocommerce/pull/50655)
+* Enhancement - Add a filter to override the SKU database lock. [#49755](https://github.com/woocommerce/woocommerce/pull/49755)
+* Enhancement - Add email type to Checkout block email field. [#48611](https://github.com/woocommerce/woocommerce/pull/48611)
+* Enhancement - Add filter `woocommerce_is_store_page` to modify whether Coming Soon mode considers a URL a store page or not. [#50174](https://github.com/woocommerce/woocommerce/pull/50174)
+* Enhancement - Add username in email reset-password link [#49737](https://github.com/woocommerce/woocommerce/pull/49737)
+* Enhancement - CYS: improve CTA [#50278](https://github.com/woocommerce/woocommerce/pull/50278)
+* Enhancement - Ensure `wccomHelper` data is only loaded on the Extensions page where it's needed. [#49758](https://github.com/woocommerce/woocommerce/pull/49758)
+* Enhancement - Fixed minor issues in the developer documentation recently added by public resources team [#50845](https://github.com/woocommerce/woocommerce/pull/50845)
+* Enhancement - Hide zoomed product images for screen readers. [#50003](https://github.com/woocommerce/woocommerce/pull/50003)
+* Enhancement - Improve hover style on product tabs when using the Minimal style in the Product Details block [#50605](https://github.com/woocommerce/woocommerce/pull/50605)
+* Enhancement - Make screen readers announce notice messages once page loads. [#50061](https://github.com/woocommerce/woocommerce/pull/50061)
+* Enhancement - Refactor: Migrate the All Products block to API version 3 [#50203](https://github.com/woocommerce/woocommerce/pull/50203)
+* Enhancement - Remove opacity from the hover style of the mini cart button [#50240](https://github.com/woocommerce/woocommerce/pull/50240)
+* Enhancement - Use standard link color in legal disclaimers on core profiler [#50830](https://github.com/woocommerce/woocommerce/pull/50830)
+
= 9.2.3 2024-08-26 =
**WooCommerce**
diff --git a/docs/cart-and-checkout-blocks/additional-checkout-fields.md b/docs/cart-and-checkout-blocks/additional-checkout-fields.md
index 29981df9bdc..89af92968c2 100644
--- a/docs/cart-and-checkout-blocks/additional-checkout-fields.md
+++ b/docs/cart-and-checkout-blocks/additional-checkout-fields.md
@@ -339,11 +339,11 @@ This results in the following address form (the billing form will be the same):
The rendered markup looks like this:
```html
-
+ data-custom="custom data" value="" >
```
### Rendering a checkbox field
diff --git a/docs/cart-and-checkout-blocks/available-filters/README.md b/docs/cart-and-checkout-blocks/available-filters/README.md
index 6185107f41b..80eeab35f71 100644
--- a/docs/cart-and-checkout-blocks/available-filters/README.md
+++ b/docs/cart-and-checkout-blocks/available-filters/README.md
@@ -81,7 +81,7 @@ const modifyCartItemClass = ( defaultValue, extensions, args ) => {
const modifyCartItemPrice = ( defaultValue, extensions, args ) => {
if ( isOrderSummaryContext( args ) ) {
- return '
'. esc_html__( 'Phone From Checkout Form' ) . ': ' . esc_html( $order->get_meta( '_shipping_phone', true ) ) . '
'; + echo '<p><strong>'. esc_html__( 'Phone From Checkout Form' ) . ':</strong> ' . esc_html( $order->get_meta( '_shipping_phone', true ) ) . '</p>'; } ``` @@ -317,7 +317,7 @@ add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' ); function my_custom_checkout_field( $checkout ) { - echo '' . esc_html__( 'My Field' ) . ': ' . esc_html( $order->get_meta( 'My Field', true ) ) . '
'; + echo '<p><strong>' . esc_html__( 'My Field' ) . ':</strong> ' . esc_html( $order->get_meta( 'My Field', true ) ) . '</p>'; } ``` diff --git a/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md b/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md index 0549ead8a57..6d3caeedb2a 100644 --- a/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md +++ b/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md @@ -33,7 +33,7 @@ function woocommerce_custom_field_example() { $custom_field_value = get_post_meta( $product->get_id(), 'woo_custom_field', true ); if ( ! empty( $custom_field_value ) ) { - echo 'Hello World (from the editor).
; + return <p>Hello World (from the editor).</p>; } registerBlockType( 'tutorial/new-product-form-field', { @@ -217,8 +217,8 @@ function Edit( { attributes } ) { const blockProps = useWooBlockProps( attributes ); return ( -- { __( - "Attributes are needed for filtering your products. You haven't created any attributes yet.", - 'woocommerce' - ) } -
-+ { __( + "Attributes are needed for filtering your products. You haven't created any attributes yet.", + 'woocommerce' + ) } +
+{ __( 'Please select an attribute to use this filter!', @@ -160,22 +214,14 @@ const Edit = ( props: EditProps ) => { ) }
{ __( 'There are no products with the selected attributes.', @@ -183,30 +229,28 @@ const Edit = ( props: EditProps ) => { ) }
+ + +
+ + settings = apply_filters( + 'woocommerce_brands_settings_fields', + array( + array( + 'name' => __( 'Brands Archives', 'woocommerce' ), + 'type' => 'title', + 'desc' => '', + 'id' => 'brands_archives', + ), + array( + 'name' => __( 'Show description', 'woocommerce' ), + 'desc' => __( 'Choose to show the brand description on the archive page. Turn this off if you intend to use the description widget instead. Please note: this is only for themes that do not show the description.', 'woocommerce' ), + 'tip' => '', + 'id' => 'wc_brands_show_description', + 'css' => '', + 'std' => 'yes', + 'type' => 'checkbox', + ), + array( + 'type' => 'sectionend', + 'id' => 'brands_archives', + ), + ) + ); + } + + /** + * Enqueue scripts. + * + * @return void + */ + public function scripts() { + $screen = get_current_screen(); + $version = Constants::get_constant( 'WC_VERSION' ); + $suffix = Constants::is_true( 'SCRIPT_DEBUG' ) ? '' : '.min'; + + if ( 'edit-product' === $screen->id ) { + wp_register_script( + 'wc-brands-enhanced-select', + WC()->plugin_url() . '/assets/js/admin/wc-brands-enhanced-select' . $suffix . '.js', + array( 'jquery', 'selectWoo', 'wc-enhanced-select', 'wp-api' ), + $version, + true + ); + wp_localize_script( + 'wc-brands-enhanced-select', + 'wc_brands_enhanced_select_params', + array( 'ajax_url' => get_rest_url() . 'brands/search' ) + ); + wp_enqueue_script( 'wc-brands-enhanced-select' ); + } + + if ( in_array( $screen->id, array( 'edit-product_brand' ), true ) ) { + wp_enqueue_media(); + wp_enqueue_style( 'woocommerce_admin_styles' ); + } + } + + /** + * Enqueue styles. + * + * @return void + */ + public function styles() { + $version = Constants::get_constant( 'WC_VERSION' ); + wp_enqueue_style( 'brands-admin-styles', WC()->plugin_url() . '/assets/css/brands-admin.css', array(), $version ); + } + + /** + * Admin settings function. + */ + public function admin_settings() { + woocommerce_admin_fields( $this->settings ); + } + + /** + * Save admin settings function. + */ + public function save_admin_settings() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( isset( $_GET['section'] ) && 'brands' === $_GET['section'] ) { + woocommerce_update_options( $this->settings ); + } + } + + /** + * Category thumbnails. + */ + public function add_thumbnail_field() { + global $woocommerce; + ?> +
+ + +
+ widget_cssclass = 'woocommerce widget_brand_nav widget_layered_nav'; + $this->widget_description = __( 'Shows brands in a widget which lets you narrow down the list of products when viewing products.', 'woocommerce' ); + $this->widget_id = 'woocommerce_brand_nav'; + $this->widget_name = __( 'WooCommerce Brand Layered Nav', 'woocommerce' ); + + add_filter( 'woocommerce_product_subcategories_args', array( $this, 'filter_out_cats' ) ); + + /* Create the widget. */ + parent::__construct(); + } + + /** + * Filter out all categories and not display them + * + * @param array $cat_args Category arguments. + */ + public function filter_out_cats( $cat_args ) { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( ! empty( $_GET['filter_product_brand'] ) ) { + return array( 'taxonomy' => '' ); + } + + return $cat_args; + } + + /** + * Return the currently viewed taxonomy name. + * + * @return string + */ + protected function get_current_taxonomy() { + return is_tax() ? get_queried_object()->taxonomy : ''; + } + + /** + * Return the currently viewed term ID. + * + * @return int + */ + protected function get_current_term_id() { + return absint( is_tax() ? get_queried_object()->term_id : 0 ); + } + + /** + * Return the currently viewed term slug. + * + * @return int + */ + protected function get_current_term_slug() { + return absint( is_tax() ? get_queried_object()->slug : 0 ); + } + + /** + * Widget function. + * + * @see WP_Widget + * + * @param array $args Arguments. + * @param array $instance Widget instance. + * @return void + */ + public function widget( $args, $instance ) { + $attribute_array = array(); + $attribute_taxonomies = wc_get_attribute_taxonomies(); + + if ( ! empty( $attribute_taxonomies ) ) { + foreach ( $attribute_taxonomies as $tax ) { + if ( taxonomy_exists( wc_attribute_taxonomy_name( $tax->attribute_name ) ) ) { + $attribute_array[ $tax->attribute_name ] = $tax->attribute_name; + } + } + } + + if ( ! is_post_type_archive( 'product' ) && ! is_tax( array_merge( is_array( $attribute_array ) ? $attribute_array : array(), array( 'product_cat', 'product_tag' ) ) ) ) { + return; + } + + $_chosen_attributes = WC_Query::get_layered_nav_chosen_attributes(); + + $current_term = $attribute_array && is_tax( $attribute_array ) ? get_queried_object()->term_id : ''; + $current_tax = $attribute_array && is_tax( $attribute_array ) ? get_queried_object()->taxonomy : ''; + + /** + * Filter the widget's title. + * + * @since 9.4.0 + * + * @param string $title Widget title + * @param array $instance The settings for the particular instance of the widget. + * @param string $woo_widget_idbase The widget's id base. + */ + $title = apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base ); + $taxonomy = 'product_brand'; + $display_type = isset( $instance['display_type'] ) ? $instance['display_type'] : 'list'; + + if ( ! taxonomy_exists( $taxonomy ) ) { + return; + } + + // Get only parent terms. Methods will recursively retrieve children. + $terms = get_terms( + array( + 'taxonomy' => $taxonomy, + 'hide_empty' => true, + 'parent' => 0, + ) + ); + + if ( empty( $terms ) ) { + return; + } + + ob_start(); + + $this->widget_start( $args, $instance ); + + if ( 'dropdown' === $display_type ) { + $found = $this->layered_nav_dropdown( $terms, $taxonomy ); + } else { + $found = $this->layered_nav_list( $terms, $taxonomy ); + } + + $this->widget_end( $args ); + + // Force found when option is selected - do not force found on taxonomy attributes. + if ( ! is_tax() && is_array( $_chosen_attributes ) && array_key_exists( $taxonomy, $_chosen_attributes ) ) { + $found = true; + } + + if ( ! $found ) { + ob_end_clean(); + } else { + echo ob_get_clean(); // phpcs:ignore WordPress.Security.EscapeOutput + } + } + + /** + * Update function. + * + * @see WP_Widget->update + * + * @param array $new_instance The new settings for the particular instance of the widget. + * @param array $old_instance The old settings for the particular instance of the widget. + * @return array + */ + public function update( $new_instance, $old_instance ) { + global $woocommerce; + + if ( empty( $new_instance['title'] ) ) { + $new_instance['title'] = __( 'Brands', 'woocommerce' ); + } + + $instance['title'] = wp_strip_all_tags( stripslashes( $new_instance['title'] ) ); + $instance['display_type'] = stripslashes( $new_instance['display_type'] ); + + return $instance; + } + + /** + * Form function. + * + * @see WP_Widget->form + * + * @param array $instance Widget instance. + * @return void + */ + public function form( $instance ) { + global $woocommerce; + + if ( ! isset( $instance['display_type'] ) ) { + $instance['display_type'] = 'list'; + } + ?> ++ +
+ ++
+ $data ) { + if ( $name === $taxonomy ) { + continue; + } + $filter_name = sanitize_title( str_replace( 'pa_', '', $name ) ); + if ( ! empty( $data['terms'] ) ) { + $link = add_query_arg( 'filter_' . $filter_name, implode( ',', $data['terms'] ), $link ); + } + if ( 'or' === $data['query_type'] ) { + $link = add_query_arg( 'query_type_' . $filter_name, 'or', $link ); + } + } + } + + // phpcs:enable WordPress.Security.NonceVerification.Recommended + return esc_url( $link ); + } + + /** + * Gets the currently selected attributes + * + * @return array + */ + public function get_chosen_attributes() { + // phpcs:ignore WordPress.Security.NonceVerification.Recommended + if ( ! empty( $_GET['filter_product_brand'] ) ) { + $filter_product_brand = wc_clean( wp_unslash( $_GET['filter_product_brand'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended + return array_map( 'intval', explode( ',', $filter_product_brand ) ); + } + + return array(); + } + + /** + * Show dropdown layered nav. + * + * @param array $terms Terms. + * @param string $taxonomy Taxonomy. + * @param int $depth Depth. + * @return bool Will nav display? + */ + protected function layered_nav_dropdown( $terms, $taxonomy, $depth = 0 ) { + $found = false; + + if ( $taxonomy !== $this->get_current_taxonomy() ) { + $term_counts = $this->get_filtered_term_product_counts( wp_list_pluck( $terms, 'term_id' ), $taxonomy, 'or' ); + $_chosen_attributes = $this->get_chosen_attributes(); + + if ( 0 === $depth ) { + echo ''; + + wc_enqueue_js( + " + jQuery( '.wc-brand-dropdown-layered-nav-" . esc_js( $taxonomy ) . "' ).change( function() { + var slug = jQuery( this ).val(); + location.href = '" . preg_replace( '%\/page\/[0-9]+%', '', str_replace( array( '&', '%2C' ), array( '&', ',' ), esc_js( add_query_arg( 'filtering', '1', $link ) ) ) ) . '&filter_' . esc_js( $taxonomy ) . "=' + jQuery( '.wc-brand-dropdown-layered-nav-" . esc_js( $taxonomy ) . "' ).val(); + }); + " + ); + } + } + + return $found; + } + + /** + * Show list based layered nav. + * + * @param array $terms Terms. + * @param string $taxonomy Taxonomy. + * @param int $depth Depth. + * @return bool Will nav display? + */ + protected function layered_nav_list( $terms, $taxonomy, $depth = 0 ) { + // List display. + echo '+ + +
+ ++ + +
+ ++ + id="get_field_id( 'fluid_columns' ) ); ?>" name="get_field_name( 'fluid_columns' ) ); ?>" /> +
+ ++ + +
+ ++ + +
+ ++ + +
+ ++ + +
+ get_param( 'redirect_url' ); - $calypso_env = defined( 'WOOCOMMERCE_CALYPSO_ENVIRONMENT' ) && in_array( WOOCOMMERCE_CALYPSO_ENVIRONMENT, [ 'development', 'wpcalypso', 'horizon', 'stage' ], true ) ? WOOCOMMERCE_CALYPSO_ENVIRONMENT : 'production'; + $calypso_env = defined( 'WOOCOMMERCE_CALYPSO_ENVIRONMENT' ) && in_array( WOOCOMMERCE_CALYPSO_ENVIRONMENT, array( 'development', 'wpcalypso', 'horizon', 'stage' ), true ) ? WOOCOMMERCE_CALYPSO_ENVIRONMENT : 'production'; + + $authorization_url = $manager->get_authorization_url( null, $redirect_url ); + $authorization_url = add_query_arg( 'locale', $this->get_wpcom_locale(), $authorization_url ); + + if ( Features::is_enabled( 'use-wp-horizon' ) ) { + $calypso_env = 'horizon'; + } return [ 'success' => ! $errors->has_errors(), 'errors' => $errors->get_error_messages(), 'url' => add_query_arg( - [ + array( 'from' => $request->get_param( 'from' ), 'calypso_env' => $calypso_env, - ], - $manager->get_authorization_url( null, $redirect_url ) + ), + $authorization_url, ), ]; } + /** + * Return a locale string for wpcom. + * + * @return string + */ + private function get_wpcom_locale() { + // List of locales that should be used with region code. + $locale_to_lang = array( + 'bre' => 'br', + 'de_AT' => 'de-at', + 'de_CH' => 'de-ch', + 'de' => 'de_formal', + 'el' => 'el-po', + 'en_GB' => 'en-gb', + 'es_CL' => 'es-cl', + 'es_MX' => 'es-mx', + 'fr_BE' => 'fr-be', + 'fr_CA' => 'fr-ca', + 'nl_BE' => 'nl-be', + 'nl' => 'nl_formal', + 'pt_BR' => 'pt-br', + 'sr' => 'sr_latin', + 'zh_CN' => 'zh-cn', + 'zh_HK' => 'zh-hk', + 'zh_SG' => 'zh-sg', + 'zh_TW' => 'zh-tw', + ); + + $system_locale = get_locale(); + if ( isset( $locale_to_lang[ $system_locale ] ) ) { + // Return the locale with region code if it's in the list. + return $locale_to_lang[ $system_locale ]; + } + + // If the locale is not in the list, return the language code only. + return explode( '_', $system_locale )[0]; + } + /** * Check whether the current user has permission to install plugins * @@ -400,7 +446,7 @@ class OnboardingPlugins extends WC_REST_Data_Controller { ), $slug ), - 'type' => 'plugin_info_api_error', + 'type' => 'plugin_info_api_error', 'slug' => $slug, 'api_version' => $api->version, 'api_download_link' => $api->download_link, diff --git a/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php b/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php index e13ed41c47c..7f740eff74e 100644 --- a/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php +++ b/plugins/woocommerce/src/Admin/API/Reports/Customers/DataStore.php @@ -615,6 +615,11 @@ class DataStore extends ReportsDataStore implements DataStoreInterface { if ( is_null( $customer_user ) ) { $customer_user = new \WC_Customer( $user_id ); } + + // Set email as customer email instead of Order Billing Email if we have a customer. + $data['email'] = $customer_user->get_email( 'edit' ); + + // Adding other relevant customer data. $data['user_id'] = $user_id; $data['username'] = $customer_user->get_username( 'edit' ); $data['date_registered'] = $customer_user->get_date_created( 'edit' ) ? $customer_user->get_date_created( 'edit' )->date( TimeInterval::$sql_datetime_format ) : null; diff --git a/plugins/woocommerce/src/Admin/API/Reports/Taxes/Controller.php b/plugins/woocommerce/src/Admin/API/Reports/Taxes/Controller.php index d31db463c0c..a794fee018f 100644 --- a/plugins/woocommerce/src/Admin/API/Reports/Taxes/Controller.php +++ b/plugins/woocommerce/src/Admin/API/Reports/Taxes/Controller.php @@ -244,7 +244,15 @@ class Controller extends GenericController implements ExportableInterface { */ public function prepare_item_for_export( $item ) { return array( - 'tax_code' => \WC_Tax::get_rate_code( $item['tax_rate_id'] ), + 'tax_code' => \WC_Tax::get_rate_code( + (object) array( + 'tax_rate_id' => $item['tax_rate_id'], + 'tax_rate_country' => $item['country'], + 'tax_rate_state' => $item['state'], + 'tax_rate_name' => $item['name'], + 'tax_rate_priority' => $item['priority'], + ) + ), 'rate' => $item['tax_rate'], 'total_tax' => self::csv_number_format( $item['total_tax'] ), 'order_tax' => self::csv_number_format( $item['order_tax'] ), diff --git a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php index ba33d9b2362..b0a65b969e6 100644 --- a/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php +++ b/plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Tax.php @@ -15,6 +15,7 @@ class Tax extends Task { /** * Used to cache is_complete() method result. + * * @var null */ private $is_complete_result = null; @@ -109,12 +110,16 @@ class Tax extends Task { */ public function is_complete() { if ( $this->is_complete_result === null ) { - $wc_connect_taxes_enabled = get_option( 'wc_connect_taxes_enabled' ); + $wc_connect_taxes_enabled = get_option( 'wc_connect_taxes_enabled' ); $is_wc_connect_taxes_enabled = ( $wc_connect_taxes_enabled === 'yes' ) || ( $wc_connect_taxes_enabled === true ); // seems that in some places boolean is used, and other places 'yes' | 'no' is used + // phpcs:ignore WooCommerce.Commenting.CommentHooks.MissingHookComment -- We will replace this with a formal system by WC 9.6 so lets not advertise it yet. + $third_party_complete = apply_filters( 'woocommerce_admin_third_party_tax_setup_complete', false ); + $this->is_complete_result = $is_wc_connect_taxes_enabled || count( TaxDataStore::get_taxes( array() ) ) > 0 || - get_option( 'woocommerce_no_sales_tax' ) !== false; + get_option( 'woocommerce_no_sales_tax' ) !== false || + $third_party_complete; } return $this->is_complete_result; diff --git a/plugins/woocommerce/src/Admin/Notes/Note.php b/plugins/woocommerce/src/Admin/Notes/Note.php index af986572efa..9058906d87b 100644 --- a/plugins/woocommerce/src/Admin/Notes/Note.php +++ b/plugins/woocommerce/src/Admin/Notes/Note.php @@ -579,6 +579,11 @@ class Note extends \WC_Data { $layout = 'plain'; } $valid_layouts = array( 'banner', 'plain', 'thumbnail' ); + + if ( 'banner' === $layout ) { + wc_deprecated_argument( 'Note::set_layout', '9.4.0', 'The "banner" layout is deprecated. Please use "thumbnail" instead to display a image.' ); + } + if ( in_array( $layout, $valid_layouts, true ) ) { $this->set_prop( 'layout', $layout ); } else { diff --git a/plugins/woocommerce/src/Admin/PluginsHelper.php b/plugins/woocommerce/src/Admin/PluginsHelper.php index efcf9152f9e..1900bfdf493 100644 --- a/plugins/woocommerce/src/Admin/PluginsHelper.php +++ b/plugins/woocommerce/src/Admin/PluginsHelper.php @@ -33,17 +33,24 @@ if ( ! function_exists( 'get_plugins' ) ) { class PluginsHelper { /** - * Indicates whether the expiration notice for subscriptions can be displayed. + * Subscription notices in Woo screens are shown in clear priority order, first + * expired, and if those don't exist, expiring, and finally if none of those exist, + * then missing. This keeps track of whether we can show the next set of notices. * * @var bool */ - public static $can_show_expiring_subs_notice = true; + public static $subscription_usage_notices_already_shown = false; /** * The URL for the WooCommerce subscription page. */ const WOO_SUBSCRIPTION_PAGE_URL = 'https://woocommerce.com/my-account/my-subscriptions/'; + /** + * The URL for the WooCommerce.com cart page. + */ + const WOO_CART_PAGE_URL = 'https://woocommerce.com/cart/'; + /** * The URL for the WooCommerce.com add payment method page. */ @@ -59,6 +66,11 @@ class PluginsHelper { */ const DISMISS_EXPIRING_SUBS_NOTICE = 'woo_subscription_expiring_notice_dismiss'; + /** + * Meta key for dismissing missing subscription notices + */ + const DISMISS_MISSING_SUBS_NOTICE = 'woo_subscription_missing_notice_dismiss'; + /** * Initialize hooks. */ @@ -67,10 +79,7 @@ class PluginsHelper { add_action( 'woocommerce_plugins_install_and_activate_async_callback', array( __CLASS__, 'install_and_activate_plugins_async_callback' ), 10, 2 ); add_action( 'woocommerce_plugins_activate_callback', array( __CLASS__, 'activate_plugins' ), 10, 2 ); add_action( 'admin_notices', array( __CLASS__, 'maybe_show_connect_notice_in_plugin_list' ) ); - add_action( 'admin_notices', array( __CLASS__, 'maybe_show_expired_subscriptions_notice' ), 10 ); - add_action( 'admin_notices', array( __CLASS__, 'maybe_show_expiring_subscriptions_notice' ), 11 ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'maybe_enqueue_scripts_for_connect_notice' ) ); - add_action( 'admin_enqueue_scripts', array( __CLASS__, 'maybe_enqueue_scripts_for_subscription_notice' ) ); add_action( 'admin_enqueue_scripts', array( __CLASS__, 'maybe_enqueue_scripts_for_notices_in_plugins' ) ); } @@ -659,6 +668,7 @@ class PluginsHelper { wp_enqueue_script( 'woo-plugin-update-connect-notice' ); wp_enqueue_script( 'woo-enable-autorenew' ); wp_enqueue_script( 'woo-renew-subscription' ); + wp_enqueue_script( 'woo-purchase-subscription' ); } /** @@ -733,11 +743,15 @@ class PluginsHelper { * @return array notice data to return. Contains type, parsed_message and product_id. */ public static function get_subscriptions_notice_data( array $all_subs, array $subs_to_show, int $total, array $messages, string $type ) { + $utm_campaign = 'expired' === $type ? + 'pu_settings_screen_renew' : + ( 'missing' === $type ? 'pu_settings_screen_purchase' : 'pu_settings_screen_enable_autorenew' ); + if ( 1 < $total ) { $hyperlink_url = add_query_arg( array( 'utm_source' => 'pu', - 'utm_campaign' => 'expired' === $type ? 'pu_settings_screen_renew' : 'pu_settings_screen_enable_autorenew', + 'utm_campaign' => $utm_campaign, ), self::WOO_SUBSCRIPTION_PAGE_URL @@ -750,10 +764,18 @@ class PluginsHelper { esc_attr( $total ), ); + // All product ids. + $product_ids = array_map( + function ( $sub ) { + return $sub['product_id']; + }, + $subs_to_show + ); + return array( 'type' => 'different_subscriptions', 'parsed_message' => $parsed_message, - 'product_id' => '', + 'product_ids' => $product_ids, ); } @@ -769,8 +791,9 @@ class PluginsHelper { ) ); - $message_key = $has_multiple_subs_for_product ? 'multiple_manage' : 'single_manage'; - $renew_string = __( 'Renew', 'woocommerce' ); + $message_key = $has_multiple_subs_for_product ? 'multiple_manage' : 'single_manage'; + $renew_string = __( 'Renew', 'woocommerce' ); + $subscribe_string = __( 'Subscribe', 'woocommerce' ); if ( isset( $subscription['product_regular_price'] ) ) { /* translators: 1: Product price */ $renew_string = sprintf( __( 'Renew for %1$s', 'woocommerce' ), $subscription['product_regular_price'] ); @@ -781,7 +804,7 @@ class PluginsHelper { 'product_id' => $product_id, 'type' => $type, 'utm_source' => 'pu', - 'utm_campaign' => 'expired' === $type ? 'pu_settings_screen_renew' : 'pu_settings_screen_enable_autorenew', + 'utm_campaign' => $utm_campaign, ), self::WOO_SUBSCRIPTION_PAGE_URL @@ -798,7 +821,8 @@ class PluginsHelper { esc_attr( $subscription['product_name'] ), esc_attr( $expiry_date ), esc_url( $hyperlink_url ), - esc_attr( $renew_string ), + // Show subscribe for missing subscriptions, renew otherwise. + 'missing' === $type ? esc_attr( $subscribe_string ) : esc_attr( $renew_string ), ); return array( @@ -826,7 +850,7 @@ class PluginsHelper { return array(); } - if ( ! self::$can_show_expiring_subs_notice ) { + if ( self::$subscription_usage_notices_already_shown ) { return array(); } @@ -851,6 +875,9 @@ class PluginsHelper { $total_expiring_subscriptions = count( $expiring_subscriptions ); + // Don't show missing notice if there are expiring subscriptions. + self::$subscription_usage_notices_already_shown = true; + // When payment method is missing on WooCommerce.com. $helper_notices = WC_Helper::get_notices(); if ( ! empty( $helper_notices['missing_payment_method_notice'] ) ) { @@ -927,8 +954,8 @@ class PluginsHelper { return array(); } - $total_expired_subscriptions = count( $expired_subscriptions ); - self::$can_show_expiring_subs_notice = false; + $total_expired_subscriptions = count( $expired_subscriptions ); + self::$subscription_usage_notices_already_shown = true; $notice_data = self::get_subscriptions_notice_data( $subscriptions, @@ -947,17 +974,17 @@ class PluginsHelper { $button_link = add_query_arg( array( + 'add-to-cart' => $notice_data['product_ids'], 'utm_source' => 'pu', 'utm_campaign' => $allowed_link ? 'pu_settings_screen_renew' : 'pu_in_apps_screen_renew', ), - self::WOO_SUBSCRIPTION_PAGE_URL + self::WOO_CART_PAGE_URL ); if ( in_array( $notice_data['type'], array( 'single_manage', 'multiple_manage' ), true ) ) { $button_link = add_query_arg( array( - 'product_id' => $notice_data['product_id'], - 'type' => 'expiring', + 'add-to-cart' => $notice_data['product_id'], ), $button_link ); @@ -970,6 +997,86 @@ class PluginsHelper { ); } + /** + * Get formatted notice information for missing subscription. + * + * @return array notice information. + */ + public static function get_missing_subscription_notice() { + if ( ! WC_Helper::is_site_connected() ) { + return array(); + } + + if ( self::$subscription_usage_notices_already_shown ) { + return array(); + } + + if ( ! self::should_show_notice( self::DISMISS_MISSING_SUBS_NOTICE ) ) { + return array(); + } + + $subscriptions = WC_Helper::get_subscription_list_data(); + $missing_subscriptions = array_filter( + $subscriptions, + function ( $sub ) { + return ( ! empty( $sub['local']['installed'] ) && empty( $sub['product_key'] ) ); + }, + ); + + // Remove WUM from missing subscriptions list. + $missing_subscriptions = array_filter( + $missing_subscriptions, + function ( $sub ) { + return 'woo-update-manager' !== $sub['zip_slug']; + } + ); + + if ( ! $missing_subscriptions ) { + return array(); + } + + $total_missing_subscriptions = count( $missing_subscriptions ); + + $notice_data = self::get_subscriptions_notice_data( + $subscriptions, + $missing_subscriptions, + $total_missing_subscriptions, + array( + /* translators: 1) product name */ + 'single_manage' => __( 'You don\'t have a subscription for %1$s. Subscribe to receive updates and streamlined support.', 'woocommerce' ), + /* translators: 1) total expired subscriptions */ + 'different_subscriptions' => __( 'You don\'t have subscriptions for %1$s Woo extensions. Subscribe to receive updates and streamlined support.', 'woocommerce' ), + ), + 'missing', + ); + + $button_link = add_query_arg( + array( + 'add-to-cart' => $notice_data['product_ids'], + 'utm_source' => 'pu', + 'utm_campaign' => 'pu_in_apps_screen_purchase', + ), + self::WOO_CART_PAGE_URL + ); + + if ( in_array( $notice_data['type'], array( 'single_manage', 'multiple_manage' ), true ) ) { + $button_link = add_query_arg( + array( + 'add-to-cart' => $notice_data['product_id'], + ), + $button_link + ); + } + + $button_text = __( 'Subscribe', 'woocommerce' ); + + return array( + 'description' => $notice_data['parsed_message'], + 'button_text' => $button_text, + 'button_link' => $button_link, + ); + } + /** * Determine whether a specific notice should be shown to the current user. * diff --git a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/BaseLocationCountryRuleProcessor.php b/plugins/woocommerce/src/Admin/RemoteInboxNotifications/BaseLocationCountryRuleProcessor.php deleted file mode 100644 index 3854f372b83..00000000000 --- a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/BaseLocationCountryRuleProcessor.php +++ /dev/null @@ -1,33 +0,0 @@ -source ) ) { $note->set_source( $spec->source ); } + if ( isset( $spec->layout ) ) { + $note->set_layout( $spec->layout ); + } // Recreate actions. $note->set_actions( self::get_actions( $spec ) ); diff --git a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/StoredStateRuleProcessor.php b/plugins/woocommerce/src/Admin/RemoteInboxNotifications/StoredStateRuleProcessor.php deleted file mode 100644 index bc4f2c5e9fb..00000000000 --- a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/StoredStateRuleProcessor.php +++ /dev/null @@ -1,33 +0,0 @@ - "media" ), - array("industry" => "software" ) -); -``` - -Use `array_column` to extract `array("media", "software")` then choose the first element with `dot_notation`. - -```php -"transformers": [ - { - "use": "array_column", - "arguments": { - "key": "industry" - } - }, - { - "use": "dot_notation", - "arguments": { - "key": "0" - } - } -], -``` - -**Output**: "media" - - - - - -## array_flatten - -Flattens a nested array. - -#### Arguments: N/A - -#### Definition: - -```php -"transformers": [ - { - "use": "array_flatten" - } -], -``` - -#### Example: - -Given the following data - -```php -array( - array( - 'member1', - ), - array( - 'member2', - ), - array( - 'member3', - ), -); -``` - -Use `array_flatten` to extract `array("member1", "member2", "member3")` then use `array_search` to make sure it has `member2` - - -```php -"transformers": [ - { - "use": "array_flatten", - }, - { - "use": "array_search", - "arguments": { - "key": "member2" - } - } -], -``` - -**Output**: true - -## array_keys - -PHP's built-in `array_keys` to return keys from an array. For more information about how `array_keys` works, please see PHP’s [official documentation](https://www.php.net/manual/en/function.array-column.php). - -#### Arguments: N/A - -####Definition: - -```php -"transformers": [ - { - "use": "array_keys" - } -], -``` - -#### Example: - -Given the following data - -```php -array( - "name" => "tester", - "address" => "test", - "supports_version_2" => true -) -``` - -Use `array_keys` to extract `array("name", "address", "supports_version_2")` and then use `array_search` to make sure it has `supports_version_2` - -```php -"transformers": [ - { - "use": "array_keys", - }, - { - "use": "array_search", - "arguments": { - "key": "member2" - } - } -], -``` - -**Output**: true - -## array_search - -PHP's built-in `array_search` to search a value in an array. For more information about how `array_search` works, please see PHP’s [official documentation](https://www.php.net/manual/en/function.array-search.php). - -#### Arguments: - -|name|description| -|----|---------| -| value | a value to search in the given array | - -#### Definition: - -```php -"transformers": [ - { - "use": "array_search", - "arguments": { - "value": "test" - } - } -], -``` - -#### Examples - -See examples from [array_flatten](#array_flatten) and [array_keys](#array_keys) - -## array_values - -PHP's built-in array_values to return values from an array. For more information about how `array_values` works, please see PHP’s [official documentation](https://www.php.net/manual/en/function.array-values). - - -#### Arguments: N/A - -#### Definition: - -```php -"transformers": [ - { - "use": "array_values" - } -], -``` - -#### Example: - -Given the following data - -```php -array ( - "size" => "x-large" -) -``` - -Use `array_values` to extract `array("x-large")` - -```php -"transformers": [ - { - "use": "array_values", - } -], -``` - -**Output:** "x-large" - - -## dot_notation - -Uses dot notation to select a value in an array. Dot notation lets you access an array as if it is an object. - -#### Arguments: N/A - -#### Definition: - - -```php -"transformers": [ - { - "use": "dot_notation", - "arguments": { - "path": "name" - } - } -], -``` - -#### Example: - - - -Given the following data - -```php -array( - 'name' => 'john', - 'members' => ['member1', 'member2'] -); -``` - -Select `name` field. - -```php -"transformers": [ - { - "use": "dot_notation", - "arguments": { - "path": "name" - } - } -], -``` - -**Output:** "john" - -Select `member2`. You can access array items with an index. - -```php -"transformers": [ - { - "use": "dot_notation", - "arguments": { - "path": "members.1" - } - } -], -``` - -**Output:**: "member2" - -## count - -PHP's built-in count to return the number of values from a countable, such as an array. - -#### Arguments: N/A - -#### Definition: - -```php -"transformers": [ - { - "use": "count" - } -], -``` - -#### Example: - -Given the following list of usernames - -```php -array( - "username1", - "username2", - "username3" -) -``` - -Let's count # of users with `count` - -```php -"transformers": [ - { - "use": "count", - } -], -``` - -**Output:** 3 - -## prepare_url - -This prepares the site URL by removing the protocol and the last slash. - -#### Arguments: N/A - -####Definition: - -```php -"transformers": [ - { - "use": "prepare_url" - } -], -``` - -#### Example: - -Given the following data - -```php -$siteurl = "https://mysite.com/" -``` - -Removes the protocol and the last slash. - -```php -"transformers": [ - { - "use": "prepare_url", - } -], -``` - -**Output:** "mysite.com" diff --git a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/WCAdminActiveForProvider.php b/plugins/woocommerce/src/Admin/RemoteInboxNotifications/WCAdminActiveForProvider.php deleted file mode 100644 index 21d53b4c0c1..00000000000 --- a/plugins/woocommerce/src/Admin/RemoteInboxNotifications/WCAdminActiveForProvider.php +++ /dev/null @@ -1,31 +0,0 @@ -%4$s';
printf(
- /* translators: %s: is referring to the plugin's name. */
+ /* translators: %s: is referring to the plugin's name. */
esc_html__( 'The %1$s plugin has been deactivated as the latest improvements are now included with the %2$s plugin.', 'woocommerce' ),
'' . esc_html( $plugin_data['Name'] ) . '
',
'WooCommerce
'
@@ -118,13 +194,71 @@ class Packages {
}
}
+ /**
+ * Prevent plugins already merged into WooCommerce core from getting activated as standalone plugins.
+ *
+ * @param string $plugin Plugin name.
+ */
+ public static function deactivate_merged_plugins( $plugin ) {
+ $plugin_dir = basename( dirname( $plugin ) );
+
+ if ( self::is_package_enabled( $plugin_dir ) ) {
+ $plugins_url = esc_url( admin_url( 'plugins.php' ) );
+ wp_die(
+ esc_html__( 'This plugin cannot be activated because its functionality is now included in WooCommerce core.', 'woocommerce' ),
+ esc_html__( 'Plugin Activation Error', 'woocommerce' ),
+ array(
+ 'link_url' => esc_url( $plugins_url ),
+ 'link_text' => esc_html__( 'Return to the Plugins page', 'woocommerce' ),
+ ),
+ );
+ }
+ }
+
+ /**
+ * Mark merged plugins as pending update.
+ * This is required for correctly displaying maintenance notices.
+ *
+ * @param array $plugins Plugins list.
+ */
+ public static function mark_merged_plugins_as_pending_update( $plugins ) {
+ foreach ( $plugins as $plugin_name => $plugin_data ) {
+ $plugin_dir = basename( dirname( $plugin_name ) );
+ if ( self::is_package_enabled( $plugin_dir ) ) {
+ // Necessary to properly display notice within row.
+ $plugins[ $plugin_name ]['update'] = 1;
+ }
+ }
+ return $plugins;
+ }
+
+ /**
+ * Displays a maintenance notice next to merged plugins, to inform users
+ * that the plugin functionality is now offered by WooCommerce core.
+ *
+ * Requires 'mark_merged_plugins_as_pending_update' to properly display this notice.
+ *
+ * @param string $plugin_file Plugin file.
+ */
+ public static function display_notice_for_merged_plugins( $plugin_file ) {
+ global $wp_list_table;
+
+ $plugin_dir = basename( dirname( $plugin_file ) );
+ $columns_count = $wp_list_table->get_column_count();
+ $notice = __( 'This plugin can no longer be activated because its functionality is now included in WooCommerce. It is recommended to delete it.', 'woocommerce' );
+
+ if ( self::is_package_enabled( $plugin_dir ) ) {
+ echo '
diff --git a/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php b/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php index 25f915d2862..3fce3214ab0 100644 --- a/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php +++ b/plugins/woocommerce/src/StoreApi/Utilities/ProductQuery.php @@ -16,7 +16,7 @@ class ProductQuery { * @return array */ public function prepare_objects_query( $request ) { - $args = [ + $args = array( 'offset' => $request['offset'], 'order' => $request['order'], 'orderby' => $request['orderby'], @@ -31,17 +31,17 @@ class ProductQuery { 'fields' => 'ids', 'ignore_sticky_posts' => true, 'post_status' => 'publish', - 'date_query' => [], + 'date_query' => array(), 'post_type' => 'product', - ]; + ); // If searching for a specific SKU or slug, allow any post type. if ( ! empty( $request['sku'] ) || ! empty( $request['slug'] ) ) { - $args['post_type'] = [ 'product', 'product_variation' ]; + $args['post_type'] = array( 'product', 'product_variation' ); } // Taxonomy query to filter products by type, category, tag, shipping class, and attribute. - $tax_query = []; + $tax_query = array(); // Filter product type by slug. if ( ! empty( $request['type'] ) ) { @@ -49,11 +49,11 @@ class ProductQuery { $args['post_type'] = 'product_variation'; } else { $args['post_type'] = 'product'; - $tax_query[] = [ + $tax_query[] = array( 'taxonomy' => 'product_type', 'field' => 'slug', 'terms' => $request['type'], - ]; + ); } } @@ -77,12 +77,12 @@ class ProductQuery { } // Set custom args to handle later during clauses. - $custom_keys = [ + $custom_keys = array( 'sku', 'min_price', 'max_price', 'stock_status', - ]; + ); foreach ( $custom_keys as $key ) { if ( ! empty( $request[ $key ] ) ) { @@ -90,11 +90,11 @@ class ProductQuery { } } - $operator_mapping = [ + $operator_mapping = array( 'in' => 'IN', 'not_in' => 'NOT IN', 'and' => 'AND', - ]; + ); // Gets all registered product taxonomies and prefixes them with `tax_`. // This is needed to avoid situations where a user registers a new product taxonomy with the same name as default field. @@ -107,10 +107,10 @@ class ProductQuery { ); // Map between taxonomy name and arg key. - $default_taxonomies = [ + $default_taxonomies = array( 'product_cat' => 'category', 'product_tag' => 'tag', - ]; + ); $taxonomies = array_merge( $all_product_taxonomies, $default_taxonomies ); @@ -118,18 +118,18 @@ class ProductQuery { foreach ( $taxonomies as $taxonomy => $key ) { if ( ! empty( $request[ $key ] ) ) { $operator = $request->get_param( $key . '_operator' ) && isset( $operator_mapping[ $request->get_param( $key . '_operator' ) ] ) ? $operator_mapping[ $request->get_param( $key . '_operator' ) ] : 'IN'; - $tax_query[] = [ + $tax_query[] = array( 'taxonomy' => $taxonomy, 'field' => 'term_id', 'terms' => $request[ $key ], 'operator' => $operator, - ]; + ); } } // Filter by attributes. if ( ! empty( $request['attributes'] ) ) { - $att_queries = []; + $att_queries = array(); foreach ( $request['attributes'] as $attribute ) { if ( empty( $attribute['term_id'] ) && empty( $attribute['slug'] ) ) { @@ -137,22 +137,22 @@ class ProductQuery { } if ( in_array( $attribute['attribute'], wc_get_attribute_taxonomy_names(), true ) ) { $operator = isset( $attribute['operator'], $operator_mapping[ $attribute['operator'] ] ) ? $operator_mapping[ $attribute['operator'] ] : 'IN'; - $att_queries[] = [ + $att_queries[] = array( 'taxonomy' => $attribute['attribute'], 'field' => ! empty( $attribute['term_id'] ) ? 'term_id' : 'slug', 'terms' => ! empty( $attribute['term_id'] ) ? $attribute['term_id'] : $attribute['slug'], 'operator' => $operator, - ]; + ); } } if ( 1 < count( $att_queries ) ) { // Add relation arg when using multiple attributes. $relation = $request->get_param( 'attribute_relation' ) && isset( $operator_mapping[ $request->get_param( 'attribute_relation' ) ] ) ? $operator_mapping[ $request->get_param( 'attribute_relation' ) ] : 'IN'; - $tax_query[] = [ + $tax_query[] = array( 'relation' => $relation, $att_queries, - ]; + ); } else { $tax_query = array_merge( $tax_query, $att_queries ); } @@ -176,12 +176,12 @@ class ProductQuery { // Filter featured. if ( is_bool( $request['featured'] ) ) { - $args['tax_query'][] = [ + $args['tax_query'][] = array( 'taxonomy' => 'product_visibility', 'field' => 'name', 'terms' => 'featured', 'operator' => true === $request['featured'] ? 'IN' : 'NOT IN', - ]; + ); } // Filter by on sale products. @@ -190,7 +190,7 @@ class ProductQuery { $on_sale_ids = wc_get_product_ids_on_sale(); // Use 0 when there's no on sale products to avoid return all products. - $on_sale_ids = empty( $on_sale_ids ) ? [ 0 ] : $on_sale_ids; + $on_sale_ids = empty( $on_sale_ids ) ? array( 0 ) : $on_sale_ids; $args[ $on_sale_key ] += $on_sale_ids; } @@ -203,25 +203,25 @@ class ProductQuery { $exclude_from_catalog = 'search' === $catalog_visibility ? '' : 'exclude-from-catalog'; $exclude_from_search = 'catalog' === $catalog_visibility ? '' : 'exclude-from-search'; - $args['tax_query'][] = [ + $args['tax_query'][] = array( 'taxonomy' => 'product_visibility', 'field' => 'name', - 'terms' => [ $exclude_from_catalog, $exclude_from_search ], + 'terms' => array( $exclude_from_catalog, $exclude_from_search ), 'operator' => 'hidden' === $catalog_visibility ? 'AND' : 'NOT IN', 'rating_filter' => true, - ]; + ); } if ( $rating ) { - $rating_terms = []; + $rating_terms = array(); foreach ( $rating as $value ) { $rating_terms[] = 'rated-' . $value; } - $args['tax_query'][] = [ + $args['tax_query'][] = array( 'taxonomy' => 'product_visibility', 'field' => 'name', 'terms' => $rating_terms, - ]; + ); } $orderby = $request->get_param( 'orderby' ); @@ -283,7 +283,7 @@ class ProductQuery { public function get_results( $request ) { $query_args = $this->prepare_objects_query( $request ); - add_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10, 2 ); + add_filter( 'posts_clauses', array( $this, 'add_query_clauses' ), 10, 2 ); $query = new \WP_Query(); $results = $query->query( $query_args ); @@ -297,13 +297,13 @@ class ProductQuery { $total_posts = $count_query->found_posts; } - remove_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10 ); + remove_filter( 'posts_clauses', array( $this, 'add_query_clauses' ), 10 ); - return [ + return array( 'results' => $results, 'total' => (int) $total_posts, 'pages' => $query->query_vars['posts_per_page'] > 0 ? (int) ceil( $total_posts / (int) $query->query_vars['posts_per_page'] ) : 1, - ]; + ); } /** @@ -315,11 +315,11 @@ class ProductQuery { public function get_objects( $request ) { $results = $this->get_results( $request ); - return [ + return array( 'objects' => array_map( 'wc_get_product', $results['results'] ), 'total' => $results['total'], 'pages' => $results['pages'], - ]; + ); } /** @@ -442,7 +442,7 @@ class ProductQuery { return ''; } - $or_queries = []; + $or_queries = array(); // We need to adjust the filter for each possible tax class and combine the queries into one. foreach ( $product_tax_classes as $tax_class ) { diff --git a/plugins/woocommerce/templates/brands/brand-description.php b/plugins/woocommerce/templates/brands/brand-description.php new file mode 100644 index 00000000000..a72a251a3f6 --- /dev/null +++ b/plugins/woocommerce/templates/brands/brand-description.php @@ -0,0 +1,35 @@ + +
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + - 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. ' + - 'Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n'; - - const simpleProducts = await request.post( - '/wp-json/wc/v3/products/batch', - { - data: { - create: [ - { - name: 'Beanie with Logo oxo', - date_created_gmt: '2021-09-01T15:50:20', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'Woo-beanie-logo', - price: '18', - regular_price: '20', - sale_price: '18', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.2', - dimensions: { - length: '6', - width: '4', - height: '1', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.accessoriesJSON.id, - }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Red' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 62, 63, 61, 60 ], - stock_status: 'instock', - }, - { - name: 'T-Shirt with Logo oxo', - date_created_gmt: '2021-09-02T15:50:20', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'Woo-tshirt-logo', - price: '18', - regular_price: '18', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.5', - dimensions: { - length: '10', - width: '12', - height: '0.5', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.tshirtsJSON.id, - }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Gray' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 59, 67, 66, 56 ], - stock_status: 'instock', - }, - { - name: 'Single oxo', - date_created_gmt: '2021-09-03T15:50:19', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple, virtual product.
\n', - sku: 'woo-single', - price: '2', - regular_price: '3', - sale_price: '2', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: true, - total_sales: 0, - virtual: true, - downloadable: true, - downloads: [ - { - id: '2579cf07-8b08-4c25-888a-b6258dd1f035', - name: 'Single', - file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg', - }, - ], - download_limit: 1, - download_expiry: 1, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '', - dimensions: { - length: '', - width: '', - height: '', - }, - shipping_required: false, - shipping_taxable: false, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.musicJSON.id, - }, - ], - tags: [], - attributes: [], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 68 ], - stock_status: 'instock', - }, - { - name: 'Album oxo', - date_created_gmt: '2021-09-04T15:50:19', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple, virtual product.
\n', - sku: 'woo-album', - price: '15', - regular_price: '15', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: true, - downloadable: true, - downloads: [ - { - id: 'cc10249f-1de2-44d4-93d3-9f88ae629f76', - name: 'Single 1', - file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg', - }, - { - id: 'aea8ef69-ccdc-4d83-8e21-3c395ebb9411', - name: 'Single 2', - file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/album.jpg', - }, - ], - download_limit: 1, - download_expiry: 1, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '', - dimensions: { - length: '', - width: '', - height: '', - }, - shipping_required: false, - shipping_taxable: false, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.musicJSON.id, - }, - ], - tags: [], - attributes: [], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 69 ], - stock_status: 'instock', - }, - { - name: 'Polo oxo', - date_created_gmt: '2021-09-05T15:50:19', - type: 'simple', - status: 'pending', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-polo', - price: '20', - regular_price: '20', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.8', - dimensions: { - length: '6', - width: '5', - height: '1', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.tshirtsJSON.id, - }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Blue' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 59, 56, 66, 76 ], - stock_status: 'instock', - }, - { - name: 'Long Sleeve Tee oxo', - date_created_gmt: '2021-09-06T15:50:19', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-long-sleeve-tee', - price: '25', - regular_price: '25', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '1', - dimensions: { - length: '7', - width: '5', - height: '1', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: 'freight', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.tshirtsJSON.id, - }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Green' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 59, 56, 76, 67 ], - stock_status: 'instock', - }, - { - name: 'Hoodie with Zipper oxo', - date_created_gmt: '2021-09-07T15:50:19', - type: 'simple', - status: 'publish', - featured: true, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-hoodie-with-zipper', - price: '45', - regular_price: '45', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '2', - dimensions: { - length: '8', - width: '6', - height: '2', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.hoodiesJSON.id, - }, - ], - tags: [], - attributes: [], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 57, 58 ], - stock_status: 'instock', - }, - { - name: 'Hoodie with Pocket oxo', - date_created_gmt: '2021-09-08T15:50:19', - type: 'simple', - status: 'publish', - featured: true, - catalog_visibility: 'hidden', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-hoodie-with-pocket', - price: '35', - regular_price: '45', - sale_price: '35', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '3', - dimensions: { - length: '10', - width: '8', - height: '2', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.hoodiesJSON.id, - }, - ], - tags: [ - { - id: tags.coolJSON.id, - }, - ], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Gray' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 65, 57, 58 ], - stock_status: 'instock', - }, - { - name: 'Sunglasses oxo', - date_created_gmt: '2021-09-09T15:50:19', - type: 'simple', - status: 'publish', - featured: true, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-sunglasses', - price: '90', - regular_price: '90', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: 'reduced-rate', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.2', - dimensions: { - length: '4', - width: '1.4', - height: '1', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.accessoriesJSON.id, - }, - ], - tags: [ - { - id: tags.coolJSON.id, - }, - ], - attributes: [], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 60, 62, 77, 61 ], - stock_status: 'instock', - }, - { - name: 'Cap oxo', - date_created_gmt: '2021-09-10T15:50:19', - type: 'simple', - status: 'publish', - featured: true, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-cap', - price: '16', - regular_price: '18', - sale_price: '16', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.6', - dimensions: { - length: '8', - width: '6.5', - height: '4', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.accessoriesJSON.id, - }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Yellow' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 60, 77, 61, 63 ], - stock_status: 'instock', - }, - { - name: 'Belt oxo', - date_created_gmt: '2021-09-12T15:50:19', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-belt', - price: '55', - regular_price: '65', - sale_price: '55', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '1.2', - dimensions: { - length: '12', - width: '2', - height: '1.5', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.accessoriesJSON.id, - }, - ], - tags: [], - attributes: [], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 63, 77, 62, 60 ], - stock_status: 'instock', - }, - { - name: 'Beanie oxo', - date_created_gmt: '2021-09-13T15:50:19', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-beanie', - price: '18', - regular_price: '20', - sale_price: '18', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.2', - dimensions: { - length: '4', - width: '5', - height: '0.5', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.accessoriesJSON.id, - }, - ], - tags: [ - { - id: tags.coolJSON.id, - }, - ], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Red' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 63, 62, 61, 77 ], - stock_status: 'instock', - }, - { - name: 'T-Shirt oxo', - date_created_gmt: '2021-09-14T15:50:19', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-tshirt', - price: '18', - regular_price: '18', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.8', - dimensions: { - length: '8', - width: '6', - height: '1', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.tshirtsJSON.id, - }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Gray' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 67, 76, 56, 66 ], - stock_status: 'onbackorder', - }, - { - name: 'Hoodie with Logo oxo', - date_created_gmt: '2021-09-15T15:50:19', - type: 'simple', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: - 'This is a simple product.
\n', - sku: 'woo-hoodie-with-logo', - price: '45', - regular_price: '45', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '2', - dimensions: { - length: '10', - width: '6', - height: '3', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.hoodiesJSON.id, - }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: false, - options: [ 'Blue' ], - }, - ], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [ 57, 65 ], - stock_status: 'instock', - }, - ], - }, - } - ); - const simpleProductsJSON = await simpleProducts.json(); - - return simpleProductsJSON.create; - }; - - const createSampleExternalProducts = async ( categories ) => { - const externalProducts = await request.post( - '/wp-json/wc/v3/products/batch', - { - data: { - create: [ - { - name: 'WordPress Pennant oxo', - date_created_gmt: '2021-09-16T15:50:20', - type: 'external', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description: - 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + - 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. ' + - 'Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n', - short_description: - 'This is an external product.
\n', - sku: 'wp-pennant', - price: '11.05', - regular_price: '11.05', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: false, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: - 'https://mercantile.wordpress.org/product/wordpress-pennant/', - button_text: 'Buy on the WordPress swag store!', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '', - dimensions: { - length: '', - width: '', - height: '', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.decorJSON.id, - }, - ], - tags: [], - attributes: [], - default_attributes: [], - variations: [], - grouped_products: [], - menu_order: 0, - related_ids: [], - stock_status: 'instock', - }, - ], - }, - } - ); - const externalProductsJSON = await externalProducts.json(); - - return externalProductsJSON.create; - }; - - const createSampleGroupedProduct = async ( categories ) => { - const logoProducts = await request.get( '/wp-json/wc/v3/products', { - params: { - search: 'logo', - _fields: [ 'id' ], - }, - } ); - const logoProductsJSON = await logoProducts.json(); - - const groupedProducts = await request.post( - '/wp-json/wc/v3/products/batch', - { - data: { - create: [ - { - name: 'Logo Collection oxo', - date_created_gmt: '2021-09-17T15:50:20', - type: 'grouped', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description: - 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + - 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. ' + - 'Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n', - short_description: - 'This is a grouped product.
\n', - sku: 'logo-collection', - price: '18', - regular_price: '', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: false, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '', - dimensions: { - length: '', - width: '', - height: '', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.clothingJSON.id, - }, - ], - tags: [], - attributes: [], - default_attributes: [], - variations: [], - grouped_products: logoProductsJSON.map( - ( p ) => p.id - ), - menu_order: 0, - related_ids: [], - stock_status: 'instock', - }, - ], - }, - } - ); - const groupedProductsJSON = await groupedProducts.json(); - - return groupedProductsJSON.create; - }; - - const createSampleVariableProducts = async ( - categories, - attributes - ) => { - const description = - 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + - 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. ' + - 'Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n'; - - const hoodie = await request.post( '/wp-json/wc/v3/products', { - data: { - name: 'Hoodie oxo', - date_created_gmt: '2021-09-18T15:50:19', - type: 'variable', - status: 'publish', - featured: false, - catalog_visibility: 'visible', - description, - short_description: 'This is a variable product.
\n', - sku: 'woo-hoodie', - price: '42', - regular_price: '', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '1.5', - dimensions: { - length: '10', - width: '8', - height: '3', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.hoodiesJSON.id, + const accessories = await request.post( + '/wp-json/wc/v3/products/categories', + { + data: { + name: 'Accessories', + parent: clothingJSON.id, }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: true, - options: [ 'Blue', 'Green', 'Red' ], - }, - { - id: 0, - name: 'Logo', - position: 1, - visible: true, - variation: true, - options: [ 'Yes', 'No' ], - }, - ], - default_attributes: [], - grouped_products: [], - menu_order: 0, - stock_status: 'instock', - }, - } ); - const hoodieJSON = await hoodie.json(); + } + ); + const accessoriesJSON = await accessories.json(); - const variationDescription = - 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sagittis orci ac odio dictum tincidunt. ' + - 'Donec ut metus leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. ' + - 'Sed luctus, dui eu sagittis sodales, nulla nibh sagittis augue, vel porttitor diam enim non metus. ' + - 'Vestibulum aliquam augue neque. Phasellus tincidunt odio eget ullamcorper efficitur. ' + - 'Cras placerat ut turpis pellentesque vulputate. Nam sed consequat tortor. Curabitur finibus sapien dolor. ' + - 'Ut eleifend tellus nec erat pulvinar dignissim. Nam non arcu purus. Vivamus et massa massa.
\n'; - - const hoodieVariations = await request.post( - `/wp-json/wc/v3/products/${ hoodieJSON.id }/variations/batch`, - { - data: { - create: [ - { - date_created_gmt: '2021-09-19T15:50:20', - description: variationDescription, - sku: 'woo-hoodie-blue-logo', - price: '45', - regular_price: '45', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - status: 'publish', - purchasable: true, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - stock_status: 'instock', - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - weight: '1.5', - dimensions: { - length: '10', - width: '8', - height: '3', - }, - shipping_class: '', - attributes: [ - { - id: attributes.colorJSON.id, - option: 'Blue', - }, - { - id: 0, - name: 'Logo', - option: 'Yes', - }, - ], - menu_order: 0, - }, - { - date_created_gmt: '2021-09-20T15:50:20', - description: variationDescription, - sku: 'woo-hoodie-blue', - price: '45', - regular_price: '45', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - status: 'publish', - purchasable: true, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - stock_status: 'instock', - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - weight: '1.5', - dimensions: { - length: '10', - width: '8', - height: '3', - }, - shipping_class: '', - attributes: [ - { - id: attributes.colorJSON.id, - option: 'Blue', - }, - { - id: 0, - name: 'Logo', - option: 'No', - }, - ], - menu_order: 3, - }, - { - date_created_gmt: '2021-09-21T15:50:20', - description: variationDescription, - sku: 'woo-hoodie-green', - price: '45', - regular_price: '45', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - status: 'publish', - purchasable: true, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - stock_status: 'instock', - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - weight: '1.5', - dimensions: { - length: '10', - width: '8', - height: '3', - }, - shipping_class: '', - attributes: [ - { - id: attributes.colorJSON.id, - option: 'Green', - }, - { - id: 0, - name: 'Logo', - option: 'No', - }, - ], - menu_order: 2, - }, - { - date_created_gmt: '2021-09-22T15:50:19', - description: variationDescription, - sku: 'woo-hoodie-red', - price: '42', - regular_price: '45', - sale_price: '42', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: true, - status: 'publish', - purchasable: true, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - stock_status: 'instock', - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - weight: '1.5', - dimensions: { - length: '10', - width: '8', - height: '3', - }, - shipping_class: '', - attributes: [ - { - id: attributes.colorJSON.id, - option: 'Red', - }, - { - id: 0, - name: 'Logo', - option: 'No', - }, - ], - menu_order: 1, - }, - ], - }, - } - ); - const hoodieVariationsJSON = await hoodieVariations.json(); - - const vneck = await request.post( '/wp-json/wc/v3/products', { - data: { - name: 'V-Neck T-Shirt oxo', - date_created_gmt: '2021-09-23T15:50:19', - type: 'variable', - status: 'publish', - featured: true, - catalog_visibility: 'visible', - description, - short_description: 'This is a variable product.
\n', - sku: 'woo-vneck-tee', - price: '15', - regular_price: '', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - purchasable: true, - total_sales: 0, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - external_url: '', - button_text: '', - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - sold_individually: false, - weight: '0.5', - dimensions: { - length: '24', - width: '1', - height: '2', - }, - shipping_required: true, - shipping_taxable: true, - shipping_class: '', - reviews_allowed: true, - average_rating: '0.00', - rating_count: 0, - upsell_ids: [], - cross_sell_ids: [], - parent_id: 0, - purchase_note: '', - categories: [ - { - id: categories.tshirtsJSON.id, + const hoodies = await request.post( + '/wp-json/wc/v3/products/categories', + { + data: { + name: 'Hoodies', + parent: clothingJSON.id, }, - ], - tags: [], - attributes: [ - { - id: attributes.colorJSON.id, - position: 0, - visible: true, - variation: true, - options: [ 'Blue', 'Green', 'Red' ], - }, - { - id: attributes.sizeJSON.id, - position: 1, - visible: true, - variation: true, - options: [ 'Large', 'Medium', 'Small' ], - }, - ], - default_attributes: [], - grouped_products: [], - menu_order: 0, - stock_status: 'instock', - }, - } ); - const vneckJSON = await vneck.json(); + } + ); + const hoodiesJSON = await hoodies.json(); - const vneckVariations = await request.post( - `/wp-json/wc/v3/products/${ vneckJSON.id }/variations/batch`, - { - data: { - create: [ - { - date_created_gmt: '2021-09-24T15:50:19', - description: variationDescription, - sku: 'woo-vneck-tee-blue', - price: '15', - regular_price: '15', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - status: 'publish', - purchasable: true, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - stock_status: 'instock', - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - weight: '0.5', - dimensions: { - length: '24', - width: '1', - height: '2', - }, - shipping_class: '', - attributes: [ - { - id: attributes.colorJSON.id, - option: 'Blue', - }, - ], - menu_order: 0, - }, - { - date_created_gmt: '2021-09-25T15:50:19', - description: variationDescription, - sku: 'woo-vneck-tee-green', - price: '20', - regular_price: '20', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - status: 'publish', - purchasable: true, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - stock_status: 'instock', - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - weight: '0.5', - dimensions: { - length: '24', - width: '1', - height: '2', - }, - shipping_class: '', - attributes: [ - { - id: attributes.colorJSON.id, - option: 'Green', - }, - ], - menu_order: 0, - }, - { - date_created_gmt: '2021-09-26T15:50:19', - description: variationDescription, - sku: 'woo-vneck-tee-red', - price: '20', - regular_price: '20', - sale_price: '', - date_on_sale_from_gmt: null, - date_on_sale_to_gmt: null, - on_sale: false, - status: 'publish', - purchasable: true, - virtual: false, - downloadable: false, - downloads: [], - download_limit: 0, - download_expiry: 0, - tax_status: 'taxable', - tax_class: '', - manage_stock: false, - stock_quantity: null, - stock_status: 'instock', - backorders: 'no', - backorders_allowed: false, - backordered: false, - low_stock_amount: null, - weight: '0.5', - dimensions: { - length: '24', - width: '1', - height: '2', - }, - shipping_class: '', - attributes: [ - { - id: attributes.colorJSON.id, - option: 'Red', - }, - ], - menu_order: 0, - }, - ], - }, - } - ); - const vneckVariationsJSON = await vneckVariations.json(); + const tshirts = await request.post( + '/wp-json/wc/v3/products/categories', + { + data: { + name: 'Tshirts', + parent: clothingJSON.id, + }, + } + ); + const tshirtsJSON = await tshirts.json(); - return { - hoodieJSON, - hoodieVariations: hoodieVariationsJSON.create, - vneckJSON, - vneckVariations: vneckVariationsJSON.create, + const decor = await request.post( + '/wp-json/wc/v3/products/categories', + { + data: { + name: 'Decor', + }, + } + ); + const decorJSON = await decor.json(); + + const music = await request.post( + '/wp-json/wc/v3/products/categories', + { + data: { + name: 'Music', + }, + } + ); + const musicJSON = await music.json(); + + return { + clothingJSON, + accessoriesJSON, + hoodiesJSON, + tshirtsJSON, + decorJSON, + musicJSON, + }; }; - }; - const createSampleHierarchicalProducts = async () => { - const parent = await request.post( '/wp-json/wc/v3/products', { - data: { - name: 'Parent Product oxo', - date_created_gmt: '2021-09-27T15:50:19', - }, - } ); - const parentJSON = await parent.json(); + const createSampleAttributes = async () => { + const color = await request.post( + '/wp-json/wc/v3/products/attributes', + { + data: { + name: 'Color', + }, + } + ); + const colorJSON = await color.json(); - const child = await request.post( '/wp-json/wc/v3/products', { - data: { - name: 'Child Product oxo', - parent_id: parentJSON.id, - date_created_gmt: '2021-09-28T15:50:19', - }, - } ); - const childJSON = await child.json(); + const size = await request.post( + '/wp-json/wc/v3/products/attributes', + { + data: { + name: 'Size', + }, + } + ); + const sizeJSON = await size.json(); - return { - parentJSON, - childJSON, + const colorNames = [ 'Blue', 'Gray', 'Green', 'Red', 'Yellow' ]; + + const colorNamesObjectArray = colorNames.map( ( name ) => ( { + name, + } ) ); + + const colors = await request.post( + `/wp-json/wc/v3/products/attributes/${ colorJSON.id }/terms/batch`, + { + data: { + create: colorNamesObjectArray, + }, + } + ); + + const colorsJSON = await colors.json(); + + const sizeNames = [ 'Large', 'Medium', 'Small' ]; + + const sizeNamesObjectArray = sizeNames.map( ( name ) => ( { + name, + } ) ); + + const sizes = await request.post( + `/wp-json/wc/v3/products/attributes/${ sizeJSON.id }/terms/batch`, + { + data: { + create: sizeNamesObjectArray, + }, + } + ); + const sizesJSON = await sizes.json(); + + return { + colorJSON, + colors: colorsJSON.create, + sizeJSON, + sizes: sizesJSON.create, + }; }; - }; - const createSampleProductReviews = async ( simpleProducts ) => { - const cap = simpleProducts.find( ( p ) => p.name === 'Cap oxo' ); - - const shirt = simpleProducts.find( - ( p ) => p.name === 'T-Shirt oxo' - ); - - const sunglasses = simpleProducts.find( - ( p ) => p.name === 'Sunglasses oxo' - ); - - const review1 = await request.post( - '/wp-json/wc/v3/products/reviews', - { - data: { - product_id: cap.id, - rating: 3, - review: 'Decent cap.', - reviewer: 'John Doe', - reviewer_email: 'john.doe@example.com', - }, - } - ); - const review1JSON = await review1.json(); - - // We need to update the review in order for the product's - // average_rating to be recalculated. - // See: https://github.com/woocommerce/woocommerce/issues/29906. - //await updateProductReview(review1.id); - await request.post( - `/wp-json/wc/v3/products/reviews/${ review1JSON.id }`, - { - data: {}, - } - ); - - const review2 = await request.post( - '/wp-json/wc/v3/products/reviews', - { - data: { - product_id: shirt.id, - rating: 5, - review: 'The BEST shirt ever!!', - reviewer: 'Shannon Smith', - reviewer_email: 'shannon.smith@example.com', - }, - } - ); - const review2JSON = await review2.json(); - - //await updateProductReview(review2.id); - await request.post( - `/wp-json/wc/v3/products/reviews/${ review2JSON.id }`, - { - data: {}, - } - ); - - const review3 = await request.post( - '/wp-json/wc/v3/products/reviews', - { - data: { - product_id: sunglasses.id, - rating: 1, - review: 'These are way too expensive.', - reviewer: 'Tim Frugalman', - reviewer_email: 'timmyfrufru@example.com', - }, - } - ); - const review3JSON = await review3.json(); - - await request.post( - `/wp-json/wc/v3/products/reviews/${ review3JSON.id }`, - { - data: {}, - } - ); - - return [ review1JSON.id, review2JSON.id, review3JSON.id ]; - }; - - const createSampleProductOrders = async ( simpleProducts ) => { - const single = simpleProducts.find( - ( p ) => p.name === 'Single oxo' - ); - const beanie = simpleProducts.find( - ( p ) => p.name === 'Beanie with Logo oxo' - ); - const shirt = simpleProducts.find( - ( p ) => p.name === 'T-Shirt oxo' - ); - - const order1 = await request.post( '/wp-json/wc/v3/orders', { - data: { - set_paid: true, - status: 'completed', - line_items: [ - { - product_id: single.id, - quantity: 2, + const createSampleTags = async () => { + const cool = await request.post( + '/wp-json/wc/v3/products/tags', + { + data: { + name: 'Cool', }, - { - product_id: beanie.id, - quantity: 3, + } + ); + const coolJSON = await cool.json(); + + return { + coolJSON, + }; + }; + + const createSampleShippingClasses = async () => { + const freight = await request.post( + '/wp-json/wc/v3/products/shipping_classes', + { + data: { + name: 'Freight', }, + } + ); + const freightJSON = await freight.json(); + + return { + freightJSON, + }; + }; + + const createSampleTaxClasses = async () => { + //check to see if Reduced Rate tax class exists - if not, create it + let reducedRate = await request.get( + '/wp-json/wc/v3/taxes/classes/reduced-rate' + ); + let reducedRateJSON = await reducedRate.json(); + expect( Array.isArray( reducedRateJSON ) ).toBe( true ); + + //if tax class does not exist then create it + if ( reducedRateJSON.length < 1 ) { + reducedRate = await request.post( + '/wp-json/wc/v3/taxes/classes', { - product_id: shirt.id, - quantity: 1, - }, - ], - }, - } ); - const orderJSON = await order1.json(); + data: { + name: 'Reduced Rate', + }, + } + ); + reducedRateJSON = await reducedRate.json(); + return { reducedRateJSON }; + } - return [ orderJSON ]; - }; + // return an empty object as nothing new was created so nothing will + // need deleted during cleanup + return {}; + }; - const productsTestSetupCreateSampleData = async () => { - const categories = await createSampleCategories(); - - const attributes = await createSampleAttributes(); - - const tags = await createSampleTags(); - - const shippingClasses = await createSampleShippingClasses(); - - const taxClasses = await createSampleTaxClasses(); - - const simpleProducts = await createSampleSimpleProducts( + const createSampleSimpleProducts = async ( categories, attributes, tags - ); + ) => { + const description = + 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + + 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. ' + + 'Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n'; - const externalProducts = await createSampleExternalProducts( - categories - ); + const simpleProducts = await request.post( + '/wp-json/wc/v3/products/batch', + { + data: { + create: [ + { + name: 'Beanie with Logo oxo', + date_created_gmt: '2021-09-01T15:50:20', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'Woo-beanie-logo', + price: '18', + regular_price: '20', + sale_price: '18', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.2', + dimensions: { + length: '6', + width: '4', + height: '1', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.accessoriesJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Red' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 62, 63, 61, 60 ], + stock_status: 'instock', + }, + { + name: 'T-Shirt with Logo oxo', + date_created_gmt: '2021-09-02T15:50:20', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'Woo-tshirt-logo', + price: '18', + regular_price: '18', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.5', + dimensions: { + length: '10', + width: '12', + height: '0.5', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.tshirtsJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Gray' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 59, 67, 66, 56 ], + stock_status: 'instock', + }, + { + name: 'Single oxo', + date_created_gmt: '2021-09-03T15:50:19', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple, virtual product.
\n', + sku: 'woo-single', + price: '2', + regular_price: '3', + sale_price: '2', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: true, + total_sales: 0, + virtual: true, + downloadable: true, + downloads: [ + { + id: '2579cf07-8b08-4c25-888a-b6258dd1f035', + name: 'Single', + file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg', + }, + ], + download_limit: 1, + download_expiry: 1, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '', + dimensions: { + length: '', + width: '', + height: '', + }, + shipping_required: false, + shipping_taxable: false, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.musicJSON.id, + }, + ], + tags: [], + attributes: [], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 68 ], + stock_status: 'instock', + }, + { + name: 'Album oxo', + date_created_gmt: '2021-09-04T15:50:19', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple, virtual product.
\n', + sku: 'woo-album', + price: '15', + regular_price: '15', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: true, + downloadable: true, + downloads: [ + { + id: 'cc10249f-1de2-44d4-93d3-9f88ae629f76', + name: 'Single 1', + file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/single.jpg', + }, + { + id: 'aea8ef69-ccdc-4d83-8e21-3c395ebb9411', + name: 'Single 2', + file: 'https://demo.woothemes.com/woocommerce/wp-content/uploads/sites/56/2017/08/album.jpg', + }, + ], + download_limit: 1, + download_expiry: 1, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '', + dimensions: { + length: '', + width: '', + height: '', + }, + shipping_required: false, + shipping_taxable: false, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.musicJSON.id, + }, + ], + tags: [], + attributes: [], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 69 ], + stock_status: 'instock', + }, + { + name: 'Polo oxo', + date_created_gmt: '2021-09-05T15:50:19', + type: 'simple', + status: 'pending', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-polo', + price: '20', + regular_price: '20', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.8', + dimensions: { + length: '6', + width: '5', + height: '1', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.tshirtsJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Blue' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 59, 56, 66, 76 ], + stock_status: 'instock', + }, + { + name: 'Long Sleeve Tee oxo', + date_created_gmt: '2021-09-06T15:50:19', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-long-sleeve-tee', + price: '25', + regular_price: '25', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '1', + dimensions: { + length: '7', + width: '5', + height: '1', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: 'freight', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.tshirtsJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Green' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 59, 56, 76, 67 ], + stock_status: 'instock', + }, + { + name: 'Hoodie with Zipper oxo', + date_created_gmt: '2021-09-07T15:50:19', + type: 'simple', + status: 'publish', + featured: true, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-hoodie-with-zipper', + price: '45', + regular_price: '45', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '2', + dimensions: { + length: '8', + width: '6', + height: '2', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.hoodiesJSON.id, + }, + ], + tags: [], + attributes: [], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 57, 58 ], + stock_status: 'instock', + }, + { + name: 'Hoodie with Pocket oxo', + date_created_gmt: '2021-09-08T15:50:19', + type: 'simple', + status: 'publish', + featured: true, + catalog_visibility: 'hidden', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-hoodie-with-pocket', + price: '35', + regular_price: '45', + sale_price: '35', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '3', + dimensions: { + length: '10', + width: '8', + height: '2', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.hoodiesJSON.id, + }, + ], + tags: [ + { + id: tags.coolJSON.id, + }, + ], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Gray' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 65, 57, 58 ], + stock_status: 'instock', + }, + { + name: 'Sunglasses oxo', + date_created_gmt: '2021-09-09T15:50:19', + type: 'simple', + status: 'publish', + featured: true, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-sunglasses', + price: '90', + regular_price: '90', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: 'reduced-rate', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.2', + dimensions: { + length: '4', + width: '1.4', + height: '1', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.accessoriesJSON.id, + }, + ], + tags: [ + { + id: tags.coolJSON.id, + }, + ], + attributes: [], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 60, 62, 77, 61 ], + stock_status: 'instock', + }, + { + name: 'Cap oxo', + date_created_gmt: '2021-09-10T15:50:19', + type: 'simple', + status: 'publish', + featured: true, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-cap', + price: '16', + regular_price: '18', + sale_price: '16', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.6', + dimensions: { + length: '8', + width: '6.5', + height: '4', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.accessoriesJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Yellow' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 60, 77, 61, 63 ], + stock_status: 'instock', + }, + { + name: 'Belt oxo', + date_created_gmt: '2021-09-12T15:50:19', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-belt', + price: '55', + regular_price: '65', + sale_price: '55', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '1.2', + dimensions: { + length: '12', + width: '2', + height: '1.5', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.accessoriesJSON.id, + }, + ], + tags: [], + attributes: [], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 63, 77, 62, 60 ], + stock_status: 'instock', + }, + { + name: 'Beanie oxo', + date_created_gmt: '2021-09-13T15:50:19', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-beanie', + price: '18', + regular_price: '20', + sale_price: '18', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.2', + dimensions: { + length: '4', + width: '5', + height: '0.5', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.accessoriesJSON.id, + }, + ], + tags: [ + { + id: tags.coolJSON.id, + }, + ], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Red' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 63, 62, 61, 77 ], + stock_status: 'instock', + }, + { + name: 'T-Shirt oxo', + date_created_gmt: '2021-09-14T15:50:19', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-tshirt', + price: '18', + regular_price: '18', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.8', + dimensions: { + length: '8', + width: '6', + height: '1', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.tshirtsJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Gray' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 67, 76, 56, 66 ], + stock_status: 'onbackorder', + }, + { + name: 'Hoodie with Logo oxo', + date_created_gmt: '2021-09-15T15:50:19', + type: 'simple', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a simple product.
\n', + sku: 'woo-hoodie-with-logo', + price: '45', + regular_price: '45', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '2', + dimensions: { + length: '10', + width: '6', + height: '3', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.hoodiesJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: false, + options: [ 'Blue' ], + }, + ], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [ 57, 65 ], + stock_status: 'instock', + }, + ], + }, + } + ); + const simpleProductsJSON = await simpleProducts.json(); - const groupedProducts = await createSampleGroupedProduct( - categories - ); + return simpleProductsJSON.create; + }; - const variableProducts = await createSampleVariableProducts( + const createSampleExternalProducts = async ( categories ) => { + const externalProducts = await request.post( + '/wp-json/wc/v3/products/batch', + { + data: { + create: [ + { + name: 'WordPress Pennant oxo', + date_created_gmt: '2021-09-16T15:50:20', + type: 'external', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description: + 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + + 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. ' + + 'Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n', + short_description: + 'This is an external product.
\n', + sku: 'wp-pennant', + price: '11.05', + regular_price: '11.05', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: false, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: + 'https://mercantile.wordpress.org/product/wordpress-pennant/', + button_text: + 'Buy on the WordPress swag store!', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '', + dimensions: { + length: '', + width: '', + height: '', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.decorJSON.id, + }, + ], + tags: [], + attributes: [], + default_attributes: [], + variations: [], + grouped_products: [], + menu_order: 0, + related_ids: [], + stock_status: 'instock', + }, + ], + }, + } + ); + const externalProductsJSON = await externalProducts.json(); + + return externalProductsJSON.create; + }; + + const createSampleGroupedProduct = async ( categories ) => { + const logoProducts = await request.get( + '/wp-json/wc/v3/products', + { + params: { + search: 'logo', + _fields: [ 'id' ], + }, + } + ); + const logoProductsJSON = await logoProducts.json(); + + const groupedProducts = await request.post( + '/wp-json/wc/v3/products/batch', + { + data: { + create: [ + { + name: 'Logo Collection oxo', + date_created_gmt: '2021-09-17T15:50:20', + type: 'grouped', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description: + 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + + 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. ' + + 'Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n', + short_description: + 'This is a grouped product.
\n', + sku: 'logo-collection', + price: '18', + regular_price: '', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: false, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '', + dimensions: { + length: '', + width: '', + height: '', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.clothingJSON.id, + }, + ], + tags: [], + attributes: [], + default_attributes: [], + variations: [], + grouped_products: logoProductsJSON.map( + ( p ) => p.id + ), + menu_order: 0, + related_ids: [], + stock_status: 'instock', + }, + ], + }, + } + ); + const groupedProductsJSON = await groupedProducts.json(); + + return groupedProductsJSON.create; + }; + + const createSampleVariableProducts = async ( categories, attributes - ); + ) => { + const description = + 'Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. ' + + 'Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. ' + + 'Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo.
\n'; - const hierarchicalProducts = - await createSampleHierarchicalProducts(); + const hoodie = await request.post( '/wp-json/wc/v3/products', { + data: { + name: 'Hoodie oxo', + date_created_gmt: '2021-09-18T15:50:19', + type: 'variable', + status: 'publish', + featured: false, + catalog_visibility: 'visible', + description, + short_description: + 'This is a variable product.
\n', + sku: 'woo-hoodie', + price: '42', + regular_price: '', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '1.5', + dimensions: { + length: '10', + width: '8', + height: '3', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.hoodiesJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: true, + options: [ 'Blue', 'Green', 'Red' ], + }, + { + id: 0, + name: 'Logo', + position: 1, + visible: true, + variation: true, + options: [ 'Yes', 'No' ], + }, + ], + default_attributes: [], + grouped_products: [], + menu_order: 0, + stock_status: 'instock', + }, + } ); + const hoodieJSON = await hoodie.json(); - const reviewIds = await createSampleProductReviews( - simpleProducts - ); + const variationDescription = + 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum sagittis orci ac odio dictum tincidunt. ' + + 'Donec ut metus leo. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. ' + + 'Sed luctus, dui eu sagittis sodales, nulla nibh sagittis augue, vel porttitor diam enim non metus. ' + + 'Vestibulum aliquam augue neque. Phasellus tincidunt odio eget ullamcorper efficitur. ' + + 'Cras placerat ut turpis pellentesque vulputate. Nam sed consequat tortor. Curabitur finibus sapien dolor. ' + + 'Ut eleifend tellus nec erat pulvinar dignissim. Nam non arcu purus. Vivamus et massa massa.
\n'; - const orders = await createSampleProductOrders( simpleProducts ); + const hoodieVariations = await request.post( + `/wp-json/wc/v3/products/${ hoodieJSON.id }/variations/batch`, + { + data: { + create: [ + { + date_created_gmt: '2021-09-19T15:50:20', + description: variationDescription, + sku: 'woo-hoodie-blue-logo', + price: '45', + regular_price: '45', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + status: 'publish', + purchasable: true, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + stock_status: 'instock', + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + weight: '1.5', + dimensions: { + length: '10', + width: '8', + height: '3', + }, + shipping_class: '', + attributes: [ + { + id: attributes.colorJSON.id, + option: 'Blue', + }, + { + id: 0, + name: 'Logo', + option: 'Yes', + }, + ], + menu_order: 0, + }, + { + date_created_gmt: '2021-09-20T15:50:20', + description: variationDescription, + sku: 'woo-hoodie-blue', + price: '45', + regular_price: '45', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + status: 'publish', + purchasable: true, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + stock_status: 'instock', + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + weight: '1.5', + dimensions: { + length: '10', + width: '8', + height: '3', + }, + shipping_class: '', + attributes: [ + { + id: attributes.colorJSON.id, + option: 'Blue', + }, + { + id: 0, + name: 'Logo', + option: 'No', + }, + ], + menu_order: 3, + }, + { + date_created_gmt: '2021-09-21T15:50:20', + description: variationDescription, + sku: 'woo-hoodie-green', + price: '45', + regular_price: '45', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + status: 'publish', + purchasable: true, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + stock_status: 'instock', + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + weight: '1.5', + dimensions: { + length: '10', + width: '8', + height: '3', + }, + shipping_class: '', + attributes: [ + { + id: attributes.colorJSON.id, + option: 'Green', + }, + { + id: 0, + name: 'Logo', + option: 'No', + }, + ], + menu_order: 2, + }, + { + date_created_gmt: '2021-09-22T15:50:19', + description: variationDescription, + sku: 'woo-hoodie-red', + price: '42', + regular_price: '45', + sale_price: '42', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: true, + status: 'publish', + purchasable: true, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + stock_status: 'instock', + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + weight: '1.5', + dimensions: { + length: '10', + width: '8', + height: '3', + }, + shipping_class: '', + attributes: [ + { + id: attributes.colorJSON.id, + option: 'Red', + }, + { + id: 0, + name: 'Logo', + option: 'No', + }, + ], + menu_order: 1, + }, + ], + }, + } + ); + const hoodieVariationsJSON = await hoodieVariations.json(); - return { - categories, - attributes, - tags, - shippingClasses, - taxClasses, - simpleProducts, - externalProducts, - groupedProducts, - variableProducts, - hierarchicalProducts, - reviewIds, - orders, + const vneck = await request.post( '/wp-json/wc/v3/products', { + data: { + name: 'V-Neck T-Shirt oxo', + date_created_gmt: '2021-09-23T15:50:19', + type: 'variable', + status: 'publish', + featured: true, + catalog_visibility: 'visible', + description, + short_description: + 'This is a variable product.
\n', + sku: 'woo-vneck-tee', + price: '15', + regular_price: '', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + purchasable: true, + total_sales: 0, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + external_url: '', + button_text: '', + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + sold_individually: false, + weight: '0.5', + dimensions: { + length: '24', + width: '1', + height: '2', + }, + shipping_required: true, + shipping_taxable: true, + shipping_class: '', + reviews_allowed: true, + average_rating: '0.00', + rating_count: 0, + upsell_ids: [], + cross_sell_ids: [], + parent_id: 0, + purchase_note: '', + categories: [ + { + id: categories.tshirtsJSON.id, + }, + ], + tags: [], + attributes: [ + { + id: attributes.colorJSON.id, + position: 0, + visible: true, + variation: true, + options: [ 'Blue', 'Green', 'Red' ], + }, + { + id: attributes.sizeJSON.id, + position: 1, + visible: true, + variation: true, + options: [ 'Large', 'Medium', 'Small' ], + }, + ], + default_attributes: [], + grouped_products: [], + menu_order: 0, + stock_status: 'instock', + }, + } ); + const vneckJSON = await vneck.json(); + + const vneckVariations = await request.post( + `/wp-json/wc/v3/products/${ vneckJSON.id }/variations/batch`, + { + data: { + create: [ + { + date_created_gmt: '2021-09-24T15:50:19', + description: variationDescription, + sku: 'woo-vneck-tee-blue', + price: '15', + regular_price: '15', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + status: 'publish', + purchasable: true, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + stock_status: 'instock', + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + weight: '0.5', + dimensions: { + length: '24', + width: '1', + height: '2', + }, + shipping_class: '', + attributes: [ + { + id: attributes.colorJSON.id, + option: 'Blue', + }, + ], + menu_order: 0, + }, + { + date_created_gmt: '2021-09-25T15:50:19', + description: variationDescription, + sku: 'woo-vneck-tee-green', + price: '20', + regular_price: '20', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + status: 'publish', + purchasable: true, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + stock_status: 'instock', + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + weight: '0.5', + dimensions: { + length: '24', + width: '1', + height: '2', + }, + shipping_class: '', + attributes: [ + { + id: attributes.colorJSON.id, + option: 'Green', + }, + ], + menu_order: 0, + }, + { + date_created_gmt: '2021-09-26T15:50:19', + description: variationDescription, + sku: 'woo-vneck-tee-red', + price: '20', + regular_price: '20', + sale_price: '', + date_on_sale_from_gmt: null, + date_on_sale_to_gmt: null, + on_sale: false, + status: 'publish', + purchasable: true, + virtual: false, + downloadable: false, + downloads: [], + download_limit: 0, + download_expiry: 0, + tax_status: 'taxable', + tax_class: '', + manage_stock: false, + stock_quantity: null, + stock_status: 'instock', + backorders: 'no', + backorders_allowed: false, + backordered: false, + low_stock_amount: null, + weight: '0.5', + dimensions: { + length: '24', + width: '1', + height: '2', + }, + shipping_class: '', + attributes: [ + { + id: attributes.colorJSON.id, + option: 'Red', + }, + ], + menu_order: 0, + }, + ], + }, + } + ); + const vneckVariationsJSON = await vneckVariations.json(); + + return { + hoodieJSON, + hoodieVariations: hoodieVariationsJSON.create, + vneckJSON, + vneckVariations: vneckVariationsJSON.create, + }; }; - }; - // create Sample Data function - const createSampleData = async () => { - const testProductData = await productsTestSetupCreateSampleData(); - const orderedProducts = { - pocketHoodie: testProductData.simpleProducts.find( - ( p ) => p.name === 'Hoodie with Pocket oxo' - ), - sunglasses: testProductData.simpleProducts.find( + const createSampleHierarchicalProducts = async () => { + const parent = await request.post( '/wp-json/wc/v3/products', { + data: { + name: 'Parent Product oxo', + date_created_gmt: '2021-09-27T15:50:19', + }, + } ); + const parentJSON = await parent.json(); + + const child = await request.post( '/wp-json/wc/v3/products', { + data: { + name: 'Child Product oxo', + parent_id: parentJSON.id, + date_created_gmt: '2021-09-28T15:50:19', + }, + } ); + const childJSON = await child.json(); + + return { + parentJSON, + childJSON, + }; + }; + + const createSampleProductReviews = async ( simpleProducts ) => { + const cap = simpleProducts.find( + ( p ) => p.name === 'Cap oxo' + ); + + const shirt = simpleProducts.find( + ( p ) => p.name === 'T-Shirt oxo' + ); + + const sunglasses = simpleProducts.find( ( p ) => p.name === 'Sunglasses oxo' - ), - beanie: testProductData.simpleProducts.find( - ( p ) => p.name === 'Beanie oxo' - ), - blueVneck: - testProductData.variableProducts.vneckVariations.find( - ( p ) => p.sku === 'woo-vneck-tee-blue' + ); + + const review1 = await request.post( + '/wp-json/wc/v3/products/reviews', + { + data: { + product_id: cap.id, + rating: 3, + review: 'Decent cap.', + reviewer: 'John Doe', + reviewer_email: 'john.doe@example.com', + }, + } + ); + const review1JSON = await review1.json(); + + // We need to update the review in order for the product's + // average_rating to be recalculated. + // See: https://github.com/woocommerce/woocommerce/issues/29906. + //await updateProductReview(review1.id); + await request.post( + `/wp-json/wc/v3/products/reviews/${ review1JSON.id }`, + { + data: {}, + } + ); + + const review2 = await request.post( + '/wp-json/wc/v3/products/reviews', + { + data: { + product_id: shirt.id, + rating: 5, + review: 'The BEST shirt ever!!', + reviewer: 'Shannon Smith', + reviewer_email: 'shannon.smith@example.com', + }, + } + ); + const review2JSON = await review2.json(); + + //await updateProductReview(review2.id); + await request.post( + `/wp-json/wc/v3/products/reviews/${ review2JSON.id }`, + { + data: {}, + } + ); + + const review3 = await request.post( + '/wp-json/wc/v3/products/reviews', + { + data: { + product_id: sunglasses.id, + rating: 1, + review: 'These are way too expensive.', + reviewer: 'Tim Frugalman', + reviewer_email: 'timmyfrufru@example.com', + }, + } + ); + const review3JSON = await review3.json(); + + await request.post( + `/wp-json/wc/v3/products/reviews/${ review3JSON.id }`, + { + data: {}, + } + ); + + return [ review1JSON.id, review2JSON.id, review3JSON.id ]; + }; + + const createSampleProductOrders = async ( simpleProducts ) => { + const single = simpleProducts.find( + ( p ) => p.name === 'Single oxo' + ); + const beanie = simpleProducts.find( + ( p ) => p.name === 'Beanie with Logo oxo' + ); + const shirt = simpleProducts.find( + ( p ) => p.name === 'T-Shirt oxo' + ); + + const order1 = await request.post( '/wp-json/wc/v3/orders', { + data: { + set_paid: true, + status: 'completed', + line_items: [ + { + product_id: single.id, + quantity: 2, + }, + { + product_id: beanie.id, + quantity: 3, + }, + { + product_id: shirt.id, + quantity: 1, + }, + ], + }, + } ); + const orderJSON = await order1.json(); + + return [ orderJSON ]; + }; + + const productsTestSetupCreateSampleData = async () => { + const categories = await createSampleCategories(); + + const attributes = await createSampleAttributes(); + + const tags = await createSampleTags(); + + const shippingClasses = await createSampleShippingClasses(); + + const taxClasses = await createSampleTaxClasses(); + + const simpleProducts = await createSampleSimpleProducts( + categories, + attributes, + tags + ); + + const externalProducts = await createSampleExternalProducts( + categories + ); + + const groupedProducts = await createSampleGroupedProduct( + categories + ); + + const variableProducts = await createSampleVariableProducts( + categories, + attributes + ); + + const hierarchicalProducts = + await createSampleHierarchicalProducts(); + + const reviewIds = await createSampleProductReviews( + simpleProducts + ); + + const orders = await createSampleProductOrders( + simpleProducts + ); + + return { + categories, + attributes, + tags, + shippingClasses, + taxClasses, + simpleProducts, + externalProducts, + groupedProducts, + variableProducts, + hierarchicalProducts, + reviewIds, + orders, + }; + }; + + // create Sample Data function + const createSampleData = async () => { + const testProductData = + await productsTestSetupCreateSampleData(); + const orderedProducts = { + pocketHoodie: testProductData.simpleProducts.find( + ( p ) => p.name === 'Hoodie with Pocket oxo' ), - pennant: testProductData.externalProducts[ 0 ], - }; + sunglasses: testProductData.simpleProducts.find( + ( p ) => p.name === 'Sunglasses oxo' + ), + beanie: testProductData.simpleProducts.find( + ( p ) => p.name === 'Beanie oxo' + ), + blueVneck: + testProductData.variableProducts.vneckVariations.find( + ( p ) => p.sku === 'woo-vneck-tee-blue' + ), + pennant: testProductData.externalProducts[ 0 ], + }; - const johnAddress = { - first_name: 'John', - last_name: 'Doe', - company: 'Automattic', - country: 'US', - address_1: '60 29th Street', - address_2: '#343', - city: 'San Francisco', - state: 'CA', - postcode: '94110', - phone: '123456789', - }; - const tinaAddress = { - first_name: 'Tina', - last_name: 'Clark', - company: 'Automattic', - country: 'US', - address_1: 'Oxford Ave', - address_2: '', - city: 'Buffalo', - state: 'NY', - postcode: '14201', - phone: '123456789', - }; - const guestShippingAddress = { - first_name: 'Ano', - last_name: 'Nymous', - company: '', - country: 'US', - address_1: '0 Incognito St', - address_2: '', - city: 'Erie', - state: 'PA', - postcode: '16515', - phone: '123456789', - }; - const guestBillingAddress = { - first_name: 'Ben', - last_name: 'Efactor', - company: '', - country: 'US', - address_1: '200 W University Avenue', - address_2: '', - city: 'Gainesville', - state: 'FL', - postcode: '32601', - phone: '123456789', - email: 'ben.efactor@email.net', - }; - - const john = await request.post( '/wp-json/wc/v3/customers', { - data: { + const johnAddress = { first_name: 'John', last_name: 'Doe', - username: 'john.doe', - email: 'john.doe@example.com', - billing: { - ...johnAddress, - email: 'john.doe@example.com', - }, - shipping: johnAddress, - }, - } ); - const johnJSON = await john.json(); - - const tina = await request.post( '/wp-json/wc/v3/customers', { - data: { + company: 'Automattic', + country: 'US', + address_1: '60 29th Street', + address_2: '#343', + city: 'San Francisco', + state: 'CA', + postcode: '94110', + phone: '123456789', + }; + const tinaAddress = { first_name: 'Tina', last_name: 'Clark', - username: 'tina.clark', - email: 'tina.clark@example.com', - billing: { - ...tinaAddress, - email: 'tina.clark@example.com', - }, - shipping: tinaAddress, - }, - } ); - const tinaJSON = await tina.json(); + company: 'Automattic', + country: 'US', + address_1: 'Oxford Ave', + address_2: '', + city: 'Buffalo', + state: 'NY', + postcode: '14201', + phone: '123456789', + }; + const guestShippingAddress = { + first_name: 'Ano', + last_name: 'Nymous', + company: '', + country: 'US', + address_1: '0 Incognito St', + address_2: '', + city: 'Erie', + state: 'PA', + postcode: '16515', + phone: '123456789', + }; + const guestBillingAddress = { + first_name: 'Ben', + last_name: 'Efactor', + company: '', + country: 'US', + address_1: '200 W University Avenue', + address_2: '', + city: 'Gainesville', + state: 'FL', + postcode: '32601', + phone: '123456789', + email: 'ben.efactor@email.net', + }; - const orderBaseData = { - payment_method: 'cod', - payment_method_title: 'Cash on Delivery', - status: 'processing', - set_paid: false, - currency: 'USD', - customer_id: 0, - }; - - const orders = []; - // Have "John" order all products. - Object.values( orderedProducts ).forEach( async ( product ) => { - const order2 = await request.post( '/wp-json/wc/v3/orders', { + const john = await request.post( '/wp-json/wc/v3/customers', { data: { - ...orderBaseData, - customer_id: johnJSON.id, + first_name: 'John', + last_name: 'Doe', + username: 'john.doe', + email: 'john.doe@example.com', billing: { ...johnAddress, email: 'john.doe@example.com', }, shipping: johnAddress, - line_items: [ - { - product_id: product.id, - quantity: 1, - }, - ], }, } ); - const orderJSON = await order2.json(); + const johnJSON = await john.json(); - orders.push( orderJSON ); - } ); - - // Have "Tina" order some sunglasses and make a child order. - // This somewhat resembles a subscription renewal, but we're just testing the `parent` field. - const order2 = await request.post( '/wp-json/wc/v3/orders', { - data: { - ...orderBaseData, - status: 'completed', - set_paid: true, - customer_id: tinaJSON.id, - billing: { - ...tinaAddress, - email: 'tina.clark@example.com', - }, - shipping: tinaAddress, - line_items: [ - { - product_id: orderedProducts.sunglasses.id, - quantity: 1, - }, - ], - }, - } ); - const order2JSON = await order2.json(); - - orders.push( order2JSON ); - - // create child order by referencing a parent_id - const order3 = await request.post( '/wp-json/wc/v3/orders', { - data: { - ...orderBaseData, - parent_id: order2JSON.id, - customer_id: tinaJSON.id, - billing: { - ...tinaAddress, - email: 'tina.clark@example.com', - }, - shipping: tinaAddress, - line_items: [ - { - product_id: orderedProducts.sunglasses.id, - quantity: 1, - }, - ], - }, - } ); - const order3JSON = await order3.json(); - - orders.push( order3JSON ); - - // Guest order. - const guestOrder = await request.post( '/wp-json/wc/v3/orders', { - data: { - ...orderBaseData, - billing: guestBillingAddress, - shipping: guestShippingAddress, - line_items: [ - { - product_id: orderedProducts.pennant.id, - quantity: 2, - }, - { - product_id: orderedProducts.beanie.id, - quantity: 1, - }, - ], - }, - } ); - const guestOrderJSON = await guestOrder.json(); - - // Create an order with all possible numerical fields (taxes, fees, refunds, etc). - await request.put( - '/wp-json/wc/v3/settings/general/woocommerce_calc_taxes', - { + const tina = await request.post( '/wp-json/wc/v3/customers', { data: { - value: 'yes', + first_name: 'Tina', + last_name: 'Clark', + username: 'tina.clark', + email: 'tina.clark@example.com', + billing: { + ...tinaAddress, + email: 'tina.clark@example.com', + }, + shipping: tinaAddress, }, - } - ); + } ); + const tinaJSON = await tina.json(); - await request.post( '/wp-json/wc/v3/taxes', { - data: { - country: '*', - state: '*', - postcode: '*', - city: '*', - name: 'Tax', - rate: '5.5', - shipping: true, - }, - } ); + const orderBaseData = { + payment_method: 'cod', + payment_method_title: 'Cash on Delivery', + status: 'processing', + set_paid: false, + currency: 'USD', + customer_id: 0, + }; - const coupon = await request.post( '/wp-json/wc/v3/coupons', { - data: { - code: 'save5', - amount: '5', - }, - } ); - const couponJSON = await coupon.json(); - - const order4 = await request.post( '/wp-json/wc/v3/orders', { - data: { - ...orderBaseData, - line_items: [ + const orders = []; + // Have "John" order all products. + Object.values( orderedProducts ).forEach( async ( product ) => { + const order2 = await request.post( + '/wp-json/wc/v3/orders', { - product_id: orderedProducts.blueVneck.id, - quantity: 1, - }, - ], - coupon_lines: [ - { - code: 'save5', - }, - ], - shipping_lines: [ - { - method_id: 'flat_rate', - total: '5.00', - }, - ], - fee_lines: [ - { - total: '1.00', - name: 'Test Fee', - }, - ], - }, - } ); - const order4JSON = await order4.json(); - - await request.post( - `/wp-json/wc/v3/orders/${ order4JSON.id }/refunds`, - { - data: { - api_refund: false, // Prevent an actual refund request (fails with CoD), - line_items: [ - { - id: order4JSON.line_items[ 0 ].id, - quantity: 1, - refund_total: order4JSON.line_items[ 0 ].total, - refund_tax: [ + data: { + ...orderBaseData, + customer_id: johnJSON.id, + billing: { + ...johnAddress, + email: 'john.doe@example.com', + }, + shipping: johnAddress, + line_items: [ { - id: order4JSON.line_items[ 0 ] - .taxes[ 0 ].id, - refund_total: - order4JSON.line_items[ 0 ] - .total_tax, + product_id: product.id, + quantity: 1, }, ], }, + } + ); + const orderJSON = await order2.json(); + + orders.push( orderJSON ); + } ); + + // Have "Tina" order some sunglasses and make a child order. + // This somewhat resembles a subscription renewal, but we're just testing the `parent` field. + const order2 = await request.post( '/wp-json/wc/v3/orders', { + data: { + ...orderBaseData, + status: 'completed', + set_paid: true, + customer_id: tinaJSON.id, + billing: { + ...tinaAddress, + email: 'tina.clark@example.com', + }, + shipping: tinaAddress, + line_items: [ + { + product_id: orderedProducts.sunglasses.id, + quantity: 1, + }, ], }, - } - ); - orders.push( order4JSON ); + } ); + const order2JSON = await order2.json(); - return { - customers: { - johnJSON, - tinaJSON, - }, - orders, - precisionOrder: order4JSON, - hierarchicalOrders: { - parent: order2JSON, - child: order3JSON, - }, - guestOrderJSON, - testProductData, - couponJSON, + orders.push( order2JSON ); + + // create child order by referencing a parent_id + const order3 = await request.post( '/wp-json/wc/v3/orders', { + data: { + ...orderBaseData, + parent_id: order2JSON.id, + customer_id: tinaJSON.id, + billing: { + ...tinaAddress, + email: 'tina.clark@example.com', + }, + shipping: tinaAddress, + line_items: [ + { + product_id: orderedProducts.sunglasses.id, + quantity: 1, + }, + ], + }, + } ); + const order3JSON = await order3.json(); + + orders.push( order3JSON ); + + // Guest order. + const guestOrder = await request.post( + '/wp-json/wc/v3/orders', + { + data: { + ...orderBaseData, + billing: guestBillingAddress, + shipping: guestShippingAddress, + line_items: [ + { + product_id: orderedProducts.pennant.id, + quantity: 2, + }, + { + product_id: orderedProducts.beanie.id, + quantity: 1, + }, + ], + }, + } + ); + const guestOrderJSON = await guestOrder.json(); + + // Create an order with all possible numerical fields (taxes, fees, refunds, etc). + await request.put( + '/wp-json/wc/v3/settings/general/woocommerce_calc_taxes', + { + data: { + value: 'yes', + }, + } + ); + + await request.post( '/wp-json/wc/v3/taxes', { + data: { + country: '*', + state: '*', + postcode: '*', + city: '*', + name: 'Tax', + rate: '5.5', + shipping: true, + }, + } ); + + const coupon = await request.post( '/wp-json/wc/v3/coupons', { + data: { + code: 'save5', + amount: '5', + }, + } ); + const couponJSON = await coupon.json(); + + const order4 = await request.post( '/wp-json/wc/v3/orders', { + data: { + ...orderBaseData, + line_items: [ + { + product_id: orderedProducts.blueVneck.id, + quantity: 1, + }, + ], + coupon_lines: [ + { + code: 'save5', + }, + ], + shipping_lines: [ + { + method_id: 'flat_rate', + total: '5.00', + }, + ], + fee_lines: [ + { + total: '1.00', + name: 'Test Fee', + }, + ], + }, + } ); + const order4JSON = await order4.json(); + + await request.post( + `/wp-json/wc/v3/orders/${ order4JSON.id }/refunds`, + { + data: { + api_refund: false, // Prevent an actual refund request (fails with CoD), + line_items: [ + { + id: order4JSON.line_items[ 0 ].id, + quantity: 1, + refund_total: + order4JSON.line_items[ 0 ].total, + refund_tax: [ + { + id: order4JSON.line_items[ 0 ] + .taxes[ 0 ].id, + refund_total: + order4JSON.line_items[ 0 ] + .total_tax, + }, + ], + }, + ], + }, + } + ); + orders.push( order4JSON ); + + return { + customers: { + johnJSON, + tinaJSON, + }, + orders, + precisionOrder: order4JSON, + hierarchicalOrders: { + parent: order2JSON, + child: order3JSON, + }, + guestOrderJSON, + testProductData, + couponJSON, + }; }; - }; - sampleData = await createSampleData(); - }, 100000 ); + sampleData = await createSampleData(); + }, 100000 ); - test.afterAll( async ( { request } ) => { - const productsTestSetupDeleteSampleData = async ( _sampleData ) => { - const { - categories, - attributes, - tags, - shippingClasses, - taxClasses, - simpleProducts, - externalProducts, - groupedProducts, - variableProducts, - hierarchicalProducts, - orders, - } = _sampleData; + test.afterAll( async ( { request } ) => { + const productsTestSetupDeleteSampleData = async ( _sampleData ) => { + const { + categories, + attributes, + tags, + shippingClasses, + taxClasses, + simpleProducts, + externalProducts, + groupedProducts, + variableProducts, + hierarchicalProducts, + orders, + } = _sampleData; - const productIds = [] - .concat( simpleProducts.map( ( p ) => p.id ) ) - .concat( externalProducts.map( ( p ) => p.id ) ) - .concat( groupedProducts.map( ( p ) => p.id ) ) - .concat( [ - variableProducts.hoodieJSON.id, - variableProducts.vneckJSON.id, - ] ) - .concat( [ - hierarchicalProducts.parentJSON.id, - hierarchicalProducts.childJSON.id, - ] ); + const productIds = [] + .concat( simpleProducts.map( ( p ) => p.id ) ) + .concat( externalProducts.map( ( p ) => p.id ) ) + .concat( groupedProducts.map( ( p ) => p.id ) ) + .concat( [ + variableProducts.hoodieJSON.id, + variableProducts.vneckJSON.id, + ] ) + .concat( [ + hierarchicalProducts.parentJSON.id, + hierarchicalProducts.childJSON.id, + ] ); - for ( const _order of orders ) { - await request.delete( `/wp-json/wc/v3/orders/${ _order.id }`, { - data: { - force: true, - }, - } ); - } - - for ( const productId of productIds ) { - await request.delete( - `/wp-json/wc/v3/products/${ productId }`, - { - data: { - force: true, - }, - } - ); - } - - await request.delete( - `/wp-json/wc/v3/products/attributes/${ attributes.colorJSON.id }`, - { - data: { - force: true, - }, + for ( const _order of orders ) { + await request.delete( + `/wp-json/wc/v3/orders/${ _order.id }`, + { + data: { + force: true, + }, + } + ); } - ); - await request.delete( - `/wp-json/wc/v3/products/attributes/${ attributes.sizeJSON.id }`, - { - data: { - force: true, - }, + for ( const productId of productIds ) { + await request.delete( + `/wp-json/wc/v3/products/${ productId }`, + { + data: { + force: true, + }, + } + ); } - ); - for ( const category of Object.values( categories ) ) { await request.delete( - `/wp-json/wc/v3/products/categories/${ category.id }`, + `/wp-json/wc/v3/products/attributes/${ attributes.colorJSON.id }`, { data: { force: true, }, } ); - } - for ( const tag of Object.values( tags ) ) { await request.delete( - `/wp-json/wc/v3/products/tags/${ tag.id }`, + `/wp-json/wc/v3/products/attributes/${ attributes.sizeJSON.id }`, { data: { force: true, }, } ); - } - for ( const shippingClass of Object.values( shippingClasses ) ) { - await request.delete( - `/wp-json/wc/v3/products/shipping_classes/${ shippingClass.id }`, - { - data: { - force: true, - }, - } + for ( const category of Object.values( categories ) ) { + await request.delete( + `/wp-json/wc/v3/products/categories/${ category.id }`, + { + data: { + force: true, + }, + } + ); + } + + for ( const tag of Object.values( tags ) ) { + await request.delete( + `/wp-json/wc/v3/products/tags/${ tag.id }`, + { + data: { + force: true, + }, + } + ); + } + + for ( const shippingClass of Object.values( + shippingClasses + ) ) { + await request.delete( + `/wp-json/wc/v3/products/shipping_classes/${ shippingClass.id }`, + { + data: { + force: true, + }, + } + ); + } + + for ( const taxClass of Object.values( taxClasses ) ) { + await request.delete( + `/wp-json/wc/v3/taxes/classes/${ taxClass.slug }`, + { + data: { + force: true, + }, + } + ); + } + }; + + const deleteSampleData = async ( _sampleData ) => { + await productsTestSetupDeleteSampleData( + _sampleData.testProductData ); - } - for ( const taxClass of Object.values( taxClasses ) ) { - await request.delete( - `/wp-json/wc/v3/taxes/classes/${ taxClass.slug }`, - { - data: { - force: true, - }, - } - ); - } - }; + for ( const _order of _sampleData.orders.concat( [ + _sampleData.guestOrderJSON, + ] ) ) { + await request.delete( + `/wp-json/wc/v3/orders/${ _order.id }`, + { + data: { + force: true, + }, + } + ); + } - const deleteSampleData = async ( _sampleData ) => { - await productsTestSetupDeleteSampleData( - _sampleData.testProductData - ); + for ( const customer of Object.values( + _sampleData.customers + ) ) { + await request.delete( + `/wp-json/wc/v3/customers/${ customer.id }`, + { + data: { + force: true, + }, + } + ); + } + }; - for ( const _order of _sampleData.orders.concat( [ - _sampleData.guestOrderJSON, - ] ) ) { - await request.delete( `/wp-json/wc/v3/orders/${ _order.id }`, { - data: { - force: true, - }, - } ); - } + await deleteSampleData( sampleData ); + }, 10000 ); - for ( const customer of Object.values( _sampleData.customers ) ) { - await request.delete( - `/wp-json/wc/v3/customers/${ customer.id }`, - { - data: { - force: true, - }, - } - ); - } - }; - - await deleteSampleData( sampleData ); - }, 10000 ); - - test( 'can create an order', async ( { request } ) => { - const response = await request.post( '/wp-json/wc/v3/orders', { - data: order, - } ); - const responseJSON = await response.json(); - - expect( response.status() ).toEqual( 201 ); - expect( responseJSON.id ).toBeDefined(); - orderId = responseJSON.id; - - // Validate the data type and verify the order is in a pending state - expect( typeof responseJSON.status ).toBe( 'string' ); - expect( responseJSON.status ).toEqual( 'pending' ); - } ); - - test( 'can retrieve an order', async ( { request } ) => { - const response = await request.get( - `/wp-json/wc/v3/orders/${ orderId }` - ); - const responseJSON = await response.json(); - - expect( response.status() ).toEqual( 200 ); - expect( responseJSON.id ).toEqual( orderId ); - } ); - - test( 'can add shipping and billing contacts to an order', async ( { - request, - } ) => { - // Update the billing and shipping fields on the order - order.billing = updatedCustomerBilling; - order.shipping = updatedCustomerShipping; - - const response = await request.put( - `/wp-json/wc/v3/orders/${ orderId }`, - { + test( 'can create an order', async ( { request } ) => { + const response = await request.post( '/wp-json/wc/v3/orders', { data: order, - } - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - - expect( responseJSON.billing ).toEqual( updatedCustomerBilling ); - expect( responseJSON.shipping ).toEqual( updatedCustomerShipping ); - } ); - - test( 'can permanently delete an order', async ( { request } ) => { - const response = await request.delete( - `/wp-json/wc/v3/orders/${ orderId }`, - { - data: { - force: true, - }, - } - ); - expect( response.status() ).toEqual( 200 ); - - const getOrderResponse = await request.get( - `/wp-json/wc/v3/orders/${ orderId }` - ); - expect( getOrderResponse.status() ).toEqual( 404 ); - } ); - - test.describe( 'List all orders', () => { - const ORDERS_COUNT = 10; - - test( 'pagination', async ( { request } ) => { - const pageSize = 4; - const page1 = await request.get( '/wp-json/wc/v3/orders', { - params: { - per_page: pageSize, - search: 'oxo', - }, } ); - const page1JSON = await page1.json(); + const responseJSON = await response.json(); - const page2 = await request.get( '/wp-json/wc/v3/orders', { - params: { - per_page: pageSize, - page: 2, - search: 'oxo', - }, - } ); - const page2JSON = await page2.json(); + expect( response.status() ).toEqual( 201 ); + expect( responseJSON.id ).toBeDefined(); + orderId = responseJSON.id; - expect( page1.status() ).toEqual( 200 ); - expect( page2.status() ).toEqual( 200 ); - - // Verify total page count. - expect( page1.headers()[ 'x-wp-total' ] ).toEqual( - ORDERS_COUNT.toString() - ); - expect( page1.headers()[ 'x-wp-totalpages' ] ).toEqual( '3' ); - - // Verify we get pageSize'd arrays. - expect( Array.isArray( page1JSON ) ).toBe( true ); - expect( Array.isArray( page2JSON ) ).toBe( true ); - expect( page1JSON ).toHaveLength( pageSize ); - expect( page2JSON ).toHaveLength( pageSize ); - - // Ensure all of the order IDs are unique (no page overlap). - const allOrderIds = page1JSON - .concat( page2JSON ) - .reduce( ( acc, { id } ) => { - acc[ id ] = 1; - return acc; - }, {} ); - expect( Object.keys( allOrderIds ) ).toHaveLength( pageSize * 2 ); - - // Verify that offset takes precedent over page number. - const page2Offset = await request.get( 'wp-json/wc/v3/orders', { - params: { - per_page: pageSize, - page: 2, - offset: pageSize + 1, - search: 'oxo', - }, - } ); - const page2OffsetJSON = await page2Offset.json(); - - // The offset pushes the result set 1 order past the start of page 2. - expect( page2OffsetJSON ).toEqual( - expect.not.arrayContaining( [ - expect.objectContaining( { - id: page2JSON[ 0 ].id, - } ), - ] ) - ); - expect( page2OffsetJSON[ 0 ].id ).toEqual( page2JSON[ 1 ].id ); - - // Verify the last page only has 1 order as we expect. - const lastPage = await request.get( 'wp-json/wc/v3/orders', { - params: { - per_page: pageSize, - page: 3, - search: 'oxo', - }, - } ); - const lastPageJSON = await lastPage.json(); - - expect( Array.isArray( lastPageJSON ) ).toBe( true ); - expect( lastPageJSON ).toHaveLength( 2 ); - - // Verify a page outside the total page count is empty. - const page6 = await request.get( 'wp-json/wc/v3/orders', { - params: { - page: 6, - search: 'oxo', - }, - } ); - const page6JSON = await page6.json(); - - expect( Array.isArray( page6JSON ) ).toBe( true ); - expect( page6JSON ).toHaveLength( 0 ); + // Validate the data type and verify the order is in a pending state + expect( typeof responseJSON.status ).toBe( 'string' ); + expect( responseJSON.status ).toEqual( 'pending' ); } ); - test( 'inclusion / exclusion', async ( { request } ) => { - const allOrders = await request.get( 'wp-json/wc/v3/orders', { - params: { - per_page: 10, - search: 'oxo', - }, - } ); - const allOrdersJSON = await allOrders.json(); - - expect( allOrders.status() ).toEqual( 200 ); - const allOrdersIds = allOrdersJSON.map( ( _order ) => _order.id ); - expect( allOrdersIds ).toHaveLength( ORDERS_COUNT ); - - const ordersToFilter = [ - allOrdersIds[ 0 ], - allOrdersIds[ 2 ], - allOrdersIds[ 4 ], - allOrdersIds[ 7 ], - ]; - - const included = await request.get( 'wp-json/wc/v3/orders', { - params: { - per_page: 20, - include: ordersToFilter.join( ',' ), - }, - } ); - const includedJSON = await included.json(); - - expect( included.status() ).toEqual( 200 ); - expect( includedJSON ).toHaveLength( ordersToFilter.length ); - expect( includedJSON ).toEqual( - expect.arrayContaining( - ordersToFilter.map( ( id ) => - expect.objectContaining( { - id, - } ) - ) - ) + test( 'can retrieve an order', async ( { request } ) => { + const response = await request.get( + `/wp-json/wc/v3/orders/${ orderId }` ); + const responseJSON = await response.json(); - const excluded = await request.get( 'wp-json/wc/v3/orders', { - params: { - per_page: 20, - exclude: ordersToFilter.join( ',' ), - }, - } ); - const excludedJSON = await excluded.json(); - - expect( excluded.status() ).toEqual( 200 ); - expect( excludedJSON.length ).toBeGreaterThanOrEqual( - Number( ORDERS_COUNT - ordersToFilter.length ) - ); - expect( excludedJSON ).toEqual( - expect.not.arrayContaining( - ordersToFilter.map( ( id ) => - expect.objectContaining( { - id, - } ) - ) - ) - ); + expect( response.status() ).toEqual( 200 ); + expect( responseJSON.id ).toEqual( orderId ); } ); - test( 'parent', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/orders', { - params: { - parent: sampleData.hierarchicalOrders.parent.id, - }, - } ); - const result1JSON = await result1.json(); + test( 'can add shipping and billing contacts to an order', async ( { + request, + } ) => { + // Update the billing and shipping fields on the order + order.billing = updatedCustomerBilling; + order.shipping = updatedCustomerShipping; - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 1 ); - expect( result1JSON[ 0 ].id ).toBe( - sampleData.hierarchicalOrders.child.id + const response = await request.put( + `/wp-json/wc/v3/orders/${ orderId }`, + { + data: order, + } ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); - const result2 = await request.get( 'wp-json/wc/v3/orders', { - params: { - parent_exclude: sampleData.hierarchicalOrders.parent.id, - }, - } ); - const result2JSON = await result2.json(); - - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toEqual( - expect.not.arrayContaining( [ - expect.objectContaining( { - id: sampleData.hierarchicalOrders.child.id, - } ), - ] ) - ); + expect( responseJSON.billing ).toEqual( updatedCustomerBilling ); + expect( responseJSON.shipping ).toEqual( updatedCustomerShipping ); } ); - test( 'status', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/orders', { - params: { - status: 'completed', - search: 'oxo', - }, - } ); - const result1JSON = await result1.json(); - - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 2 ); - expect( result1JSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - status: 'completed', - customer_id: 0, - line_items: expect.arrayContaining( [ - expect.objectContaining( { - name: 'Single oxo', - quantity: 2, - } ), - expect.objectContaining( { - name: 'Beanie with Logo oxo', - quantity: 3, - } ), - expect.objectContaining( { - name: 'T-Shirt oxo', - quantity: 1, - } ), - ] ), - } ), - expect.objectContaining( { - status: 'completed', - customer_id: sampleData.customers.tinaJSON.id, - line_items: expect.arrayContaining( [ - expect.objectContaining( { - name: 'Sunglasses oxo', - quantity: 1, - } ), - ] ), - } ), - ] ) + test( 'can permanently delete an order', async ( { request } ) => { + const response = await request.delete( + `/wp-json/wc/v3/orders/${ orderId }`, + { + data: { + force: true, + }, + } ); + expect( response.status() ).toEqual( 200 ); - const result2 = await request.get( 'wp-json/wc/v3/orders', { - params: { - status: 'processing', - search: 'oxo', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 8 ); - expect( result2JSON ).toEqual( - expect.not.arrayContaining( - result1JSON.map( ( { id } ) => - expect.objectContaining( { - id, - } ) - ) - ) + const getOrderResponse = await request.get( + `/wp-json/wc/v3/orders/${ orderId }` ); + expect( getOrderResponse.status() ).toEqual( 404 ); } ); - test( 'customer', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/orders', { - params: { - customer: sampleData.customers.johnJSON.id, - }, - } ); - const result1JSON = await result1.json(); + test.describe( 'List all orders', () => { + const ORDERS_COUNT = 10; - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 5 ); - result1JSON.forEach( ( _order ) => - expect( _order ).toEqual( - expect.objectContaining( { - customer_id: sampleData.customers.johnJSON.id, - } ) - ) - ); + test( 'pagination', async ( { request } ) => { + const pageSize = 4; + const page1 = await request.get( '/wp-json/wc/v3/orders', { + params: { + per_page: pageSize, + search: 'oxo', + }, + } ); + const page1JSON = await page1.json(); - const result2 = await request.get( 'wp-json/wc/v3/orders', { - params: { - customer: 0, - search: 'oxo', - }, - } ); - const result2JSON = await result2.json(); + const page2 = await request.get( '/wp-json/wc/v3/orders', { + params: { + per_page: pageSize, + page: 2, + search: 'oxo', + }, + } ); + const page2JSON = await page2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 3 ); - result2JSON.forEach( ( _order ) => - expect( _order ).toEqual( - expect.objectContaining( { - customer_id: 0, - } ) - ) - ); - } ); + expect( page1.status() ).toEqual( 200 ); + expect( page2.status() ).toEqual( 200 ); - test( 'product', async ( { request } ) => { - const beanie = sampleData.testProductData.simpleProducts.find( - ( p ) => p.name === 'Beanie oxo' - ); - const result1 = await request.get( 'wp-json/wc/v3/orders', { - params: { - product: beanie.id, - }, - } ); - const result1JSON = await result1.json(); - - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 2 ); - result1JSON.forEach( ( _order ) => - expect( _order ).toEqual( - expect.objectContaining( { - line_items: expect.arrayContaining( [ - expect.objectContaining( { - name: 'Beanie oxo', - } ), - ] ), - } ) - ) - ); - } ); - - // NOTE: This does not verify the `taxes` array nested in line items. - // While the precision parameter doesn't affect those values, after some - // discussion it seems `dp` may not be supported in v4 of the API. - test( 'dp (precision)', async ( { request } ) => { - const expectPrecisionToMatch = ( value, dp ) => { - expect( value ).toEqual( - Number.parseFloat( value ).toFixed( dp ) + // Verify total page count. + expect( page1.headers()[ 'x-wp-total' ] ).toEqual( + ORDERS_COUNT.toString() ); - }; + expect( page1.headers()[ 'x-wp-totalpages' ] ).toEqual( '3' ); - const verifyOrderPrecision = ( _order, dp ) => { - expectPrecisionToMatch( _order.discount_total, dp ); - expectPrecisionToMatch( _order.discount_tax, dp ); - expectPrecisionToMatch( _order.shipping_total, dp ); - expectPrecisionToMatch( _order.shipping_tax, dp ); - expectPrecisionToMatch( _order.cart_tax, dp ); - expectPrecisionToMatch( _order.total, dp ); - expectPrecisionToMatch( _order.total_tax, dp ); + // Verify we get pageSize'd arrays. + expect( Array.isArray( page1JSON ) ).toBe( true ); + expect( Array.isArray( page2JSON ) ).toBe( true ); + expect( page1JSON ).toHaveLength( pageSize ); + expect( page2JSON ).toHaveLength( pageSize ); - _order.line_items.forEach( ( lineItem ) => { - expectPrecisionToMatch( lineItem.total, dp ); - expectPrecisionToMatch( lineItem.total_tax, dp ); - } ); + // Ensure all of the order IDs are unique (no page overlap). + const allOrderIds = page1JSON + .concat( page2JSON ) + .reduce( ( acc, { id } ) => { + acc[ id ] = 1; + return acc; + }, {} ); + expect( Object.keys( allOrderIds ) ).toHaveLength( + pageSize * 2 + ); - _order.tax_lines.forEach( ( taxLine ) => { - expectPrecisionToMatch( taxLine.tax_total, dp ); - expectPrecisionToMatch( taxLine.shipping_tax_total, dp ); - } ); - - _order.shipping_lines.forEach( ( shippingLine ) => { - expectPrecisionToMatch( shippingLine.total, dp ); - expectPrecisionToMatch( shippingLine.total_tax, dp ); - } ); - - _order.fee_lines.forEach( ( feeLine ) => { - expectPrecisionToMatch( feeLine.total, dp ); - expectPrecisionToMatch( feeLine.total_tax, dp ); - } ); - - _order.refunds.forEach( ( refund ) => { - expectPrecisionToMatch( refund.total, dp ); - } ); - }; - - const result1 = await request.get( - `wp-json/wc/v3/orders/${ sampleData.precisionOrder.id }`, - { + // Verify that offset takes precedent over page number. + const page2Offset = await request.get( 'wp-json/wc/v3/orders', { params: { - dp: 1, + per_page: pageSize, + page: 2, + offset: pageSize + 1, + search: 'oxo', }, - } - ); - const result1JSON = await result1.json(); + } ); + const page2OffsetJSON = await page2Offset.json(); - expect( result1.status() ).toEqual( 200 ); - verifyOrderPrecision( result1JSON, 1 ); + // The offset pushes the result set 1 order past the start of page 2. + expect( page2OffsetJSON ).toEqual( + expect.not.arrayContaining( [ + expect.objectContaining( { + id: page2JSON[ 0 ].id, + } ), + ] ) + ); + expect( page2OffsetJSON[ 0 ].id ).toEqual( page2JSON[ 1 ].id ); - const result2 = await request.get( - `wp-json/wc/v3/orders/${ sampleData.precisionOrder.id }`, - { + // Verify the last page only has 1 order as we expect. + const lastPage = await request.get( 'wp-json/wc/v3/orders', { params: { - dp: 3, + per_page: pageSize, + page: 3, + search: 'oxo', }, - } - ); - const result2JSON = await result2.json(); + } ); + const lastPageJSON = await lastPage.json(); - expect( result2.status() ).toEqual( 200 ); - verifyOrderPrecision( result2JSON, 3 ); + expect( Array.isArray( lastPageJSON ) ).toBe( true ); + expect( lastPageJSON ).toHaveLength( 2 ); - const result3 = await request.get( - `wp-json/wc/v3/orders/${ sampleData.precisionOrder.id }` - ); - const result3JSON = await result3.json(); + // Verify a page outside the total page count is empty. + const page6 = await request.get( 'wp-json/wc/v3/orders', { + params: { + page: 6, + search: 'oxo', + }, + } ); + const page6JSON = await page6.json(); - expect( result3.status() ).toEqual( 200 ); - verifyOrderPrecision( result3JSON, 2 ); // The default value for 'dp' is 2. - } ); - - test( 'search', async ( { request } ) => { - // By default, 'search' looks in: - // - _billing_address_index - // - _shipping_address_index - // - _billing_last_name - // - _billing_email - // - order_item_name - - // Test billing email. - const result1 = await request.get( 'wp-json/wc/v3/orders', { - params: { - search: 'example.com', - }, + expect( Array.isArray( page6JSON ) ).toBe( true ); + expect( page6JSON ).toHaveLength( 0 ); } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON.length ).toBeGreaterThanOrEqual( 1 ); - result1JSON.forEach( ( _order ) => - expect( _order.billing.email ).toContain( 'example.com' ) - ); + test( 'inclusion / exclusion', async ( { request } ) => { + const allOrders = await request.get( 'wp-json/wc/v3/orders', { + params: { + per_page: 10, + search: 'oxo', + }, + } ); + const allOrdersJSON = await allOrders.json(); - // Test billing address. - const result2 = await request.get( 'wp-json/wc/v3/orders', { - params: { - search: 'gainesville', - }, - } ); - const result2JSON = await result2.json(); + expect( allOrders.status() ).toEqual( 200 ); + const allOrdersIds = allOrdersJSON.map( + ( _order ) => _order.id + ); + expect( allOrdersIds ).toHaveLength( ORDERS_COUNT ); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 1 ); - expect( result2JSON[ 0 ].id ).toEqual( - sampleData.guestOrderJSON.id - ); + const ordersToFilter = [ + allOrdersIds[ 0 ], + allOrdersIds[ 2 ], + allOrdersIds[ 4 ], + allOrdersIds[ 7 ], + ]; - // Test shipping address. - const result3 = await request.get( 'wp-json/wc/v3/orders', { - params: { - search: 'Incognito', - }, - } ); - const result3JSON = await result3.json(); + const included = await request.get( 'wp-json/wc/v3/orders', { + params: { + per_page: 20, + include: ordersToFilter.join( ',' ), + }, + } ); + const includedJSON = await included.json(); - expect( result3.status() ).toEqual( 200 ); - expect( result3JSON ).toHaveLength( 1 ); - expect( result3JSON[ 0 ].id ).toEqual( - sampleData.guestOrderJSON.id - ); - - // Test billing last name. - const result4 = await request.get( 'wp-json/wc/v3/orders', { - params: { - search: 'Doe', - }, - } ); - const result4JSON = await result4.json(); - - expect( result4.status() ).toEqual( 200 ); - expect( result4JSON.length ).toBeGreaterThanOrEqual( 1 ); - result4JSON.forEach( ( _order ) => - expect( _order.billing.last_name ).toEqual( 'Doe' ) - ); - - // Test order item name. - const result5 = await request.get( 'wp-json/wc/v3/orders', { - params: { - search: 'Pennant oxo', - }, - } ); - const result5JSON = await result5.json(); - - expect( result5.status() ).toEqual( 200 ); - expect( result5JSON ).toHaveLength( 2 ); - result5JSON.forEach( ( _order ) => - expect( _order ).toEqual( - expect.objectContaining( { - line_items: expect.arrayContaining( [ + expect( included.status() ).toEqual( 200 ); + expect( includedJSON ).toHaveLength( ordersToFilter.length ); + expect( includedJSON ).toEqual( + expect.arrayContaining( + ordersToFilter.map( ( id ) => expect.objectContaining( { - name: 'WordPress Pennant oxo', - } ), - ] ), - } ) - ) - ); - } ); - } ); + id, + } ) + ) + ) + ); - test.describe( 'orderby', () => { - // The orders endpoint `orderby` parameter uses WP_Query, so our tests won't - // include slug and title, since they are programmatically generated. - test( 'default', async ( { request } ) => { - // Default = date desc. - const result = await request.get( 'wp-json/wc/v3/orders' ); - const resultJSON = await result.json(); - expect( result.status() ).toEqual( 200 ); + const excluded = await request.get( 'wp-json/wc/v3/orders', { + params: { + per_page: 20, + exclude: ordersToFilter.join( ',' ), + }, + } ); + const excludedJSON = await excluded.json(); - // Verify all dates are in descending order. - let lastDate = Date.now(); - resultJSON.forEach( ( { date_created } ) => { - const created = Date.parse( date_created + '.000Z' ); - expect( lastDate ).toBeGreaterThanOrEqual( created ); - lastDate = created; + expect( excluded.status() ).toEqual( 200 ); + expect( excludedJSON.length ).toBeGreaterThanOrEqual( + Number( ORDERS_COUNT - ordersToFilter.length ) + ); + expect( excludedJSON ).toEqual( + expect.not.arrayContaining( + ordersToFilter.map( ( id ) => + expect.objectContaining( { + id, + } ) + ) + ) + ); + } ); + + test( 'parent', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/orders', { + params: { + parent: sampleData.hierarchicalOrders.parent.id, + }, + } ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 1 ); + expect( result1JSON[ 0 ].id ).toBe( + sampleData.hierarchicalOrders.child.id + ); + + const result2 = await request.get( 'wp-json/wc/v3/orders', { + params: { + parent_exclude: sampleData.hierarchicalOrders.parent.id, + }, + } ); + const result2JSON = await result2.json(); + + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toEqual( + expect.not.arrayContaining( [ + expect.objectContaining( { + id: sampleData.hierarchicalOrders.child.id, + } ), + ] ) + ); + } ); + + test( 'status', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/orders', { + params: { + status: 'completed', + search: 'oxo', + }, + } ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 2 ); + expect( result1JSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + status: 'completed', + customer_id: 0, + line_items: expect.arrayContaining( [ + expect.objectContaining( { + name: 'Single oxo', + quantity: 2, + } ), + expect.objectContaining( { + name: 'Beanie with Logo oxo', + quantity: 3, + } ), + expect.objectContaining( { + name: 'T-Shirt oxo', + quantity: 1, + } ), + ] ), + } ), + expect.objectContaining( { + status: 'completed', + customer_id: sampleData.customers.tinaJSON.id, + line_items: expect.arrayContaining( [ + expect.objectContaining( { + name: 'Sunglasses oxo', + quantity: 1, + } ), + ] ), + } ), + ] ) + ); + + const result2 = await request.get( 'wp-json/wc/v3/orders', { + params: { + status: 'processing', + search: 'oxo', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 8 ); + expect( result2JSON ).toEqual( + expect.not.arrayContaining( + result1JSON.map( ( { id } ) => + expect.objectContaining( { + id, + } ) + ) + ) + ); + } ); + + test( 'customer', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/orders', { + params: { + customer: sampleData.customers.johnJSON.id, + }, + } ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 5 ); + result1JSON.forEach( ( _order ) => + expect( _order ).toEqual( + expect.objectContaining( { + customer_id: sampleData.customers.johnJSON.id, + } ) + ) + ); + + const result2 = await request.get( 'wp-json/wc/v3/orders', { + params: { + customer: 0, + search: 'oxo', + }, + } ); + const result2JSON = await result2.json(); + + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 3 ); + result2JSON.forEach( ( _order ) => + expect( _order ).toEqual( + expect.objectContaining( { + customer_id: 0, + } ) + ) + ); + } ); + + test( 'product', async ( { request } ) => { + const beanie = sampleData.testProductData.simpleProducts.find( + ( p ) => p.name === 'Beanie oxo' + ); + const result1 = await request.get( 'wp-json/wc/v3/orders', { + params: { + product: beanie.id, + }, + } ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 2 ); + result1JSON.forEach( ( _order ) => + expect( _order ).toEqual( + expect.objectContaining( { + line_items: expect.arrayContaining( [ + expect.objectContaining( { + name: 'Beanie oxo', + } ), + ] ), + } ) + ) + ); + } ); + + // NOTE: This does not verify the `taxes` array nested in line items. + // While the precision parameter doesn't affect those values, after some + // discussion it seems `dp` may not be supported in v4 of the API. + test( 'dp (precision)', async ( { request } ) => { + const expectPrecisionToMatch = ( value, dp ) => { + expect( value ).toEqual( + Number.parseFloat( value ).toFixed( dp ) + ); + }; + + const verifyOrderPrecision = ( _order, dp ) => { + expectPrecisionToMatch( _order.discount_total, dp ); + expectPrecisionToMatch( _order.discount_tax, dp ); + expectPrecisionToMatch( _order.shipping_total, dp ); + expectPrecisionToMatch( _order.shipping_tax, dp ); + expectPrecisionToMatch( _order.cart_tax, dp ); + expectPrecisionToMatch( _order.total, dp ); + expectPrecisionToMatch( _order.total_tax, dp ); + + _order.line_items.forEach( ( lineItem ) => { + expectPrecisionToMatch( lineItem.total, dp ); + expectPrecisionToMatch( lineItem.total_tax, dp ); + } ); + + _order.tax_lines.forEach( ( taxLine ) => { + expectPrecisionToMatch( taxLine.tax_total, dp ); + expectPrecisionToMatch( + taxLine.shipping_tax_total, + dp + ); + } ); + + _order.shipping_lines.forEach( ( shippingLine ) => { + expectPrecisionToMatch( shippingLine.total, dp ); + expectPrecisionToMatch( shippingLine.total_tax, dp ); + } ); + + _order.fee_lines.forEach( ( feeLine ) => { + expectPrecisionToMatch( feeLine.total, dp ); + expectPrecisionToMatch( feeLine.total_tax, dp ); + } ); + + _order.refunds.forEach( ( refund ) => { + expectPrecisionToMatch( refund.total, dp ); + } ); + }; + + const result1 = await request.get( + `wp-json/wc/v3/orders/${ sampleData.precisionOrder.id }`, + { + params: { + dp: 1, + }, + } + ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + verifyOrderPrecision( result1JSON, 1 ); + + const result2 = await request.get( + `wp-json/wc/v3/orders/${ sampleData.precisionOrder.id }`, + { + params: { + dp: 3, + }, + } + ); + const result2JSON = await result2.json(); + + expect( result2.status() ).toEqual( 200 ); + verifyOrderPrecision( result2JSON, 3 ); + + const result3 = await request.get( + `wp-json/wc/v3/orders/${ sampleData.precisionOrder.id }` + ); + const result3JSON = await result3.json(); + + expect( result3.status() ).toEqual( 200 ); + verifyOrderPrecision( result3JSON, 2 ); // The default value for 'dp' is 2. + } ); + + test( 'search', async ( { request } ) => { + // By default, 'search' looks in: + // - _billing_address_index + // - _shipping_address_index + // - _billing_last_name + // - _billing_email + // - order_item_name + + // Test billing email. + const result1 = await request.get( 'wp-json/wc/v3/orders', { + params: { + search: 'example.com', + }, + } ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON.length ).toBeGreaterThanOrEqual( 1 ); + result1JSON.forEach( ( _order ) => + expect( _order.billing.email ).toContain( 'example.com' ) + ); + + // Test billing address. + const result2 = await request.get( 'wp-json/wc/v3/orders', { + params: { + search: 'gainesville', + }, + } ); + const result2JSON = await result2.json(); + + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 1 ); + expect( result2JSON[ 0 ].id ).toEqual( + sampleData.guestOrderJSON.id + ); + + // Test shipping address. + const result3 = await request.get( 'wp-json/wc/v3/orders', { + params: { + search: 'Incognito', + }, + } ); + const result3JSON = await result3.json(); + + expect( result3.status() ).toEqual( 200 ); + expect( result3JSON ).toHaveLength( 1 ); + expect( result3JSON[ 0 ].id ).toEqual( + sampleData.guestOrderJSON.id + ); + + // Test billing last name. + const result4 = await request.get( 'wp-json/wc/v3/orders', { + params: { + search: 'Doe', + }, + } ); + const result4JSON = await result4.json(); + + expect( result4.status() ).toEqual( 200 ); + expect( result4JSON.length ).toBeGreaterThanOrEqual( 1 ); + result4JSON.forEach( ( _order ) => + expect( _order.billing.last_name ).toEqual( 'Doe' ) + ); + + // Test order item name. + const result5 = await request.get( 'wp-json/wc/v3/orders', { + params: { + search: 'Pennant oxo', + }, + } ); + const result5JSON = await result5.json(); + + expect( result5.status() ).toEqual( 200 ); + expect( result5JSON ).toHaveLength( 2 ); + result5JSON.forEach( ( _order ) => + expect( _order ).toEqual( + expect.objectContaining( { + line_items: expect.arrayContaining( [ + expect.objectContaining( { + name: 'WordPress Pennant oxo', + } ), + ] ), + } ) + ) + ); } ); } ); - test( 'date', async ( { request } ) => { - const result = await request.get( 'wp-json/wc/v3/orders', { - params: { - order: 'asc', - orderby: 'date', - }, + test.describe( 'orderby', () => { + // The orders endpoint `orderby` parameter uses WP_Query, so our tests won't + // include slug and title, since they are programmatically generated. + test( 'default', async ( { request } ) => { + // Default = date desc. + const result = await request.get( 'wp-json/wc/v3/orders' ); + const resultJSON = await result.json(); + expect( result.status() ).toEqual( 200 ); + + // Verify all dates are in descending order. + let lastDate = Date.now(); + resultJSON.forEach( ( { date_created } ) => { + const created = Date.parse( date_created + '.000Z' ); + expect( lastDate ).toBeGreaterThanOrEqual( created ); + lastDate = created; + } ); } ); - const resultJSON = await result.json(); - expect( result.status() ).toEqual( 200 ); + test( 'date', async ( { request } ) => { + const result = await request.get( 'wp-json/wc/v3/orders', { + params: { + order: 'asc', + orderby: 'date', + }, + } ); + const resultJSON = await result.json(); - // Verify all dates are in ascending order. - let lastDate = 0; - resultJSON.forEach( ( { date_created } ) => { - const created = Date.parse( date_created + '.000Z' ); - expect( created ).toBeGreaterThanOrEqual( lastDate ); - lastDate = created; + expect( result.status() ).toEqual( 200 ); + + // Verify all dates are in ascending order. + let lastDate = 0; + resultJSON.forEach( ( { date_created } ) => { + const created = Date.parse( date_created + '.000Z' ); + expect( created ).toBeGreaterThanOrEqual( lastDate ); + lastDate = created; + } ); + } ); + + test( 'id', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/orders', { + params: { + order: 'asc', + orderby: 'id', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + + // Verify all results are in ascending order. + let lastId = 0; + result1JSON.forEach( ( { id } ) => { + expect( id ).toBeGreaterThan( lastId ); + lastId = id; + } ); + + const result2 = await request.get( 'wp-json/wc/v3/orders', { + params: { + order: 'desc', + orderby: 'id', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + + // Verify all results are in descending order. + lastId = Number.MAX_SAFE_INTEGER; + result2JSON.forEach( ( { id } ) => { + expect( lastId ).toBeGreaterThan( id ); + lastId = id; + } ); + } ); + + test( 'include', async ( { request } ) => { + const includeIds = [ + sampleData.precisionOrder.id, + sampleData.hierarchicalOrders.parent.id, + sampleData.guestOrderJSON.id, + ]; + + const result1 = await request.get( 'wp-json/wc/v3/orders', { + params: { + order: 'asc', + orderby: 'include', + include: includeIds.join( ',' ), + }, + } ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( includeIds.length ); + + // Verify all results are in proper order. + result1JSON.forEach( ( { id }, idx ) => { + expect( id ).toBe( includeIds[ idx ] ); + } ); + + const result2 = await request.get( 'wp-json/wc/v3/orders', { + params: { + order: 'desc', + orderby: 'include', + include: includeIds.join( ',' ), + }, + } ); + const result2JSON = await result2.json(); + + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( includeIds.length ); + + // Verify all results are in proper order. + result2JSON.forEach( ( { id }, idx ) => { + expect( id ).toBe( includeIds[ idx ] ); + } ); } ); } ); - - test( 'id', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/orders', { - params: { - order: 'asc', - orderby: 'id', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - - // Verify all results are in ascending order. - let lastId = 0; - result1JSON.forEach( ( { id } ) => { - expect( id ).toBeGreaterThan( lastId ); - lastId = id; - } ); - - const result2 = await request.get( 'wp-json/wc/v3/orders', { - params: { - order: 'desc', - orderby: 'id', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - - // Verify all results are in descending order. - lastId = Number.MAX_SAFE_INTEGER; - result2JSON.forEach( ( { id } ) => { - expect( lastId ).toBeGreaterThan( id ); - lastId = id; - } ); - } ); - - test( 'include', async ( { request } ) => { - const includeIds = [ - sampleData.precisionOrder.id, - sampleData.hierarchicalOrders.parent.id, - sampleData.guestOrderJSON.id, - ]; - - const result1 = await request.get( 'wp-json/wc/v3/orders', { - params: { - order: 'asc', - orderby: 'include', - include: includeIds.join( ',' ), - }, - } ); - const result1JSON = await result1.json(); - - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( includeIds.length ); - - // Verify all results are in proper order. - result1JSON.forEach( ( { id }, idx ) => { - expect( id ).toBe( includeIds[ idx ] ); - } ); - - const result2 = await request.get( 'wp-json/wc/v3/orders', { - params: { - order: 'desc', - orderby: 'include', - include: includeIds.join( ',' ), - }, - } ); - const result2JSON = await result2.json(); - - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( includeIds.length ); - - // Verify all results are in proper order. - result2JSON.forEach( ( { id }, idx ) => { - expect( id ).toBe( includeIds[ idx ] ); - } ); - } ); - } ); -} ); + } +); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js index c4d021c65f5..a0cd439f3e4 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/payment-gateways/payment-gateways-crud.test.js @@ -1,170 +1,176 @@ const { test, expect } = require( '../../../fixtures/api-tests-fixtures' ); test.describe( 'Payment Gateways API tests', () => { - test( 'can view all payment gateways', async ( { request } ) => { - // call API to retrieve the payment gateways - const response = await request.get( '/wp-json/wc/v3/payment_gateways' ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( Array.isArray( responseJSON ) ).toBe( true ); + test( + 'can view all payment gateways', + { tag: [ '@skip-on-default-pressable', '@skip-on-default-wpcom' ] }, + async ( { request } ) => { + // call API to retrieve the payment gateways + const response = await request.get( + '/wp-json/wc/v3/payment_gateways' + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( Array.isArray( responseJSON ) ).toBe( true ); - const localPickupKey = - // eslint-disable-next-line playwright/no-conditional-in-test - process.env.BASE_URL && - ! process.env.BASE_URL.includes( 'localhost' ) - ? 'pickup_location' - : 'local_pickup'; - console.log( 'localPickupKey=', localPickupKey ); + const localPickupKey = + // eslint-disable-next-line playwright/no-conditional-in-test + process.env.BASE_URL && + ! process.env.BASE_URL.includes( 'localhost' ) + ? 'pickup_location' + : 'local_pickup'; + console.log( 'localPickupKey=', localPickupKey ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'bacs', - title: 'Direct bank transfer', - description: - 'Make your payment directly into our bank account. Please use your Order ID as the payment reference. Your order will not be shipped until the funds have cleared in our account.', - order: '', - enabled: false, - method_title: 'Direct bank transfer', - method_description: - 'Take payments in person via BACS. More commonly known as direct bank/wire transfer.', - method_supports: [ 'products' ], - settings: { - title: { - id: 'title', - label: 'Title', - description: - 'This controls the title which the user sees during checkout.', - type: 'safe_text', - value: 'Direct bank transfer', - default: 'Direct bank transfer', - tip: 'This controls the title which the user sees during checkout.', - placeholder: '', + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'bacs', + title: 'Direct bank transfer', + description: + 'Make your payment directly into our bank account. Please use your Order ID as the payment reference. Your order will not be shipped until the funds have cleared in our account.', + order: '', + enabled: false, + method_title: 'Direct bank transfer', + method_description: + 'Take payments in person via BACS. More commonly known as direct bank/wire transfer.', + method_supports: [ 'products' ], + settings: { + title: { + id: 'title', + label: 'Title', + description: + 'This controls the title which the user sees during checkout.', + type: 'safe_text', + value: 'Direct bank transfer', + default: 'Direct bank transfer', + tip: 'This controls the title which the user sees during checkout.', + placeholder: '', + }, + instructions: { + id: 'instructions', + label: 'Instructions', + description: + 'Instructions that will be added to the thank you page and emails.', + type: 'textarea', + value: '', + default: '', + tip: 'Instructions that will be added to the thank you page and emails.', + placeholder: '', + }, }, - instructions: { - id: 'instructions', - label: 'Instructions', - description: - 'Instructions that will be added to the thank you page and emails.', - type: 'textarea', - value: '', - default: '', - tip: 'Instructions that will be added to the thank you page and emails.', - placeholder: '', - }, - }, - } ), + } ), - expect.objectContaining( { - id: 'cheque', - title: 'Check payments', - description: - 'Please send a check to Store Name, Store Street, Store Town, Store State / County, Store Postcode.', - order: '', - enabled: false, - method_title: 'Check payments', - method_description: - 'Take payments in person via checks. This offline gateway can also be useful to test purchases.', - method_supports: [ 'products' ], - settings: { - title: { - id: 'title', - label: 'Title', - description: - 'This controls the title which the user sees during checkout.', - type: 'safe_text', - value: 'Check payments', - default: 'Check payments', - tip: 'This controls the title which the user sees during checkout.', - placeholder: '', + expect.objectContaining( { + id: 'cheque', + title: 'Check payments', + description: + 'Please send a check to Store Name, Store Street, Store Town, Store State / County, Store Postcode.', + order: '', + enabled: false, + method_title: 'Check payments', + method_description: + 'Take payments in person via checks. This offline gateway can also be useful to test purchases.', + method_supports: [ 'products' ], + settings: { + title: { + id: 'title', + label: 'Title', + description: + 'This controls the title which the user sees during checkout.', + type: 'safe_text', + value: 'Check payments', + default: 'Check payments', + tip: 'This controls the title which the user sees during checkout.', + placeholder: '', + }, + instructions: { + id: 'instructions', + label: 'Instructions', + description: + 'Instructions that will be added to the thank you page and emails.', + type: 'textarea', + value: '', + default: '', + tip: 'Instructions that will be added to the thank you page and emails.', + placeholder: '', + }, }, - instructions: { - id: 'instructions', - label: 'Instructions', - description: - 'Instructions that will be added to the thank you page and emails.', - type: 'textarea', - value: '', - default: '', - tip: 'Instructions that will be added to the thank you page and emails.', - placeholder: '', - }, - }, - } ), + } ), - expect.objectContaining( { - id: 'cod', - title: 'Cash on delivery', - description: 'Pay with cash upon delivery.', - order: '', - enabled: false, - method_title: 'Cash on delivery', - method_description: - 'Have your customers pay with cash (or by other means) upon delivery.', - method_supports: [ 'products' ], - settings: { - title: { - id: 'title', - label: 'Title', - description: - 'Payment method description that the customer will see on your checkout.', - type: 'safe_text', - value: 'Cash on delivery', - default: 'Cash on delivery', - tip: 'Payment method description that the customer will see on your checkout.', - placeholder: '', - }, - instructions: { - id: 'instructions', - label: 'Instructions', - description: - 'Instructions that will be added to the thank you page.', - type: 'textarea', - value: 'Pay with cash upon delivery.', - default: 'Pay with cash upon delivery.', - tip: 'Instructions that will be added to the thank you page.', - placeholder: '', - }, - enable_for_methods: { - id: 'enable_for_methods', - label: 'Enable for shipping methods', - description: - 'If COD is only available for certain methods, set it up here. Leave blank to enable for all methods.', - type: 'multiselect', - value: '', - default: '', - tip: 'If COD is only available for certain methods, set it up here. Leave blank to enable for all methods.', - placeholder: '', - options: expect.objectContaining( { - 'Flat rate': { - flat_rate: - 'Any "Flat rate" method', - }, - 'Free shipping': { - free_shipping: - 'Any "Free shipping" method', - }, - 'Local pickup': expect.objectContaining( { - [ localPickupKey ]: - 'Any "Local pickup" method', + expect.objectContaining( { + id: 'cod', + title: 'Cash on delivery', + description: 'Pay with cash upon delivery.', + order: '', + enabled: false, + method_title: 'Cash on delivery', + method_description: + 'Have your customers pay with cash (or by other means) upon delivery.', + method_supports: [ 'products' ], + settings: { + title: { + id: 'title', + label: 'Title', + description: + 'Payment method description that the customer will see on your checkout.', + type: 'safe_text', + value: 'Cash on delivery', + default: 'Cash on delivery', + tip: 'Payment method description that the customer will see on your checkout.', + placeholder: '', + }, + instructions: { + id: 'instructions', + label: 'Instructions', + description: + 'Instructions that will be added to the thank you page.', + type: 'textarea', + value: 'Pay with cash upon delivery.', + default: 'Pay with cash upon delivery.', + tip: 'Instructions that will be added to the thank you page.', + placeholder: '', + }, + enable_for_methods: { + id: 'enable_for_methods', + label: 'Enable for shipping methods', + description: + 'If COD is only available for certain methods, set it up here. Leave blank to enable for all methods.', + type: 'multiselect', + value: '', + default: '', + tip: 'If COD is only available for certain methods, set it up here. Leave blank to enable for all methods.', + placeholder: '', + options: expect.objectContaining( { + 'Flat rate': { + flat_rate: + 'Any "Flat rate" method', + }, + 'Free shipping': { + free_shipping: + 'Any "Free shipping" method', + }, + 'Local pickup': expect.objectContaining( { + [ localPickupKey ]: + 'Any "Local pickup" method', + } ), } ), - } ), + }, + enable_for_virtual: { + id: 'enable_for_virtual', + label: 'Accept COD if the order is virtual', + description: '', + type: 'checkbox', + value: 'yes', + default: 'yes', + tip: '', + placeholder: '', + }, }, - enable_for_virtual: { - id: 'enable_for_virtual', - label: 'Accept COD if the order is virtual', - description: '', - type: 'checkbox', - value: 'yes', - default: 'yes', - tip: '', - placeholder: '', - }, - }, - } ), - ] ) - ); - } ); + } ), + ] ) + ); + } + ); test( 'can view a payment gateway', async ( { request } ) => { // call API to retrieve a single payment gateway diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.js b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.js index 03f51112b37..d9faf15633c 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/product-list.test.js @@ -2230,1077 +2230,1170 @@ test.describe( 'Products API tests: List All Products', () => { await deleteSampleData( sampleData ); }, 10000 ); - test.describe( 'List all products', () => { - test( 'defaults', async ( { request } ) => { - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - search: 'xxx', - }, + test.describe( + 'List all products', + { tag: [ '@skip-on-default-pressable', '@skip-on-default-wpcom' ] }, + () => { + test( 'defaults', async ( { request } ) => { + const result = await request.get( 'wp-json/wc/v3/products', { + params: { + search: 'xxx', + }, + } ); + + expect( result.status() ).toEqual( 200 ); + expect( result.headers()[ 'x-wp-total' ] ).toEqual( + PRODUCTS_COUNT.toString() + ); + expect( result.headers()[ 'x-wp-totalpages' ] ).toEqual( '2' ); } ); - expect( result.status() ).toEqual( 200 ); - expect( result.headers()[ 'x-wp-total' ] ).toEqual( - PRODUCTS_COUNT.toString() - ); - expect( result.headers()[ 'x-wp-totalpages' ] ).toEqual( '2' ); - } ); + test( 'pagination', async ( { request } ) => { + const pageSize = 6; + const page1 = await request.get( 'wp-json/wc/v3/products', { + params: { + per_page: pageSize, + search: 'xxx', + }, + } ); + const page1JSON = await page1.json(); + const page2 = await request.get( 'wp-json/wc/v3/products', { + params: { + per_page: pageSize, + page: 2, + search: 'xxx', + }, + } ); + const page2JSON = await page2.json(); + expect( page1.status() ).toEqual( 200 ); + expect( page2.status() ).toEqual( 200 ); - test( 'pagination', async ( { request } ) => { - const pageSize = 6; - const page1 = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: pageSize, - search: 'xxx', - }, - } ); - const page1JSON = await page1.json(); - const page2 = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: pageSize, - page: 2, - search: 'xxx', - }, - } ); - const page2JSON = await page2.json(); - expect( page1.status() ).toEqual( 200 ); - expect( page2.status() ).toEqual( 200 ); + // Verify total page count. + expect( page1.headers()[ 'x-wp-total' ] ).toEqual( + PRODUCTS_COUNT.toString() + ); + expect( page1.headers()[ 'x-wp-totalpages' ] ).toEqual( '4' ); - // Verify total page count. - expect( page1.headers()[ 'x-wp-total' ] ).toEqual( - PRODUCTS_COUNT.toString() - ); - expect( page1.headers()[ 'x-wp-totalpages' ] ).toEqual( '4' ); + // Verify we get pageSize'd arrays. + expect( Array.isArray( page1JSON ) ).toBe( true ); + expect( Array.isArray( page2JSON ) ).toBe( true ); + expect( page1JSON ).toHaveLength( pageSize ); + expect( page2JSON ).toHaveLength( pageSize ); - // Verify we get pageSize'd arrays. - expect( Array.isArray( page1JSON ) ).toBe( true ); - expect( Array.isArray( page2JSON ) ).toBe( true ); - expect( page1JSON ).toHaveLength( pageSize ); - expect( page2JSON ).toHaveLength( pageSize ); + // Ensure all of the product IDs are unique (no page overlap). + const allProductIds = page1JSON + .concat( page2JSON ) + .reduce( ( acc, product ) => { + acc[ product.id ] = 1; + return acc; + }, {} ); + expect( Object.keys( allProductIds ) ).toHaveLength( + pageSize * 2 + ); - // Ensure all of the product IDs are unique (no page overlap). - const allProductIds = page1JSON - .concat( page2JSON ) - .reduce( ( acc, product ) => { - acc[ product.id ] = 1; - return acc; - }, {} ); - expect( Object.keys( allProductIds ) ).toHaveLength( pageSize * 2 ); - - // Verify that offset takes precedent over page number. - const page2Offset = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: pageSize, - page: 2, - offset: pageSize + 1, - search: 'xxx', - }, - } ); - const page2OffsetJSON = await page2Offset.json(); - // The offset pushes the result set 1 product past the start of page 2. - expect( page2OffsetJSON ).toEqual( - expect.not.arrayContaining( [ - expect.objectContaining( { - id: page2JSON[ 0 ].id, - } ), - ] ) - ); - expect( page2OffsetJSON[ 0 ].id ).toEqual( page2JSON[ 1 ].id ); - - // Verify the last page only has 2 products as we expect. - const lastPage = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: pageSize, - page: 4, - search: 'xxx', - }, - } ); - const lastPageJSON = await lastPage.json(); - expect( Array.isArray( lastPageJSON ) ).toBe( true ); - expect( lastPageJSON ).toHaveLength( 2 ); - - // Verify a page outside the total page count is empty. - const page6 = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: pageSize, - page: 6, - search: 'xxx', - }, - } ); - const page6JSON = await page6.json(); - expect( Array.isArray( page6JSON ) ).toBe( true ); - expect( page6JSON ).toHaveLength( 0 ); - } ); - - test( 'search', async ( { request } ) => { - // Match in the short description. - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - search: 'external', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON.length ).toBeGreaterThanOrEqual( 1 ); - expect( result1JSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - name: 'WordPress Pennant xxx', - } ), - ] ) - ); - - // Match in the product name. - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - search: 'pocket xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 1 ); - expect( result2JSON[ 0 ].name ).toBe( 'Hoodie with Pocket xxx' ); - } ); - - test( 'inclusion / exclusion', async ( { request } ) => { - const allProducts = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: 20, - search: 'xxx', - }, - } ); - const allProductsJSON = await allProducts.json(); - expect( allProducts.status() ).toEqual( 200 ); - const allProductIds = allProductsJSON.map( - ( product ) => product.id - ); - expect( allProductIds ).toHaveLength( PRODUCTS_COUNT ); - - const productsToFilter = [ - allProductIds[ 2 ], - allProductIds[ 4 ], - allProductIds[ 7 ], - allProductIds[ 13 ], - ]; - - const included = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: 20, - include: productsToFilter.join( ',' ), - }, - } ); - const includedJSON = await included.json(); - expect( included.status() ).toEqual( 200 ); - expect( includedJSON ).toHaveLength( productsToFilter.length ); - expect( includedJSON ).toEqual( - expect.arrayContaining( - productsToFilter.map( ( id ) => + // Verify that offset takes precedent over page number. + const page2Offset = await request.get( + 'wp-json/wc/v3/products', + { + params: { + per_page: pageSize, + page: 2, + offset: pageSize + 1, + search: 'xxx', + }, + } + ); + const page2OffsetJSON = await page2Offset.json(); + // The offset pushes the result set 1 product past the start of page 2. + expect( page2OffsetJSON ).toEqual( + expect.not.arrayContaining( [ expect.objectContaining( { - id, - } ) - ) - ) - ); + id: page2JSON[ 0 ].id, + } ), + ] ) + ); + expect( page2OffsetJSON[ 0 ].id ).toEqual( page2JSON[ 1 ].id ); - const excluded = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: 20, - exclude: productsToFilter.join( ',' ), - }, + // Verify the last page only has 2 products as we expect. + const lastPage = await request.get( 'wp-json/wc/v3/products', { + params: { + per_page: pageSize, + page: 4, + search: 'xxx', + }, + } ); + const lastPageJSON = await lastPage.json(); + expect( Array.isArray( lastPageJSON ) ).toBe( true ); + expect( lastPageJSON ).toHaveLength( 2 ); + + // Verify a page outside the total page count is empty. + const page6 = await request.get( 'wp-json/wc/v3/products', { + params: { + per_page: pageSize, + page: 6, + search: 'xxx', + }, + } ); + const page6JSON = await page6.json(); + expect( Array.isArray( page6JSON ) ).toBe( true ); + expect( page6JSON ).toHaveLength( 0 ); } ); - const excludedJSON = await excluded.json(); - expect( excluded.status() ).toEqual( 200 ); - expect( excludedJSON.length ).toBeGreaterThanOrEqual( - Number( PRODUCTS_COUNT - productsToFilter.length ) - ); - expect( excludedJSON ).toEqual( - expect.not.arrayContaining( - productsToFilter.map( ( id ) => + + test( 'search', async ( { request } ) => { + // Match in the short description. + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + search: 'external', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON.length ).toBeGreaterThanOrEqual( 1 ); + expect( result1JSON ).toEqual( + expect.arrayContaining( [ expect.objectContaining( { - id, - } ) + name: 'WordPress Pennant xxx', + } ), + ] ) + ); + + // Match in the product name. + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + search: 'pocket xxx', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 1 ); + expect( result2JSON[ 0 ].name ).toBe( + 'Hoodie with Pocket xxx' + ); + } ); + + test( 'inclusion / exclusion', async ( { request } ) => { + const allProducts = await request.get( + 'wp-json/wc/v3/products', + { + params: { + per_page: 20, + search: 'xxx', + }, + } + ); + const allProductsJSON = await allProducts.json(); + expect( allProducts.status() ).toEqual( 200 ); + const allProductIds = allProductsJSON.map( + ( product ) => product.id + ); + expect( allProductIds ).toHaveLength( PRODUCTS_COUNT ); + + const productsToFilter = [ + allProductIds[ 2 ], + allProductIds[ 4 ], + allProductIds[ 7 ], + allProductIds[ 13 ], + ]; + + const included = await request.get( 'wp-json/wc/v3/products', { + params: { + per_page: 20, + include: productsToFilter.join( ',' ), + }, + } ); + const includedJSON = await included.json(); + expect( included.status() ).toEqual( 200 ); + expect( includedJSON ).toHaveLength( productsToFilter.length ); + expect( includedJSON ).toEqual( + expect.arrayContaining( + productsToFilter.map( ( id ) => + expect.objectContaining( { + id, + } ) + ) ) - ) + ); + + const excluded = await request.get( 'wp-json/wc/v3/products', { + params: { + per_page: 20, + exclude: productsToFilter.join( ',' ), + }, + } ); + const excludedJSON = await excluded.json(); + expect( excluded.status() ).toEqual( 200 ); + expect( excludedJSON.length ).toBeGreaterThanOrEqual( + Number( PRODUCTS_COUNT - productsToFilter.length ) + ); + expect( excludedJSON ).toEqual( + expect.not.arrayContaining( + productsToFilter.map( ( id ) => + expect.objectContaining( { + id, + } ) + ) + ) + ); + } ); + + test( 'slug', async ( { request } ) => { + // Match by slug. + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + slug: 't-shirt-with-logo-xxx', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 1 ); + expect( result1JSON[ 0 ].slug ).toBe( 't-shirt-with-logo-xxx' ); + + // No matches + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + slug: 'no-product-with-this-slug', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 0 ); + } ); + + test( 'sku', async ( { request } ) => { + // Match by SKU. + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + sku: 'woo-sunglasses-product', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 1 ); + expect( result1JSON[ 0 ].sku ).toBe( 'woo-sunglasses-product' ); + + // No matches + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + sku: 'no-product-with-this-sku', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 0 ); + } ); + + test( 'type', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + type: 'simple', + search: 'xxx', + }, + } ); + expect( result1.status() ).toEqual( 200 ); + expect( result1.headers()[ 'x-wp-total' ] ).toEqual( '16' ); + + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + type: 'external', + search: 'xxx', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 1 ); + expect( result2JSON[ 0 ].name ).toBe( 'WordPress Pennant xxx' ); + + const result3 = await request.get( 'wp-json/wc/v3/products', { + params: { + type: 'variable', + search: 'xxx', + }, + } ); + const result3JSON = await result3.json(); + expect( result3.status() ).toEqual( 200 ); + expect( result3JSON ).toHaveLength( 2 ); + + const result4 = await request.get( 'wp-json/wc/v3/products', { + params: { + type: 'grouped', + search: 'xxx', + }, + } ); + const result4JSON = await result4.json(); + expect( result4.status() ).toEqual( 200 ); + expect( result4JSON ).toHaveLength( 1 ); + expect( result4JSON[ 0 ].name ).toBe( 'Logo Collection xxx' ); + } ); + + test( 'featured', async ( { request } ) => { + const featured = [ + expect.objectContaining( { + name: 'Hoodie with Zipper xxx', + } ), + expect.objectContaining( { + name: 'Hoodie with Pocket xxx', + } ), + expect.objectContaining( { + name: 'Sunglasses xxx', + } ), + expect.objectContaining( { + name: 'Cap xxx', + } ), + expect.objectContaining( { + name: 'V-Neck T-Shirt xxx', + } ), + ]; + + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + featured: true, + search: 'xxx', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( featured.length ); + expect( result1JSON ).toEqual( + expect.arrayContaining( featured ) + ); + + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + featured: false, + search: 'xxx', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toEqual( + expect.not.arrayContaining( featured ) + ); + } ); + + test( + 'categories', + { tag: '@skip-on-default-wpcom' }, + async ( { request } ) => { + const accessory = [ + expect.objectContaining( { + name: 'Beanie xxx', + } ), + ]; + const hoodies = [ + expect.objectContaining( { + name: 'Hoodie with Zipper xxx', + } ), + expect.objectContaining( { + name: 'Hoodie with Pocket xxx', + } ), + expect.objectContaining( { + name: 'Hoodie with Logo xxx', + } ), + expect.objectContaining( { + name: 'Hoodie xxx', + } ), + ]; + + // Verify that subcategories are included. + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + per_page: 20, + category: sampleData.categories.clothingJSON.id, + }, + } + ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toEqual( + expect.arrayContaining( accessory ) + ); + expect( result1JSON ).toEqual( + expect.arrayContaining( hoodies ) + ); + + // Verify sibling categories are not. + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + category: sampleData.categories.hoodiesJSON.id, + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toEqual( + expect.not.arrayContaining( accessory ) + ); + expect( result2JSON ).toEqual( + expect.arrayContaining( hoodies ) + ); + } ); - } ); - test( 'slug', async ( { request } ) => { - // Match by slug. - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - slug: 't-shirt-with-logo-xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 1 ); - expect( result1JSON[ 0 ].slug ).toBe( 't-shirt-with-logo-xxx' ); - - // No matches - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - slug: 'no-product-with-this-slug', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 0 ); - } ); - - test( 'sku', async ( { request } ) => { - // Match by SKU. - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - sku: 'woo-sunglasses-product', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 1 ); - expect( result1JSON[ 0 ].sku ).toBe( 'woo-sunglasses-product' ); - - // No matches - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - sku: 'no-product-with-this-sku', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 0 ); - } ); - - test( 'type', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - type: 'simple', - search: 'xxx', - }, - } ); - expect( result1.status() ).toEqual( 200 ); - expect( result1.headers()[ 'x-wp-total' ] ).toEqual( '16' ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - type: 'external', - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 1 ); - expect( result2JSON[ 0 ].name ).toBe( 'WordPress Pennant xxx' ); - - const result3 = await request.get( 'wp-json/wc/v3/products', { - params: { - type: 'variable', - search: 'xxx', - }, - } ); - const result3JSON = await result3.json(); - expect( result3.status() ).toEqual( 200 ); - expect( result3JSON ).toHaveLength( 2 ); - - const result4 = await request.get( 'wp-json/wc/v3/products', { - params: { - type: 'grouped', - search: 'xxx', - }, - } ); - const result4JSON = await result4.json(); - expect( result4.status() ).toEqual( 200 ); - expect( result4JSON ).toHaveLength( 1 ); - expect( result4JSON[ 0 ].name ).toBe( 'Logo Collection xxx' ); - } ); - - test( 'featured', async ( { request } ) => { - const featured = [ - expect.objectContaining( { - name: 'Hoodie with Zipper xxx', - } ), - expect.objectContaining( { - name: 'Hoodie with Pocket xxx', - } ), - expect.objectContaining( { - name: 'Sunglasses xxx', - } ), - expect.objectContaining( { - name: 'Cap xxx', - } ), - expect.objectContaining( { - name: 'V-Neck T-Shirt xxx', - } ), - ]; - - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - featured: true, - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( featured.length ); - expect( result1JSON ).toEqual( expect.arrayContaining( featured ) ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - featured: false, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toEqual( - expect.not.arrayContaining( featured ) - ); - } ); - - test( 'categories', async ( { request } ) => { - const accessory = [ - expect.objectContaining( { - name: 'Beanie xxx', - } ), - ]; - const hoodies = [ - expect.objectContaining( { - name: 'Hoodie with Zipper xxx', - } ), - expect.objectContaining( { - name: 'Hoodie with Pocket xxx', - } ), - expect.objectContaining( { - name: 'Hoodie with Logo xxx', - } ), - expect.objectContaining( { - name: 'Hoodie xxx', - } ), - ]; - - // Verify that subcategories are included. - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - per_page: 20, - category: sampleData.categories.clothingJSON.id, - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toEqual( - expect.arrayContaining( accessory ) - ); - expect( result1JSON ).toEqual( expect.arrayContaining( hoodies ) ); - - // Verify sibling categories are not. - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - category: sampleData.categories.hoodiesJSON.id, - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toEqual( - expect.not.arrayContaining( accessory ) - ); - expect( result2JSON ).toEqual( expect.arrayContaining( hoodies ) ); - } ); - - test( 'on sale', async ( { request } ) => { - const onSale = [ - expect.objectContaining( { - name: 'Beanie with Logo xxx', - } ), - expect.objectContaining( { - name: 'Hoodie with Pocket xxx', - } ), - expect.objectContaining( { - name: 'Single xxx', - } ), - expect.objectContaining( { - name: 'Cap xxx', - } ), - expect.objectContaining( { - name: 'Belt xxx', - } ), - expect.objectContaining( { - name: 'Beanie xxx', - } ), - expect.objectContaining( { - name: 'Hoodie xxx', - } ), - ]; - - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - on_sale: true, - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( onSale.length ); - expect( result1JSON ).toEqual( expect.arrayContaining( onSale ) ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - on_sale: false, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toEqual( - expect.not.arrayContaining( onSale ) - ); - } ); - - test( 'price', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - min_price: 21, - max_price: 28, - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 1 ); - expect( result1JSON[ 0 ].name ).toBe( 'Long Sleeve Tee xxx' ); - expect( result1JSON[ 0 ].price ).toBe( '25' ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - max_price: 5, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 1 ); - expect( result2JSON[ 0 ].name ).toBe( 'Single xxx' ); - expect( result2JSON[ 0 ].price ).toBe( '2' ); - - const result3 = await request.get( 'wp-json/wc/v3/products', { - params: { - min_price: 5, - order: 'asc', - orderby: 'price', - search: 'xxx', - }, - } ); - const result3JSON = await result3.json(); - expect( result3.status() ).toEqual( 200 ); - expect( result3JSON ).toEqual( - expect.not.arrayContaining( [ + test( 'on sale', async ( { request } ) => { + const onSale = [ + expect.objectContaining( { + name: 'Beanie with Logo xxx', + } ), + expect.objectContaining( { + name: 'Hoodie with Pocket xxx', + } ), expect.objectContaining( { name: 'Single xxx', } ), - ] ) - ); - } ); + expect.objectContaining( { + name: 'Cap xxx', + } ), + expect.objectContaining( { + name: 'Belt xxx', + } ), + expect.objectContaining( { + name: 'Beanie xxx', + } ), + expect.objectContaining( { + name: 'Hoodie xxx', + } ), + ]; - test( 'before / after', async ( { request } ) => { - const before = [ - expect.objectContaining( { - name: 'Album xxx', - } ), - expect.objectContaining( { - name: 'Single xxx', - } ), - expect.objectContaining( { - name: 'T-Shirt with Logo xxx', - } ), - expect.objectContaining( { - name: 'Beanie with Logo xxx', - } ), - ]; - const after = [ - expect.objectContaining( { - name: 'Hoodie xxx', - } ), - expect.objectContaining( { - name: 'V-Neck T-Shirt xxx', - } ), - expect.objectContaining( { - name: 'Parent Product xxx', - } ), - expect.objectContaining( { - name: 'Child Product xxx', - } ), - ]; + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + on_sale: true, + search: 'xxx', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( onSale.length ); + expect( result1JSON ).toEqual( + expect.arrayContaining( onSale ) + ); - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - before: '2021-09-05T15:50:19', - search: 'xxx', - }, + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + on_sale: false, + search: 'xxx', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toEqual( + expect.not.arrayContaining( onSale ) + ); } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( before.length ); - expect( result1JSON ).toEqual( expect.arrayContaining( before ) ); - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - after: '2021-09-18T15:50:18', - search: 'xxx', - }, + test( 'price', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + min_price: 21, + max_price: 28, + search: 'xxx', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 1 ); + expect( result1JSON[ 0 ].name ).toBe( 'Long Sleeve Tee xxx' ); + expect( result1JSON[ 0 ].price ).toBe( '25' ); + + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + max_price: 5, + search: 'xxx', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 1 ); + expect( result2JSON[ 0 ].name ).toBe( 'Single xxx' ); + expect( result2JSON[ 0 ].price ).toBe( '2' ); + + const result3 = await request.get( 'wp-json/wc/v3/products', { + params: { + min_price: 5, + order: 'asc', + orderby: 'price', + search: 'xxx', + }, + } ); + const result3JSON = await result3.json(); + expect( result3.status() ).toEqual( 200 ); + expect( result3JSON ).toEqual( + expect.not.arrayContaining( [ + expect.objectContaining( { + name: 'Single xxx', + } ), + ] ) + ); } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toEqual( - expect.not.arrayContaining( before ) - ); - expect( result2JSON ).toHaveLength( after.length ); - expect( result2JSON ).toEqual( expect.arrayContaining( after ) ); - } ); - test( 'attributes', async ( { request } ) => { - const red = sampleData.attributes.colors.find( - ( term ) => term.name === 'Red' - ); - - const redProducts = [ - expect.objectContaining( { - name: 'V-Neck T-Shirt xxx', - } ), - expect.objectContaining( { - name: 'Hoodie xxx', - } ), - expect.objectContaining( { - name: 'Beanie xxx', - } ), - expect.objectContaining( { - name: 'Beanie with Logo xxx', - } ), - ]; - - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - attribute: 'pa_colorxxx', - attribute_term: red.id, - }, - } ); - const resultJSON = await result.json(); - - expect( result.status() ).toEqual( 200 ); - expect( resultJSON ).toHaveLength( redProducts.length ); - expect( resultJSON ).toEqual( - expect.arrayContaining( redProducts ) - ); - } ); - - test( 'status', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - status: 'pending', - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 1 ); - expect( result1JSON[ 0 ].name ).toBe( 'Polo xxx' ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - status: 'draft', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( 0 ); - } ); - - test( 'shipping class', async ( { request } ) => { - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - shipping_class: sampleData.shippingClasses.freightJSON.id, - }, - } ); - const resultJSON = await result.json(); - expect( result.status() ).toEqual( 200 ); - expect( resultJSON ).toHaveLength( 1 ); - expect( resultJSON[ 0 ].name ).toBe( 'Long Sleeve Tee xxx' ); - } ); - - test( 'tax class', async ( { request } ) => { - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - tax_class: 'reduced-rate', - search: 'xxx', - }, - } ); - const resultJSON = await result.json(); - expect( result.status() ).toEqual( 200 ); - expect( resultJSON ).toHaveLength( 1 ); - expect( resultJSON[ 0 ].name ).toBe( 'Sunglasses xxx' ); - } ); - - test( 'stock status', async ( { request } ) => { - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - stock_status: 'onbackorder', - search: 'xxx', - }, - } ); - const resultJSON = await result.json(); - expect( result.status() ).toEqual( 200 ); - expect( resultJSON ).toHaveLength( 1 ); - expect( resultJSON[ 0 ].name ).toBe( 'T-Shirt xxx' ); - } ); - - test( 'tags', async ( { request } ) => { - const coolProducts = [ - expect.objectContaining( { - name: 'Sunglasses xxx', - } ), - expect.objectContaining( { - name: 'Hoodie with Pocket xxx', - } ), - expect.objectContaining( { - name: 'Beanie xxx', - } ), - ]; - - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - tag: sampleData.tags.coolJSON.id, - }, - } ); - const resultJSON = await result.json(); - - expect( result.status() ).toEqual( 200 ); - expect( resultJSON ).toHaveLength( coolProducts.length ); - expect( resultJSON ).toEqual( - expect.arrayContaining( coolProducts ) - ); - } ); - - test( 'parent', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - parent: sampleData.hierarchicalProducts.parentJSON.id, - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( 1 ); - expect( result1JSON[ 0 ].name ).toBe( 'Child Product xxx' ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - parent_exclude: - sampleData.hierarchicalProducts.parentJSON.id, - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toEqual( - expect.not.arrayContaining( [ + test( 'before / after', async ( { request } ) => { + const before = [ + expect.objectContaining( { + name: 'Album xxx', + } ), + expect.objectContaining( { + name: 'Single xxx', + } ), + expect.objectContaining( { + name: 'T-Shirt with Logo xxx', + } ), + expect.objectContaining( { + name: 'Beanie with Logo xxx', + } ), + ]; + const after = [ + expect.objectContaining( { + name: 'Hoodie xxx', + } ), + expect.objectContaining( { + name: 'V-Neck T-Shirt xxx', + } ), + expect.objectContaining( { + name: 'Parent Product xxx', + } ), expect.objectContaining( { name: 'Child Product xxx', } ), - ] ) - ); - } ); - - test.describe( 'orderby', () => { - const productNamesAsc = [ - 'Album xxx', - 'Beanie with Logo xxx', - 'Beanie xxx', - 'Belt xxx', - 'Cap xxx', - 'Child Product xxx', - 'Hoodie with Logo xxx', - 'Hoodie with Pocket xxx', - 'Hoodie with Zipper xxx', - 'Hoodie xxx', - 'Logo Collection xxx', - 'Long Sleeve Tee xxx', - 'Parent Product xxx', - 'Polo xxx', - 'Single xxx', - 'Sunglasses xxx', - 'T-Shirt with Logo xxx', - 'T-Shirt xxx', - 'V-Neck T-Shirt xxx', - 'WordPress Pennant xxx', - ]; - const productNamesDesc = [ ...productNamesAsc ].reverse(); - const productNamesByRatingAsc = [ - 'Sunglasses xxx', - 'Cap xxx', - 'T-Shirt xxx', - ]; - const productNamesByRatingDesc = [ - ...productNamesByRatingAsc, - ].reverse(); - const productNamesByPopularityDesc = [ - 'Beanie with Logo xxx', - 'Single xxx', - 'T-Shirt xxx', - ]; - const productNamesByPopularityAsc = [ - ...productNamesByPopularityDesc, - ].reverse(); - - test( 'default', async ( { request } ) => { - // Default = date desc. - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - search: 'xxx', - }, - } ); - const resultJSON = await result.json(); - expect( result.status() ).toEqual( 200 ); - - // Verify all dates are in descending order. - let lastDate = Date.now(); - resultJSON.forEach( ( { date_created_gmt } ) => { - const created = Date.parse( date_created_gmt + '.000Z' ); - expect( lastDate ).toBeGreaterThan( created ); - lastDate = created; - } ); - } ); - - test( 'date', async ( { request } ) => { - const result = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'date', - search: 'xxx', - }, - } ); - const resultJSON = await result.json(); - expect( result.status() ).toEqual( 200 ); - - // Verify all dates are in ascending order. - let lastDate = 0; - resultJSON.forEach( ( { date_created_gmt } ) => { - const created = Date.parse( date_created_gmt + '.000Z' ); - expect( created ).toBeGreaterThan( lastDate ); - lastDate = created; - } ); - } ); - - test( 'id', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'id', - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - - // Verify all results are in ascending order. - let lastId = 0; - result1JSON.forEach( ( { id } ) => { - expect( id ).toBeGreaterThan( lastId ); - lastId = id; - } ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'desc', - orderby: 'id', - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - - // Verify all results are in descending order. - lastId = Number.MAX_SAFE_INTEGER; - result2JSON.forEach( ( { id } ) => { - expect( lastId ).toBeGreaterThan( id ); - lastId = id; - } ); - } ); - - test( 'title', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'title', - per_page: productNamesAsc.length, - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - - // Verify all results are in ascending order. - result1JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesAsc[ idx ] ); - } ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'desc', - orderby: 'title', - per_page: productNamesDesc.length, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - - // Verify all results are in descending order. - result2JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesDesc[ idx ] ); - } ); - } ); - - test( 'slug orderby', async ( { request } ) => { - const productNamesBySlugAsc = [ - 'Polo xxx', // The Polo isn't published so it has an empty slug. - ...productNamesAsc.filter( ( p ) => p !== 'Polo xxx' ), ]; - const productNamesBySlugDesc = [ - ...productNamesBySlugAsc, + + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + before: '2021-09-05T15:50:19', + search: 'xxx', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( before.length ); + expect( result1JSON ).toEqual( + expect.arrayContaining( before ) + ); + + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + after: '2021-09-18T15:50:18', + search: 'xxx', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toEqual( + expect.not.arrayContaining( before ) + ); + expect( result2JSON ).toHaveLength( after.length ); + expect( result2JSON ).toEqual( + expect.arrayContaining( after ) + ); + } ); + + test( 'attributes', async ( { request } ) => { + const red = sampleData.attributes.colors.find( + ( term ) => term.name === 'Red' + ); + + const redProducts = [ + expect.objectContaining( { + name: 'V-Neck T-Shirt xxx', + } ), + expect.objectContaining( { + name: 'Hoodie xxx', + } ), + expect.objectContaining( { + name: 'Beanie xxx', + } ), + expect.objectContaining( { + name: 'Beanie with Logo xxx', + } ), + ]; + + const result = await request.get( 'wp-json/wc/v3/products', { + params: { + attribute: 'pa_colorxxx', + attribute_term: red.id, + }, + } ); + const resultJSON = await result.json(); + + expect( result.status() ).toEqual( 200 ); + expect( resultJSON ).toHaveLength( redProducts.length ); + expect( resultJSON ).toEqual( + expect.arrayContaining( redProducts ) + ); + } ); + + test( 'status', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + status: 'pending', + search: 'xxx', + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 1 ); + expect( result1JSON[ 0 ].name ).toBe( 'Polo xxx' ); + + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + status: 'draft', + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( 0 ); + } ); + + test( 'shipping class', async ( { request } ) => { + const result = await request.get( 'wp-json/wc/v3/products', { + params: { + shipping_class: + sampleData.shippingClasses.freightJSON.id, + }, + } ); + const resultJSON = await result.json(); + expect( result.status() ).toEqual( 200 ); + expect( resultJSON ).toHaveLength( 1 ); + expect( resultJSON[ 0 ].name ).toBe( 'Long Sleeve Tee xxx' ); + } ); + + test( 'tax class', async ( { request } ) => { + const result = await request.get( 'wp-json/wc/v3/products', { + params: { + tax_class: 'reduced-rate', + search: 'xxx', + }, + } ); + const resultJSON = await result.json(); + expect( result.status() ).toEqual( 200 ); + expect( resultJSON ).toHaveLength( 1 ); + expect( resultJSON[ 0 ].name ).toBe( 'Sunglasses xxx' ); + } ); + + test( 'stock status', async ( { request } ) => { + const result = await request.get( 'wp-json/wc/v3/products', { + params: { + stock_status: 'onbackorder', + search: 'xxx', + }, + } ); + const resultJSON = await result.json(); + expect( result.status() ).toEqual( 200 ); + expect( resultJSON ).toHaveLength( 1 ); + expect( resultJSON[ 0 ].name ).toBe( 'T-Shirt xxx' ); + } ); + + test( 'tags', async ( { request } ) => { + const coolProducts = [ + expect.objectContaining( { + name: 'Sunglasses xxx', + } ), + expect.objectContaining( { + name: 'Hoodie with Pocket xxx', + } ), + expect.objectContaining( { + name: 'Beanie xxx', + } ), + ]; + + const result = await request.get( 'wp-json/wc/v3/products', { + params: { + tag: sampleData.tags.coolJSON.id, + }, + } ); + const resultJSON = await result.json(); + + expect( result.status() ).toEqual( 200 ); + expect( resultJSON ).toHaveLength( coolProducts.length ); + expect( resultJSON ).toEqual( + expect.arrayContaining( coolProducts ) + ); + } ); + + test( 'parent', async ( { request } ) => { + const result1 = await request.get( 'wp-json/wc/v3/products', { + params: { + parent: sampleData.hierarchicalProducts.parentJSON.id, + }, + } ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( 1 ); + expect( result1JSON[ 0 ].name ).toBe( 'Child Product xxx' ); + + const result2 = await request.get( 'wp-json/wc/v3/products', { + params: { + parent_exclude: + sampleData.hierarchicalProducts.parentJSON.id, + }, + } ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toEqual( + expect.not.arrayContaining( [ + expect.objectContaining( { + name: 'Child Product xxx', + } ), + ] ) + ); + } ); + + test.describe( 'orderby', () => { + const productNamesAsc = [ + 'Album xxx', + 'Beanie with Logo xxx', + 'Beanie xxx', + 'Belt xxx', + 'Cap xxx', + 'Child Product xxx', + 'Hoodie with Logo xxx', + 'Hoodie with Pocket xxx', + 'Hoodie with Zipper xxx', + 'Hoodie xxx', + 'Logo Collection xxx', + 'Long Sleeve Tee xxx', + 'Parent Product xxx', + 'Polo xxx', + 'Single xxx', + 'Sunglasses xxx', + 'T-Shirt with Logo xxx', + 'T-Shirt xxx', + 'V-Neck T-Shirt xxx', + 'WordPress Pennant xxx', + ]; + const productNamesDesc = [ ...productNamesAsc ].reverse(); + const productNamesByRatingAsc = [ + 'Sunglasses xxx', + 'Cap xxx', + 'T-Shirt xxx', + ]; + const productNamesByRatingDesc = [ + ...productNamesByRatingAsc, + ].reverse(); + const productNamesByPopularityDesc = [ + 'Beanie with Logo xxx', + 'Single xxx', + 'T-Shirt xxx', + ]; + const productNamesByPopularityAsc = [ + ...productNamesByPopularityDesc, ].reverse(); - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'slug', - per_page: productNamesBySlugAsc.length, - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); + test( 'default', async ( { request } ) => { + // Default = date desc. + const result = await request.get( + 'wp-json/wc/v3/products', + { + params: { + search: 'xxx', + }, + } + ); + const resultJSON = await result.json(); + expect( result.status() ).toEqual( 200 ); - // Verify all results are in ascending order. - result1JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesBySlugAsc[ idx ] ); + // Verify all dates are in descending order. + let lastDate = Date.now(); + resultJSON.forEach( ( { date_created_gmt } ) => { + const created = Date.parse( + date_created_gmt + '.000Z' + ); + expect( lastDate ).toBeGreaterThan( created ); + lastDate = created; + } ); } ); - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'desc', - orderby: 'slug', - per_page: productNamesBySlugDesc.length, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); + test( 'date', async ( { request } ) => { + const result = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'date', + search: 'xxx', + }, + } + ); + const resultJSON = await result.json(); + expect( result.status() ).toEqual( 200 ); - // Verify all results are in descending order. - result2JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesBySlugDesc[ idx ] ); + // Verify all dates are in ascending order. + let lastDate = 0; + resultJSON.forEach( ( { date_created_gmt } ) => { + const created = Date.parse( + date_created_gmt + '.000Z' + ); + expect( created ).toBeGreaterThan( lastDate ); + lastDate = created; + } ); + } ); + + test( 'id', async ( { request } ) => { + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'id', + search: 'xxx', + }, + } + ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + + // Verify all results are in ascending order. + let lastId = 0; + result1JSON.forEach( ( { id } ) => { + expect( id ).toBeGreaterThan( lastId ); + lastId = id; + } ); + + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'desc', + orderby: 'id', + search: 'xxx', + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + + // Verify all results are in descending order. + lastId = Number.MAX_SAFE_INTEGER; + result2JSON.forEach( ( { id } ) => { + expect( lastId ).toBeGreaterThan( id ); + lastId = id; + } ); + } ); + + test( 'title', async ( { request } ) => { + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'title', + per_page: productNamesAsc.length, + search: 'xxx', + }, + } + ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + + // Verify all results are in ascending order. + result1JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesAsc[ idx ] ); + } ); + + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'desc', + orderby: 'title', + per_page: productNamesDesc.length, + search: 'xxx', + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + + // Verify all results are in descending order. + result2JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesDesc[ idx ] ); + } ); + } ); + + test( 'slug orderby', async ( { request } ) => { + const productNamesBySlugAsc = [ + 'Polo xxx', // The Polo isn't published so it has an empty slug. + ...productNamesAsc.filter( ( p ) => p !== 'Polo xxx' ), + ]; + const productNamesBySlugDesc = [ + ...productNamesBySlugAsc, + ].reverse(); + + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'slug', + per_page: productNamesBySlugAsc.length, + search: 'xxx', + }, + } + ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + + // Verify all results are in ascending order. + result1JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesBySlugAsc[ idx ] ); + } ); + + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'desc', + orderby: 'slug', + per_page: productNamesBySlugDesc.length, + search: 'xxx', + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + + // Verify all results are in descending order. + result2JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesBySlugDesc[ idx ] ); + } ); + } ); + + test( 'price orderby', async ( { request } ) => { + const productNamesMinPriceAsc = [ + 'Parent Product xxx', + 'Child Product xxx', + 'Single xxx', + 'WordPress Pennant xxx', + 'Album xxx', + 'V-Neck T-Shirt xxx', + 'Cap xxx', + 'Beanie with Logo xxx', + 'T-Shirt with Logo xxx', + 'Beanie xxx', + 'T-Shirt xxx', + 'Logo Collection xxx', + 'Polo xxx', + 'Long Sleeve Tee xxx', + 'Hoodie with Pocket xxx', + 'Hoodie xxx', + 'Hoodie with Zipper xxx', + 'Hoodie with Logo xxx', + 'Belt xxx', + 'Sunglasses xxx', + ]; + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'price', + per_page: productNamesMinPriceAsc.length, + search: 'xxx', + }, + } + ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( + productNamesMinPriceAsc.length + ); + + // Verify all results are in ascending order. + // The query uses the min price calculated in the product meta lookup table, + // so we can't just check the price property of the response. + result1JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesMinPriceAsc[ idx ] ); + } ); + + const productNamesMaxPriceDesc = [ + 'Sunglasses xxx', + 'Belt xxx', + 'Hoodie xxx', + 'Logo Collection xxx', + 'Hoodie with Logo xxx', + 'Hoodie with Zipper xxx', + 'Hoodie with Pocket xxx', + 'Long Sleeve Tee xxx', + 'V-Neck T-Shirt xxx', + 'Polo xxx', + 'T-Shirt xxx', + 'Beanie xxx', + 'T-Shirt with Logo xxx', + 'Beanie with Logo xxx', + 'Cap xxx', + 'Album xxx', + 'WordPress Pennant xxx', + 'Single xxx', + 'Child Product xxx', + 'Parent Product xxx', + ]; + + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'desc', + orderby: 'price', + per_page: productNamesMaxPriceDesc.length, + search: 'xxx', + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( + productNamesMaxPriceDesc.length + ); + + // Verify all results are in descending order. + // The query uses the max price calculated in the product meta lookup table, + // so we can't just check the price property of the response. + result2JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesMaxPriceDesc[ idx ] ); + } ); + } ); + + test( 'include', async ( { request } ) => { + const includeIds = [ + sampleData.groupedProducts[ 0 ].id, + sampleData.simpleProducts[ 3 ].id, + sampleData.hierarchicalProducts.parentJSON.id, + ]; + + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'include', + include: includeIds.join( ',' ), + }, + } + ); + const result1JSON = await result1.json(); + + expect( result1.status() ).toEqual( 200 ); + expect( result1JSON ).toHaveLength( includeIds.length ); + + // Verify all results are in proper order. + result1JSON.forEach( ( { id }, idx ) => { + expect( id ).toBe( includeIds[ idx ] ); + } ); + + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'desc', + orderby: 'include', + include: includeIds.join( ',' ), + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + expect( result2JSON ).toHaveLength( includeIds.length ); + + // Verify all results are in proper order. + result2JSON.forEach( ( { id }, idx ) => { + expect( id ).toBe( includeIds[ idx ] ); + } ); + } ); + + test( 'rating (desc)', async ( { request } ) => { + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'desc', + orderby: 'rating', + per_page: productNamesByRatingDesc.length, + search: 'xxx', + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + + // Verify all results are in descending order. + result2JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesByRatingDesc[ idx ] ); + } ); + } ); + + // This case will remain skipped until ratings can be sorted ascending. + // See: https://github.com/woocommerce/woocommerce/issues/30354#issuecomment-925955099. + test.skip( 'rating (asc)', async ( { request } ) => { + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'rating', + per_page: productNamesByRatingAsc.length, + search: 'xxx', + }, + } + ); + expect( result1.status() ).toEqual( 200 ); + const result1JSON = await result1.json(); + + // Verify all results are in ascending order. + result1JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( productNamesByRatingAsc[ idx ] ); + } ); + } ); + + // This case will remain skipped until popularity can be sorted ascending. + // See: https://github.com/woocommerce/woocommerce/issues/30354#issuecomment-925955099. + test.skip( 'popularity (asc)', async ( { request } ) => { + const result1 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'asc', + orderby: 'popularity', + per_page: productNamesByPopularityAsc.length, + search: 'xxx', + }, + } + ); + const result1JSON = await result1.json(); + expect( result1.status() ).toEqual( 200 ); + + // Verify all results are in ascending order. + result1JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( + productNamesByPopularityAsc[ idx ] + ); + } ); + } ); + + test( 'popularity (desc)', async ( { request } ) => { + const result2 = await request.get( + 'wp-json/wc/v3/products', + { + params: { + order: 'desc', + orderby: 'popularity', + per_page: productNamesByPopularityDesc.length, + search: 'xxx', + }, + } + ); + const result2JSON = await result2.json(); + expect( result2.status() ).toEqual( 200 ); + + // Verify all results are in descending order. + result2JSON.forEach( ( { name }, idx ) => { + expect( name ).toBe( + productNamesByPopularityDesc[ idx ] + ); + } ); } ); } ); - - test( 'price orderby', async ( { request } ) => { - const productNamesMinPriceAsc = [ - 'Parent Product xxx', - 'Child Product xxx', - 'Single xxx', - 'WordPress Pennant xxx', - 'Album xxx', - 'V-Neck T-Shirt xxx', - 'Cap xxx', - 'Beanie with Logo xxx', - 'T-Shirt with Logo xxx', - 'Beanie xxx', - 'T-Shirt xxx', - 'Logo Collection xxx', - 'Polo xxx', - 'Long Sleeve Tee xxx', - 'Hoodie with Pocket xxx', - 'Hoodie xxx', - 'Hoodie with Zipper xxx', - 'Hoodie with Logo xxx', - 'Belt xxx', - 'Sunglasses xxx', - ]; - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'price', - per_page: productNamesMinPriceAsc.length, - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( - productNamesMinPriceAsc.length - ); - - // Verify all results are in ascending order. - // The query uses the min price calculated in the product meta lookup table, - // so we can't just check the price property of the response. - result1JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesMinPriceAsc[ idx ] ); - } ); - - const productNamesMaxPriceDesc = [ - 'Sunglasses xxx', - 'Belt xxx', - 'Hoodie xxx', - 'Logo Collection xxx', - 'Hoodie with Logo xxx', - 'Hoodie with Zipper xxx', - 'Hoodie with Pocket xxx', - 'Long Sleeve Tee xxx', - 'V-Neck T-Shirt xxx', - 'Polo xxx', - 'T-Shirt xxx', - 'Beanie xxx', - 'T-Shirt with Logo xxx', - 'Beanie with Logo xxx', - 'Cap xxx', - 'Album xxx', - 'WordPress Pennant xxx', - 'Single xxx', - 'Child Product xxx', - 'Parent Product xxx', - ]; - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'desc', - orderby: 'price', - per_page: productNamesMaxPriceDesc.length, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( - productNamesMaxPriceDesc.length - ); - - // Verify all results are in descending order. - // The query uses the max price calculated in the product meta lookup table, - // so we can't just check the price property of the response. - result2JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesMaxPriceDesc[ idx ] ); - } ); - } ); - - test( 'include', async ( { request } ) => { - const includeIds = [ - sampleData.groupedProducts[ 0 ].id, - sampleData.simpleProducts[ 3 ].id, - sampleData.hierarchicalProducts.parentJSON.id, - ]; - - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'include', - include: includeIds.join( ',' ), - }, - } ); - const result1JSON = await result1.json(); - - expect( result1.status() ).toEqual( 200 ); - expect( result1JSON ).toHaveLength( includeIds.length ); - - // Verify all results are in proper order. - result1JSON.forEach( ( { id }, idx ) => { - expect( id ).toBe( includeIds[ idx ] ); - } ); - - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'desc', - orderby: 'include', - include: includeIds.join( ',' ), - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - expect( result2JSON ).toHaveLength( includeIds.length ); - - // Verify all results are in proper order. - result2JSON.forEach( ( { id }, idx ) => { - expect( id ).toBe( includeIds[ idx ] ); - } ); - } ); - - test( 'rating (desc)', async ( { request } ) => { - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'desc', - orderby: 'rating', - per_page: productNamesByRatingDesc.length, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - - // Verify all results are in descending order. - result2JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesByRatingDesc[ idx ] ); - } ); - } ); - - // This case will remain skipped until ratings can be sorted ascending. - // See: https://github.com/woocommerce/woocommerce/issues/30354#issuecomment-925955099. - test.skip( 'rating (asc)', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'rating', - per_page: productNamesByRatingAsc.length, - search: 'xxx', - }, - } ); - expect( result1.status() ).toEqual( 200 ); - const result1JSON = await result1.json(); - - // Verify all results are in ascending order. - result1JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesByRatingAsc[ idx ] ); - } ); - } ); - - // This case will remain skipped until popularity can be sorted ascending. - // See: https://github.com/woocommerce/woocommerce/issues/30354#issuecomment-925955099. - test.skip( 'popularity (asc)', async ( { request } ) => { - const result1 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'asc', - orderby: 'popularity', - per_page: productNamesByPopularityAsc.length, - search: 'xxx', - }, - } ); - const result1JSON = await result1.json(); - expect( result1.status() ).toEqual( 200 ); - - // Verify all results are in ascending order. - result1JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesByPopularityAsc[ idx ] ); - } ); - } ); - - test( 'popularity (desc)', async ( { request } ) => { - const result2 = await request.get( 'wp-json/wc/v3/products', { - params: { - order: 'desc', - orderby: 'popularity', - per_page: productNamesByPopularityDesc.length, - search: 'xxx', - }, - } ); - const result2JSON = await result2.json(); - expect( result2.status() ).toEqual( 200 ); - - // Verify all results are in descending order. - result2JSON.forEach( ( { name }, idx ) => { - expect( name ).toBe( productNamesByPopularityDesc[ idx ] ); - } ); - } ); - } ); - } ); + } + ); } ); diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/products-crud.test.js b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/products-crud.test.js index 64bf5072cfd..cbb39c3aed7 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/products-crud.test.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/products/products-crud.test.js @@ -589,278 +589,301 @@ test.describe( 'Products API tests: CRUD', () => { } ); } ); - test.describe( 'Product review tests: CRUD', () => { - let productReviewId; - let reviewsTestProduct; + test.describe( + 'Product review tests: CRUD', + { tag: '@skip-on-default-wpcom' }, + () => { + let productReviewId; + let reviewsTestProduct; - test.beforeAll( async ( { simpleTestProduct } ) => { - reviewsTestProduct = simpleTestProduct; - } ); - - test( 'can add a product review', async ( { request } ) => { - const response = await request.post( - 'wp-json/wc/v3/products/reviews', - { - data: { - product_id: reviewsTestProduct.id, - review: 'Nice simple product!', - reviewer: 'John Doe', - reviewer_email: 'john.doe@example.com', - rating: 5, - }, - } - ); - const responseJSON = await response.json(); - productReviewId = responseJSON.id; - - expect( response.status() ).toEqual( 201 ); - expect( typeof productReviewId ).toEqual( 'number' ); - expect( responseJSON.id ).toEqual( productReviewId ); - expect( responseJSON.product_name ).toEqual( 'A Simple Product' ); - expect( responseJSON.status ).toEqual( 'approved' ); - expect( responseJSON.reviewer ).toEqual( 'John Doe' ); - expect( responseJSON.reviewer_email ).toEqual( - 'john.doe@example.com' - ); - expect( responseJSON.review ).toEqual( 'Nice simple product!' ); - expect( responseJSON.rating ).toEqual( 5 ); - expect( responseJSON.verified ).toEqual( false ); - } ); - - test( 'cannot add a product review with invalid product_id', async ( { - request, - } ) => { - const response = await request.post( - 'wp-json/wc/v3/products/reviews', - { - data: { - product_id: 999, - review: 'A non existent product!', - reviewer: 'John Do Not', - reviewer_email: 'john.do.not@example.com', - rating: 5, - }, - } - ); - const responseJSON = await response.json(); - - expect( response.status() ).toEqual( 404 ); - expect( responseJSON.code ).toEqual( - 'woocommerce_rest_product_invalid_id' - ); - expect( responseJSON.message ).toEqual( 'Invalid product ID.' ); - } ); - - test( 'cannot add a duplicate product review', async ( { - request, - } ) => { - const response = await request.post( - 'wp-json/wc/v3/products/reviews', - { - data: { - product_id: reviewsTestProduct.id, - review: 'Nice simple product!', - reviewer: 'John Doe', - reviewer_email: 'john.doe@example.com', - rating: 5, - }, - } - ); - const responseJSON = await response.json(); - - expect( response.status() ).toEqual( 409 ); - expect( responseJSON.code ).toEqual( - 'woocommerce_rest_comment_duplicate' - ); - expect( responseJSON.message ).toEqual( - 'Duplicate comment detected; it looks as though you’ve already said that!' - ); - } ); - - test( 'can retrieve a product review', async ( { request } ) => { - const response = await request.get( - `wp-json/wc/v3/products/reviews/${ productReviewId }` - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( responseJSON.id ).toEqual( productReviewId ); - expect( responseJSON.product_id ).toEqual( reviewsTestProduct.id ); - expect( responseJSON.product_name ).toEqual( 'A Simple Product' ); - expect( responseJSON.status ).toEqual( 'approved' ); - expect( responseJSON.reviewer ).toEqual( 'John Doe' ); - expect( responseJSON.reviewer_email ).toEqual( - 'john.doe@example.com' - ); - expect( responseJSON.review ).toEqual( - 'Nice simple product!
\n' - ); - expect( responseJSON.rating ).toEqual( 5 ); - expect( responseJSON.verified ).toEqual( false ); - } ); - - test( 'can retrieve all product reviews', async ( { request } ) => { - // call API to retrieve all product reviews - const response = await request.get( - '/wp-json/wc/v3/products/reviews' - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( Array.isArray( responseJSON ) ).toBe( true ); - expect( responseJSON.length ).toBeGreaterThan( 0 ); - } ); - - test( 'can update a product review', async ( { request } ) => { - // call API to retrieve all product reviews - const response = await request.put( - `wp-json/wc/v3/products/reviews/${ productReviewId }`, - { - data: { - rating: 1, - }, - } - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( responseJSON.id ).toEqual( productReviewId ); - expect( responseJSON.product_id ).toEqual( reviewsTestProduct.id ); - expect( responseJSON.product_name ).toEqual( 'A Simple Product' ); - expect( responseJSON.status ).toEqual( 'approved' ); - expect( responseJSON.reviewer ).toEqual( 'John Doe' ); - expect( responseJSON.reviewer_email ).toEqual( - 'john.doe@example.com' - ); - expect( responseJSON.review ).toEqual( 'Nice simple product!' ); - expect( responseJSON.rating ).toEqual( 1 ); - expect( responseJSON.verified ).toEqual( false ); - } ); - - test( 'can permanently delete a product review', async ( { - request, - } ) => { - // Delete the product review. - const response = await request.delete( - `wp-json/wc/v3/products/reviews/${ productReviewId }`, - { - data: { - force: true, - }, - } - ); - expect( response.status() ).toEqual( 200 ); - - // Verify that the product review can no longer be retrieved. - const getDeletedProductReviewResponse = await request.get( - `wp-json/wc/v3/products/reviews/${ productReviewId }` - ); - expect( getDeletedProductReviewResponse.status() ).toEqual( 404 ); - } ); - - test( 'can batch update product reviews', async ( { request } ) => { - // Batch create product reviews. - const response = await request.post( - `wp-json/wc/v3/products/reviews/batch`, - { - data: { - create: [ - { - product_id: reviewsTestProduct.id, - review: 'Nice product!', - reviewer: 'John Doe', - reviewer_email: 'john.doe@example.com', - rating: 4, - }, - { - product_id: reviewsTestProduct.id, - review: 'I love this thing!', - reviewer: 'Jane Doe', - reviewer_email: 'Jane.doe@example.com', - rating: 5, - }, - ], - }, - } - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( responseJSON.create[ 0 ].product_id ).toEqual( - reviewsTestProduct.id - ); - expect( responseJSON.create[ 0 ].review ).toEqual( - 'Nice product!' - ); - expect( responseJSON.create[ 0 ].reviewer ).toEqual( 'John Doe' ); - expect( responseJSON.create[ 0 ].reviewer_email ).toEqual( - 'john.doe@example.com' - ); - expect( responseJSON.create[ 0 ].rating ).toEqual( 4 ); - - expect( responseJSON.create[ 1 ].product_id ).toEqual( - reviewsTestProduct.id - ); - expect( responseJSON.create[ 1 ].review ).toEqual( - 'I love this thing!' - ); - expect( responseJSON.create[ 1 ].reviewer ).toEqual( 'Jane Doe' ); - expect( responseJSON.create[ 1 ].reviewer_email ).toEqual( - 'Jane.doe@example.com' - ); - expect( responseJSON.create[ 1 ].rating ).toEqual( 5 ); - const review1Id = responseJSON.create[ 0 ].id; - const review2Id = responseJSON.create[ 1 ].id; - - // Batch create a new review, update a review and delete another. - const responseBatchUpdate = await request.post( - `wp-json/wc/v3/products/reviews/batch`, - { - data: { - create: [ - { - product_id: reviewsTestProduct.id, - review: 'Ok product.', - reviewer: 'Jack Doe', - reviewer_email: 'jack.doe@example.com', - rating: 3, - }, - ], - update: [ - { - id: review1Id, - review: 'On reflection, I hate this thing!', - rating: 1, - }, - ], - delete: [ review2Id ], - }, - } - ); - const responseBatchUpdateJSON = await responseBatchUpdate.json(); - const review3Id = responseBatchUpdateJSON.create[ 0 ].id; - expect( response.status() ).toEqual( 200 ); - - const responseUpdatedReview = await request.get( - `wp-json/wc/v3/products/reviews/${ review1Id }` - ); - const responseUpdatedReviewJSON = - await responseUpdatedReview.json(); - expect( responseUpdatedReviewJSON.review ).toEqual( - 'On reflection, I hate this thing!
\n' - ); - expect( responseUpdatedReviewJSON.rating ).toEqual( 1 ); - - // Verify that the deleted review can no longer be retrieved. - const getDeletedProductReviewResponse = await request.get( - `wp-json/wc/v3/products/reviews/${ review2Id }` - ); - expect( getDeletedProductReviewResponse.status() ).toEqual( 404 ); - - // Batch delete the created tags - await request.post( `wp-json/wc/v3/products/reviews/batch`, { - data: { - delete: [ review1Id, review3Id ], - }, + test.beforeAll( async ( { simpleTestProduct } ) => { + reviewsTestProduct = simpleTestProduct; } ); - } ); - } ); + + test( 'can add a product review', async ( { request } ) => { + const response = await request.post( + 'wp-json/wc/v3/products/reviews', + { + data: { + product_id: reviewsTestProduct.id, + review: 'Nice simple product!', + reviewer: 'John Doe', + reviewer_email: 'john.doe@example.com', + rating: 5, + }, + } + ); + const responseJSON = await response.json(); + productReviewId = responseJSON.id; + + expect( response.status() ).toEqual( 201 ); + expect( typeof productReviewId ).toEqual( 'number' ); + expect( responseJSON.id ).toEqual( productReviewId ); + expect( responseJSON.product_name ).toEqual( + 'A Simple Product' + ); + expect( responseJSON.status ).toEqual( 'approved' ); + expect( responseJSON.reviewer ).toEqual( 'John Doe' ); + expect( responseJSON.reviewer_email ).toEqual( + 'john.doe@example.com' + ); + expect( responseJSON.review ).toEqual( 'Nice simple product!' ); + expect( responseJSON.rating ).toEqual( 5 ); + expect( responseJSON.verified ).toEqual( false ); + } ); + + test( 'cannot add a product review with invalid product_id', async ( { + request, + } ) => { + const response = await request.post( + 'wp-json/wc/v3/products/reviews', + { + data: { + product_id: 999, + review: 'A non existent product!', + reviewer: 'John Do Not', + reviewer_email: 'john.do.not@example.com', + rating: 5, + }, + } + ); + const responseJSON = await response.json(); + + expect( response.status() ).toEqual( 404 ); + expect( responseJSON.code ).toEqual( + 'woocommerce_rest_product_invalid_id' + ); + expect( responseJSON.message ).toEqual( 'Invalid product ID.' ); + } ); + + test( 'cannot add a duplicate product review', async ( { + request, + } ) => { + const response = await request.post( + 'wp-json/wc/v3/products/reviews', + { + data: { + product_id: reviewsTestProduct.id, + review: 'Nice simple product!', + reviewer: 'John Doe', + reviewer_email: 'john.doe@example.com', + rating: 5, + }, + } + ); + const responseJSON = await response.json(); + + expect( response.status() ).toEqual( 409 ); + expect( responseJSON.code ).toEqual( + 'woocommerce_rest_comment_duplicate' + ); + expect( responseJSON.message ).toEqual( + 'Duplicate comment detected; it looks as though you’ve already said that!' + ); + } ); + + test( 'can retrieve a product review', async ( { request } ) => { + const response = await request.get( + `wp-json/wc/v3/products/reviews/${ productReviewId }` + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( responseJSON.id ).toEqual( productReviewId ); + expect( responseJSON.product_id ).toEqual( + reviewsTestProduct.id + ); + expect( responseJSON.product_name ).toEqual( + 'A Simple Product' + ); + expect( responseJSON.status ).toEqual( 'approved' ); + expect( responseJSON.reviewer ).toEqual( 'John Doe' ); + expect( responseJSON.reviewer_email ).toEqual( + 'john.doe@example.com' + ); + expect( responseJSON.review ).toEqual( + 'Nice simple product!
\n' + ); + expect( responseJSON.rating ).toEqual( 5 ); + expect( responseJSON.verified ).toEqual( false ); + } ); + + test( 'can retrieve all product reviews', async ( { request } ) => { + // call API to retrieve all product reviews + const response = await request.get( + '/wp-json/wc/v3/products/reviews' + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( Array.isArray( responseJSON ) ).toBe( true ); + expect( responseJSON.length ).toBeGreaterThan( 0 ); + } ); + + test( 'can update a product review', async ( { request } ) => { + // call API to retrieve all product reviews + const response = await request.put( + `wp-json/wc/v3/products/reviews/${ productReviewId }`, + { + data: { + rating: 1, + }, + } + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( responseJSON.id ).toEqual( productReviewId ); + expect( responseJSON.product_id ).toEqual( + reviewsTestProduct.id + ); + expect( responseJSON.product_name ).toEqual( + 'A Simple Product' + ); + expect( responseJSON.status ).toEqual( 'approved' ); + expect( responseJSON.reviewer ).toEqual( 'John Doe' ); + expect( responseJSON.reviewer_email ).toEqual( + 'john.doe@example.com' + ); + expect( responseJSON.review ).toEqual( 'Nice simple product!' ); + expect( responseJSON.rating ).toEqual( 1 ); + expect( responseJSON.verified ).toEqual( false ); + } ); + + test( 'can permanently delete a product review', async ( { + request, + } ) => { + // Delete the product review. + const response = await request.delete( + `wp-json/wc/v3/products/reviews/${ productReviewId }`, + { + data: { + force: true, + }, + } + ); + expect( response.status() ).toEqual( 200 ); + + // Verify that the product review can no longer be retrieved. + const getDeletedProductReviewResponse = await request.get( + `wp-json/wc/v3/products/reviews/${ productReviewId }` + ); + expect( getDeletedProductReviewResponse.status() ).toEqual( + 404 + ); + } ); + + test( 'can batch update product reviews', async ( { request } ) => { + // Batch create product reviews. + const response = await request.post( + `wp-json/wc/v3/products/reviews/batch`, + { + data: { + create: [ + { + product_id: reviewsTestProduct.id, + review: 'Nice product!', + reviewer: 'John Doe', + reviewer_email: 'john.doe@example.com', + rating: 4, + }, + { + product_id: reviewsTestProduct.id, + review: 'I love this thing!', + reviewer: 'Jane Doe', + reviewer_email: 'Jane.doe@example.com', + rating: 5, + }, + ], + }, + } + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( responseJSON.create[ 0 ].product_id ).toEqual( + reviewsTestProduct.id + ); + expect( responseJSON.create[ 0 ].review ).toEqual( + 'Nice product!' + ); + expect( responseJSON.create[ 0 ].reviewer ).toEqual( + 'John Doe' + ); + expect( responseJSON.create[ 0 ].reviewer_email ).toEqual( + 'john.doe@example.com' + ); + expect( responseJSON.create[ 0 ].rating ).toEqual( 4 ); + + expect( responseJSON.create[ 1 ].product_id ).toEqual( + reviewsTestProduct.id + ); + expect( responseJSON.create[ 1 ].review ).toEqual( + 'I love this thing!' + ); + expect( responseJSON.create[ 1 ].reviewer ).toEqual( + 'Jane Doe' + ); + expect( responseJSON.create[ 1 ].reviewer_email ).toEqual( + 'Jane.doe@example.com' + ); + expect( responseJSON.create[ 1 ].rating ).toEqual( 5 ); + const review1Id = responseJSON.create[ 0 ].id; + const review2Id = responseJSON.create[ 1 ].id; + + // Batch create a new review, update a review and delete another. + const responseBatchUpdate = await request.post( + `wp-json/wc/v3/products/reviews/batch`, + { + data: { + create: [ + { + product_id: reviewsTestProduct.id, + review: 'Ok product.', + reviewer: 'Jack Doe', + reviewer_email: 'jack.doe@example.com', + rating: 3, + }, + ], + update: [ + { + id: review1Id, + review: 'On reflection, I hate this thing!', + rating: 1, + }, + ], + delete: [ review2Id ], + }, + } + ); + const responseBatchUpdateJSON = + await responseBatchUpdate.json(); + const review3Id = responseBatchUpdateJSON.create[ 0 ].id; + expect( response.status() ).toEqual( 200 ); + + const responseUpdatedReview = await request.get( + `wp-json/wc/v3/products/reviews/${ review1Id }` + ); + const responseUpdatedReviewJSON = + await responseUpdatedReview.json(); + expect( responseUpdatedReviewJSON.review ).toEqual( + 'On reflection, I hate this thing!
\n' + ); + expect( responseUpdatedReviewJSON.rating ).toEqual( 1 ); + + // Verify that the deleted review can no longer be retrieved. + const getDeletedProductReviewResponse = await request.get( + `wp-json/wc/v3/products/reviews/${ review2Id }` + ); + expect( getDeletedProductReviewResponse.status() ).toEqual( + 404 + ); + + // Batch delete the created tags + await request.post( `wp-json/wc/v3/products/reviews/batch`, { + data: { + delete: [ review1Id, review3Id ], + }, + } ); + } ); + } + ); test.describe( 'Product shipping classes tests: CRUD', () => { let productShippingClassId; @@ -958,83 +981,91 @@ test.describe( 'Products API tests: CRUD', () => { ); } ); - test( 'can batch update product shipping classes', async ( { - request, - } ) => { - // Batch create product shipping classes. - const response = await request.post( - `wp-json/wc/v3/products/shipping_classes/batch`, - { - data: { - create: [ - { - name: 'Small Items', - }, - { - name: 'Large Items', - }, - ], - }, - } - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( responseJSON.create[ 0 ].name ).toEqual( 'Small Items' ); - expect( responseJSON.create[ 1 ].name ).toEqual( 'Large Items' ); - const shippingClass1Id = responseJSON.create[ 0 ].id; - const shippingClass2Id = responseJSON.create[ 1 ].id; + test( + 'can batch update product shipping classes', + { tag: [ '@skip-on-default-pressable', '@skip-on-default-wpcom' ] }, + async ( { request } ) => { + // Batch create product shipping classes. + const response = await request.post( + `wp-json/wc/v3/products/shipping_classes/batch`, + { + data: { + create: [ + { + name: 'Small Items', + }, + { + name: 'Large Items', + }, + ], + }, + } + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( responseJSON.create[ 0 ].name ).toEqual( + 'Small Items' + ); + expect( responseJSON.create[ 1 ].name ).toEqual( + 'Large Items' + ); + const shippingClass1Id = responseJSON.create[ 0 ].id; + const shippingClass2Id = responseJSON.create[ 1 ].id; - // Batch create a new shipping class, update a shipping class and delete another. - const responseBatchUpdate = await request.post( - `wp-json/wc/v3/products/shipping_classes/batch`, - { - data: { - create: [ - { - name: 'Express', - }, - ], - update: [ - { - id: shippingClass1Id, - description: 'Priority shipping.', - }, - ], - delete: [ shippingClass2Id ], - }, - } - ); - const responseBatchUpdateJSON = await responseBatchUpdate.json(); - const shippingClass3Id = responseBatchUpdateJSON.create[ 0 ].id; - expect( response.status() ).toEqual( 200 ); + // Batch create a new shipping class, update a shipping class and delete another. + const responseBatchUpdate = await request.post( + `wp-json/wc/v3/products/shipping_classes/batch`, + { + data: { + create: [ + { + name: 'Express', + }, + ], + update: [ + { + id: shippingClass1Id, + description: 'Priority shipping.', + }, + ], + delete: [ shippingClass2Id ], + }, + } + ); + const responseBatchUpdateJSON = + await responseBatchUpdate.json(); + const shippingClass3Id = responseBatchUpdateJSON.create[ 0 ].id; + expect( response.status() ).toEqual( 200 ); - const responseUpdatedShippingClass = await request.get( - `wp-json/wc/v3/products/shipping_classes/${ shippingClass1Id }` - ); - const responseUpdatedShippingClassJSON = - await responseUpdatedShippingClass.json(); - expect( responseUpdatedShippingClassJSON.description ).toEqual( - 'Priority shipping.' - ); + const responseUpdatedShippingClass = await request.get( + `wp-json/wc/v3/products/shipping_classes/${ shippingClass1Id }` + ); + const responseUpdatedShippingClassJSON = + await responseUpdatedShippingClass.json(); + expect( responseUpdatedShippingClassJSON.description ).toEqual( + 'Priority shipping.' + ); - // Verify that the product tag can no longer be retrieved. - const getDeletedProductShippingClassResponse = await request.get( - `wp-json/wc/v3/products/shipping_classes/${ shippingClass2Id }` - ); - expect( getDeletedProductShippingClassResponse.status() ).toEqual( - 404 - ); + // Verify that the product tag can no longer be retrieved. + const getDeletedProductShippingClassResponse = + await request.get( + `wp-json/wc/v3/products/shipping_classes/${ shippingClass2Id }` + ); + expect( + getDeletedProductShippingClassResponse.status() + ).toEqual( 404 ); - // Batch delete the created tags - await request.post( - `wp-json/wc/v3/products/shipping_classes/batch`, - { - data: { - delete: [ shippingClass1Id, shippingClass3Id ], - }, - } - ); - } ); + // Batch delete the created tags + await request.post( + `wp-json/wc/v3/products/shipping_classes/batch`, + { + data: { + delete: [ shippingClass1Id, shippingClass3Id ], + }, + } + ); + } + ); } ); test.describe( 'Product tags tests: CRUD', () => { diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js index 376d606c745..e7caee7e0b4 100644 --- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js +++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/settings/settings-crud.test.js @@ -280,7 +280,7 @@ test.describe.serial( 'Settings API tests: CRUD', () => { type: 'text', default: '', tip: 'The street address for your business location.', - value: '', + value: expect.any( String ), } ), ] ) ); @@ -310,7 +310,7 @@ test.describe.serial( 'Settings API tests: CRUD', () => { type: 'text', default: '', tip: 'The city in which your business is located.', - value: '', + value: expect.any( String ), } ), ] ) ); @@ -341,7 +341,7 @@ test.describe.serial( 'Settings API tests: CRUD', () => { type: 'text', default: '', tip: 'The postal code, if any, in which your business is located.', - value: '', + value: expect.any( String ), } ), ] ) ); @@ -1019,157 +1019,164 @@ test.describe.serial( 'Settings API tests: CRUD', () => { } ); test.describe( 'List all Tax settings options', () => { - test( 'can retrieve all tax settings', async ( { request } ) => { - // call API to retrieve all settings options - const response = await request.get( '/wp-json/wc/v3/settings/tax' ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( Array.isArray( responseJSON ) ).toBe( true ); - expect( responseJSON.length ).toBeGreaterThan( 0 ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_prices_include_tax', - label: 'Prices entered with tax', - description: '', - type: 'radio', - default: 'no', - options: { - yes: 'Yes, I will enter prices inclusive of tax', - no: 'No, I will enter prices exclusive of tax', - }, - tip: 'This option is important as it will affect how you input prices. Changing it will not update existing products.', - value: 'no', - } ), - ] ) - ); + test( + 'can retrieve all tax settings', + { tag: [ '@skip-on-default-pressable', '@skip-on-default-wpcom' ] }, + async ( { request } ) => { + // call API to retrieve all settings options + const response = await request.get( + '/wp-json/wc/v3/settings/tax' + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( Array.isArray( responseJSON ) ).toBe( true ); + expect( responseJSON.length ).toBeGreaterThan( 0 ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_prices_include_tax', + label: 'Prices entered with tax', + description: '', + type: 'radio', + default: 'no', + options: { + yes: 'Yes, I will enter prices inclusive of tax', + no: 'No, I will enter prices exclusive of tax', + }, + tip: 'This option is important as it will affect how you input prices. Changing it will not update existing products.', + value: 'no', + } ), + ] ) + ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_tax_based_on', - label: 'Calculate tax based on', - description: '', - type: 'select', - default: 'shipping', - options: { - shipping: 'Customer shipping address', - billing: 'Customer billing address', - base: 'Shop base address', - }, - tip: 'This option determines which address is used to calculate tax.', - value: 'shipping', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_shipping_tax_class', - label: 'Shipping tax class', - description: - 'Optionally control which tax class shipping gets, or leave it so shipping tax is based on the cart items themselves.', - type: 'select', - default: 'inherit', - options: { - inherit: 'Shipping tax class based on cart items', - '': 'Standard', - 'reduced-rate': 'Reduced rate', - 'zero-rate': 'Zero rate', - }, - tip: 'Optionally control which tax class shipping gets, or leave it so shipping tax is based on the cart items themselves.', - value: 'inherit', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_tax_round_at_subtotal', - label: 'Rounding', - description: - 'Round tax at subtotal level, instead of rounding per line', - type: 'checkbox', - default: 'no', - value: 'no', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_tax_classes', - label: 'Additional tax classes', - description: '', - type: 'textarea', - default: '', - tip: 'List additional tax classes you need below (1 per line, e.g. Reduced Rates). These are in addition to "Standard rate" which exists by default.', - value: '', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_tax_display_shop', - label: 'Display prices in the shop', - description: '', - type: 'select', - default: 'excl', - options: { - incl: 'Including tax', - excl: 'Excluding tax', - }, - value: 'excl', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_tax_display_cart', - label: 'Display prices during cart and checkout', - description: '', - type: 'select', - default: 'excl', - options: { - incl: 'Including tax', - excl: 'Excluding tax', - }, - value: 'excl', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_price_display_suffix', - label: 'Price display suffix', - description: '', - type: 'text', - default: '', - tip: 'Define text to show after your product prices. This could be, for example, "inc. Vat" to explain your pricing. You can also have prices substituted here using one of the following: {price_including_tax}, {price_excluding_tax}.', - value: '', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_tax_total_display', - label: 'Display tax totals', - description: '', - type: 'select', - default: 'itemized', - options: { - single: 'As a single total', - itemized: 'Itemized', - }, - value: 'itemized', - } ), - ] ) - ); - } ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_tax_based_on', + label: 'Calculate tax based on', + description: '', + type: 'select', + default: 'shipping', + options: { + shipping: 'Customer shipping address', + billing: 'Customer billing address', + base: 'Shop base address', + }, + tip: 'This option determines which address is used to calculate tax.', + value: 'shipping', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_shipping_tax_class', + label: 'Shipping tax class', + description: + 'Optionally control which tax class shipping gets, or leave it so shipping tax is based on the cart items themselves.', + type: 'select', + default: 'inherit', + options: { + inherit: + 'Shipping tax class based on cart items', + '': 'Standard', + 'reduced-rate': 'Reduced rate', + 'zero-rate': 'Zero rate', + }, + tip: 'Optionally control which tax class shipping gets, or leave it so shipping tax is based on the cart items themselves.', + value: 'inherit', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_tax_round_at_subtotal', + label: 'Rounding', + description: + 'Round tax at subtotal level, instead of rounding per line', + type: 'checkbox', + default: 'no', + value: 'no', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_tax_classes', + label: 'Additional tax classes', + description: '', + type: 'textarea', + default: '', + tip: 'List additional tax classes you need below (1 per line, e.g. Reduced Rates). These are in addition to "Standard rate" which exists by default.', + value: '', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_tax_display_shop', + label: 'Display prices in the shop', + description: '', + type: 'select', + default: 'excl', + options: { + incl: 'Including tax', + excl: 'Excluding tax', + }, + value: 'excl', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_tax_display_cart', + label: 'Display prices during cart and checkout', + description: '', + type: 'select', + default: 'excl', + options: { + incl: 'Including tax', + excl: 'Excluding tax', + }, + value: 'excl', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_price_display_suffix', + label: 'Price display suffix', + description: '', + type: 'text', + default: '', + tip: 'Define text to show after your product prices. This could be, for example, "inc. Vat" to explain your pricing. You can also have prices substituted here using one of the following: {price_including_tax}, {price_excluding_tax}.', + value: '', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_tax_total_display', + label: 'Display tax totals', + description: '', + type: 'select', + default: 'itemized', + options: { + single: 'As a single total', + itemized: 'Itemized', + }, + value: 'itemized', + } ), + ] ) + ); + } + ); } ); test.describe( 'List all Shipping settings options', () => { @@ -1613,286 +1620,294 @@ test.describe.serial( 'Settings API tests: CRUD', () => { } ); } ); - test.describe( 'List all Advanced settings options', () => { - test( 'can retrieve all advanced settings', async ( { request } ) => { - // call API to retrieve all settings options - const response = await request.get( - '/wp-json/wc/v3/settings/advanced' - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( Array.isArray( responseJSON ) ).toBe( true ); + test.describe( + 'List all Advanced settings options', + { tag: '@skip-on-default-wpcom' }, + () => { + test( 'can retrieve all advanced settings', async ( { + request, + } ) => { + // call API to retrieve all settings options + const response = await request.get( + '/wp-json/wc/v3/settings/advanced' + ); + const responseJSON = await response.json(); + expect( response.status() ).toEqual( 200 ); + expect( Array.isArray( responseJSON ) ).toBe( true ); + + // not present in external host + // eslint-disable-next-line playwright/no-conditional-in-test + if ( ! shouldSkip ) { + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_cart_page_id', + label: 'Cart page', + description: + 'Page where shoppers review their shopping cart', + type: 'select', + default: '', + tip: 'Page where shoppers review their shopping cart', + value: expect.any( String ), + options: expect.any( Object ), + } ), + ] ) + ); + } + + // not present in external host + // eslint-disable-next-line playwright/no-conditional-in-test + if ( ! shouldSkip ) { + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_checkout_page_id', + label: 'Checkout page', + description: + 'Page where shoppers go to finalize their purchase', + type: 'select', + default: expect.any( Number ), + tip: 'Page where shoppers go to finalize their purchase', + value: expect.any( String ), + options: expect.any( Object ), + } ), + ] ) + ); + } - // not present in external host - // eslint-disable-next-line playwright/no-conditional-in-test - if ( ! shouldSkip ) { expect( responseJSON ).toEqual( expect.arrayContaining( [ expect.objectContaining( { - id: 'woocommerce_cart_page_id', - label: 'Cart page', + id: 'woocommerce_myaccount_page_id', + label: 'My account page', description: - 'Page where shoppers review their shopping cart', + 'Page contents: [woocommerce_my_account]', type: 'select', default: '', - tip: 'Page where shoppers review their shopping cart', + tip: 'Page contents: [woocommerce_my_account]', value: expect.any( String ), options: expect.any( Object ), } ), ] ) ); - } - - // not present in external host - // eslint-disable-next-line playwright/no-conditional-in-test - if ( ! shouldSkip ) { expect( responseJSON ).toEqual( expect.arrayContaining( [ expect.objectContaining( { - id: 'woocommerce_checkout_page_id', - label: 'Checkout page', + id: 'woocommerce_checkout_pay_endpoint', + label: 'Pay', description: - 'Page where shoppers go to finalize their purchase', - type: 'select', - default: expect.any( Number ), - tip: 'Page where shoppers go to finalize their purchase', - value: expect.any( String ), - options: expect.any( Object ), + 'Endpoint for the "Checkout → Pay" page.', + type: 'text', + default: 'order-pay', + tip: 'Endpoint for the "Checkout → Pay" page.', + value: 'order-pay', } ), ] ) ); - } - - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_page_id', - label: 'My account page', - description: 'Page contents: [woocommerce_my_account]', - type: 'select', - default: '', - tip: 'Page contents: [woocommerce_my_account]', - value: expect.any( String ), - options: expect.any( Object ), - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_checkout_pay_endpoint', - label: 'Pay', - description: - 'Endpoint for the "Checkout → Pay" page.', - type: 'text', - default: 'order-pay', - tip: 'Endpoint for the "Checkout → Pay" page.', - value: 'order-pay', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_checkout_order_received_endpoint', - label: 'Order received', - description: - 'Endpoint for the "Checkout → Order received" page.', - type: 'text', - default: 'order-received', - tip: 'Endpoint for the "Checkout → Order received" page.', - value: 'order-received', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_add_payment_method_endpoint', - label: 'Add payment method', - description: - 'Endpoint for the "Checkout → Add payment method" page.', - type: 'text', - default: 'add-payment-method', - tip: 'Endpoint for the "Checkout → Add payment method" page.', - value: 'add-payment-method', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_delete_payment_method_endpoint', - label: 'Delete payment method', - description: - 'Endpoint for the delete payment method page.', - type: 'text', - default: 'delete-payment-method', - tip: 'Endpoint for the delete payment method page.', - value: 'delete-payment-method', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_orders_endpoint', - label: 'Orders', - description: - 'Endpoint for the "My account → Orders" page.', - type: 'text', - default: 'orders', - tip: 'Endpoint for the "My account → Orders" page.', - value: 'orders', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_view_order_endpoint', - label: 'View order', - description: - 'Endpoint for the "My account → View order" page.', - type: 'text', - default: 'view-order', - tip: 'Endpoint for the "My account → View order" page.', - value: 'view-order', - } ), - ] ) - ); - - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_downloads_endpoint', - label: 'Downloads', - description: - 'Endpoint for the "My account → Downloads" page.', - type: 'text', - default: 'downloads', - tip: 'Endpoint for the "My account → Downloads" page.', - value: 'downloads', - } ), - ] ) - ); - - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_edit_account_endpoint', - label: 'Edit account', - description: - 'Endpoint for the "My account → Edit account" page.', - type: 'text', - default: 'edit-account', - tip: 'Endpoint for the "My account → Edit account" page.', - value: 'edit-account', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_edit_address_endpoint', - label: 'Addresses', - description: - 'Endpoint for the "My account → Addresses" page.', - type: 'text', - default: 'edit-address', - tip: 'Endpoint for the "My account → Addresses" page.', - value: 'edit-address', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_payment_methods_endpoint', - label: 'Payment methods', - description: - 'Endpoint for the "My account → Payment methods" page.', - type: 'text', - default: 'payment-methods', - tip: 'Endpoint for the "My account → Payment methods" page.', - value: 'payment-methods', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_myaccount_lost_password_endpoint', - label: 'Lost password', - description: - 'Endpoint for the "My account → Lost password" page.', - type: 'text', - default: 'lost-password', - tip: 'Endpoint for the "My account → Lost password" page.', - value: 'lost-password', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_logout_endpoint', - label: 'Logout', - description: - 'Endpoint for the triggering logout. You can add this to your menus via a custom link: yoursite.com/?customer-logout=true', - type: 'text', - default: 'customer-logout', - tip: 'Endpoint for the triggering logout. You can add this to your menus via a custom link: yoursite.com/?customer-logout=true', - value: 'customer-logout', - } ), - ] ) - ); - // eslint-disable-next-line playwright/no-conditional-in-test - if ( ! shouldSkip ) { expect( responseJSON ).toEqual( expect.arrayContaining( [ expect.objectContaining( { - id: 'woocommerce_allow_tracking', - label: 'Enable tracking', + id: 'woocommerce_checkout_order_received_endpoint', + label: 'Order received', description: - 'Allow usage of WooCommerce to be tracked', + 'Endpoint for the "Checkout → Order received" page.', + type: 'text', + default: 'order-received', + tip: 'Endpoint for the "Checkout → Order received" page.', + value: 'order-received', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_add_payment_method_endpoint', + label: 'Add payment method', + description: + 'Endpoint for the "Checkout → Add payment method" page.', + type: 'text', + default: 'add-payment-method', + tip: 'Endpoint for the "Checkout → Add payment method" page.', + value: 'add-payment-method', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_delete_payment_method_endpoint', + label: 'Delete payment method', + description: + 'Endpoint for the delete payment method page.', + type: 'text', + default: 'delete-payment-method', + tip: 'Endpoint for the delete payment method page.', + value: 'delete-payment-method', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_orders_endpoint', + label: 'Orders', + description: + 'Endpoint for the "My account → Orders" page.', + type: 'text', + default: 'orders', + tip: 'Endpoint for the "My account → Orders" page.', + value: 'orders', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_view_order_endpoint', + label: 'View order', + description: + 'Endpoint for the "My account → View order" page.', + type: 'text', + default: 'view-order', + tip: 'Endpoint for the "My account → View order" page.', + value: 'view-order', + } ), + ] ) + ); + + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_downloads_endpoint', + label: 'Downloads', + description: + 'Endpoint for the "My account → Downloads" page.', + type: 'text', + default: 'downloads', + tip: 'Endpoint for the "My account → Downloads" page.', + value: 'downloads', + } ), + ] ) + ); + + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_edit_account_endpoint', + label: 'Edit account', + description: + 'Endpoint for the "My account → Edit account" page.', + type: 'text', + default: 'edit-account', + tip: 'Endpoint for the "My account → Edit account" page.', + value: 'edit-account', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_edit_address_endpoint', + label: 'Addresses', + description: + 'Endpoint for the "My account → Addresses" page.', + type: 'text', + default: 'edit-address', + tip: 'Endpoint for the "My account → Addresses" page.', + value: 'edit-address', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_payment_methods_endpoint', + label: 'Payment methods', + description: + 'Endpoint for the "My account → Payment methods" page.', + type: 'text', + default: 'payment-methods', + tip: 'Endpoint for the "My account → Payment methods" page.', + value: 'payment-methods', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_myaccount_lost_password_endpoint', + label: 'Lost password', + description: + 'Endpoint for the "My account → Lost password" page.', + type: 'text', + default: 'lost-password', + tip: 'Endpoint for the "My account → Lost password" page.', + value: 'lost-password', + } ), + ] ) + ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_logout_endpoint', + label: 'Logout', + description: + 'Endpoint for the triggering logout. You can add this to your menus via a custom link: yoursite.com/?customer-logout=true', + type: 'text', + default: 'customer-logout', + tip: 'Endpoint for the triggering logout. You can add this to your menus via a custom link: yoursite.com/?customer-logout=true', + value: 'customer-logout', + } ), + ] ) + ); + // eslint-disable-next-line playwright/no-conditional-in-test + if ( ! shouldSkip ) { + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_allow_tracking', + label: 'Enable tracking', + description: + 'Allow usage of WooCommerce to be tracked', + type: 'checkbox', + default: 'no', + tip: 'To opt out, leave this box unticked. Your store remains untracked, and no data will be collected. Read about what usage data is tracked at: WooCommerce.com Usage Tracking Documentation.', + value: 'no', + } ), + ] ) + ); + } else { + // Test is failing on external hosts + } + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_show_marketplace_suggestions', + label: 'Show Suggestions', + description: + 'Display suggestions within WooCommerce', type: 'checkbox', - default: 'no', - tip: 'To opt out, leave this box unticked. Your store remains untracked, and no data will be collected. Read about what usage data is tracked at: WooCommerce.com Usage Tracking Documentation.', - value: 'no', + default: 'yes', + tip: 'Leave this box unchecked if you do not want to pull suggested extensions from WooCommerce.com. You will see a static list of extensions instead.', + value: 'yes', } ), ] ) ); - } else { - // Test is failing on external hosts - } - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_show_marketplace_suggestions', - label: 'Show Suggestions', - description: 'Display suggestions within WooCommerce', - type: 'checkbox', - default: 'yes', - tip: 'Leave this box unchecked if you do not want to pull suggested extensions from WooCommerce.com. You will see a static list of extensions instead.', - value: 'yes', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'woocommerce_analytics_enabled', - label: 'Analytics', - description: 'Enable WooCommerce Analytics', - type: 'checkbox', - default: 'yes', - value: 'yes', - } ), - ] ) - ); - } ); - } ); + expect( responseJSON ).toEqual( + expect.arrayContaining( [ + expect.objectContaining( { + id: 'woocommerce_analytics_enabled', + label: 'Analytics', + description: 'Enable WooCommerce Analytics', + type: 'checkbox', + default: 'yes', + value: 'yes', + } ), + ] ) + ); + } ); + } + ); test.describe( 'List all Email New Order settings', () => { test( 'can retrieve all email new order settings', async ( { @@ -1930,7 +1945,7 @@ test.describe.serial( 'Settings API tests: CRUD', () => { tip: expect.stringContaining( 'Enter recipients (comma separated) for this email. Defaults to' ), - value: '', + value: expect.any( String ), } ), ] ) ); @@ -1998,107 +2013,110 @@ test.describe.serial( 'Settings API tests: CRUD', () => { } ); test.describe( 'List all Email Failed Order settings', () => { - test( 'can retrieve all email failed order settings', async ( { - request, - } ) => { - // call API to retrieve all settings options - const response = await request.get( - '/wp-json/wc/v3/settings/email_failed_order' - ); - const responseJSON = await response.json(); - expect( response.status() ).toEqual( 200 ); - expect( Array.isArray( responseJSON ) ).toBe( true ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'enabled', - label: 'Enable/Disable', - description: '', - type: 'checkbox', - default: 'yes', - value: 'yes', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'recipient', - label: 'Recipient(s)', - description: expect.stringContaining( - 'Enter recipients (comma separated) for this email. Defaults to' - ), - type: 'text', - default: '', - tip: expect.stringContaining( - 'Enter recipients (comma separated) for this email. Defaults to' - ), - value: '', - } ), - ] ) - ); - expect( responseJSON ).toEqual( - expect.arrayContaining( [ - expect.objectContaining( { - id: 'subject', - label: 'Subject', - description: - 'Available placeholders:{site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
- type: 'text',
- default: '',
- tip: 'Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
- value: '',
- } ),
- ] )
- );
- expect( responseJSON ).toEqual(
- expect.arrayContaining( [
- expect.objectContaining( {
- id: 'heading',
- label: 'Email heading',
- description:
- 'Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
- type: 'text',
- default: '',
- tip: 'Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
- value: '',
- } ),
- ] )
- );
- expect( responseJSON ).toEqual(
- expect.arrayContaining( [
- expect.objectContaining( {
- id: 'additional_content',
- label: 'Additional content',
- description:
- 'Text to appear below the main email content. Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
- type: 'textarea',
- default:
- 'Hopefully they’ll be back. Read more about troubleshooting failed payments.',
- tip: 'Text to appear below the main email content. Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
- value: 'Hopefully they’ll be back. Read more about troubleshooting failed payments.',
- } ),
- ] )
- );
- expect( responseJSON ).toEqual(
- expect.arrayContaining( [
- expect.objectContaining( {
- id: 'email_type',
- label: 'Email type',
- description: 'Choose which format of email to send.',
- type: 'select',
- default: 'html',
- options: {
- plain: 'Plain text',
- html: 'HTML',
- multipart: 'Multipart',
- },
- tip: 'Choose which format of email to send.',
- value: 'html',
- } ),
- ] )
- );
- } );
+ test(
+ 'can retrieve all email failed order settings',
+ { tag: '@skip-on-default-pressable' },
+ async ( { request } ) => {
+ // call API to retrieve all settings options
+ const response = await request.get(
+ '/wp-json/wc/v3/settings/email_failed_order'
+ );
+ const responseJSON = await response.json();
+ expect( response.status() ).toEqual( 200 );
+ expect( Array.isArray( responseJSON ) ).toBe( true );
+ expect( responseJSON ).toEqual(
+ expect.arrayContaining( [
+ expect.objectContaining( {
+ id: 'enabled',
+ label: 'Enable/Disable',
+ description: '',
+ type: 'checkbox',
+ default: 'yes',
+ value: 'yes',
+ } ),
+ ] )
+ );
+ expect( responseJSON ).toEqual(
+ expect.arrayContaining( [
+ expect.objectContaining( {
+ id: 'recipient',
+ label: 'Recipient(s)',
+ description: expect.stringContaining(
+ 'Enter recipients (comma separated) for this email. Defaults to'
+ ),
+ type: 'text',
+ default: '',
+ tip: expect.stringContaining(
+ 'Enter recipients (comma separated) for this email. Defaults to'
+ ),
+ value: '',
+ } ),
+ ] )
+ );
+ expect( responseJSON ).toEqual(
+ expect.arrayContaining( [
+ expect.objectContaining( {
+ id: 'subject',
+ label: 'Subject',
+ description:
+ 'Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
+ type: 'text',
+ default: '',
+ tip: 'Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
+ value: '',
+ } ),
+ ] )
+ );
+ expect( responseJSON ).toEqual(
+ expect.arrayContaining( [
+ expect.objectContaining( {
+ id: 'heading',
+ label: 'Email heading',
+ description:
+ 'Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
+ type: 'text',
+ default: '',
+ tip: 'Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
+ value: '',
+ } ),
+ ] )
+ );
+ expect( responseJSON ).toEqual(
+ expect.arrayContaining( [
+ expect.objectContaining( {
+ id: 'additional_content',
+ label: 'Additional content',
+ description:
+ 'Text to appear below the main email content. Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
+ type: 'textarea',
+ default:
+ 'Hopefully they’ll be back. Read more about troubleshooting failed payments.',
+ tip: 'Text to appear below the main email content. Available placeholders: {site_title}</code>, <code>{site_address}</code>, <code>{site_url}</code>, <code>{order_date}</code>, <code>{order_number}
',
+ value: 'Hopefully they’ll be back. Read more about troubleshooting failed payments.',
+ } ),
+ ] )
+ );
+ expect( responseJSON ).toEqual(
+ expect.arrayContaining( [
+ expect.objectContaining( {
+ id: 'email_type',
+ label: 'Email type',
+ description:
+ 'Choose which format of email to send.',
+ type: 'select',
+ default: 'html',
+ options: {
+ plain: 'Plain text',
+ html: 'HTML',
+ multipart: 'Multipart',
+ },
+ tip: 'Choose which format of email to send.',
+ value: 'html',
+ } ),
+ ] )
+ );
+ }
+ );
} );
test.describe( 'List all Email Customer On Hold Order settings', () => {
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.js b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.js
index 65d56a07196..005c48a99cd 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/api-tests/system-status/system-status-crud.test.js
@@ -3,582 +3,590 @@ const { BASE_URL } = process.env;
const shouldSkip = BASE_URL !== undefined && ! BASE_URL.includes( 'localhost' );
test.describe( 'System Status API tests', () => {
- test( 'can view all system status items', async ( { request } ) => {
- // call API to view all system status items
- const response = await request.get( '/wp-json/wc/v3/system_status' );
- const responseJSON = await response.json();
- expect( response.status() ).toEqual( 200 );
+ test(
+ 'can view all system status items',
+ { tag: '@skip-on-default-wpcom' },
+ async ( { request } ) => {
+ // call API to view all system status items
+ const response = await request.get(
+ '/wp-json/wc/v3/system_status'
+ );
+ const responseJSON = await response.json();
+ expect( response.status() ).toEqual( 200 );
+
+ // local environment differs from external hosts. Local listed first.
+ // eslint-disable-next-line playwright/no-conditional-in-test
+ if ( ! shouldSkip ) {
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ environment: expect.objectContaining( {
+ home_url: expect.any( String ),
+ site_url: expect.any( String ),
+ version: expect.any( String ),
+ log_directory: expect.any( String ),
+ log_directory_writable: expect.any( Boolean ),
+ wp_version: expect.any( String ),
+ wp_multisite: expect.any( Boolean ),
+ wp_memory_limit: expect.any( Number ),
+ wp_debug_mode: expect.any( Boolean ),
+ wp_cron: expect.any( Boolean ),
+ language: expect.any( String ),
+ external_object_cache: null,
+ server_info: expect.any( String ),
+ php_version: expect.any( String ),
+ php_post_max_size: expect.any( Number ),
+ php_max_execution_time: expect.any( Number ),
+ php_max_input_vars: expect.any( Number ),
+ curl_version: expect.any( String ),
+ suhosin_installed: expect.any( Boolean ),
+ max_upload_size: expect.any( Number ),
+ mysql_version: expect.any( String ),
+ mysql_version_string: expect.any( String ),
+ default_timezone: expect.any( String ),
+ fsockopen_or_curl_enabled: expect.any( Boolean ),
+ soapclient_enabled: expect.any( Boolean ),
+ domdocument_enabled: expect.any( Boolean ),
+ gzip_enabled: expect.any( Boolean ),
+ mbstring_enabled: expect.any( Boolean ),
+ remote_post_successful: expect.any( Boolean ),
+ remote_post_response: expect.any( String ),
+ remote_get_successful: expect.any( Boolean ),
+ remote_get_response: expect.any( String ),
+ } ),
+ } )
+ );
+ } else {
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ environment: expect.objectContaining( {
+ home_url: expect.any( String ),
+ site_url: expect.any( String ),
+ version: expect.any( String ),
+ log_directory: expect.any( String ),
+ log_directory_writable: expect.any( Boolean ),
+ wp_version: expect.any( String ),
+ wp_multisite: expect.any( Boolean ),
+ wp_memory_limit: expect.any( Number ),
+ wp_debug_mode: expect.any( Boolean ),
+ wp_cron: expect.any( Boolean ),
+ language: expect.any( String ),
+ external_object_cache: expect.any( Boolean ),
+ server_info: expect.any( String ),
+ php_version: expect.any( String ),
+ php_post_max_size: expect.any( Number ),
+ php_max_execution_time: expect.any( Number ),
+ php_max_input_vars: expect.any( Number ),
+ curl_version: expect.any( String ),
+ suhosin_installed: expect.any( Boolean ),
+ max_upload_size: expect.any( Number ),
+ mysql_version: expect.any( String ),
+ mysql_version_string: expect.any( String ),
+ default_timezone: expect.any( String ),
+ fsockopen_or_curl_enabled: expect.any( Boolean ),
+ soapclient_enabled: expect.any( Boolean ),
+ domdocument_enabled: expect.any( Boolean ),
+ gzip_enabled: expect.any( Boolean ),
+ mbstring_enabled: expect.any( Boolean ),
+ remote_post_successful: expect.any( Boolean ),
+ remote_post_response: expect.any( Number ),
+ remote_get_successful: expect.any( Boolean ),
+ remote_get_response: expect.any( Number ),
+ } ),
+ } )
+ );
+ }
- // local environment differs from external hosts. Local listed first.
- // eslint-disable-next-line playwright/no-conditional-in-test
- if ( ! shouldSkip ) {
expect( responseJSON ).toEqual(
expect.objectContaining( {
- environment: expect.objectContaining( {
- home_url: expect.any( String ),
- site_url: expect.any( String ),
- version: expect.any( String ),
- log_directory: expect.any( String ),
- log_directory_writable: expect.any( Boolean ),
- wp_version: expect.any( String ),
- wp_multisite: expect.any( Boolean ),
- wp_memory_limit: expect.any( Number ),
- wp_debug_mode: expect.any( Boolean ),
- wp_cron: expect.any( Boolean ),
- language: expect.any( String ),
- external_object_cache: null,
- server_info: expect.any( String ),
- php_version: expect.any( String ),
- php_post_max_size: expect.any( Number ),
- php_max_execution_time: expect.any( Number ),
- php_max_input_vars: expect.any( Number ),
- curl_version: expect.any( String ),
- suhosin_installed: expect.any( Boolean ),
- max_upload_size: expect.any( Number ),
- mysql_version: expect.any( String ),
- mysql_version_string: expect.any( String ),
- default_timezone: expect.any( String ),
- fsockopen_or_curl_enabled: expect.any( Boolean ),
- soapclient_enabled: expect.any( Boolean ),
- domdocument_enabled: expect.any( Boolean ),
- gzip_enabled: expect.any( Boolean ),
- mbstring_enabled: expect.any( Boolean ),
- remote_post_successful: expect.any( Boolean ),
- remote_post_response: expect.any( String ),
- remote_get_successful: expect.any( Boolean ),
- remote_get_response: expect.any( String ),
- } ),
- } )
- );
- } else {
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- environment: expect.objectContaining( {
- home_url: expect.any( String ),
- site_url: expect.any( String ),
- version: expect.any( String ),
- log_directory: expect.any( String ),
- log_directory_writable: expect.any( Boolean ),
- wp_version: expect.any( String ),
- wp_multisite: expect.any( Boolean ),
- wp_memory_limit: expect.any( Number ),
- wp_debug_mode: expect.any( Boolean ),
- wp_cron: expect.any( Boolean ),
- language: expect.any( String ),
- external_object_cache: expect.any( Boolean ),
- server_info: expect.any( String ),
- php_version: expect.any( String ),
- php_post_max_size: expect.any( Number ),
- php_max_execution_time: expect.any( Number ),
- php_max_input_vars: expect.any( Number ),
- curl_version: expect.any( String ),
- suhosin_installed: expect.any( Boolean ),
- max_upload_size: expect.any( Number ),
- mysql_version: expect.any( String ),
- mysql_version_string: expect.any( String ),
- default_timezone: expect.any( String ),
- fsockopen_or_curl_enabled: expect.any( Boolean ),
- soapclient_enabled: expect.any( Boolean ),
- domdocument_enabled: expect.any( Boolean ),
- gzip_enabled: expect.any( Boolean ),
- mbstring_enabled: expect.any( Boolean ),
- remote_post_successful: expect.any( Boolean ),
- remote_post_response: expect.any( Number ),
- remote_get_successful: expect.any( Boolean ),
- remote_get_response: expect.any( Number ),
- } ),
- } )
- );
- }
-
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- database: expect.objectContaining( {
- wc_database_version: expect.any( String ),
- database_prefix: expect.any( String ),
- maxmind_geoip_database: expect.any( String ),
- database_tables: expect.objectContaining( {
- woocommerce: expect.objectContaining( {
- wp_woocommerce_sessions: expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_api_keys: expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_attribute_taxonomies:
- expect.objectContaining( {
+ database: expect.objectContaining( {
+ wc_database_version: expect.any( String ),
+ database_prefix: expect.any( String ),
+ maxmind_geoip_database: expect.any( String ),
+ database_tables: expect.objectContaining( {
+ woocommerce: expect.objectContaining( {
+ wp_woocommerce_sessions:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_api_keys:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_attribute_taxonomies:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_downloadable_product_permissions:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_order_items:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_order_itemmeta:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_tax_rates:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_tax_rate_locations:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_shipping_zones:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_shipping_zone_locations:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_shipping_zone_methods:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_payment_tokens:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_payment_tokenmeta:
+ expect.objectContaining( {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ } ),
+ wp_woocommerce_log: expect.objectContaining( {
data: expect.any( String ),
index: expect.any( String ),
engine: expect.any( String ),
} ),
- wp_woocommerce_downloadable_product_permissions:
- expect.objectContaining( {
+ } ),
+ other: expect.objectContaining( {
+ wp_actionscheduler_actions: {
data: expect.any( String ),
index: expect.any( String ),
engine: expect.any( String ),
- } ),
- wp_woocommerce_order_items: expect.objectContaining(
+ },
+ wp_actionscheduler_claims: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_actionscheduler_groups: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_actionscheduler_logs: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_commentmeta: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_comments: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_links: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_options: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_postmeta: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_posts: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_termmeta: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_terms: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_term_relationships: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_term_taxonomy: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_usermeta: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_users: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_admin_notes: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_admin_note_actions: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_category_lookup: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_customer_lookup: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_download_log: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_order_coupon_lookup: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_order_product_lookup: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_order_stats: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_order_tax_lookup: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_product_attributes_lookup: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_product_download_directories: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_product_meta_lookup: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_rate_limits: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_reserved_stock: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_tax_rate_classes: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ wp_wc_webhooks: {
+ data: expect.any( String ),
+ index: expect.any( String ),
+ engine: expect.any( String ),
+ },
+ } ),
+ } ),
+ database_size: {
+ data: expect.any( Number ),
+ index: expect.any( Number ),
+ },
+ } ),
+ } )
+ );
+
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ active_plugins: expect.arrayContaining( [
+ {
+ plugin: expect.any( String ),
+ name: expect.any( String ),
+ version: expect.any( String ),
+ version_latest: expect.any( String ),
+ url: expect.any( String ),
+ author_name: expect.any( String ),
+ author_url: expect.any( String ),
+ network_activated: expect.any( Boolean ),
+ },
+ {
+ plugin: expect.any( String ),
+ name: expect.any( String ),
+ version: expect.any( String ),
+ version_latest: expect.any( String ),
+ url: expect.any( String ),
+ author_name: expect.any( String ),
+ author_url: expect.any( String ),
+ network_activated: expect.any( Boolean ),
+ },
+ {
+ plugin: expect.any( String ),
+ name: expect.any( String ),
+ version: expect.any( String ),
+ version_latest: expect.any( String ),
+ url: expect.any( String ),
+ author_name: expect.any( String ),
+ author_url: expect.any( String ),
+ network_activated: expect.any( Boolean ),
+ },
+ {
+ plugin: expect.any( String ),
+ name: expect.any( String ),
+ version: expect.any( String ),
+ version_latest: expect.any( String ),
+ url: expect.any( String ),
+ author_name: expect.any( String ),
+ author_url: expect.any( String ),
+ network_activated: expect.any( Boolean ),
+ },
+ ] ),
+ } )
+ );
+
+ // local environment differs from external hosts. Local listed first.
+ // eslint-disable-next-line playwright/no-conditional-in-test
+ if ( ! shouldSkip ) {
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ dropins_mu_plugins: expect.objectContaining( {
+ dropins: expect.arrayContaining( [] ),
+ mu_plugins: expect.arrayContaining( [] ),
+ } ),
+ } )
+ );
+ } else {
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ dropins_mu_plugins: expect.objectContaining( {
+ dropins: expect.arrayContaining( [
{
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- }
- ),
- wp_woocommerce_order_itemmeta:
- expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_tax_rates: expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_tax_rate_locations:
- expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_shipping_zones:
- expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_shipping_zone_locations:
- expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_shipping_zone_methods:
- expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_payment_tokens:
- expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_payment_tokenmeta:
- expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
- wp_woocommerce_log: expect.objectContaining( {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- } ),
+ name: expect.any( String ),
+ plugin: expect.any( String ),
+ },
+ {
+ name: expect.any( String ),
+ plugin: expect.any( String ),
+ },
+ ] ),
+ mu_plugins: [],
} ),
- other: expect.objectContaining( {
- wp_actionscheduler_actions: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_actionscheduler_claims: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_actionscheduler_groups: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_actionscheduler_logs: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_commentmeta: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_comments: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_links: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_options: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_postmeta: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_posts: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_termmeta: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_terms: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_term_relationships: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_term_taxonomy: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_usermeta: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_users: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_admin_notes: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_admin_note_actions: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_category_lookup: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_customer_lookup: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_download_log: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_order_coupon_lookup: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_order_product_lookup: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_order_stats: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_order_tax_lookup: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_product_attributes_lookup: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_product_download_directories: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_product_meta_lookup: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_rate_limits: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_reserved_stock: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_tax_rate_classes: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- wp_wc_webhooks: {
- data: expect.any( String ),
- index: expect.any( String ),
- engine: expect.any( String ),
- },
- } ),
- } ),
- database_size: {
- data: expect.any( Number ),
- index: expect.any( Number ),
- },
- } ),
- } )
- );
-
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- active_plugins: expect.arrayContaining( [
- {
- plugin: expect.any( String ),
- name: expect.any( String ),
- version: expect.any( String ),
- version_latest: expect.any( String ),
- url: expect.any( String ),
- author_name: expect.any( String ),
- author_url: expect.any( String ),
- network_activated: expect.any( Boolean ),
- },
- {
- plugin: expect.any( String ),
- name: expect.any( String ),
- version: expect.any( String ),
- version_latest: expect.any( String ),
- url: expect.any( String ),
- author_name: expect.any( String ),
- author_url: expect.any( String ),
- network_activated: expect.any( Boolean ),
- },
- {
- plugin: expect.any( String ),
- name: expect.any( String ),
- version: expect.any( String ),
- version_latest: expect.any( String ),
- url: expect.any( String ),
- author_name: expect.any( String ),
- author_url: expect.any( String ),
- network_activated: expect.any( Boolean ),
- },
- {
- plugin: expect.any( String ),
- name: expect.any( String ),
- version: expect.any( String ),
- version_latest: expect.any( String ),
- url: expect.any( String ),
- author_name: expect.any( String ),
- author_url: expect.any( String ),
- network_activated: expect.any( Boolean ),
- },
- ] ),
- } )
- );
-
- // local environment differs from external hosts. Local listed first.
- // eslint-disable-next-line playwright/no-conditional-in-test
- if ( ! shouldSkip ) {
+ } )
+ );
+ }
expect( responseJSON ).toEqual(
expect.objectContaining( {
- dropins_mu_plugins: expect.objectContaining( {
- dropins: expect.arrayContaining( [] ),
- mu_plugins: expect.arrayContaining( [] ),
+ theme: expect.objectContaining( {
+ name: expect.any( String ),
+ version: expect.any( String ),
+ version_latest: expect.any( String ),
+ author_url: expect.any( String ),
+ is_child_theme: expect.any( Boolean ),
+ has_woocommerce_support: expect.any( Boolean ),
+ has_woocommerce_file: expect.any( Boolean ),
+ has_outdated_templates: expect.any( Boolean ),
+ overrides: expect.any( Array ),
+ parent_name: expect.any( String ),
+ parent_version: expect.any( String ),
+ parent_version_latest: expect.any( String ),
+ parent_author_url: expect.any( String ),
} ),
} )
);
- } else {
expect( responseJSON ).toEqual(
expect.objectContaining( {
- dropins_mu_plugins: expect.objectContaining( {
- dropins: expect.arrayContaining( [
- {
- name: expect.any( String ),
- plugin: expect.any( String ),
- },
- {
- name: expect.any( String ),
- plugin: expect.any( String ),
- },
- ] ),
- mu_plugins: [],
+ settings: expect.objectContaining( {
+ api_enabled: expect.any( Boolean ),
+ force_ssl: expect.any( Boolean ),
+ currency: expect.any( String ),
+ currency_symbol: expect.any( String ),
+ currency_position: expect.any( String ),
+ thousand_separator: expect.any( String ),
+ decimal_separator: expect.any( String ),
+ number_of_decimals: expect.any( Number ),
+ geolocation_enabled: expect.any( Boolean ),
+ taxonomies: {
+ external: expect.any( String ),
+ grouped: expect.any( String ),
+ simple: expect.any( String ),
+ variable: expect.any( String ),
+ },
+ product_visibility_terms: {
+ 'exclude-from-catalog': expect.any( String ),
+ 'exclude-from-search': expect.any( String ),
+ featured: expect.any( String ),
+ outofstock: expect.any( String ),
+ 'rated-1': expect.any( String ),
+ 'rated-2': expect.any( String ),
+ 'rated-3': expect.any( String ),
+ 'rated-4': expect.any( String ),
+ 'rated-5': expect.any( String ),
+ },
+ woocommerce_com_connected: expect.any( String ),
} ),
} )
);
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ security: expect.objectContaining( {
+ secure_connection: expect.any( Boolean ),
+ hide_errors: expect.any( Boolean ),
+ } ),
+ } )
+ );
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ pages: expect.arrayContaining( [
+ {
+ page_name: expect.any( String ),
+ page_id: expect.any( String ),
+ page_set: expect.any( Boolean ),
+ page_exists: expect.any( Boolean ),
+ page_visible: expect.any( Boolean ),
+ shortcode: expect.any( String ),
+ block: expect.any( String ),
+ shortcode_required: expect.any( Boolean ),
+ shortcode_present: expect.any( Boolean ),
+ block_present: expect.any( Boolean ),
+ block_required: expect.any( Boolean ),
+ },
+ {
+ page_name: expect.any( String ),
+ page_id: expect.any( String ),
+ page_set: expect.any( Boolean ),
+ page_exists: expect.any( Boolean ),
+ page_visible: expect.any( Boolean ),
+ shortcode: expect.any( String ),
+ block: expect.any( String ),
+ shortcode_required: expect.any( Boolean ),
+ shortcode_present: expect.any( Boolean ),
+ block_present: expect.any( Boolean ),
+ block_required: expect.any( Boolean ),
+ },
+ {
+ page_name: expect.any( String ),
+ page_id: expect.any( String ),
+ page_set: expect.any( Boolean ),
+ page_exists: expect.any( Boolean ),
+ page_visible: expect.any( Boolean ),
+ shortcode: expect.any( String ),
+ block: expect.any( String ),
+ shortcode_required: expect.any( Boolean ),
+ shortcode_present: expect.any( Boolean ),
+ block_present: expect.any( Boolean ),
+ block_required: expect.any( Boolean ),
+ },
+ {
+ page_name: expect.any( String ),
+ page_id: expect.any( String ),
+ page_set: expect.any( Boolean ),
+ page_exists: expect.any( Boolean ),
+ page_visible: expect.any( Boolean ),
+ shortcode: expect.any( String ),
+ block: expect.any( String ),
+ shortcode_required: expect.any( Boolean ),
+ shortcode_present: expect.any( Boolean ),
+ block_present: expect.any( Boolean ),
+ block_required: expect.any( Boolean ),
+ },
+ {
+ page_name: expect.any( String ),
+ page_id: expect.any( String ),
+ page_set: expect.any( Boolean ),
+ page_exists: expect.any( Boolean ),
+ page_visible: expect.any( Boolean ),
+ shortcode: expect.any( String ),
+ block: expect.any( String ),
+ shortcode_required: expect.any( Boolean ),
+ shortcode_present: expect.any( Boolean ),
+ block_present: expect.any( Boolean ),
+ block_required: expect.any( Boolean ),
+ },
+ ] ),
+ } )
+ );
+ expect( responseJSON ).toEqual(
+ expect.objectContaining( {
+ post_type_counts: expect.arrayContaining( [
+ {
+ type: expect.any( String ),
+ count: expect.any( String ),
+ },
+ {
+ type: expect.any( String ),
+ count: expect.any( String ),
+ },
+ {
+ type: expect.any( String ),
+ count: expect.any( String ),
+ },
+ ] ),
+ } )
+ );
}
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- theme: expect.objectContaining( {
- name: expect.any( String ),
- version: expect.any( String ),
- version_latest: expect.any( String ),
- author_url: expect.any( String ),
- is_child_theme: expect.any( Boolean ),
- has_woocommerce_support: expect.any( Boolean ),
- has_woocommerce_file: expect.any( Boolean ),
- has_outdated_templates: expect.any( Boolean ),
- overrides: expect.any( Array ),
- parent_name: expect.any( String ),
- parent_version: expect.any( String ),
- parent_version_latest: expect.any( String ),
- parent_author_url: expect.any( String ),
- } ),
- } )
- );
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- settings: expect.objectContaining( {
- api_enabled: expect.any( Boolean ),
- force_ssl: expect.any( Boolean ),
- currency: expect.any( String ),
- currency_symbol: expect.any( String ),
- currency_position: expect.any( String ),
- thousand_separator: expect.any( String ),
- decimal_separator: expect.any( String ),
- number_of_decimals: expect.any( Number ),
- geolocation_enabled: expect.any( Boolean ),
- taxonomies: {
- external: expect.any( String ),
- grouped: expect.any( String ),
- simple: expect.any( String ),
- variable: expect.any( String ),
- },
- product_visibility_terms: {
- 'exclude-from-catalog': expect.any( String ),
- 'exclude-from-search': expect.any( String ),
- featured: expect.any( String ),
- outofstock: expect.any( String ),
- 'rated-1': expect.any( String ),
- 'rated-2': expect.any( String ),
- 'rated-3': expect.any( String ),
- 'rated-4': expect.any( String ),
- 'rated-5': expect.any( String ),
- },
- woocommerce_com_connected: expect.any( String ),
- } ),
- } )
- );
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- security: expect.objectContaining( {
- secure_connection: expect.any( Boolean ),
- hide_errors: expect.any( Boolean ),
- } ),
- } )
- );
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- pages: expect.arrayContaining( [
- {
- page_name: expect.any( String ),
- page_id: expect.any( String ),
- page_set: expect.any( Boolean ),
- page_exists: expect.any( Boolean ),
- page_visible: expect.any( Boolean ),
- shortcode: expect.any( String ),
- block: expect.any( String ),
- shortcode_required: expect.any( Boolean ),
- shortcode_present: expect.any( Boolean ),
- block_present: expect.any( Boolean ),
- block_required: expect.any( Boolean ),
- },
- {
- page_name: expect.any( String ),
- page_id: expect.any( String ),
- page_set: expect.any( Boolean ),
- page_exists: expect.any( Boolean ),
- page_visible: expect.any( Boolean ),
- shortcode: expect.any( String ),
- block: expect.any( String ),
- shortcode_required: expect.any( Boolean ),
- shortcode_present: expect.any( Boolean ),
- block_present: expect.any( Boolean ),
- block_required: expect.any( Boolean ),
- },
- {
- page_name: expect.any( String ),
- page_id: expect.any( String ),
- page_set: expect.any( Boolean ),
- page_exists: expect.any( Boolean ),
- page_visible: expect.any( Boolean ),
- shortcode: expect.any( String ),
- block: expect.any( String ),
- shortcode_required: expect.any( Boolean ),
- shortcode_present: expect.any( Boolean ),
- block_present: expect.any( Boolean ),
- block_required: expect.any( Boolean ),
- },
- {
- page_name: expect.any( String ),
- page_id: expect.any( String ),
- page_set: expect.any( Boolean ),
- page_exists: expect.any( Boolean ),
- page_visible: expect.any( Boolean ),
- shortcode: expect.any( String ),
- block: expect.any( String ),
- shortcode_required: expect.any( Boolean ),
- shortcode_present: expect.any( Boolean ),
- block_present: expect.any( Boolean ),
- block_required: expect.any( Boolean ),
- },
- {
- page_name: expect.any( String ),
- page_id: expect.any( String ),
- page_set: expect.any( Boolean ),
- page_exists: expect.any( Boolean ),
- page_visible: expect.any( Boolean ),
- shortcode: expect.any( String ),
- block: expect.any( String ),
- shortcode_required: expect.any( Boolean ),
- shortcode_present: expect.any( Boolean ),
- block_present: expect.any( Boolean ),
- block_required: expect.any( Boolean ),
- },
- ] ),
- } )
- );
- expect( responseJSON ).toEqual(
- expect.objectContaining( {
- post_type_counts: expect.arrayContaining( [
- {
- type: expect.any( String ),
- count: expect.any( String ),
- },
- {
- type: expect.any( String ),
- count: expect.any( String ),
- },
- {
- type: expect.any( String ),
- count: expect.any( String ),
- },
- ] ),
- } )
- );
- } );
+ );
test( 'can view all system status tools', async ( { request } ) => {
// call API to view system status tools
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js
index c5f0d7ec448..7279c31fbea 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-checkout-block.spec.js
@@ -149,9 +149,11 @@ test.describe(
.locator( 'legend' )
).toBeVisible();
await expect(
- page.locator(
- '.wp-block-woocommerce-checkout-order-summary-block'
- )
+ page
+ .locator(
+ '.wp-block-woocommerce-checkout-order-summary-block'
+ )
+ .first()
).toBeVisible();
await expect(
page.locator( '.wc-block-components-address-form' ).first()
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js
index 2630674a42b..1d38fd68d5c 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-coupon.spec.js
@@ -39,102 +39,110 @@ const test = baseTest.extend( {
},
} );
-test.describe( 'Coupon management', { tag: '@services' }, () => {
- for ( const couponType of Object.keys( couponData ) ) {
- test( `can create new ${ couponType } coupon`, async ( {
- page,
- coupon,
- } ) => {
- await test.step( 'add new coupon', async () => {
- await page.goto(
- 'wp-admin/post-new.php?post_type=shop_coupon'
- );
- await page
- .getByLabel( 'Coupon code' )
- .fill( couponData[ couponType ].code );
- await page
- .getByPlaceholder( 'Description (optional)' )
- .fill( couponData[ couponType ].description );
- await page
- .getByPlaceholder( '0' )
- .fill( couponData[ couponType ].amount );
+test.describe(
+ 'Coupon management',
+ { tag: [ '@services', '@skip-on-default-wpcom' ] },
+ () => {
+ for ( const couponType of Object.keys( couponData ) ) {
+ test( `can create new ${ couponType } coupon`, async ( {
+ page,
+ coupon,
+ } ) => {
+ await test.step( 'add new coupon', async () => {
+ await page.goto(
+ 'wp-admin/post-new.php?post_type=shop_coupon'
+ );
+ await page
+ .getByLabel( 'Coupon code' )
+ .fill( couponData[ couponType ].code );
+ await page
+ .getByPlaceholder( 'Description (optional)' )
+ .fill( couponData[ couponType ].description );
+ await page
+ .getByPlaceholder( '0' )
+ .fill( couponData[ couponType ].amount );
- // set expiry date if it was provided
+ // set expiry date if it was provided
+ if ( couponData[ couponType ].expiryDate ) {
+ await page
+ .getByPlaceholder( 'yyyy-mm-dd' )
+ .fill( couponData[ couponType ].expiryDate );
+ }
+
+ // be explicit about whether free shipping is allowed
+ if ( couponData[ couponType ].freeShipping ) {
+ await page.getByLabel( 'Allow free shipping' ).check();
+ } else {
+ await page
+ .getByLabel( 'Allow free shipping' )
+ .uncheck();
+ }
+ } );
+
+ // publish the coupon and retrieve the id
+ await test.step( 'publish the coupon', async () => {
+ await expect(
+ page.getByRole( 'link', { name: 'Move to Trash' } )
+ ).toBeVisible();
+ await page
+ .getByRole( 'button', { name: 'Publish', exact: true } )
+ .click();
+ await expect(
+ page.getByText( 'Coupon updated.' )
+ ).toBeVisible();
+ coupon.id = page.url().match( /(?<=post=)\d+/ )[ 0 ];
+ expect( coupon.id ).toBeDefined();
+ } );
+
+ // verify the creation of the coupon and details
+ await test.step( 'verify coupon creation', async () => {
+ await page.goto(
+ 'wp-admin/edit.php?post_type=shop_coupon'
+ );
+ await expect(
+ page.getByRole( 'cell', {
+ name: couponData[ couponType ].code,
+ } )
+ ).toBeVisible();
+ await expect(
+ page.getByRole( 'cell', {
+ name: couponData[ couponType ].description,
+ } )
+ ).toBeVisible();
+ await expect(
+ page.getByRole( 'cell', {
+ name: couponData[ couponType ].amount,
+ exact: true,
+ } )
+ ).toBeVisible();
+ } );
+
+ // check expiry date if it was set
if ( couponData[ couponType ].expiryDate ) {
- await page
- .getByPlaceholder( 'yyyy-mm-dd' )
- .fill( couponData[ couponType ].expiryDate );
+ await test.step( 'verify coupon expiry date', async () => {
+ await page
+ .getByText( couponData[ couponType ].code )
+ .last()
+ .click();
+ await expect(
+ page.getByPlaceholder( 'yyyy-mm-dd' )
+ ).toHaveValue( couponData[ couponType ].expiryDate );
+ } );
}
- // be explicit about whether free shipping is allowed
+ // if it was a free shipping coupon check that
if ( couponData[ couponType ].freeShipping ) {
- await page.getByLabel( 'Allow free shipping' ).check();
- } else {
- await page.getByLabel( 'Allow free shipping' ).uncheck();
+ await test.step( 'verify free shipping', async () => {
+ await page
+ .getByText( couponData[ couponType ].code )
+ .last()
+ .click();
+ await expect(
+ page.getByLabel( 'Allow free shipping' )
+ ).toBeChecked();
+ } );
}
} );
-
- // publish the coupon and retrieve the id
- await test.step( 'publish the coupon', async () => {
- await expect(
- page.getByRole( 'link', { name: 'Move to Trash' } )
- ).toBeVisible();
- await page
- .getByRole( 'button', { name: 'Publish', exact: true } )
- .click();
- await expect(
- page.getByText( 'Coupon updated.' )
- ).toBeVisible();
- coupon.id = page.url().match( /(?<=post=)\d+/ )[ 0 ];
- expect( coupon.id ).toBeDefined();
- } );
-
- // verify the creation of the coupon and details
- await test.step( 'verify coupon creation', async () => {
- await page.goto( 'wp-admin/edit.php?post_type=shop_coupon' );
- await expect(
- page.getByRole( 'cell', {
- name: couponData[ couponType ].code,
- } )
- ).toBeVisible();
- await expect(
- page.getByRole( 'cell', {
- name: couponData[ couponType ].description,
- } )
- ).toBeVisible();
- await expect(
- page.getByRole( 'cell', {
- name: couponData[ couponType ].amount,
- exact: true,
- } )
- ).toBeVisible();
- } );
-
- // check expiry date if it was set
- if ( couponData[ couponType ].expiryDate ) {
- await test.step( 'verify coupon expiry date', async () => {
- await page
- .getByText( couponData[ couponType ].code )
- .last()
- .click();
- await expect(
- page.getByPlaceholder( 'yyyy-mm-dd' )
- ).toHaveValue( couponData[ couponType ].expiryDate );
- } );
- }
-
- // if it was a free shipping coupon check that
- if ( couponData[ couponType ].freeShipping ) {
- await test.step( 'verify free shipping', async () => {
- await page
- .getByText( couponData[ couponType ].code )
- .last()
- .click();
- await expect(
- page.getByLabel( 'Allow free shipping' )
- ).toBeChecked();
- } );
- }
- } );
+ }
}
-} );
+);
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-product-brand.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-product-brand.spec.js
new file mode 100644
index 00000000000..2288819aa86
--- /dev/null
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-product-brand.spec.js
@@ -0,0 +1,181 @@
+const { test, expect } = require( '@playwright/test' );
+
+test.use( { storageState: process.env.ADMINSTATE } );
+
+test.skip( 'Merchant can add brands', async ( { page } ) => {
+ /**
+ * Go to the Brands page.
+ *
+ * This will visit the Products page first, and then click on the Brands link.
+ * This is to workaround the hover menu for now.
+ */
+ const goToBrandsPage = async () => {
+ await page.goto(
+ 'wp-admin/edit-tags.php?taxonomy=product_brand&post_type=product'
+ );
+
+ // Wait for the Brands page to load.
+ // This is needed so that checking for existing brands would work.
+ await page.waitForSelector( '.wp-list-table' );
+ };
+
+ const createBrandIfNotExist = async (
+ name,
+ slug,
+ parentBrand,
+ description,
+ thumbnailFileName
+ ) => {
+ // Create "WooCommerce" brand if it does not exist.
+ const cellVisible = await page
+ .locator( '#posts-filter' )
+ .getByRole( 'cell', { name: slug, exact: true } )
+ .isVisible();
+
+ if ( cellVisible ) {
+ return;
+ }
+
+ await page.getByRole( 'textbox', { name: 'Name' } ).click();
+ await page.getByRole( 'textbox', { name: 'Name' } ).fill( name );
+ await page.getByRole( 'textbox', { name: 'Slug' } ).click();
+ await page.getByRole( 'textbox', { name: 'Slug' } ).fill( slug );
+
+ await page
+ .getByRole( 'combobox', { name: 'Parent Brand' } )
+ .selectOption( { label: parentBrand } );
+
+ await page.getByRole( 'textbox', { name: 'Description' } ).click();
+ await page
+ .getByRole( 'textbox', { name: 'Description' } )
+ .fill( description );
+ await page.getByRole( 'button', { name: 'Upload/Add image' } ).click();
+ await page.getByRole( 'tab', { name: 'Media Library' } ).click();
+ await page.getByRole( 'checkbox', { name: thumbnailFileName } ).click();
+ await page.getByRole( 'button', { name: 'Use image' } ).click();
+ await page.getByRole( 'button', { name: 'Add New Brand' } ).click();
+
+ // We should see an "Item added." notice message at the top of the page.
+ await expect(
+ page.locator( '#ajax-response' ).getByText( 'Item added.' )
+ ).toBeVisible();
+
+ // We should see the newly created brand in the Brands table.
+ await expect(
+ page
+ .locator( '#posts-filter' )
+ .getByRole( 'cell', { name: slug, exact: true } )
+ ).toHaveCount( 1 );
+ };
+
+ /**
+ * Edit a brand.
+ *
+ * You must be in the Brands page before calling this function.
+ * To do so, call `goToBrandsPage()` first.
+ *
+ * After a brand is edited, you will be redirected to the Brands page.
+ */
+ const editBrand = async (
+ currentName,
+ { name, slug, parentBrand, description, thumbnailFileName }
+ ) => {
+ await page.getByLabel( `“${ currentName }” (Edit)` ).click();
+ await page.getByLabel( 'Name' ).fill( name );
+ await page.getByLabel( 'Slug' ).fill( slug );
+ await page
+ .getByLabel( 'Parent Brand' )
+ .selectOption( { label: parentBrand } );
+ await page.getByLabel( 'Description' ).fill( description );
+
+ await page.getByRole( 'button', { name: 'Upload/Add image' } ).click();
+ await page.getByRole( 'tab', { name: 'Media Library' } ).click();
+ await page.getByLabel( thumbnailFileName ).click();
+ await page.getByRole( 'button', { name: 'Use image' } ).click();
+
+ await page.getByRole( 'button', { name: 'Update' } ).click();
+
+ // We should see an "Item updated." notice message at the top of the page.
+ await expect(
+ page.locator( '#message' ).getByText( 'Item updated.' )
+ ).toBeVisible();
+
+ // navigate back to Brands page.
+ await page.getByRole( 'link', { name: '← Go to Brands' } ).click();
+
+ // confirm that the brand has been updated.
+ await expect(
+ page
+ .locator( '#posts-filter' )
+ .getByRole( 'cell', { name: slug, exact: true } )
+ ).toHaveCount( 1 );
+ };
+
+ /**
+ * Delete a brand.
+ *
+ * You must be in the Brands page before calling this function.
+ * To do so, call `goToBrandsPage()` first.
+ *
+ * After a brand is deleted, you will be redirected to the Brands page.
+ */
+ const deleteBrand = async ( name ) => {
+ await page.getByLabel( `“${ name }” (Edit)` ).click();
+
+ // After clicking the "Delete" button, there will be a confirmation dialog.
+ page.once( 'dialog', ( dialog ) => {
+ // Click "OK" to confirm the deletion.
+ dialog.accept();
+ } );
+
+ // Click on the "Delete" button.
+ await page.getByRole( 'link', { name: 'Delete' } ).click();
+
+ // We should now be in the Brands page.
+ // Confirm that the brand has been deleted and is no longer in the Brands table.
+ await expect(
+ page
+ .locator( '#posts-filter' )
+ .getByRole( 'cell', { name, exact: true } )
+ ).toHaveCount( 0 );
+ };
+
+ await goToBrandsPage();
+ await createBrandIfNotExist(
+ 'WooCommerce',
+ 'woocommerce',
+ 'None',
+ 'All things WooCommerce!',
+ 'image-01'
+ );
+
+ // Create child brand under the "WooCommerce" parent brand.
+ await createBrandIfNotExist(
+ 'WooCommerce Apparels',
+ 'woocommerce-apparels',
+ 'WooCommerce',
+ 'Cool WooCommerce clothings!',
+ 'image-02'
+ );
+
+ // Create a dummy child brand called "WooCommerce Dummy" under the "WooCommerce" parent brand.
+ await createBrandIfNotExist(
+ 'WooCommerce Dummy',
+ 'woocommerce-dummy',
+ 'WooCommerce',
+ 'Dummy WooCommerce brand!',
+ 'image-02'
+ );
+
+ // Edit the dummy child brand from "WooCommerce Dummy" to "WooCommerce Dummy Edited".
+ await editBrand( 'WooCommerce Dummy', {
+ name: 'WooCommerce Dummy Edited',
+ slug: 'woocommerce-dummy-edited',
+ parentBrand: 'WooCommerce',
+ description: 'Dummy WooCommerce brand edited!',
+ thumbnailFileName: 'image-03',
+ } );
+
+ // Delete the dummy child brand "WooCommerce Dummy Edited".
+ await deleteBrand( 'WooCommerce Dummy Edited' );
+} );
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js
index 2f26691761b..3fd0b4c1717 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/create-restricted-coupons.spec.js
@@ -37,6 +37,12 @@ const couponData = {
amount: '60',
excludeProductCategories: [ 'Uncategorized' ],
},
+ excludeProductBrands: {
+ code: `excludeProductBrands-${ new Date().getTime().toString() }`,
+ description: 'Exclude product brands coupon',
+ amount: '65',
+ excludeProductBrands: [ 'WooCommerce Apparels' ],
+ },
products: {
code: `products-${ new Date().getTime().toString() }`,
description: 'Products coupon',
@@ -202,6 +208,26 @@ test.describe( 'Restricted coupon management', { tag: [ '@services' ] }, () => {
.click();
} );
}
+
+ // Skip Brands tests while behind a feature flag.
+ const skipBrandsTests = true;
+
+ // set exclude product brands
+ if ( couponType === 'excludeProductBrands' && ! skipBrandsTests ) {
+ await test.step( 'set exclude product brands coupon', async () => {
+ await page
+ .getByRole( 'link', {
+ name: 'Usage restriction',
+ } )
+ .click();
+ await page
+ .getByPlaceholder( 'No brands' )
+ .pressSequentially( 'WooCommerce Apparels' );
+ await page
+ .getByRole( 'option', { name: 'WooCommerce Apparels' } )
+ .click();
+ } );
+ }
// set products
if ( couponType === 'products' ) {
await test.step( 'set products coupon', async () => {
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-create-simple.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-create-simple.spec.js
index 77b8a6ebefa..46934a82a1d 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-create-simple.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-create-simple.spec.js
@@ -112,7 +112,7 @@ for ( const productType of Object.keys( productData ) ) {
.getByRole( 'link', { name: 'Attributes' } )
.click();
await page
- .getByPlaceholder( 'f.e. size or color' )
+ .getByPlaceholder( 'e.g. length or weight' )
.fill( attributeName );
await page
.getByPlaceholder( 'Enter some descriptive text.' )
@@ -183,7 +183,7 @@ for ( const productType of Object.keys( productData ) ) {
.getByPlaceholder( '0' )
.fill( productData[ productType ].shipping.weight );
await page
- .getByPlaceholder( 'Length' )
+ .getByPlaceholder( 'Length', { exact: true } )
.fill( productData[ productType ].shipping.length );
await page
.getByPlaceholder( 'Width' )
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-import-csv.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-import-csv.spec.js
index 103d50fd8f6..507568812a0 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-import-csv.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/product-import-csv.spec.js
@@ -89,8 +89,7 @@ const productCategories = [
];
const productAttributes = [ 'Color', 'Size' ];
-const errorMessage =
- 'Invalid file type. The importer supports CSV and TXT file formats.';
+const errorMessage = 'File is empty. Please upload something more substantial.';
test.describe.serial(
'Import Products from a CSV file',
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-product-attributes.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-product-attributes.spec.js
index 77db0953f5c..9be4189e4b9 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-product-attributes.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-product-attributes.spec.js
@@ -39,8 +39,9 @@ test.describe( 'Add product attributes', { tag: '@gutenberg' }, () => {
} );
test( 'can add custom product attributes', async ( { page } ) => {
- const textbox_attributeName =
- page.getByPlaceholder( 'f.e. size or color' );
+ const textbox_attributeName = page.getByPlaceholder(
+ 'e.g. length or weight'
+ );
const textbox_attributeValues = page.getByPlaceholder(
'Enter options for customers to choose from'
);
diff --git a/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-variations.spec.js b/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-variations.spec.js
index b1271496bf6..16f2965b3b4 100644
--- a/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-variations.spec.js
+++ b/plugins/woocommerce/tests/e2e-pw/tests/merchant/products/add-variable-product/create-variations.spec.js
@@ -84,105 +84,117 @@ test.describe( 'Add variations', { tag: '@gutenberg' }, () => {
}
} );
- test( 'can manually add a variation', async ( { page } ) => {
- await test.step( `Open "Edit product" page of product id ${ productId_addManually }`, async () => {
- await page.goto(
- `/wp-admin/post.php?post=${ productId_addManually }&action=edit`
- );
- } );
-
- // hook up the woocommerce_variations_added jQuery trigger so we can check if it's fired
- await test.step( 'Hook up the woocommerce_variations_added jQuery trigger', async () => {
- await page.evaluate( () => {
- window.woocommerceVariationsAddedFunctionCalls = [];
-
- window
- .jQuery( '#variable_product_options' )
- .on( 'woocommerce_variations_added', ( event, data ) => {
- window.woocommerceVariationsAddedFunctionCalls.push( [
- event,
- data,
- ] );
- } );
+ test(
+ 'can manually add a variation',
+ { tag: '@skip-on-default-wpcom' },
+ async ( { page } ) => {
+ await test.step( `Open "Edit product" page of product id ${ productId_addManually }`, async () => {
+ await page.goto(
+ `/wp-admin/post.php?post=${ productId_addManually }&action=edit`
+ );
} );
- } );
- await test.step( 'Click on the "Variations" tab.', async () => {
- await page.locator( '.variations_tab' ).click();
- } );
+ // hook up the woocommerce_variations_added jQuery trigger so we can check if it's fired
+ await test.step( 'Hook up the woocommerce_variations_added jQuery trigger', async () => {
+ await page.evaluate( () => {
+ window.woocommerceVariationsAddedFunctionCalls = [];
- await test.step( `Manually add ${ variationsToManuallyCreate.length } variations`, async () => {
- const variationRows = page.locator( '.woocommerce_variation h3' );
- let variationRowsCount = await variationRows.count();
- const originalVariationRowsCount = variationRowsCount;
-
- for ( const variationToCreate of variationsToManuallyCreate ) {
- await test.step( 'Click "Add manually"', async () => {
- const addManuallyButton = page.getByRole( 'button', {
- name: 'Add manually',
- } );
-
- await addManuallyButton.click();
-
- await expect( variationRows ).toHaveCount(
- ++variationRowsCount
- );
-
- // verify that the woocommerce_variations_added jQuery trigger was fired
- const woocommerceVariationsAddedFunctionCalls =
- await page.evaluate(
- () => window.woocommerceVariationsAddedFunctionCalls
+ window
+ .jQuery( '#variable_product_options' )
+ .on(
+ 'woocommerce_variations_added',
+ ( event, data ) => {
+ window.woocommerceVariationsAddedFunctionCalls.push(
+ [ event, data ]
+ );
+ }
);
- expect(
- woocommerceVariationsAddedFunctionCalls.length
- ).toEqual(
- variationRowsCount - originalVariationRowsCount
- );
} );
+ } );
- for ( const attributeValue of variationToCreate ) {
- const attributeName = productAttributes.find(
- ( { options } ) => options.includes( attributeValue )
- ).name;
- const addAttributeMenu = variationRows
- .nth( 0 )
- .locator( 'select', {
- has: page.locator( 'option', {
- hasText: attributeValue,
- } ),
+ await test.step( 'Click on the "Variations" tab.', async () => {
+ await page.locator( '.variations_tab' ).click();
+ } );
+
+ await test.step( `Manually add ${ variationsToManuallyCreate.length } variations`, async () => {
+ const variationRows = page.locator(
+ '.woocommerce_variation h3'
+ );
+ let variationRowsCount = await variationRows.count();
+ const originalVariationRowsCount = variationRowsCount;
+
+ for ( const variationToCreate of variationsToManuallyCreate ) {
+ await test.step( 'Click "Add manually"', async () => {
+ const addManuallyButton = page.getByRole( 'button', {
+ name: 'Add manually',
} );
- await test.step( `Select "${ attributeValue }" from the "${ attributeName }" attribute menu`, async () => {
- await addAttributeMenu.selectOption( attributeValue );
+ await addManuallyButton.click();
+
+ await expect( variationRows ).toHaveCount(
+ ++variationRowsCount
+ );
+
+ // verify that the woocommerce_variations_added jQuery trigger was fired
+ const woocommerceVariationsAddedFunctionCalls =
+ await page.evaluate(
+ () =>
+ window.woocommerceVariationsAddedFunctionCalls
+ );
+ expect(
+ woocommerceVariationsAddedFunctionCalls.length
+ ).toEqual(
+ variationRowsCount - originalVariationRowsCount
+ );
} );
- }
-
- await test.step( 'Click "Save changes"', async () => {
- await page
- .getByRole( 'button', {
- name: 'Save changes',
- } )
- .click();
- } );
-
- await test.step( `Expect the variation ${ variationToCreate.join(
- ', '
- ) } to be successfully saved.`, async () => {
- let newlyAddedVariationRow;
for ( const attributeValue of variationToCreate ) {
- newlyAddedVariationRow = (
- newlyAddedVariationRow || variationRows
- ).filter( {
- has: page.locator( 'option[selected]', {
- hasText: attributeValue,
- } ),
+ const attributeName = productAttributes.find(
+ ( { options } ) =>
+ options.includes( attributeValue )
+ ).name;
+ const addAttributeMenu = variationRows
+ .nth( 0 )
+ .locator( 'select', {
+ has: page.locator( 'option', {
+ hasText: attributeValue,
+ } ),
+ } );
+
+ await test.step( `Select "${ attributeValue }" from the "${ attributeName }" attribute menu`, async () => {
+ await addAttributeMenu.selectOption(
+ attributeValue
+ );
} );
}
- await expect( newlyAddedVariationRow ).toBeVisible();
- } );
- }
- } );
- } );
+ await test.step( 'Click "Save changes"', async () => {
+ await page
+ .getByRole( 'button', {
+ name: 'Save changes',
+ } )
+ .click();
+ } );
+
+ await test.step( `Expect the variation ${ variationToCreate.join(
+ ', '
+ ) } to be successfully saved.`, async () => {
+ let newlyAddedVariationRow;
+
+ for ( const attributeValue of variationToCreate ) {
+ newlyAddedVariationRow = (
+ newlyAddedVariationRow || variationRows
+ ).filter( {
+ has: page.locator( 'option[selected]', {
+ hasText: attributeValue,
+ } ),
+ } );
+ }
+
+ await expect( newlyAddedVariationRow ).toBeVisible();
+ } );
+ }
+ } );
+ }
+ );
} );
diff --git a/plugins/woocommerce/tests/legacy/framework/helpers/class-wc-helper-admin-notes.php b/plugins/woocommerce/tests/legacy/framework/helpers/class-wc-helper-admin-notes.php
index 66f12f2a352..247d3c5fa84 100644
--- a/plugins/woocommerce/tests/legacy/framework/helpers/class-wc-helper-admin-notes.php
+++ b/plugins/woocommerce/tests/legacy/framework/helpers/class-wc-helper-admin-notes.php
@@ -60,7 +60,7 @@ class WC_Helper_Admin_Notes {
$note_2->set_source( 'PHPUNIT_TEST' );
$note_2->set_status( Note::E_WC_ADMIN_NOTE_ACTIONED );
$note_2->set_is_snoozable( true );
- $note_2->set_layout( 'banner' );
+ $note_2->set_layout( 'thumbnail' );
$note_2->set_image( 'https://an-image.jpg' );
// This note has no actions.
$note_2->save();
@@ -100,7 +100,6 @@ class WC_Helper_Admin_Notes {
'?s=PHPUNIT_TEST_NOTE_4_ACTION_2_URL'
);
$note_4->save();
-
}
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/product-reviews.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/product-reviews.php
index df53aeece57..a68ad775f87 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/product-reviews.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/product-reviews.php
@@ -1,4 +1,7 @@
assertEquals( 200, $response->get_status() );
$this->assertEquals( 10, count( $product_reviews ) );
- $this->assertContains(
- array(
- 'id' => $review_id,
- 'date_created' => $product_reviews[0]['date_created'],
- 'date_created_gmt' => $product_reviews[0]['date_created_gmt'],
- 'product_id' => $product->get_id(),
- 'product_name' => $product->get_name(),
- 'product_permalink' => $product->get_permalink(),
- 'status' => 'approved',
- 'reviewer' => 'admin',
- 'reviewer_email' => 'woo@woo.local',
- 'review' => "Review content here
\n", - 'rating' => 0, - 'verified' => false, - 'reviewer_avatar_urls' => $product_reviews[0]['reviewer_avatar_urls'], - '_links' => array( - 'self' => array( - array( - 'href' => rest_url( '/wc/v3/products/reviews/' . $review_id ), + $this->assertEmpty( + ArrayUtil::deep_assoc_array_diff( + array( + 'id' => $review_id, + 'date_created' => $product_reviews[0]['date_created'], + 'date_created_gmt' => $product_reviews[0]['date_created_gmt'], + 'product_id' => $product->get_id(), + 'product_name' => $product->get_name(), + 'product_permalink' => $product->get_permalink(), + 'status' => 'approved', + 'reviewer' => 'admin', + 'reviewer_email' => 'woo@woo.local', + 'review' => "Review content here
\n", + 'rating' => 0, + 'verified' => false, + 'reviewer_avatar_urls' => $product_reviews[0]['reviewer_avatar_urls'], + '_links' => array( + 'self' => array( + array( + 'href' => rest_url( '/wc/v3/products/reviews/' . $review_id ), + ), ), - ), - 'collection' => array( - array( - 'href' => rest_url( '/wc/v3/products/reviews' ), + 'collection' => array( + array( + 'href' => rest_url( '/wc/v3/products/reviews' ), + ), ), - ), - 'up' => array( - array( - 'href' => rest_url( '/wc/v3/products/' . $product->get_id() ), + 'up' => array( + array( + 'href' => rest_url( '/wc/v3/products/' . $product->get_id() ), + ), ), ), ), - ), - $product_reviews + $product_reviews[0] + ) ); } diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/settings.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/settings.php index 32a96fb95dc..f185a811097 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/settings.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/settings.php @@ -6,6 +6,7 @@ * @since 3.0.0 */ +use Automattic\WooCommerce\Utilities\ArrayUtil; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; /** @@ -482,29 +483,39 @@ class Settings_V2 extends WC_REST_Unit_Test_Case { $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v2/settings/products' ) ); $data = $response->get_data(); $this->assertTrue( is_array( $data ) ); - $this->assertContains( - array( - 'id' => 'woocommerce_downloads_require_login', - 'label' => 'Access restriction', - 'description' => 'Downloads require login', - 'type' => 'checkbox', - 'default' => 'no', - 'tip' => 'This setting does not apply to guest purchases.', - 'value' => 'no', - '_links' => array( - 'self' => array( - array( - 'href' => rest_url( '/wc/v2/settings/products/woocommerce_downloads_require_login' ), + $data_download_required_login = null; + foreach ( $data as $setting ) { + if ( 'woocommerce_downloads_require_login' === $setting['id'] ) { + $data_download_required_login = $setting; + break; + } + } + $this->assertNotEmpty( $data_download_required_login ); + $this->assertEmpty( + ArrayUtil::deep_assoc_array_diff( + array( + 'id' => 'woocommerce_downloads_require_login', + 'label' => 'Access restriction', + 'description' => 'Downloads require login', + 'type' => 'checkbox', + 'default' => 'no', + 'tip' => 'This setting does not apply to guest purchases.', + 'value' => 'no', + '_links' => array( + 'self' => array( + array( + 'href' => rest_url( '/wc/v2/settings/products/woocommerce_downloads_require_login' ), + ), ), - ), - 'collection' => array( - array( - 'href' => rest_url( '/wc/v2/settings/products' ), + 'collection' => array( + array( + 'href' => rest_url( '/wc/v2/settings/products' ), + ), ), ), ), - ), - $data + $data_download_required_login + ) ); // test get single. @@ -540,29 +551,41 @@ class Settings_V2 extends WC_REST_Unit_Test_Case { $this->assertEquals( 200, $response->get_status() ); - $this->assertContains( - array( - 'id' => 'recipient', - 'label' => 'Recipient(s)', - 'description' => 'Enter recipients (comma separated) for this email. Defaults toadmin@example.org
.',
- 'type' => 'text',
- 'default' => '',
- 'tip' => 'Enter recipients (comma separated) for this email. Defaults to admin@example.org
.',
- 'value' => '',
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v2/settings/email_new_order/recipient' ),
+ $recipient_setting = null;
+ foreach ( $settings as $setting ) {
+ if ( 'recipient' === $setting['id'] ) {
+ $recipient_setting = $setting;
+ break;
+ }
+ }
+
+ $this->assertNotEmpty( $recipient_setting );
+
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => 'recipient',
+ 'label' => 'Recipient(s)',
+ 'description' => 'Enter recipients (comma separated) for this email. Defaults to admin@example.org
.',
+ 'type' => 'text',
+ 'default' => '',
+ 'tip' => 'Enter recipients (comma separated) for this email. Defaults to admin@example.org
.',
+ 'value' => '',
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/settings/email_new_order/recipient' ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v2/settings/email_new_order' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/settings/email_new_order' ),
+ ),
),
),
),
- ),
- $settings
+ $recipient_setting
+ )
);
// test get single.
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-methods.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-methods.php
index 3f13ecb2ee1..d27efd5b67b 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-methods.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-methods.php
@@ -1,4 +1,7 @@
get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertContains(
- array(
- 'id' => 'free_shipping',
- 'title' => 'Free shipping',
- 'description' => 'Free shipping is a special method which can be triggered with coupons and minimum spends.',
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping_methods/free_shipping' ),
+
+ $free_shipping_method = null;
+ foreach ( $methods as $method ) {
+ if ( 'free_shipping' === $method['id'] ) {
+ $free_shipping_method = $method;
+ break;
+ }
+ }
+ $this->assertNotEmpty( $free_shipping_method );
+
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => 'free_shipping',
+ 'title' => 'Free shipping',
+ 'description' => 'Free shipping is a special method which can be triggered with coupons and minimum spends.',
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping_methods/free_shipping' ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping_methods' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping_methods' ),
+ ),
),
),
),
- ),
- $methods
+ $free_shipping_method
+ )
);
}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-zones.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-zones.php
index bc020791d02..1e15bb91e02 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-zones.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version2/shipping-zones.php
@@ -1,5 +1,7 @@
assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 1 );
- $this->assertContains(
- array(
- 'id' => $data[0]['id'],
- 'name' => 'Locations not covered by your other zones',
- 'order' => 0,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[0]['id'] ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $data[0]['id'],
+ 'name' => 'Locations not covered by your other zones',
+ 'order' => 0,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[0]['id'] ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[0]['id'] . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[0]['id'] . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data[0]
+ )
);
// Create a zone and make sure it's in the response
@@ -108,30 +112,32 @@ class WC_Tests_API_Shipping_Zones_V2 extends WC_REST_Unit_Test_Case {
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 2 );
- $this->assertContains(
- array(
- 'id' => $data[1]['id'],
- 'name' => 'Zone 1',
- 'order' => 0,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[1]['id'] ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $data[1]['id'],
+ 'name' => 'Zone 1',
+ 'order' => 0,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[1]['id'] ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[1]['id'] . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $data[1]['id'] . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data[1]
+ )
);
}
@@ -195,30 +201,32 @@ class WC_Tests_API_Shipping_Zones_V2 extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$this->assertEquals( 201, $response->get_status() );
- $this->assertEquals(
- array(
- 'id' => $data['id'],
- 'name' => 'Test Zone',
- 'order' => 1,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $data['id'] ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $data['id'],
+ 'name' => 'Test Zone',
+ 'order' => 1,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $data['id'] ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $data['id'] . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $data['id'] . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data
+ )
);
}
@@ -260,30 +268,32 @@ class WC_Tests_API_Shipping_Zones_V2 extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertEquals(
- array(
- 'id' => $zone->get_id(),
- 'name' => 'Zone Test',
- 'order' => 2,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $zone->get_id(),
+ 'name' => 'Zone Test',
+ 'order' => 2,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data
+ )
);
}
@@ -359,30 +369,32 @@ class WC_Tests_API_Shipping_Zones_V2 extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertEquals(
- array(
- 'id' => $zone->get_id(),
- 'name' => 'Test Zone',
- 'order' => 0,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $zone->get_id(),
+ 'name' => 'Test Zone',
+ 'order' => 0,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v2/shipping/zones/' . $zone->get_id() . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data
+ )
);
}
@@ -624,13 +636,13 @@ class WC_Tests_API_Shipping_Zones_V2 extends WC_REST_Unit_Test_Case {
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 1 );
- $this->assertContains( $expected, $data );
+ $this->assertEmpty( ArrayUtil::deep_assoc_array_diff( $expected, $data[0] ) );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v2/shipping/zones/' . $zone->get_id() . '/methods/' . $instance_id ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertEquals( $expected, $data );
+ $this->assertEmpty( ArrayUtil::deep_assoc_array_diff( $expected, $data ) );
}
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/product-reviews.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/product-reviews.php
index 11aa94c16b7..b655ffb538a 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/product-reviews.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/product-reviews.php
@@ -1,4 +1,7 @@
assertEquals( 200, $response->get_status() );
$this->assertEquals( 10, count( $product_reviews ) );
- $this->assertContains(
- array(
- 'id' => $review_id,
- 'date_created' => $product_reviews[0]['date_created'],
- 'date_created_gmt' => $product_reviews[0]['date_created_gmt'],
- 'product_id' => $product->get_id(),
- 'product_name' => $product->get_name(),
- 'product_permalink' => $product->get_permalink(),
- 'status' => 'approved',
- 'reviewer' => 'admin',
- 'reviewer_email' => 'woo@woo.local',
- 'review' => "Review content here
\n", - 'rating' => 0, - 'verified' => false, - 'reviewer_avatar_urls' => $product_reviews[0]['reviewer_avatar_urls'], - '_links' => array( - 'self' => array( - array( - 'href' => rest_url( '/wc/v3/products/reviews/' . $review_id ), + $this->assertEmpty( + ArrayUtil::deep_assoc_array_diff( + array( + 'id' => $review_id, + 'date_created' => $product_reviews[0]['date_created'], + 'date_created_gmt' => $product_reviews[0]['date_created_gmt'], + 'product_id' => $product->get_id(), + 'product_name' => $product->get_name(), + 'product_permalink' => $product->get_permalink(), + 'status' => 'approved', + 'reviewer' => 'admin', + 'reviewer_email' => 'woo@woo.local', + 'review' => "Review content here
\n", + 'rating' => 0, + 'verified' => false, + 'reviewer_avatar_urls' => $product_reviews[0]['reviewer_avatar_urls'], + '_links' => array( + 'self' => array( + array( + 'href' => rest_url( '/wc/v3/products/reviews/' . $review_id ), + ), ), - ), - 'collection' => array( - array( - 'href' => rest_url( '/wc/v3/products/reviews' ), + 'collection' => array( + array( + 'href' => rest_url( '/wc/v3/products/reviews' ), + ), ), - ), - 'up' => array( - array( - 'href' => rest_url( '/wc/v3/products/' . $product->get_id() ), + 'up' => array( + array( + 'href' => rest_url( '/wc/v3/products/' . $product->get_id() ), + ), ), ), ), - ), - $product_reviews + $product_reviews[0] + ) ); } diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/settings.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/settings.php index d8890569eff..d10062ec2ee 100644 --- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/settings.php +++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/settings.php @@ -6,6 +6,7 @@ * @since 3.5.0 */ +use Automattic\WooCommerce\Utilities\ArrayUtil; use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; /** @@ -481,29 +482,42 @@ class Settings extends WC_REST_Unit_Test_Case { $response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/settings/products' ) ); $data = $response->get_data(); $this->assertTrue( is_array( $data ) ); - $this->assertContains( - array( - 'id' => 'woocommerce_downloads_require_login', - 'label' => 'Access restriction', - 'description' => 'Downloads require login', - 'type' => 'checkbox', - 'default' => 'no', - 'tip' => 'This setting does not apply to guest purchases.', - 'value' => 'no', - '_links' => array( - 'self' => array( - array( - 'href' => rest_url( '/wc/v3/settings/products/woocommerce_downloads_require_login' ), + + $setting_downloads_required = null; + foreach ( $data as $setting ) { + if ( 'woocommerce_downloads_require_login' === $setting['id'] ) { + $setting_downloads_required = $setting; + break; + } + } + + $this->assertNotEmpty( $setting_downloads_required ); + + $this->assertEmpty( + ArrayUtil::deep_assoc_array_diff( + array( + 'id' => 'woocommerce_downloads_require_login', + 'label' => 'Access restriction', + 'description' => 'Downloads require login', + 'type' => 'checkbox', + 'default' => 'no', + 'tip' => 'This setting does not apply to guest purchases.', + 'value' => 'no', + '_links' => array( + 'self' => array( + array( + 'href' => rest_url( '/wc/v3/settings/products/woocommerce_downloads_require_login' ), + ), ), - ), - 'collection' => array( - array( - 'href' => rest_url( '/wc/v3/settings/products' ), + 'collection' => array( + array( + 'href' => rest_url( '/wc/v3/settings/products' ), + ), ), ), ), - ), - $data + $setting_downloads_required + ) ); // test get single. @@ -539,29 +553,41 @@ class Settings extends WC_REST_Unit_Test_Case { $this->assertEquals( 200, $response->get_status() ); - $this->assertContains( - array( - 'id' => 'recipient', - 'label' => 'Recipient(s)', - 'description' => 'Enter recipients (comma separated) for this email. Defaults toadmin@example.org
.',
- 'type' => 'text',
- 'default' => '',
- 'tip' => 'Enter recipients (comma separated) for this email. Defaults to admin@example.org
.',
- 'value' => '',
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v3/settings/email_new_order/recipient' ),
+ $recipient_setting = null;
+ foreach ( $settings as $setting ) {
+ if ( 'recipient' === $setting['id'] ) {
+ $recipient_setting = $setting;
+ break;
+ }
+ }
+
+ $this->assertNotEmpty( $recipient_setting );
+
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => 'recipient',
+ 'label' => 'Recipient(s)',
+ 'description' => 'Enter recipients (comma separated) for this email. Defaults to admin@example.org
.',
+ 'type' => 'text',
+ 'default' => '',
+ 'tip' => 'Enter recipients (comma separated) for this email. Defaults to admin@example.org
.',
+ 'value' => '',
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/settings/email_new_order/recipient' ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v3/settings/email_new_order' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/settings/email_new_order' ),
+ ),
),
),
),
- ),
- $settings
+ $recipient_setting
+ )
);
// test get single.
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-methods.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-methods.php
index 31dc36c1b14..05d38ad0517 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-methods.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-methods.php
@@ -1,4 +1,7 @@
get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertContains(
- array(
- 'id' => 'free_shipping',
- 'title' => 'Free shipping',
- 'description' => 'Free shipping is a special method which can be triggered with coupons and minimum spends.',
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping_methods/free_shipping' ),
+
+ $free_shipping = null;
+ foreach ( $methods as $method ) {
+ if ( 'free_shipping' === $method['id'] ) {
+ $free_shipping = $method;
+ break;
+ }
+ }
+ $this->assertNotEmpty( $free_shipping );
+
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => 'free_shipping',
+ 'title' => 'Free shipping',
+ 'description' => 'Free shipping is a special method which can be triggered with coupons and minimum spends.',
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping_methods/free_shipping' ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping_methods' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping_methods' ),
+ ),
),
),
),
- ),
- $methods
+ $free_shipping
+ )
);
}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-zones.php b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-zones.php
index 1dd58034653..3c49902d989 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-zones.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/rest-api/Tests/Version3/shipping-zones.php
@@ -1,5 +1,7 @@
assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 1 );
- $this->assertContains(
- array(
- 'id' => $data[0]['id'],
- 'name' => 'Locations not covered by your other zones',
- 'order' => 0,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[0]['id'] ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $data[0]['id'],
+ 'name' => 'Locations not covered by your other zones',
+ 'order' => 0,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[0]['id'] ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[0]['id'] . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[0]['id'] . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data[0]
+ )
);
// Create a zone and make sure it's in the response
@@ -111,30 +115,32 @@ class WC_Tests_API_Shipping_Zones extends WC_REST_Unit_Test_Case {
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 2 );
- $this->assertContains(
- array(
- 'id' => $data[1]['id'],
- 'name' => 'Zone 1',
- 'order' => 0,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[1]['id'] ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $data[1]['id'],
+ 'name' => 'Zone 1',
+ 'order' => 0,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[1]['id'] ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[1]['id'] . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $data[1]['id'] . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data[1]
+ )
);
}
@@ -202,30 +208,32 @@ class WC_Tests_API_Shipping_Zones extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$this->assertEquals( 201, $response->get_status() );
- $this->assertEquals(
- array(
- 'id' => $data['id'],
- 'name' => 'Test Zone',
- 'order' => 1,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $data['id'] ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $data['id'],
+ 'name' => 'Test Zone',
+ 'order' => 1,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $data['id'] ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $data['id'] . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $data['id'] . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data
+ )
);
}
@@ -269,30 +277,32 @@ class WC_Tests_API_Shipping_Zones extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertEquals(
- array(
- 'id' => $zone->get_id(),
- 'name' => 'Zone Test',
- 'order' => 2,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $zone->get_id(),
+ 'name' => 'Zone Test',
+ 'order' => 2,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data
+ )
);
}
@@ -373,30 +383,32 @@ class WC_Tests_API_Shipping_Zones extends WC_REST_Unit_Test_Case {
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertEquals(
- array(
- 'id' => $zone->get_id(),
- 'name' => 'Test Zone',
- 'order' => 0,
- '_links' => array(
- 'self' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() ),
+ $this->assertEmpty(
+ ArrayUtil::deep_assoc_array_diff(
+ array(
+ 'id' => $zone->get_id(),
+ 'name' => 'Test Zone',
+ 'order' => 0,
+ '_links' => array(
+ 'self' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() ),
+ ),
),
- ),
- 'collection' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ 'collection' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones' ),
+ ),
),
- ),
- 'describedby' => array(
- array(
- 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() . '/locations' ),
+ 'describedby' => array(
+ array(
+ 'href' => rest_url( '/wc/v3/shipping/zones/' . $zone->get_id() . '/locations' ),
+ ),
),
),
),
- ),
- $data
+ $data
+ )
);
}
@@ -644,13 +656,12 @@ class WC_Tests_API_Shipping_Zones extends WC_REST_Unit_Test_Case {
$this->assertEquals( 200, $response->get_status() );
$this->assertEquals( count( $data ), 1 );
- $this->assertContains( $expected, $data );
-
+ $this->assertEmpty( ArrayUtil::deep_assoc_array_diff( $expected, $data[0] ) );
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/shipping/zones/' . $zone->get_id() . '/methods/' . $instance_id ) );
$data = $response->get_data();
$this->assertEquals( 200, $response->get_status() );
- $this->assertEquals( $expected, $data );
+ $this->assertEmpty( ArrayUtil::deep_assoc_array_diff( $expected, $data ) );
}
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/base-location-country-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/base-location-country-rule-processor.php
similarity index 94%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/base-location-country-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/base-location-country-rule-processor.php
index b49df23970d..031da61b9f2 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/base-location-country-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/base-location-country-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Base Location country rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\BaseLocationCountryRuleProcessor;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_BaseLocationCountryRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_BaseLocationCountryRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_BaseLocationCountryRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_BaseLocationCountryRuleProcessor extends WC_Unit_Test_Case {
/**
* Get the publish_before rule.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/base-location-state-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/base-location-state-rule-processor.php
similarity index 84%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/base-location-state-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/base-location-state-rule-processor.php
index 9135ab0b05d..d69972954c0 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/base-location-state-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/base-location-state-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Base Location state rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\BaseLocationStateRuleProcessor;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_BaseLocationStateRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_BaseLocationStateRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_BaseLocationStateRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_BaseLocationStateRuleProcessor extends WC_Unit_Test_Case {
/**
* Get the base_location_state rule.
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/comparison-operation.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/comparison-operation.php
similarity index 90%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/comparison-operation.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/comparison-operation.php
index 85fa28f8e9f..7ea8bd7dd8b 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/comparison-operation.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/comparison-operation.php
@@ -5,12 +5,14 @@
* @package WooCommerce\Admin\Tests\RemoteInboxNotification
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\ComparisonOperation;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Comparison_Operation
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_Comparison_Operation
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Comparison_Operation extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_Comparison_Operation extends WC_Unit_Test_Case {
/**
* @var ComparisonOperation $operation
*/
@@ -36,7 +38,6 @@ class WC_Admin_Tests_RemoteInboxNotifications_Comparison_Operation extends WC_Un
$this->assertFalse( $this->operation->compare( 11, array( 1, 10 ), 'range' ) );
$this->assertFalse( $this->operation->compare( 11, array( 1, 10, 2 ), 'range' ) );
$this->assertFalse( $this->operation->compare( 11, 'string', 'range' ) );
-
}
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/evaluate-and-get-status.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/evaluate-and-get-status.php
similarity index 95%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/evaluate-and-get-status.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/evaluate-and-get-status.php
index 7de3b0c6251..7ec67d2f995 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/evaluate-and-get-status.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/evaluate-and-get-status.php
@@ -2,15 +2,17 @@
/**
* Evaluate and get status tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\EvaluateAndGetStatus;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_EvaluateAndGetStatus
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_EvaluateAndGetStatus
*/
-class WC_Admin_Tests_RemoteInboxNotifications_EvaluateAndGetStatus extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_EvaluateAndGetStatus extends WC_Unit_Test_Case {
/**
* Build up a spec given the supplied parameters.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/failing-rule-evaluator.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/failing-rule-evaluator.php
similarity index 58%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/failing-rule-evaluator.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/failing-rule-evaluator.php
index 8d856895e5b..b4c79cffb31 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/failing-rule-evaluator.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/failing-rule-evaluator.php
@@ -2,9 +2,11 @@
/**
* FailingRuleEvaluator
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
/**
* class FailingRuleEvaluator
*/
@@ -16,7 +18,7 @@ class FailingRuleEvaluator {
*
* @return bool The evaluated result.
*/
- public function evaluate( $rules ) {
+ public function evaluate( $rules ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
return false;
}
}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/get-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/get-rule-processor.php
similarity index 70%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/get-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/get-rule-processor.php
index b5eee559d84..fb2721229eb 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/get-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/get-rule-processor.php
@@ -2,15 +2,17 @@
/**
* Get rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\GetRuleProcessor;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_GetRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_GetRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_GetRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_GetRuleProcessor extends WC_Unit_Test_Case {
/**
* Tests that an unknown rule processor returns a FailRuleProcessor
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/is-woo-express-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/is-woo-express-rule-processor.php
similarity index 91%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/is-woo-express-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/is-woo-express-rule-processor.php
index 5db49ff717f..ba2bca4b7cf 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/is-woo-express-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/is-woo-express-rule-processor.php
@@ -2,15 +2,17 @@
/**
* Is WooExpress rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\IsWooExpressRuleProcessor;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_IsWooExpressRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_IsWooExpressRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_IsWooExpressRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_IsWooExpressRuleProcessor extends WC_Unit_Test_Case {
/**
* Set Up Before Class.
*/
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-date-time-provider.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-date-time-provider.php
similarity index 87%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-date-time-provider.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-date-time-provider.php
index e250192bb23..cc8c32321c2 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-date-time-provider.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-date-time-provider.php
@@ -2,9 +2,11 @@
/**
* Mock DateTime Provider.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\DateTimeProvider\DateTimeProviderInterface;
/**
@@ -29,4 +31,3 @@ class MockDateTimeProvider implements DateTimeProviderInterface {
return $this->now;
}
}
-
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-get-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-get-rule-processor.php
similarity index 91%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-get-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-get-rule-processor.php
index 5de623920a5..805e6aabca2 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-get-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-get-rule-processor.php
@@ -2,9 +2,11 @@
/**
* MockGetRuleProcessor.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PublishAfterTimeRuleProcessor;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\FailRuleProcessor;
@@ -29,4 +31,3 @@ class MockGetRuleProcessor {
return new FailRuleProcessor();
}
}
-
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-plugins-provider.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-plugins-provider.php
similarity index 96%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-plugins-provider.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-plugins-provider.php
index 72e4bc22b62..f9a14565af9 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-plugins-provider.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-plugins-provider.php
@@ -2,9 +2,11 @@
/**
* Mock plugins Provider.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProviderInterface;
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-product-query.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-product-query.php
similarity index 85%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-product-query.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-product-query.php
index 681309d4045..8b3c0381e77 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-product-query.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-product-query.php
@@ -2,9 +2,11 @@
/**
* Mock product query.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
/**
* Mock product query.
*/
@@ -29,4 +31,3 @@ class MockProductQuery {
);
}
}
-
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-wc-admin-active-for-provider.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-wc-admin-active-for-provider.php
similarity index 80%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-wc-admin-active-for-provider.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-wc-admin-active-for-provider.php
index 37932001686..3f65b3f1030 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/mock-wc-admin-active-for-provider.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/mock-wc-admin-active-for-provider.php
@@ -2,9 +2,11 @@
/**
* Mock WCAdminActiveForProvider
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
/**
* Mock WCAdminActiveForProvider
*/
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/not-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/not-rule-processor.php
similarity index 88%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/not-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/not-rule-processor.php
index 9088cec3242..f2628792362 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/not-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/not-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Not rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\NotRuleProcessor;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_NotRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_NotRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_NotRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_NotRuleProcessor extends WC_Unit_Test_Case {
/**
* An empty operand evaluates to false, so negating that should
* evaluate to true.
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/onboarding-profile-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/onboarding-profile-rule-processor.php
similarity index 87%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/onboarding-profile-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/onboarding-profile-rule-processor.php
index 097670b0115..9f59c1ab06f 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/onboarding-profile-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/onboarding-profile-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Onboarding profile rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OnboardingProfileRuleProcessor;
use Automattic\WooCommerce\Internal\Admin\Onboarding\OnboardingProfile;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_OnboardingProfileRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_OnboardingProfileRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_OnboardingProfileRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_OnboardingProfileRuleProcessor extends WC_Unit_Test_Case {
/**
* Get the publish_before rule.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/option-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/option-rule-processor.php
similarity index 93%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/option-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/option-rule-processor.php
index 6e062f0ec7a..20f5dccad84 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/option-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/option-rule-processor.php
@@ -2,15 +2,17 @@
/**
* Option rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OptionRuleProcessor;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_OptionRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_OptionRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_OptionRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_OptionRuleProcessor extends WC_Unit_Test_Case {
/**
* No default option resolves to false.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/or-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/or-rule-processor.php
similarity index 93%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/or-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/or-rule-processor.php
index 6c93dfd1fb8..90c95605e1a 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/or-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/or-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Or rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\OrRuleProcessor;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\RuleEvaluator;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_OrRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_OrRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_OrRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_OrRuleProcessor extends WC_Unit_Test_Case {
/**
* Both operands evaluating to false and ORed together evaluates to false.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/passing-rule-evaluator.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/passing-rule-evaluator.php
similarity index 58%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/passing-rule-evaluator.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/passing-rule-evaluator.php
index 9a504e784cd..f0d730f1ced 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/passing-rule-evaluator.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/passing-rule-evaluator.php
@@ -2,9 +2,11 @@
/**
* PassingRuleEvaluator
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
/**
* class PassingRuleEvaluator
*/
@@ -16,7 +18,7 @@ class PassingRuleEvaluator {
*
* @return bool The evaluated result.
*/
- public function evaluate( $rules ) {
+ public function evaluate( $rules ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
return true;
}
}
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/plugin-version-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/plugin-version-rule-processor.php
similarity index 94%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/plugin-version-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/plugin-version-rule-processor.php
index a38fdbb9a63..cd2d9c5811e 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/plugin-version-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/plugin-version-rule-processor.php
@@ -2,15 +2,17 @@
/**
* Plugin version rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PluginVersionRuleProcessor;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_PluginVersionRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PluginVersionRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_PluginVersionRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PluginVersionRuleProcessor extends WC_Unit_Test_Case {
/**
* Test that the processor does not pass if the plugin is not activated.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/plugins-activated-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/plugins-activated-rule-processor.php
similarity index 93%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/plugins-activated-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/plugins-activated-rule-processor.php
index 41f478cedce..6250102b9bc 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/plugins-activated-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/plugins-activated-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Plugins activated rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PluginsActivatedRuleProcessor;
use Automattic\WooCommerce\Admin\PluginsProvider\PluginsProviderInterface;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_PluginsActivatedRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PluginsActivatedRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_PluginsActivatedRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PluginsActivatedRuleProcessor extends WC_Unit_Test_Case {
/**
* Tests that the processor does not pass a plugins_activated rule with
* no plugins to verify.
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/product-count-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/product-count-rule-processor.php
similarity index 81%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/product-count-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/product-count-rule-processor.php
index a3ca1a8cb74..2e4b0e1891f 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/product-count-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/product-count-rule-processor.php
@@ -2,15 +2,17 @@
/**
* Product count rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\ProductCountRuleProcessor;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_ProductCountRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_ProductCountRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_ProductCountRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_ProductCountRuleProcessor extends WC_Unit_Test_Case {
/**
* Get a product_count rule that passes when the product count is > 5.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/publish-after-time-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/publish-after-time-rule-processor.php
similarity index 90%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/publish-after-time-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/publish-after-time-rule-processor.php
index 9aec0acfcfd..4057a9f1daf 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/publish-after-time-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/publish-after-time-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Publish after time rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PublishAfterTimeRuleProcessor;
use Automattic\WooCommerce\Admin\DateTimeProvider\DateTimeProviderInterface;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_PublishAfterTimeRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PublishAfterTimeRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_PublishAfterTimeRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PublishAfterTimeRuleProcessor extends WC_Unit_Test_Case {
/**
* Get the publish_after rule.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/publish-before-time-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/publish-before-time-rule-processor.php
similarity index 90%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/publish-before-time-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/publish-before-time-rule-processor.php
index 0234df59c87..60e23fbf5ec 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/publish-before-time-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/publish-before-time-rule-processor.php
@@ -2,16 +2,18 @@
/**
* Publish before time rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\PublishBeforeTimeRuleProcessor;
use Automattic\WooCommerce\Admin\DateTimeProvider\DateTimeProviderInterface;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_PublishBeforeTimeRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PublishBeforeTimeRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_PublishBeforeTimeRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_PublishBeforeTimeRuleProcessor extends WC_Unit_Test_Case {
/**
* Get the publish_before rule.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/stored-state-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/stored-state-rule-processor.php
similarity index 97%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/stored-state-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/stored-state-rule-processor.php
index 47567a6627d..ed1f616e67c 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/stored-state-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/stored-state-rule-processor.php
@@ -2,15 +2,17 @@
/**
* Stored state rule processor tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\StoredStateRuleProcessor;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_StoredStateRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_StoredStateRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_StoredStateRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_StoredStateRuleProcessor extends WC_Unit_Test_Case {
/**
* Empty $stored_state evaluates to false.
*
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/total-payments-volume-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/total-payments-volume-processor.php
similarity index 93%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/total-payments-volume-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/total-payments-volume-processor.php
index d177dd8f975..7d11b482a78 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/total-payments-volume-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/total-payments-volume-processor.php
@@ -5,13 +5,15 @@
* @package WooCommerce\Admin\Tests\RemoteInboxNotification
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\TotalPaymentsVolumeProcessor;
use Automattic\WooCommerce\Admin\API\Reports\Revenue\Query as RevenueQuery;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_TotalPaymentsVolumeProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_TotalPaymentsVolumeProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_TotalPaymentsVolumeProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_TotalPaymentsVolumeProcessor extends WC_Unit_Test_Case {
/**
* Greater than 1000 total payments volume evaluates to false.
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/transformer-service.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformer-service.php
similarity index 95%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/transformer-service.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformer-service.php
index 224e7ba86e4..c5e17aee945 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/transformer-service.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformer-service.php
@@ -2,16 +2,18 @@
/**
* TransformerService tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayKeys;
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\TransformerService;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_TransformerService
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_TransformerService
*/
-class WC_Admin_Tests_RemoteInboxNotifications_TransformerService extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_TransformerService extends WC_Unit_Test_Case {
/**
* Test it creates a transformer with snake case 'use' value
*/
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-column.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-column.php
similarity index 82%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-column.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-column.php
index e5303725b37..bb1ed192b74 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-column.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-column.php
@@ -2,23 +2,25 @@
/**
* ArrayColumn tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayColumn;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayColumn
+ * class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayColumn
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayColumn extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayColumn extends WC_Unit_Test_Case {
/**
* Test validate method returns false when 'key' argument is missing
*/
public function test_validate_returns_false_when_key_argument_is_missing() {
$array_column = new ArrayColumn();
$result = $array_column->validate( (object) array() );
- $this->assertFalse( false, $result );
+ $this->assertFalse( $result );
}
/**
@@ -31,14 +33,14 @@ class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayColumn extends W
'key' => true,
)
);
- $this->assertFalse( false, $result );
+ $this->assertFalse( $result );
$result = $array_column->validate(
(object) array(
'key' => array(),
)
);
- $this->assertFalse( false, $result );
+ $this->assertFalse( $result );
}
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-flatten.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-flatten.php
similarity index 92%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-flatten.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-flatten.php
index b02ba40fff9..5e5d76c2834 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-flatten.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-flatten.php
@@ -2,9 +2,11 @@
/**
* ArrayKeys tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayFlatten;
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-keys.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-keys.php
similarity index 77%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-keys.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-keys.php
index b8e7d036192..f9e7b5df6c3 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-keys.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-keys.php
@@ -2,15 +2,17 @@
/**
* ArrayKeys tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayKeys;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayKeys
+ * class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayKeys
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayKeys extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayKeys extends WC_Unit_Test_Case {
/**
* Test it returns default value when value is not an array
*/
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-search.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-search.php
similarity index 84%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-search.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-search.php
index 46167d4b93e..17172146021 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-search.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-search.php
@@ -2,22 +2,24 @@
/**
* ArraySearch tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArraySearch;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArraySearch
+ * class WC_Admin_Tests_RemoteSpecs_Transformers_ArraySearch
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArraySearch extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_Transformers_ArraySearch extends WC_Unit_Test_Case {
/**
* Test validate method returns false when 'value' argument is missing
*/
public function test_validate_returns_false_when_value_argument_is_missing() {
$array_column = new ArraySearch();
$result = $array_column->validate( (object) array() );
- $this->assertFalse( false, $result );
+ $this->assertFalse( $result );
}
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-values.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-values.php
similarity index 77%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-values.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-values.php
index efef87142be..18d96425cf4 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/array-values.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/array-values.php
@@ -2,15 +2,17 @@
/**
* ArrayValues tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\ArrayValues;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayValues
+ * class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayValues
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayValues extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayValues extends WC_Unit_Test_Case {
/**
* Test it returns default value when value is not an array
*/
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/count.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/count.php
similarity index 76%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/count.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/count.php
index 703a5804909..38f0f65ccb5 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/count.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/count.php
@@ -2,15 +2,17 @@
/**
* ArrayValues tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\Count;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayValues
+ * class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayValues
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Transformers_ArrayCount extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_Transformers_ArrayCount extends WC_Unit_Test_Case {
/**
* Test it returns default value when value is not an array.
*/
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/dot-notation.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/dot-notation.php
similarity index 88%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/dot-notation.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/dot-notation.php
index 1e74188467a..32f76474014 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/dot-notation.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/dot-notation.php
@@ -2,16 +2,18 @@
/**
* DotNotation tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\DotNotation;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Transformers_DotNotation
+ * class WC_Admin_Tests_RemoteSpecs_Transformers_DotNotation
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Transformers_DotNotation extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_Transformers_DotNotation extends WC_Unit_Test_Case {
/**
* Test validate method returns false when 'path' argument is missing
@@ -19,7 +21,7 @@ class WC_Admin_Tests_RemoteInboxNotifications_Transformers_DotNotation extends W
public function test_validate_returns_false_when_path_argument_is_missing() {
$array_column = new DotNotation();
$result = $array_column->validate( (object) array() );
- $this->assertFalse( false, $result );
+ $this->assertFalse( $result );
}
/**
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/prepare-url.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/prepare-url.php
similarity index 84%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/prepare-url.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/prepare-url.php
index a6f9d42478a..0e8c2145358 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/Transformers/prepare-url.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/transformers/prepare-url.php
@@ -2,15 +2,17 @@
/**
* PrepareUrl tests.
*
- * @package WooCommerce\Admin\Tests\RemoteInboxNotifications
+ * @package WooCommerce\Admin\Tests\RemoteSpecs
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\Transformers\PrepareUrl;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_Transformers_PrepareUrl
+ * class WC_Admin_Tests_RemoteSpecs_Transformers_PrepareUrl
*/
-class WC_Admin_Tests_RemoteInboxNotifications_Transformers_PrepareUrl extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_Transformers_PrepareUrl extends WC_Unit_Test_Case {
/**
* Test it returns default value when url is not string.
*/
diff --git a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/wcadmin-active-for-rule-processor.php b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/wcadmin-active-for-rule-processor.php
similarity index 93%
rename from plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/wcadmin-active-for-rule-processor.php
rename to plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/wcadmin-active-for-rule-processor.php
index dca95841a92..8cd0349f66f 100644
--- a/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-inbox-notifications/wcadmin-active-for-rule-processor.php
+++ b/plugins/woocommerce/tests/legacy/unit-tests/woocommerce-admin/remote-specs/rule-processors/wcadmin-active-for-rule-processor.php
@@ -5,12 +5,14 @@
* @package WooCommerce\Admin\Tests\RemoteInboxNotification
*/
+declare( strict_types = 1 );
+
use Automattic\WooCommerce\Admin\RemoteSpecs\RuleProcessors\WCAdminActiveForRuleProcessor;
/**
- * class WC_Admin_Tests_RemoteInboxNotifications_WCAdminActiveForRuleProcessor
+ * class WC_Admin_Tests_RemoteSpecs_RuleProcessors_WCAdminActiveForRuleProcessor
*/
-class WC_Admin_Tests_RemoteInboxNotifications_WCAdminActiveForRuleProcessor extends WC_Unit_Test_Case {
+class WC_Admin_Tests_RemoteSpecs_RuleProcessors_WCAdminActiveForRuleProcessor extends WC_Unit_Test_Case {
/**
* Greater than 7 days evaluates to true
*
diff --git a/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-brands-test.php b/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-brands-test.php
new file mode 100644
index 00000000000..5ca5953daf5
--- /dev/null
+++ b/plugins/woocommerce/tests/php/includes/admin/class-wc-admin-brands-test.php
@@ -0,0 +1,116 @@
+factory()->term->create(
+ array(
+ 'taxonomy' => 'product_brand',
+ 'name' => 'Blah_A',
+ )
+ );
+ $term_b_id = $this->factory()->term->create(
+ array(
+ 'taxonomy' => 'product_brand',
+ 'name' => 'Foo_A',
+ )
+ );
+ $term_c_id = $this->factory()->term->create(
+ array(
+ 'taxonomy' => 'product_brand',
+ 'name' => 'Blah_B',
+ )
+ );
+
+ wp_set_post_terms( $simple_product->get_id(), array( $term_a_id, $term_b_id, $term_c_id ), 'product_brand' );
+
+ add_filter(
+ 'woocommerce_product_brand_filter_threshold',
+ function () {
+ return 3;
+ }
+ );
+
+ $brands_admin = new WC_Brands_Admin();
+ ob_start();
+ $brands_admin->render_product_brand_filter();
+ $output = ob_get_contents();
+ ob_end_clean();
+
+ $this->assertStringContainsString(
+ '