diff --git a/composer.json b/composer.json index b04a148f..440e42f8 100644 --- a/composer.json +++ b/composer.json @@ -25,6 +25,7 @@ "wpackagist-plugin/advanced-custom-fields": "5.8.12", "wpackagist-plugin/easy-digital-downloads": "^2.9.23", "wpackagist-plugin/user-switching": "^1.5.5", + "wpackagist-plugin/woocommerce": "^4.4", "wpsh/local": "^0.2.3" }, "config": { diff --git a/composer.lock b/composer.lock index 03b357a7..be2d2aa0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c025a44ff83e162076363f15803df9da", + "content-hash": "845c0e3b708c2ae893cdd6c36db0e8a1", "packages": [ { "name": "composer/installers", - "version": "v1.9.0", + "version": "v1.10.0", "source": { "type": "git", "url": "https://github.com/composer/installers.git", - "reference": "b93bcf0fa1fccb0b7d176b0967d969691cd74cca" + "reference": "1a0357fccad9d1cc1ea0c9a05b8847fbccccb78d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/installers/zipball/b93bcf0fa1fccb0b7d176b0967d969691cd74cca", - "reference": "b93bcf0fa1fccb0b7d176b0967d969691cd74cca", + "url": "https://api.github.com/repos/composer/installers/zipball/1a0357fccad9d1cc1ea0c9a05b8847fbccccb78d", + "reference": "1a0357fccad9d1cc1ea0c9a05b8847fbccccb78d", "shasum": "" }, "require": { @@ -28,17 +28,18 @@ "shama/baton": "*" }, "require-dev": { - "composer/composer": "1.6.* || 2.0.*@dev", - "composer/semver": "1.0.* || 2.0.*@dev", - "phpunit/phpunit": "^4.8.36", - "sebastian/comparator": "^1.2.4", + "composer/composer": "1.6.* || ^2.0", + "composer/semver": "^1 || ^3", + "phpstan/phpstan": "^0.12.55", + "phpstan/phpstan-phpunit": "^0.12.16", + "symfony/phpunit-bridge": "^4.2 || ^5", "symfony/process": "^2.3" }, "type": "composer-plugin", "extra": { "class": "Composer\\Installers\\Plugin", "branch-alias": { - "dev-master": "1.0-dev" + "dev-main": "1.x-dev" } }, "autoload": { @@ -76,6 +77,7 @@ "Porto", "RadPHP", "SMF", + "Starbug", "Thelia", "Whmcs", "WolfCMS", @@ -116,6 +118,7 @@ "phpbb", "piwik", "ppi", + "processwire", "puppet", "pxcms", "reindex", @@ -133,19 +136,23 @@ ], "support": { "issues": "https://github.com/composer/installers/issues", - "source": "https://github.com/composer/installers/tree/v1.9.0" + "source": "https://github.com/composer/installers/tree/v1.10.0" }, "funding": [ { "url": "https://packagist.com", "type": "custom" }, + { + "url": "https://github.com/composer", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/composer/composer", "type": "tidelift" } ], - "time": "2020-04-07T06:57:05+00:00" + "time": "2021-01-14T11:07:16+00:00" } ], "packages-dev": [ @@ -279,16 +286,16 @@ }, { "name": "composer/composer", - "version": "1.10.19", + "version": "1.10.20", "source": { "type": "git", "url": "https://github.com/composer/composer.git", - "reference": "196601d50c08c3fae389a417a7689367fcf37cef" + "reference": "e55d297525f0ecc805c813a0f63a40114fd670f6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/composer/zipball/196601d50c08c3fae389a417a7689367fcf37cef", - "reference": "196601d50c08c3fae389a417a7689367fcf37cef", + "url": "https://api.github.com/repos/composer/composer/zipball/e55d297525f0ecc805c813a0f63a40114fd670f6", + "reference": "e55d297525f0ecc805c813a0f63a40114fd670f6", "shasum": "" }, "require": { @@ -358,7 +365,7 @@ "support": { "irc": "irc://irc.freenode.org/composer", "issues": "https://github.com/composer/composer/issues", - "source": "https://github.com/composer/composer/tree/1.10.19" + "source": "https://github.com/composer/composer/tree/1.10.20" }, "funding": [ { @@ -374,7 +381,7 @@ "type": "tidelift" } ], - "time": "2020-12-04T08:14:16+00:00" + "time": "2021-01-27T14:41:06+00:00" }, { "name": "composer/semver", @@ -1079,20 +1086,20 @@ }, { "name": "johnpbloch/wordpress", - "version": "5.6.0", + "version": "5.6.1", "source": { "type": "git", "url": "https://github.com/johnpbloch/wordpress.git", - "reference": "3055975734646c8d0b8caf7b5af168ced6ec4309" + "reference": "d7a597988102967cdfc28851b6b897d018613823" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/johnpbloch/wordpress/zipball/3055975734646c8d0b8caf7b5af168ced6ec4309", - "reference": "3055975734646c8d0b8caf7b5af168ced6ec4309", + "url": "https://api.github.com/repos/johnpbloch/wordpress/zipball/d7a597988102967cdfc28851b6b897d018613823", + "reference": "d7a597988102967cdfc28851b6b897d018613823", "shasum": "" }, "require": { - "johnpbloch/wordpress-core": "5.6.0", + "johnpbloch/wordpress-core": "5.6.1", "johnpbloch/wordpress-core-installer": "^1.0 || ^2.0", "php": ">=5.6.20" }, @@ -1121,20 +1128,20 @@ "source": "http://core.trac.wordpress.org/browser", "wiki": "http://codex.wordpress.org/" }, - "time": "2020-12-08T22:34:35+00:00" + "time": "2021-02-03T21:27:41+00:00" }, { "name": "johnpbloch/wordpress-core", - "version": "5.6.0", + "version": "5.6.1", "source": { "type": "git", "url": "https://github.com/johnpbloch/wordpress-core.git", - "reference": "f074617dd69f466302836d1ae5de75c0bd7b6dfd" + "reference": "82592ec73d42cf784da38adb0028a24dbacab1b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/johnpbloch/wordpress-core/zipball/f074617dd69f466302836d1ae5de75c0bd7b6dfd", - "reference": "f074617dd69f466302836d1ae5de75c0bd7b6dfd", + "url": "https://api.github.com/repos/johnpbloch/wordpress-core/zipball/82592ec73d42cf784da38adb0028a24dbacab1b4", + "reference": "82592ec73d42cf784da38adb0028a24dbacab1b4", "shasum": "" }, "require": { @@ -1142,7 +1149,7 @@ "php": ">=5.6.20" }, "provide": { - "wordpress/core-implementation": "5.6.0" + "wordpress/core-implementation": "5.6.1" }, "type": "wordpress-core", "notification-url": "https://packagist.org/downloads/", @@ -1169,7 +1176,7 @@ "source": "https://core.trac.wordpress.org/browser", "wiki": "https://codex.wordpress.org/" }, - "time": "2020-12-08T22:34:23+00:00" + "time": "2021-02-03T21:27:35+00:00" }, { "name": "johnpbloch/wordpress-core-installer", @@ -3145,16 +3152,16 @@ }, { "name": "sirbrillig/phpcs-variable-analysis", - "version": "v2.10.1", + "version": "v2.10.2", "source": { "type": "git", "url": "https://github.com/sirbrillig/phpcs-variable-analysis.git", - "reference": "c6716a98fe7bee25d31306e14fb62c3ffa16d70a" + "reference": "0775e0c683badad52c03b11c2cd86a9fdecb937a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/c6716a98fe7bee25d31306e14fb62c3ffa16d70a", - "reference": "c6716a98fe7bee25d31306e14fb62c3ffa16d70a", + "url": "https://api.github.com/repos/sirbrillig/phpcs-variable-analysis/zipball/0775e0c683badad52c03b11c2cd86a9fdecb937a", + "reference": "0775e0c683badad52c03b11c2cd86a9fdecb937a", "shasum": "" }, "require": { @@ -3194,7 +3201,7 @@ "source": "https://github.com/sirbrillig/phpcs-variable-analysis", "wiki": "https://github.com/sirbrillig/phpcs-variable-analysis/wiki" }, - "time": "2020-12-12T18:28:57+00:00" + "time": "2021-01-08T16:31:05+00:00" }, { "name": "squizlabs/php_codesniffer", @@ -4288,12 +4295,12 @@ "version": "1.9.1", "source": { "type": "git", - "url": "https://github.com/webmozart/assert.git", + "url": "https://github.com/webmozarts/assert.git", "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/webmozart/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/bafc69caeb4d49c39fd0779086c03a3738cbb389", "reference": "bafc69caeb4d49c39fd0779086c03a3738cbb389", "shasum": "" }, @@ -4331,8 +4338,8 @@ "validate" ], "support": { - "issues": "https://github.com/webmozart/assert/issues", - "source": "https://github.com/webmozart/assert/tree/master" + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.9.1" }, "time": "2020-07-08T17:02:28+00:00" }, @@ -6476,16 +6483,16 @@ }, { "name": "wp-phpunit/wp-phpunit", - "version": "5.6.0", + "version": "5.6.1", "source": { "type": "git", "url": "https://github.com/wp-phpunit/wp-phpunit.git", - "reference": "7130a214573cc8c12a0f8fe8a74b18b453bce1e9" + "reference": "f6b3fb65bccc0ff70b3bc7cc241935597dbd5562" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/wp-phpunit/wp-phpunit/zipball/7130a214573cc8c12a0f8fe8a74b18b453bce1e9", - "reference": "7130a214573cc8c12a0f8fe8a74b18b453bce1e9", + "url": "https://api.github.com/repos/wp-phpunit/wp-phpunit/zipball/f6b3fb65bccc0ff70b3bc7cc241935597dbd5562", + "reference": "f6b3fb65bccc0ff70b3bc7cc241935597dbd5562", "shasum": "" }, "type": "library", @@ -6520,7 +6527,7 @@ "issues": "https://github.com/wp-phpunit/issues", "source": "https://github.com/wp-phpunit/wp-phpunit" }, - "time": "2020-12-09T18:06:02+00:00" + "time": "2021-02-04T18:24:14+00:00" }, { "name": "wpackagist-plugin/advanced-custom-fields", @@ -6576,6 +6583,24 @@ "type": "wordpress-plugin", "homepage": "https://wordpress.org/plugins/user-switching/" }, + { + "name": "wpackagist-plugin/woocommerce", + "version": "4.9.2", + "source": { + "type": "svn", + "url": "https://plugins.svn.wordpress.org/woocommerce/", + "reference": "tags/4.9.2" + }, + "dist": { + "type": "zip", + "url": "https://downloads.wordpress.org/plugin/woocommerce.4.9.2.zip" + }, + "require": { + "composer/installers": "~1.0" + }, + "type": "wordpress-plugin", + "homepage": "https://wordpress.org/plugins/woocommerce/" + }, { "name": "wpsh/local", "version": "0.2.3", diff --git a/connectors/class-connector-woocommerce.php b/connectors/class-connector-woocommerce.php index 1ab9aff0..7fe14c10 100644 --- a/connectors/class-connector-woocommerce.php +++ b/connectors/class-connector-woocommerce.php @@ -109,6 +109,16 @@ public function register() { $this->get_woocommerce_settings_fields(); } + /** + * Unregister connection callbacks + */ + public function unregister() { + parent::unregister(); + + remove_filter( 'wp_stream_posts_exclude_post_types', array( $this, 'exclude_order_post_types' ) ); + remove_action( 'wp_stream_comments_exclude_comment_types', array( $this, 'exclude_order_comment_types' ) ); + } + /** * Check if plugin dependencies are satisfied and add an admin notice if not * @@ -327,6 +337,13 @@ public function exclude_order_comment_types( $comment_types ) { return $comment_types; } + /** + * Clears logged order + */ + public function flush_logged_order() { + $this->order_update_logged = false; + } + /** * Log Order major status changes ( creating / updating / trashing ) * @@ -337,6 +354,7 @@ public function exclude_order_comment_types( $comment_types ) { * @param \WP_Post $post Post object. */ public function callback_transition_post_status( $new, $old, $post ) { + // Only track orders. if ( 'shop_order' !== $post->post_type ) { return; @@ -357,9 +375,10 @@ public function callback_transition_post_status( $new, $old, $post ) { return; } - if ( in_array( $new, array( 'auto-draft', 'draft', 'inherit' ), true ) ) { + $start_statuses = array( 'auto-draft', 'inherit', 'new' ); + if ( in_array( $new, $start_statuses, true ) ) { return; - } elseif ( 'auto-draft' === $old && 'publish' === $new ) { + } elseif ( in_array( $old, $start_statuses, true ) && ! in_array( $new, $start_statuses, true ) ) { /* translators: %s: an order title (e.g. "Order #42") */ $message = esc_html_x( '%s created', @@ -375,7 +394,7 @@ public function callback_transition_post_status( $new, $old, $post ) { 'stream' ); $action = 'trashed'; - } elseif ( 'trash' === $old && 'publish' === $new ) { + } elseif ( 'trash' === $old && ! in_array( $new, $start_statuses, true ) ) { /* translators: %s: an order title (e.g. "Order #42") */ $message = esc_html_x( '%s restored from the trash', @@ -390,13 +409,10 @@ public function callback_transition_post_status( $new, $old, $post ) { 'Order title', 'stream' ); + $action = 'updated'; } - if ( empty( $action ) ) { - $action = 'updated'; - } - - $order = new \WC_Order( $post->ID ); + $order = \wc_get_order( $post->ID ); $order_title = esc_html__( 'Order number', 'stream' ) . ' ' . esc_html( $order->get_order_number() ); $order_type_name = esc_html__( 'order', 'stream' ); @@ -437,7 +453,7 @@ public function callback_deleted_post( $post_id ) { return; } - $order = new \WC_Order( $post->ID ); + $order = \wc_get_order( $post->ID ); $order_title = esc_html__( 'Order number', 'stream' ) . ' ' . esc_html( $order->get_order_number() ); $order_type_name = esc_html__( 'order', 'stream' ); @@ -468,6 +484,7 @@ public function callback_deleted_post( $post_id ) { * @param string $new New status. */ public function callback_woocommerce_order_status_changed( $order_id, $old, $new ) { + // Don't track customer actions. if ( ! is_admin() ) { return; @@ -488,19 +505,21 @@ public function callback_woocommerce_order_status_changed( $order_id, $old, $new $old_status_name = $old_status->name; } - /* translators: %1$s: an order title, %2$s: order status, %3$s: another order status (e.g. "Order #42", "processing", "complete") */ - $message = esc_html_x( - '%1$s status changed from %2$s to %3$s', - '1. Order title, 2. Old status, 3. New status', - 'stream' + $order = \wc_get_order( $order_id ); + $order_title = sprintf( + /* translators: %d: Order number */ + __( 'Order number %d', 'stream' ), + $order->get_order_number() ); - - $order = new \WC_Order( $order_id ); - $order_title = esc_html__( 'Order number', 'stream' ) . ' ' . esc_html( $order->get_order_number() ); $order_type_name = esc_html__( 'order', 'stream' ); $this->log( - $message, + /* translators: %1$s: an order title, %2$s: order status, %3$s: another order status (e.g. "Order #42", "processing", "complete") */ + esc_html_x( + '%1$s status changed from %2$s to %3$s', + '1. Order title, 2. Old status, 3. New status', + 'stream' + ), array( 'post_title' => $order_title, 'old_status_name' => $old_status_name, @@ -641,27 +660,14 @@ public function callback_woocommerce_tax_rate_updated( $tax_rate_id, $tax_rate ) * @param int $tax_rate_id Tax Rate ID. */ public function callback_woocommerce_tax_rate_deleted( $tax_rate_id ) { - global $wpdb; - - $tax_rate_name = $wpdb->get_var( - $wpdb->prepare( - "SELECT tax_rate_name FROM {$wpdb->prefix}woocommerce_tax_rates - WHERE tax_rate_id = %s - ", - $tax_rate_id - ) - ); - $this->log( /* translators: %4$s: a tax rate name (e.g. "GST") */ _x( - '"%s" tax rate deleted', + 'Tax rate identified by ID:"%s" deleted', 'Tax rate name', 'stream' ), - array( - 'tax_rate_name' => $tax_rate_name, - ), + compact( 'tax_rate_id' ), $tax_rate_id, 'tax', 'deleted' diff --git a/phpunit.xml b/phpunit.xml index af2b1c44..8e53407e 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -10,7 +10,7 @@ diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 3c911062..dfdbf1bd 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -23,7 +23,7 @@ * @param array $active_plugins * @return array */ -function xwp_filter_active_plugins_for_phpunit( $active_plugins ) { +function wp_stream_filter_active_plugins_for_phpunit( $active_plugins ) { $forced_active_plugins = array(); if ( defined( 'WP_TEST_ACTIVATED_PLUGINS' ) ) { $forced_active_plugins = preg_split( '/\s*,\s*/', WP_TEST_ACTIVATED_PLUGINS ); @@ -36,8 +36,8 @@ function xwp_filter_active_plugins_for_phpunit( $active_plugins ) { } return $active_plugins; } -tests_add_filter( 'site_option_active_sitewide_plugins', 'xwp_filter_active_plugins_for_phpunit' ); -tests_add_filter( 'option_active_plugins', 'xwp_filter_active_plugins_for_phpunit' ); +tests_add_filter( 'site_option_active_sitewide_plugins', 'wp_stream_filter_active_plugins_for_phpunit' ); +tests_add_filter( 'option_active_plugins', 'wp_stream_filter_active_plugins_for_phpunit' ); tests_add_filter( 'muplugins_loaded', @@ -79,6 +79,27 @@ function( $status = false, $args = array(), $url = '') { ); } +function wp_stream_install_wc() { + WC_Install::install(); + + // Initialize the WC API extensions. + \Automattic\WooCommerce\Admin\Install::create_tables(); + \Automattic\WooCommerce\Admin\Install::create_events(); + + // Reload capabilities after install, see https://core.trac.wordpress.org/ticket/28374. + if ( version_compare( $GLOBALS['wp_version'], '4.7', '<' ) ) { + $GLOBALS['wp_roles']->reinit(); + } else { + $GLOBALS['wp_roles'] = null; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited + wp_roles(); + } + + echo esc_html( 'Installing WooCommerce...' . PHP_EOL ); +} + +// install WC. +tests_add_filter( 'setup_theme', 'wp_stream_install_wc' ); + // @see https://core.trac.wordpress.org/browser/trunk/tests/phpunit/includes/bootstrap.php require $_tests_dir . '/includes/bootstrap.php'; diff --git a/tests/tests/connectors/test-class-connector-woocommerce.php b/tests/tests/connectors/test-class-connector-woocommerce.php new file mode 100644 index 00000000..662b6928 --- /dev/null +++ b/tests/tests/connectors/test-class-connector-woocommerce.php @@ -0,0 +1,559 @@ +plugin->connectors->unload_connector( 'woocommerce' ); + // Make partial of Connector_Woocommmerce class, with mocked "log" function. + $this->mock = $this->getMockBuilder( Connector_Woocommerce::class ) + ->setMethods( array( 'log' ) ) + ->getMock(); + + // Register connector. + $this->mock->is_dependency_satisfied(); + $this->mock->register(); + } + + /** + * Create simple product. + * + * @param bool $save Save or return object. + * @param array $props Properties to be set in the new product, as an associative array. + * + * @return WC_Product_Simple + */ + private function create_simple_product( $save = true, $props = array() ) { + $product = new \WC_Product_Simple(); + $default_props = + array( + 'name' => 'Dummy Product', + 'regular_price' => 10, + 'price' => 10, + 'sku' => 'DUMMY SKU', + 'manage_stock' => false, + 'tax_status' => 'taxable', + 'downloadable' => false, + 'virtual' => false, + 'stock_status' => 'instock', + 'weight' => '1.1', + ); + + $product->set_props( array_merge( $default_props, $props ) ); + + if ( $save ) { + $product->save(); + return \wc_get_product( $product->get_id() ); + } else { + return $product; + } + } + + /** + * Create a simple flat rate at the cost of 10. + * + * @param float $cost Optional. Cost of flat rate method. + */ + private function create_simple_flat_rate( $cost = 10 ) { + $flat_rate_settings = array( + 'enabled' => 'yes', + 'title' => 'Flat rate', + 'availability' => 'all', + 'countries' => '', + 'tax_status' => 'taxable', + 'cost' => $cost, + ); + + update_option( 'woocommerce_flat_rate_settings', $flat_rate_settings ); + update_option( 'woocommerce_flat_rate', array() ); + \WC_Cache_Helper::get_transient_version( 'shipping', true ); + \WC()->shipping()->load_shipping_methods(); + } + + /** + * Create a order. + * + * @param int $customer_id The ID of the customer the order is for. + * @param WC_Product $product The product to add to the order. + * + * @return WC_Order + */ + private function create_order( $customer_id = 1, $product = null ) { + + if ( ! is_a( $product, 'WC_Product' ) ) { + $product = $this->create_simple_product(); + } + + $this->create_simple_flat_rate(); + + $order_data = array( + 'status' => 'pending', + 'customer_id' => $customer_id, + 'customer_note' => '', + 'total' => '', + ); + + $_SERVER['REMOTE_ADDR'] = '127.0.0.1'; // Required, else wc_create_order throws an exception. + $order = \wc_create_order( $order_data ); + + // Add order products. + $item = new \WC_Order_Item_Product(); + $item->set_props( + array( + 'product' => $product, + 'quantity' => 4, + 'subtotal' => \wc_get_price_excluding_tax( $product, array( 'qty' => 4 ) ), + 'total' => \wc_get_price_excluding_tax( $product, array( 'qty' => 4 ) ), + ) + ); + $item->save(); + $order->add_item( $item ); + + // Set billing address. + $order->set_billing_first_name( 'Jeroen' ); + $order->set_billing_last_name( 'Sormani' ); + $order->set_billing_company( 'WooCompany' ); + $order->set_billing_address_1( 'WooAddress' ); + $order->set_billing_address_2( '' ); + $order->set_billing_city( 'WooCity' ); + $order->set_billing_state( 'NY' ); + $order->set_billing_postcode( '12345' ); + $order->set_billing_country( 'US' ); + $order->set_billing_email( 'admin@example.org' ); + $order->set_billing_phone( '555-32123' ); + + // Add shipping costs. + $shipping_taxes = \WC_Tax::calc_shipping_tax( '10', \WC_Tax::get_shipping_tax_rates() ); + $rate = new \WC_Shipping_Rate( 'flat_rate_shipping', 'Flat rate shipping', '10', $shipping_taxes, 'flat_rate' ); + $item = new \WC_Order_Item_Shipping(); + $item->set_props( + array( + 'method_title' => $rate->label, + 'method_id' => $rate->id, + 'total' => wc_format_decimal( $rate->cost ), + 'taxes' => $rate->taxes, + ) + ); + foreach ( $rate->get_meta_data() as $key => $value ) { + $item->add_meta_data( $key, $value, true ); + } + $order->add_item( $item ); + + // Set payment gateway. + $payment_gateways = WC()->payment_gateways->payment_gateways(); + $order->set_payment_method( $payment_gateways['bacs'] ); + + // Set totals. + $order->set_shipping_total( 10 ); + $order->set_discount_total( 0 ); + $order->set_discount_tax( 0 ); + $order->set_cart_tax( 0 ); + $order->set_shipping_tax( 0 ); + $order->set_total( 50 ); // 4 x $10 simple helper product + + return $order->save(); + } + + public function test_callback_transition_post_status() { + $this->mock->expects( $this->exactly( 4 ) ) + ->method( 'log' ) + ->withConsecutive( + array( + $this->equalTo( + esc_html_x( + '%s created', + 'Order title', + 'stream' + ) + ), + $this->callback( + function( $meta ) { + $expected_meta = array( + 'singular_name' => 'order', + 'new_status' => 'wc-pending', + 'old_status' => 'new', + 'revision_id' => null, + ); + + return $expected_meta === array_intersect_key( $expected_meta, $meta ); + } + ), + $this->greaterThan( 0 ), + $this->equalTo( 'shop_order' ), + $this->equalTo( 'created' ), + ), + array( + $this->equalTo( + esc_html_x( + '%s trashed', + 'Order title', + 'stream' + ) + ), + $this->callback( + function( $meta ) { + $expected_meta = array( + 'singular_name' => 'order', + 'new_status' => 'trashed', + 'old_status' => 'wc-pending', + 'revision_id' => null, + ); + + return $expected_meta === array_intersect_key( $expected_meta, $meta ); + } + ), + $this->greaterThan( 0 ), + $this->equalTo( 'shop_order' ), + $this->equalTo( 'trashed' ), + ), + array( + $this->equalTo( + esc_html_x( + '%s restored from the trash', + 'Order title', + 'stream' + ) + ), + $this->callback( + function( $meta ) { + $expected_meta = array( + 'singular_name' => 'order', + 'new_status' => 'wc-pending', + 'old_status' => 'trashed', + 'revision_id' => null, + ); + + return $expected_meta === array_intersect_key( $expected_meta, $meta ); + } + ), + $this->greaterThan( 0 ), + $this->equalTo( 'shop_order' ), + $this->equalTo( 'untrashed' ), + ), + array( + $this->equalTo( + esc_html_x( + '%s updated', + 'Order title', + 'stream' + ) + ), + $this->callback( + function( $meta ) { + $expected_meta = array( + 'singular_name' => 'order', + 'new_status' => 'wc-failed', + 'old_status' => 'wc-pending', + 'revision_id' => null, + ); + + return $expected_meta === array_intersect_key( $expected_meta, $meta ); + } + ), + $this->greaterThan( 0 ), + $this->equalTo( 'shop_order' ), + $this->equalTo( 'updated' ), + ) + ); + + // Create/update/trash/restore order to trigger callback. + $order_id = $this->create_order(); + $this->mock->flush_logged_order(); + + wp_trash_post( $order_id ); + $this->mock->flush_logged_order(); + + wp_untrash_post( $order_id ); + $this->mock->flush_logged_order(); + + wp_update_post( + array( + 'ID' => $order_id, + 'post_status' => 'wc-failed', + ) + ); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_transition_post_status' ) ); + } + + public function test_callback_deleted_post() { + // Create order for later use. + $order_id = $this->create_order(); + $order = \wc_get_order( $order_id ); + + // Expected log call. + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( + _x( + '"%s" deleted from trash', + 'Order title', + 'stream' + ) + ), + $this->equalTo( + array( + 'post_title' => 'Order number '. $order->get_order_number(), + 'singular_name' => 'order', + ) + ), + $this->equalTo( $order_id ), + $this->equalTo( 'shop_order' ), + $this->equalTo( 'deleted' ) + ); + + // Delete order to trigger callback. + wp_delete_post( $order_id ); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_deleted_post' ) ); + } + + public function test_callback_woocommerce_order_status_changed() { + // Create order for later use. + $order_id = $this->create_order(); + $order = \wc_get_order( $order_id ); + + // Expected log call. + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( '%1$s status changed from %2$s to %3$s' ), + $this->equalTo( + array( + 'post_title' => 'Order number '. $order->get_order_number(), + 'old_status_name' => 'Pending payment', + 'new_status_name' => 'Completed', + 'singular_name' => 'order', + 'new_status' => 'completed', + 'old_status' => 'pending', + 'revision_id' => null, + ) + ), + $this->equalTo( $order_id ), + $this->equalTo( 'shop_order' ), + $this->equalTo( 'updated' ) + ); + + // Update order status to trigger callback. + $order->update_status( 'completed' ); + $order->save(); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_woocommerce_order_status_changed' ) ); + } + + public function test_callback_woocommerce_attribute_added() { + // Expected log calls + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( '"%s" product attribute created' ), + $this->equalTo( + array( + 'attribute_label' => 'color', + 'attribute_name' => 'color', + 'attribute_type' => 'select', + 'attribute_orderby' => 'menu_order', + 'attribute_public' => 0, + ) + ), + $this->greaterThan( 0 ), + $this->equalTo( 'attributes' ), + $this->equalTo( 'created' ) + ); + + // Create attribute to product to trigger callback. + \wc_create_attribute( + array( + 'name' => 'color', + 'slug' => 'color', + 'text' => 'text', + ) + ); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_woocommerce_attribute_added' ) ); + } + + public function test_callback_woocommerce_attribute_updated() { + // Create attribute for later use. + $attribute_id = \wc_create_attribute( + array( + 'name' => 'color', + 'slug' => 'color', + 'text' => 'text', + ) + ); + + // Expected log calls + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( '"%s" product attribute updated' ), + $this->equalTo( + array( + 'attribute_label' => 'color', + 'attribute_name' => 'colors', + 'attribute_type' => 'select', + 'attribute_orderby' => 'menu_order', + 'attribute_public' => 0, + ) + ), + $this->equalTo( $attribute_id ), + $this->equalTo( 'attributes' ), + $this->equalTo( 'updated' ) + ); + + // Update attribute to trigger callback. + \wc_update_attribute( $attribute_id, array( 'slug' => 'colors' ) ); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_woocommerce_attribute_updated' ) ); + } + + public function test_callback_woocommerce_attribute_deleted() { + // Create attribute for later use. + $attribute_id = \wc_create_attribute( + array( + 'name' => 'color', + 'slug' => 'color', + 'text' => 'text', + ) + ); + + // Expected log calls + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( '"%s" product attribute deleted' ), + $this->equalTo( + array( + 'attribute_name' => 'color' + ) + ), + $this->equalTo( $attribute_id ), + $this->equalTo( 'attributes' ), + $this->equalTo( 'deleted' ) + ); + + // Delete attribute to trigger callback. + \wc_delete_attribute( $attribute_id ); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_woocommerce_attribute_deleted' ) ); + } + + public function test_callback_woocommerce_tax_rate_added() { + // Create tax rate array for later use. + $tax_rate = array( + 'tax_rate' => '10', + 'tax_rate_name' => 'test tax rate', + ); + + // Expected log calls + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( '"%4$s" tax rate created' ), + $this->equalTo( $tax_rate ), + $this->greaterThan( 0 ), + $this->equalTo( 'tax' ), + $this->equalTo( 'created' ) + ); + + // Create tax rate to trigger callback. + \WC_Tax::_insert_tax_rate( $tax_rate ); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_woocommerce_tax_rate_added' ) ); + } + + public function test_callback_woocommerce_tax_rate_updated() { + // Create tax rate for later use. + $tax_rate = array( + 'tax_rate_country' => 'USA', + 'tax_rate_state' => 'Pennsylvania', + 'tax_rate' => '10', + 'tax_rate_name' => 'test tax rate', + 'tax_rate_priority' => 1, + 'tax_rate_compound' => 1, + 'tax_rate_shipping' => 1, + 'tax_rate_order' => 0, + 'tax_rate_class' => '', + ); + $tax_rate_id = \WC_Tax::_insert_tax_rate( $tax_rate ); + + // Check tax rate data here for use in the upcoming `with()`. + $tax_rate['tax_rate_state'] = 'Virginia'; + + // Expected log calls + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( '"%4$s" tax rate updated' ), + $this->equalTo( $tax_rate ), + $this->equalTo( $tax_rate_id ), + $this->equalTo( 'tax' ), + $this->equalTo( 'updated' ) + ); + + // Update tax rate to trigger callback. + \WC_Tax::_update_tax_rate( $tax_rate_id, $tax_rate ); + + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_woocommerce_tax_rate_updated' ) ); + } + + public function test_callback_woocommerce_tax_rate_deleted() { + // Create tax rate for later use. + $tax_rate = array( + 'tax_rate_country' => 'USA', + 'tax_rate_state' => 'Pennsylvania', + 'tax_rate' => '10', + 'tax_rate_name' => 'test tax rate', + 'tax_rate_priority' => 1, + 'tax_rate_compound' => 1, + 'tax_rate_shipping' => 1, + 'tax_rate_order' => 0, + 'tax_rate_class' => '', + ); + $tax_rate_id = \WC_Tax::_insert_tax_rate( $tax_rate ); + + // Expected log calls + $this->mock->expects( $this->once() ) + ->method( 'log' ) + ->with( + $this->equalTo( 'Tax rate identified by ID:"%s" deleted' ), + $this->equalTo( compact( 'tax_rate_id' ) ), + $this->equalTo( $tax_rate_id ), + $this->equalTo( 'tax' ), + $this->equalTo( 'deleted' ) + ); + + // Delete tax rate to trigger callback. + \WC_Tax::_delete_tax_rate( $tax_rate_id ); + + // Check callback test action. + $this->assertGreaterThan( 0, did_action( $this->action_prefix . 'callback_woocommerce_tax_rate_deleted' ) ); + } + + public function test_callback_updated_option() { + $this->markTestSkipped( 'This test needs to be written.' ); + } +}