Merge branch 'trunk' into add/api-tests-orders-crud

This commit is contained in:
Rodel 2021-11-09 14:38:19 +08:00
commit 1f341df486
37 changed files with 604 additions and 116 deletions

View File

@ -18,7 +18,7 @@ jobs:
ref: ${{ matrix.build }}
- name: Build
id: build
uses: woocommerce/action-build@v2
uses: woocommerce/action-build@trunk
- name: Deploy nightly build
uses: WebFreak001/deploy-nightly@v1.1.0
env:

View File

@ -75,4 +75,9 @@ jobs:
WC_E2E_SCREENSHOTS: 1
E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }}
E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }}
run: pnpx wc-e2e test:e2e
BASE_URL: ${{ secrets.PR_E2E_TEST_URL }}
USER_KEY: ${{ secrets.PR_E2E_TEST_ADMIN_USER }}
USER_SECRET: ${{ secrets.PR_E2E_TEST_ADMIN_PASSWORD }}
run: |
pnpx wc-e2e test:e2e
pnpx wc-api-tests test api

View File

@ -1,6 +1,8 @@
name: Run smoke tests against pull request.
on:
pull_request:
branches:
- trunk
types:
- labeled
jobs:
@ -19,16 +21,19 @@ jobs:
- name: Checkout code.
uses: actions/checkout@v2
with:
ref: trunk
path: package/woocommerce
- name: Install prerequisites.
working-directory: package/woocommerce/plugins/woocommerce
run: |
npm install
npm install -g pnpm
pnpm install
composer install --no-dev
npm run build:assets
npm install jest
pnpm run build:assets
pnpm install jest
- name: Run smoke test.
working-directory: package/woocommerce/plugins/woocommerce
env:
SMOKE_TEST_URL: ${{ secrets.SMOKE_TEST_URL }}
SMOKE_TEST_ADMIN_USER: ${{ secrets.SMOKE_TEST_ADMIN_USER }}
@ -43,8 +48,8 @@ jobs:
UPDATE_WC: 1
DEFAULT_TIMEOUT_OVERRIDE: 120000
run: |
npx wc-e2e test:e2e ./tests/e2e/specs/smoke-tests/update-woocommerce.js
npx wc-e2e test:e2e
pnpx wc-e2e test:e2e plugins/woocommerce/tests/e2e/specs/smoke-tests/update-woocommerce.js
pnpx wc-e2e test:e2e
- name: Remove label from pull request.
if: "${{ contains(github.event.pull_request.labels.*.name, 'run: smoke tests') }}"

View File

@ -18,16 +18,20 @@ jobs:
- name: Checkout code.
uses: actions/checkout@v2
with:
path: package/woocommerce
ref: trunk
- name: Install prerequisites.
working-directory: package/woocommerce/plugins/woocommerce
run: |
npm install
npm install -g pnpm
pnpm install
composer install --no-dev
npm run build:assets
npm install jest
pnpm run build:assets
pnpm install jest
- name: Run smoke test.
working-directory: package/woocommerce/plugins/woocommerce
env:
SMOKE_TEST_URL: ${{ secrets.SMOKE_TEST_URL }}
SMOKE_TEST_ADMIN_USER: ${{ secrets.SMOKE_TEST_ADMIN_USER }}
@ -45,6 +49,6 @@ jobs:
USER_KEY: ${{ secrets.SMOKE_TEST_ADMIN_USER }}
USER_SECRET: ${{ secrets.SMOKE_TEST_ADMIN_PASSWORD }}
run: |
npx wc-e2e test:e2e ./tests/e2e/specs/smoke-tests/update-woocommerce.js
npx wc-e2e test:e2e
npx wc-api-tests test api
pnpx wc-e2e test:e2e plugins/woocommerce/tests/e2e/specs/smoke-tests/update-woocommerce.js
pnpx wc-e2e test:e2e
pnpx wc-api-tests test api

View File

@ -18,16 +18,20 @@ jobs:
- name: Checkout code.
uses: actions/checkout@v2
with:
path: package/woocommerce
ref: trunk
- name: Install prerequisites.
working-directory: package/woocommerce/plugins/woocommerce
run: |
npm install
npm install -g pnpm
pnpm install
composer install --no-dev
npm run build:assets
npm install jest
pnpm run build:assets
pnpm install jest
- name: Run smoke test.
working-directory: package/woocommerce/plugins/woocommerce
env:
SMOKE_TEST_URL: ${{ secrets.RELEASE_TEST_URL }}
SMOKE_TEST_ADMIN_USER: ${{ secrets.RELEASE_TEST_ADMIN_USER }}
@ -46,9 +50,9 @@ jobs:
USER_KEY: ${{ secrets.RELEASE_TEST_ADMIN_USER }}
USER_SECRET: ${{ secrets.RELEASE_TEST_ADMIN_PASSWORD }}
run: |
npx wc-e2e test:e2e ./tests/e2e/specs/smoke-tests/update-woocommerce.js
npx wc-e2e test:e2e
npx wc-api-tests test api
pnpx wc-e2e test:e2e plugins/woocommerce/tests/e2e/specs/smoke-tests/update-woocommerce.js
pnpx wc-e2e test:e2e
pnpx wc-api-tests test api
test-wp-version:
name: Smoke test on L-${{ matrix.wp }} WordPress version
runs-on: ubuntu-18.04
@ -70,17 +74,18 @@ jobs:
path: package/woocommerce
- name: Run npm install.
working-directory: package/woocommerce
run: npm install
working-directory: package/woocommerce/plugins/woocommerce
npm install -g pnpm
pnpm install
- name: Load docker images and start containers.
working-directory: package/woocommerce
working-directory: package/woocommerce/plugins/woocommerce
env:
LATEST_WP_VERSION_MINUS: ${{ matrix.wp }}
run: npx wc-e2e docker:up
run: pnpx wc-e2e docker:up
- name: Move current directory to code. We will install zip file in this dir later.
run: mv ./package/woocommerce/* ./code/woocommerce
run: mv ./package/woocommerce/plugins/woocommerce/* ./code/woocommerce
- name: Download WooCommerce release zip
working-directory: tmp
@ -90,12 +95,12 @@ jobs:
curl https://api.github.com/repos/woocommerce/woocommerce/releases/assets/${ASSET_ID} -LJOH 'Accept: application/octet-stream'
unzip woocommerce.zip -d woocommerce
mv woocommerce/* ../package/woocommerce/
mv woocommerce/woocommerce/* ../package/woocommerce/plugins/woocommerce/
- name: Run tests command.
working-directory: code/woocommerce
working-directory: package/woocommerce/plugins/woocommerce
env:
WC_E2E_SCREENSHOTS: 1
E2E_SLACK_TOKEN: ${{ secrets.SMOKE_TEST_SLACK_TOKEN }}
E2E_SLACK_CHANNEL: ${{ secrets.RELEASE_TEST_SLACK_CHANNEL }}
run: npx wc-e2e test:e2e
run: pnpx wc-e2e test:e2e

View File

@ -1,9 +1,13 @@
== Changelog ==
= 5.9.0 beta 2021-10-19 =
= 5.9.0 2021-11-09 =
**WooCommerce**
* Fix - Bug in the handling of remote file names for downloadable files.
* Fix - Remove the absolute path to the currency-info.php from within locale-info.php. #31036
* Fix - wc_get_price_excluding_tax when an order with no customer is passed. #31015
* Fix - Rename transient used to cache data for Featured page of In-App Marketplace. #31002
* Fix - Variable product price caching bug with VAT exemption. #30889
* Fix - Allow to pass null as the email for billing addresses in REST API. #30850
* Fix - Ensure woocommerce_cancel_unpaid_orders event is always re-scheduled. #30830
@ -13,13 +17,16 @@
* Dev - Add mobile data to WCTracker. #30415
* Tweak - Remove hardcode category banners in Settings > Marketplace and use the WooCommerce.com API instead. #30938
* Tweak - Show a search again message when marketplace results are empty. #30642
* Tweak - Add promoted cards styling to marketplace section. #30861
* Enhancement - Add ratings, reviews and icons into Marketplace's Product Cards. #30840
* Enhancement - Update Storefront banner width and track links in the marketplace page. #30882
* Enhancement - Revamp the WooCommerce Marketplace page. #30900
**WooCommerce Admin - 2.8.0 RC 2**
**WooCommerce Admin - 2.8.0 **
* Add - Store Profiler and Product task - include Subscriptions. #7734
* Fix - Issue where stock activity panel was not rendering correctly. #7817
* Fix - Increase CSS specificity to avoid conflicts and broken panel styling. #7813
* Fix - Updated link to WooCommerce Developers Blog in readme.txt. #7824
* Fix - Fixed navigation menu text color after Gutenberg 11.6.0. #7771
* Fix - Add status param to notes/delete/all REST endpoint, to correctly delete all notes. #7743
* Fix - Allow already installed marketing extensions to be activated. #7740
@ -29,9 +36,12 @@
* Fix - Fixing an unwanted page refresh when using Woo Navigation. #7615
* Fix - Fix naming of event names and properties. #7677
* Fix - Fix white screen for variation analytic data without a name. #7686
* Add - Store Profiler and Product task - include Subscriptions. #7734
* Update - Update WC pay supported country list for the default free extensions. #7873
* Update - Update back up copy of free extension for Google Listing & Ads plugin. #7798
* Update - Update Eway payment gateway capitalization (was eWAY). #7678
* Update - Enable Square in France. #7679
* Enhancement - Only load tasks during rest api requests. #7856
* Enhancement - Add experiment for promoting WooCommerce Payments in payment methods table. #7666
**WooCommerce Blocks - 6.0.0 & 6.0.1 & 6.0.2 & 6.1.0**

View File

@ -6,7 +6,7 @@
* https://woocommerce.github.io/woocommerce-rest-api-docs/#order-refund-properties
*
*/
const refund = {
const refund = {
api_refund: false,
amount: '1.00',
reason: 'Late delivery refund.',

View File

@ -0,0 +1,60 @@
/**
* Internal dependencies
*/
const {
getRequest,
postRequest,
deleteRequest,
} = require( '../utils/request' );
/**
* WooCommerce Refunds endpoints.
*
* https://woocommerce.github.io/woocommerce-rest-api-docs/#refunds
*/
const refundsApi = {
name: 'Refunds',
create: {
name: 'Create a refund',
method: 'POST',
path: 'orders/<id>/refunds',
responseCode: 201,
refund: async ( orderId, refundDetails ) =>
postRequest( `orders/${ orderId }/refunds`, refundDetails ),
},
retrieve: {
name: 'Retrieve a refund',
method: 'GET',
path: 'orders/<id>/refunds/<refund_id>',
responseCode: 200,
refund: async ( orderId, refundId ) =>
getRequest( `orders/${ orderId }/refunds/${ refundId }` ),
},
listAll: {
name: 'List all refunds',
method: 'GET',
path: 'orders/<id>/refunds',
responseCode: 200,
refunds: async ( orderId ) =>
getRequest( `orders/${ orderId }/refunds` ),
},
delete: {
name: 'Delete a refund',
method: 'DELETE',
path: 'orders/<id>/refunds/<refund_id>',
responseCode: 200,
payload: {
force: false,
},
refund: async ( orderId, refundId, deletePermanently ) =>
deleteRequest(
`orders/${ orderId }/refunds/${ refundId }`,
deletePermanently
),
},
};
module.exports = {
refundsApi: refundsApi,
};

View File

@ -0,0 +1,122 @@
const { refundsApi } = require( '../../endpoints/refunds' );
const { ordersApi } = require( '../../endpoints/orders' );
const { productsApi } = require( '../../endpoints/products' );
const { refund } = require( '../../data' );
/**
* Tests for the WooCommerce Refunds API.
*
* @group api
* @group refunds
*
*/
describe( 'Refunds API tests', () => {
let expectedRefund;
let orderId;
let productId;
beforeAll( async () => {
// Create a product and save its product ID
const product = {
name: 'Simple Product for Refunds API tests',
regular_price: '100',
};
const createProductResponse = await productsApi.create.product(
product
);
productId = createProductResponse.body.id;
// Create an order with a product line item, and save its Order ID
const order = {
status: 'pending',
line_items: [
{
product_id: productId,
},
],
};
const createOrderResponse = await ordersApi.create.order( order );
orderId = createOrderResponse.body.id;
// Setup the expected refund object
expectedRefund = {
...refund,
line_items: [
{
product_id: productId,
},
],
};
} );
afterAll( async () => {
// Cleanup the created product and order
await productsApi.delete.product( productId, true );
await ordersApi.delete.order( orderId, true );
} );
it( 'can create a refund', async () => {
const { status, body } = await refundsApi.create.refund(
orderId,
expectedRefund
);
expect( status ).toEqual( refundsApi.create.responseCode );
expect( body.id ).toBeDefined();
// Save the refund ID
expectedRefund.id = body.id;
// Verify that the order was refunded.
const getOrderResponse = await ordersApi.retrieve.order( orderId );
expect( getOrderResponse.body.refunds ).toHaveLength( 1 );
expect( getOrderResponse.body.refunds[ 0 ].id ).toEqual(
expectedRefund.id
);
expect( getOrderResponse.body.refunds[ 0 ].reason ).toEqual(
expectedRefund.reason
);
expect( getOrderResponse.body.refunds[ 0 ].total ).toEqual(
`-${ expectedRefund.amount }`
);
} );
it( 'can retrieve a refund', async () => {
const { status, body } = await refundsApi.retrieve.refund(
orderId,
expectedRefund.id
);
expect( status ).toEqual( refundsApi.retrieve.responseCode );
expect( body.id ).toEqual( expectedRefund.id );
} );
it( 'can list all refunds', async () => {
const { status, body } = await refundsApi.listAll.refunds( orderId );
expect( status ).toEqual( refundsApi.listAll.responseCode );
expect( body ).toHaveLength( 1 );
expect( body[ 0 ].id ).toEqual( expectedRefund.id );
} );
it( 'can delete a refund', async () => {
const { status, body } = await refundsApi.delete.refund(
orderId,
expectedRefund.id,
true
);
expect( status ).toEqual( refundsApi.delete.responseCode );
expect( body.id ).toEqual( expectedRefund.id );
// Verify that the refund cannot be retrieved
const retrieveRefundResponse = await refundsApi.retrieve.refund(
orderId,
expectedRefund.id
);
expect( retrieveRefundResponse.status ).toEqual( 404 );
// Verify that the order no longer has a refund
const retrieveOrderResponse = await ordersApi.retrieve.order( orderId );
expect( retrieveOrderResponse.body.refunds ).toHaveLength( 0 );
} );
} );

View File

@ -16,7 +16,7 @@ This package contains the automated end-to-end tests for WooCommerce.
### Setting up the test environment
Follow [E2E setup instructions](https://github.com/woocommerce/woocommerce/blob/trunk/tests/e2e/README.md).
Follow [E2E setup instructions](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/e2e/README.md).
### Setting up core tests

View File

@ -2,7 +2,7 @@
"name": "@woocommerce/e2e-core-tests",
"version": "0.1.6",
"description": "End-To-End (E2E) tests for WooCommerce",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/core-tests/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-core-tests/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce.git"

View File

@ -12,7 +12,7 @@ const getCoreTestsRoot = require( '../../core-tests-root' );
/**
* External dependencies
*/
const { it, describe, beforeAll } = require( '@jest/globals' );
const { it, describe, beforeAll, afterAll } = require( '@jest/globals' );
const path = require( 'path' );
const coreTestsPath = getCoreTestsRoot();
@ -103,6 +103,15 @@ const runImportProductsTest = () => {
await merchant.openAllProductsView();
await merchant.openImportProducts();
} );
afterAll(async () => {
// Delete imported products
await withRestApi.deleteAllProducts();
await withRestApi.deleteAllProductAttributes();
await withRestApi.deleteAllProductCategories();
await withRestApi.deleteAllProductTags();
});
it( 'should show error message if you go without providing CSV file', async () => {
// Verify the error message if you go without providing CSV file
await Promise.all( [
@ -212,9 +221,6 @@ const runImportProductsTest = () => {
expect( productPrices.sort() ).toEqual(
productPricesOverride.sort()
);
// Delete imported products
await withRestApi.deleteAllProducts();
} );
} );
};

View File

@ -1,7 +1,7 @@
/**
* Internal dependencies
*/
const { merchant } = require('@woocommerce/e2e-utils');
const { merchant, withRestApi } = require('@woocommerce/e2e-utils');
const { lorem, helpers } = require('faker');
const runAddShippingClassesTest = () => {
@ -13,6 +13,10 @@ const runAddShippingClassesTest = () => {
await merchant.openSettings('shipping', 'classes');
});
afterAll(async () => {
await withRestApi.deleteAllShippingClasses();
});
it('can add shipping classes', async () => {
const shippingClassSlug = {
name: lorem.words(),

View File

@ -5,6 +5,10 @@
- Added quotes around `WORDPRESS_TITLE` value in .env file to address issue with docker compose 2 "key cannot contain a space" error.
- Added `LATEST_WP_VERSION_MINUS` that allows setting a number to subtract from the current WordPress version for the WordPress Docker image.
## Fixed
- Use consistent `defaultViewport` in both headless and non-headless context
# 0.2.3
## Added

View File

@ -104,7 +104,7 @@ For a list of the methods that the above timeout affects, please see the Puppete
### Test Against Previous WordPress Versions
You can use the `LATEST_WP_VERSION_MINUS` flag to determine how many versions back from the current WordPress version to use in the Docker environment. This is calculated from the current WordPress version minus the set value. For example, if `LATEST_WP_VERSION_MINUS` is set to 1, it will calculate the current WordPress version minus one, and use that for the WordPress Docker container.
You can use the `LATEST_WP_VERSION_MINUS` flag to determine how many versions back from the current WordPress version to use in the Docker environment. This is calculated from the current WordPress version minus the set value. For example, if `LATEST_WP_VERSION_MINUS` is set to 1, it will calculate the current WordPress version minus one, and use that for the WordPress Docker container.
For example, you could run the following command:
@ -163,7 +163,7 @@ Jest provides [setup and teardown functions](https://jestjs.io/docs/setup-teardo
#### Console filtering
**Added version 0.2.3**
By default, messages logged to the console are included in the test results. The test runner suppresses 404 not found and proxy connection messages.
By default, messages logged to the console are included in the test results. The test runner suppresses 404 not found and proxy connection messages.
Pages that you are testing may contain repetitive console output that you expect. Use `addConsoleSuppression` in your jest setup script to filter these repetitive messages:
@ -182,8 +182,8 @@ removeConsoleSuppression( 'suppress this after the first instance' );
Depending on the project and testing scenario, the built in testing environment container might not be the best solution for testing. This could be local testing where there is already a testing container, a repository that isn't a plugin or theme and there are multiple folders mapped into the container, or similar. The `e2e-environment` test runner supports using either the built in container or an external container. See the appropriate readme for details:
- [Built In Container](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env/builtin.md)
- [External Container](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env/external.md)
- [Built In Container](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-environment/builtin.md)
- [External Container](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-environment/external.md)
### Slackbot Setup
@ -233,4 +233,4 @@ This will return a string with the latest release URL. Optionally, you can use t
## Additional information
Refer to [`tests/e2e/core-tests`](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/core-tests) for some test examples, and [`tests/e2e`](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e) for general information on e2e tests.
Refer to [`@woocommerce/e2e-core-tests`](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-core-tests) for some test examples, and [`plugins/woocommerce/tests/e2e`](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e) for general information on e2e tests.

View File

@ -8,6 +8,10 @@ if ( 'no' == global.process.env.node_config_dev ) {
launch: {
// Required for the logged out and logged in tests so they don't share app state/token.
browserContext: 'incognito',
defaultViewport: {
width: 1280,
height: 800,
},
},
};
} else {

View File

@ -5,6 +5,8 @@
- `utils.waitForTimeout( delay )` pause processing for `delay` milliseconds
- `AdminEdit` class with utility functions for the respective edit screens
- Update `shopper.addToCartFromShopPage()` and `.removeFromCart()` to accept product Id or Title
- Added `deleteAllProductAttributes()`, `deleteAllProductCategories()`, and `deleteAllProductTags()` to clean up meta data added when products are imported
- Added `withRestApi.createProductCategory()` that creates a product category and returns the ID
# 0.1.6

View File

@ -1,4 +1,4 @@
# WooCommerce End to End Test Utilities
# WooCommerce End to End Test Utilities
This package contains utilities to simplify writing e2e tests specific to WooCommmerce.
@ -46,7 +46,7 @@ This package provides support for enabling retries in tests:
- `WP_ADMIN_DASHBOARD` - WordPress dashboard
- `WP_ADMIN_WP_UPDATES` - WordPress updates
- `WP_ADMIN_PLUGINS` - Plugin list
- `WP_ADMIN_PERMALINK_SETTINGS` - Permalink settings
- `WP_ADMIN_PERMALINK_SETTINGS` - Permalink settings
- `WP_ADMIN_ALL_USERS_VIEW` - WordPress user list
- `WP_ADMIN_POST_TYPE` - Post listing
- `WP_ADMIN_NEW_POST_TYPE` - New post
@ -69,7 +69,7 @@ This package provides support for enabling retries in tests:
#### Front end
- `SHOP_PAGE` - Shop page
- `SHOP_PRODUCT_PAGE` - Single product page
- `SHOP_PRODUCT_PAGE` - Single product page
- `SHOP_CART_PAGE` - Cart page
- `SHOP_CHECKOUT_PAGE` - Checkout page
- `SHOP_MY_ACCOUNT_PAGE` - Customer account page
@ -105,10 +105,10 @@ This package provides support for enabling retries in tests:
| `openImportProducts` | | Open the Import Products page |
| `openExtensions` | | Go to WooCommerce -> Extensions |
| `openWordPressUpdatesPage` | | Go to Dashboard -> Updates |
| `installAllUpdates` | | Install all pending updates on Dashboard -> Updates|
| `updateWordPress` | | Install pending WordPress updates on Dashboard -> Updates|
| `updatePlugins` | | Install all pending plugin updates on Dashboard -> Updates|
| `updateThemes` | | Install all pending theme updates on Dashboard -> Updates|
| `installAllUpdates` | | Install all pending updates on Dashboard -> Updates|
| `updateWordPress` | | Install pending WordPress updates on Dashboard -> Updates|
| `updatePlugins` | | Install all pending plugin updates on Dashboard -> Updates|
| `updateThemes` | | Install all pending theme updates on Dashboard -> Updates|
| `runDatabaseUpdate` || Runs the database update if needed |
### Shopper `shopper`
@ -138,6 +138,8 @@ This package provides support for enabling retries in tests:
### REST API `withRestApi`
Please note: if you're using a non-SSL environment (such as a Docker container from [`wc-e2e`](https://www.npmjs.com/package/@woocommerce/e2e-environment)) you will need to use Basic Auth in order to authenticate with the API and use the `withRestApi` methods listed below. To do so, you will need to install the [the Basic Auth plugin](https://github.com/WP-API/Basic-Auth). One way this can be accomplished is by adding `wp plugin install https://github.com/WP-API/Basic-Auth/archive/master.zip --activate` to your `initialize.sh` script.
| Function | Parameters | Description |
|----------|------------|-------------|
| `resetOnboarding` | | Reset onboarding settings |
@ -151,7 +153,11 @@ This package provides support for enabling retries in tests:
| `deleteAllOrders` | | Permanently delete all orders |
| `updateSettingOption` | `settingsGroup`, `settingID`, `payload` | Update a settings group |
| `updatePaymentGateway`| `paymentGatewayId`, `payload` | Update a payment gateway |
| `getSystemEnvironment` | | Get the current environment from the WooCommerce system status API.
| `getSystemEnvironment` | | Get the current environment from the WooCommerce system status API. |
| `deleteAllProductAttributes` | | Permanently delete all product attributes. |
| `deleteAllProductCategories` | | Permanently delete all product categories. |
| `deleteAllProductTags` | | Permanently delete all product tags. |
| `createProductCategory` | `categoryName` | Create a product category with the provided name. |
### Classes

View File

@ -2,7 +2,7 @@
"name": "@woocommerce/e2e-utils",
"version": "0.1.6",
"description": "End-To-End (E2E) test utils for WooCommerce",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/utils/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-utils/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce.git"

View File

@ -17,6 +17,7 @@ import {
} from './page-utils';
import factories from './factories';
import { waitForTimeout } from './flows/utils';
import { withRestApi } from './flows/with-rest-api';
import { Coupon, Order } from '@woocommerce/api';
const client = factories.api.withDefaultPermalinks;
@ -208,12 +209,15 @@ const createSimpleProduct = async ( productTitle = simpleProductName, productPri
* @param categoryName Product's category which can be changed when writing a test
*/
const createSimpleProductWithCategory = async ( productName, productPrice, categoryName ) => {
// Get the category ID so we can add it to the product below
const categoryId = await withRestApi.createProductCategory( categoryName );
const product = await factories.products.simple.create( {
name: productName,
regularPrice: productPrice,
categories: [
{
name: categoryName,
id: categoryId,
}
],
isVirtual: true,

View File

@ -1,4 +1,5 @@
import factories from '../factories';
import { getSlug } from './utils';
import {Coupon, Setting, SimpleProduct, Order} from '@woocommerce/api';
const client = factories.api.withDefaultPermalinks;
@ -7,6 +8,8 @@ const shippingZoneEndpoint = '/wc/v3/shipping/zones';
const shippingClassesEndpoint = '/wc/v3/products/shipping_classes';
const userEndpoint = '/wp/v2/users';
const systemStatusEndpoint = '/wc/v3/system_status';
const productsEndpoint = '/wc/v3/products';
const productCategoriesEndpoint = '/wc/v3/products/categories';
/**
* Utility function to delete all merchant created data store objects.
@ -83,6 +86,55 @@ export const withRestApi = {
const repository = SimpleProduct.restRepository( client );
await deleteAllRepositoryObjects( repository );
},
/**
* Use the API to delete all product attributes.
*
* @return {Promise} Promise resolving once attributes have been deleted.
*/
deleteAllProductAttributes: async () => {
const productAttributesPath = productsEndpoint + '/attributes';
const productAttributes = await client.get( productAttributesPath );
if ( productAttributes.data && productAttributes.data.length ) {
for ( let a = 0; a < productAttributes.data.length; a++ ) {
const response = await client.delete( productAttributesPath + `/${productAttributes.data[a].id}?force=true` );
expect( response.status ).toBe( 200 );
}
}
},
/**
* Use the API to delete all product categories.
*
* @return {Promise} Promise resolving once categories have been deleted.
*/
deleteAllProductCategories: async () => {
const productCategoriesPath = productsEndpoint + '/categories';
const productCategories = await client.get( productCategoriesPath );
if ( productCategories.data && productCategories.data.length ) {
for ( let c = 0; c < productCategories.data.length; c++ ) {
// The default `uncategorized` category can't be deleted
if ( productCategories.data[c].id == 0 ) {
continue;
}
const response = await client.delete( productCategoriesPath + `/${productCategories.data[c].id}?force=true` );
expect( response.status ).toBe( 200 );
}
}
},
/**
* Use the API to delete all product tags.
*
* @return {Promise} Promise resolving once tags have been deleted.
*/
deleteAllProductTags: async () => {
const productTagsPath = productsEndpoint + '/tags';
const productTags = await client.get( productTagsPath );
if ( productTags.data && productTags.data.length ) {
for ( let t = 0; t < productTags.data.length; t++ ) {
const response = await client.delete( productTagsPath + `/${productTags.data[t].id}?force=true` );
expect( response.status ).toBe( 200 );
}
}
},
/**
* Use api package to delete all orders.
*
@ -300,5 +352,36 @@ export const withRestApi = {
} else {
return;
}
}
},
/**
* Create a product category and return the ID. If the category already exists, the ID of the existing category is returned.
*
* @param {string} categoryName The name of the category to create
* @return {Promise<number>} The ID of the category.
*/
createProductCategory: async ( categoryName ) => {
const payload = { name: categoryName };
let categoryId;
// First, convert the name to slug for easier searching
const categorySlug = getSlug( categoryName );
const category = await client.get(
`${ productCategoriesEndpoint }?slug=${ categorySlug }`
);
// If the length is 0, nothing was found, so create the category
if ( category.data ) {
// If the length is 0, no existing category was found, so create the category
if ( category.data.length === 0 ) {
const response = await client.post(
productCategoriesEndpoint,
payload
);
categoryId = response.data.id;
} else {
categoryId = category.data[ 0 ].id;
}
}
return categoryId;
},
};

View File

@ -816,7 +816,7 @@ jQuery( function ( $ ) {
window.wcTracks.recordEvent( 'order_edit_recalc_totals', {
order_id: data.post_id,
OK_cancel: 'OK',
ok_cancel: 'OK',
status: $( '#order_status' ).val()
} );
}
@ -824,7 +824,7 @@ jQuery( function ( $ ) {
} else {
window.wcTracks.recordEvent( 'order_edit_recalc_totals', {
order_id: woocommerce_admin_meta_boxes.post_id,
OK_cancel: 'cancel',
ok_cancel: 'cancel',
status: $( '#order_status' ).val()
} );
}

View File

@ -21,7 +21,7 @@
"pelago/emogrifier": "3.1.0",
"psr/container": "1.0.0",
"woocommerce/action-scheduler": "3.3.0",
"woocommerce/woocommerce-admin": "2.8.0-rc.2",
"woocommerce/woocommerce-admin": "2.8.0",
"woocommerce/woocommerce-blocks": "6.1.0"
},
"require-dev": {

View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "fb2d2b34aa7845cd6d39a187b7c53753",
"content-hash": "2850714f99d072cbc80188fd4b56630f",
"packages": [
{
"name": "automattic/jetpack-autoloader",
@ -533,16 +533,16 @@
},
{
"name": "woocommerce/woocommerce-admin",
"version": "2.8.0-rc.2",
"version": "2.8.0",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
"reference": "f3974919906d4d2168531025340b4f139ae65f1d"
"reference": "63b93a95db4bf788f42587a41f2378128a2adfdf"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/f3974919906d4d2168531025340b4f139ae65f1d",
"reference": "f3974919906d4d2168531025340b4f139ae65f1d",
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/63b93a95db4bf788f42587a41f2378128a2adfdf",
"reference": "63b93a95db4bf788f42587a41f2378128a2adfdf",
"shasum": ""
},
"require": {
@ -598,9 +598,9 @@
"homepage": "https://github.com/woocommerce/woocommerce-admin",
"support": {
"issues": "https://github.com/woocommerce/woocommerce-admin/issues",
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.8.0-rc.2"
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.8.0"
},
"time": "2021-10-15T00:51:46+00:00"
"time": "2021-11-02T19:28:38+00:00"
},
{
"name": "woocommerce/woocommerce-blocks",
@ -2459,5 +2459,5 @@
"platform-overrides": {
"php": "7.0"
},
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.0.0"
}

View File

@ -262,16 +262,17 @@ class WC_Download_Handler {
* via filters we can still do the string replacement on a HTTP file.
*/
$replacements = array(
$wp_uploads_url => $wp_uploads_dir,
network_site_url( '/', 'https' ) => ABSPATH,
$wp_uploads_url => $wp_uploads_dir,
network_site_url( '/', 'https' ) => ABSPATH,
str_replace( 'https:', 'http:', network_site_url( '/', 'http' ) ) => ABSPATH,
site_url( '/', 'https' ) => ABSPATH,
str_replace( 'https:', 'http:', site_url( '/', 'http' ) ) => ABSPATH,
site_url( '/', 'https' ) => ABSPATH,
str_replace( 'https:', 'http:', site_url( '/', 'http' ) ) => ABSPATH,
);
$count = 0;
$file_path = str_replace( array_keys( $replacements ), array_values( $replacements ), $file_path );
$parsed_file_path = wp_parse_url( $file_path );
$remote_file = true;
$remote_file = null === $count || 0 === $count; // Remote file only if there were no replacements.
// Paths that begin with '//' are always remote URLs.
if ( '//' === substr( $file_path, 0, 2 ) ) {
@ -291,7 +292,7 @@ class WC_Download_Handler {
$file_path = realpath( WP_CONTENT_DIR . substr( $file_path, 11 ) );
// Check if we have an absolute path.
} elseif ( ( ! isset( $parsed_file_path['scheme'] ) || ! in_array( $parsed_file_path['scheme'], array( 'http', 'https', 'ftp' ), true ) ) && isset( $parsed_file_path['path'] ) && file_exists( $parsed_file_path['path'] ) ) {
} elseif ( ( ! isset( $parsed_file_path['scheme'] ) || ! in_array( $parsed_file_path['scheme'], array( 'http', 'https', 'ftp' ), true ) ) && isset( $parsed_file_path['path'] ) ) {
$remote_file = false;
$file_path = $parsed_file_path['path'];
}

View File

@ -7,6 +7,8 @@
* @since 3.0.0
*/
use Automattic\Jetpack\Constants;
defined( 'ABSPATH' ) || exit;
/**
@ -98,18 +100,28 @@ class WC_Product_Download implements ArrayAccess {
$file_path = $this->get_file();
// File types for URL-based files located on the server should get validated.
$is_file_on_server = false;
if ( false !== stripos( $file_path, network_site_url( '/', 'https' ) ) ||
false !== stripos( $file_path, network_site_url( '/', 'http' ) ) ||
false !== stripos( $file_path, site_url( '/', 'https' ) ) ||
false !== stripos( $file_path, site_url( '/', 'http' ) )
) {
$is_file_on_server = true;
}
$parsed_file_path = WC_Download_Handler::parse_file_path( $file_path );
$is_file_on_server = ! $parsed_file_path['remote_file'];
$file_path_type = $this->get_type_of_file_path( $file_path );
if ( ! $is_file_on_server && 'relative' !== $this->get_type_of_file_path() ) {
// Shortcodes are allowed, validations should be done by the shortcode provider in this case.
if ( 'shortcode' === $file_path_type ) {
return true;
}
// Remote paths are allowed.
if ( ! $is_file_on_server && 'relative' !== $file_path_type ) {
return true;
}
// On windows system, local files ending with `.` are not allowed.
// @link https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#naming-conventions.
if ( $is_file_on_server && ! $this->get_file_extension() && 'WIN' === strtoupper( substr( Constants::get_constant( 'PHP_OS' ), 0, 3 ) ) ) {
if ( '.' === substr( $file_path, -1 ) ) {
return false;
}
}
return ! $this->get_file_extension() || in_array( $this->get_file_type(), $this->get_allowed_mime_types(), true );
}

View File

@ -107,9 +107,17 @@ class WC_Template_Loader {
return false;
}
return is_readable(
get_stylesheet_directory() . '/block-templates/' . $template_name . '.html'
);
$has_template = is_readable( get_stylesheet_directory() . '/block-templates/' . $template_name . '.html' );
/**
* Filters the value of the result of the block template check.
*
* @since x.x.x
*
* @param boolean $has_template value to be filtered.
* @param string $template_name The name of the template.
*/
return (bool) apply_filters( 'woocommerce_has_block_template', $has_template, $template_name );
}
/**

View File

@ -730,7 +730,7 @@ function get_woocommerce_currency_symbols() {
'ILS' => '&#8362;',
'IMP' => '&pound;',
'INR' => '&#8377;',
'IQD' => '&#x639;.&#x62f;',
'IQD' => '&#x62f;.&#x639;',
'IRR' => '&#xfdfc;',
'IRT' => '&#x062A;&#x0648;&#x0645;&#x0627;&#x0646;',
'ISK' => 'kr.',

View File

@ -1083,12 +1083,16 @@ function wc_get_price_excluding_tax( $product, $args = array() ) {
$line_price = $price * $qty;
if ( $product->is_taxable() && wc_prices_include_tax() ) {
$order = ArrayUtil::get_value_or_default( $args, 'order' );
$customer = $order ? wc_get_container()->get( LegacyProxy::class )->get_instance_of( WC_Customer::class, $order->get_customer_id() ) : null;
$tax_rates = WC_Tax::get_rates( $product->get_tax_class(), $customer );
$base_tax_rates = WC_Tax::get_base_tax_rates( $product->get_tax_class( 'unfiltered' ) );
$remove_taxes = apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ? WC_Tax::calc_tax( $line_price, $base_tax_rates, true ) : WC_Tax::calc_tax( $line_price, $tax_rates, true );
$return_price = $line_price - array_sum( $remove_taxes ); // Unrounded since we're dealing with tax inclusive prices. Matches logic in cart-totals class. @see adjust_non_base_location_price.
$order = ArrayUtil::get_value_or_default( $args, 'order' );
$customer_id = $order ? $order->get_customer_id() : 0;
if ( apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) || ! $customer_id ) {
$tax_rates = WC_Tax::get_base_tax_rates( $product->get_tax_class( 'unfiltered' ) );
} else {
$customer = wc_get_container()->get( LegacyProxy::class )->get_instance_of( WC_Customer::class, $customer_id );
$tax_rates = WC_Tax::get_rates( $product->get_tax_class(), $customer );
}
$remove_taxes = WC_Tax::calc_tax( $line_price, $tax_rates, true );
$return_price = $line_price - array_sum( $remove_taxes ); // Unrounded since we're dealing with tax inclusive prices. Matches logic in cart-totals class. @see adjust_non_base_location_price.
} else {
$return_price = $line_price;
}

View File

@ -4,7 +4,7 @@ Tags: e-commerce, store, sales, sell, woo, shop, cart, checkout, downloadable, d
Requires at least: 5.6
Tested up to: 5.8
Requires PHP: 7.0
Stable tag: 5.8.0
Stable tag: 5.9.0
License: GPLv3
License URI: https://www.gnu.org/licenses/gpl-3.0.html
@ -140,7 +140,7 @@ Visit the [WooCommerce server requirements documentation](https://docs.woocommer
= Automatic installation =
Automatic installation is the easiest option -- WordPress will handles the file transfer, and you wont need to leave your web browser. To do an automatic install of WooCommerce, log in to your WordPress dashboard, navigate to the Plugins menu, and click “Add New.”
Automatic installation is the easiest option -- WordPress will handle the file transfer, and you wont need to leave your web browser. To do an automatic install of WooCommerce, log in to your WordPress dashboard, navigate to the Plugins menu, and click “Add New.”
In the search field type “WooCommerce,” then click “Search Plugins.” Once youve found us, you can view details about it such as the point release, rating, and description. Most importantly of course, you can install it by! Click “Install Now,” and WordPress will take it from there.
@ -160,10 +160,14 @@ WooCommerce comes with some sample data you can use to see how products look; im
== Changelog ==
= 5.9.0 beta 2021-10-19 =
= 5.9.0 2021-11-09 =
**WooCommerce**
* Fix - Bug in the handling of remote file names for downloadable files.
* Fix - Remove the absolute path to the currency-info.php from within locale-info.php. #31036
* Fix - wc_get_price_excluding_tax when an order with no customer is passed. #31015
* Fix - Rename transient used to cache data for Featured page of In-App Marketplace. #31002
* Fix - Variable product price caching bug with VAT exemption. #30889
* Fix - Allow to pass null as the email for billing addresses in REST API. #30850
* Fix - Ensure woocommerce_cancel_unpaid_orders event is always re-scheduled. #30830
@ -173,13 +177,16 @@ WooCommerce comes with some sample data you can use to see how products look; im
* Dev - Add mobile data to WCTracker. #30415
* Tweak - Remove hardcode category banners in Settings > Marketplace and use the WooCommerce.com API instead. #30938
* Tweak - Show a search again message when marketplace results are empty. #30642
* Tweak - Add promoted cards styling to marketplace section. #30861
* Enhancement - Add ratings, reviews and icons into Marketplace's Product Cards. #30840
* Enhancement - Update Storefront banner width and track links in the marketplace page. #30882
* Enhancement - Revamp the WooCommerce Marketplace page. #30900
**WooCommerce Admin - 2.8.0 RC 2**
**WooCommerce Admin - 2.8.0 **
* Add - Store Profiler and Product task - include Subscriptions. #7734
* Fix - Issue where stock activity panel was not rendering correctly. #7817
* Fix - Increase CSS specificity to avoid conflicts and broken panel styling. #7813
* Fix - Updated link to WooCommerce Developers Blog in readme.txt. #7824
* Fix - Fixed navigation menu text color after Gutenberg 11.6.0. #7771
* Fix - Add status param to notes/delete/all REST endpoint, to correctly delete all notes. #7743
* Fix - Allow already installed marketing extensions to be activated. #7740
@ -189,9 +196,12 @@ WooCommerce comes with some sample data you can use to see how products look; im
* Fix - Fixing an unwanted page refresh when using Woo Navigation. #7615
* Fix - Fix naming of event names and properties. #7677
* Fix - Fix white screen for variation analytic data without a name. #7686
* Add - Store Profiler and Product task - include Subscriptions. #7734
* Update - Update WC pay supported country list for the default free extensions. #7873
* Update - Update back up copy of free extension for Google Listing & Ads plugin. #7798
* Update - Update Eway payment gateway capitalization (was eWAY). #7678
* Update - Enable Square in France. #7679
* Enhancement - Only load tasks during rest api requests. #7856
* Enhancement - Add experiment for promoting WooCommerce Payments in payment methods table. #7666
**WooCommerce Blocks - 6.0.0 & 6.0.1 & 6.0.2 & 6.1.0**

View File

@ -52,6 +52,7 @@ do_action( 'woocommerce_before_add_to_cart_form' ); ?>
<?php endforeach; ?>
</tbody>
</table>
<?php do_action( 'woocommerce_after_variations_table' ); ?>
<div class="single_variation_wrap">
<?php

View File

@ -1,6 +1,6 @@
# WooCommerce Tests
This document discusses unit tests. See [the e2e README](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e) to learn how to setup testing environment for running e2e tests and run them.
This document discusses unit tests. See [the e2e README](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e) to learn how to setup testing environment for running e2e tests and run them.
## Table of contents
@ -25,7 +25,7 @@ To run the tests, you need to create a test database. You can:
- Access a database on a server
- Connect to your local database on your machine
- Use a solution like VVV - if you are using VVV you might need to `vagrant ssh` first
- Run a throwaway database in docker with this one-liner: `docker run --rm --name woocommerce_test_db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=woocommerce_test_password -d mysql:5.7.33`. ( Use `tests/bin/install.sh woocommerce_tests root woocommerce_test_password 0.0.0.0` in next step)
- Run a throwaway database in docker with this one-liner: `docker run --rm --name woocommerce_test_db -p 3306:3306 -e MYSQL_ROOT_PASSWORD=woocommerce_test_password -d mysql:5.7.33`. ( Use `tests/bin/install.sh woocommerce_tests root woocommerce_test_password 0.0.0.0` in next step)
### Setup instructions
@ -103,7 +103,7 @@ curl -L https://github.com/woocommerce/phpunit/archive/add-compatibility-with-ph
unzip -d /tmp/phpunit-7.5-fork /tmp/phpunit-7.5-fork.zip
composer bin phpunit config --unset platform
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
```
Just remember that you can't include the modified `composer.json` in any commit!
@ -123,7 +123,7 @@ Each test file should correspond to an associated source file and be named accor
* When testing functions: use one test file per functions group file, for example `wc-formatting-functions-test.php` for code in the `wc-formatting-functions.php` file.
See also [the guidelines for writing unit tests for `src` code](https://github.com/woocommerce/woocommerce/tree/trunk/src/README.md#writing-unit-tests) and [the guidelines for `includes` code](https://github.com/woocommerce/woocommerce/tree/trunk/includes/README.md#writing-unit-tests).
See also [the guidelines for writing unit tests for `src` code](https://github.com/woocommerce/woocommerce/tree/trunk/src/README.md#writing-unit-tests) and [the guidelines for `includes` code](https://github.com/woocommerce/woocommerce/tree/trunk/includes/README.md#writing-unit-tests).
General guidelines for all the unit tests:

View File

@ -97,6 +97,8 @@ Puppeteer will still automatically download Chromium when needed.
## Running tests
If you are using Windows, we recommend using [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/) for End-to-end testing. Follow the [WSL Setup Instructions](./WSL_SETUP_INSTRUCTIONS.md) first before proceeding with the steps below.
### Prep work for running tests
Run the following in a terminal/command line window
@ -351,8 +353,8 @@ FAIL ../specs/front-end/front-end-my-account.test.js (9.219s)
In the example above, you can see that `allows customer to see downloads` part of the test failed and can start looking at it right away. Without steps the test goes through being detailed, it is more difficult to debug it.
## Debugging tests
## Debugging tests
The test sequencer (`npx wc-e2e test:e2e`) includes support for saving [screenshots on test errors](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env#test-screenshots) which can be sent to a Slack channel via a [Slackbot](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env#slackbot-setup).
The test sequencer (`npx wc-e2e test:e2e`) includes support for saving [screenshots on test errors](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-environment#test-screenshots) which can be sent to a Slack channel via a [Slackbot](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/e2e-environment#slackbot-setup).
For Puppeteer debugging, follow [Google's documentation](https://developers.google.com/web/tools/puppeteer/debugging).
For Puppeteer debugging, follow [Google's documentation](https://developers.google.com/web/tools/puppeteer/debugging).

View File

@ -0,0 +1,58 @@
# Setup Instructions for Windows Subsystem for Linux (WSL)
You can set up a local development environment on Windows with [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/). The following instructions are for Ubuntu 20.04.
## Pre-requisites
You should have the following already set up on your Windows computer:
- **Docker Desktop for Windows** - https://docs.docker.com/docker-for-windows/install/
- **WSL 2** - https://docs.microsoft.com/en-us/windows/wsl/install
- **Ubuntu 20.04 set as default Linux distribution** - https://docs.microsoft.com/en-us/windows/wsl/wsl-config#list-installed-distributions
## Setup Steps
Update and upgrade packages.
```bash
sudo apt update -y && sudo apt upgrade -y
```
In order for Composer commands to work later on, you have to install the following:
- PHP
- Composer
- `php-xml`
- `php-mbstring`
```bash
sudo apt install php-cli unzip -y
cd ~
curl -sS https://getcomposer.org/installer -o composer-setup.php
HASH=`curl -sS https://composer.github.io/installer.sig`
echo $HASH
php -r "if (hash_file('SHA384', 'composer-setup.php') === '$HASH') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
sudo php composer-setup.php --install-dir=/usr/local/bin --filename=composer
composer --version --no-interaction # Verify that Composer installation was successful
sudo apt install php-xml -y
sudo apt install php-mbstring -y
```
For Puppeteer to run in headless mode you'll need to install additional packages:
```bash
sudo apt install -y ca-certificates fonts-liberation gconf-service libappindicator1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libcairo2 libcups2 libdbus-1-3 libexpat1 libfontconfig1 libgbm1 libgcc1 libgconf-2-4 libgdk-pixbuf2.0-0 libglib2.0-0 libgtk-3-0 libnspr4 libnss3 libpango-1.0-0 libpangocairo-1.0-0 libstdc++6 libx11-6 libx11-xcb1 libxcb1 libxcomposite1 libxcursor1 libxdamage1 libxext6 libxfixes3 libxi6 libxrandr2 libxrender1 libxss1 libxtst6 lsb-release wget xdg-utils
```
Add your username to the `docker` group to avoid having to type `sudo` when you run Docker commands.
```bash
sudo usermod -aG docker ${YOUR_USERNAME}
su - ${YOUR_USERNAME}
```
At this point, you're now ready to proceed with the steps in [Prep work for running tests](./README.md#prep-work-for-running-tests).

View File

@ -54,7 +54,7 @@ Alternatively the k6 docker image can be used to execute tests.
Before using the tests a test environment is needed to run against.
In the WooCommerce e2e tests there is a Docker Initialization Script [`init-sample-products.sh`](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/docker/init-sample-products.sh) that will set up a shop with sample products imported and the shop settings (payment method, permalinks, address etc) needed for the tests already set. It is recommended using this to just see the tests in action.
In the WooCommerce e2e tests there is a Docker Initialization Script [`init-sample-products.sh`](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e/docker/init-sample-products.sh) that will set up a shop with sample products imported and the shop settings (payment method, permalinks, address etc) needed for the tests already set. It is recommended using this to just see the tests in action.
`npx wc-e2e docker:up ./tests/e2e/docker/init-sample-products.sh`

View File

@ -0,0 +1,38 @@
<?php
/**
* Class WC_Product_Download_Test
*/
class WC_Product_Download_Test extends WC_Unit_Test_Case {
/**
* Test for file without extension.
*/
public function test_is_allowed_filetype_with_no_extension() {
$upload_dir = trailingslashit( wp_upload_dir()['basedir'] );
$file_path_with_no_extension = $upload_dir . 'upload_file';
if ( ! file_exists( $file_path_with_no_extension ) ) {
// Copy an existing file without extension.
$this->assertTrue( touch( $file_path_with_no_extension ), 'Unable to create file without extension.' );
}
$download = new WC_Product_Download();
$download->set_file( $file_path_with_no_extension );
$this->assertEquals( true, $download->is_allowed_filetype() );
}
/**
* Simulates test condition for windows when filename ends with a period.
*/
public function test_is_allowed_filetype_on_windows_with_period_at_end() {
$upload_dir = trailingslashit( wp_upload_dir()['basedir'] );
$file_path_with_period_at_end = $upload_dir . 'upload_file.';
if ( ! file_exists( $file_path_with_period_at_end ) ) {
// Copy an existing file without extension.
$this->assertTrue( touch( $file_path_with_period_at_end ), 'Unable to create file with period at the end.' );
}
\Automattic\Jetpack\Constants::set_constant( 'PHP_OS', 'winnt' );
$download = new WC_Product_Download();
$download->set_file( $file_path_with_period_at_end );
$this->assertEquals( false, $download->is_allowed_filetype() );
}
}

View File

@ -16,15 +16,26 @@ class WC_Product_Functions_Tests extends \WC_Unit_Test_Case {
/**
* @testdox If 'wc_get_price_excluding_tax' gets an order as argument, it passes the order customer to 'WC_Tax::get_rates'.
*
* @testWith [true]
* [false]
* @testWith [true, 1, true]
* [true, 1, false]
* [true, 0, true]
* [true, 0, false]
* [false, null, true]
* [false, null, false]
*
* @param bool $pass_order Whether an order is passed to 'wc_get_price_excluding_tax' or not.
* @param bool $pass_order Whether an order is passed to 'wc_get_price_excluding_tax' or not.
* @param int|null $customer_id Id of the customer associated to the order.
* @param bool $set_filter Whether the 'woocommerce_adjust_non_base_location_prices' filter should be set to return false.
*/
public function test_wc_get_price_excluding_tax_passes_order_customer_to_get_rates_if_order_is_available( $pass_order ) {
public function test_wc_get_price_excluding_tax_passes_order_customer_to_get_rates_if_order_is_available( $pass_order, $customer_id, $set_filter ) {
$customer_passed_to_get_rates = false;
$get_base_rates_invoked = false;
$customer_id_passed_to_wc_customer_constructor = false;
if ( $set_filter ) {
add_filter( 'woocommerce_adjust_non_base_location_prices', '__return_false' );
}
FunctionsMockerHack::add_function_mocks(
array(
'wc_prices_include_tax' => '__return_true',
@ -38,7 +49,8 @@ class WC_Product_Functions_Tests extends \WC_Unit_Test_Case {
'get_rates' => function( $tax_class, $customer ) use ( &$customer_passed_to_get_rates ) {
$customer_passed_to_get_rates = $customer;
},
'get_base_tax_rates' => function( $tax_class ) {
'get_base_tax_rates' => function( $tax_class ) use ( &$get_base_rates_invoked ) {
$get_base_rates_invoked = true;
return 0;
},
'calc_tax' => function( $price, $rates, $price_includes_tax = false, $deprecated = false ) {
@ -48,7 +60,7 @@ class WC_Product_Functions_Tests extends \WC_Unit_Test_Case {
)
);
// phpcs:disable Squiz.Commenting.FunctionComment.Missing
// phpcs:disable Squiz.Commenting
$product = new class() extends WC_Product {
public function get_price( $context = 'view' ) {
@ -75,23 +87,41 @@ class WC_Product_Functions_Tests extends \WC_Unit_Test_Case {
);
if ( $pass_order ) {
$order = new class() {
$order = new class( $customer_id ) {
private $customer_id;
public function __construct( $customer_id ) {
$this->customer_id = $customer_id;
}
public function get_customer_id() {
return 1;
return $this->customer_id;
}
};
wc_get_price_excluding_tax( $product, array( 'order' => $order ) );
$this->assertEquals( $order->get_customer_id(), $customer_id_passed_to_wc_customer_constructor );
$this->assertSame( $customer, $customer_passed_to_get_rates );
if ( $customer_id && $set_filter ) {
$this->assertEquals( $order->get_customer_id(), $customer_id_passed_to_wc_customer_constructor );
$this->assertFalse( $get_base_rates_invoked );
$this->assertSame( $customer, $customer_passed_to_get_rates );
} else {
$this->assertFalse( $customer_id_passed_to_wc_customer_constructor );
$this->assertFalse( $customer_passed_to_get_rates );
$this->assertTrue( $get_base_rates_invoked );
}
} else {
wc_get_price_excluding_tax( $product );
$this->assertFalse( $customer_id_passed_to_wc_customer_constructor );
$this->assertNull( $customer_passed_to_get_rates );
$this->assertFalse( $customer_passed_to_get_rates );
$this->assertTrue( $get_base_rates_invoked );
}
// phpcs:enable Squiz.Commenting.FunctionComment.Missing
// phpcs:enable Squiz.Commenting
if ( $set_filter ) {
remove_filter( 'woocommerce_adjust_non_base_location_prices', '__return_false' );
}
}
}