From cd443581cfbad571787af10ab0f4a6bdb6a7a25f Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Wed, 4 Nov 2020 12:39:45 +0100 Subject: [PATCH 01/52] Fix code sniffer errors --- includes/customizer/class-wc-shop-customizer.php | 2 +- includes/theme-support/class-wc-twenty-nineteen.php | 2 +- includes/wc-core-functions.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/customizer/class-wc-shop-customizer.php b/includes/customizer/class-wc-shop-customizer.php index dd966b8de39..90af6a94c0b 100644 --- a/includes/customizer/class-wc-shop-customizer.php +++ b/includes/customizer/class-wc-shop-customizer.php @@ -769,7 +769,7 @@ class WC_Shop_Customizer { ); } else { $choose_pages = array( - 'woocommerce_terms_page_id' => __( 'Terms and conditions', 'woocommerce' ), + 'woocommerce_terms_page_id' => __( 'Terms and conditions', 'woocommerce' ), ); } $pages = get_pages( diff --git a/includes/theme-support/class-wc-twenty-nineteen.php b/includes/theme-support/class-wc-twenty-nineteen.php index 47c1aff660c..9d1f44cc64c 100644 --- a/includes/theme-support/class-wc-twenty-nineteen.php +++ b/includes/theme-support/class-wc-twenty-nineteen.php @@ -48,7 +48,7 @@ class WC_Twenty_Nineteen { // Tweak Twenty Nineteen features. add_action( 'wp', array( __CLASS__, 'tweak_theme_features' ) ); - // Color scheme CSS + // Color scheme CSS. add_filter( 'twentynineteen_custom_colors_css', array( __CLASS__, 'custom_colors_css' ), 10, 3 ); } diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php index 097770fede8..34b225af008 100644 --- a/includes/wc-core-functions.php +++ b/includes/wc-core-functions.php @@ -390,7 +390,7 @@ function wc_locate_template( $template_name, $template_path = '', $default_path // Look within passed path within the theme - this is priority. if ( false !== strpos( $template_name, 'product_cat' ) || false !== strpos( $template_name, 'product_tag' ) ) { $cs_template = str_replace( '_', '-', $template_name ); - $template = locate_template( + $template = locate_template( array( trailingslashit( $template_path ) . $cs_template, $cs_template, From d620f1d2321785f52926e067df348cb52f547c75 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Wed, 4 Nov 2020 12:56:42 +0100 Subject: [PATCH 02/52] Fix #25900 - image size customisation controls not shown - Added the `ThemeSupport class`, with methods to add and get theme support options. - It also has a new `add_default_options` method that adds the options under a `_defaults` key. - The `WC_Twenty_*` classes now use `ThemeSupport` instead of the `add_theme_support` function to define image and thumbnail sizes. - The values are defined as default options. - The `WC_Shop_Customizer` class now uses `ThemeSupport` instead of `wc_get_theme_support` to check if image and thumbnail sizes UI should be rendered. - The check is made excluding default values. With these changes the UI to change the image and thumbnail sizes is hidden only if the options are added as non-defaults elsewhere. Additional changes: - The code of the `wc_get_theme_support` function is replaced with a simple call to `get_option` in `ThemeSupport`. - Added the utility class `ArrayUtil`. --- .../customizer/class-wc-shop-customizer.php | 19 +- .../theme-support/class-wc-twenty-eleven.php | 5 +- .../theme-support/class-wc-twenty-fifteen.php | 5 +- .../class-wc-twenty-fourteen.php | 5 +- .../class-wc-twenty-nineteen.php | 4 +- .../class-wc-twenty-seventeen.php | 4 +- .../theme-support/class-wc-twenty-sixteen.php | 5 +- .../theme-support/class-wc-twenty-ten.php | 5 +- .../class-wc-twenty-thirteen.php | 5 +- .../theme-support/class-wc-twenty-twelve.php | 5 +- .../theme-support/class-wc-twenty-twenty.php | 4 +- includes/wc-core-functions.php | 34 +-- src/Container.php | 4 +- .../ThemeManagementServiceProvider.php | 31 +++ src/ThemeManagement/ThemeSupport.php | 118 ++++++++ src/Utilities/ArrayUtil.php | 48 ++++ tests/legacy/bootstrap.php | 9 +- .../class-wc-shop-customizer-test.php | 59 ++++ .../php/src/ThemeSupport/ThemeSupportTest.php | 254 ++++++++++++++++++ tests/php/src/Utilities/ArrayUtilTest.php | 66 +++++ 20 files changed, 631 insertions(+), 58 deletions(-) create mode 100644 src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php create mode 100644 src/ThemeManagement/ThemeSupport.php create mode 100644 src/Utilities/ArrayUtil.php create mode 100644 tests/php/includes/customizer/class-wc-shop-customizer-test.php create mode 100644 tests/php/src/ThemeSupport/ThemeSupportTest.php create mode 100644 tests/php/src/Utilities/ArrayUtilTest.php diff --git a/includes/customizer/class-wc-shop-customizer.php b/includes/customizer/class-wc-shop-customizer.php index 90af6a94c0b..1a42c04b10c 100644 --- a/includes/customizer/class-wc-shop-customizer.php +++ b/includes/customizer/class-wc-shop-customizer.php @@ -6,6 +6,8 @@ * @package WooCommerce */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -13,10 +15,19 @@ defined( 'ABSPATH' ) || exit; */ class WC_Shop_Customizer { + /** + * Holds the instance of ThemeSupport to use. + * + * @var ThemeSupport $theme_support The instance of ThemeSupport to use. + */ + private $theme_support; + /** * Constructor. */ public function __construct() { + $this->theme_support = wc_get_container()->get( ThemeSupport::class ); + add_action( 'customize_register', array( $this, 'add_sections' ) ); add_action( 'customize_controls_print_styles', array( $this, 'add_styles' ) ); add_action( 'customize_controls_print_scripts', array( $this, 'add_scripts' ), 30 ); @@ -545,11 +556,11 @@ class WC_Shop_Customizer { ) ); - if ( ! wc_get_theme_support( 'single_image_width' ) ) { + if ( ! $this->theme_support->has_option( 'single_image_width', false ) ) { $wp_customize->add_setting( 'woocommerce_single_image_width', array( - 'default' => 600, + 'default' => $this->theme_support->get_option( 'single_image_width', 600 ), 'type' => 'option', 'capability' => 'manage_woocommerce', 'sanitize_callback' => 'absint', @@ -573,11 +584,11 @@ class WC_Shop_Customizer { ); } - if ( ! wc_get_theme_support( 'thumbnail_image_width' ) ) { + if ( ! $this->theme_support->has_option( 'thumbnail_image_width', false ) ) { $wp_customize->add_setting( 'woocommerce_thumbnail_image_width', array( - 'default' => 300, + 'default' => $this->theme_support->get_option( 'thumbnail_image_width', 300 ), 'type' => 'option', 'capability' => 'manage_woocommerce', 'sanitize_callback' => 'absint', diff --git a/includes/theme-support/class-wc-twenty-eleven.php b/includes/theme-support/class-wc-twenty-eleven.php index fb06a7a84dc..9bb77c9e70e 100644 --- a/includes/theme-support/class-wc-twenty-eleven.php +++ b/includes/theme-support/class-wc-twenty-eleven.php @@ -6,6 +6,8 @@ * @package WooCommerce\Classes */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -29,8 +31,7 @@ class WC_Twenty_Eleven { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 150, 'single_image_width' => 300, diff --git a/includes/theme-support/class-wc-twenty-fifteen.php b/includes/theme-support/class-wc-twenty-fifteen.php index 83e1930cf93..828b2ed6d61 100644 --- a/includes/theme-support/class-wc-twenty-fifteen.php +++ b/includes/theme-support/class-wc-twenty-fifteen.php @@ -7,6 +7,8 @@ * @package WooCommerce\Classes */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -30,8 +32,7 @@ class WC_Twenty_Fifteen { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 200, 'single_image_width' => 350, diff --git a/includes/theme-support/class-wc-twenty-fourteen.php b/includes/theme-support/class-wc-twenty-fourteen.php index ce04395299d..e068e57c96c 100644 --- a/includes/theme-support/class-wc-twenty-fourteen.php +++ b/includes/theme-support/class-wc-twenty-fourteen.php @@ -7,6 +7,8 @@ * @package WooCommerce\Classes */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -30,8 +32,7 @@ class WC_Twenty_Fourteen { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 150, 'single_image_width' => 300, diff --git a/includes/theme-support/class-wc-twenty-nineteen.php b/includes/theme-support/class-wc-twenty-nineteen.php index 9d1f44cc64c..795fa079208 100644 --- a/includes/theme-support/class-wc-twenty-nineteen.php +++ b/includes/theme-support/class-wc-twenty-nineteen.php @@ -7,6 +7,7 @@ */ use Automattic\Jetpack\Constants; +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; defined( 'ABSPATH' ) || exit; @@ -37,8 +38,7 @@ class WC_Twenty_Nineteen { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 300, 'single_image_width' => 450, diff --git a/includes/theme-support/class-wc-twenty-seventeen.php b/includes/theme-support/class-wc-twenty-seventeen.php index 2093d2200e7..6fff3aab843 100644 --- a/includes/theme-support/class-wc-twenty-seventeen.php +++ b/includes/theme-support/class-wc-twenty-seventeen.php @@ -7,6 +7,7 @@ */ use Automattic\Jetpack\Constants; +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; defined( 'ABSPATH' ) || exit; @@ -30,8 +31,7 @@ class WC_Twenty_Seventeen { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 250, 'single_image_width' => 350, diff --git a/includes/theme-support/class-wc-twenty-sixteen.php b/includes/theme-support/class-wc-twenty-sixteen.php index c9681fa5e98..1dc0b137e7f 100644 --- a/includes/theme-support/class-wc-twenty-sixteen.php +++ b/includes/theme-support/class-wc-twenty-sixteen.php @@ -6,6 +6,8 @@ * @package WooCommerce\Classes */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -29,8 +31,7 @@ class WC_Twenty_Sixteen { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 250, 'single_image_width' => 400, diff --git a/includes/theme-support/class-wc-twenty-ten.php b/includes/theme-support/class-wc-twenty-ten.php index 8a9262e6191..67f14aeab94 100644 --- a/includes/theme-support/class-wc-twenty-ten.php +++ b/includes/theme-support/class-wc-twenty-ten.php @@ -6,6 +6,8 @@ * @package WooCommerce\Classes */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -29,8 +31,7 @@ class WC_Twenty_Ten { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 200, 'single_image_width' => 300, diff --git a/includes/theme-support/class-wc-twenty-thirteen.php b/includes/theme-support/class-wc-twenty-thirteen.php index 4e80b3e27c6..eac4e70130f 100644 --- a/includes/theme-support/class-wc-twenty-thirteen.php +++ b/includes/theme-support/class-wc-twenty-thirteen.php @@ -7,6 +7,8 @@ * @package WooCommerce\Classes */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -30,8 +32,7 @@ class WC_Twenty_Thirteen { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 200, 'single_image_width' => 300, diff --git a/includes/theme-support/class-wc-twenty-twelve.php b/includes/theme-support/class-wc-twenty-twelve.php index 116dabea432..a5e7315c911 100644 --- a/includes/theme-support/class-wc-twenty-twelve.php +++ b/includes/theme-support/class-wc-twenty-twelve.php @@ -7,6 +7,8 @@ * @package WooCommerce\Classes */ +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; + defined( 'ABSPATH' ) || exit; /** @@ -30,8 +32,7 @@ class WC_Twenty_Twelve { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 200, 'single_image_width' => 300, diff --git a/includes/theme-support/class-wc-twenty-twenty.php b/includes/theme-support/class-wc-twenty-twenty.php index 47296f639ab..f2327680da0 100644 --- a/includes/theme-support/class-wc-twenty-twenty.php +++ b/includes/theme-support/class-wc-twenty-twenty.php @@ -7,6 +7,7 @@ */ use Automattic\Jetpack\Constants; +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; defined( 'ABSPATH' ) || exit; @@ -37,8 +38,7 @@ class WC_Twenty_Twenty { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 450, 'single_image_width' => 600, diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php index 34b225af008..604fa4ce103 100644 --- a/includes/wc-core-functions.php +++ b/includes/wc-core-functions.php @@ -9,6 +9,7 @@ */ use Automattic\Jetpack\Constants; +use Automattic\WooCommerce\ThemeManagement\ThemeSupport; use Automattic\WooCommerce\Utilities\NumberUtil; if ( ! defined( 'ABSPATH' ) ) { @@ -879,38 +880,7 @@ function wc_mail( $to, $subject, $message, $headers = "Content-Type: text/html\r * @return mixed Value of prop(s). */ function wc_get_theme_support( $prop = '', $default = null ) { - $theme_support = get_theme_support( 'woocommerce' ); - $theme_support = is_array( $theme_support ) ? $theme_support[0] : false; - - if ( ! $theme_support ) { - return $default; - } - - if ( $prop ) { - $prop_stack = explode( '::', $prop ); - $prop_key = array_shift( $prop_stack ); - - if ( isset( $theme_support[ $prop_key ] ) ) { - $value = $theme_support[ $prop_key ]; - - if ( count( $prop_stack ) ) { - foreach ( $prop_stack as $prop_key ) { - if ( is_array( $value ) && isset( $value[ $prop_key ] ) ) { - $value = $value[ $prop_key ]; - } else { - $value = $default; - break; - } - } - } - } else { - $value = $default; - } - - return $value; - } - - return $theme_support; + return wc_get_container()->get( ThemeSupport::class )->get_option( $prop, $default ); } /** diff --git a/src/Container.php b/src/Container.php index 4291867682b..91986c21a74 100644 --- a/src/Container.php +++ b/src/Container.php @@ -6,12 +6,13 @@ namespace Automattic\WooCommerce; use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\ProxiesServiceProvider; +use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\ThemeManagementServiceProvider; use Automattic\WooCommerce\Internal\DependencyManagement\ExtendedContainer; /** * PSR11 compliant dependency injection container for WooCommerce. * - * Classes in the `src` directory should specify dependencies from that directory via constructor arguments + * Classes in the `src` directory should specify dependencies from that directory via an 'init' method having arguments * with type hints. If an instance of the container itself is needed, the type hint to use is \Psr\Container\ContainerInterface. * * Classes in the `src` directory should interact with anything outside (especially code in the `includes` directory @@ -33,6 +34,7 @@ final class Container implements \Psr\Container\ContainerInterface { */ private $service_providers = array( ProxiesServiceProvider::class, + ThemeManagementServiceProvider::class, ); /** diff --git a/src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php b/src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php new file mode 100644 index 00000000000..9ae7f90d848 --- /dev/null +++ b/src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php @@ -0,0 +1,31 @@ +share_with_auto_arguments( ThemeSupport::class ); + } +} diff --git a/src/ThemeManagement/ThemeSupport.php b/src/ThemeManagement/ThemeSupport.php new file mode 100644 index 00000000000..82c6bff089a --- /dev/null +++ b/src/ThemeManagement/ThemeSupport.php @@ -0,0 +1,118 @@ +legacy_proxy = $legacy_proxy; + } + + /** + * Adds theme support options for the current theme. + * + * @param array $options The options to be added. + */ + public function add_options( $options ) { + $this->legacy_proxy->call_function( 'add_theme_support', 'woocommerce', $options ); + } + + /** + * Adds default theme support options for the current theme. + * + * @param array $options The options to be added. + */ + public function add_default_options( $options ) { + $default_options = $this->get_option( self::DEFAULTS_KEY, array() ); + $default_options = array_merge( $default_options, $options ); + $this->add_options( array( self::DEFAULTS_KEY => $default_options ) ); + } + + /** + * Gets "theme support" options from the current theme, if set. + * + * @param string $option_name Option name, possibly nested (key::subkey), to get specific value. Blank to get all the existing options as an array. + * @param mixed $default_value Value to return if the specified option doesn't exist. + * @return mixed The retrieved option or the default value. + */ + public function get_option( $option_name = '', $default_value = null ) { + $theme_support_options = $this->get_all_options(); + + if ( ! $theme_support_options ) { + return $default_value; + } + + if ( $option_name ) { + $value = ArrayUtil::get_nested_value( $theme_support_options, $option_name ); + if ( is_null( $value ) ) { + $value = ArrayUtil::get_nested_value( $theme_support_options, self::DEFAULTS_KEY . '::' . $option_name, $default_value ); + } + return $value; + } + + return $theme_support_options; + } + + /** + * Checks whether a given theme support option has been defined. + * + * @param string $option_name The (possibly nested) name of the option to check. + * @param bool $include_defaults True to include the default values in the check, false otherwise. + * + * @return bool True if the specified theme support option has been defined, false otherwise. + */ + public function has_option( $option_name, $include_defaults = true ) { + $theme_support_options = $this->get_all_options(); + + if ( ! $theme_support_options ) { + return false; + } + + $value = ArrayUtil::get_nested_value( $theme_support_options, $option_name ); + if ( ! is_null( $value ) ) { + return true; + } + + if ( ! $include_defaults ) { + return false; + } + $value = ArrayUtil::get_nested_value( $theme_support_options, self::DEFAULTS_KEY . '::' . $option_name ); + return ! is_null( $value ); + } + + /** + * Get all the defined theme support options for the 'woocommerce' feature. + * + * @return array An array with all the theme support options defined for the 'woocommerce' feature, or false if nothing has been defined for that feature. + */ + private function get_all_options() { + $theme_support = $this->legacy_proxy->call_function( 'get_theme_support', 'woocommerce' ); + return is_array( $theme_support ) ? $theme_support[0] : false; + } +} diff --git a/src/Utilities/ArrayUtil.php b/src/Utilities/ArrayUtil.php new file mode 100644 index 00000000000..b381dbef86a --- /dev/null +++ b/src/Utilities/ArrayUtil.php @@ -0,0 +1,48 @@ + [ 'bar' => [ 'fizz' => 'buzz' ] ] ] the value for key 'foo::bar::fizz' would be 'buzz'. + * + * @param array $array The array to get the value from. + * @param string $key The complete key hierarchy, using '::' as separator. + * @param mixed $default The value to return if the key doesn't exist in the array. + * + * @return mixed The retrieved value, or the supplied default value. + * @throws \Exception $array is not an array. + */ + public static function get_nested_value( array $array, string $key, $default = null ) { + $key_stack = explode( '::', $key ); + $subkey = array_shift( $key_stack ); + + if ( isset( $array[ $subkey ] ) ) { + $value = $array[ $subkey ]; + + if ( count( $key_stack ) ) { + foreach ( $key_stack as $subkey ) { + if ( is_array( $value ) && isset( $value[ $subkey ] ) ) { + $value = $value[ $subkey ]; + } else { + $value = $default; + break; + } + } + } + } else { + $value = $default; + } + + return $value; + } +} + diff --git a/tests/legacy/bootstrap.php b/tests/legacy/bootstrap.php index bfbcd11edeb..62d93d87254 100644 --- a/tests/legacy/bootstrap.php +++ b/tests/legacy/bootstrap.php @@ -103,7 +103,14 @@ class WC_Unit_Tests_Bootstrap { * @throws Exception Error when initializing one of the hacks. */ private function initialize_code_hacker() { - CodeHacker::initialize( array( __DIR__ . '/../../includes/' ) ); + $wp_dir = getenv( 'WP_TESTS_WP_DIR' ) ? getenv( 'WP_TESTS_WP_DIR' ) : sys_get_temp_dir() . '/wordpress'; + CodeHacker::initialize( + array( + $this->plugin_dir . '/includes/', + $wp_dir . '/wp-includes/class-wp-customize-manager.php', + ) + ); + $replaceable_functions = include_once __DIR__ . '/mockable-functions.php'; if ( ! empty( $replaceable_functions ) ) { FunctionsMockerHack::initialize( $replaceable_functions ); diff --git a/tests/php/includes/customizer/class-wc-shop-customizer-test.php b/tests/php/includes/customizer/class-wc-shop-customizer-test.php new file mode 100644 index 00000000000..c1c73f66c56 --- /dev/null +++ b/tests/php/includes/customizer/class-wc-shop-customizer-test.php @@ -0,0 +1,59 @@ +createMock( WP_Customize_Manager::class ); + $added_settings = array(); + $added_controls = array(); + + $add_setting_callback = function( $id, $args = array() ) use ( &$added_settings ) { + array_push( $added_settings, $id ); + }; + $add_control_callback = function( $id, $args = array() ) use ( &$added_controls ) { + array_push( $added_controls, $id ); + }; + $customize_manager->method( 'add_setting' )->will( $this->returnCallback( $add_setting_callback ) ); + $customize_manager->method( 'add_control' )->will( $this->returnCallback( $add_control_callback ) ); + + $theme_support = $this->get_instance_of( ThemeSupport::class ); + $add_support_method = $add_explicit_theme_support ? 'add_options' : 'add_default_options'; + $theme_support->$add_support_method( array( $option_name => 1234 ) ); + + $sut = $this->get_legacy_instance_of( WC_Shop_Customizer::class ); + $sut->add_sections( $customize_manager ); + + $this->assertEquals( $expected_to_have_added_customization, in_array( 'woocommerce_' . $option_name, $added_settings, true ) ); + $this->assertEquals( $expected_to_have_added_customization, in_array( 'woocommerce_' . $option_name, $added_controls, true ) ); + } +} diff --git a/tests/php/src/ThemeSupport/ThemeSupportTest.php b/tests/php/src/ThemeSupport/ThemeSupportTest.php new file mode 100644 index 00000000000..3b3a5f9304f --- /dev/null +++ b/tests/php/src/ThemeSupport/ThemeSupportTest.php @@ -0,0 +1,254 @@ +sut = $this->get_instance_of( ThemeSupport::class ); + remove_theme_support( 'woocommerce' ); + } + + /** + * @testdox add_options should add the supplied options under the 'woocommerce' feature. + */ + public function test_add_options() { + $actual_added_feature = null; + $actual_added_options = null; + + $this->register_legacy_proxy_function_mocks( + array( + 'add_theme_support' => function( $feature, ...$args ) use ( &$actual_added_feature, &$actual_added_options ) { + $actual_added_feature = $feature; + $actual_added_options = $args; + }, + ) + ); + + $options = array( 'foo' => 'bar' ); + $this->sut->add_options( $options ); + + $this->assertEquals( 'woocommerce', $actual_added_feature ); + $this->assertEquals( $options, $actual_added_options[0] ); + + $this->reset_legacy_proxy_mocks(); + + $this->sut->add_options( $options ); + + $actual_retrieved_options = get_theme_support( 'woocommerce' )[0]; + $this->assertEquals( $options, $actual_retrieved_options ); + } + + /** + * @testdox add_default_options should add the supplied options under the 'woocommerce' feature on a '_defaults' key. + */ + public function test_2_add_default_options() { + $actual_added_options = array(); + + $this->register_legacy_proxy_function_mocks( + array( + 'add_theme_support' => function( $feature, ...$args ) use ( &$actual_added_options ) { + array_push( $actual_added_options, $args ); + }, + ) + ); + + $this->sut->add_default_options( array( 'foo' => 'bar' ) ); + $this->sut->add_default_options( array( 'fizz' => 'buzz' ) ); + + $expected_added_options = array( + array( + array( + ThemeSupport::DEFAULTS_KEY => + array( + 'foo' => 'bar', + ), + ), + ), + array( + array( + ThemeSupport::DEFAULTS_KEY => + array( + 'fizz' => 'buzz', + ), + ), + ), + ); + + $this->assertEquals( $expected_added_options, $actual_added_options ); + + $this->reset_legacy_proxy_mocks(); + + $this->sut->add_default_options( array( 'foo' => 'bar' ) ); + $this->sut->add_default_options( array( 'fizz' => 'buzz' ) ); + + $actual_retrieved_options = get_theme_support( 'woocommerce' )[0]; + $expected_retrieved_options = array( + ThemeSupport::DEFAULTS_KEY => array( + 'foo' => 'bar', + 'fizz' => 'buzz', + ), + ); + $this->assertEquals( $expected_retrieved_options, $actual_retrieved_options ); + } + + /** + * @testdox add_default_options should add the supplied options under the 'woocommerce' feature on a '_defaults' key. + */ + public function test_add_default_options() { + $this->sut->add_default_options( array( 'foo' => 'bar' ) ); + $this->sut->add_default_options( array( 'fizz' => 'buzz' ) ); + + $actual = get_theme_support( 'woocommerce' )[0]; + $expected = array( + ThemeSupport::DEFAULTS_KEY => array( + 'foo' => 'bar', + 'fizz' => 'buzz', + ), + ); + $this->assertEquals( $expected, $actual ); + } + + /** + * @testdox get_option should return all the options under the 'woocommerce' feature when invoked with blank option name. + */ + public function test_get_option_with_no_option_name() { + $options = array( 'foo' => 'bar' ); + $this->sut->add_options( $options ); + + $actual = $this->sut->get_option(); + $this->assertEquals( $options, $actual ); + } + + /** + * @testdox get_option should return null if no 'woocommerce' feature exists and no default value is supplied. + */ + public function test_get_option_with_no_option_name_when_no_options_exist_and_no_default_value_supplied() { + $actual = $this->sut->get_option(); + $this->assertNull( $actual ); + } + + /** + * @testdox get_option should return the supplied default value if no 'woocommerce' feature exists. + */ + public function test_get_option_with_no_option_name_when_no_options_exist_and_default_value_supplied() { + $actual = $this->sut->get_option( '', 'DEFAULT' ); + $this->assertEquals( 'DEFAULT', $actual ); + } + + /** + * @testdox get_theme_support should return the value of the requested option if it exists. + */ + public function test_get_theme_support_with_option_name() { + $options = array( 'foo' => array( 'bar' => 'fizz' ) ); + $this->sut->add_options( $options ); + + $actual = $this->sut->get_option( 'foo::bar' ); + $this->assertEquals( 'fizz', $actual ); + } + + /** + * @testdox get_option should return null if the requested option doesn't exist and no default value is supplied. + */ + public function test_get_option_with_option_name_when_option_does_not_exist_and_no_default_value_supplied() { + $options = array( 'foo' => array( 'bar' => 'fizz' ) ); + $this->sut->add_options( $options ); + + $actual = $this->sut->get_option( 'buzz' ); + $this->assertNull( $actual ); + } + + /** + * @testdox get_option should return the supplied default value if the requested option doesn't exist. + */ + public function test_get_option_with_option_name_when_option_does_not_exist_and_default_value_supplied() { + $options = array( 'foo' => array( 'bar' => 'fizz' ) ); + $this->sut->add_options( $options ); + + $actual = $this->sut->get_option( 'buzz', 'DEFAULT' ); + $this->assertEquals( 'DEFAULT', $actual ); + } + + /** + * @testdox get_option should return the value of the requested option if it has been defined as a default. + */ + public function test_get_option_with_option_name_and_option_defined_as_default() { + $options = array( 'foo' => array( 'bar' => 'fizz' ) ); + $this->sut->add_default_options( $options ); + + $actual = $this->sut->get_option( 'foo::bar' ); + $this->assertEquals( 'fizz', $actual ); + } + + /** + * @testdox has_option should return false if no 'woocommerce' feature exists. + * + * @testWith [true] + * [false] + * + * @param bool $include_defaults Whether to include defaults in the search or not. + */ + public function test_has_option_when_no_woocommerce_feature_is_defined( $include_defaults ) { + $this->assertFalse( $this->sut->has_option( 'foo::bar', $include_defaults ) ); + } + + /** + * @testdox has_option should return false if the specified option has not been defined. + * + * @testWith [true] + * [false] + * + * @param bool $include_defaults Whether to include defaults in the search or not. + */ + public function test_has_option_when_option_is_not_defined( $include_defaults ) { + $this->sut->add_options( array( 'foo' => 'bar' ) ); + $this->assertFalse( $this->sut->has_option( 'fizz::buzz', $include_defaults ) ); + } + + /** + * @testdox has_option should return true if the specified option has been defined. + * + * @testWith [true] + * [false] + * + * @param bool $include_defaults Whether to include defaults in the search or not. + */ + public function test_has_option_when_option_is_defined( $include_defaults ) { + $this->sut->add_options( array( 'foo' => 'bar' ) ); + $this->assertTrue( $this->sut->has_option( 'foo', $include_defaults ) ); + } + + /** + * @testdox If an option has been defined as a default, has_theme_support should return true if $include_defaults is passed as true, should return false otherwise. + * + * @testWith [true, true] + * [false, false] + * + * @param bool $include_defaults Whether to include defaults in the search or not. + * @param bool $expected_result The expected return value from the tested method. + */ + public function test_has_option_when_option_is_defined_as_default( $include_defaults, $expected_result ) { + $this->sut->add_default_options( array( 'foo' => 'bar' ) ); + $this->assertEquals( $expected_result, $this->sut->has_option( 'foo', $include_defaults ) ); + } +} diff --git a/tests/php/src/Utilities/ArrayUtilTest.php b/tests/php/src/Utilities/ArrayUtilTest.php new file mode 100644 index 00000000000..77f225942ac --- /dev/null +++ b/tests/php/src/Utilities/ArrayUtilTest.php @@ -0,0 +1,66 @@ + 'buzz' ); + $actual = ArrayUtil::get_nested_value( $array, $key ); + + $this->assertNull( $actual ); + } + + /** + * @testdox `get_nested_value` should return the supplied default value if the requested key doesn't exist. + * + * @testWith ["foo"] + * ["foo::bar"] + * + * @param string $key The key to test. + */ + public function test_get_nested_value_returns_supplied_default_if_non_existing_key( $key ) { + $array = array( 'fizz' => 'buzz' ); + $actual = ArrayUtil::get_nested_value( $array, $key, 'DEFAULT' ); + + $this->assertEquals( 'DEFAULT', $actual ); + } + + /** + * @testdox `get_nested_value` should return the proper value when a simple key is passed. + */ + public function test_get_nested_value_works_for_simple_keys() { + $array = array( 'foo' => 'bar' ); + $actual = ArrayUtil::get_nested_value( $array, 'foo' ); + + $this->assertEquals( 'bar', $actual ); + } + + /** + * @testdox `get_nested_value` should return the proper value when a nested key is passed. + */ + public function test_get_nested_value_works_for_nested_keys() { + $array = array( + 'foo' => array( + 'bar' => array( + 'fizz' => 'buzz', + ), + ), + ); + $actual = ArrayUtil::get_nested_value( $array, 'foo::bar::fizz' ); + + $this->assertEquals( 'buzz', $actual ); + } +} From a6467681c86be1bd0f7246236469248913b1ab8d Mon Sep 17 00:00:00 2001 From: Veljko Date: Wed, 7 Apr 2021 17:50:09 +0200 Subject: [PATCH 03/52] Add new e2e test shopper cart calculate shipping --- tests/e2e/core-tests/specs/index.js | 3 + .../front-end-cart-calculate-shipping.test.js | 147 ++++++++++++++++++ .../front-end/test-cart-calculate-shipping.js | 6 + 3 files changed, 156 insertions(+) create mode 100644 tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js create mode 100644 tests/e2e/specs/front-end/test-cart-calculate-shipping.js diff --git a/tests/e2e/core-tests/specs/index.js b/tests/e2e/core-tests/specs/index.js index 4d8997e462b..8aa6791858c 100644 --- a/tests/e2e/core-tests/specs/index.js +++ b/tests/e2e/core-tests/specs/index.js @@ -21,6 +21,7 @@ const runSingleProductPageTest = require( './shopper/front-end-single-product.te const runVariableProductUpdateTest = require( './shopper/front-end-variable-product-updates.test' ); const runCheckoutCreateAccountTest = require( './shopper/front-end-checkout-create-account.test' ); const runCheckoutLoginAccountTest = require( './shopper/front-end-checkout-login-account.test' ); +const runCartCalculateShippingTest = require( './shopper/front-end-cart-calculate-shipping.test' ); // Merchant tests const runAddNewShippingZoneTest = require ( './merchant/wp-admin-settings-shipping-zones.test' ); @@ -67,6 +68,7 @@ const runShopperTests = () => { runVariableProductUpdateTest(); runCheckoutCreateAccountTest(); runCheckoutLoginAccountTest(); + runCartCalculateShippingTest(); }; const runMerchantTests = () => { @@ -139,4 +141,5 @@ module.exports = { runCheckoutCreateAccountTest, runCheckoutLoginAccountTest, runMyAccountCreateAccountTest, + runCartCalculateShippingTest, }; diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js new file mode 100644 index 00000000000..2a8d87da894 --- /dev/null +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -0,0 +1,147 @@ +/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */ +/** + * Internal dependencies + */ +const { + shopper, + merchant, + createSimpleProduct, + addShippingZoneAndMethod, + clearAndFillInput, + evalAndClick, + uiUnblocked, + selectOptionInSelect2, +} = require( '@woocommerce/e2e-utils' ); + +const config = require( 'config' ); +const firstProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; +const secondProductPrice = '4.99'; +const fourProductPrice = firstProductPrice * 4; +var twoProductsPrice = eval([firstProductPrice,secondProductPrice].join('+')); +var firstProductPriceWithFlatRate = eval([firstProductPrice,5].join('+')); +var fourProductPriceWithFlatRate = eval([fourProductPrice,5].join('+')); +var twoProductsPriceWithFlatRate = eval([twoProductsPrice,5].join('+')); +const firstProductName = 'First Product'; +const secondProductName = 'Second Product'; +const shippingZoneNameDE = 'Germany Free Shipping'; +const shippingCountryDE = 'country:DE'; +const shippingZoneNameFR = 'France Flat Local'; +const shippingCountryFR = 'country:FR'; + +const runCartCalculateShippingTest = () => { + describe('Cart Calculate Shipping', () => { + beforeAll(async () => { + await merchant.login(); + await createSimpleProduct(firstProductName); + await createSimpleProduct(secondProductName, secondProductPrice); + await merchant.openSettings('shipping'); + + // Delete existing shipping zones. + try { + let zone = await page.$( '.wc-shipping-zone-delete' ); + if ( zone ) { + // WP action links aren't clickable because they are hidden with a left=-9999 style. + await page.evaluate(() => { + document.querySelector('.wc-shipping-zone-name .row-actions') + .style + .left = '0'; + }); + while ( zone ) { + await evalAndClick( '.wc-shipping-zone-delete' ); + await uiUnblocked(); + zone = await page.$( '.wc-shipping-zone-delete' ); + } + } + } catch (error) { + // Prevent an error here causing the test to fail. + } + + // Add a new shipping zone Germany with Free shipping + await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); + + // Add a new shipping zone for France with Flat rate & Local pickup + await addShippingZoneAndMethod(shippingZoneNameFR, shippingCountryFR, ' ', 'flat_rate'); + await page.waitFor(1000); // to avoid flakiness in headless + await page.click('a.wc-shipping-zone-method-settings', {text: 'Flat rate'}); + await clearAndFillInput('#woocommerce_flat_rate_cost', '5'); + await page.click('.wc-backbone-modal-main button#btn-ok'); + // Add additional method Local pickup for the same location + await page.waitFor(1000); // to avoid flakiness in headless + await page.click('button.wc-shipping-zone-add-method', {text:'Add shipping method'}); + await page.waitForSelector('.wc-shipping-zone-method-selector'); + await page.select('select[name="add_method_id"]', 'local_pickup'); + await page.click('button#btn-ok'); + await page.waitForSelector('#zone_locations'); + + await merchant.logout(); + }); + + it('allows customer to calculate Free Shipping if in Germany', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(firstProductName); + await shopper.goToCart(); + + // Set shipping country to Germany + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('Germany'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping ul#shipping_method > li', {text: 'Free shipping'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPrice}`}); + }); + + it('allows customer to calculate Flat rate and Local pickup if in France', async () => { + await page.reload(); + + // Set shipping country to France + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('France'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPriceWithFlatRate}`}); + }); + + it('should show correct total cart price after updating quantity', async () => { + await shopper.setCartQuantity(firstProductName, 4); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); + }); + + it('should show correct total cart price with 2 products and flat rate', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(secondProductName); + await shopper.goToCart(); + + await shopper.setCartQuantity(firstProductName, 1); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); + }); + + it('should show correct total cart price with 2 products without flat rate', async () => { + await page.reload(); + + // Set shipping country to Spain + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('Spain'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); + }); + }); +}; + +module.exports = runCartCalculateShippingTest; diff --git a/tests/e2e/specs/front-end/test-cart-calculate-shipping.js b/tests/e2e/specs/front-end/test-cart-calculate-shipping.js new file mode 100644 index 00000000000..6ee84f7b8f2 --- /dev/null +++ b/tests/e2e/specs/front-end/test-cart-calculate-shipping.js @@ -0,0 +1,6 @@ +/* + * Internal dependencies + */ +const { runCartCalculateShippingTest } = require( '@woocommerce/e2e-core-tests' ); + +runCartCalculateShippingTest(); From 9fdbaae76e5c6a32fbaba90e4e7717e18e3b0c86 Mon Sep 17 00:00:00 2001 From: Veljko Date: Wed, 7 Apr 2021 17:52:58 +0200 Subject: [PATCH 04/52] Add changelog and update spaces --- tests/e2e/core-tests/CHANGELOG.md | 1 + tests/e2e/core-tests/README.md | 1 + .../front-end-cart-calculate-shipping.test.js | 74 +++++++++---------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/tests/e2e/core-tests/CHANGELOG.md b/tests/e2e/core-tests/CHANGELOG.md index bf220a9d338..6d546e5571d 100644 --- a/tests/e2e/core-tests/CHANGELOG.md +++ b/tests/e2e/core-tests/CHANGELOG.md @@ -6,6 +6,7 @@ - Shopper Checkout Login Account - Shopper My Account Create Account +- Shopper Cart Calculate Shipping ## Fixed diff --git a/tests/e2e/core-tests/README.md b/tests/e2e/core-tests/README.md index 26f58a36c67..75d272ab1dd 100644 --- a/tests/e2e/core-tests/README.md +++ b/tests/e2e/core-tests/README.md @@ -79,6 +79,7 @@ The functions to access the core tests are: - `runCheckoutCreateAccountTest` - Shopper can create an account during checkout - `runCheckoutLoginAccountTest` - Shopper can login to an account during checkout - `runMyAccountCreateAccountTest` - Shopper can create an account via my account page + - `runCartCalculateShippingTest` - Shopper can calculate shipping in the cart ### REST API diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 2a8d87da894..59c980a620c 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -33,7 +33,7 @@ const runCartCalculateShippingTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(firstProductName); - await createSimpleProduct(secondProductName, secondProductPrice); + await createSimpleProduct(secondProductName, secondProductPrice); await merchant.openSettings('shipping'); // Delete existing shipping zones. @@ -61,31 +61,31 @@ const runCartCalculateShippingTest = () => { // Add a new shipping zone for France with Flat rate & Local pickup await addShippingZoneAndMethod(shippingZoneNameFR, shippingCountryFR, ' ', 'flat_rate'); - await page.waitFor(1000); // to avoid flakiness in headless + await page.waitFor(1000); // to avoid flakiness in headless await page.click('a.wc-shipping-zone-method-settings', {text: 'Flat rate'}); await clearAndFillInput('#woocommerce_flat_rate_cost', '5'); await page.click('.wc-backbone-modal-main button#btn-ok'); - // Add additional method Local pickup for the same location - await page.waitFor(1000); // to avoid flakiness in headless - await page.click('button.wc-shipping-zone-add-method', {text:'Add shipping method'}); - await page.waitForSelector('.wc-shipping-zone-method-selector'); - await page.select('select[name="add_method_id"]', 'local_pickup'); - await page.click('button#btn-ok'); - await page.waitForSelector('#zone_locations'); + // Add additional method Local pickup for the same location + await page.waitFor(1000); // to avoid flakiness in headless + await page.click('button.wc-shipping-zone-add-method', {text:'Add shipping method'}); + await page.waitForSelector('.wc-shipping-zone-method-selector'); + await page.select('select[name="add_method_id"]', 'local_pickup'); + await page.click('button#btn-ok'); + await page.waitForSelector('#zone_locations'); await merchant.logout(); }); it('allows customer to calculate Free Shipping if in Germany', async () => { await shopper.goToShop(); - await shopper.addToCartFromShopPage(firstProductName); - await shopper.goToCart(); - - // Set shipping country to Germany + await shopper.addToCartFromShopPage(firstProductName); + await shopper.goToCart(); + + // Set shipping country to Germany await expect(page).toClick('a.shipping-calculator-button'); await expect(page).toClick('#select2-calc_shipping_country-container'); await selectOptionInSelect2('Germany'); - await expect(page).toClick('button[name="calc_shipping"]'); + await expect(page).toClick('button[name="calc_shipping"]'); // Verify shipping costs await page.waitForSelector('.order-total'); @@ -93,54 +93,54 @@ const runCartCalculateShippingTest = () => { await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPrice}`}); }); - it('allows customer to calculate Flat rate and Local pickup if in France', async () => { - await page.reload(); + it('allows customer to calculate Flat rate and Local pickup if in France', async () => { + await page.reload(); - // Set shipping country to France + // Set shipping country to France await expect(page).toClick('a.shipping-calculator-button'); await expect(page).toClick('#select2-calc_shipping_country-container'); await selectOptionInSelect2('France'); - await expect(page).toClick('button[name="calc_shipping"]'); + await expect(page).toClick('button[name="calc_shipping"]'); // Verify shipping costs await page.waitForSelector('.order-total'); await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPriceWithFlatRate}`}); - }); + }); - it('should show correct total cart price after updating quantity', async () => { - await shopper.setCartQuantity(firstProductName, 4); + it('should show correct total cart price after updating quantity', async () => { + await shopper.setCartQuantity(firstProductName, 4); await expect(page).toClick('button', {text: 'Update cart'}); await uiUnblocked(); - await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); - }); + await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); + }); - it('should show correct total cart price with 2 products and flat rate', async () => { - await shopper.goToShop(); - await shopper.addToCartFromShopPage(secondProductName); - await shopper.goToCart(); + it('should show correct total cart price with 2 products and flat rate', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(secondProductName); + await shopper.goToCart(); - await shopper.setCartQuantity(firstProductName, 1); - await expect(page).toClick('button', {text: 'Update cart'}); - await uiUnblocked(); - await page.waitForSelector('.order-total'); + await shopper.setCartQuantity(firstProductName, 1); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await page.waitForSelector('.order-total'); await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); - }); + }); - it('should show correct total cart price with 2 products without flat rate', async () => { - await page.reload(); + it('should show correct total cart price with 2 products without flat rate', async () => { + await page.reload(); - // Set shipping country to Spain + // Set shipping country to Spain await expect(page).toClick('a.shipping-calculator-button'); await expect(page).toClick('#select2-calc_shipping_country-container'); await selectOptionInSelect2('Spain'); - await expect(page).toClick('button[name="calc_shipping"]'); + await expect(page).toClick('button[name="calc_shipping"]'); // Verify shipping costs await page.waitForSelector('.order-total'); await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); - }); + }); }); }; From ca4d690c5cd07eeefc29a6ab5e3392bad9de9d96 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 09:19:47 +0200 Subject: [PATCH 05/52] Try with 45s timeout --- tests/e2e/env/bin/e2e-test-integration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/env/bin/e2e-test-integration.js b/tests/e2e/env/bin/e2e-test-integration.js index 46d457d974b..3cdb11bde66 100755 --- a/tests/e2e/env/bin/e2e-test-integration.js +++ b/tests/e2e/env/bin/e2e-test-integration.js @@ -40,7 +40,7 @@ let testEnvVars = { NODE_ENV: 'test-e2e', NODE_CONFIG_DIR: nodeConfigDirs.join( ':' ), node_config_dev: program.dev ? 'yes' : 'no', - jest_test_timeout: program.dev ? 120000 : 30000, + jest_test_timeout: program.dev ? 120000 : 45000, }; if ( ! JEST_PUPPETEER_CONFIG ) { From 615bb66d412a7d3a6c0bc4121eb717f22dcbb434 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 10:09:12 +0200 Subject: [PATCH 06/52] Revert timeout back and split test --- .../front-end-cart-calculate-shipping.test.js | 27 ------------------- tests/e2e/env/bin/e2e-test-integration.js | 2 +- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 59c980a620c..6a8aa527e88 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -114,33 +114,6 @@ const runCartCalculateShippingTest = () => { await uiUnblocked(); await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); }); - - it('should show correct total cart price with 2 products and flat rate', async () => { - await shopper.goToShop(); - await shopper.addToCartFromShopPage(secondProductName); - await shopper.goToCart(); - - await shopper.setCartQuantity(firstProductName, 1); - await expect(page).toClick('button', {text: 'Update cart'}); - await uiUnblocked(); - await page.waitForSelector('.order-total'); - await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); - await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); - }); - - it('should show correct total cart price with 2 products without flat rate', async () => { - await page.reload(); - - // Set shipping country to Spain - await expect(page).toClick('a.shipping-calculator-button'); - await expect(page).toClick('#select2-calc_shipping_country-container'); - await selectOptionInSelect2('Spain'); - await expect(page).toClick('button[name="calc_shipping"]'); - - // Verify shipping costs - await page.waitForSelector('.order-total'); - await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); - }); }); }; diff --git a/tests/e2e/env/bin/e2e-test-integration.js b/tests/e2e/env/bin/e2e-test-integration.js index 3cdb11bde66..46d457d974b 100755 --- a/tests/e2e/env/bin/e2e-test-integration.js +++ b/tests/e2e/env/bin/e2e-test-integration.js @@ -40,7 +40,7 @@ let testEnvVars = { NODE_ENV: 'test-e2e', NODE_CONFIG_DIR: nodeConfigDirs.join( ':' ), node_config_dev: program.dev ? 'yes' : 'no', - jest_test_timeout: program.dev ? 120000 : 45000, + jest_test_timeout: program.dev ? 120000 : 30000, }; if ( ! JEST_PUPPETEER_CONFIG ) { From 6574db5c2c48a6e7bf4598b239c61aea7f3f269c Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 10:43:07 +0200 Subject: [PATCH 07/52] Add additional test scenarios --- .../front-end-cart-calculate-shipping.test.js | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 6a8aa527e88..f2885988bcf 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -55,7 +55,9 @@ const runCartCalculateShippingTest = () => { } catch (error) { // Prevent an error here causing the test to fail. } + }); + it('can prepare the shipping zones for the test', async () => { // Add a new shipping zone Germany with Free shipping await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); @@ -72,8 +74,6 @@ const runCartCalculateShippingTest = () => { await page.select('select[name="add_method_id"]', 'local_pickup'); await page.click('button#btn-ok'); await page.waitForSelector('#zone_locations'); - - await merchant.logout(); }); it('allows customer to calculate Free Shipping if in Germany', async () => { @@ -114,6 +114,33 @@ const runCartCalculateShippingTest = () => { await uiUnblocked(); await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); }); + + it('should show correct total cart price with 2 products and flat rate', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(secondProductName); + await shopper.goToCart(); + + await shopper.setCartQuantity(firstProductName, 1); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); + }); + + it('should show correct total cart price with 2 products without flat rate', async () => { + await page.reload(); + + // Set shipping country to Spain + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('Spain'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); + }); }); }; From b195e354a22ad8aa4c4a53f281df7749728507f8 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 11:44:54 +0200 Subject: [PATCH 08/52] Make test more granular --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index f2885988bcf..f5fe1fcff2d 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -33,9 +33,12 @@ const runCartCalculateShippingTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(firstProductName); + await merchant.openSettings('general'); await createSimpleProduct(secondProductName, secondProductPrice); await merchant.openSettings('shipping'); + }); + it('can remove the existing shippings if they are present', async () => { // Delete existing shipping zones. try { let zone = await page.$( '.wc-shipping-zone-delete' ); From 7a1ba36fc9d775c05b797cd37abf2a834607add1 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 12:41:02 +0200 Subject: [PATCH 09/52] Added new component and updated tests --- .../wp-admin-settings-shipping-zones.test.js | 25 ++-------------- .../front-end-cart-calculate-shipping.test.js | 28 ++--------------- tests/e2e/utils/CHANGELOG.md | 1 + tests/e2e/utils/README.md | 1 + tests/e2e/utils/src/components.js | 30 ++++++++++++++++++- 5 files changed, 35 insertions(+), 50 deletions(-) diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js index e7da3ffe377..6e5b8fb51c9 100644 --- a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js +++ b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js @@ -10,8 +10,7 @@ const { addShippingZoneAndMethod, clearAndFillInput, selectOptionInSelect2, - evalAndClick, - uiUnblocked, + deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); const config = require( 'config' ); @@ -28,27 +27,7 @@ const runAddNewShippingZoneTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(); - await merchant.openSettings('shipping'); - - // Delete existing shipping zones. - try { - let zone = await page.$( '.wc-shipping-zone-delete' ); - if ( zone ) { - // WP action links aren't clickable because they are hidden with a left=-9999 style. - await page.evaluate(() => { - document.querySelector('.wc-shipping-zone-name .row-actions') - .style - .left = '0'; - }); - while ( zone ) { - await evalAndClick( '.wc-shipping-zone-delete' ); - await uiUnblocked(); - zone = await page.$( '.wc-shipping-zone-delete' ); - } - } - } catch (error) { - // Prevent an error here causing the test to fail. - } + await deleteAllShippingZones(); }); it('add shipping zone for San Francisco with free Local pickup', async () => { diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index f5fe1fcff2d..aa9baaee694 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -8,7 +8,7 @@ const { createSimpleProduct, addShippingZoneAndMethod, clearAndFillInput, - evalAndClick, + deleteAllShippingZones, uiUnblocked, selectOptionInSelect2, } = require( '@woocommerce/e2e-utils' ); @@ -33,33 +33,9 @@ const runCartCalculateShippingTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(firstProductName); - await merchant.openSettings('general'); await createSimpleProduct(secondProductName, secondProductPrice); - await merchant.openSettings('shipping'); + await deleteAllShippingZones(); }); - - it('can remove the existing shippings if they are present', async () => { - // Delete existing shipping zones. - try { - let zone = await page.$( '.wc-shipping-zone-delete' ); - if ( zone ) { - // WP action links aren't clickable because they are hidden with a left=-9999 style. - await page.evaluate(() => { - document.querySelector('.wc-shipping-zone-name .row-actions') - .style - .left = '0'; - }); - while ( zone ) { - await evalAndClick( '.wc-shipping-zone-delete' ); - await uiUnblocked(); - zone = await page.$( '.wc-shipping-zone-delete' ); - } - } - } catch (error) { - // Prevent an error here causing the test to fail. - } - }); - it('can prepare the shipping zones for the test', async () => { // Add a new shipping zone Germany with Free shipping await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); diff --git a/tests/e2e/utils/CHANGELOG.md b/tests/e2e/utils/CHANGELOG.md index 07e70e130fe..561ee7f4105 100644 --- a/tests/e2e/utils/CHANGELOG.md +++ b/tests/e2e/utils/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - `emptyCart()` Shopper flow helper that empties the cart +- `deleteAllShippingZones` Delete all the existing shipping zones # 0.1.4 diff --git a/tests/e2e/utils/README.md b/tests/e2e/utils/README.md index f6b5c662e4f..bffe722c41c 100644 --- a/tests/e2e/utils/README.md +++ b/tests/e2e/utils/README.md @@ -124,6 +124,7 @@ describe( 'Cart page', () => { | `removeCoupon` | | helper method that removes a single coupon within cart or checkout | | `selectOrderAction` | `action` | Helper method to select an order action in the `Order Actions` postbox | | `clickUpdateOrder` | `noticeText`, `waitForSave` | Helper method to click the Update button on the order details page | +| `deleteAllShippingZones` | | Delete all the existing shipping zones | ### Test Utilities diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index c449622937b..addeed491ff 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -12,7 +12,8 @@ import { verifyCheckboxIsUnset, selectOptionInSelect2, setCheckbox, - unsetCheckbox + unsetCheckbox, + evalAndClick, } from './page-utils'; import factories from './factories'; @@ -538,6 +539,32 @@ const deleteAllEmailLogs = async () => { } }; +/** + * Delete all the existing shipping zones. + */ +const deleteAllShippingZones = async () => { + await merchant.openSettings('shipping'); + // Delete existing shipping zones. + try { + let zone = await page.$( '.wc-shipping-zone-delete' ); + if ( zone ) { + // WP action links aren't clickable because they are hidden with a left=-9999 style. + await page.evaluate(() => { + document.querySelector('.wc-shipping-zone-name .row-actions') + .style + .left = '0'; + }); + while ( zone ) { + await evalAndClick( '.wc-shipping-zone-delete' ); + await uiUnblocked(); + zone = await page.$( '.wc-shipping-zone-delete' ); + }; + }; + } catch (error) { + // Prevent an error here causing the test to fail. + }; +}; + export { completeOnboardingWizard, createSimpleProduct, @@ -551,4 +578,5 @@ export { createSimpleProductWithCategory, clickUpdateOrder, deleteAllEmailLogs, + deleteAllShippingZones, }; From 4fed8f8dab92f1e901009d8ade607413b65e4e01 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 15:09:59 +0200 Subject: [PATCH 10/52] Add missing jest/global --- .../shopper/front-end-cart-calculate-shipping.test.js | 9 +++++++++ tests/e2e/utils/src/components.js | 1 + 2 files changed, 10 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index aa9baaee694..ae32e9bc1d0 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -13,6 +13,15 @@ const { selectOptionInSelect2, } = require( '@woocommerce/e2e-utils' ); +/** + * External dependencies + */ + const { + it, + describe, + beforeAll, +} = require( '@jest/globals' ); + const config = require( 'config' ); const firstProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; const secondProductPrice = '4.99'; diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index addeed491ff..7e52fa090af 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -544,6 +544,7 @@ const deleteAllEmailLogs = async () => { */ const deleteAllShippingZones = async () => { await merchant.openSettings('shipping'); + // Delete existing shipping zones. try { let zone = await page.$( '.wc-shipping-zone-delete' ); From a9ce07c02040bcbff8856f58b447a7333047395f Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 17:11:29 +0200 Subject: [PATCH 11/52] Update test --- .../merchant/wp-admin-settings-shipping-zones.test.js | 9 +++++++++ .../shopper/front-end-cart-calculate-shipping.test.js | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js index 6e5b8fb51c9..c6bae31d94f 100644 --- a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js +++ b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js @@ -13,6 +13,15 @@ const { deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); +/** + * External dependencies + */ +const { + it, + describe, + beforeAll, +} = require( '@jest/globals' ); + const config = require( 'config' ); const simpleProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; const simpleProductName = config.get( 'products.simple.name' ); diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index ae32e9bc1d0..83d2c05a3e3 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -1,4 +1,5 @@ /* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */ + /** * Internal dependencies */ @@ -16,7 +17,7 @@ const { /** * External dependencies */ - const { +const { it, describe, beforeAll, From d4d93f9239bac14ba73122eceec1e6e217d866df Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 18:18:59 +0200 Subject: [PATCH 12/52] Remove shipping method deletion --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 83d2c05a3e3..879f5f17f5d 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -9,7 +9,6 @@ const { createSimpleProduct, addShippingZoneAndMethod, clearAndFillInput, - deleteAllShippingZones, uiUnblocked, selectOptionInSelect2, } = require( '@woocommerce/e2e-utils' ); @@ -44,9 +43,8 @@ const runCartCalculateShippingTest = () => { await merchant.login(); await createSimpleProduct(firstProductName); await createSimpleProduct(secondProductName, secondProductPrice); - await deleteAllShippingZones(); - }); - it('can prepare the shipping zones for the test', async () => { + await merchant.openNewShipping(); + // Add a new shipping zone Germany with Free shipping await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); From 6c7c420d257e62eacd8c37b2e32ee3f19be77972 Mon Sep 17 00:00:00 2001 From: roykho Date: Mon, 12 Apr 2021 09:28:30 -0700 Subject: [PATCH 13/52] Set US:CA as the default store location --- includes/admin/class-wc-admin-dashboard-setup.php | 2 +- .../admin/settings/class-wc-settings-general.php | 2 +- includes/wc-core-functions.php | 12 ++++++------ tests/legacy/unit-tests/countries/countries.php | 4 +++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/includes/admin/class-wc-admin-dashboard-setup.php b/includes/admin/class-wc-admin-dashboard-setup.php index 580bdc00b2e..4360241b37f 100644 --- a/includes/admin/class-wc-admin-dashboard-setup.php +++ b/includes/admin/class-wc-admin-dashboard-setup.php @@ -172,7 +172,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard_Setup', false ) ) : */ private function populate_payment_tasks() { $is_woo_payment_installed = is_plugin_active( 'woocommerce-payments/woocommerce-payments.php' ); - $country = explode( ':', get_option( 'woocommerce_default_country', '' ) )[0]; + $country = explode( ':', get_option( 'woocommerce_default_country', 'US:CA' ) )[0]; // woocommerce-payments requires its plugin activated and country must be US. if ( ! $is_woo_payment_installed || 'US' !== $country ) { diff --git a/includes/admin/settings/class-wc-settings-general.php b/includes/admin/settings/class-wc-settings-general.php index 8535dd7f956..28864828d0d 100644 --- a/includes/admin/settings/class-wc-settings-general.php +++ b/includes/admin/settings/class-wc-settings-general.php @@ -81,7 +81,7 @@ class WC_Settings_General extends WC_Settings_Page { 'title' => __( 'Country / State', 'woocommerce' ), 'desc' => __( 'The country and state or province, if any, in which your business is located.', 'woocommerce' ), 'id' => 'woocommerce_default_country', - 'default' => 'GB', + 'default' => 'US:CA', 'type' => 'single_select_country', 'desc_tip' => true, ), diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php index 6564d77f698..fd6c6aed831 100644 --- a/includes/wc-core-functions.php +++ b/includes/wc-core-functions.php @@ -390,7 +390,7 @@ function wc_locate_template( $template_name, $template_path = '', $default_path // Look within passed path within the theme - this is priority. if ( false !== strpos( $template_name, 'product_cat' ) || false !== strpos( $template_name, 'product_tag' ) ) { $cs_template = str_replace( '_', '-', $template_name ); - $template = locate_template( + $template = locate_template( array( trailingslashit( $template_path ) . $cs_template, $cs_template, @@ -1270,7 +1270,7 @@ function wc_format_country_state_string( $country_string ) { * @return array */ function wc_get_base_location() { - $default = apply_filters( 'woocommerce_get_base_location', get_option( 'woocommerce_default_country' ) ); + $default = apply_filters( 'woocommerce_get_base_location', get_option( 'woocommerce_default_country', 'US:CA' ) ); return wc_format_country_state_string( $default ); } @@ -1286,7 +1286,7 @@ function wc_get_base_location() { */ function wc_get_customer_default_location() { $set_default_location_to = get_option( 'woocommerce_default_customer_address', 'base' ); - $default_location = '' === $set_default_location_to ? '' : get_option( 'woocommerce_default_country', '' ); + $default_location = '' === $set_default_location_to ? '' : get_option( 'woocommerce_default_country', 'US:CA' ); $location = wc_format_country_state_string( apply_filters( 'woocommerce_customer_default_location', $default_location ) ); // Geolocation takes priority if used and if geolocation is possible. @@ -2269,9 +2269,9 @@ function wc_prevent_dangerous_auto_updates( $should_update, $plugin ) { include_once dirname( __FILE__ ) . '/admin/plugin-updates/class-wc-plugin-updates.php'; } - $new_version = wc_clean( $plugin->new_version ); - $plugin_updates = new WC_Plugin_Updates(); - $version_type = Constants::get_constant( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE' ); + $new_version = wc_clean( $plugin->new_version ); + $plugin_updates = new WC_Plugin_Updates(); + $version_type = Constants::get_constant( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE' ); if ( ! is_string( $version_type ) ) { $version_type = 'none'; } diff --git a/tests/legacy/unit-tests/countries/countries.php b/tests/legacy/unit-tests/countries/countries.php index 73f41fbd55c..d2e6c0e76d4 100644 --- a/tests/legacy/unit-tests/countries/countries.php +++ b/tests/legacy/unit-tests/countries/countries.php @@ -5,6 +5,8 @@ * @package WooCommerce\Tests\Countries */ +// phpcs:disable WordPress.Files.FileName + /** * WC_Countries tests. */ @@ -178,7 +180,7 @@ class WC_Tests_Countries extends WC_Unit_Test_Case { update_option( 'woocommerce_default_country', 'NO' ); $this->assertEquals( 'VAT', $countries->tax_or_vat() ); - update_option( 'woocommerce_default_country', 'US' ); + update_option( 'woocommerce_default_country', 'US:CA' ); $this->assertEquals( 'Tax', $countries->tax_or_vat() ); } From ded5c9c7c41303abc121e47bbddd7b2ace18bf83 Mon Sep 17 00:00:00 2001 From: roykho Date: Mon, 12 Apr 2021 14:13:27 -0700 Subject: [PATCH 14/52] Update unit tests to reflect new base address --- .../helpers/class-wc-helper-customer.php | 26 +++++++------- tests/legacy/unit-tests/account/functions.php | 2 +- tests/legacy/unit-tests/customer/crud.php | 14 ++++---- tests/legacy/unit-tests/customer/customer.php | 2 +- .../unit-tests/formatting/functions.php | 2 +- .../order/class-wc-tests-crud-orders.php | 8 ++--- tests/legacy/unit-tests/privacy/export.php | 12 +++---- .../rest-api/Helpers/CustomerHelper.php | 26 +++++++------- .../rest-api/Tests/Version2/customers.php | 24 ++++++------- .../rest-api/Tests/Version3/customers.php | 36 +++++++++---------- tests/legacy/unit-tests/tax/tax.php | 4 +-- .../util/class-wc-tests-core-functions.php | 4 +-- 12 files changed, 80 insertions(+), 80 deletions(-) diff --git a/tests/legacy/framework/helpers/class-wc-helper-customer.php b/tests/legacy/framework/helpers/class-wc-helper-customer.php index fe6b9ba644d..c814ac104d7 100644 --- a/tests/legacy/framework/helpers/class-wc-helper-customer.php +++ b/tests/legacy/framework/helpers/class-wc-helper-customer.php @@ -17,15 +17,15 @@ class WC_Helper_Customer { 'id' => 0, 'date_modified' => null, 'country' => 'US', - 'state' => 'PA', - 'postcode' => '19123', - 'city' => 'Philadelphia', + 'state' => 'CA', + 'postcode' => '94110', + 'city' => 'San Francisco', 'address' => '123 South Street', 'address_2' => 'Apt 1', 'shipping_country' => 'US', - 'shipping_state' => 'PA', - 'shipping_postcode' => '19123', - 'shipping_city' => 'Philadelphia', + 'shipping_state' => 'CA', + 'shipping_postcode' => '94110', + 'shipping_city' => 'San Francisco', 'shipping_address' => '123 South Street', 'shipping_address_2' => 'Apt 1', 'is_vat_exempt' => false, @@ -46,15 +46,15 @@ class WC_Helper_Customer { $customer = new WC_Customer(); $customer->set_billing_country( 'US' ); $customer->set_first_name( 'Justin' ); - $customer->set_billing_state( 'PA' ); - $customer->set_billing_postcode( '19123' ); - $customer->set_billing_city( 'Philadelphia' ); + $customer->set_billing_state( 'CA' ); + $customer->set_billing_postcode( '94110' ); + $customer->set_billing_city( 'San Francisco' ); $customer->set_billing_address( '123 South Street' ); $customer->set_billing_address_2( 'Apt 1' ); $customer->set_shipping_country( 'US' ); - $customer->set_shipping_state( 'PA' ); - $customer->set_shipping_postcode( '19123' ); - $customer->set_shipping_city( 'Philadelphia' ); + $customer->set_shipping_state( 'CA' ); + $customer->set_shipping_postcode( '94110' ); + $customer->set_shipping_city( 'San Francisco' ); $customer->set_shipping_address( '123 South Street' ); $customer->set_shipping_address_2( 'Apt 1' ); $customer->set_username( $username ); @@ -70,7 +70,7 @@ class WC_Helper_Customer { * @return array */ public static function get_expected_store_location() { - return array( 'GB', '', '', '' ); + return array( 'US', 'CA', '', '' ); } /** diff --git a/tests/legacy/unit-tests/account/functions.php b/tests/legacy/unit-tests/account/functions.php index b9b5756b1c6..ca57ba3bf5e 100644 --- a/tests/legacy/unit-tests/account/functions.php +++ b/tests/legacy/unit-tests/account/functions.php @@ -179,7 +179,7 @@ class WC_Tests_Account_Functions extends WC_Unit_Test_Case { public function test_wc_get_account_formatted_address() { $customer = WC_Helper_Customer::create_customer(); - $this->assertEquals( '123 South Street
Apt 1
Philadelphia, PA 19123
United States (US)', wc_get_account_formatted_address( 'billing', $customer->get_id() ) ); + $this->assertEquals( '123 South Street
Apt 1
San Francisco, CA 94110', wc_get_account_formatted_address( 'billing', $customer->get_id() ) ); $customer->delete( true ); } diff --git a/tests/legacy/unit-tests/customer/crud.php b/tests/legacy/unit-tests/customer/crud.php index 41c801d6538..2b070bbc309 100644 --- a/tests/legacy/unit-tests/customer/crud.php +++ b/tests/legacy/unit-tests/customer/crud.php @@ -324,16 +324,16 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case { update_option( 'woocommerce_tax_based_on', 'shipping' ); $taxable = $customer->get_taxable_address(); $this->assertEquals( 'US', $taxable[0] ); - $this->assertEquals( 'PA', $taxable[1] ); + $this->assertEquals( 'CA', $taxable[1] ); $this->assertEquals( '11111', $taxable[2] ); $this->assertEquals( 'Test', $taxable[3] ); update_option( 'woocommerce_tax_based_on', 'billing' ); $taxable = $customer->get_taxable_address(); $this->assertEquals( 'US', $taxable[0] ); - $this->assertEquals( 'PA', $taxable[1] ); - $this->assertEquals( '19123', $taxable[2] ); - $this->assertEquals( 'Philadelphia', $taxable[3] ); + $this->assertEquals( 'CA', $taxable[1] ); + $this->assertEquals( '94110', $taxable[2] ); + $this->assertEquals( 'San Francisco', $taxable[3] ); update_option( 'woocommerce_tax_based_on', 'base' ); $taxable = $customer->get_taxable_address(); @@ -431,7 +431,7 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case { */ public function test_customer_is_customer_outside_base() { $customer = WC_Helper_Customer::create_customer(); - $this->assertTrue( $customer->is_customer_outside_base() ); + $this->assertFalse( $customer->is_customer_outside_base() ); update_option( 'woocommerce_tax_based_on', 'base' ); $customer->set_billing_address_to_base(); $this->assertFalse( $customer->is_customer_outside_base() ); @@ -444,9 +444,9 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case { public function test_customer_sessions() { $session = WC_Helper_Customer::create_mock_customer(); // set into session.... - $this->assertEquals( '19123', $session->get_billing_postcode() ); + $this->assertEquals( '94110', $session->get_billing_postcode() ); $this->assertEquals( '123 South Street', $session->get_billing_address() ); - $this->assertEquals( 'Philadelphia', $session->get_billing_city() ); + $this->assertEquals( 'San Francisco', $session->get_billing_city() ); $session->set_billing_address( '124 South Street' ); $session->save(); diff --git a/tests/legacy/unit-tests/customer/customer.php b/tests/legacy/unit-tests/customer/customer.php index 05b093e102d..de73d7ccdaa 100644 --- a/tests/legacy/unit-tests/customer/customer.php +++ b/tests/legacy/unit-tests/customer/customer.php @@ -83,7 +83,7 @@ class WC_Tests_Customer extends WC_Unit_Test_Case { // Customer is going with the Free Shipping option, and the store calculates tax based on the customer's billing address. WC_Helper_Customer::set_chosen_shipping_methods( array( 'free_shipping' ) ); WC_Helper_Customer::set_tax_based_on( 'billing' ); - $this->assertEquals( $customer->is_customer_outside_base(), true ); + $this->assertEquals( $customer->is_customer_outside_base(), false ); // Customer is going with the Free Shipping option, and the store calculates tax based on the store base location. WC_Helper_Customer::set_chosen_shipping_methods( array( 'free_shipping' ) ); diff --git a/tests/legacy/unit-tests/formatting/functions.php b/tests/legacy/unit-tests/formatting/functions.php index 533f5ed1a5a..7ddc4ba9865 100644 --- a/tests/legacy/unit-tests/formatting/functions.php +++ b/tests/legacy/unit-tests/formatting/functions.php @@ -618,7 +618,7 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { // Ex tax label. $calc_taxes = get_option( 'woocommerce_calc_taxes' ); update_option( 'woocommerce_calc_taxes', 'yes' ); - $this->assertEquals( '£1,111.17 (ex. VAT)', wc_price( '1111.17', array( 'ex_tax_label' => true ) ) ); + $this->assertEquals( '£1,111.17 (ex. tax)', wc_price( '1111.17', array( 'ex_tax_label' => true ) ) ); update_option( 'woocommerce_calc_taxes', $calc_taxes ); } diff --git a/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php b/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php index 190f4257c19..2444987f2ae 100644 --- a/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php +++ b/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php @@ -1245,7 +1245,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $order->set_billing_country( 'US' ); $order->set_billing_city( 'Portland' ); $order->set_billing_postcode( '97266' ); - $this->assertEquals( '123 Test St.
Portland, 97266
United States (US)', $order->get_formatted_billing_address( 'none' ) ); + $this->assertEquals( '123 Test St.
Portland, 97266', $order->get_formatted_billing_address( 'none' ) ); $this->assertTrue( $order->has_billing_address() ); $this->assertFalse( $order->has_shipping_address() ); @@ -1265,7 +1265,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $order->set_shipping_country( 'US' ); $order->set_shipping_city( 'Portland' ); $order->set_shipping_postcode( '97266' ); - $this->assertEquals( '123 Test St.
Portland, 97266
United States (US)', $order->get_formatted_shipping_address( 'none' ) ); + $this->assertEquals( '123 Test St.
Portland, 97266', $order->get_formatted_shipping_address( 'none' ) ); $this->assertFalse( $order->has_billing_address() ); $this->assertTrue( $order->has_shipping_address() ); @@ -1498,7 +1498,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $object->set_billing_state( 'Boulder' ); $object->set_billing_postcode( '00001' ); $object->set_billing_country( 'US' ); - $this->assertEquals( 'Fred Flintstone
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001
United States (US)', $object->get_formatted_billing_address() ); + $this->assertEquals( 'Fred Flintstone
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001', $object->get_formatted_billing_address() ); } /** @@ -1515,7 +1515,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $object->set_shipping_state( 'Boulder' ); $object->set_shipping_postcode( '00001' ); $object->set_shipping_country( 'US' ); - $this->assertEquals( 'Barney Rubble
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001
United States (US)', $object->get_formatted_shipping_address() ); + $this->assertEquals( 'Barney Rubble
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001', $object->get_formatted_shipping_address() ); } /** diff --git a/tests/legacy/unit-tests/privacy/export.php b/tests/legacy/unit-tests/privacy/export.php index 0d8db0ee39e..68d8b7fe85a 100644 --- a/tests/legacy/unit-tests/privacy/export.php +++ b/tests/legacy/unit-tests/privacy/export.php @@ -86,15 +86,15 @@ class WC_Test_Privacy_Export extends WC_Unit_Test_Case { ), array( 'name' => 'Billing City', - 'value' => 'Philadelphia', + 'value' => 'San Francisco', ), array( 'name' => 'Billing Postal/Zip Code', - 'value' => '19123', + 'value' => '94110', ), array( 'name' => 'Billing State', - 'value' => 'PA', + 'value' => 'CA', ), array( 'name' => 'Billing Country / Region', @@ -114,15 +114,15 @@ class WC_Test_Privacy_Export extends WC_Unit_Test_Case { ), array( 'name' => 'Shipping City', - 'value' => 'Philadelphia', + 'value' => 'San Francisco', ), array( 'name' => 'Shipping Postal/Zip Code', - 'value' => '19123', + 'value' => '94110', ), array( 'name' => 'Shipping State', - 'value' => 'PA', + 'value' => 'CA', ), array( 'name' => 'Shipping Country / Region', diff --git a/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php b/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php index 5751cf31f32..2dfcbdbb4e6 100644 --- a/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php +++ b/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php @@ -26,15 +26,15 @@ class CustomerHelper { 'id' => 0, 'date_modified' => null, 'country' => 'US', - 'state' => 'PA', - 'postcode' => '19123', - 'city' => 'Philadelphia', + 'state' => 'CA', + 'postcode' => '94110', + 'city' => 'San Francisco', 'address' => '123 South Street', 'address_2' => 'Apt 1', 'shipping_country' => 'US', - 'shipping_state' => 'PA', - 'shipping_postcode' => '19123', - 'shipping_city' => 'Philadelphia', + 'shipping_state' => 'CA', + 'shipping_postcode' => '94110', + 'shipping_city' => 'San Francisco', 'shipping_address' => '123 South Street', 'shipping_address_2' => 'Apt 1', 'is_vat_exempt' => false, @@ -55,15 +55,15 @@ class CustomerHelper { $customer = new WC_Customer(); $customer->set_billing_country( 'US' ); $customer->set_first_name( 'Justin' ); - $customer->set_billing_state( 'PA' ); - $customer->set_billing_postcode( '19123' ); - $customer->set_billing_city( 'Philadelphia' ); + $customer->set_billing_state( 'CA' ); + $customer->set_billing_postcode( '94110' ); + $customer->set_billing_city( 'San Francisco' ); $customer->set_billing_address( '123 South Street' ); $customer->set_billing_address_2( 'Apt 1' ); $customer->set_shipping_country( 'US' ); - $customer->set_shipping_state( 'PA' ); - $customer->set_shipping_postcode( '19123' ); - $customer->set_shipping_city( 'Philadelphia' ); + $customer->set_shipping_state( 'CA' ); + $customer->set_shipping_postcode( '94110' ); + $customer->set_shipping_city( 'San Francisco' ); $customer->set_shipping_address( '123 South Street' ); $customer->set_shipping_address_2( 'Apt 1' ); $customer->set_username( $username ); @@ -79,7 +79,7 @@ class CustomerHelper { * @return array */ public static function get_expected_store_location() { - return array( 'GB', '', '', '' ); + return array( 'US', 'CA', '', '' ); } /** diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php b/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php index f9a4d5acca1..cebf6cdad9c 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php @@ -70,9 +70,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -83,9 +83,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, @@ -315,9 +315,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -328,9 +328,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php index 8d4508bade4..15e02ae4c9b 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php @@ -77,9 +77,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -90,9 +90,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, @@ -147,9 +147,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -160,9 +160,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, @@ -387,9 +387,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -400,9 +400,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, diff --git a/tests/legacy/unit-tests/tax/tax.php b/tests/legacy/unit-tests/tax/tax.php index 9269f766526..8862aa848cd 100644 --- a/tests/legacy/unit-tests/tax/tax.php +++ b/tests/legacy/unit-tests/tax/tax.php @@ -117,8 +117,8 @@ class WC_Tests_Tax extends WC_Unit_Test_Case { */ public function test_get_base_tax_rates() { $tax_rate = array( - 'tax_rate_country' => 'GB', - 'tax_rate_state' => '', + 'tax_rate_country' => 'US', + 'tax_rate_state' => 'CA', 'tax_rate' => '20.0000', 'tax_rate_name' => 'VAT', 'tax_rate_priority' => '1', diff --git a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php index a782089e51b..8f5b1419fbe 100644 --- a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php +++ b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php @@ -348,8 +348,8 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case { public function test_wc_get_base_location() { $default = wc_get_base_location(); - $this->assertEquals( 'GB', $default['country'] ); - $this->assertEquals( '', $default['state'] ); + $this->assertEquals( 'US', $default['country'] ); + $this->assertEquals( 'CA', $default['state'] ); } /** From aea8e1655fd3a2f02c95d098f97407bc76f5d034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Tue, 13 Apr 2021 20:06:33 +0200 Subject: [PATCH 15/52] Update WooCommerce Blocks package to 4.9.1 --- composer.json | 2 +- composer.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index da6ef18a12f..7d363c2ccba 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", "woocommerce/woocommerce-admin": "2.1.5", - "woocommerce/woocommerce-blocks": "4.7.2" + "woocommerce/woocommerce-blocks": "4.9.1" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4" diff --git a/composer.lock b/composer.lock index 874d83c7834..99c54366482 100644 --- a/composer.lock +++ b/composer.lock @@ -579,16 +579,16 @@ }, { "name": "woocommerce/woocommerce-blocks", - "version": "v4.7.2", + "version": "v4.9.1", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git", - "reference": "942e58553b1a299ad04842e7f0d7465d9e029ac3" + "reference": "62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/942e58553b1a299ad04842e7f0d7465d9e029ac3", - "reference": "942e58553b1a299ad04842e7f0d7465d9e029ac3", + "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce", + "reference": "62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce", "shasum": "" }, "require": { @@ -624,9 +624,9 @@ ], "support": { "issues": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues", - "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v4.7.2" + "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v4.9.1" }, - "time": "2021-04-13T16:06:16+00:00" + "time": "2021-04-13T16:11:16+00:00" } ], "packages-dev": [ From 8663c3b5f9f38229f390438363987a517f03b380 Mon Sep 17 00:00:00 2001 From: roykho Date: Tue, 13 Apr 2021 19:43:04 -0700 Subject: [PATCH 16/52] Assign default category to products closes #29540 --- includes/admin/class-wc-admin-taxonomies.php | 17 +++++++++ .../class-wc-rest-terms-controller.php | 7 ++++ includes/wc-term-functions.php | 35 +++++++++++++++++++ includes/wc-update-functions.php | 31 ++++------------ 4 files changed, 65 insertions(+), 25 deletions(-) diff --git a/includes/admin/class-wc-admin-taxonomies.php b/includes/admin/class-wc-admin-taxonomies.php index 82651dbc65d..68db2ac2ee7 100644 --- a/includes/admin/class-wc-admin-taxonomies.php +++ b/includes/admin/class-wc-admin-taxonomies.php @@ -49,6 +49,7 @@ class WC_Admin_Taxonomies { // Category/term ordering. add_action( 'create_term', array( $this, 'create_term' ), 5, 3 ); + add_action( 'delete_product_cat', array( $this, 'maybe_assign_default_product_cat' ) ); // Add form. add_action( 'product_cat_add_form_fields', array( $this, 'add_category_fields' ) ); @@ -110,6 +111,22 @@ class WC_Admin_Taxonomies { wc_deprecated_function( 'delete_term', '3.6' ); } + /** + * Assigns default product category. This is done when the product + * has no assgined product category. + * + * @since 5.3 + * @return void + */ + public function maybe_assign_default_product_cat() { + /* + * When a product category is deleted, we need to check + * if the product has no categories assigned. Then assign + * it a default category. + */ + _wc_maybe_assign_default_product_cat(); + } + /** * Category thumbnail fields. */ diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php index f434ef60b00..a6fc7b9524e 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php @@ -563,6 +563,13 @@ abstract class WC_REST_Terms_Controller extends WC_REST_Controller { return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce' ), array( 'status' => 500 ) ); } + /* + * When a product category is deleted, we need to check + * if the product has no categories assigned. Then assign + * it a default category. + */ + _wc_maybe_assign_default_product_cat(); + /** * Fires after a single term is deleted via the REST API. * diff --git a/includes/wc-term-functions.php b/includes/wc-term-functions.php index c6fd42ab966..ba6ab629b11 100644 --- a/includes/wc-term-functions.php +++ b/includes/wc-term-functions.php @@ -689,3 +689,38 @@ function _wc_recount_terms_by_product( $product_id = '' ) { _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), false, false ); } } + +/** + * Assigns default product category for products + * that have no categories. + * + * @since 5.3 + * @return void + */ +function _wc_maybe_assign_default_product_cat() { + global $wpdb; + + $default_category = get_option( 'default_product_cat', 0 ); + + if ( $default_category ) { + $wpdb->query( + $wpdb->prepare( + "INSERT INTO {$wpdb->term_relationships} (object_id, term_taxonomy_id) + SELECT DISTINCT posts.ID, %s FROM {$wpdb->posts} posts + LEFT JOIN + ( + SELECT object_id FROM {$wpdb->term_relationships} term_relationships + LEFT JOIN {$wpdb->term_taxonomy} term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id + WHERE term_taxonomy.taxonomy = 'product_cat' + ) AS tax_query + ON posts.ID = tax_query.object_id + WHERE posts.post_type = 'product' + AND tax_query.object_id IS NULL", + $default_category + ) + ); + wp_cache_flush(); + delete_transient( 'wc_term_counts' ); + wp_update_term_count_now( array( $default_category ), 'product_cat' ); + } +} diff --git a/includes/wc-update-functions.php b/includes/wc-update-functions.php index 439095d5482..c6b8ed58102 100644 --- a/includes/wc-update-functions.php +++ b/includes/wc-update-functions.php @@ -1567,31 +1567,12 @@ function wc_update_330_webhooks() { * Assign default cat to all products with no cats. */ function wc_update_330_set_default_product_cat() { - global $wpdb; - - $default_category = get_option( 'default_product_cat', 0 ); - - if ( $default_category ) { - $wpdb->query( - $wpdb->prepare( - "INSERT INTO {$wpdb->term_relationships} (object_id, term_taxonomy_id) - SELECT DISTINCT posts.ID, %s FROM {$wpdb->posts} posts - LEFT JOIN - ( - SELECT object_id FROM {$wpdb->term_relationships} term_relationships - LEFT JOIN {$wpdb->term_taxonomy} term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id - WHERE term_taxonomy.taxonomy = 'product_cat' - ) AS tax_query - ON posts.ID = tax_query.object_id - WHERE posts.post_type = 'product' - AND tax_query.object_id IS NULL", - $default_category - ) - ); - wp_cache_flush(); - delete_transient( 'wc_term_counts' ); - wp_update_term_count_now( array( $default_category ), 'product_cat' ); - } + /* + * When a product category is deleted, we need to check + * if the product has no categories assigned. Then assign + * it a default category. + */ + _wc_maybe_assign_default_product_cat(); } /** From 2c13c994b20c8127389cfa398d3f46dc207a6f54 Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Wed, 14 Apr 2021 10:05:03 -0300 Subject: [PATCH 17/52] add screenshot utility --- tests/e2e/env/CHANGELOG.md | 3 ++ tests/e2e/env/README.md | 6 +++ tests/e2e/env/package-lock.json | 2 +- tests/e2e/env/src/setup/jest.failure.js | 25 +++-------- tests/e2e/env/utils/index.js | 2 + tests/e2e/env/utils/take-screenshot.js | 37 +++++++++++++++ tests/e2e/utils/src/page-utils.js | 60 ++++++++----------------- 7 files changed, 74 insertions(+), 61 deletions(-) create mode 100644 tests/e2e/env/utils/take-screenshot.js diff --git a/tests/e2e/env/CHANGELOG.md b/tests/e2e/env/CHANGELOG.md index 4b0fa6d81e5..0448af10265 100644 --- a/tests/e2e/env/CHANGELOG.md +++ b/tests/e2e/env/CHANGELOG.md @@ -1,5 +1,8 @@ # Unreleased +## Added + +- `takeScreenshotFor` utility function to take screenshots within tests # 0.2.1 diff --git a/tests/e2e/env/README.md b/tests/e2e/env/README.md index 121e52440f1..ea1be7a0a9d 100644 --- a/tests/e2e/env/README.md +++ b/tests/e2e/env/README.md @@ -79,6 +79,12 @@ The test sequencer provides a screenshot function for test failures. To enable s WC_E2E_SCREENSHOTS=1 npx wc-e2e test:e2e ``` +To take adhoc in test screenshots use + +```js +await takeScreenshotFor( 'name of current step' ); +``` + Screenshots will be saved to `tests/e2e/screenshots`. This folder is cleared at the beginning of each test run. ### Jest Puppeteer Config diff --git a/tests/e2e/env/package-lock.json b/tests/e2e/env/package-lock.json index 0b7e8c5a069..2766327b895 100644 --- a/tests/e2e/env/package-lock.json +++ b/tests/e2e/env/package-lock.json @@ -1,6 +1,6 @@ { "name": "@woocommerce/e2e-environment", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tests/e2e/env/src/setup/jest.failure.js b/tests/e2e/env/src/setup/jest.failure.js index 31a906a10ee..7eb0947a784 100644 --- a/tests/e2e/env/src/setup/jest.failure.js +++ b/tests/e2e/env/src/setup/jest.failure.js @@ -4,10 +4,8 @@ import { sendFailedTestMessageToSlack, } from '../slack'; -const path = require( 'path' ); -const mkdirp = require( 'mkdirp' ); import { bind } from 'jest-each'; -const { getAppRoot } = require( '../../utils' ); +const { takeScreenshotFor } = require( '../../utils' ); /** * Override the test case method so we can take screenshots of assertion failures. @@ -88,22 +86,11 @@ const screenshotTest = async ( testName, callback ) => { try { await callback(); } catch ( e ) { - const testTitle = testName.replace( /\.$/, '' ); - const appPath = getAppRoot(); - const savePath = path.resolve( appPath, 'tests/e2e/screenshots' ); - const filePath = path.join( - savePath, - `${ testTitle }.png`.replace( /[^a-z0-9.-]+/gi, '-' ) - ); - - mkdirp.sync( savePath ); - await page.screenshot( { - path: filePath, - fullPage: true, - } ); - - await sendFailedTestMessageToSlack( testTitle ); - await sendFailedTestScreenshotToSlack( filePath ); + const { title, filePath } = await takeScreenshotFor( testName ); + await sendFailedTestMessageToSlack( title ); + if ( filePath ) { + await sendFailedTestScreenshotToSlack( filePath ); + } throw ( e ); } diff --git a/tests/e2e/env/utils/index.js b/tests/e2e/env/utils/index.js index ce89ae395f7..bb6331f46bb 100644 --- a/tests/e2e/env/utils/index.js +++ b/tests/e2e/env/utils/index.js @@ -1,6 +1,7 @@ const getAppRoot = require( './app-root' ); const { getAppName, getAppBase } = require( './app-name' ); const { getTestConfig, getAdminConfig } = require( './test-config' ); +const takeScreenshotFor = require( './take-screenshot' ); module.exports = { getAppBase, @@ -8,4 +9,5 @@ module.exports = { getAppName, getTestConfig, getAdminConfig, + takeScreenshotFor, }; diff --git a/tests/e2e/env/utils/take-screenshot.js b/tests/e2e/env/utils/take-screenshot.js new file mode 100644 index 00000000000..634da95dfab --- /dev/null +++ b/tests/e2e/env/utils/take-screenshot.js @@ -0,0 +1,37 @@ +const path = require( 'path' ); +const mkdirp = require( 'mkdirp' ); +const getAppRoot = require( './app-root' ); + +/** + * Take a screenshot if browser context exists. + * @param message + * @returns {Promise<{filePath: string, title: string}|{filePath: *, title: *}>} + */ +const takeScreenshotFor = async ( message ) => { + const title = message.replace( /\.$/, '' ); + const appPath = getAppRoot(); + const savePath = path.resolve( appPath, 'tests/e2e/screenshots' ); + const filePath = path.join( + savePath, + `${ title }.png`.replace( /[^a-z0-9.-]+/gi, '-' ) + ); + + mkdirp.sync( savePath ); + try { + await page.screenshot({ + path: filePath, + fullPage: true, + }); + } catch ( error ) { + return { + title: 'no screenshot', + filePath: '', + }; + } + return { + title, + filePath, + }; +}; + +module.exports = takeScreenshotFor; diff --git a/tests/e2e/utils/src/page-utils.js b/tests/e2e/utils/src/page-utils.js index 4bf9024989e..7e7648462e0 100644 --- a/tests/e2e/utils/src/page-utils.js +++ b/tests/e2e/utils/src/page-utils.js @@ -9,7 +9,7 @@ import { pressKeyWithModifier } from '@wordpress/e2e-test-utils'; * @param {string} selector * @param {string} value */ -const clearAndFillInput = async ( selector, value ) => { +export const clearAndFillInput = async ( selector, value ) => { await page.waitForSelector( selector ); await page.focus( selector ); await pressKeyWithModifier( 'primary', 'a' ); @@ -21,14 +21,14 @@ const clearAndFillInput = async ( selector, value ) => { * * @param {string} tabName Tab label */ -const clickTab = async ( tabName ) => { +export const clickTab = async ( tabName ) => { await expect( page ).toClick( '.wc-tabs > li > a', { text: tabName } ); }; /** * Save changes on a WooCommerce settings page. */ -const settingsPageSaveChanges = async () => { +export const settingsPageSaveChanges = async () => { await page.focus( 'button.woocommerce-save-button' ); await Promise.all( [ page.waitForNavigation( { waitUntil: 'networkidle0' } ), @@ -39,7 +39,7 @@ const settingsPageSaveChanges = async () => { /** * Save changes on Permalink settings page. */ -const permalinkSettingsPageSaveChanges = async () => { +export const permalinkSettingsPageSaveChanges = async () => { await page.focus( '.wp-core-ui .button-primary' ); await Promise.all( [ page.waitForNavigation( { waitUntil: 'networkidle0' } ), @@ -52,7 +52,7 @@ const permalinkSettingsPageSaveChanges = async () => { * * @param {string} selector */ -const setCheckbox = async( selector ) => { +export const setCheckbox = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -66,7 +66,7 @@ const setCheckbox = async( selector ) => { * * @param {string} selector */ -const unsetCheckbox = async( selector ) => { +export const unsetCheckbox = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -78,7 +78,7 @@ const unsetCheckbox = async( selector ) => { /** * Wait for UI blocking to end. */ -const uiUnblocked = async () => { +export const uiUnblocked = async () => { await page.waitForFunction( () => ! Boolean( document.querySelector( '.blockUI' ) ) ); }; @@ -90,7 +90,7 @@ const uiUnblocked = async () => { * @param {string} publishVerification * @param {string} trashVerification */ -const verifyPublishAndTrash = async ( button, publishNotice, publishVerification, trashVerification ) => { +export const verifyPublishAndTrash = async ( button, publishNotice, publishVerification, trashVerification ) => { // Wait for auto save await page.waitFor( 2000 ); @@ -124,7 +124,7 @@ const verifyPublishAndTrash = async ( button, publishNotice, publishVerification * * @param {string} selector Selector of the checkbox that needs to be verified. */ -const verifyCheckboxIsSet = async( selector ) => { +export const verifyCheckboxIsSet = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -136,7 +136,7 @@ const verifyCheckboxIsSet = async( selector ) => { * * @param {string} selector Selector of the checkbox that needs to be verified. */ -const verifyCheckboxIsUnset = async( selector ) => { +export const verifyCheckboxIsUnset = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -149,7 +149,7 @@ const verifyCheckboxIsUnset = async( selector ) => { * @param {string} selector Selector of the input field that needs to be verified. * @param {string} value Value of the input field that needs to be verified. */ -const verifyValueOfInputField = async( selector, value ) => { +export const verifyValueOfInputField = async( selector, value ) => { await page.focus( selector ); const field = await page.$( selector ); const fieldValue = ( await ( await field.getProperty( 'value' ) ).jsonValue() ); @@ -161,7 +161,7 @@ const verifyValueOfInputField = async( selector, value ) => { * * @param {string} selector Selector of the filter link to be clicked. */ -const clickFilter = async ( selector ) => { +export const clickFilter = async ( selector ) => { await page.waitForSelector( selector ); await page.focus( selector ); await Promise.all( [ @@ -175,7 +175,7 @@ const clickFilter = async ( selector ) => { * * If there's more than 20 items, it moves all 20 items on the current page. */ -const moveAllItemsToTrash = async () => { +export const moveAllItemsToTrash = async () => { await setCheckbox( '#cb-select-all-1' ); await expect( page ).toSelect( '#bulk-action-selector-top', 'Move to Trash' ); await Promise.all( [ @@ -191,7 +191,7 @@ const moveAllItemsToTrash = async () => { * * @param {string} selector Selector of the filter link to be clicked. */ -const evalAndClick = async ( selector ) => { +export const evalAndClick = async ( selector ) => { // We use this when `expect(page).toClick()` is unable to find the element // See: https://github.com/puppeteer/puppeteer/issues/1769#issuecomment-637645219 page.$eval( selector, elem => elem.click() ); @@ -203,7 +203,7 @@ const evalAndClick = async ( selector ) => { * @param {string} value Value of what to be selected * @param {string} selector Selector of the select2 search field */ -const selectOptionInSelect2 = async ( value, selector = 'input.select2-search__field' ) => { +export const selectOptionInSelect2 = async ( value, selector = 'input.select2-search__field' ) => { await page.waitForSelector(selector); await page.click(selector); await page.type(selector, value); @@ -218,7 +218,7 @@ const selectOptionInSelect2 = async ( value, selector = 'input.select2-search__f * @param {string} orderId Order ID * @param {string} customerName Customer's full name attached to order ID. */ -const searchForOrder = async (value, orderId, customerName) => { +export const searchForOrder = async (value, orderId, customerName) => { await clearAndFillInput('#post-search-input', value); await expect(page).toMatchElement('#post-search-input', value); await expect(page).toClick('#search-submit'); @@ -234,7 +234,7 @@ const searchForOrder = async (value, orderId, customerName) => { * @param couponCode string * @returns {Promise} */ -const applyCoupon = async ( couponCode ) => { +export const applyCoupon = async ( couponCode ) => { try { await expect(page).toClick('a', {text: 'Click here to enter your code'}); await uiUnblocked(); @@ -254,7 +254,7 @@ const applyCoupon = async ( couponCode ) => { * @param couponCode Coupon name. * @returns {Promise} */ -const removeCoupon = async ( couponCode ) => { +export const removeCoupon = async ( couponCode ) => { await expect(page).toClick('[data-coupon="'+couponCode.toLowerCase()+'"]', {text: '[Remove]'}); await uiUnblocked(); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon has been removed.'}); @@ -266,32 +266,10 @@ const removeCoupon = async ( couponCode ) => { * * @param {string} action The action to take on the order. */ -const selectOrderAction = async ( action ) => { +export const selectOrderAction = async ( action ) => { await page.select( 'select[name=wc_order_action]', action ); await Promise.all( [ page.click( '.wc-reload' ), page.waitForNavigation( { waitUntil: 'networkidle0' } ), ] ); } - -export { - clearAndFillInput, - clickTab, - settingsPageSaveChanges, - permalinkSettingsPageSaveChanges, - setCheckbox, - unsetCheckbox, - uiUnblocked, - verifyPublishAndTrash, - verifyCheckboxIsSet, - verifyCheckboxIsUnset, - verifyValueOfInputField, - clickFilter, - moveAllItemsToTrash, - evalAndClick, - selectOptionInSelect2, - searchForOrder, - applyCoupon, - removeCoupon, - selectOrderAction, -}; From 0bb3180d68210a4be9e381e88a4e850065e04005 Mon Sep 17 00:00:00 2001 From: roykho Date: Wed, 14 Apr 2021 06:52:39 -0700 Subject: [PATCH 18/52] Schedule cron jobs for running the assign default cat function --- includes/admin/class-wc-admin-taxonomies.php | 14 ++++++++++---- .../Version3/class-wc-rest-terms-controller.php | 10 ++++++++-- includes/wc-term-functions.php | 7 +++++-- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/includes/admin/class-wc-admin-taxonomies.php b/includes/admin/class-wc-admin-taxonomies.php index 68db2ac2ee7..00acdd7d318 100644 --- a/includes/admin/class-wc-admin-taxonomies.php +++ b/includes/admin/class-wc-admin-taxonomies.php @@ -92,7 +92,7 @@ class WC_Admin_Taxonomies { * @param string $taxonomy Taxonomy slug. */ public function create_term( $term_id, $tt_id = '', $taxonomy = '' ) { - if ( 'product_cat' != $taxonomy && ! taxonomy_is_product_attribute( $taxonomy ) ) { + if ( 'product_cat' !== $taxonomy && ! taxonomy_is_product_attribute( $taxonomy ) ) { return; } @@ -115,16 +115,22 @@ class WC_Admin_Taxonomies { * Assigns default product category. This is done when the product * has no assgined product category. * - * @since 5.3 + * @since 5.4 * @return void */ public function maybe_assign_default_product_cat() { /* * When a product category is deleted, we need to check * if the product has no categories assigned. Then assign - * it a default category. + * it a default category. We delay this with a scheduled + * action job to not block the response. */ - _wc_maybe_assign_default_product_cat(); + WC()->queue()->schedule_single( + time(), + 'wc_schedule_update_product_default_cat', + array(), + 'wc_update_product_default_cat' + ); } /** diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php index a6fc7b9524e..c5f05c2156f 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php @@ -566,9 +566,15 @@ abstract class WC_REST_Terms_Controller extends WC_REST_Controller { /* * When a product category is deleted, we need to check * if the product has no categories assigned. Then assign - * it a default category. + * it a default category. We delay this with a scheduled + * action job to not block the response. */ - _wc_maybe_assign_default_product_cat(); + WC()->queue()->schedule_single( + time(), + 'wc_schedule_update_product_default_cat', + array(), + 'wc_update_product_default_cat' + ); /** * Fires after a single term is deleted via the REST API. diff --git a/includes/wc-term-functions.php b/includes/wc-term-functions.php index ba6ab629b11..369193df15a 100644 --- a/includes/wc-term-functions.php +++ b/includes/wc-term-functions.php @@ -486,7 +486,8 @@ function _wc_term_recount( $terms, $taxonomy, $callback = true, $terms_are_term_ $term_query['join'] .= " INNER JOIN ( SELECT object_id FROM {$wpdb->term_relationships} INNER JOIN {$wpdb->term_taxonomy} using( term_taxonomy_id ) WHERE term_id IN ( " . implode( ',', array_map( 'absint', $terms_to_count ) ) . ' ) ) AS include_join ON include_join.object_id = p.ID'; // Get the count. - $count = $wpdb->get_var( implode( ' ', $term_query ) ); // WPCS: unprepared SQL ok. + // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared + $count = $wpdb->get_var( implode( ' ', $term_query ) ); // Update the count. update_term_meta( $term_id, 'product_count_' . $taxonomy->name, absint( $count ) ); @@ -694,7 +695,7 @@ function _wc_recount_terms_by_product( $product_id = '' ) { * Assigns default product category for products * that have no categories. * - * @since 5.3 + * @since 5.4 * @return void */ function _wc_maybe_assign_default_product_cat() { @@ -724,3 +725,5 @@ function _wc_maybe_assign_default_product_cat() { wp_update_term_count_now( array( $default_category ), 'product_cat' ); } } + +add_action( 'wc_schedule_update_product_default_cat', '_wc_maybe_assign_default_product_cat' ); From fc5499f9b8eddb6eba023d5643d732f44c7fe1ce Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Wed, 24 Mar 2021 12:47:15 -0400 Subject: [PATCH 19/52] Bump WooCommerce Admin version to 2.2.0-beta.2 --- composer.json | 2 +- composer.lock | 40 +++++----------------------------------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index da6ef18a12f..7a0af66954e 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "pelago/emogrifier": "3.1.0", "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", - "woocommerce/woocommerce-admin": "2.1.5", + "woocommerce/woocommerce-admin": "2.2.0-beta.2", "woocommerce/woocommerce-blocks": "4.7.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 874d83c7834..dfc2253c628 100644 --- a/composer.lock +++ b/composer.lock @@ -85,9 +85,6 @@ "GPL-2.0-or-later" ], "description": "A wrapper for defining constants in a more testable way.", - "support": { - "source": "https://github.com/Automattic/jetpack-constants/tree/v1.5.1" - }, "time": "2020-10-28T19:00:31+00:00" }, { @@ -218,10 +215,6 @@ "zend", "zikula" ], - "support": { - "issues": "https://github.com/composer/installers/issues", - "source": "https://github.com/composer/installers/tree/v1.10.0" - }, "funding": [ { "url": "https://packagist.com", @@ -296,10 +289,6 @@ "geolocation", "maxmind" ], - "support": { - "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", - "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.6.0" - }, "time": "2019-12-19T22:59:03+00:00" }, { @@ -374,10 +363,6 @@ "email", "pre-processing" ], - "support": { - "issues": "https://github.com/MyIntervals/emogrifier/issues", - "source": "https://github.com/MyIntervals/emogrifier" - }, "time": "2019-12-26T19:37:31+00:00" }, { @@ -427,10 +412,6 @@ "container-interop", "psr" ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" - }, "time": "2017-02-14T16:28:37+00:00" }, { @@ -484,9 +465,6 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/css-selector/tree/master" - }, "time": "2017-05-01T15:01:29+00:00" }, { @@ -522,24 +500,20 @@ ], "description": "Action Scheduler for WordPress and WooCommerce", "homepage": "https://actionscheduler.org/", - "support": { - "issues": "https://github.com/woocommerce/action-scheduler/issues", - "source": "https://github.com/woocommerce/action-scheduler/tree/master" - }, "time": "2020-05-12T16:22:33+00:00" }, { "name": "woocommerce/woocommerce-admin", - "version": "2.1.5", + "version": "2.2.0-beta.2", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-admin.git", - "reference": "71c233d8463f551430edbe1877e51d19a4bb2df6" + "reference": "6229ea56742380149c966af0e5fdca725f54f754" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/71c233d8463f551430edbe1877e51d19a4bb2df6", - "reference": "71c233d8463f551430edbe1877e51d19a4bb2df6", + "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/6229ea56742380149c966af0e5fdca725f54f754", + "reference": "6229ea56742380149c966af0e5fdca725f54f754", "shasum": "" }, "require": { @@ -674,10 +648,6 @@ "isolation", "tool" ], - "support": { - "issues": "https://github.com/bamarni/composer-bin-plugin/issues", - "source": "https://github.com/bamarni/composer-bin-plugin/tree/master" - }, "time": "2020-05-03T08:27:20+00:00" } ], @@ -693,5 +663,5 @@ "platform-overrides": { "php": "7.0" }, - "plugin-api-version": "2.0.0" + "plugin-api-version": "1.1.0" } From 63dbdddf64ba784ca919e3baa2b5d7b8c99f1cfc Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Fri, 26 Mar 2021 12:28:22 -0400 Subject: [PATCH 20/52] Update to rc1 --- composer.json | 2 +- composer.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 7a0af66954e..e3cb0ce95a7 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "pelago/emogrifier": "3.1.0", "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", - "woocommerce/woocommerce-admin": "2.2.0-beta.2", + "woocommerce/woocommerce-admin": "2.2.0-rc.1", "woocommerce/woocommerce-blocks": "4.7.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index dfc2253c628..5b66b273b3c 100644 --- a/composer.lock +++ b/composer.lock @@ -504,16 +504,16 @@ }, { "name": "woocommerce/woocommerce-admin", - "version": "2.2.0-beta.2", + "version": "2.2.0-rc.1", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-admin.git", - "reference": "6229ea56742380149c966af0e5fdca725f54f754" + "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/6229ea56742380149c966af0e5fdca725f54f754", - "reference": "6229ea56742380149c966af0e5fdca725f54f754", + "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/d1364ec144a0a580fac1b47f657a652363fcc7cd", + "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd", "shasum": "" }, "require": { From 1d4368f38408ff9769989986f1d2eccf3c9f7718 Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Wed, 14 Apr 2021 12:55:12 -0400 Subject: [PATCH 21/52] Bump WooCommerce Admin version to 2.2.1 --- composer.json | 2 +- composer.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index e3cb0ce95a7..ec4f2ec5cd3 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "pelago/emogrifier": "3.1.0", "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", - "woocommerce/woocommerce-admin": "2.2.0-rc.1", + "woocommerce/woocommerce-admin": "2.2.1", "woocommerce/woocommerce-blocks": "4.7.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 5b66b273b3c..43c7cdd1659 100644 --- a/composer.lock +++ b/composer.lock @@ -504,16 +504,16 @@ }, { "name": "woocommerce/woocommerce-admin", - "version": "2.2.0-rc.1", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-admin.git", - "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd" + "reference": "78cc9c5ef7de5be5bd0f9208483e5ae97422be9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/d1364ec144a0a580fac1b47f657a652363fcc7cd", - "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd", + "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/78cc9c5ef7de5be5bd0f9208483e5ae97422be9a", + "reference": "78cc9c5ef7de5be5bd0f9208483e5ae97422be9a", "shasum": "" }, "require": { From d37a31927eeaae1924ff8477478af9f9445e9edc Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Wed, 14 Apr 2021 13:10:35 -0400 Subject: [PATCH 22/52] Update composer.lock --- composer.lock | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 43c7cdd1659..bbba8925e66 100644 --- a/composer.lock +++ b/composer.lock @@ -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": "aaad3b20adf49ba997d4be94865087c6", + "content-hash": "11158f53934e897bd84be190a184ec87", "packages": [ { "name": "automattic/jetpack-autoloader", @@ -51,9 +51,6 @@ "GPL-2.0-or-later" ], "description": "Creates a custom autoloader for a plugin or theme.", - "support": { - "source": "https://github.com/Automattic/jetpack-autoloader/tree/2.10.1" - }, "time": "2021-03-30T15:15:59+00:00" }, { @@ -545,11 +542,7 @@ ], "description": "A modern, javascript-driven WooCommerce Admin experience.", "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.1.5" - }, - "time": "2021-04-02T16:48:38+00:00" + "time": "2021-04-02T19:30:03+00:00" }, { "name": "woocommerce/woocommerce-blocks", @@ -596,10 +589,6 @@ "gutenberg", "woocommerce" ], - "support": { - "issues": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues", - "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v4.7.2" - }, "time": "2021-04-13T16:06:16+00:00" } ], From 427be84875885ec865cdbc4598042a4c85320083 Mon Sep 17 00:00:00 2001 From: roykho Date: Wed, 14 Apr 2021 11:53:18 -0700 Subject: [PATCH 23/52] Add unit tests --- tests/php/includes/wc-term-functions-test.php | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tests/php/includes/wc-term-functions-test.php diff --git a/tests/php/includes/wc-term-functions-test.php b/tests/php/includes/wc-term-functions-test.php new file mode 100644 index 00000000000..a1f9e97a468 --- /dev/null +++ b/tests/php/includes/wc-term-functions-test.php @@ -0,0 +1,56 @@ +query( + $wpdb->prepare( + "DELETE FROM {$wpdb->term_relationships} WHERE object_id = %d AND term_taxonomy_id = %d", + $product->get_id(), + $default_category + ) + ); + } + + // Ensure all categories are removed from products. + foreach ( $products as $product ) { + $cats = wp_get_post_terms( $product->get_id(), 'product_cat' ); + + $this->assertEmpty( $cats ); + } + + // Add in default category. + _wc_maybe_assign_default_product_cat(); + + // Ensure default category are now assigned to products. + foreach ( $products as $product ) { + $cats = wp_list_pluck( wp_get_post_terms( $product->get_id(), 'product_cat' ), 'term_id' ); + + $this->assertContains( $default_category, $cats ); + } + } +} From a07523243420b8ad64c4c60475a1ed829aaa2c74 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 10:06:06 +0200 Subject: [PATCH 24/52] Updated code for calculating prices --- .../shopper/front-end-cart-calculate-shipping.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 879f5f17f5d..4efc8ac54e9 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -26,10 +26,10 @@ const config = require( 'config' ); const firstProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; const secondProductPrice = '4.99'; const fourProductPrice = firstProductPrice * 4; -var twoProductsPrice = eval([firstProductPrice,secondProductPrice].join('+')); -var firstProductPriceWithFlatRate = eval([firstProductPrice,5].join('+')); -var fourProductPriceWithFlatRate = eval([fourProductPrice,5].join('+')); -var twoProductsPriceWithFlatRate = eval([twoProductsPrice,5].join('+')); +var twoProductsPrice = (+firstProductPrice) + (+secondProductPrice); +var firstProductPriceWithFlatRate = (+firstProductPrice) + (+5); +var fourProductPriceWithFlatRate = (+fourProductPrice) + (+5); +var twoProductsPriceWithFlatRate = (+twoProductsPrice) + (+5); const firstProductName = 'First Product'; const secondProductName = 'Second Product'; const shippingZoneNameDE = 'Germany Free Shipping'; From c887830d68aad6e568949df620aeeb1f21407ee9 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Thu, 15 Apr 2021 10:35:33 +0200 Subject: [PATCH 25/52] Update changelog and readme for 5.2.2, change stable tag to 5.2.2 --- changelog.txt | 6 ++++++ readme.txt | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 4cfdac0fc66..4b636018665 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ == Changelog == += 5.2.2 2021-04-15 = + +**WooCommerce** + +* Fix - Can't grant permission for download from order details page. #29691 + = 5.2.1 2021-04-14 = **WooCommerce** diff --git a/readme.txt b/readme.txt index 76ce7b54471..6c7b73bf3ba 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: e-commerce, store, sales, sell, woo, shop, cart, checkout, downloadable, d Requires at least: 5.5 Tested up to: 5.7 Requires PHP: 7.0 -Stable tag: 5.2.1 +Stable tag: 5.2.2 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -160,6 +160,12 @@ WooCommerce comes with some sample data you can use to see how products look; im == Changelog == += 5.2.2 2021-04-15 = + +**WooCommerce** + +* Fix - Can't grant permission for download from order details page. #29691 + = 5.2.1 2021-04-14 = **WooCommerce** From 950d08b7a5d5babcd1cf75550baad174e65099b9 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 13:28:25 +0200 Subject: [PATCH 26/52] Add new e2e test shopper order email receiving --- tests/e2e/core-tests/CHANGELOG.md | 1 + tests/e2e/core-tests/README.md | 1 + tests/e2e/core-tests/specs/index.js | 7 ++- .../front-end-order-email-receiving.test.js | 57 +++++++++++++++++++ .../front-end/test-order-email-receiving.js | 6 ++ 5 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js create mode 100644 tests/e2e/specs/front-end/test-order-email-receiving.js diff --git a/tests/e2e/core-tests/CHANGELOG.md b/tests/e2e/core-tests/CHANGELOG.md index 789e7afc3fb..d2a04ff9f9a 100644 --- a/tests/e2e/core-tests/CHANGELOG.md +++ b/tests/e2e/core-tests/CHANGELOG.md @@ -3,6 +3,7 @@ ## Added - Support for re-running setup and shopper tests +- Shopper Order Email Receiving ## Fixed diff --git a/tests/e2e/core-tests/README.md b/tests/e2e/core-tests/README.md index ef2cd6a45be..091025e0718 100644 --- a/tests/e2e/core-tests/README.md +++ b/tests/e2e/core-tests/README.md @@ -86,6 +86,7 @@ The functions to access the core tests are: - `runCheckoutLoginAccountTest` - Shopper can login to an account during checkout - `runMyAccountCreateAccountTest` - Shopper can create an account via my account page - `runCartRedirectionTest` - Shopper is redirected to the cart page after adding to cart + - `runOrderEmailReceivingTest` - Shopper can receive an email for his order ### REST API diff --git a/tests/e2e/core-tests/specs/index.js b/tests/e2e/core-tests/specs/index.js index 8ffcff1742c..4e1debc641c 100644 --- a/tests/e2e/core-tests/specs/index.js +++ b/tests/e2e/core-tests/specs/index.js @@ -22,6 +22,7 @@ const runVariableProductUpdateTest = require( './shopper/front-end-variable-prod const runCheckoutCreateAccountTest = require( './shopper/front-end-checkout-create-account.test' ); const runCheckoutLoginAccountTest = require( './shopper/front-end-checkout-login-account.test' ); const runCartRedirectionTest = require( './shopper/front-end-cart-redirection.test' ); +const runOrderEmailReceivingTest = require( './shopper/front-end-order-email-receiving.test' ); // Merchant tests const runAddNewShippingZoneTest = require ( './merchant/wp-admin-settings-shipping-zones.test' ); @@ -70,7 +71,8 @@ const runShopperTests = () => { runVariableProductUpdateTest(); runCheckoutCreateAccountTest(); runCheckoutLoginAccountTest(); - runCartRedirectionTest(); + runCartRedirectionTest(); + runOrderEmailReceivingTest(); }; const runMerchantTests = () => { @@ -144,8 +146,9 @@ module.exports = { runAddShippingClassesTest, runAnalyticsPageLoadsTest, runCheckoutCreateAccountTest, - runImportProductsTest, + runImportProductsTest, runCheckoutLoginAccountTest, runCartRedirectionTest, runMyAccountCreateAccountTest, + runOrderEmailReceivingTest, }; diff --git a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js new file mode 100644 index 00000000000..ff517948dcd --- /dev/null +++ b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js @@ -0,0 +1,57 @@ +/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */ +/** + * Internal dependencies + */ + const { + shopper, + merchant, + createSimpleProduct, + uiUnblocked, +} = require( '@woocommerce/e2e-utils' ); + +let simplePostIdValue; +let orderId; +const config = require( 'config' ); +const simpleProductName = config.get( 'products.simple.name' ); +const customerEmail = config.get( 'addresses.customer.billing.email' ); +const storeName = 'WooCommerce Core E2E Test Suite'; + +/** + * External dependencies + */ +const { + it, + describe, + beforeAll, +} = require( '@jest/globals' ); + +const runOrderEmailReceivingTest = () => { + describe('Shopper Order Email Receiving', () => { + beforeAll(async () => { + await merchant.login(); + simplePostIdValue = await createSimpleProduct(); + await merchant.logout(); + }); + + it('should receive order email after purchasing an item', async () => { + await shopper.login(); + + // Go to the shop and purchase an item + await shopper.goToProduct(simplePostIdValue); + await shopper.addToCart(simpleProductName); + await shopper.goToCheckout(); + await uiUnblocked(); + await shopper.placeOrder(); + // Get order ID from the order received html element on the page + orderId = await page.$$eval(".woocommerce-order-overview__order strong", elements => elements.map(item => item.textContent)); + + // Verify the new order email has been received + await merchant.login(); + await merchant.openEmailLog(); + await expect( page ).toMatchElement( '.column-receiver', { text: customerEmail } ); + await expect( page ).toMatchElement( '.column-subject', { text: `[${storeName}]: New order #${orderId}` } ); + }); + }); +}; + +module.exports = runOrderEmailReceivingTest; diff --git a/tests/e2e/specs/front-end/test-order-email-receiving.js b/tests/e2e/specs/front-end/test-order-email-receiving.js new file mode 100644 index 00000000000..a85e21d0c22 --- /dev/null +++ b/tests/e2e/specs/front-end/test-order-email-receiving.js @@ -0,0 +1,6 @@ +/* + * Internal dependencies + */ +const { runOrderEmailReceivingTest } = require( '@woocommerce/e2e-core-tests' ); + +runOrderEmailReceivingTest(); From 5c633e1c3b628254776a70477a73662ee3105454 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 14:01:28 +0200 Subject: [PATCH 27/52] Add deleting email logs if any --- .../specs/shopper/front-end-order-email-receiving.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js index ff517948dcd..69b9124f0e3 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js @@ -7,6 +7,7 @@ merchant, createSimpleProduct, uiUnblocked, + deleteAllEmailLogs, } = require( '@woocommerce/e2e-utils' ); let simplePostIdValue; @@ -29,6 +30,7 @@ const runOrderEmailReceivingTest = () => { describe('Shopper Order Email Receiving', () => { beforeAll(async () => { await merchant.login(); + await deleteAllEmailLogs(); simplePostIdValue = await createSimpleProduct(); await merchant.logout(); }); From 1bc0b25f0cd1a12a352079cd12dde72783c737dc Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 14:30:06 +0200 Subject: [PATCH 28/52] Fix spaces --- .../specs/shopper/front-end-order-email-receiving.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js index 69b9124f0e3..da466cae6de 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js @@ -7,7 +7,7 @@ merchant, createSimpleProduct, uiUnblocked, - deleteAllEmailLogs, + deleteAllEmailLogs, } = require( '@woocommerce/e2e-utils' ); let simplePostIdValue; @@ -30,7 +30,7 @@ const runOrderEmailReceivingTest = () => { describe('Shopper Order Email Receiving', () => { beforeAll(async () => { await merchant.login(); - await deleteAllEmailLogs(); + await deleteAllEmailLogs(); simplePostIdValue = await createSimpleProduct(); await merchant.logout(); }); From a0c965964b6c97cb28ca38b0605d1cfe30493074 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Thu, 15 Apr 2021 17:16:00 +0200 Subject: [PATCH 29/52] Add a GitHub action for automatic assignment of milestone to merged PRs The milestone is chosen as follows: 1. List all the open milestones with a title of "X.Y.Z" 2. Sort them desc using verson_compare 3. foreach them in order, and take the last one not having a corresponding release branch ("release/X.Y") --- .../pull-request-post-merge-processing.yml | 32 ++++ .../scripts/assign-milestone-to-merged-pr.php | 144 ++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 .github/workflows/pull-request-post-merge-processing.yml create mode 100644 .github/workflows/scripts/assign-milestone-to-merged-pr.php diff --git a/.github/workflows/pull-request-post-merge-processing.yml b/.github/workflows/pull-request-post-merge-processing.yml new file mode 100644 index 00000000000..d7ada48dbd4 --- /dev/null +++ b/.github/workflows/pull-request-post-merge-processing.yml @@ -0,0 +1,32 @@ +name: "Pull request post-merge processing" +on: + pull_request: + types: [closed] + +jobs: + assign-milestone: + name: "Assign milestone to merged pull request" + if: github.event.pull_request.merged == true && ! github.event.pull_request.milestone + runs-on: ubuntu-latest + steps: + - name: "Get the milestone changer script" + run: | + curl \ + --silent \ + --fail \ + --header 'Authorization: bearer ${{ secrets.GITHUB_TOKEN }}' \ + --header 'User-Agent: GitHub action to set the milestone for a pull request' \ + --header 'Accept: application/vnd.github.v3.raw' \ + --remote-name \ + --location $GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/assign-milestone-to-merged-pr.php + env: + GITHUB_API_URL: ${{ env.GITHUB_API_URL }} + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + - name: "Run the milestone changer script" + run: php assign-milestone-to-merged-pr.php + env: + PULL_REQUEST_ID: ${{ github.event.pull_request.node_id }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/scripts/assign-milestone-to-merged-pr.php b/.github/workflows/scripts/assign-milestone-to-merged-pr.php new file mode 100644 index 00000000000..deb4ab0875a --- /dev/null +++ b/.github/workflows/scripts/assign-milestone-to-merged-pr.php @@ -0,0 +1,144 @@ + "$keyword { $body }" ); + $context = stream_context_create( + array( + 'http' => array( + 'method' => 'POST', + 'header' => array( + 'Accept: application/json', + 'Content-Type: application/json', + 'User-Agent: GitHub action to set the milestone for a pull request', + 'Authorization: bearer ' . $github_token, + ), + 'content' => json_encode( $data ), + ), + ) + ); + + $result = file_get_contents( $graphql_api_url, false, $context ); + return json_decode( $result, true ); +} + +// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions From b09ddd7984af145f5de1cc0c61d6088b3e4068d6 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Fri, 16 Apr 2021 13:06:49 +0200 Subject: [PATCH 30/52] Add a GitHub action to manually trigger the generation of a release zip file --- .github/workflows/build-release-zip-file.yml | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/build-release-zip-file.yml diff --git a/.github/workflows/build-release-zip-file.yml b/.github/workflows/build-release-zip-file.yml new file mode 100644 index 00000000000..2f6dd819e20 --- /dev/null +++ b/.github/workflows/build-release-zip-file.yml @@ -0,0 +1,30 @@ +name: Build release zip file +on: + workflow_dispatch: + inputs: + ref: + description: 'By default the zip file is generated from the branch the workflow runs from, but you can specify an explicit reference to use instead here (e.g. refs/tags/tag_name). The resulting file will be available as an artifact on the workflow run.' + required: false + default: '' +jobs: + build: + name: Build release zip file + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - name: Build the zip file + id: build + uses: woocommerce/action-build@v2 + - name: Unzip the file (prevents double zip problem) + run: unzip ${{ steps.build.outputs.zip_path }} -d zipfile + - name: Upload the zip file as an artifact + uses: actions/upload-artifact@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + name: woocommerce + path: zipfile + retention-days: 7 From 23e09d33ddef81450033fc0afe23f1f70428205f Mon Sep 17 00:00:00 2001 From: Veljko Date: Fri, 16 Apr 2021 14:11:27 +0200 Subject: [PATCH 31/52] Add shipping zones remover --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 4efc8ac54e9..4f5af5c8bca 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -11,6 +11,7 @@ const { clearAndFillInput, uiUnblocked, selectOptionInSelect2, + deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); /** @@ -43,6 +44,7 @@ const runCartCalculateShippingTest = () => { await merchant.login(); await createSimpleProduct(firstProductName); await createSimpleProduct(secondProductName, secondProductPrice); + await deleteAllShippingZones(); await merchant.openNewShipping(); // Add a new shipping zone Germany with Free shipping From 5da39b4ff0f9fc0e8e0c7472664375afee56fa6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Soriano?= Date: Fri, 16 Apr 2021 15:48:38 +0200 Subject: [PATCH 32/52] Enclose action step name in double quotes for consistency. Co-authored-by: Leif Singer --- .github/workflows/pull-request-post-merge-processing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-post-merge-processing.yml b/.github/workflows/pull-request-post-merge-processing.yml index d7ada48dbd4..1347ed5e5e1 100644 --- a/.github/workflows/pull-request-post-merge-processing.yml +++ b/.github/workflows/pull-request-post-merge-processing.yml @@ -21,7 +21,7 @@ jobs: --location $GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/assign-milestone-to-merged-pr.php env: GITHUB_API_URL: ${{ env.GITHUB_API_URL }} - - name: Install PHP + - name: "Install PHP" uses: shivammathur/setup-php@v2 with: php-version: '7.4' From 1c7bec0489b49e00b274255c733f5aaa96171ea5 Mon Sep 17 00:00:00 2001 From: Veljko Date: Fri, 16 Apr 2021 21:22:34 +0200 Subject: [PATCH 33/52] Remove shipping zones remover --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 4f5af5c8bca..4efc8ac54e9 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -11,7 +11,6 @@ const { clearAndFillInput, uiUnblocked, selectOptionInSelect2, - deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); /** @@ -44,7 +43,6 @@ const runCartCalculateShippingTest = () => { await merchant.login(); await createSimpleProduct(firstProductName); await createSimpleProduct(secondProductName, secondProductPrice); - await deleteAllShippingZones(); await merchant.openNewShipping(); // Add a new shipping zone Germany with Free shipping From c73ce8ea0489b472865305d16f1bb0ebdc65ae3c Mon Sep 17 00:00:00 2001 From: roykho Date: Fri, 16 Apr 2021 12:23:40 -0700 Subject: [PATCH 34/52] Convert to using internal DI container --- includes/admin/class-wc-admin-taxonomies.php | 20 ++---- includes/class-woocommerce.php | 2 + .../class-wc-rest-terms-controller.php | 16 ++--- includes/wc-term-functions.php | 37 ---------- includes/wc-update-functions.php | 4 +- src/Container.php | 2 + src/Internal/AssignDefaultCategory.php | 72 +++++++++++++++++++ .../AssignDefaultCategoryServiceProvider.php | 31 ++++++++ .../Internal/AssignDefaultCategoryTest.php} | 29 +++++--- 9 files changed, 139 insertions(+), 74 deletions(-) create mode 100644 src/Internal/AssignDefaultCategory.php create mode 100644 src/Internal/DependencyManagement/ServiceProviders/AssignDefaultCategoryServiceProvider.php rename tests/php/{includes/wc-term-functions-test.php => src/Internal/AssignDefaultCategoryTest.php} (61%) diff --git a/includes/admin/class-wc-admin-taxonomies.php b/includes/admin/class-wc-admin-taxonomies.php index 00acdd7d318..4163fdbbfee 100644 --- a/includes/admin/class-wc-admin-taxonomies.php +++ b/includes/admin/class-wc-admin-taxonomies.php @@ -11,6 +11,8 @@ if ( ! defined( 'ABSPATH' ) ) { exit; // Exit if accessed directly. } +use Automattic\WooCommerce\Internal\AssignDefaultCategory; + /** * WC_Admin_Taxonomies class. */ @@ -49,7 +51,7 @@ class WC_Admin_Taxonomies { // Category/term ordering. add_action( 'create_term', array( $this, 'create_term' ), 5, 3 ); - add_action( 'delete_product_cat', array( $this, 'maybe_assign_default_product_cat' ) ); + add_action( 'delete_product_cat', array( $this, 'assign_default_product_cat' ) ); // Add form. add_action( 'product_cat_add_form_fields', array( $this, 'add_category_fields' ) ); @@ -118,19 +120,9 @@ class WC_Admin_Taxonomies { * @since 5.4 * @return void */ - public function maybe_assign_default_product_cat() { - /* - * When a product category is deleted, we need to check - * if the product has no categories assigned. Then assign - * it a default category. We delay this with a scheduled - * action job to not block the response. - */ - WC()->queue()->schedule_single( - time(), - 'wc_schedule_update_product_default_cat', - array(), - 'wc_update_product_default_cat' - ); + public function assign_default_product_cat() { + // Schedule action to assign default category. + wc_get_container()->get( AssignDefaultCategory::class )->schedule_action(); } /** diff --git a/includes/class-woocommerce.php b/includes/class-woocommerce.php index be2df455f7d..8c74c11fd5b 100644 --- a/includes/class-woocommerce.php +++ b/includes/class-woocommerce.php @@ -9,6 +9,7 @@ defined( 'ABSPATH' ) || exit; use Automattic\WooCommerce\Internal\DownloadPermissionsAdjuster; +use Automattic\WooCommerce\Internal\AssignDefaultCategory; use Automattic\WooCommerce\Proxies\LegacyProxy; /** @@ -207,6 +208,7 @@ final class WooCommerce { // These classes set up hooks on instantiation. wc_get_container()->get( DownloadPermissionsAdjuster::class ); + wc_get_container()->get( AssignDefaultCategory::class ); } /** diff --git a/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php b/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php index c5f05c2156f..40423decb89 100644 --- a/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php +++ b/includes/rest-api/Controllers/Version3/class-wc-rest-terms-controller.php @@ -10,6 +10,8 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } +use Automattic\WooCommerce\Internal\AssignDefaultCategory; + /** * Terms controller class. */ @@ -563,18 +565,8 @@ abstract class WC_REST_Terms_Controller extends WC_REST_Controller { return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'The resource cannot be deleted.', 'woocommerce' ), array( 'status' => 500 ) ); } - /* - * When a product category is deleted, we need to check - * if the product has no categories assigned. Then assign - * it a default category. We delay this with a scheduled - * action job to not block the response. - */ - WC()->queue()->schedule_single( - time(), - 'wc_schedule_update_product_default_cat', - array(), - 'wc_update_product_default_cat' - ); + // Schedule action to assign default category. + wc_get_container()->get( AssignDefaultCategory::class )->schedule_action(); /** * Fires after a single term is deleted via the REST API. diff --git a/includes/wc-term-functions.php b/includes/wc-term-functions.php index 369193df15a..163a1e476c8 100644 --- a/includes/wc-term-functions.php +++ b/includes/wc-term-functions.php @@ -690,40 +690,3 @@ function _wc_recount_terms_by_product( $product_id = '' ) { _wc_term_recount( $product_tags, get_taxonomy( 'product_tag' ), false, false ); } } - -/** - * Assigns default product category for products - * that have no categories. - * - * @since 5.4 - * @return void - */ -function _wc_maybe_assign_default_product_cat() { - global $wpdb; - - $default_category = get_option( 'default_product_cat', 0 ); - - if ( $default_category ) { - $wpdb->query( - $wpdb->prepare( - "INSERT INTO {$wpdb->term_relationships} (object_id, term_taxonomy_id) - SELECT DISTINCT posts.ID, %s FROM {$wpdb->posts} posts - LEFT JOIN - ( - SELECT object_id FROM {$wpdb->term_relationships} term_relationships - LEFT JOIN {$wpdb->term_taxonomy} term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id - WHERE term_taxonomy.taxonomy = 'product_cat' - ) AS tax_query - ON posts.ID = tax_query.object_id - WHERE posts.post_type = 'product' - AND tax_query.object_id IS NULL", - $default_category - ) - ); - wp_cache_flush(); - delete_transient( 'wc_term_counts' ); - wp_update_term_count_now( array( $default_category ), 'product_cat' ); - } -} - -add_action( 'wc_schedule_update_product_default_cat', '_wc_maybe_assign_default_product_cat' ); diff --git a/includes/wc-update-functions.php b/includes/wc-update-functions.php index c6b8ed58102..afefd264c5a 100644 --- a/includes/wc-update-functions.php +++ b/includes/wc-update-functions.php @@ -10,6 +10,8 @@ defined( 'ABSPATH' ) || exit; +use Automattic\WooCommerce\Internal\AssignDefaultCategory; + /** * Update file paths for 2.0 * @@ -1572,7 +1574,7 @@ function wc_update_330_set_default_product_cat() { * if the product has no categories assigned. Then assign * it a default category. */ - _wc_maybe_assign_default_product_cat(); + wc_get_container()->get( AssignDefaultCategory::class )->maybe_assign_default_product_cat(); } /** diff --git a/src/Container.php b/src/Container.php index 517239afeb7..59e2d58045c 100644 --- a/src/Container.php +++ b/src/Container.php @@ -7,6 +7,7 @@ namespace Automattic\WooCommerce; use Automattic\WooCommerce\Internal\DependencyManagement\ExtendedContainer; use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\DownloadPermissionsAdjusterServiceProvider; +use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\AssignDefaultCategoryServiceProvider; use Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders\ProxiesServiceProvider; /** @@ -35,6 +36,7 @@ final class Container implements \Psr\Container\ContainerInterface { private $service_providers = array( ProxiesServiceProvider::class, DownloadPermissionsAdjusterServiceProvider::class, + AssignDefaultCategoryServiceProvider::class, ); /** diff --git a/src/Internal/AssignDefaultCategory.php b/src/Internal/AssignDefaultCategory.php new file mode 100644 index 00000000000..1c6f743b34a --- /dev/null +++ b/src/Internal/AssignDefaultCategory.php @@ -0,0 +1,72 @@ +queue()->schedule_single( + time(), + 'wc_schedule_update_product_default_cat', + array(), + 'wc_update_product_default_cat' + ); + } + + /** + * Assigns default product category for products + * that have no categories. + * + * @since 5.4 + * @return void + */ + public function maybe_assign_default_product_cat() { + global $wpdb; + + $default_category = get_option( 'default_product_cat', 0 ); + + if ( $default_category ) { + $wpdb->query( + $wpdb->prepare( + "INSERT INTO {$wpdb->term_relationships} (object_id, term_taxonomy_id) + SELECT DISTINCT posts.ID, %s FROM {$wpdb->posts} posts + LEFT JOIN + ( + SELECT object_id FROM {$wpdb->term_relationships} term_relationships + LEFT JOIN {$wpdb->term_taxonomy} term_taxonomy ON term_relationships.term_taxonomy_id = term_taxonomy.term_taxonomy_id + WHERE term_taxonomy.taxonomy = 'product_cat' + ) AS tax_query + ON posts.ID = tax_query.object_id + WHERE posts.post_type = 'product' + AND tax_query.object_id IS NULL", + $default_category + ) + ); + wp_cache_flush(); + delete_transient( 'wc_term_counts' ); + wp_update_term_count_now( array( $default_category ), 'product_cat' ); + } + } +} diff --git a/src/Internal/DependencyManagement/ServiceProviders/AssignDefaultCategoryServiceProvider.php b/src/Internal/DependencyManagement/ServiceProviders/AssignDefaultCategoryServiceProvider.php new file mode 100644 index 00000000000..cba9e812aab --- /dev/null +++ b/src/Internal/DependencyManagement/ServiceProviders/AssignDefaultCategoryServiceProvider.php @@ -0,0 +1,31 @@ +share( AssignDefaultCategory::class ); + } +} diff --git a/tests/php/includes/wc-term-functions-test.php b/tests/php/src/Internal/AssignDefaultCategoryTest.php similarity index 61% rename from tests/php/includes/wc-term-functions-test.php rename to tests/php/src/Internal/AssignDefaultCategoryTest.php index a1f9e97a468..1b638b56e19 100644 --- a/tests/php/includes/wc-term-functions-test.php +++ b/tests/php/src/Internal/AssignDefaultCategoryTest.php @@ -1,16 +1,24 @@ sut = new AssignDefaultCategory(); + $product1 = ProductHelper::create_simple_product(); + $product2 = ProductHelper::create_simple_product(); + $product3 = ProductHelper::create_simple_product(); $default_category = (int) get_option( 'default_product_cat', 0 ); $products = array( $product1, $product2, $product3 ); @@ -44,7 +53,7 @@ class WC_Term_Functions_Tests extends \WC_Unit_Test_Case { } // Add in default category. - _wc_maybe_assign_default_product_cat(); + $this->sut->maybe_assign_default_product_cat(); // Ensure default category are now assigned to products. foreach ( $products as $product ) { From 3ada9fc5623b42f14f247baaabcf05683fca2494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Soriano?= Date: Mon, 19 Apr 2021 14:46:45 +0200 Subject: [PATCH 35/52] Change GH API query for milestones to get only the open ones. Co-authored-by: Vedanshu Jain --- .github/workflows/scripts/assign-milestone-to-merged-pr.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scripts/assign-milestone-to-merged-pr.php b/.github/workflows/scripts/assign-milestone-to-merged-pr.php index deb4ab0875a..0258813e209 100644 --- a/.github/workflows/scripts/assign-milestone-to-merged-pr.php +++ b/.github/workflows/scripts/assign-milestone-to-merged-pr.php @@ -35,7 +35,7 @@ echo "Getting the list of milestones...\n"; $query = " repository(owner:\"$repo_owner\", name:\"$repo_name\") { - milestones(first: 10, orderBy: {field: CREATED_AT, direction: DESC}) { + milestones(first: 10, states: [OPEN], orderBy: {field: CREATED_AT, direction: DESC}) { nodes { id title @@ -48,7 +48,7 @@ $json = do_graphql_api_request( $query ); $milestones = $json['data']['repository']['milestones']['nodes']; $milestones = array_map( function( $x ) { - return 'OPEN' === $x['state'] && 1 === preg_match( '/^\d+\.\d+\.\d+$/D', $x['title'] ) ? $x : null; + return 1 === preg_match( '/^\d+\.\d+\.\d+$/D', $x['title'] ) ? $x : null; }, $milestones ); From 94e5991c660a83b0f94a44dbaff540de9354a23a Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Mon, 19 Apr 2021 12:15:07 -0300 Subject: [PATCH 36/52] package lock maintenance --- package-lock.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 2ec65648a08..9358ea03b15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "woocommerce", - "version": "5.1.0", + "version": "5.3.0", "lockfileVersion": 1, "requires": true, "dependencies": { From 1008835488447207853c99c99a16faf9fe346991 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Tue, 20 Apr 2021 09:42:07 +0200 Subject: [PATCH 37/52] Fix code sniffer violations in stock functions and its tests --- includes/wc-stock-functions.php | 2 +- tests/php/includes/wc-stock-functions-tests.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/includes/wc-stock-functions.php b/includes/wc-stock-functions.php index 70b268836d5..09027c5e7bd 100644 --- a/includes/wc-stock-functions.php +++ b/includes/wc-stock-functions.php @@ -403,7 +403,7 @@ function wc_get_low_stock_amount( WC_Product $product ) { $low_stock_amount = $product->get_low_stock_amount(); if ( '' === $low_stock_amount && $product->is_type( 'variation' ) ) { - $product = wc_get_product( $product->get_parent_id() ); + $product = wc_get_product( $product->get_parent_id() ); $low_stock_amount = $product->get_low_stock_amount(); } diff --git a/tests/php/includes/wc-stock-functions-tests.php b/tests/php/includes/wc-stock-functions-tests.php index 368eab017cf..ce2b747c9c2 100644 --- a/tests/php/includes/wc-stock-functions-tests.php +++ b/tests/php/includes/wc-stock-functions-tests.php @@ -228,8 +228,8 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $product = WC_Helper_Product::create_simple_product( true, array( - 'manage_stock' => true, - 'stock_quantity' => 10, + 'manage_stock' => true, + 'stock_quantity' => 10, ) ); @@ -254,7 +254,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { // Set the variation low stock amount. $variations = $variable_product->get_available_variations( 'objects' ); - $var1 = $variations[0]; + $var1 = $variations[0]; $var1->set_manage_stock( true ); $var1->set_low_stock_amount( $variation_low_stock_amount ); $var1->save(); @@ -292,7 +292,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { // Set the variation low stock amount. $variations = $variable_product->get_available_variations( 'objects' ); - $var1 = $variations[0]; + $var1 = $variations[0]; $var1->set_manage_stock( true ); $var1->set_low_stock_amount( $variation_low_stock_amount ); $var1->save(); @@ -319,7 +319,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { // Don't set the variation low stock amount. $variations = $variable_product->get_available_variations( 'objects' ); - $var1 = $variations[0]; + $var1 = $variations[0]; $this->assertEquals( $parent_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); } @@ -340,7 +340,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { // Don't set the variation low stock amount. $variations = $variable_product->get_available_variations( 'objects' ); - $var1 = $variations[0]; + $var1 = $variations[0]; $var1->set_manage_stock( false ); $this->assertEquals( $site_wide_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); From 76a613a5bb47afda75bf925e17861ec32d9fdb16 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Tue, 20 Apr 2021 10:17:50 +0200 Subject: [PATCH 38/52] Modify wc_get_low_stock_amount so that it always returns an integer. Previously, if the product didn't have an explicit low stock value amount the value of the woocommerce_notify_low_stock_amount option, which is a string, was returned verbatim. Also, update related unit tests to create the option value as a string, and to check that the value returned by woocommerce_notify_low_stock_amount is always an integer. --- includes/wc-stock-functions.php | 2 +- .../framework/class-wc-unit-test-case.php | 11 ++++++ .../php/includes/wc-stock-functions-tests.php | 39 ++++++++++++------- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/includes/wc-stock-functions.php b/includes/wc-stock-functions.php index 09027c5e7bd..8e158aa9e4d 100644 --- a/includes/wc-stock-functions.php +++ b/includes/wc-stock-functions.php @@ -411,5 +411,5 @@ function wc_get_low_stock_amount( WC_Product $product ) { $low_stock_amount = get_option( 'woocommerce_notify_low_stock_amount', 2 ); } - return $low_stock_amount; + return intval( $low_stock_amount ); } diff --git a/tests/legacy/framework/class-wc-unit-test-case.php b/tests/legacy/framework/class-wc-unit-test-case.php index 74289f2b413..5426c2ca6ae 100644 --- a/tests/legacy/framework/class-wc-unit-test-case.php +++ b/tests/legacy/framework/class-wc-unit-test-case.php @@ -246,4 +246,15 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase { public function register_legacy_proxy_class_mocks( array $mocks ) { wc_get_container()->get( LegacyProxy::class )->register_class_mocks( $mocks ); } + + /** + * Check if a value is of integer type. + * This function is already built-in in PHPUnit 8 so this one can be removed once we upgrade to that version of newer. + * + * @param mixed $value The value to check. + * @return bool mixed True if the value is of integer type, false otherwise. + */ + protected function assertIsInt( $value ) { + return $this->assertInternalType( 'int', $value ); + } } diff --git a/tests/php/includes/wc-stock-functions-tests.php b/tests/php/includes/wc-stock-functions-tests.php index ce2b747c9c2..74470a86cbc 100644 --- a/tests/php/includes/wc-stock-functions-tests.php +++ b/tests/php/includes/wc-stock-functions-tests.php @@ -192,6 +192,17 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { } } + /** + * Assert that a value is equal to another one and is of integer type. + * + * @param mixed $expected The value $actual must be equal to. + * @param mixed $actual The value to check for equality to $expected and for type. + */ + private function assertIsIntAndEquals( $expected, $actual ) { + $this->assertEquals( $expected, $actual ); + $this->assertIsInt( $actual ); + } + /** * Test wc_get_low_stock_amount with a simple product which has low stock amount set. */ @@ -200,7 +211,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $site_wide_low_stock_amount = 3; // Set the store-wide default. - update_option( 'woocommerce_notify_low_stock_amount', $site_wide_low_stock_amount ); + update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) ); // Simple product, set low stock amount. $product = WC_Helper_Product::create_simple_product( @@ -212,7 +223,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { ) ); - $this->assertEquals( $product_low_stock_amount, wc_get_low_stock_amount( $product ) ); + $this->assertIsIntAndEquals( $product_low_stock_amount, wc_get_low_stock_amount( $product ) ); } /** @@ -222,7 +233,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $site_wide_low_stock_amount = 3; // Set the store-wide default. - update_option( 'woocommerce_notify_low_stock_amount', $site_wide_low_stock_amount ); + update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) ); // Simple product, don't set low stock amount. $product = WC_Helper_Product::create_simple_product( @@ -233,7 +244,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { ) ); - $this->assertEquals( $site_wide_low_stock_amount, wc_get_low_stock_amount( $product ) ); + $this->assertIsIntAndEquals( $site_wide_low_stock_amount, wc_get_low_stock_amount( $product ) ); } /** @@ -245,7 +256,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $variation_low_stock_amount = 7; // Set the store-wide default. - update_option( 'woocommerce_notify_low_stock_amount', $site_wide_low_stock_amount ); + update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) ); // Parent low stock amount NOT set. $variable_product = WC_Helper_Product::create_variation_product(); @@ -259,17 +270,17 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $var1->set_low_stock_amount( $variation_low_stock_amount ); $var1->save(); - $this->assertEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); + $this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); // Even after turning on manage stock on the parent, but with no value. $variable_product->set_manage_stock( true ); $variable_product->save(); - $this->assertEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); + $this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); // Ans also after turning the manage stock off again on the parent. $variable_product->set_manage_stock( false ); $variable_product->save(); - $this->assertEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); + $this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); } /** @@ -282,7 +293,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $variation_low_stock_amount = 7; // Set the store-wide default. - update_option( 'woocommerce_notify_low_stock_amount', $site_wide_low_stock_amount ); + update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) ); // Set the parent low stock amount. $variable_product = WC_Helper_Product::create_variation_product(); @@ -297,7 +308,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $var1->set_low_stock_amount( $variation_low_stock_amount ); $var1->save(); - $this->assertEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); + $this->assertIsIntAndEquals( $variation_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); } /** @@ -309,7 +320,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $parent_low_stock_amount = 5; // Set the store-wide default. - update_option( 'woocommerce_notify_low_stock_amount', $site_wide_low_stock_amount ); + update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) ); // Set the parent low stock amount. $variable_product = WC_Helper_Product::create_variation_product(); @@ -321,7 +332,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $variations = $variable_product->get_available_variations( 'objects' ); $var1 = $variations[0]; - $this->assertEquals( $parent_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); + $this->assertIsIntAndEquals( $parent_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); } /** @@ -332,7 +343,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $site_wide_low_stock_amount = 3; // Set the store-wide default. - update_option( 'woocommerce_notify_low_stock_amount', $site_wide_low_stock_amount ); + update_option( 'woocommerce_notify_low_stock_amount', strval( $site_wide_low_stock_amount ) ); // Set the parent low stock amount. $variable_product = WC_Helper_Product::create_variation_product(); @@ -343,7 +354,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { $var1 = $variations[0]; $var1->set_manage_stock( false ); - $this->assertEquals( $site_wide_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); + $this->assertIsIntAndEquals( $site_wide_low_stock_amount, wc_get_low_stock_amount( $var1 ) ); } } From 78a57e53ec629537390d82d2decf8338fa1f507a Mon Sep 17 00:00:00 2001 From: roykho Date: Tue, 20 Apr 2021 06:17:50 -0700 Subject: [PATCH 39/52] Update to use closure per review comment --- includes/admin/class-wc-admin-taxonomies.php | 19 ++++++------------- src/Internal/AssignDefaultCategory.php | 3 ++- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/includes/admin/class-wc-admin-taxonomies.php b/includes/admin/class-wc-admin-taxonomies.php index 4163fdbbfee..fd6d297dfa1 100644 --- a/includes/admin/class-wc-admin-taxonomies.php +++ b/includes/admin/class-wc-admin-taxonomies.php @@ -51,7 +51,12 @@ class WC_Admin_Taxonomies { // Category/term ordering. add_action( 'create_term', array( $this, 'create_term' ), 5, 3 ); - add_action( 'delete_product_cat', array( $this, 'assign_default_product_cat' ) ); + add_action( + 'delete_product_cat', + function() { + wc_get_container()->get( AssignDefaultCategory::class )->schedule_action(); + } + ); // Add form. add_action( 'product_cat_add_form_fields', array( $this, 'add_category_fields' ) ); @@ -113,18 +118,6 @@ class WC_Admin_Taxonomies { wc_deprecated_function( 'delete_term', '3.6' ); } - /** - * Assigns default product category. This is done when the product - * has no assgined product category. - * - * @since 5.4 - * @return void - */ - public function assign_default_product_cat() { - // Schedule action to assign default category. - wc_get_container()->get( AssignDefaultCategory::class )->schedule_action(); - } - /** * Category thumbnail fields. */ diff --git a/src/Internal/AssignDefaultCategory.php b/src/Internal/AssignDefaultCategory.php index 1c6f743b34a..34968e974ee 100644 --- a/src/Internal/AssignDefaultCategory.php +++ b/src/Internal/AssignDefaultCategory.php @@ -25,6 +25,8 @@ class AssignDefaultCategory { * if the product has no categories assigned. Then assign * it a default category. We delay this with a scheduled * action job to not block the response. + * + * @return void */ public function schedule_action() { WC()->queue()->schedule_single( @@ -39,7 +41,6 @@ class AssignDefaultCategory { * Assigns default product category for products * that have no categories. * - * @since 5.4 * @return void */ public function maybe_assign_default_product_cat() { From d214eab1575fed9c48e42a1d9ce1e3ce2f1f18ab Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Tue, 20 Apr 2021 16:35:42 +0200 Subject: [PATCH 40/52] Use int cast instead of intval in wc_get_low_stock_amount --- includes/wc-stock-functions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/wc-stock-functions.php b/includes/wc-stock-functions.php index 8e158aa9e4d..f8fc3d557ff 100644 --- a/includes/wc-stock-functions.php +++ b/includes/wc-stock-functions.php @@ -411,5 +411,5 @@ function wc_get_low_stock_amount( WC_Product $product ) { $low_stock_amount = get_option( 'woocommerce_notify_low_stock_amount', 2 ); } - return intval( $low_stock_amount ); + return (int) $low_stock_amount; } From b88eb4c9812f7340d2bd385de77a37447a7d3299 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Tue, 20 Apr 2021 17:16:59 +0200 Subject: [PATCH 41/52] Rename "assertIsInt" to "assertIsInteger" and make it static - Renaming to prevent conflicts with the existing method in the newer PHPUnit used in PHP 8. - Making it static because "assertIsInt" is static too, so it'll be easier to replace in the future. --- tests/legacy/framework/class-wc-unit-test-case.php | 12 +++++++----- tests/php/includes/wc-stock-functions-tests.php | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/legacy/framework/class-wc-unit-test-case.php b/tests/legacy/framework/class-wc-unit-test-case.php index 5426c2ca6ae..c3255481fef 100644 --- a/tests/legacy/framework/class-wc-unit-test-case.php +++ b/tests/legacy/framework/class-wc-unit-test-case.php @@ -7,6 +7,7 @@ use Automattic\WooCommerce\Proxies\LegacyProxy; use Automattic\WooCommerce\Testing\Tools\CodeHacking\CodeHacker; +use PHPUnit\Framework\Constraint\IsType; /** * WC Unit Test Case. @@ -248,13 +249,14 @@ class WC_Unit_Test_Case extends WP_HTTP_TestCase { } /** - * Check if a value is of integer type. - * This function is already built-in in PHPUnit 8 so this one can be removed once we upgrade to that version of newer. + * Asserts that a variable is of type int. + * TODO: After upgrading to PHPUnit 8 or newer, remove this method and replace calls with PHPUnit's built-in 'assertIsInt'. * - * @param mixed $value The value to check. + * @param mixed $actual The value to check. + * @param mixed $message Error message to use if the assertion fails. * @return bool mixed True if the value is of integer type, false otherwise. */ - protected function assertIsInt( $value ) { - return $this->assertInternalType( 'int', $value ); + public static function assertIsInteger( $actual, $message = '' ) { + return self::assertInternalType( 'int', $actual, $message ); } } diff --git a/tests/php/includes/wc-stock-functions-tests.php b/tests/php/includes/wc-stock-functions-tests.php index 74470a86cbc..4e04dc29d29 100644 --- a/tests/php/includes/wc-stock-functions-tests.php +++ b/tests/php/includes/wc-stock-functions-tests.php @@ -200,7 +200,7 @@ class WC_Stock_Functions_Tests extends \WC_Unit_Test_Case { */ private function assertIsIntAndEquals( $expected, $actual ) { $this->assertEquals( $expected, $actual ); - $this->assertIsInt( $actual ); + self::assertIsInteger( $actual ); } /** From 43a502e1855cce3012d980caf8a1db1271d521ac Mon Sep 17 00:00:00 2001 From: Gracie Ofslager Date: Wed, 31 Mar 2021 11:30:40 -0400 Subject: [PATCH 42/52] Update class-wc-settings-emails.php Adding copy to line 54 for instructions on how to ensure email is delivered successfully and linking to troubleshooting documentation. --- includes/admin/settings/class-wc-settings-emails.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/includes/admin/settings/class-wc-settings-emails.php b/includes/admin/settings/class-wc-settings-emails.php index f5b1f75a0fd..3774fef6a16 100644 --- a/includes/admin/settings/class-wc-settings-emails.php +++ b/includes/admin/settings/class-wc-settings-emails.php @@ -51,7 +51,9 @@ class WC_Settings_Emails extends WC_Settings_Page { array( array( 'title' => __( 'Email notifications', 'woocommerce' ), - 'desc' => __( 'Email notifications sent from WooCommerce are listed below. Click on an email to configure it.', 'woocommerce' ), + 'desc' => __( 'Email notifications sent from WooCommerce are listed below. Click on an email to configure it. + + To ensure your store’s notifications arrive in your and your customers’ inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn’t seem to be sending correctly, install the WP Mail Logging Plugin. Learn more and see troubleshooting steps here.', 'woocommerce' ), 'type' => 'title', 'id' => 'email_notification_settings', ), From 00a0118858a48cc0a33ac2a20d14188a1d6fdc2a Mon Sep 17 00:00:00 2001 From: vedanshujain Date: Tue, 6 Apr 2021 15:33:06 +0530 Subject: [PATCH 43/52] Improvements in text for translators. --- includes/admin/settings/class-wc-settings-emails.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/includes/admin/settings/class-wc-settings-emails.php b/includes/admin/settings/class-wc-settings-emails.php index 3774fef6a16..28141816813 100644 --- a/includes/admin/settings/class-wc-settings-emails.php +++ b/includes/admin/settings/class-wc-settings-emails.php @@ -46,14 +46,19 @@ class WC_Settings_Emails extends WC_Settings_Page { * @return array */ public function get_settings() { + $desc_help_text = sprintf( + /* translators: %1$s: Link to WP Mail Logging plugin, %2$s: Link to Email FAQ support page. */ + __( 'To ensure your store’s notifications arrive in your and your customers’ inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn’t seem to be sending correctly, install the WP Mail Logging Plugin or check the Email FAQ page.', 'woocommerce' ), + 'https://wordpress.org/plugins/wp-mail-logging/', + 'https://docs.woocommerce.com/document/email-faq' + ); $settings = apply_filters( 'woocommerce_email_settings', array( array( 'title' => __( 'Email notifications', 'woocommerce' ), - 'desc' => __( 'Email notifications sent from WooCommerce are listed below. Click on an email to configure it. - - To ensure your store’s notifications arrive in your and your customers’ inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn’t seem to be sending correctly, install the WP Mail Logging Plugin. Learn more and see troubleshooting steps here.', 'woocommerce' ), + /* translators: %s: help description with link to WP Mail logging and support page. */ + 'desc' => sprintf( __( 'Email notifications sent from WooCommerce are listed below. Click on an email to configure it.
%s', 'woocommerce' ), $desc_help_text ), 'type' => 'title', 'id' => 'email_notification_settings', ), From 96f1ccfe610cd76e41b1ed694d398e59da7c670d Mon Sep 17 00:00:00 2001 From: vedanshujain Date: Tue, 20 Apr 2021 12:08:00 +0530 Subject: [PATCH 44/52] Use encoding instead of direct quote character to follow WP guideline. --- includes/admin/settings/class-wc-settings-emails.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/includes/admin/settings/class-wc-settings-emails.php b/includes/admin/settings/class-wc-settings-emails.php index 28141816813..0543e42631e 100644 --- a/includes/admin/settings/class-wc-settings-emails.php +++ b/includes/admin/settings/class-wc-settings-emails.php @@ -48,7 +48,7 @@ class WC_Settings_Emails extends WC_Settings_Page { public function get_settings() { $desc_help_text = sprintf( /* translators: %1$s: Link to WP Mail Logging plugin, %2$s: Link to Email FAQ support page. */ - __( 'To ensure your store’s notifications arrive in your and your customers’ inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn’t seem to be sending correctly, install the WP Mail Logging Plugin or check the Email FAQ page.', 'woocommerce' ), + __( 'To ensure your store’s notifications arrive in your and your customers’ inboxes, we recommend connecting your email address to your domain and setting up a dedicated SMTP server. If something doesn’t seem to be sending correctly, install the WP Mail Logging Plugin or check the Email FAQ page.', 'woocommerce' ), 'https://wordpress.org/plugins/wp-mail-logging/', 'https://docs.woocommerce.com/document/email-faq' ); From 3a895c9eed7c7f6192c63f87ef69aa30ca7026aa Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Wed, 21 Apr 2021 12:57:56 +0200 Subject: [PATCH 45/52] Move ThemeSupport class to Internal namespace, and use in 2021 theme. --- includes/customizer/class-wc-shop-customizer.php | 2 +- includes/theme-support/class-wc-twenty-eleven.php | 2 +- includes/theme-support/class-wc-twenty-fifteen.php | 2 +- includes/theme-support/class-wc-twenty-fourteen.php | 2 +- includes/theme-support/class-wc-twenty-nineteen.php | 2 +- includes/theme-support/class-wc-twenty-seventeen.php | 2 +- includes/theme-support/class-wc-twenty-sixteen.php | 2 +- includes/theme-support/class-wc-twenty-ten.php | 2 +- includes/theme-support/class-wc-twenty-thirteen.php | 2 +- includes/theme-support/class-wc-twenty-twelve.php | 2 +- includes/theme-support/class-wc-twenty-twenty-one.php | 4 ++-- includes/theme-support/class-wc-twenty-twenty.php | 2 +- includes/wc-core-functions.php | 2 +- .../ServiceProviders/ThemeManagementServiceProvider.php | 2 +- src/{ThemeManagement => Internal}/ThemeSupport.php | 2 +- .../php/includes/customizer/class-wc-shop-customizer-test.php | 2 +- tests/php/src/ThemeSupport/ThemeSupportTest.php | 2 +- 17 files changed, 18 insertions(+), 18 deletions(-) rename src/{ThemeManagement => Internal}/ThemeSupport.php (98%) diff --git a/includes/customizer/class-wc-shop-customizer.php b/includes/customizer/class-wc-shop-customizer.php index 1bbb099faf5..f17cac7dfea 100644 --- a/includes/customizer/class-wc-shop-customizer.php +++ b/includes/customizer/class-wc-shop-customizer.php @@ -6,7 +6,7 @@ * @package WooCommerce */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-eleven.php b/includes/theme-support/class-wc-twenty-eleven.php index 9bb77c9e70e..db598f78907 100644 --- a/includes/theme-support/class-wc-twenty-eleven.php +++ b/includes/theme-support/class-wc-twenty-eleven.php @@ -6,7 +6,7 @@ * @package WooCommerce\Classes */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-fifteen.php b/includes/theme-support/class-wc-twenty-fifteen.php index 828b2ed6d61..a3a194c7579 100644 --- a/includes/theme-support/class-wc-twenty-fifteen.php +++ b/includes/theme-support/class-wc-twenty-fifteen.php @@ -7,7 +7,7 @@ * @package WooCommerce\Classes */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-fourteen.php b/includes/theme-support/class-wc-twenty-fourteen.php index e068e57c96c..b8f5cf09a6b 100644 --- a/includes/theme-support/class-wc-twenty-fourteen.php +++ b/includes/theme-support/class-wc-twenty-fourteen.php @@ -7,7 +7,7 @@ * @package WooCommerce\Classes */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-nineteen.php b/includes/theme-support/class-wc-twenty-nineteen.php index 795fa079208..5419ade5b0a 100644 --- a/includes/theme-support/class-wc-twenty-nineteen.php +++ b/includes/theme-support/class-wc-twenty-nineteen.php @@ -7,7 +7,7 @@ */ use Automattic\Jetpack\Constants; -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-seventeen.php b/includes/theme-support/class-wc-twenty-seventeen.php index 6fff3aab843..661121063a5 100644 --- a/includes/theme-support/class-wc-twenty-seventeen.php +++ b/includes/theme-support/class-wc-twenty-seventeen.php @@ -7,7 +7,7 @@ */ use Automattic\Jetpack\Constants; -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-sixteen.php b/includes/theme-support/class-wc-twenty-sixteen.php index 1dc0b137e7f..f78fbb634f5 100644 --- a/includes/theme-support/class-wc-twenty-sixteen.php +++ b/includes/theme-support/class-wc-twenty-sixteen.php @@ -6,7 +6,7 @@ * @package WooCommerce\Classes */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-ten.php b/includes/theme-support/class-wc-twenty-ten.php index 67f14aeab94..4988aea16a4 100644 --- a/includes/theme-support/class-wc-twenty-ten.php +++ b/includes/theme-support/class-wc-twenty-ten.php @@ -6,7 +6,7 @@ * @package WooCommerce\Classes */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-thirteen.php b/includes/theme-support/class-wc-twenty-thirteen.php index eac4e70130f..527fa176ee0 100644 --- a/includes/theme-support/class-wc-twenty-thirteen.php +++ b/includes/theme-support/class-wc-twenty-thirteen.php @@ -7,7 +7,7 @@ * @package WooCommerce\Classes */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-twelve.php b/includes/theme-support/class-wc-twenty-twelve.php index a5e7315c911..3815ac4c26d 100644 --- a/includes/theme-support/class-wc-twenty-twelve.php +++ b/includes/theme-support/class-wc-twenty-twelve.php @@ -7,7 +7,7 @@ * @package WooCommerce\Classes */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/theme-support/class-wc-twenty-twenty-one.php b/includes/theme-support/class-wc-twenty-twenty-one.php index 6b568ae0e2d..7707c05ecd5 100644 --- a/includes/theme-support/class-wc-twenty-twenty-one.php +++ b/includes/theme-support/class-wc-twenty-twenty-one.php @@ -7,6 +7,7 @@ */ use Automattic\Jetpack\Constants; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; @@ -37,8 +38,7 @@ class WC_Twenty_Twenty_One { add_theme_support( 'wc-product-gallery-zoom' ); add_theme_support( 'wc-product-gallery-lightbox' ); add_theme_support( 'wc-product-gallery-slider' ); - add_theme_support( - 'woocommerce', + wc_get_container()->get( ThemeSupport::class )->add_default_options( array( 'thumbnail_image_width' => 450, 'single_image_width' => 600, diff --git a/includes/theme-support/class-wc-twenty-twenty.php b/includes/theme-support/class-wc-twenty-twenty.php index f2327680da0..862376f9eda 100644 --- a/includes/theme-support/class-wc-twenty-twenty.php +++ b/includes/theme-support/class-wc-twenty-twenty.php @@ -7,7 +7,7 @@ */ use Automattic\Jetpack\Constants; -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; defined( 'ABSPATH' ) || exit; diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php index fa92a78481d..63ff71103cc 100644 --- a/includes/wc-core-functions.php +++ b/includes/wc-core-functions.php @@ -9,7 +9,7 @@ */ use Automattic\Jetpack\Constants; -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; use Automattic\WooCommerce\Utilities\NumberUtil; if ( ! defined( 'ABSPATH' ) ) { diff --git a/src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php b/src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php index 9ae7f90d848..7216b04271b 100644 --- a/src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php +++ b/src/Internal/DependencyManagement/ServiceProviders/ThemeManagementServiceProvider.php @@ -5,7 +5,7 @@ namespace Automattic\WooCommerce\Internal\DependencyManagement\ServiceProviders; -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; use Automattic\WooCommerce\Internal\DependencyManagement\AbstractServiceProvider; /** diff --git a/src/ThemeManagement/ThemeSupport.php b/src/Internal/ThemeSupport.php similarity index 98% rename from src/ThemeManagement/ThemeSupport.php rename to src/Internal/ThemeSupport.php index 82c6bff089a..46e627eb137 100644 --- a/src/ThemeManagement/ThemeSupport.php +++ b/src/Internal/ThemeSupport.php @@ -5,7 +5,7 @@ * @package Automattic\WooCommerce\ThemeManagement */ -namespace Automattic\WooCommerce\ThemeManagement; +namespace Automattic\WooCommerce\Internal; use Automattic\WooCommerce\Proxies\LegacyProxy; use Automattic\WooCommerce\Utilities\ArrayUtil; diff --git a/tests/php/includes/customizer/class-wc-shop-customizer-test.php b/tests/php/includes/customizer/class-wc-shop-customizer-test.php index c1c73f66c56..0dc8057ccc9 100644 --- a/tests/php/includes/customizer/class-wc-shop-customizer-test.php +++ b/tests/php/includes/customizer/class-wc-shop-customizer-test.php @@ -3,7 +3,7 @@ * Tests for WC_Shop_Customizer */ -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; require_once ABSPATH . WPINC . '/class-wp-customize-control.php'; diff --git a/tests/php/src/ThemeSupport/ThemeSupportTest.php b/tests/php/src/ThemeSupport/ThemeSupportTest.php index 3b3a5f9304f..0add81a3415 100644 --- a/tests/php/src/ThemeSupport/ThemeSupportTest.php +++ b/tests/php/src/ThemeSupport/ThemeSupportTest.php @@ -7,7 +7,7 @@ namespace Automattic\WooCommerce\Tests\ThemeManagement; -use Automattic\WooCommerce\ThemeManagement\ThemeSupport; +use Automattic\WooCommerce\Internal\ThemeSupport; /** * Tests for ThemeSupport From 00e1ca530e2f4359eab33740c4975e33ec3d97f7 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 22 Apr 2021 14:50:31 +0200 Subject: [PATCH 46/52] Fixed checkout coupons flaky scenario --- .../core-tests/specs/shopper/front-end-checkout-coupons.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js b/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js index 9b009823b96..38f844effe7 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js @@ -86,6 +86,8 @@ const runCheckoutApplyCouponsTest = () => { }); it('allows customer to apply multiple coupons', async () => { + await page.reload(); + await page.waitForSelector('.woocommerce-notices-wrapper'); await applyCoupon(couponFixedProduct); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'}); From 82348d023d19115560a468f4cddf8f0ac9943cd9 Mon Sep 17 00:00:00 2001 From: Greg Date: Thu, 22 Apr 2021 11:37:12 -0600 Subject: [PATCH 47/52] Logout merchant and clear the cart before running tests --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 4efc8ac54e9..7bdccb60e00 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -61,6 +61,8 @@ const runCartCalculateShippingTest = () => { await page.select('select[name="add_method_id"]', 'local_pickup'); await page.click('button#btn-ok'); await page.waitForSelector('#zone_locations'); + await merchant.logout(); + await shopper.emptyCart(); }); it('allows customer to calculate Free Shipping if in Germany', async () => { From 55ab8cb966c692685346db302625735cabb66f83 Mon Sep 17 00:00:00 2001 From: Jonathan Sadowski Date: Fri, 23 Apr 2021 09:29:12 -0500 Subject: [PATCH 48/52] Set USD as default store currency --- includes/admin/class-wc-admin-setup-wizard.php | 2 +- includes/admin/settings/class-wc-settings-general.php | 2 +- tests/legacy/unit-tests/util/class-wc-tests-core-functions.php | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/includes/admin/class-wc-admin-setup-wizard.php b/includes/admin/class-wc-admin-setup-wizard.php index 14c11081d8c..255776aa251 100644 --- a/includes/admin/class-wc-admin-setup-wizard.php +++ b/includes/admin/class-wc-admin-setup-wizard.php @@ -481,7 +481,7 @@ class WC_Admin_Setup_Wizard { $state = WC()->countries->get_base_state(); $country = WC()->countries->get_base_country(); $postcode = WC()->countries->get_base_postcode(); - $currency = get_option( 'woocommerce_currency', 'GBP' ); + $currency = get_option( 'woocommerce_currency', 'USD' ); $product_type = get_option( 'woocommerce_product_type', 'both' ); $sell_in_person = get_option( 'woocommerce_sell_in_person', 'none_selected' ); diff --git a/includes/admin/settings/class-wc-settings-general.php b/includes/admin/settings/class-wc-settings-general.php index 28864828d0d..1476c428c0c 100644 --- a/includes/admin/settings/class-wc-settings-general.php +++ b/includes/admin/settings/class-wc-settings-general.php @@ -229,7 +229,7 @@ class WC_Settings_General extends WC_Settings_Page { 'title' => __( 'Currency', 'woocommerce' ), 'desc' => __( 'This controls what currency prices are listed at in the catalog and which currency gateways will take payments in.', 'woocommerce' ), 'id' => 'woocommerce_currency', - 'default' => 'GBP', + 'default' => 'USD', 'type' => 'select', 'class' => 'wc-enhanced-select', 'desc_tip' => true, diff --git a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php index 8f5b1419fbe..4b2426857ac 100644 --- a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php +++ b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php @@ -30,7 +30,7 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case { */ public function test_get_woocommerce_currency() { - $this->assertEquals( 'GBP', get_woocommerce_currency() ); + $this->assertEquals( 'USD', get_woocommerce_currency() ); } /** From cd7b8ee30fe9e2c1c84263cbe49800df0bf95049 Mon Sep 17 00:00:00 2001 From: Jonathan Sadowski Date: Fri, 23 Apr 2021 09:52:30 -0500 Subject: [PATCH 49/52] Fix unit tests for new default USD currency --- .../unit-tests/formatting/functions.php | 28 +++++++++---------- tests/legacy/unit-tests/product/data.php | 6 ++-- .../util/class-wc-tests-core-functions.php | 4 +-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/tests/legacy/unit-tests/formatting/functions.php b/tests/legacy/unit-tests/formatting/functions.php index 7ddc4ba9865..ae237dacf6e 100644 --- a/tests/legacy/unit-tests/formatting/functions.php +++ b/tests/legacy/unit-tests/formatting/functions.php @@ -593,32 +593,32 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { */ public function test_wc_price() { // Common prices. - $this->assertEquals( '£1.00', wc_price( 1 ) ); - $this->assertEquals( '£1.10', wc_price( 1.1 ) ); - $this->assertEquals( '£1.17', wc_price( 1.17 ) ); - $this->assertEquals( '£1,111.17', wc_price( 1111.17 ) ); - $this->assertEquals( '£0.00', wc_price( 0 ) ); + $this->assertEquals( '$1.00', wc_price( 1 ) ); + $this->assertEquals( '$1.10', wc_price( 1.1 ) ); + $this->assertEquals( '$1.17', wc_price( 1.17 ) ); + $this->assertEquals( '$1,111.17', wc_price( 1111.17 ) ); + $this->assertEquals( '$0.00', wc_price( 0 ) ); // Different currency. - $this->assertEquals( '$1,111.17', wc_price( 1111.17, array( 'currency' => 'USD' ) ) ); + $this->assertEquals( '£1,111.17', wc_price( 1111.17, array( 'currency' => 'GBP' ) ) ); // Negative price. - $this->assertEquals( '-£1.17', wc_price( -1.17 ) ); + $this->assertEquals( '-$1.17', wc_price( -1.17 ) ); // Bogus prices. - $this->assertEquals( '£0.00', wc_price( null ) ); - $this->assertEquals( '£0.00', wc_price( 'Q' ) ); - $this->assertEquals( '£0.00', wc_price( 'ಠ_ಠ' ) ); + $this->assertEquals( '$0.00', wc_price( null ) ); + $this->assertEquals( '$0.00', wc_price( 'Q' ) ); + $this->assertEquals( '$0.00', wc_price( 'ಠ_ಠ' ) ); // Trim zeros. add_filter( 'woocommerce_price_trim_zeros', '__return_true' ); - $this->assertEquals( '£1', wc_price( 1.00 ) ); + $this->assertEquals( '$1', wc_price( 1.00 ) ); remove_filter( 'woocommerce_price_trim_zeros', '__return_true' ); // Ex tax label. $calc_taxes = get_option( 'woocommerce_calc_taxes' ); update_option( 'woocommerce_calc_taxes', 'yes' ); - $this->assertEquals( '£1,111.17 (ex. tax)', wc_price( '1111.17', array( 'ex_tax_label' => true ) ) ); + $this->assertEquals( '$1,111.17 (ex. tax)', wc_price( '1111.17', array( 'ex_tax_label' => true ) ) ); update_option( 'woocommerce_calc_taxes', $calc_taxes ); } @@ -926,7 +926,7 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { * @since 3.3.0 */ public function test_wc_format_sale_price() { - $this->assertEquals( ' £5.00', wc_format_sale_price( '10', '5' ) ); + $this->assertEquals( ' $5.00', wc_format_sale_price( '10', '5' ) ); } /** @@ -935,7 +935,7 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { * @since 3.3.0 */ public function test_wc_format_price_range() { - $this->assertEquals( '£10.00£5.00', wc_format_price_range( '10', '5' ) ); + $this->assertEquals( '$10.00$5.00', wc_format_price_range( '10', '5' ) ); } /** diff --git a/tests/legacy/unit-tests/product/data.php b/tests/legacy/unit-tests/product/data.php index b3beb1f9f2a..09c5f78ea57 100644 --- a/tests/legacy/unit-tests/product/data.php +++ b/tests/legacy/unit-tests/product/data.php @@ -259,15 +259,15 @@ class WC_Tests_Product_Data extends WC_Unit_Test_Case { $product = wc_get_product( $product1_id ); $this->assertEquals( $product1_id, $product->get_id() ); - $this->assertEquals( ' £7.00', $product->get_price_html() ); + $this->assertEquals( ' $7.00', $product->get_price_html() ); $product = wc_get_product( $product2_id ); $this->assertEquals( $product2_id, $product->get_id() ); - $this->assertEquals( ' £16.00', $product->get_price_html() ); + $this->assertEquals( ' $16.00', $product->get_price_html() ); $product = wc_get_product( $product3_id ); $this->assertEquals( $product3_id, $product->get_id() ); - $this->assertEquals( '£50.00', $product->get_price_html() ); + $this->assertEquals( '$50.00', $product->get_price_html() ); } /** diff --git a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php index 4b2426857ac..6f2c17b7d5e 100644 --- a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php +++ b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php @@ -222,10 +222,10 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case { public function test_get_woocommerce_currency_symbol() { // Default currency. - $this->assertEquals( '£', get_woocommerce_currency_symbol() ); + $this->assertEquals( '$', get_woocommerce_currency_symbol() ); // Given specific currency. - $this->assertEquals( '$', get_woocommerce_currency_symbol( 'USD' ) ); + $this->assertEquals( '£', get_woocommerce_currency_symbol( 'GBP' ) ); // Each case. foreach ( array_keys( get_woocommerce_currencies() ) as $currency_code ) { From 01d0f45088d811fcf09138113c0ff7467b7af468 Mon Sep 17 00:00:00 2001 From: Veljko Date: Fri, 23 Apr 2021 20:03:48 +0200 Subject: [PATCH 50/52] Update functions instead scenario --- .../specs/shopper/front-end-checkout-coupons.test.js | 2 -- tests/e2e/utils/src/page-utils.js | 8 ++++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js b/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js index 38f844effe7..9b009823b96 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-checkout-coupons.test.js @@ -86,8 +86,6 @@ const runCheckoutApplyCouponsTest = () => { }); it('allows customer to apply multiple coupons', async () => { - await page.reload(); - await page.waitForSelector('.woocommerce-notices-wrapper'); await applyCoupon(couponFixedProduct); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'}); diff --git a/tests/e2e/utils/src/page-utils.js b/tests/e2e/utils/src/page-utils.js index 7e7648462e0..7a5f5e7d181 100644 --- a/tests/e2e/utils/src/page-utils.js +++ b/tests/e2e/utils/src/page-utils.js @@ -236,6 +236,10 @@ export const searchForOrder = async (value, orderId, customerName) => { */ export const applyCoupon = async ( couponCode ) => { try { + await Promise.all([ + page.reload(), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ]); await expect(page).toClick('a', {text: 'Click here to enter your code'}); await uiUnblocked(); await clearAndFillInput('#coupon_code', couponCode); @@ -255,6 +259,10 @@ export const applyCoupon = async ( couponCode ) => { * @returns {Promise} */ export const removeCoupon = async ( couponCode ) => { + await Promise.all([ + page.reload(), + page.waitForNavigation( { waitUntil: 'networkidle0' } ), + ]); await expect(page).toClick('[data-coupon="'+couponCode.toLowerCase()+'"]', {text: '[Remove]'}); await uiUnblocked(); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon has been removed.'}); From d571e570e43f688d33106d34839cf795f68589aa Mon Sep 17 00:00:00 2001 From: roykho Date: Mon, 26 Apr 2021 08:18:09 -0700 Subject: [PATCH 51/52] Remove set_backorders logic from external products closes #29696 --- includes/admin/class-wc-admin-post-types.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/includes/admin/class-wc-admin-post-types.php b/includes/admin/class-wc-admin-post-types.php index e2d145206a1..2eaef024a14 100644 --- a/includes/admin/class-wc-admin-post-types.php +++ b/includes/admin/class-wc-admin-post-types.php @@ -430,7 +430,10 @@ class WC_Admin_Post_Types { // phpcs:enable WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $product->set_manage_stock( $manage_stock ); - $product->set_backorders( $backorders ); + + if ( 'external' !== $product->get_type() ) { + $product->set_backorders( $backorders ); + } if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { $stock_amount = 'yes' === $manage_stock && isset( $request_data['_stock'] ) && is_numeric( wp_unslash( $request_data['_stock'] ) ) ? wc_stock_amount( wp_unslash( $request_data['_stock'] ) ) : ''; @@ -550,7 +553,10 @@ class WC_Admin_Post_Types { $stock_amount = 'yes' === $manage_stock && ! empty( $request_data['change_stock'] ) && isset( $request_data['_stock'] ) ? wc_stock_amount( $request_data['_stock'] ) : $product->get_stock_quantity(); $product->set_manage_stock( $manage_stock ); - $product->set_backorders( $backorders ); + + if ( 'external' !== $product->get_type() ) { + $product->set_backorders( $backorders ); + } if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) { $change_stock = absint( $request_data['change_stock'] ); From 9829c01c78cdb9ce5c460977080b885d6afb7fdc Mon Sep 17 00:00:00 2001 From: Jonathan Sadowski Date: Mon, 26 Apr 2021 14:46:57 -0500 Subject: [PATCH 52/52] Update version to 5.4.0-dev in woocommerce.php --- woocommerce.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/woocommerce.php b/woocommerce.php index 89d55866da5..1fb1516fb43 100644 --- a/woocommerce.php +++ b/woocommerce.php @@ -3,7 +3,7 @@ * Plugin Name: WooCommerce * Plugin URI: https://woocommerce.com/ * Description: An eCommerce toolkit that helps you sell anything. Beautifully. - * Version: 5.3.0-dev + * Version: 5.4.0-dev * Author: Automattic * Author URI: https://woocommerce.com * Text Domain: woocommerce