Resolving conflict with migration branch
This commit is contained in:
commit
3a7aeb04e6
|
@ -13,7 +13,7 @@ There are many ways to contribute to the project!
|
|||
|
||||
If you wish to contribute code, please read the information in the sections below. Then [fork](https://help.github.com/articles/fork-a-repo/) WooCommerce, commit your changes, and [submit a pull request](https://help.github.com/articles/using-pull-requests/) 🎉
|
||||
|
||||
We use the `help wanted` label to mark issues that are suitable for new contributors. You can find all the issues with this label [here](https://github.com/woocommerce/woocommerce/issues?q=is%3Aopen+is%3Aissue+label%3A%22help+wanted%22).
|
||||
We use the `good first issue` label to mark issues that are suitable for new contributors. You can find all the issues with this label [here](https://github.com/woocommerce/woocommerce/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
|
||||
|
||||
WooCommerce is licensed under the GPLv3+, and all contributions to the project will be released under the same license. You maintain copyright over any contribution you make, and by submitting a pull request, you are agreeing to release that contribution under the GPLv3+ license.
|
||||
|
||||
|
|
14
.travis.yml
14
.travis.yml
|
@ -5,6 +5,8 @@ dist: xenial
|
|||
services:
|
||||
- xvfb
|
||||
- mysql
|
||||
- docker
|
||||
- docker-compose
|
||||
|
||||
sudo: false
|
||||
|
||||
|
@ -32,14 +34,10 @@ matrix:
|
|||
- name: "Coding standard check"
|
||||
php: 7.2
|
||||
env: WP_VERSION=latest WP_MULTISITE=0 RUN_PHPCS=1
|
||||
- name: "e2e tests"
|
||||
php: 7.2
|
||||
env: WP_VERSION=latest WP_MULTISITE=0 RUN_E2E=1
|
||||
addons:
|
||||
chrome: beta
|
||||
apt:
|
||||
packages:
|
||||
- nginx
|
||||
- name: "E2E tests"
|
||||
env: RUN_E2E=1
|
||||
script:
|
||||
- docker-compose up -d
|
||||
- name: "Unit tests code coverage"
|
||||
php: 7.3
|
||||
env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
|
||||
|
|
220
CHANGELOG.txt
220
CHANGELOG.txt
|
@ -1,5 +1,225 @@
|
|||
== Changelog ==
|
||||
|
||||
= 3.8.0 - 2019-11-05 =
|
||||
* Enhancement - Show error message in "My Account - view order" if order does not exist. #24435
|
||||
* Enhancement - Add support to allow connect and install for in-app purchase flow. #24451
|
||||
* Enhancement - Declared support to Unicode CLDR. #24564
|
||||
* Enhancement - Declared support for PHP 7.4 in CI by removing PHP 7.4 from list of allowed failures. #24668
|
||||
* Enhancement - Update the recommended PHP version to 7.0 and the recommended WP version to 5.0. #24730
|
||||
* Enhancement - Change On Boarding Wizard to opt out of usage tracking by default. #24680
|
||||
* Enhancement - Add `Available on backorder` message for products available on backorder. #24559
|
||||
* Tweak - Hide Vietnam's state field. #24158
|
||||
* Tweak - Better wording when no downloads are available on My Account > Downloads. #24172
|
||||
* Tweak - Only consider orders created via checkout to hold stock. #24159
|
||||
* Tweak - Stop to load order data twice in "View order" screen on "My Account" page. #24437
|
||||
* Tweak - Prevent PHP warnings in tracker if order doesn't have a created date yet. #24441
|
||||
* Tweak - Use `wc_get_checkout_url()` to get checkout URL. #24544
|
||||
* Tweak - Maintain value of select fields in credit card form. #24720
|
||||
* Tweak - Prevent filter per category while exporting product variations. #24517
|
||||
* Tweak - Better wording for subtotal of items in cart and review order. #24440
|
||||
* Tweak - Prevent new lines in product quantity in checkout details. #24311
|
||||
* Tweak - Add a tooltip in the "Coupon expity date" field. #24749
|
||||
* Tweak - CSS styling changes for WP 5.3. #24832
|
||||
* Template - Moved HTML for displaying product price filter widget to a new template `product price filter widget`. #23384
|
||||
* Accessibility - Make $subtext color darker. #24739
|
||||
* Dev - Consistent register/login submit button css class names. Preserve old class names as well for backwards compatibility. #23701
|
||||
* Dev - Added woocommerce_disable_password_change_notification filter, set to false by default. #24154
|
||||
* Dev - Add filter `woocommerce_cart_item_removed_message` and `woocommerce_cart_product_cannot_be_purchased_message` to filter notice content when an item is removed from cart, or when a product cannot be purchased. #24176
|
||||
* Dev - Prevent fatal error if trying to run `wc_load_cart()` before `before_woocommerce_init`. #24198
|
||||
* Dev - Add woocommerce_get_zone_criteria filter hook to add custom criteria for matching zone ID. #24199
|
||||
* Dev - Fire actions `woocommerce_before_delete_product_variation`, `woocommerce_delete_product_variation` and `woocommerce_trash_product_variation` appropriately when deleting or trashing product variations. #24239
|
||||
* Dev - In filter `woocommerce_update_product_stock_query` use `$new_stock` instead of `$stock_quantity`. #24229
|
||||
* Dev - Introduced woocommerce_prevent_adjust_line_item_product_stock filter. #24279
|
||||
* Dev - Introduced `woocommerce_logout_default_redirect_url` filter to allow custom default URL. #24282
|
||||
* Dev - Added woocommerce_sort_fees_callback filter. #24280
|
||||
* Dev - Remove deprecated i18n/states directory. #24364
|
||||
* Dev - Add filter `woocommerce_shipping_show_shipping_calculator` for showing shipping calculator. #24375
|
||||
* Dev - Corrected UG states location. #24388
|
||||
* Dev - Remove deprecations notices with PHP 7.4 by changing parameter order for `implode`. #24396
|
||||
* Dev - Add ``$this` param to email filter for additional_content added in 3.7. #24399
|
||||
* Dev - Add `woocommerce_product_import_process_item_data` filter to allow modifying a row before importing. #24412
|
||||
* Dev - Fixed warnings when error_get_last() returns null. #24442
|
||||
* Dev - Use brackets instead of braces to avoid deprecation notice in PHP 7.4. #24460
|
||||
* Dev - Implement Puppeteer's architecture for running E2E tests locally. #24479
|
||||
* Dev - Remove call to get_magic_quotes_runtime() as it is deprecated as of PHP 7.4. #24485
|
||||
* Dev - Return value of `$mailer->send()` in `wc_mail` function. #24505
|
||||
* Dev - Remove Selenium e2e tests & add Puppeteer new product e2e test. #24513
|
||||
* Dev - Add a filter `woocommerce_ajax_add_order_item_validation` to allow validations in `add_order_item` function. #24518
|
||||
* Dev - Use `wc_get_cart_url` instead of `wc_get_page_permalink( 'cart' )` because former has a filter `woocommerce_get_cart_url` to allow customization. #24530
|
||||
* Dev - New `woocommerce_product_after_tabs` action hook added. #24694
|
||||
* Dev - Enable append hashes on custom events (like ajax requests) #24665
|
||||
* Dev - Introduced `woocommerce_order_get_formatted_billing_address` and `woocommerce_order_get_formatted_shipping_address` filters. #24677
|
||||
* Dev - WC_Abstract_Order::recalculate_coupons() is public now. #24740
|
||||
* Dev - Added 'applied_coupon' trigger to checkout.js. #24406
|
||||
* Dev - Introduced woocommerce_output_cart_shortcode_content filter. #24738
|
||||
* Dev - Add WPML compatibility to the geolocation URL. #24722
|
||||
* Dev - Validate server requirements in WCCCOM Site Installer endpoints. #24690
|
||||
* Dev - Introduced woocommerce_payment_token_class filter. #24542
|
||||
* Dev - Add support for post type count to system status report. #24536
|
||||
* Dev - Check for max discount to be -ve to prevent overwriting refunded fee amount. #24341
|
||||
* Dev: Add filter woocommerce_european_union_countries to the method WC_Countries::get_european_union_countries(). #24741
|
||||
* Dev - Allow WC_Product_Query sort products by include order. #24294
|
||||
* Dev - Removed duplicated include of WC_Admin_Importers. #24751
|
||||
* Dev - Refactor minimum requirement notice to use constant for easier changes in the future. #24830
|
||||
* Fix - Clean products transients when term is removed. #23991
|
||||
* Fix - Only add the image node to structured data if product has image. #24191
|
||||
* Fix - Product attribute terms endpoint in legacy REST API v3 by converting `attribute_id` to int. #24203
|
||||
* Fix - Prevent duplicate processing/stock reduction when IPN or PDT notifications are enabled by checking if order is not already in `processing` or `completed` status. #24249
|
||||
* Fix - Position of ID section in mobile rows actions when displaying the list of products in the admin. #24277
|
||||
* Fix - Endpoints URLs to follow slashes preferences from WordPress permalinks. #24283
|
||||
* Fix - Ensure that postcode validation doesn't return any whitespace on beginning and end of a postcode. #24284
|
||||
* Fix - Shipping classes sort under products alphabetically. #24291
|
||||
* Fix - Shipping rates layout in admin settings. #24327
|
||||
* Fix - Retain the focus on the select box when product variation is changed. #24339
|
||||
* Fix - Prevent PHP notice in WC_Order_Item_Data_Store::get_order_item_type() when there is no entry in the database for the order item ID passed. #24353
|
||||
* Fix - Add translation in class-wc-shipping.php for matching zone message. #24366
|
||||
* Fix - Previewing email template. #24380
|
||||
* Fix - Check if order exist before generate hash for downloads. #24384
|
||||
* Fix - Ensure WC_Product_Data_Store_CPT::is_existing_sku() return boolean. #24385
|
||||
* Fix - `function_exists` check for wc_hex_is_light(). #24391
|
||||
* Fix - Removed Emoji from default additional email content due problem on some database that doesn't allow Emojis. #24450
|
||||
* Fix - Fixed escaping on an attribute in `class-wc-admin-menus.php`. #24466
|
||||
* Fix - Add translation for image alt attribute text in multiple places. #24467, #24468, #24469
|
||||
* Fix - Uneven padding in the input field with class "location-input" in on boarding wizard. #24476
|
||||
* Fix - Duplicate id in pages settings. #24478
|
||||
* Fix - Use `esc_attr_e` instead of `esc_html_e` for escaping an attribute in multiple places. #24481, #24520, #24521, #24522, #24523, #24524
|
||||
* Fix - Use `esc_attr__` instead of `esc_html__` in escaping attributes string. #24525, #24529
|
||||
* Fix - Typo fix in payment captured error message. #24501
|
||||
* Fix - Documentation URL in failed order email content. #24535
|
||||
* Fix - "Add to cart" links in feed. #24545
|
||||
* Fix - Escaping in Storefront banner. #24546
|
||||
* Fix - Use `wp_kses_post` to allow certain html tags in extensions page. #24589
|
||||
* Fix - Escape `$prefix` in item download links. #24601
|
||||
* Fix - Use `esc_attr` instead of `esc_html` in multiple places for proper escaping. #24613, #24614
|
||||
* Fix - Use `esc_html` instead of `esc_attr` in multiple places for proper escaping. #24616
|
||||
* Fix - Use `esc_html_e` instead of `_e` in multiple places for proper escaping. #24615, #24618, #24630
|
||||
* Fix - Use `esc_html__` instead of `esc_html` for proper escaping and some typo fixes. #24639
|
||||
* Fix - Add no-store and remove max-age header (no longer needed). #24652
|
||||
* Fix - Use correct meta value for `downloadable` column in product lookup table regenerate function. #24681
|
||||
* Fix - Admin sub-menus becoming unaligned when scrolling down in the orders page when there are no orders. #24688
|
||||
* Fix - OWB country and sell in person alignment. #24700
|
||||
* Fix - Domain replacement script now replaces both double and single quoted `woo-gutenberg-products-block` with `woocommerce` in both PHP and JavaScript files. #24696
|
||||
* Fix - Convert `current_user_id` to string in some places to prevent unnecessary session database updates. #24016
|
||||
* Fix - Fixed description of failed order emails. #24737
|
||||
* Fix - Fixed Photoswipe styles. #24296
|
||||
* Fix - Also consider refunded item when updating order and adjusting stocks. #24745
|
||||
* Fix - Handle 0 attribute value for variations correctly. #24750
|
||||
* Fix - Fixed spaces in form fields of External Products. #24295
|
||||
* Fix - Removed links to downloadable products from refund emails. #24952
|
||||
* Localization - Add Zambia's Provinces to the list of states. #24307
|
||||
* Localization - Adaptation of the order of last name and first name and addresses in Japan. #24336
|
||||
* Localization - Fixed Namibian dollar symbol. #24438
|
||||
* Localization - Change localization tag `action-scheduler` to `woocommerce`. #24474
|
||||
* Localization - Fixed missing US Minor Outlying Islands states. #24826
|
||||
* Security - Add an exit after the redirect when checking author archive capabilities for customers.
|
||||
* Security - Ensure 404 pages with single product urls cannot be exploited using Open Redirect.
|
||||
|
||||
= 3.7.1 - 2019-10-09
|
||||
* Security - Add an exit after the redirect when checking author archive capabilities for customers.
|
||||
* Security - Ensure 404 pages with single product urls cannot be exploited using Open Redirect.
|
||||
|
||||
= 3.7.0 - 2019-08-12 =
|
||||
* Enhancement - Added table ENGINE to system status report for debugging purposes. #23101
|
||||
* Enhancement - Format empty cart message as information notice. #23152
|
||||
* Enhancement - Add taxonomy-specific classes to active filters widget. #23122
|
||||
* Enhancement - Allow emails `Thanks` wording to be modified via the email settings. #22927
|
||||
* Enhancement - Move tax classes from WordPress Options to a new `wc_tax_rate_classes` table. #23093
|
||||
* Enhancement - Make WooCommerce shop roles translatable. #23150
|
||||
* Enhancement - Prevent the Cart, Checkout and My Account pages from being set to the same pages. #23479
|
||||
* Enhancement - New coupon code generate button on the coupon page. #24069
|
||||
* Enhancement - Add `tag_operator` paramater to the `[products]` shortcode for use with the `tag` paramater ie. `[products tag='tag1,tag2' tag_operator='AND']`. #24111
|
||||
* Tweak - When cleaning up variations due to product type change, force delete them instead of trashing. #23478
|
||||
* Tweak - Change wording on the link to change the address so reflect if an address is already present or not. #23532
|
||||
* Tweak - If variations are missing prices, show a notice in the product data panel. #23133
|
||||
* Tweak - Use `determine_locale()` to properly load custom translation files. #23785
|
||||
* Tweak - OBW: Switch shipping labels and shipping zones placement. #23781
|
||||
* Tweak - Show the quantity refunded on customer facing order screens. #23038
|
||||
* Tweak - CSV product import now allows true/false values for the published field, as well as the original 0 (private), -1 (draft), 1 (publish) values. #23207
|
||||
* Tweak - Update product attribute sorting tooltip to clarify usage. #23222
|
||||
* Tweak - Store tax rate percentage in the tax line items on orders. #23268
|
||||
* Tweak - Remove the left and right margin from the logo in emails. #23360
|
||||
* Tweak - Use the high res version of the WP spinner in the coupon Block UI. #23364
|
||||
* Tweak - Improve user registration validation messages. #23468
|
||||
* Tweak - Auto generate a new username when a username is blacklisted by WordPress. #23672
|
||||
* Tweak - Guest cart sessions now gets deleted when a user logs in, preventing duplicate cart sessions. #23687
|
||||
* Tweak - Include the store's base postcode and city when calculating order taxes. #23695
|
||||
* Tweak - Update the generate username setting description label to reflect how the username is actually generated. #23911
|
||||
* Tweak - OBW: Adjust plugin highlight container sizes to avoid overlap. #23997
|
||||
* Tweak - Round tax amounts late when the round at subtotal level setting is enabled to reduce rounding errors. #24024
|
||||
* Tweak - OBW: Now includes WooCommerce Admin as a recommended plugin. #24058
|
||||
* Template - Review and update all template files escaping. #23460
|
||||
* Template - Remove mention of shipping section from the checkout/form-login.php template as shipping is not always a requirement for an order. #23941
|
||||
* Template - Add new filter `woocommerce_before_thankyou` to the checkout/thankyou.php template. #23538
|
||||
* Template - Add new `woocommerce_widget_shopping_cart_total` hook to replace hardcoded subtotal in cart/mini-cart.php template. #24145
|
||||
* Template - Add new `woocommerce_widget_shopping_cart_after_buttons` hook in cart/mini-cart.php template. #24145
|
||||
* Template - Add new `woocommerce_before_cart_collaterals` hook in cart/cart.php template. #24145
|
||||
* Template - Correct the plural forms usage in loop/result-count.php template. #24005
|
||||
* Dev - Introduce new PHP 5.6 minimum requirement. #23924
|
||||
* Dev - Introduce new WordPress 4.9 minimum requirement. #24156
|
||||
* Dev - Move the settings save functionality from the `settings_page_init` function to the `wp_loaded` action so it is not saved after the settings page renders. #23091
|
||||
* Dev - Add quantity input action hooks `woocommerce_before_add_to_cart_quantity` and `woocommerce_after_add_to_cart_quantity`. #23166
|
||||
* Dev - Add `$this` parameter to email class filters. #23250
|
||||
* Dev - Add new `WC_Abstract_Order::get_coupons()` method for returning all coupon line item objects on an order. #23663
|
||||
* Dev - Added new action `woocommerce_product_read` to `WC_Product_Data_Store_CPT::read()`. #23181
|
||||
* Dev - Add new filter `woocommerce_admin_order_buyer_name` to the `WC_Admin_List_Table_Orders::render_order_number_column()` method to change the buyer name in orders list screen. #23741
|
||||
* Dev - Add new actions to `WC_Helper` class for when WooCommerce.com Product Subscription statuses change `woocommerce_helper_subscription_activate_success`, `woocommerce_helper_subscription_activate_error`, `woocommerce_helper_subscription_deactivate_success`, and `woocommerce_helper_subscription_deactivate_error`. #23041
|
||||
* Dev - Extend usage and event tracking (if opted in) to system status, admin order and admin coupon pages. #23190 #23189 #23883
|
||||
* Dev - Add `woocommerce_after_X_object_save` actions, and passed objects to `woocommerce_new_x` and `woocommerce_update_x` actions. #23338
|
||||
* Dev - Update customer order and lifetime spend totals in `wc_update_new_customer_past_orders()` to trigger `customer.updated` webhooks for paid orders. #23402
|
||||
* Dev - Preserve the State field's custom css classes when selecting an option from the Country dropdown. #23433
|
||||
* Dev - Add new `woocommerce_product_related_posts_shuffle` filter in `wc_get_related_products()` to enable/disable related product shuffling, defaults to true. #23562
|
||||
* Dev - Deprecate the `WC_Abstract_Order::get_used_coupons()` method and replace it with a new method `WC_Abstract_Order::get_coupon_codes()`. #23689
|
||||
* Dev - Add new `woocommerce_prices_include_tax` filter in the `wc_prices_include_tax()` function. #23697
|
||||
* Dev - Add new `woocommerce_admin_after_product_gallery_item` filter in the `WC_Meta_Box_Product_Images::output()` method for adding additional markup after product gallery items. #23743
|
||||
* Dev - Remove unused images `assets/images/klarna-white.png` and `assets/images/square-white.png`. #23748
|
||||
* Dev - Move Free Shipping method JavaScript code from outputting on all shipping setting pages to just the Free Shipping page using the `admin_footer` hook. #23776
|
||||
* Dev - Prevent PHP fatal error while throwing exceptions in `woocommerce_rest_insert_{post_type}_object` hooks. #23793
|
||||
* Dev - Add new `woocommerce_enforce_password_strength_meter_on_checkout` filter in the `WC_Frontend_Scripts::get_script_data()` method to allow enforcing the password strength meter on checkout. #23811
|
||||
* Dev - Add new `woocommerce_search_products_post_statuses` filter in the `WC_Product_Data_Store_CPT::search_products()` method for controlling what post statuses to include in product searches. #23838
|
||||
* Dev - Allow filtering `woocommerce_order_formatted_shipping_address` even when no shipping address is defined. #23859
|
||||
* Dev - Change the query in the `WC_Product_Data_Store::find_matching_product_variation()` method to always respect the ordering of variations. #23881
|
||||
* Dev - Move all feature plugin features out from the WooCommerce codebase and utilize composer and an autoloader for including it in WooCommerce core, affects WC REST API and WC Blocks. #23957
|
||||
* Dev - Allow displaying multiple error messages through the registration validation. #23968
|
||||
* Dev - Add new `woocommerce_cart_item_removed_notice_type`, `woocommerce_cart_updated_notice_type` and `woocommerce_add_to_cart_notice_type` filters for changing the default notice types for cart notices. #24021
|
||||
* Dev - Add namespaced support for Jetpack 7.5 tracking library. #24140
|
||||
* Dev - Add support for an improved WooCommerce.com Marketplace browse and purchase experience (in progress). #24075 #24123
|
||||
* Dev - Added `$order` and `$product` as parameters to the `woocommerce_ajax_order_item` filter in `WC_Ajax::add_order_item()`. #24108
|
||||
* Dev - Add new `woocommerce_product_import_image_separator` filter in `WC_Product_CSV_Importer::parse_images_field()` for adjusting the product images seperator. #24120
|
||||
* Dev - Add new `woocommerce_widget_shopping_cart_subtotal()` template function that hooks into the `woocommerce_widget_shopping_cart_total` action to output the mini cart subtotal. #24145
|
||||
* Dev - Deprecate the `woocommerce_before_cart_item_quantity_zero` action from `WC_Cart::restore_cart_item()` in favor of existing `woocommerce_cart_item_removed` action. #23112
|
||||
* Dev - Deprecate WC_Tax::maybe_remove_tax_class_rates which hooked into the WP Options update hook for taxes in favor of new function WC_Tax::delete_tax_class_by which works on the new tax classes table. #24213
|
||||
* Fix - Use version_compare for determining the maximum WooCommerce database version number. #23092
|
||||
* Fix - Missing space and closing `<strong>` tag in WooCommerce.com disconnect message. #24073
|
||||
* Fix - CSV Importer - Skip rows during update if a SKU column exists, but the value is empty. #23262
|
||||
* Fix - Allow matching `Any` attributes when calling `WC_Product_Data_Store::find_matching_product_variation()`. #23067
|
||||
* Fix - Switch coupon amount validation based on decimal seperator setting. #23137
|
||||
* Fix - Show the correct results for shortcodes on static homepages when sorting. #23159
|
||||
* Fix - Queue AJAX add to cart events to avoid overwriting session data. #23293
|
||||
* Fix - Wrong subtotals when changing tax classes via the `woocommerce_product_get_tax_class` filter. #23344
|
||||
* Fix - Fatal error on plain text order emails where products were deleted. #23754
|
||||
* Fix - Do not pass the `no_shipping` argument to PayPal when the order contains shippable items. #23773
|
||||
* Fix - Product review form does respects the `require_name_email` WordPress core option. #23786
|
||||
* Fix - Do not cache expired sessions, negative expiry causes errors in some caching modules. #23863
|
||||
* Fix - WC_Log_Handler_DB logs now uses the same timestamp format as text logs, Y-m-d H:i:s. #23863
|
||||
* Fix - Display line breaks for customer notes in emails, and order details. #23969
|
||||
* Fix - Correct plural forms usage in `WC_Admin_Report` class. #24020
|
||||
* Fix - System status database info section throwing a PHP notice on some DB environments. #24023
|
||||
* Fix - On the system status database info section display a message informing users that WooCommerce was unable to get database information instead of an error, when a database sharding plugin is active. #24034
|
||||
* Fix - Usage and event tracking (if opted in) was not working correctly in the OBW. #24056
|
||||
* Fix - Fatal error on downloads report when some download files were missing. #24118
|
||||
* Fix - Prevents the taxes columns from being removed when the order is no longer editable in admin. #23884
|
||||
* Performance - Improve the speed of the admin dashboard by only updating transients once per class. #23011
|
||||
* Performance - Reduce number of queries needed to populate variations data by priming post caches. #23272
|
||||
* Performance - Persistant cart improvements, only update the persistent cart if the cart items actually change. #23112
|
||||
* Performance - Exclude `action_log` comment types from `wp_count_comments`. #24071
|
||||
* Localization - Added validation for Italian postcodes. #23269
|
||||
* Localization - Remove unused tax locale defaults since we now promote auto tax services instead. #23431
|
||||
* Localization - Define correct address format for Uganda. #23178
|
||||
* Localization - Hide the postcode and update the state label to "Province" for Mozambique. #23764
|
||||
* Localization - OBW: Make postal code optional based on locale data. #23915
|
||||
* Localization - Add new currency for São Tomé, Príncipe dobra and Mauritanian ouguiya. #23950
|
||||
* Localization - Change Canada poscode label to `Postal code`. #23740
|
||||
|
||||
= 3.6.5 - 2019-07-02 =
|
||||
* Security - Introduce file type check for tax rate importer.
|
||||
* Security - Added nonce check to CSV importer actions.
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
FROM wordpress:latest
|
||||
|
||||
COPY . /var/www/html/wp-content/plugins/woocommerce
|
|
@ -4184,6 +4184,10 @@ img.help_tip {
|
|||
padding: 2px;
|
||||
display: none;
|
||||
|
||||
@media (max-width: 768px) {
|
||||
display: block;
|
||||
}
|
||||
|
||||
li {
|
||||
float: right;
|
||||
margin: 0 0 0 2px;
|
||||
|
|
|
@ -360,9 +360,12 @@ jQuery( function( $ ) {
|
|||
// Always update the fragments
|
||||
if ( data && data.fragments ) {
|
||||
$.each( data.fragments, function ( key, value ) {
|
||||
if ( ! wc_checkout_form.fragments || wc_checkout_form.fragments[ key ] !== value ) {
|
||||
$( key ).replaceWith( value );
|
||||
}
|
||||
$( key ).unblock();
|
||||
} );
|
||||
wc_checkout_form.fragments = data.fragments;
|
||||
}
|
||||
|
||||
// Recheck the terms and conditions box, if needed
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
"automattic/jetpack-autoloader": "^1.2.0",
|
||||
"php": ">=5.6|>=7.0",
|
||||
"composer/installers": "1.7.0",
|
||||
"woocommerce/woocommerce-blocks": "2.4.3",
|
||||
"woocommerce/woocommerce-blocks": "2.4.5",
|
||||
"woocommerce/woocommerce-rest-api": "1.0.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "7.5.16",
|
||||
"woocommerce/woocommerce-sniffs": "0.0.8"
|
||||
"phpunit/phpunit": "7.5.17",
|
||||
"woocommerce/woocommerce-sniffs": "0.0.9"
|
||||
},
|
||||
"config": {
|
||||
"platform": {
|
||||
|
|
|
@ -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": "c955d86ce8d65e6fb1e0e97282642d7b",
|
||||
"content-hash": "a5cb448a1d94f10a40207b6f0dfa1c50",
|
||||
"packages": [
|
||||
{
|
||||
"name": "automattic/jetpack-autoloader",
|
||||
|
@ -166,16 +166,16 @@
|
|||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-blocks",
|
||||
"version": "v2.4.3",
|
||||
"version": "v2.4.5",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git",
|
||||
"reference": "9a4b30a18f055ed83d819959cbc1386111f401a5"
|
||||
"reference": "130bc40824f844c0870c94c0ad0aa7a6abb74f6f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/9a4b30a18f055ed83d819959cbc1386111f401a5",
|
||||
"reference": "9a4b30a18f055ed83d819959cbc1386111f401a5",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/130bc40824f844c0870c94c0ad0aa7a6abb74f6f",
|
||||
"reference": "130bc40824f844c0870c94c0ad0aa7a6abb74f6f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -209,7 +209,7 @@
|
|||
"gutenberg",
|
||||
"woocommerce"
|
||||
],
|
||||
"time": "2019-10-14T13:20:09+00:00"
|
||||
"time": "2019-11-02T13:48:18+00:00"
|
||||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-rest-api",
|
||||
|
@ -527,16 +527,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpcompatibility/php-compatibility",
|
||||
"version": "9.3.1",
|
||||
"version": "9.3.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCompatibility/PHPCompatibility.git",
|
||||
"reference": "9999344e47e7af6b00e1a898eacc4e4368fb7196"
|
||||
"reference": "1f37659196e4f3113ea506a7efba201c52303bf1"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/9999344e47e7af6b00e1a898eacc4e4368fb7196",
|
||||
"reference": "9999344e47e7af6b00e1a898eacc4e4368fb7196",
|
||||
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibility/zipball/1f37659196e4f3113ea506a7efba201c52303bf1",
|
||||
"reference": "1f37659196e4f3113ea506a7efba201c52303bf1",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -581,20 +581,20 @@
|
|||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"time": "2019-09-05T18:36:49+00:00"
|
||||
"time": "2019-11-15T04:12:02+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpcompatibility/phpcompatibility-paragonie",
|
||||
"version": "1.1.0",
|
||||
"version": "1.3.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie.git",
|
||||
"reference": "b1bb79a7cab1fb856b56f1b5cf110b6e52d8e936"
|
||||
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b1bb79a7cab1fb856b56f1b5cf110b6e52d8e936",
|
||||
"reference": "b1bb79a7cab1fb856b56f1b5cf110b6e52d8e936",
|
||||
"url": "https://api.github.com/repos/PHPCompatibility/PHPCompatibilityParagonie/zipball/b862bc32f7e860d0b164b199bd995e690b4b191c",
|
||||
"reference": "b862bc32f7e860d0b164b199bd995e690b4b191c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -633,7 +633,7 @@
|
|||
"polyfill",
|
||||
"standards"
|
||||
],
|
||||
"time": "2019-08-28T15:58:19+00:00"
|
||||
"time": "2019-11-04T15:17:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpcompatibility/phpcompatibility-wp",
|
||||
|
@ -837,22 +837,22 @@
|
|||
},
|
||||
{
|
||||
"name": "phpspec/prophecy",
|
||||
"version": "1.8.1",
|
||||
"version": "1.9.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpspec/prophecy.git",
|
||||
"reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76"
|
||||
"reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
|
||||
"reference": "1927e75f4ed19131ec9bcc3b002e07fb1173ee76",
|
||||
"url": "https://api.github.com/repos/phpspec/prophecy/zipball/f6811d96d97bdf400077a0cc100ae56aa32b9203",
|
||||
"reference": "f6811d96d97bdf400077a0cc100ae56aa32b9203",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"doctrine/instantiator": "^1.0.2",
|
||||
"php": "^5.3|^7.0",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0",
|
||||
"phpdocumentor/reflection-docblock": "^2.0|^3.0.2|^4.0|^5.0",
|
||||
"sebastian/comparator": "^1.1|^2.0|^3.0",
|
||||
"sebastian/recursion-context": "^1.0|^2.0|^3.0"
|
||||
},
|
||||
|
@ -896,7 +896,7 @@
|
|||
"spy",
|
||||
"stub"
|
||||
],
|
||||
"time": "2019-06-13T12:50:23+00:00"
|
||||
"time": "2019-10-03T11:07:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
|
@ -1152,16 +1152,16 @@
|
|||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "7.5.16",
|
||||
"version": "7.5.17",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "316afa6888d2562e04aeb67ea7f2017a0eb41661"
|
||||
"reference": "4c92a15296e58191a4cd74cff3b34fc8e374174a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/316afa6888d2562e04aeb67ea7f2017a0eb41661",
|
||||
"reference": "316afa6888d2562e04aeb67ea7f2017a0eb41661",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4c92a15296e58191a4cd74cff3b34fc8e374174a",
|
||||
"reference": "4c92a15296e58191a4cd74cff3b34fc8e374174a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1232,7 +1232,7 @@
|
|||
"testing",
|
||||
"xunit"
|
||||
],
|
||||
"time": "2019-09-14T09:08:39+00:00"
|
||||
"time": "2019-10-28T10:37:36+00:00"
|
||||
},
|
||||
{
|
||||
"name": "sebastian/code-unit-reverse-lookup",
|
||||
|
@ -1802,16 +1802,16 @@
|
|||
},
|
||||
{
|
||||
"name": "squizlabs/php_codesniffer",
|
||||
"version": "3.5.0",
|
||||
"version": "3.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
||||
"reference": "0afebf16a2e7f1e434920fa976253576151effe9"
|
||||
"reference": "65b12cdeaaa6cd276d4c3033a95b9b88b12701e7"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/0afebf16a2e7f1e434920fa976253576151effe9",
|
||||
"reference": "0afebf16a2e7f1e434920fa976253576151effe9",
|
||||
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/65b12cdeaaa6cd276d4c3033a95b9b88b12701e7",
|
||||
"reference": "65b12cdeaaa6cd276d4c3033a95b9b88b12701e7",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -1849,7 +1849,7 @@
|
|||
"phpcs",
|
||||
"standards"
|
||||
],
|
||||
"time": "2019-09-26T23:12:26+00:00"
|
||||
"time": "2019-10-28T04:36:32+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-ctype",
|
||||
|
@ -2001,23 +2001,23 @@
|
|||
},
|
||||
{
|
||||
"name": "woocommerce/woocommerce-sniffs",
|
||||
"version": "0.0.8",
|
||||
"version": "0.0.9",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/woocommerce/woocommerce-sniffs.git",
|
||||
"reference": "ccdae93ba678d59cd9741bec077d0c63c0a82958"
|
||||
"reference": "7677a84e9a355fe1e088f704090be891e7a6d427"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/ccdae93ba678d59cd9741bec077d0c63c0a82958",
|
||||
"reference": "ccdae93ba678d59cd9741bec077d0c63c0a82958",
|
||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-sniffs/zipball/7677a84e9a355fe1e088f704090be891e7a6d427",
|
||||
"reference": "7677a84e9a355fe1e088f704090be891e7a6d427",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"dealerdirect/phpcodesniffer-composer-installer": "0.5.0",
|
||||
"php": ">=7.0",
|
||||
"phpcompatibility/phpcompatibility-wp": "2.1.0",
|
||||
"wp-coding-standards/wpcs": "2.1.1"
|
||||
"wp-coding-standards/wpcs": "2.2.0"
|
||||
},
|
||||
"type": "phpcodesniffer-standard",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
|
@ -2037,20 +2037,20 @@
|
|||
"woocommerce",
|
||||
"wordpress"
|
||||
],
|
||||
"time": "2019-10-16T18:25:21+00:00"
|
||||
"time": "2019-11-11T15:48:34+00:00"
|
||||
},
|
||||
{
|
||||
"name": "wp-coding-standards/wpcs",
|
||||
"version": "2.1.1",
|
||||
"version": "2.2.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/WordPress/WordPress-Coding-Standards.git",
|
||||
"reference": "bd9c33152115e6741e3510ff7189605b35167908"
|
||||
"reference": "f90e8692ce97b693633db7ab20bfa78d930f536a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/bd9c33152115e6741e3510ff7189605b35167908",
|
||||
"reference": "bd9c33152115e6741e3510ff7189605b35167908",
|
||||
"url": "https://api.github.com/repos/WordPress/WordPress-Coding-Standards/zipball/f90e8692ce97b693633db7ab20bfa78d930f536a",
|
||||
"reference": "f90e8692ce97b693633db7ab20bfa78d930f536a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
|
@ -2073,7 +2073,7 @@
|
|||
"authors": [
|
||||
{
|
||||
"name": "Contributors",
|
||||
"homepage": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards/graphs/contributors"
|
||||
"homepage": "https://github.com/WordPress/WordPress-Coding-Standards/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "PHP_CodeSniffer rules (sniffs) to enforce WordPress coding conventions",
|
||||
|
@ -2082,7 +2082,7 @@
|
|||
"standards",
|
||||
"wordpress"
|
||||
],
|
||||
"time": "2019-05-21T02:50:00+00:00"
|
||||
"time": "2019-11-11T12:34:03+00:00"
|
||||
}
|
||||
],
|
||||
"aliases": [],
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
version: '3.7'
|
||||
|
||||
services:
|
||||
|
||||
db:
|
||||
image: mariadb:10.4
|
||||
restart: on-failure
|
||||
environment:
|
||||
MYSQL_DATABASE: testdb
|
||||
MYSQL_USER: wordpress
|
||||
MYSQL_PASSWORD: wordpress
|
||||
MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
|
||||
volumes:
|
||||
- db:/var/lib/mysql
|
||||
|
||||
wordpress-woocomerce-dev:
|
||||
depends_on:
|
||||
- db
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
ports:
|
||||
- 8084:80
|
||||
restart: on-failure
|
||||
environment:
|
||||
WORDPRESS_DB_HOST: db
|
||||
WORDPRESS_DB_NAME: testdb
|
||||
WORDPRESS_DB_USER: wordpress
|
||||
WORDPRESS_DB_PASSWORD: wordpress
|
||||
WORDPRESS_TABLE_PREFIX: "wp_"
|
||||
WORDPRESS_DEBUG: 1
|
||||
volumes:
|
||||
- wordpress:/var/www/html
|
||||
|
||||
wordpress-cli:
|
||||
depends_on:
|
||||
- db
|
||||
- wordpress-woocomerce-dev
|
||||
image: wordpress:cli
|
||||
restart: on-failure
|
||||
user: xfs
|
||||
command: >
|
||||
/bin/sh -c '
|
||||
wp core install --url=http://localhost:8084 --title="WooCommerce Core E2E Test Suite" --admin_user=admin --admin_password=password --admin_email=admin@woocommercecoree2etestsuite.com --path=/var/www/html --skip-email;
|
||||
wp plugin activate woocommerce;
|
||||
wp user create customer customer@woocommercecoree2etestsuite.com --user_pass=password --role=customer --path=/var/www/html;
|
||||
'
|
||||
volumes:
|
||||
- wordpress:/var/www/html
|
||||
|
||||
volumes:
|
||||
db:
|
||||
wordpress:
|
|
@ -599,7 +599,7 @@ class WC_Admin_Setup_Wizard {
|
|||
</article>
|
||||
<footer>
|
||||
<div class="inner">
|
||||
<button class="button button-primary button-large" id="wc_tracker_submit" aria-label="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></a>
|
||||
<button class="button button-primary button-large" id="wc_tracker_submit" aria-label="<?php esc_attr_e( 'Continue', 'woocommerce' ); ?>"><?php esc_html_e( 'Continue', 'woocommerce' ); ?></button>
|
||||
</div>
|
||||
</footer>
|
||||
</section>
|
||||
|
|
|
@ -1592,7 +1592,7 @@ class WC_Helper {
|
|||
/**
|
||||
* Flush subscriptions cache.
|
||||
*/
|
||||
private static function _flush_subscriptions_cache() {
|
||||
public static function _flush_subscriptions_cache() {
|
||||
delete_transient( '_woocommerce_helper_subscriptions' );
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ if ( ! $tab_exists ) {
|
|||
}
|
||||
?>
|
||||
<div class="wrap woocommerce">
|
||||
<?php do_action( 'woocommerce_before_settings_' . $current_tab ); ?>
|
||||
<form method="<?php echo esc_attr( apply_filters( 'woocommerce_settings_form_method_tab_' . $current_tab, 'post' ) ); ?>" id="mainform" action="" enctype="multipart/form-data">
|
||||
<nav class="nav-tab-wrapper woo-nav-tab-wrapper">
|
||||
<?php
|
||||
|
@ -46,4 +47,5 @@ if ( ! $tab_exists ) {
|
|||
<?php wp_nonce_field( 'woocommerce-settings' ); ?>
|
||||
</p>
|
||||
</form>
|
||||
<?php do_action( 'woocommerce_after_settings_' . $current_tab ); ?>
|
||||
</div>
|
||||
|
|
|
@ -637,7 +637,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
|||
*/
|
||||
public function empty_cart( $clear_persistent_cart = true ) {
|
||||
|
||||
do_action( 'woocommerce_before_cart_emptied' );
|
||||
do_action( 'woocommerce_before_cart_emptied', $clear_persistent_cart );
|
||||
|
||||
$this->cart_contents = array();
|
||||
$this->removed_cart_contents = array();
|
||||
|
@ -653,7 +653,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
|||
|
||||
$this->fees_api->remove_all_fees();
|
||||
|
||||
do_action( 'woocommerce_cart_emptied' );
|
||||
do_action( 'woocommerce_cart_emptied', $clear_persistent_cart );
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -366,6 +366,17 @@ class WC_Countries {
|
|||
return apply_filters( 'woocommerce_european_union_countries', $countries, $type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of Non-EU countries that use VAT as the Local name for their taxes based on this list - https://en.wikipedia.org/wiki/Value-added_tax#Non-European_Union_countries
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function countries_using_vat() {
|
||||
$countries = array( 'AL', 'AR', 'AZ', 'BS', 'BH', 'BY', 'BB', 'BO', 'EG', 'ET', 'CL', 'CO', 'EC', 'SV', 'FJ', 'GM', 'GH', 'GT', 'IN', 'IR', 'IL', 'KZ', 'MU', 'MK', 'MX', 'MD', 'MN', 'ME', 'NA', 'NP', 'NG', 'PS', 'PY', 'RU', 'RW', 'KN', 'SA', 'RS', 'ZA', 'KR', 'LK', 'TH', 'TR', 'UA', 'UY', 'UZ', 'VE', 'VN', 'AE' );
|
||||
|
||||
return apply_filters( 'woocommerce_countries_using_vat', $countries );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the correct string for shipping - either 'to the' or 'to'.
|
||||
*
|
||||
|
@ -400,7 +411,7 @@ class WC_Countries {
|
|||
* @return string
|
||||
*/
|
||||
public function tax_or_vat() {
|
||||
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ) ), true ) ? __( 'VAT', 'woocommerce' ) : __( 'Tax', 'woocommerce' );
|
||||
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ), $this->countries_using_vat() ), true ) ? __( 'VAT', 'woocommerce' ) : __( 'Tax', 'woocommerce' );
|
||||
|
||||
return apply_filters( 'woocommerce_countries_tax_or_vat', $return );
|
||||
}
|
||||
|
@ -411,7 +422,7 @@ class WC_Countries {
|
|||
* @return string
|
||||
*/
|
||||
public function inc_tax_or_vat() {
|
||||
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ) ), true ) ? __( '(incl. VAT)', 'woocommerce' ) : __( '(incl. tax)', 'woocommerce' );
|
||||
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ), $this->countries_using_vat() ), true ) ? __( '(incl. VAT)', 'woocommerce' ) : __( '(incl. tax)', 'woocommerce' );
|
||||
|
||||
return apply_filters( 'woocommerce_countries_inc_tax_or_vat', $return );
|
||||
}
|
||||
|
@ -422,7 +433,7 @@ class WC_Countries {
|
|||
* @return string
|
||||
*/
|
||||
public function ex_tax_or_vat() {
|
||||
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ) ), true ) ? __( '(ex. VAT)', 'woocommerce' ) : __( '(ex. tax)', 'woocommerce' );
|
||||
$return = in_array( $this->get_base_country(), array_merge( $this->get_european_union_countries( 'eu_vat' ), array( 'NO' ), $this->countries_using_vat() ), true ) ? __( '(ex. VAT)', 'woocommerce' ) : __( '(ex. tax)', 'woocommerce' );
|
||||
|
||||
return apply_filters( 'woocommerce_countries_ex_tax_or_vat', $return );
|
||||
}
|
||||
|
|
|
@ -428,7 +428,7 @@ class WC_Emails {
|
|||
* @param string $email Email address.
|
||||
*/
|
||||
public function order_downloads( $order, $sent_to_admin = false, $plain_text = false, $email = '' ) {
|
||||
$show_downloads = $order->has_downloadable_item() && $order->is_download_permitted() && ! $sent_to_admin;
|
||||
$show_downloads = $order->has_downloadable_item() && $order->is_download_permitted() && ! $sent_to_admin && ! is_a( $email, 'WC_Email_Customer_Refunded_Order' );
|
||||
|
||||
if ( ! $show_downloads ) {
|
||||
return;
|
||||
|
|
|
@ -247,7 +247,7 @@ class WC_Frontend_Scripts {
|
|||
),
|
||||
'wc-country-select' => array(
|
||||
'src' => self::get_asset_url( 'assets/js/frontend/country-select' . $suffix . '.js' ),
|
||||
'deps' => array( 'jquery', 'selectWoo' ),
|
||||
'deps' => array( 'jquery' ),
|
||||
'version' => WC_VERSION,
|
||||
),
|
||||
'wc-credit-card-form' => array(
|
||||
|
|
|
@ -366,15 +366,18 @@ class WC_Order extends WC_Abstract_Order {
|
|||
/* translators: 1: old order status 2: new order status */
|
||||
$transition_note = sprintf( __( 'Order status changed from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['from'] ), wc_get_order_status_name( $status_transition['to'] ) );
|
||||
|
||||
// Note the transition occurred.
|
||||
$this->add_status_transition_note( $transition_note, $status_transition );
|
||||
|
||||
do_action( 'woocommerce_order_status_' . $status_transition['from'] . '_to_' . $status_transition['to'], $this->get_id(), $this );
|
||||
do_action( 'woocommerce_order_status_changed', $this->get_id(), $status_transition['from'], $status_transition['to'], $this );
|
||||
} else {
|
||||
/* translators: %s: new order status */
|
||||
$transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['to'] ) );
|
||||
}
|
||||
|
||||
// Note the transition occurred.
|
||||
$this->add_order_note( trim( $status_transition['note'] . ' ' . $transition_note ), 0, $status_transition['manual'] );
|
||||
$this->add_status_transition_note( $transition_note, $status_transition );
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
$logger = wc_get_logger();
|
||||
$logger->error(
|
||||
|
@ -885,8 +888,9 @@ class WC_Order extends WC_Abstract_Order {
|
|||
* @since 3.8.0
|
||||
* @param string $address Formatted billing address string.
|
||||
* @param array $raw_address Raw billing address.
|
||||
* @param WC_Order $order Order data. @since 3.9.0
|
||||
*/
|
||||
return apply_filters( 'woocommerce_order_get_formatted_billing_address', $address ? $address : $empty_content, $raw_address );
|
||||
return apply_filters( 'woocommerce_order_get_formatted_billing_address', $address ? $address : $empty_content, $raw_address, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -908,10 +912,11 @@ class WC_Order extends WC_Abstract_Order {
|
|||
* Filter orders formatterd shipping address.
|
||||
*
|
||||
* @since 3.8.0
|
||||
* @param string $address Formatted shipping address string.
|
||||
* @param array $raw_address Raw shipping address.
|
||||
* @param string $address Formatted billing address string.
|
||||
* @param array $raw_address Raw billing address.
|
||||
* @param WC_Order $order Order data. @since 3.9.0
|
||||
*/
|
||||
return apply_filters( 'woocommerce_order_get_formatted_shipping_address', $address ? $address : $empty_content, $raw_address );
|
||||
return apply_filters( 'woocommerce_order_get_formatted_shipping_address', $address ? $address : $empty_content, $raw_address, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1705,6 +1710,19 @@ class WC_Order extends WC_Abstract_Order {
|
|||
return $comment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an order note for status transition
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @uses WC_Order::add_order_note()
|
||||
* @param string $note Note to be added giving status transition from and to details.
|
||||
* @param bool $transition Details of the status transition.
|
||||
* @return int Comment ID.
|
||||
*/
|
||||
private function add_status_transition_note( $note, $transition ) {
|
||||
return $this->add_order_note( trim( $transition['note'] . ' ' . $note ), 0, $transition['manual'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* List order notes (public) for the customer.
|
||||
*
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
* @version 3.1.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* Include dependencies.
|
||||
|
|
|
@ -72,6 +72,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
|||
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
|
||||
add_action( 'woocommerce_order_status_processing', array( $this, 'capture_payment' ) );
|
||||
add_action( 'woocommerce_order_status_completed', array( $this, 'capture_payment' ) );
|
||||
add_filter( 'woocommerce_thankyou_order_received_text', array( $this, 'order_received_text' ), 10, 2 );
|
||||
|
||||
if ( ! $this->is_valid_for_use() ) {
|
||||
$this->enabled = 'no';
|
||||
|
@ -380,17 +381,17 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
|||
|
||||
$this->log( 'Refund Result: ' . wc_print_r( $result, true ) );
|
||||
|
||||
switch ( strtolower( $result->ACK ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
||||
switch ( strtolower( $result->ACK ) ) { // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
case 'success':
|
||||
case 'successwithwarning':
|
||||
$order->add_order_note(
|
||||
/* translators: 1: Refund amount, 2: Refund ID */
|
||||
sprintf( __( 'Refunded %1$s - Refund ID: %2$s', 'woocommerce' ), $result->GROSSREFUNDAMT, $result->REFUNDTRANSACTIONID ) // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
||||
sprintf( __( 'Refunded %1$s - Refund ID: %2$s', 'woocommerce' ), $result->GROSSREFUNDAMT, $result->REFUNDTRANSACTIONID ) // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
return isset( $result->L_LONGMESSAGE0 ) ? new WP_Error( 'error', $result->L_LONGMESSAGE0 ) : false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
||||
return isset( $result->L_LONGMESSAGE0 ) ? new WP_Error( 'error', $result->L_LONGMESSAGE0 ) : false; // phpcs:ignore WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -414,7 +415,7 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
|||
|
||||
$this->log( 'Capture Result: ' . wc_print_r( $result, true ) );
|
||||
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.NotSnakeCaseMemberVar
|
||||
// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase
|
||||
if ( ! empty( $result->PAYMENTSTATUS ) ) {
|
||||
switch ( $result->PAYMENTSTATUS ) {
|
||||
case 'Completed':
|
||||
|
@ -450,4 +451,20 @@ class WC_Gateway_Paypal extends WC_Payment_Gateway {
|
|||
|
||||
wp_enqueue_script( 'woocommerce_paypal_admin', WC()->plugin_url() . '/includes/gateways/paypal/assets/js/paypal-admin' . $suffix . '.js', array(), WC_VERSION, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom PayPal order received text.
|
||||
*
|
||||
* @since 3.9.0
|
||||
* @param string $text Default text.
|
||||
* @param WC_Order $order Order data.
|
||||
* @return string
|
||||
*/
|
||||
public function order_received_text( $text, $order ) {
|
||||
if ( $this->id === $order->get_payment_method() ) {
|
||||
return esc_html__( 'Thank you for your payment. Your transaction has been completed, and a receipt for your purchase has been emailed to you. Log into your PayPal account to view transaction details.', 'woocommerce' );
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -420,7 +420,7 @@ abstract class WP_Background_Process extends WP_Async_Request {
|
|||
// Adds every 5 minutes to the existing schedules.
|
||||
$schedules[ $this->identifier . '_cron_interval' ] = array(
|
||||
'interval' => MINUTE_IN_SECONDS * $interval,
|
||||
'display' => sprintf( __( 'Every %d Minutes' ), $interval ),
|
||||
'display' => sprintf( __( 'Every %d minutes', 'woocommerce' ), $interval ),
|
||||
);
|
||||
|
||||
return $schedules;
|
||||
|
|
|
@ -43,6 +43,11 @@ class WC_Tracks_Client {
|
|||
* @return void
|
||||
*/
|
||||
public static function maybe_set_identity_cookie() {
|
||||
// Do not set on AJAX requests.
|
||||
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail if cookie already set.
|
||||
if ( isset( $_COOKIE['tk_ai'] ) ) {
|
||||
return;
|
||||
|
|
|
@ -27,9 +27,9 @@ class WC_Orders_Tracking {
|
|||
* Send a Tracks event when the Orders page is viewed.
|
||||
*/
|
||||
public function track_orders_view() {
|
||||
if ( isset( $_GET['post_type'] ) && 'shop_order' === wp_unslash( $_GET['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
if ( isset( $_GET['post_type'] ) && 'shop_order' === wp_unslash( $_GET['post_type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput
|
||||
// phpcs:disable WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput
|
||||
$properties = array(
|
||||
'status' => isset( $_GET['post_status'] ) ? sanitize_text_field( $_GET['post_status'] ) : 'all',
|
||||
);
|
||||
|
@ -77,8 +77,8 @@ class WC_Orders_Tracking {
|
|||
}
|
||||
|
||||
$order = wc_get_order( $id );
|
||||
$date_created = $order->get_date_created()->date( 'Y-m-d H:i:s' );
|
||||
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
|
||||
$date_created = $order->get_date_created() ? $order->get_date_created()->date( 'Y-m-d H:i:s' ) : '';
|
||||
// phpcs:disable WordPress.Security.NonceVerification
|
||||
$new_date = sprintf(
|
||||
'%s %2d:%2d:%2d',
|
||||
isset( $_POST['order_date'] ) ? wc_clean( wp_unslash( $_POST['order_date'] ) ) : '',
|
||||
|
@ -104,7 +104,7 @@ class WC_Orders_Tracking {
|
|||
* @param int $order_id Order ID.
|
||||
*/
|
||||
public function track_order_action( $order_id ) {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.NoNonceVerification
|
||||
// phpcs:disable WordPress.Security.NonceVerification
|
||||
if ( ! empty( $_POST['wc_order_action'] ) ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
$action = wc_clean( wp_unslash( $_POST['wc_order_action'] ) );
|
||||
|
@ -123,7 +123,7 @@ class WC_Orders_Tracking {
|
|||
* Track "add order" button on the Edit Order screen.
|
||||
*/
|
||||
public function track_add_order_from_edit() {
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.NoNonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
// phpcs:ignore WordPress.Security.NonceVerification, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
if ( isset( $_GET['post_type'] ) && 'shop_order' === wp_unslash( $_GET['post_type'] ) ) {
|
||||
$referer = wp_get_referer();
|
||||
|
||||
|
|
|
@ -151,6 +151,8 @@ function wc_get_account_menu_item_classes( $endpoint ) {
|
|||
$current = true; // Dashboard is not an endpoint, so needs a custom check.
|
||||
} elseif ( 'orders' === $endpoint && isset( $wp->query_vars['view-order'] ) ) {
|
||||
$current = true; // When looking at individual order, highlight Orders list item (to signify where in the menu the user currently is).
|
||||
} elseif ( 'payment-methods' === $endpoint && isset( $wp->query_vars['add-payment-method'] ) ) {
|
||||
$current = true;
|
||||
}
|
||||
|
||||
if ( $current ) {
|
||||
|
|
|
@ -1140,7 +1140,7 @@ function wc_get_customer_default_location() {
|
|||
$allowed_country_codes = WC()->countries->get_allowed_countries();
|
||||
|
||||
if ( ! empty( $location['country'] ) && ! array_key_exists( $location['country'], $allowed_country_codes ) ) {
|
||||
$location['country'] = current( $allowed_country_codes );
|
||||
$location['country'] = current( array_keys( $allowed_country_codes ) );
|
||||
$location['state'] = '';
|
||||
}
|
||||
|
||||
|
|
|
@ -1948,6 +1948,7 @@ if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
|
|||
array(
|
||||
'posts_per_page' => $limit,
|
||||
'orderby' => $orderby,
|
||||
'order' => $order,
|
||||
'columns' => $columns,
|
||||
)
|
||||
);
|
||||
|
@ -1955,6 +1956,7 @@ if ( ! function_exists( 'woocommerce_upsell_display' ) ) {
|
|||
wc_set_loop_prop( 'columns', apply_filters( 'woocommerce_upsells_columns', isset( $args['columns'] ) ? $args['columns'] : $columns ) );
|
||||
|
||||
$orderby = apply_filters( 'woocommerce_upsells_orderby', isset( $args['orderby'] ) ? $args['orderby'] : $orderby );
|
||||
$order = apply_filters( 'woocommerce_upsells_order', isset( $args['order'] ) ? $args['order'] : $order );
|
||||
$limit = apply_filters( 'woocommerce_upsells_total', isset( $args['posts_per_page'] ) ? $args['posts_per_page'] : $limit );
|
||||
|
||||
// Get visible upsells then sort them at random, then limit result set.
|
||||
|
|
|
@ -123,6 +123,10 @@ class WC_WCCOM_Site_Installer {
|
|||
'products' => $products,
|
||||
);
|
||||
|
||||
// Clear the cache of customer's subscription before asking for them.
|
||||
// Thus, they will be re-fetched from WooCommerce.com after a purchase.
|
||||
WC_Helper::_flush_subscriptions_cache();
|
||||
|
||||
WC()->queue()->cancel_all( 'woocommerce_wccom_install_products', $args );
|
||||
WC()->queue()->add( 'woocommerce_wccom_install_products', $args );
|
||||
|
||||
|
@ -257,7 +261,7 @@ class WC_WCCOM_Site_Installer {
|
|||
*
|
||||
* @since 3.7.0
|
||||
* @param int $product_id Product ID.
|
||||
* @return bool|\WP_Error
|
||||
* @return array|\WP_Error
|
||||
*/
|
||||
private static function get_product_info( $product_id ) {
|
||||
$product_info = array(
|
||||
|
|
File diff suppressed because it is too large
Load Diff
27
package.json
27
package.json
|
@ -14,6 +14,7 @@
|
|||
"build-watch": "grunt watch",
|
||||
"lint:js": "eslint assets/js --ext=js",
|
||||
"test:e2e": "./tests/bin/e2e-test-integration.js",
|
||||
"test:e2e-dev": "./tests/bin/e2e-test-integration.js --dev",
|
||||
"makepot": "grunt makepot",
|
||||
"git:update-hooks": "rm -r .git/hooks && mkdir -p .git/hooks && node ./node_modules/husky/husky.js install"
|
||||
},
|
||||
|
@ -24,17 +25,16 @@
|
|||
"@babel/preset-env": "^7.5.5",
|
||||
"@babel/register": "^7.5.5",
|
||||
"@wordpress/e2e-test-utils": "^2.2.0",
|
||||
"autoprefixer": "9.6.5",
|
||||
"autoprefixer": "9.7.2",
|
||||
"babel-eslint": "10.0.3",
|
||||
"chai": "4.2.0",
|
||||
"chai-as-promised": "7.1.1",
|
||||
"commander": "^3.0.0",
|
||||
"config": "3.2.3",
|
||||
"cross-env": "6.0.3",
|
||||
"eslint": "6.5.1",
|
||||
"eslint-config-wpcalypso": "4.0.1",
|
||||
"eslint-plugin-jest": "22.13.6",
|
||||
"eslint-plugin-wpcalypso": "4.1.0",
|
||||
"config": "3.2.4",
|
||||
"cross-env": "6.0.3",
|
||||
"eslint": "6.7.0",
|
||||
"eslint-config-wpcalypso": "5.0.0",
|
||||
"github-contributors-list": "https://github.com/woocommerce/github-contributors-list/tarball/master",
|
||||
"grunt": "1.0.4",
|
||||
"grunt-checktextdomain": "1.0.1",
|
||||
|
@ -51,18 +51,18 @@
|
|||
"grunt-rtlcss": "2.0.1",
|
||||
"grunt-sass": "3.1.0",
|
||||
"grunt-shell": "3.0.1",
|
||||
"grunt-stylelint": "0.11.1",
|
||||
"grunt-stylelint": "0.12.0",
|
||||
"grunt-wp-i18n": "1.0.3",
|
||||
"husky": "3.0.9",
|
||||
"husky": "3.1.0",
|
||||
"istanbul": "1.0.0-alpha.2",
|
||||
"jest": "24.8.0",
|
||||
"jest-puppeteer": "4.3.0",
|
||||
"lint-staged": "9.4.2",
|
||||
"lint-staged": "9.4.3",
|
||||
"mocha": "6.2.2",
|
||||
"node-sass": "4.12.0",
|
||||
"node-sass": "4.13.0",
|
||||
"prettier": "github:automattic/calypso-prettier#c56b4251",
|
||||
"puppeteer": "2.0.0",
|
||||
"stylelint": "11.1.1",
|
||||
"stylelint": "12.0.0",
|
||||
"stylelint-config-wordpress": "15.0.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -92,5 +92,8 @@
|
|||
"> 0.1%",
|
||||
"ie 8",
|
||||
"ie 9"
|
||||
]
|
||||
],
|
||||
"dependencies": {
|
||||
"@jest/test-sequencer": "^24.9.0"
|
||||
}
|
||||
}
|
||||
|
|
117
readme.txt
117
readme.txt
|
@ -4,7 +4,7 @@ Tags: ecommerce, e-commerce, store, sales, sell, shop, cart, checkout, downloada
|
|||
Requires at least: 4.9
|
||||
Tested up to: 5.2
|
||||
Requires PHP: 5.6
|
||||
Stable tag: 3.7.0
|
||||
Stable tag: 3.8.0
|
||||
License: GPLv3
|
||||
License URI: https://www.gnu.org/licenses/gpl-3.0.html
|
||||
|
||||
|
@ -179,120 +179,7 @@ INTERESTED IN DEVELOPMENT?
|
|||
|
||||
== Changelog ==
|
||||
|
||||
= 3.8.0 - 2019-01-10 =
|
||||
* Enhancement - Show error message in "My Account - view order" if order does not exist. #24435
|
||||
* Enhancement - Add support to allow connect and install for in-app purchase flow. #24451
|
||||
* Enhancement - Declared support to Unicode CLDR. #24564
|
||||
* Enhancement - Declared support for PHP 7.4 in CI by removing PHP 7.4 from list of allowed failures. #24668
|
||||
* Enhancement - Update the recommended PHP version to 7.0 and the recommended WP version to 5.0. #24730
|
||||
* Enhancement - Change On Boarding Wizard to opt out of usage tracking by default. #24680
|
||||
* Enhancement - Add `Available on backorder` message for products available on backorder. #24559
|
||||
* Tweak - Hide Vietnam's state field. #24158
|
||||
* Tweak - Better wording when no downloads are available on My Account > Downloads. #24172
|
||||
* Tweak - Only consider orders created via checkout to hold stock. #24159
|
||||
* Tweak - Stop to load order data twice in "View order" screen on "My Account" page. #24437
|
||||
* Tweak - Prevent PHP warnings in tracker if order doesn't have a created date yet. #24441
|
||||
* Tweak - Use `wc_get_checkout_url()` to get checkout URL. #24544
|
||||
* Tweak - Maintain value of select fields in credit card form. #24720
|
||||
* Tweak - Prevent filter per category while exporting product variations. #24517
|
||||
* Tweak - Better wording for subtotal of items in cart and review order. #24440
|
||||
* Tweak - Prevent new lines in product quantity in checkout details. #24311
|
||||
* Tweak - Add a tooltip in the "Coupon expity date" field. #24749
|
||||
* Tweak - CSS styling changes for WP 5.3. #24832
|
||||
* Template - Moved HTML for displaying product price filter widget to a new template `product price filter widget`. #23384
|
||||
* Accessibility - Make $subtext color darker. #24739
|
||||
* Dev - Consistent register/login submit button css class names. Preserve old class names as well for backwards compatibility. #23701
|
||||
* Dev - Added woocommerce_disable_password_change_notification filter, set to false by default. #24154
|
||||
* Dev - Add filter `woocommerce_cart_item_removed_message` and `woocommerce_cart_product_cannot_be_purchased_message` to filter notice content when an item is removed from cart, or when a product cannot be purchased. #24176
|
||||
* Dev - Prevent fatal error if trying to run `wc_load_cart()` before `before_woocommerce_init`. #24198
|
||||
* Dev - Add woocommerce_get_zone_criteria filter hook to add custom criteria for matching zone ID. #24199
|
||||
* Dev - Fire actions `woocommerce_before_delete_product_variation`, `woocommerce_delete_product_variation` and `woocommerce_trash_product_variation` appropriately when deleting or trashing product variations. #24239
|
||||
* Dev - In filter `woocommerce_update_product_stock_query` use `$new_stock` instead of `$stock_quantity`. #24229
|
||||
* Dev - Introduced woocommerce_prevent_adjust_line_item_product_stock filter. #24279
|
||||
* Dev - Introduced `woocommerce_logout_default_redirect_url` filter to allow custom default URL. #24282
|
||||
* Dev - Added woocommerce_sort_fees_callback filter. #24280
|
||||
* Dev - Remove deprecated i18n/states directory. #24364
|
||||
* Dev - Add filter `woocommerce_shipping_show_shipping_calculator` for showing shipping calculator. #24375
|
||||
* Dev - Corrected UG states location. #24388
|
||||
* Dev - Remove deprecations notices with PHP 7.4 by changing parameter order for `implode`. #24396
|
||||
* Dev - Add ``$this` param to email filter for additional_content added in 3.7. #24399
|
||||
* Dev - Add `woocommerce_product_import_process_item_data` filter to allow modifying a row before importing. #24412
|
||||
* Dev - Fixed warnings when error_get_last() returns null. #24442
|
||||
* Dev - Use brackets instead of braces to avoid deprecation notice in PHP 7.4. #24460
|
||||
* Dev - Implement Puppeteer's architecture for running E2E tests locally. #24479
|
||||
* Dev - Remove call to get_magic_quotes_runtime() as it is deprecated as of PHP 7.4. #24485
|
||||
* Dev - Return value of `$mailer->send()` in `wc_mail` function. #24505
|
||||
* Dev - Remove Selenium e2e tests & add Puppeteer new product e2e test. #24513
|
||||
* Dev - Add a filter `woocommerce_ajax_add_order_item_validation` to allow validations in `add_order_item` function. #24518
|
||||
* Dev - Use `wc_get_cart_url` instead of `wc_get_page_permalink( 'cart' )` because former has a filter `woocommerce_get_cart_url` to allow customization. #24530
|
||||
* Dev - New `woocommerce_product_after_tabs` action hook added. #24694
|
||||
* Dev - Enable append hashes on custom events (like ajax requests) #24665
|
||||
* Dev - Introduced `woocommerce_order_get_formatted_billing_address` and `woocommerce_order_get_formatted_shipping_address` filters. #24677
|
||||
* Dev - WC_Abstract_Order::recalculate_coupons() is public now. #24740
|
||||
* Dev - Added 'applied_coupon' trigger to checkout.js. #24406
|
||||
* Dev - Introduced woocommerce_output_cart_shortcode_content filter. #24738
|
||||
* Dev - Add WPML compatibility to the geolocation URL. #24722
|
||||
* Dev - Validate server requirements in WCCCOM Site Installer endpoints. #24690
|
||||
* Dev - Introduced woocommerce_payment_token_class filter. #24542
|
||||
* Dev - Add support for post type count to system status report. #24536
|
||||
* Dev - Check for max discount to be -ve to prevent overwriting refunded fee amount. #24341
|
||||
* Dev: Add filter woocommerce_european_union_countries to the method WC_Countries::get_european_union_countries(). #24741
|
||||
* Dev - Allow WC_Product_Query sort products by include order. #24294
|
||||
* Dev - Removed duplicated include of WC_Admin_Importers. #24751
|
||||
* Dev - Refactor minimum requirement notice to use constant for easier changes in the future. #24830
|
||||
* Fix - Clean products transients when term is removed. #23991
|
||||
* Fix - Only add the image node to structured data if product has image. #24191
|
||||
* Fix - Product attribute terms endpoint in legacy REST API v3 by converting `attribute_id` to int. #24203
|
||||
* Fix - Prevent duplicate processing/stock reduction when IPN or PDT notifications are enabled by checking if order is not already in `processing` or `completed` status. #24249
|
||||
* Fix - Position of ID section in mobile rows actions when displaying the list of products in the admin. #24277
|
||||
* Fix - Endpoints URLs to follow slashes preferences from WordPress permalinks. #24283
|
||||
* Fix - Ensure that postcode validation doesn't return any whitespace on beginning and end of a postcode. #24284
|
||||
* Fix - Shipping classes sort under products alphabetically. #24291
|
||||
* Fix - Shipping rates layout in admin settings. #24327
|
||||
* Fix - Retain the focus on the select box when product variation is changed. #24339
|
||||
* Fix - Prevent PHP notice in WC_Order_Item_Data_Store::get_order_item_type() when there is no entry in the database for the order item ID passed. #24353
|
||||
* Fix - Add translation in class-wc-shipping.php for matching zone message. #24366
|
||||
* Fix - Previewing email template. #24380
|
||||
* Fix - Check if order exist before generate hash for downloads. #24384
|
||||
* Fix - Ensure WC_Product_Data_Store_CPT::is_existing_sku() return boolean. #24385
|
||||
* Fix - `function_exists` check for wc_hex_is_light(). #24391
|
||||
* Fix - Removed Emoji from default additional email content due problem on some database that doesn't allow Emojis. #24450
|
||||
* Fix - Fixed escaping on an attribute in `class-wc-admin-menus.php`. #24466
|
||||
* Fix - Add translation for image alt attribute text in multiple places. #24467, #24468, #24469
|
||||
* Fix - Uneven padding in the input field with class "location-input" in on boarding wizard. #24476
|
||||
* Fix - Duplicate id in pages settings. #24478
|
||||
* Fix - Use `esc_attr_e` instead of `esc_html_e` for escaping an attribute in multiple places. #24481, #24520, #24521, #24522, #24523, #24524
|
||||
* Fix - Use `esc_attr__` instead of `esc_html__` in escaping attributes string. #24525, #24529
|
||||
* Fix - Typo fix in payment captured error message. #24501
|
||||
* Fix - Remove broken download link for downloadable product in refund emails. #24526
|
||||
* Fix - Documentation URL in failed order email content. #24535
|
||||
* Fix - "Add to cart" links in feed. #24545
|
||||
* Fix - Escaping in Storefront banner. #24546
|
||||
* Fix - Use `wp_kses_post` to allow certain html tags in extensions page. #24589
|
||||
* Fix - Escape `$prefix` in item download links. #24601
|
||||
* Fix - Use `esc_attr` instead of `esc_html` in multiple places for proper escaping. #24613, #24614
|
||||
* Fix - Use `esc_html` instead of `esc_attr` in multiple places for proper escaping. #24616
|
||||
* Fix - Use `esc_html_e` instead of `_e` in multiple places for proper escaping. #24615, #24618, #24630
|
||||
* Fix - Use `esc_html__` instead of `esc_html` for proper escaping and some typo fixes. #24639
|
||||
* Fix - Add no-store and remove max-age header (no longer needed). #24652
|
||||
* Fix - Use correct meta value for `downloadable` column in product lookup table regenerate function. #24681
|
||||
* Fix - Admin sub-menus becoming unaligned when scrolling down in the orders page when there are no orders. #24688
|
||||
* Fix - OWB country and sell in person alignment. #24700
|
||||
* Fix - Add selectWoo as dependency of country-select. #24347
|
||||
* Fix - Domain replacement script now replaces both double and single quoted `woo-gutenberg-products-block` with `woocommerce` in both PHP and JavaScript files. #24696
|
||||
* Fix - Convert `current_user_id` to string in some places to prevent unnecessary session database updates. #24016
|
||||
* Fix - Fixed description of failed order emails. #24737
|
||||
* Fix - Fixed Photoswipe styles. #24296
|
||||
* Fix - Also consider refunded item when updating order and adjusting stocks. #24745
|
||||
* Fix - Handle 0 attribute value for variations correctly. #24750
|
||||
* Fix - Fixed spaces in form fields of External Products. #24295
|
||||
* Localization - Add Zambia's Provinces to the list of states. #24307
|
||||
* Localization - Adaptation of the order of last name and first name and addresses in Japan. #24336
|
||||
* Localization - Fixed Namibian dollar symbol. #24438
|
||||
* Localization - Change localization tag `action-scheduler` to `woocommerce`. #24474
|
||||
* Localization - Fixed missing US Minor Outlying Islands states. #24826
|
||||
* Security - Add an exit after the redirect when checking author archive capabilities for customers.
|
||||
* Security - Ensure 404 pages with single product urls cannot be exploited using Open Redirect.
|
||||
= 3.9.0 - 2020-01-xx =
|
||||
|
||||
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce/master/CHANGELOG.txt).
|
||||
|
||||
|
|
|
@ -1,11 +1,5 @@
|
|||
#!/usr/bin/env bash
|
||||
if [[ ${RUN_E2E} == 1 ]]; then
|
||||
|
||||
WP_SITE_URL="http://localhost:8080"
|
||||
|
||||
# Set base url to that of e2e test suite.
|
||||
export BASE_URL="$WP_SITE_URL"
|
||||
|
||||
# Run the tests
|
||||
npm test
|
||||
npm install
|
||||
npm run test:e2e
|
||||
fi
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
{
|
||||
"url": "BASE_URL"
|
||||
}
|
|
@ -1,3 +1,13 @@
|
|||
{
|
||||
"url": "https://example.com/"
|
||||
"url": "http://localhost:8084/",
|
||||
"users": {
|
||||
"admin": {
|
||||
"username": "admin",
|
||||
"password": "password"
|
||||
},
|
||||
"customer": {
|
||||
"username": "customer",
|
||||
"password": "password"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
const Sequencer = require('@jest/test-sequencer').default;
|
||||
|
||||
class CustomSequencer extends Sequencer {
|
||||
sort(tests) {
|
||||
// Test structure information
|
||||
// https://github.com/facebook/jest/blob/6b8b1404a1d9254e7d5d90a8934087a9c9899dab/packages/jest-runner/src/types.ts#L17-L21
|
||||
const copyTests = Array.from(tests);
|
||||
return copyTests.sort((testA, testB) => (testA.path > testB.path ? 1 : -1));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = CustomSequencer;
|
|
@ -28,4 +28,7 @@ module.exports = {
|
|||
|
||||
// The glob patterns Jest uses to detect test files
|
||||
testMatch: [ '**/*.(test|spec).js' ],
|
||||
|
||||
// Sort test path alphabetically. This is needed so that `activate-and-setup` tests run first
|
||||
testSequencer: '<rootDir>/tests/e2e-tests/config/jest-custom-sequencer.js',
|
||||
};
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
{}
|
|
@ -0,0 +1,197 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from '../../utils/flows';
|
||||
import {
|
||||
permalinkSettingsPageSaveChanges,
|
||||
setCheckbox,
|
||||
settingsPageSaveChanges,
|
||||
verifyCheckboxIsSet,
|
||||
verifyCheckboxIsUnset, verifyValueOfInputField
|
||||
} from "../../utils";
|
||||
|
||||
describe( 'Store owner can login and make sure WooCommerce is activated', () => {
|
||||
|
||||
it( 'Can login', async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'Can make sure WooCommerce is activated. If not, activate it', async () => {
|
||||
const slug = 'woocommerce';
|
||||
await StoreOwnerFlow.openPlugins();
|
||||
const disableLink = await page.$( `tr[data-slug="${ slug }"] .deactivate a` );
|
||||
if ( disableLink ) {
|
||||
return;
|
||||
}
|
||||
await page.click( `tr[data-slug="${ slug }"] .activate a` );
|
||||
await page.waitForSelector( `tr[data-slug="${ slug }"] .deactivate a` );
|
||||
});
|
||||
|
||||
} );
|
||||
|
||||
describe( 'Store owner can go through store Setup Wizard', () => {
|
||||
|
||||
it( 'Can start Setup Wizard', async () => {
|
||||
await StoreOwnerFlow.runSetupWizard();
|
||||
} );
|
||||
|
||||
it( 'Can fill out Store setup details', async () => {
|
||||
// Fill out store address details
|
||||
await expect( page ).toSelect( 'select[name="store_country"]', 'United States (US)' );
|
||||
await expect( page ).toFill( '#store_address', 'addr 1' );
|
||||
await expect( page ).toFill( '#store_address_2', 'addr 2' );
|
||||
await expect( page ).toFill( '#store_city', 'San Francisco' );
|
||||
await expect( page ).toSelect( 'select[name="store_state"]', 'California' );
|
||||
await expect( page ).toFill( '#store_postcode', '94107' );
|
||||
|
||||
// Select currency and type of products to sell details
|
||||
await expect( page ).toSelect( 'select[name="currency_code"]', '\n' +
|
||||
'\t\t\t\t\t\tUnited States (US) dollar ($ USD)\t\t\t\t\t' );
|
||||
await expect( page ).toSelect( 'select[name="product_type"]', 'I plan to sell both physical and digital products' );
|
||||
|
||||
// Verify that checkbox next to "I will also be selling products or services in person." is not selected
|
||||
await verifyCheckboxIsUnset( '#woocommerce_sell_in_person' );
|
||||
|
||||
// Click on "Let's go!" button to move to the next step
|
||||
await page.$eval( 'button[name=save_step]', elem => elem.click() );
|
||||
|
||||
// Wait for usage tracking pop-up window to appear
|
||||
await page.waitForSelector( '#wc-backbone-modal-dialog' );
|
||||
await expect( page ).toMatchElement( '.wc-backbone-modal-header', { text: 'Help improve WooCommerce with usage tracking' } );
|
||||
|
||||
await page.waitForSelector('#wc_tracker_checkbox_dialog');
|
||||
|
||||
// Verify that checkbox next to "Enable usage tracking and help improve WooCommerce" is not selected
|
||||
await verifyCheckboxIsUnset('#wc_tracker_checkbox_dialog');
|
||||
|
||||
await Promise.all([
|
||||
// Click on "Continue" button to move to the next step
|
||||
page.$eval( '#wc_tracker_submit', elem => elem.click() ),
|
||||
|
||||
// Wait for the Payment section to load
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
]);
|
||||
} );
|
||||
|
||||
it( 'Can fill out Payment details', async () => {
|
||||
// Turn off Stripe account toggle
|
||||
await page.click( '.wc-wizard-service-toggle' );
|
||||
|
||||
// Click on "Continue" button to move to the next step
|
||||
await page.click( 'button[name=save_step]', { text: 'Continue' } );
|
||||
} );
|
||||
|
||||
it( 'Can fill out Shipping details', async () => {
|
||||
// Turn off WooCommerce Shipping option
|
||||
await page.$eval( '#wc_recommended_woocommerce_services', elem => elem.click() );
|
||||
|
||||
await page.waitForSelector( 'select[name="shipping_zones[domestic][method]"]' );
|
||||
await page.waitForSelector( 'select[name="shipping_zones[intl][method]"]' );
|
||||
|
||||
// Select Free Shipping method for domestic shipping zone
|
||||
await page.evaluate( () => {
|
||||
document.querySelector( 'select[name="shipping_zones[domestic][method]"] > option:nth-child(2)' ).selected = true;
|
||||
let element = document.querySelector( 'select[name="shipping_zones[domestic][method]"]' );
|
||||
let event = new Event( 'change', { bubbles: true } );
|
||||
event.simulated=true;
|
||||
element.dispatchEvent( event );
|
||||
} );
|
||||
|
||||
// Select Free Shipping method for the rest of the world shipping zone
|
||||
await page.evaluate( () => {
|
||||
document.querySelector( 'select[name="shipping_zones[intl][method]"] > option:nth-child(2)' ).selected = true;
|
||||
let element = document.querySelector( 'select[name="shipping_zones[intl][method]"]' );
|
||||
let event = new Event( 'change', { bubbles: true } );
|
||||
event.simulated=true;
|
||||
element.dispatchEvent( event );
|
||||
});
|
||||
|
||||
// Select product weight and product dimensions options
|
||||
await expect( page ).toSelect( 'select[name="weight_unit"]', 'Pounds' );
|
||||
await expect( page ).toSelect( 'select[name="dimension_unit"]', 'Inches' );
|
||||
|
||||
// Click on "Continue" button to move to the next step
|
||||
await page.click( 'button[name=save_step]', { text: 'Continue' } );
|
||||
} );
|
||||
|
||||
it( 'Can fill out Recommended details', async () => {
|
||||
// Turn off Storefront Theme option
|
||||
await page.$eval( '#wc_recommended_storefront_theme', elem => elem.click() );
|
||||
|
||||
// Turn off Automated Taxes option
|
||||
await page.$eval( '#wc_recommended_automated_taxes', elem => elem.click() );
|
||||
|
||||
// Turn off WooCommerce Admin option
|
||||
await page.$eval( '#wc_recommended_wc_admin', elem => elem.click() );
|
||||
|
||||
// Turn off Mailchimp option
|
||||
await page.$eval( '#wc_recommended_mailchimp', elem => elem.click() );
|
||||
|
||||
// Turn off Facebook option
|
||||
await page.$eval( '#wc_recommended_facebook', elem => elem.click() );
|
||||
|
||||
// Click on "Continue" button to move to the next step
|
||||
await page.click( 'button[name=save_step]', { text: 'Continue' } );
|
||||
} );
|
||||
|
||||
it( 'Can skip Activate Jetpack section', async () => {
|
||||
// Click on "Skip this step" in order to skip Jetpack installation
|
||||
await page.click( '.wc-setup-footer-links' );
|
||||
} );
|
||||
|
||||
it( 'Can finish Setup Wizard - Ready! section', async () => {
|
||||
// Visit Dashboard
|
||||
await StoreOwnerFlow.openDashboard();
|
||||
} );
|
||||
|
||||
} );
|
||||
|
||||
describe( 'Store owner can finish initial store setup', () => {
|
||||
|
||||
it('Can enable tax rates and calculations', async () => {
|
||||
// Go to general settings page
|
||||
await StoreOwnerFlow.openSettings( 'general' );
|
||||
|
||||
// Make sure the general tab is active
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'General' } );
|
||||
|
||||
// Enable tax rates and calculations
|
||||
await setCheckbox( '#woocommerce_calc_taxes' );
|
||||
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
verifyCheckboxIsSet( '#woocommerce_calc_taxes' ),
|
||||
] );
|
||||
});
|
||||
|
||||
it('Can configure permalink settings', async () => {
|
||||
// Go to Permalink Settings page
|
||||
await StoreOwnerFlow.openPermalinkSettings();
|
||||
|
||||
// Select "Post name" option in common settings section
|
||||
await page.click( 'input[value="/%postname%/"]', { text: ' Post name' } );
|
||||
|
||||
// Select "Custom base" in product permalinks section
|
||||
await page.click( '#woocommerce_custom_selection' );
|
||||
|
||||
// Fill custom base slug to use
|
||||
await expect( page ).toFill( '#woocommerce_permalink_structure', '/product/' );
|
||||
|
||||
await permalinkSettingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#setting-error-settings_updated', { text: 'Permalink structure updated.' } ),
|
||||
verifyValueOfInputField( '#permalink_structure', '/%postname%/' ),
|
||||
verifyValueOfInputField( '#woocommerce_permalink_structure', '/product/' ),
|
||||
] );
|
||||
});
|
||||
|
||||
} );
|
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { createSimpleProduct, createVariableProduct } from '../../utils/components';
|
||||
import { CustomerFlow, StoreOwnerFlow } from '../../utils/flows';
|
||||
import { uiUnblocked } from '../../utils';
|
||||
|
||||
let simplePostIdValue;
|
||||
let variablePostIdValue;
|
||||
|
||||
describe( 'Single Product Page', () => {
|
||||
beforeAll( async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
simplePostIdValue = await createSimpleProduct();
|
||||
await StoreOwnerFlow.logout();
|
||||
} );
|
||||
|
||||
it( 'should be able to add simple products to the cart', async () => {
|
||||
// Add 5 simple products to cart
|
||||
await CustomerFlow.goToProduct( simplePostIdValue );
|
||||
await expect( page ).toFill( 'div.quantity input.qty', '5' );
|
||||
await CustomerFlow.addToCart();
|
||||
await expect( page ).toMatchElement( '.woocommerce-message', { text: 'have been added to your cart.' } );
|
||||
|
||||
// Verify cart contents
|
||||
await CustomerFlow.goToCart();
|
||||
await CustomerFlow.productIsInCart( 'Simple product', 5 );
|
||||
|
||||
// Remove items from cart
|
||||
await CustomerFlow.removeFromCart( 'Simple product' );
|
||||
await uiUnblocked();
|
||||
await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } );
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'Variable Product Page', () => {
|
||||
beforeAll( async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
variablePostIdValue = await createVariableProduct();
|
||||
await StoreOwnerFlow.logout();
|
||||
} );
|
||||
|
||||
it( 'should be able to add variation products to the cart', async () => {
|
||||
// Add a product with one set of variations to cart
|
||||
await CustomerFlow.goToProduct( variablePostIdValue );
|
||||
await expect( page ).toSelect( '#attr-1', 'val1' );
|
||||
await expect( page ).toSelect( '#attr-2', 'val1' );
|
||||
await expect( page ).toSelect( '#attr-3', 'val1' );
|
||||
await CustomerFlow.addToCart();
|
||||
await expect( page ).toMatchElement( '.woocommerce-message', { text: 'has been added to your cart.' } );
|
||||
|
||||
// Verify cart contents
|
||||
await CustomerFlow.goToCart();
|
||||
await CustomerFlow.productIsInCart( 'Variable Product with Three Variations' );
|
||||
|
||||
// Remove items from cart
|
||||
await CustomerFlow.removeFromCart( 'Variable Product with Three Variations' );
|
||||
await uiUnblocked();
|
||||
await expect( page ).toMatchElement( '.cart-empty', { text: 'Your cart is currently empty.' } );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from '../../utils/flows';
|
||||
import { clickTab, verifyPublishAndTrash } from '../../utils';
|
||||
|
||||
describe( 'Add New Coupon Page', () => {
|
||||
beforeAll( async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'can create new coupon', async () => {
|
||||
// Go to "add coupon" page
|
||||
await StoreOwnerFlow.openNewCoupon();
|
||||
|
||||
// Make sure we're on the add coupon page
|
||||
await expect( page.title() ).resolves.toMatch( 'Add new coupon' );
|
||||
|
||||
// Fill in coupon code and description
|
||||
await expect( page ).toFill( '#title', 'code-' + new Date().getTime().toString() );
|
||||
await expect( page ).toFill( '#woocommerce-coupon-description', 'test coupon' );
|
||||
|
||||
// Set general coupon data
|
||||
await clickTab( 'General' );
|
||||
await expect( page ).toSelect( '#discount_type', 'Fixed cart discount' );
|
||||
await expect( page ).toFill( '#coupon_amount', '100' );
|
||||
|
||||
// Publish coupon, verify that it was published. Trash coupon, verify that it was trashed.
|
||||
await verifyPublishAndTrash(
|
||||
'#publish',
|
||||
'#message',
|
||||
'Coupon updated.',
|
||||
'1 coupon moved to the Trash.'
|
||||
);
|
||||
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,37 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from '../../utils/flows';
|
||||
import { verifyPublishAndTrash } from '../../utils';
|
||||
|
||||
describe( 'Add New Order Page', () => {
|
||||
beforeAll( async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'can create new order', async () => {
|
||||
// Go to "add order" page
|
||||
await StoreOwnerFlow.openNewOrder();
|
||||
|
||||
// Make sure we're on the add order page
|
||||
await expect( page.title() ).resolves.toMatch( 'Add new order' );
|
||||
|
||||
// Set order data
|
||||
await expect( page ).toSelect( '#order_status', 'Processing' );
|
||||
await expect( page ).toFill( 'input[name=order_date]', '2018-12-13' );
|
||||
await expect( page ).toFill( 'input[name=order_date_hour]', '18' );
|
||||
await expect( page ).toFill( 'input[name=order_date_minute]', '55' );
|
||||
|
||||
// Create order, verify that it was created. Trash order, verify that it was trashed.
|
||||
await verifyPublishAndTrash(
|
||||
'.order_actions li .save_order',
|
||||
'#message',
|
||||
'Order updated.',
|
||||
'1 order moved to the Trash.'
|
||||
);
|
||||
} );
|
||||
} );
|
|
@ -2,11 +2,6 @@
|
|||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { activatePlugin } from '@wordpress/e2e-test-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
|
@ -35,7 +30,7 @@ const verifyPublishAndTrash = async () => {
|
|||
|
||||
describe( 'Add New Simple Product Page', () => {
|
||||
beforeAll( async () => {
|
||||
await activatePlugin( 'woocommerce' );
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'can create simple virtual product titled "Simple Product" with regular price $9.99', async () => {
|
||||
|
@ -51,15 +46,21 @@ describe( 'Add New Simple Product Page', () => {
|
|||
await clickTab( 'General' );
|
||||
await expect( page ).toFill( '#_regular_price', '9.99' );
|
||||
|
||||
await verifyPublishAndTrash();
|
||||
// Publish product, verify that it was published. Trash product, verify that it was trashed.
|
||||
await verifyPublishAndTrash(
|
||||
'#publish',
|
||||
'.updated.notice',
|
||||
'Product published.',
|
||||
'Move to Trash',
|
||||
'1 product moved to the Trash.'
|
||||
);
|
||||
} );
|
||||
} );
|
||||
|
||||
describe( 'Add New Variable Product Page', () => {
|
||||
beforeAll( async () => {
|
||||
await activatePlugin( 'woocommerce' );
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'can create product with variations', async () => {
|
||||
// Go to "add product" page
|
||||
await StoreOwnerFlow.openNewProduct();
|
||||
|
@ -179,6 +180,13 @@ describe( 'Add New Variable Product Page', () => {
|
|||
await page.focus( 'button.save-variation-changes' );
|
||||
await expect( page ).toClick( 'button.save-variation-changes', { text: 'Save changes' } );
|
||||
|
||||
await verifyPublishAndTrash();
|
||||
// Publish product, verify that it was published. Trash product, verify that it was trashed.
|
||||
await verifyPublishAndTrash(
|
||||
'#publish',
|
||||
'.updated.notice',
|
||||
'Product published.',
|
||||
'Move to Trash',
|
||||
'1 product moved to the Trash.'
|
||||
);
|
||||
} );
|
||||
} );
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from '../../utils/flows';
|
||||
import { settingsPageSaveChanges, verifyValueOfInputField } from '../../utils';
|
||||
|
||||
describe( 'WooCommerce General Settings', () => {
|
||||
beforeAll( async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'can update settings', async () => {
|
||||
// Go to general settings page
|
||||
await StoreOwnerFlow.openSettings( 'general' );
|
||||
|
||||
// Make sure the general tab is active
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'General' } );
|
||||
|
||||
// Set selling location to all countries first,
|
||||
// so we can choose california as base location.
|
||||
await expect( page ).toSelect( '#woocommerce_allowed_countries', 'Sell to all countries' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_allowed_countries', { text: 'Sell to all countries' } ),
|
||||
] );
|
||||
|
||||
// Set base location with state CA.
|
||||
await expect( page ).toSelect( 'select[name="woocommerce_default_country"]', 'United States (US) — California' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).toMatchElement( 'select[name="woocommerce_default_country"]', { text: 'United States (US) — California' } ),
|
||||
] );
|
||||
|
||||
// Set selling location to specific countries first, so we can choose U.S as base location (without state).
|
||||
// This will makes specific countries option appears.
|
||||
await expect( page ).toSelect( '#woocommerce_allowed_countries', 'Sell to specific countries' );
|
||||
await expect( page ).toSelect( 'select[name="woocommerce_specific_allowed_countries[]"]', 'United States (US)' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_allowed_countries', { text: 'Sell to specific countries' } ),
|
||||
expect( page ).toMatchElement( 'select[name="woocommerce_specific_allowed_countries[]"]', { text: 'United States (US)' } ),
|
||||
] );
|
||||
|
||||
// Set currency options.
|
||||
await expect( page ).toFill( '#woocommerce_price_thousand_sep', ',' );
|
||||
await expect( page ).toFill( '#woocommerce_price_decimal_sep', '.' );
|
||||
await expect( page ).toFill( '#woocommerce_price_num_decimals', '2' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
verifyValueOfInputField( '#woocommerce_price_thousand_sep', ',' ),
|
||||
verifyValueOfInputField( '#woocommerce_price_decimal_sep', '.' ),
|
||||
verifyValueOfInputField( '#woocommerce_price_num_decimals', '2' ),
|
||||
] );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from '../../utils/flows';
|
||||
import { setCheckbox, settingsPageSaveChanges, unsetCheckbox, verifyCheckboxIsSet, verifyCheckboxIsUnset } from '../../utils';
|
||||
|
||||
describe( 'WooCommerce Products > Downloadable Products Settings', () => {
|
||||
beforeAll( async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'can update settings', async () => {
|
||||
// Go to downloadable products settings page
|
||||
await StoreOwnerFlow.openSettings( 'products', 'downloadable' );
|
||||
|
||||
// Make sure the product tab is active
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Products' } );
|
||||
await expect( page ).toMatchElement( 'ul.subsubsub > li > a.current', { text: 'Downloadable products' } );
|
||||
|
||||
await expect( page ).toSelect( '#woocommerce_file_download_method', 'Redirect only' );
|
||||
await setCheckbox( '#woocommerce_downloads_require_login' );
|
||||
await setCheckbox( '#woocommerce_downloads_grant_access_after_payment' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_file_download_method', { text: 'Redirect only' } ),
|
||||
verifyCheckboxIsSet( '#woocommerce_downloads_require_login' ),
|
||||
verifyCheckboxIsSet( '#woocommerce_downloads_grant_access_after_payment' ),
|
||||
] );
|
||||
|
||||
await expect( page ).toSelect( '#woocommerce_file_download_method', 'Force downloads' );
|
||||
await unsetCheckbox( '#woocommerce_downloads_require_login' );
|
||||
await unsetCheckbox( '#woocommerce_downloads_grant_access_after_payment' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_file_download_method', { text: 'Force downloads' } ),
|
||||
verifyCheckboxIsUnset( '#woocommerce_downloads_require_login' ),
|
||||
verifyCheckboxIsUnset( '#woocommerce_downloads_grant_access_after_payment' ),
|
||||
] );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,170 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from '../../utils/flows';
|
||||
import {
|
||||
clearAndFillInput,
|
||||
setCheckbox,
|
||||
settingsPageSaveChanges,
|
||||
uiUnblocked,
|
||||
verifyCheckboxIsSet,
|
||||
verifyValueOfInputField
|
||||
} from '../../utils';
|
||||
|
||||
describe( 'WooCommerce Tax Settings', () => {
|
||||
beforeAll( async () => {
|
||||
await StoreOwnerFlow.login();
|
||||
} );
|
||||
|
||||
it( 'can enable tax calculation', async() => {
|
||||
// Go to general settings page
|
||||
await StoreOwnerFlow.openSettings( 'general' );
|
||||
|
||||
// Make sure the general tab is active
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'General' } );
|
||||
|
||||
// Enable tax calculation
|
||||
await setCheckbox( 'input[name="woocommerce_calc_taxes"]' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
verifyCheckboxIsSet( '#woocommerce_calc_taxes' ),
|
||||
] );
|
||||
|
||||
// Verify that tax settings are now present
|
||||
await expect( page ).toMatchElement( 'a.nav-tab', { text: 'Tax' } );
|
||||
} );
|
||||
|
||||
it( 'can set tax options', async () => {
|
||||
// Go to tax settings page
|
||||
await StoreOwnerFlow.openSettings( 'tax' );
|
||||
|
||||
// Make sure the tax tab is active
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } );
|
||||
|
||||
// Prices exclusive of tax
|
||||
await expect( page ).toClick( 'input[name="woocommerce_prices_include_tax"][value="no"]' );
|
||||
// Tax based on customer shipping address
|
||||
await expect( page ).toSelect( '#woocommerce_tax_based_on', 'Customer shipping address' );
|
||||
// Standard tax class for shipping
|
||||
await expect( page ).toSelect( '#woocommerce_shipping_tax_class', 'Standard' );
|
||||
// Leave rounding unchecked (no-op)
|
||||
// Display prices excluding tax
|
||||
await expect( page ).toSelect( '#woocommerce_tax_display_shop', 'Excluding tax' );
|
||||
// Display prices including tax in cart and at checkout
|
||||
await expect( page ).toSelect( '#woocommerce_tax_display_cart', 'Including tax' );
|
||||
// Display a single tax total
|
||||
await expect( page ).toSelect( '#woocommerce_tax_total_display', 'As a single total' );
|
||||
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
verifyValueOfInputField( 'input[name="woocommerce_prices_include_tax"][value="no"]', 'no' ),
|
||||
expect( page ).toMatchElement( '#woocommerce_tax_based_on', { text: 'Customer shipping address' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_shipping_tax_class', { text: 'Standard' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_tax_display_shop', { text: 'Excluding tax' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_tax_display_cart', { text: 'Including tax' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_tax_total_display', { text: 'As a single total' } ),
|
||||
] );
|
||||
} );
|
||||
|
||||
it( 'can add tax classes', async () => {
|
||||
// Go to tax settings page
|
||||
await StoreOwnerFlow.openSettings( 'tax' );
|
||||
|
||||
// Make sure the tax tab is active
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } );
|
||||
|
||||
// Remove additional tax classes
|
||||
await clearAndFillInput( '#woocommerce_tax_classes', '' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).toMatchElement( '#woocommerce_tax_classes', { text: '' } ),
|
||||
] );
|
||||
|
||||
// Add a "fancy" tax class
|
||||
await clearAndFillInput( '#woocommerce_tax_classes', 'Fancy' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).toMatchElement( 'ul.subsubsub > li > a', { text: 'Fancy rates' } ),
|
||||
] );
|
||||
} );
|
||||
|
||||
it( 'can set rate settings', async () => {
|
||||
// Go to "fancy" rates tax settings page
|
||||
await StoreOwnerFlow.openSettings( 'tax', 'fancy' );
|
||||
|
||||
// Make sure the tax tab is active, with the "fancy" subsection
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } );
|
||||
await expect( page ).toMatchElement( 'ul.subsubsub > li > a.current', { text: 'Fancy rates' } );
|
||||
|
||||
// Create a state tax
|
||||
await expect( page ).toClick( '.wc_tax_rates a.insert' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate_country[new-0"]', 'US' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate_state[new-0"]', 'CA' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate[new-0"]', '7.5' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate_name[new-0"]', 'CA State Tax' );
|
||||
|
||||
// Create a federal tax
|
||||
await expect( page ).toClick( '.wc_tax_rates a.insert' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate_country[new-1"]', 'US' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate[new-1"]', '1.5' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate_priority[new-1"]', '2' );
|
||||
await expect( page ).toFill( 'input[name^="tax_rate_name[new-1"]', 'Federal Tax' );
|
||||
await expect( page ).toClick( 'input[name^="tax_rate_shipping[new-1"]' );
|
||||
|
||||
// Save changes (AJAX here)
|
||||
await expect( page ).toClick( 'button.woocommerce-save-button' );
|
||||
await uiUnblocked();
|
||||
|
||||
// Verify 2 tax rates
|
||||
expect( await page.$$( '#rates tr' ) ).toHaveLength( 2 );
|
||||
|
||||
// Delete federal rate
|
||||
await expect( page ).toClick( '#rates tr:nth-child(2) input' );
|
||||
await expect( page ).toClick( '.wc_tax_rates a.remove_tax_rates' );
|
||||
|
||||
// Save changes (AJAX here)
|
||||
await expect( page ).toClick( 'button.woocommerce-save-button' );
|
||||
await uiUnblocked();
|
||||
|
||||
// Verify 1 rate
|
||||
expect( await page.$$( '#rates tr' ) ).toHaveLength( 1 );
|
||||
await expect( page ).toMatchElement(
|
||||
'#rates tr:first-of-type input[name^="tax_rate_state"][value="CA"]'
|
||||
);
|
||||
} );
|
||||
|
||||
it( 'can remove tax classes', async () => {
|
||||
// Go to tax settings page
|
||||
await StoreOwnerFlow.openSettings( 'tax' );
|
||||
|
||||
// Make sure the tax tab is active
|
||||
await expect( page ).toMatchElement( 'a.nav-tab-active', { text: 'Tax' } );
|
||||
|
||||
// Remove "fancy" tax class
|
||||
await clearAndFillInput( '#woocommerce_tax_classes', ' ' );
|
||||
await settingsPageSaveChanges();
|
||||
|
||||
// Verify that settings have been saved
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( '#message', { text: 'Your settings have been saved.' } ),
|
||||
expect( page ).not.toMatchElement( 'ul.subsubsub > li > a', { text: 'Fancy rates' } ),
|
||||
] );
|
||||
await page.waitFor( 10000 );
|
||||
} );
|
||||
} );
|
|
@ -0,0 +1,176 @@
|
|||
/**
|
||||
* @format
|
||||
*/
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { StoreOwnerFlow } from "./flows";
|
||||
import { clickTab, uiUnblocked } from "./index";
|
||||
|
||||
const verifyAndPublish = async () => {
|
||||
// Wait for auto save
|
||||
await page.waitFor( 2000 );
|
||||
|
||||
// Publish product
|
||||
await expect( page ).toClick( '#publish' );
|
||||
await page.waitForSelector( '.updated.notice' );
|
||||
|
||||
// Verify
|
||||
await expect( page ).toMatchElement( '.updated.notice', { text: 'Product published.' } );
|
||||
};
|
||||
|
||||
/**
|
||||
* Create simple product.
|
||||
*/
|
||||
const createSimpleProduct = async () => {
|
||||
// Go to "add product" page
|
||||
await StoreOwnerFlow.openNewProduct();
|
||||
|
||||
// Make sure we're on the add order page
|
||||
await expect( page.title() ).resolves.toMatch( 'Add new product' );
|
||||
|
||||
// Set product data
|
||||
await expect( page ).toFill( '#title', 'Simple product' );
|
||||
await expect( page ).toClick( '#_virtual' );
|
||||
await clickTab( 'General' );
|
||||
await expect( page ).toFill( '#_regular_price', '9.99' );
|
||||
|
||||
await verifyAndPublish();
|
||||
|
||||
const simplePostId = await page.$( '#post_ID' );
|
||||
let simplePostIdValue = ( await ( await simplePostId.getProperty( 'value' ) ).jsonValue() );
|
||||
return simplePostIdValue;
|
||||
} ;
|
||||
|
||||
/**
|
||||
* Create variable product.
|
||||
*/
|
||||
const createVariableProduct = async () => {
|
||||
// Go to "add product" page
|
||||
await StoreOwnerFlow.openNewProduct();
|
||||
|
||||
// Make sure we're on the add order page
|
||||
await expect( page.title() ).resolves.toMatch( 'Add new product' );
|
||||
|
||||
// Set product data
|
||||
await expect( page ).toFill( '#title', 'Variable Product with Three Variations' );
|
||||
await expect( page ).toSelect( '#product-type', 'Variable product' );
|
||||
|
||||
// Create attributes for variations
|
||||
await clickTab( 'Attributes' );
|
||||
await expect( page ).toSelect( 'select[name="attribute_taxonomy"]', 'Custom product attribute' );
|
||||
|
||||
for ( let i = 0; i < 3; i++ ) {
|
||||
await expect( page ).toClick( 'button.add_attribute', { text: 'Add' } );
|
||||
// Wait for attribute form to load
|
||||
await uiUnblocked();
|
||||
|
||||
await page.focus( `input[name="attribute_names[${ i }]"]` );
|
||||
await expect( page ).toFill( `input[name="attribute_names[${ i }]"]`, 'attr #' + ( i + 1 ) );
|
||||
await expect( page ).toFill( `textarea[name="attribute_values[${ i }]"]`, 'val1 | val2' );
|
||||
await expect( page ).toClick( `input[name="attribute_variation[${ i }]"]` );
|
||||
}
|
||||
|
||||
await expect( page ).toClick( 'button', { text: 'Save attributes' } );
|
||||
|
||||
// Wait for attribute form to save (triggers 2 UI blocks)
|
||||
await uiUnblocked();
|
||||
await uiUnblocked();
|
||||
|
||||
// Create variations from attributes
|
||||
await clickTab( 'Variations' );
|
||||
await page.waitForSelector( 'select.variation_actions:not([disabled])' );
|
||||
await page.focus( 'select.variation_actions' );
|
||||
await expect( page ).toSelect( 'select.variation_actions', 'Create variations from all attributes' );
|
||||
|
||||
const firstDialog = await expect( page ).toDisplayDialog( async () => {
|
||||
// Using this technique since toClick() isn't working.
|
||||
// See: https://github.com/GoogleChrome/puppeteer/issues/1805#issuecomment-464802876
|
||||
page.$eval( 'a.do_variation_action', elem => elem.click() );
|
||||
|
||||
} );
|
||||
|
||||
expect( firstDialog.message() ).toMatch( 'Are you sure you want to link all variations?' );
|
||||
|
||||
const secondDialog = await expect( page ).toDisplayDialog( async () => {
|
||||
await firstDialog.accept();
|
||||
} );
|
||||
|
||||
expect( secondDialog.message() ).toMatch( '8 variations added' );
|
||||
await secondDialog.dismiss();
|
||||
|
||||
// Set some variation data
|
||||
await uiUnblocked();
|
||||
await uiUnblocked();
|
||||
|
||||
await page.waitForSelector( '.woocommerce_variation .handlediv' );
|
||||
|
||||
// Verify that variations were created
|
||||
await Promise.all( [
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[0]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[0]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[0]"]', { text: 'val1' } ),
|
||||
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[1]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[1]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[1]"]', { text: 'val2' } ),
|
||||
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[2]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[2]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[2]"]', { text: 'val1' } ),
|
||||
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[3]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[3]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[3]"]', { text: 'val2' } ),
|
||||
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[4]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[4]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[4]"]', { text: 'val1' } ),
|
||||
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[5]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[5]"]', { text: 'val1' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[5]"]', { text: 'val2' } ),
|
||||
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[6]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[6]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[6]"]', { text: 'val1' } ),
|
||||
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-1[7]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-2[7]"]', { text: 'val2' } ),
|
||||
expect( page ).toMatchElement( 'select[name="attribute_attr-3[7]"]', { text: 'val2' } ),
|
||||
] );
|
||||
|
||||
await expect( page ).toClick( '.woocommerce_variation:nth-of-type(2) .handlediv' );
|
||||
await page.waitFor( 2000 );
|
||||
await page.focus( 'input[name="variable_is_virtual[0]"]' );
|
||||
await expect( page ).toClick( 'input[name="variable_is_virtual[0]"]' );
|
||||
await expect( page ).toFill( 'input[name="variable_regular_price[0]"]', '9.99' );
|
||||
|
||||
await expect( page ).toClick( '.woocommerce_variation:nth-of-type(3) .handlediv' );
|
||||
await page.waitFor( 2000 );
|
||||
await page.focus( 'input[name="variable_is_virtual[1]"]' );
|
||||
await expect( page ).toClick( 'input[name="variable_is_virtual[1]"]' );
|
||||
await expect( page ).toFill( 'input[name="variable_regular_price[1]"]', '11.99' );
|
||||
|
||||
await expect( page ).toClick( '.woocommerce_variation:nth-of-type(4) .handlediv' );
|
||||
await page.waitFor( 2000 );
|
||||
await page.focus( 'input[name="variable_manage_stock[2]"]' );
|
||||
await expect( page ).toClick( 'input[name="variable_manage_stock[2]"]' );
|
||||
await expect( page ).toFill( 'input[name="variable_regular_price[2]"]', '20' );
|
||||
await expect( page ).toFill( 'input[name="variable_weight[2]"]', '200' );
|
||||
await expect( page ).toFill( 'input[name="variable_length[2]"]', '10' );
|
||||
await expect( page ).toFill( 'input[name="variable_width[2]"]', '20' );
|
||||
await expect( page ).toFill( 'input[name="variable_height[2]"]', '15' );
|
||||
|
||||
await page.focus( 'button.save-variation-changes' );
|
||||
await expect( page ).toClick( 'button.save-variation-changes', { text: 'Save changes' } );
|
||||
|
||||
await verifyAndPublish();
|
||||
|
||||
const variablePostId = await page.$( '#post_ID' );
|
||||
let variablePostIdValue = ( await ( await variablePostId.getProperty( 'value' ) ).jsonValue() );
|
||||
return variablePostIdValue;
|
||||
};
|
||||
|
||||
export { createSimpleProduct, createVariableProduct };
|
|
@ -2,9 +2,97 @@
|
|||
* @format
|
||||
*/
|
||||
|
||||
const baseUrl = process.env.WP_BASE_URL;
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
import { clearAndFillInput } from './index';
|
||||
|
||||
const WP_ADMIN_NEW_PRODUCT = baseUrl + '/wp-admin/post-new.php?post_type=product';
|
||||
const config = require( 'config' );
|
||||
const baseUrl = config.get( 'url' );
|
||||
|
||||
const WP_ADMIN_LOGIN = baseUrl + 'wp-login.php';
|
||||
const WP_ADMIN_DASHBOARD = baseUrl + 'wp-admin';
|
||||
const WP_ADMIN_PLUGINS = baseUrl + 'wp-admin/plugins.php';
|
||||
const WP_ADMIN_SETUP_WIZARD = baseUrl + 'wp-admin/admin.php?page=wc-setup';
|
||||
const WP_ADMIN_NEW_COUPON = baseUrl + 'wp-admin/post-new.php?post_type=shop_coupon';
|
||||
const WP_ADMIN_NEW_ORDER = baseUrl + 'wp-admin/post-new.php?post_type=shop_order';
|
||||
const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=product';
|
||||
const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=';
|
||||
const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php';
|
||||
|
||||
const SHOP_PRODUCT = baseUrl + '?p=';
|
||||
const SHOP_CART_PAGE = baseUrl + 'cart/';
|
||||
|
||||
const getProductColumnExpression = ( productTitle ) => (
|
||||
'td[@class="product-name" and ' +
|
||||
`a[contains(text(), "${ productTitle }")]` +
|
||||
']'
|
||||
);
|
||||
|
||||
const getQtyColumnExpression = ( args ) => (
|
||||
'td[@class="product-quantity" and ' +
|
||||
'.//' + getQtyInputExpression( args ) +
|
||||
']'
|
||||
);
|
||||
|
||||
const getQtyInputExpression = ( args = {} ) => {
|
||||
let qtyValue = '';
|
||||
|
||||
if ( args.checkQty ) {
|
||||
qtyValue = ` and @value="${ args.qty }"`;
|
||||
}
|
||||
|
||||
return 'input[contains(@class, "input-text")' + qtyValue + ']';
|
||||
};
|
||||
|
||||
const getCartItemExpression = ( productTitle, args ) => (
|
||||
'//tr[contains(@class, "cart_item") and ' +
|
||||
getProductColumnExpression( productTitle ) +
|
||||
' and ' +
|
||||
getQtyColumnExpression( args ) +
|
||||
']'
|
||||
);
|
||||
|
||||
const getRemoveExpression = () => (
|
||||
'td[@class="product-remove"]//a[@class="remove"]'
|
||||
);
|
||||
|
||||
const CustomerFlow = {
|
||||
addToCart: async () => {
|
||||
await Promise.all( [
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
page.click( '.single_add_to_cart_button' ),
|
||||
] );
|
||||
},
|
||||
|
||||
removeFromCart: async ( productTitle ) => {
|
||||
const cartItemXPath = getCartItemExpression( productTitle );
|
||||
const removeItemXPath = cartItemXPath + '//' + getRemoveExpression();
|
||||
|
||||
const [ removeButton ] = await page.$x( removeItemXPath );
|
||||
await removeButton.click();
|
||||
},
|
||||
|
||||
goToProduct: async ( postID ) => {
|
||||
await page.goto( SHOP_PRODUCT + postID, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
goToCart: async () => {
|
||||
await page.goto( SHOP_CART_PAGE, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
productIsInCart: async ( productTitle, quantity = null ) => {
|
||||
const cartItemArgs = quantity ? { qty: quantity } : {};
|
||||
const cartItemXPath = getCartItemExpression( productTitle, cartItemArgs );
|
||||
|
||||
await expect( page.$x( cartItemXPath ) ).resolves.toHaveLength( 1 );
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
const MY_ACCOUNT_ORDERS = baseUrl + '/my-account/orders/';
|
||||
const MY_ACCOUNT_DOWNLOADS = baseUrl + '/my-account/downloads/';
|
||||
|
@ -38,11 +126,90 @@ const CustomerFlow = {
|
|||
};
|
||||
|
||||
const StoreOwnerFlow = {
|
||||
login: async () => {
|
||||
await page.goto( WP_ADMIN_LOGIN, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
|
||||
await expect( page.title() ).resolves.toMatch( 'Log In' );
|
||||
|
||||
await clearAndFillInput( '#user_login', ' ' );
|
||||
|
||||
await page.type( '#user_login', config.get( 'users.admin.username' ) );
|
||||
await page.type( '#user_pass', config.get( 'users.admin.password' ) );
|
||||
|
||||
await Promise.all( [
|
||||
page.click( 'input[type=submit]' ),
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
] );
|
||||
},
|
||||
|
||||
logout: async () => {
|
||||
await page.goto(baseUrl + 'wp-login.php?action=logout', {
|
||||
waitUntil: 'networkidle0',
|
||||
});
|
||||
|
||||
await expect(page).toMatch('You are attempting to log out');
|
||||
|
||||
await Promise.all([
|
||||
page.waitForNavigation({ waitUntil: 'networkidle0' }),
|
||||
page.click('a'),
|
||||
]);
|
||||
},
|
||||
|
||||
openDashboard: async () => {
|
||||
await page.goto( WP_ADMIN_DASHBOARD, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openNewCoupon: async () => {
|
||||
await page.goto( WP_ADMIN_NEW_COUPON, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openNewOrder: async () => {
|
||||
await page.goto( WP_ADMIN_NEW_ORDER, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openNewProduct: async () => {
|
||||
await page.goto( WP_ADMIN_NEW_PRODUCT, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openPermalinkSettings: async () => {
|
||||
await page.goto( WP_ADMIN_PERMALINK_SETTINGS, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openPlugins: async () => {
|
||||
await page.goto( WP_ADMIN_PLUGINS, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
openSettings: async ( tab, section = null ) => {
|
||||
let settingsUrl = WP_ADMIN_WC_SETTINGS + tab;
|
||||
|
||||
if ( section ) {
|
||||
settingsUrl += `§ion=${ section }`;
|
||||
}
|
||||
|
||||
await page.goto( settingsUrl, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
|
||||
runSetupWizard: async () => {
|
||||
await page.goto( WP_ADMIN_SETUP_WIZARD, {
|
||||
waitUntil: 'networkidle0',
|
||||
} );
|
||||
},
|
||||
};
|
||||
|
||||
export { CustomerFlow, StoreOwnerFlow };
|
||||
|
|
|
@ -1,17 +1,84 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { pressKeyWithModifier } from '@wordpress/e2e-test-utils';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
const flows = require( './flows' );
|
||||
|
||||
/**
|
||||
* Perform a "select all" and then fill a input.
|
||||
*
|
||||
* @param {string} selector
|
||||
* @param {string} value
|
||||
*/
|
||||
const clearAndFillInput = async ( selector, value ) => {
|
||||
await page.focus( selector );
|
||||
await pressKeyWithModifier( 'primary', 'a' );
|
||||
await page.type( selector, value );
|
||||
};
|
||||
|
||||
/**
|
||||
* Click a tab (on post type edit screen).
|
||||
*
|
||||
* @param {string} tabName Tab label.
|
||||
* @param {string} tabName Tab label
|
||||
*/
|
||||
const clickTab = async ( tabName ) => {
|
||||
await expect( page ).toClick( '.wc-tabs > li > a', { text: tabName } );
|
||||
};
|
||||
|
||||
/**
|
||||
* Save changes on a WooCommerce settings page.
|
||||
*/
|
||||
const settingsPageSaveChanges = async () => {
|
||||
await page.focus( 'button.woocommerce-save-button' );
|
||||
await Promise.all( [
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
page.click( 'button.woocommerce-save-button' ),
|
||||
] );
|
||||
};
|
||||
|
||||
/**
|
||||
* Save changes on Permalink settings page.
|
||||
*/
|
||||
const permalinkSettingsPageSaveChanges = async () => {
|
||||
await page.focus( '.wp-core-ui .button-primary' );
|
||||
await Promise.all( [
|
||||
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
|
||||
page.click( '.wp-core-ui .button-primary' ),
|
||||
] );
|
||||
};
|
||||
|
||||
/**
|
||||
* Set checkbox.
|
||||
*
|
||||
* @param {string} selector
|
||||
*/
|
||||
const setCheckbox = async( selector ) => {
|
||||
await page.focus( selector );
|
||||
const checkbox = await page.$( selector );
|
||||
const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() );
|
||||
if ( checkboxStatus !== true ) {
|
||||
await page.click( selector );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Unset checkbox.
|
||||
*
|
||||
* @param {string} selector
|
||||
*/
|
||||
const unsetCheckbox = async( selector ) => {
|
||||
await page.focus( selector );
|
||||
const checkbox = await page.$( selector );
|
||||
const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() );
|
||||
if ( checkboxStatus === true ) {
|
||||
await page.click( selector );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Wait for UI blocking to end.
|
||||
*/
|
||||
|
@ -19,8 +86,90 @@ const uiUnblocked = async () => {
|
|||
await page.waitForFunction( () => ! Boolean( document.querySelector( '.blockUI' ) ) );
|
||||
};
|
||||
|
||||
/**
|
||||
* Publish, verify that item was published. Trash, verify that item was trashed.
|
||||
*
|
||||
* @param {string} button (Publish)
|
||||
* @param {string} publishNotice
|
||||
* @param {string} publishVerification
|
||||
* @param {string} trashVerification
|
||||
*/
|
||||
const verifyPublishAndTrash = async ( button, publishNotice, publishVerification, trashVerification ) => {
|
||||
// Wait for auto save
|
||||
await page.waitFor( 2000 );
|
||||
|
||||
// Publish
|
||||
await expect( page ).toClick( button );
|
||||
await page.waitForSelector( publishNotice );
|
||||
|
||||
// Verify
|
||||
await expect( page ).toMatchElement( publishNotice, { text: publishVerification } );
|
||||
if ( button === '.order_actions li .save_order' ) {
|
||||
await expect( page ).toMatchElement( '#select2-order_status-container', { text: 'Processing' } );
|
||||
await expect( page ).toMatchElement(
|
||||
'#woocommerce-order-notes .note_content',
|
||||
{
|
||||
text: 'Order status changed from Pending payment to Processing.',
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
// Trash
|
||||
await expect( page ).toClick( 'a', { text: "Move to Trash" } );
|
||||
await page.waitForSelector( '#message' );
|
||||
|
||||
// Verify
|
||||
await expect( page ).toMatchElement( publishNotice, { text: trashVerification } );
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify that checkbox is set.
|
||||
*
|
||||
* @param {string} selector Selector of the checkbox that needs to be verified.
|
||||
*/
|
||||
const verifyCheckboxIsSet = async( selector ) => {
|
||||
await page.focus( selector );
|
||||
const checkbox = await page.$( selector );
|
||||
const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() );
|
||||
await expect( checkboxStatus ).toBe( true );
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify that checkbox is unset.
|
||||
*
|
||||
* @param {string} selector Selector of the checkbox that needs to be verified.
|
||||
*/
|
||||
const verifyCheckboxIsUnset = async( selector ) => {
|
||||
await page.focus( selector );
|
||||
const checkbox = await page.$( selector );
|
||||
const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() );
|
||||
await expect( checkboxStatus ).not.toBe( true );
|
||||
};
|
||||
|
||||
/**
|
||||
* Verify the value of input field once it was saved (can be used for radio buttons verification as well).
|
||||
*
|
||||
* @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 ) => {
|
||||
await page.focus( selector );
|
||||
const field = await page.$( selector );
|
||||
const fieldValue = ( await ( await field.getProperty( 'value' ) ).jsonValue() );
|
||||
await expect( fieldValue ).toBe( value );
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
...flows,
|
||||
clearAndFillInput,
|
||||
clickTab,
|
||||
settingsPageSaveChanges,
|
||||
permalinkSettingsPageSaveChanges,
|
||||
setCheckbox,
|
||||
unsetCheckbox,
|
||||
uiUnblocked,
|
||||
verifyPublishAndTrash,
|
||||
verifyCheckboxIsSet,
|
||||
verifyCheckboxIsUnset,
|
||||
verifyValueOfInputField,
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case {
|
|||
public function test_create_customer() {
|
||||
$username = 'testusername-' . time();
|
||||
$customer = new WC_Customer();
|
||||
$customer->set_username( 'testusername-' . time() );
|
||||
$customer->set_username( $username );
|
||||
$customer->set_password( 'test123' );
|
||||
$customer->set_email( 'test@woo.local' );
|
||||
$customer->save();
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* Plugin Name: WooCommerce
|
||||
* Plugin URI: https://woocommerce.com/
|
||||
* Description: An eCommerce toolkit that helps you sell anything. Beautifully.
|
||||
* Version: 3.8.0-beta.1
|
||||
* Version: 3.9.0-dev
|
||||
* Author: Automattic
|
||||
* Author URI: https://woocommerce.com
|
||||
* Text Domain: woocommerce
|
||||
|
@ -39,7 +39,7 @@ if ( version_compare( PHP_VERSION, '5.6.0', '>=' ) ) {
|
|||
|
||||
// Include the main WooCommerce class.
|
||||
if ( ! class_exists( 'WooCommerce', false ) ) {
|
||||
include_once dirname( __FILE__ ) . '/includes/class-woocommerce.php';
|
||||
include_once dirname( WC_PLUGIN_FILE ) . '/includes/class-woocommerce.php';
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue