From 7706b199c5b654d752bee19dc6da1a03b05f745d Mon Sep 17 00:00:00 2001 From: Caleb Burks Date: Thu, 1 Apr 2021 19:37:39 -0500 Subject: [PATCH 01/41] Enhance woocommerce_logger_log_message filter --- includes/class-wc-logger.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/includes/class-wc-logger.php b/includes/class-wc-logger.php index 040dd580529..ef2184f43f1 100644 --- a/includes/class-wc-logger.php +++ b/includes/class-wc-logger.php @@ -139,11 +139,14 @@ class WC_Logger implements WC_Logger_Interface { } if ( $this->should_handle( $level ) ) { - $timestamp = current_time( 'timestamp', 1 ); - $message = apply_filters( 'woocommerce_logger_log_message', $message, $level, $context ); + $timestamp = time(); foreach ( $this->handlers as $handler ) { - $handler->handle( $timestamp, $level, $message, $context ); + $message = apply_filters( 'woocommerce_logger_log_message', $message, $level, $context, $handler ); + + if ( null !== $message ) { + $handler->handle( $timestamp, $level, $message, $context ); + } } } } From a6467681c86be1bd0f7246236469248913b1ab8d Mon Sep 17 00:00:00 2001 From: Veljko Date: Wed, 7 Apr 2021 17:50:09 +0200 Subject: [PATCH 02/41] Add new e2e test shopper cart calculate shipping --- tests/e2e/core-tests/specs/index.js | 3 + .../front-end-cart-calculate-shipping.test.js | 147 ++++++++++++++++++ .../front-end/test-cart-calculate-shipping.js | 6 + 3 files changed, 156 insertions(+) create mode 100644 tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js create mode 100644 tests/e2e/specs/front-end/test-cart-calculate-shipping.js diff --git a/tests/e2e/core-tests/specs/index.js b/tests/e2e/core-tests/specs/index.js index 4d8997e462b..8aa6791858c 100644 --- a/tests/e2e/core-tests/specs/index.js +++ b/tests/e2e/core-tests/specs/index.js @@ -21,6 +21,7 @@ const runSingleProductPageTest = require( './shopper/front-end-single-product.te const runVariableProductUpdateTest = require( './shopper/front-end-variable-product-updates.test' ); const runCheckoutCreateAccountTest = require( './shopper/front-end-checkout-create-account.test' ); const runCheckoutLoginAccountTest = require( './shopper/front-end-checkout-login-account.test' ); +const runCartCalculateShippingTest = require( './shopper/front-end-cart-calculate-shipping.test' ); // Merchant tests const runAddNewShippingZoneTest = require ( './merchant/wp-admin-settings-shipping-zones.test' ); @@ -67,6 +68,7 @@ const runShopperTests = () => { runVariableProductUpdateTest(); runCheckoutCreateAccountTest(); runCheckoutLoginAccountTest(); + runCartCalculateShippingTest(); }; const runMerchantTests = () => { @@ -139,4 +141,5 @@ module.exports = { runCheckoutCreateAccountTest, runCheckoutLoginAccountTest, runMyAccountCreateAccountTest, + runCartCalculateShippingTest, }; diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js new file mode 100644 index 00000000000..2a8d87da894 --- /dev/null +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -0,0 +1,147 @@ +/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */ +/** + * Internal dependencies + */ +const { + shopper, + merchant, + createSimpleProduct, + addShippingZoneAndMethod, + clearAndFillInput, + evalAndClick, + uiUnblocked, + selectOptionInSelect2, +} = require( '@woocommerce/e2e-utils' ); + +const config = require( 'config' ); +const firstProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; +const secondProductPrice = '4.99'; +const fourProductPrice = firstProductPrice * 4; +var twoProductsPrice = eval([firstProductPrice,secondProductPrice].join('+')); +var firstProductPriceWithFlatRate = eval([firstProductPrice,5].join('+')); +var fourProductPriceWithFlatRate = eval([fourProductPrice,5].join('+')); +var twoProductsPriceWithFlatRate = eval([twoProductsPrice,5].join('+')); +const firstProductName = 'First Product'; +const secondProductName = 'Second Product'; +const shippingZoneNameDE = 'Germany Free Shipping'; +const shippingCountryDE = 'country:DE'; +const shippingZoneNameFR = 'France Flat Local'; +const shippingCountryFR = 'country:FR'; + +const runCartCalculateShippingTest = () => { + describe('Cart Calculate Shipping', () => { + beforeAll(async () => { + await merchant.login(); + await createSimpleProduct(firstProductName); + await createSimpleProduct(secondProductName, secondProductPrice); + await merchant.openSettings('shipping'); + + // Delete existing shipping zones. + try { + let zone = await page.$( '.wc-shipping-zone-delete' ); + if ( zone ) { + // WP action links aren't clickable because they are hidden with a left=-9999 style. + await page.evaluate(() => { + document.querySelector('.wc-shipping-zone-name .row-actions') + .style + .left = '0'; + }); + while ( zone ) { + await evalAndClick( '.wc-shipping-zone-delete' ); + await uiUnblocked(); + zone = await page.$( '.wc-shipping-zone-delete' ); + } + } + } catch (error) { + // Prevent an error here causing the test to fail. + } + + // Add a new shipping zone Germany with Free shipping + await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); + + // Add a new shipping zone for France with Flat rate & Local pickup + await addShippingZoneAndMethod(shippingZoneNameFR, shippingCountryFR, ' ', 'flat_rate'); + await page.waitFor(1000); // to avoid flakiness in headless + await page.click('a.wc-shipping-zone-method-settings', {text: 'Flat rate'}); + await clearAndFillInput('#woocommerce_flat_rate_cost', '5'); + await page.click('.wc-backbone-modal-main button#btn-ok'); + // Add additional method Local pickup for the same location + await page.waitFor(1000); // to avoid flakiness in headless + await page.click('button.wc-shipping-zone-add-method', {text:'Add shipping method'}); + await page.waitForSelector('.wc-shipping-zone-method-selector'); + await page.select('select[name="add_method_id"]', 'local_pickup'); + await page.click('button#btn-ok'); + await page.waitForSelector('#zone_locations'); + + await merchant.logout(); + }); + + it('allows customer to calculate Free Shipping if in Germany', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(firstProductName); + await shopper.goToCart(); + + // Set shipping country to Germany + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('Germany'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping ul#shipping_method > li', {text: 'Free shipping'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPrice}`}); + }); + + it('allows customer to calculate Flat rate and Local pickup if in France', async () => { + await page.reload(); + + // Set shipping country to France + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('France'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPriceWithFlatRate}`}); + }); + + it('should show correct total cart price after updating quantity', async () => { + await shopper.setCartQuantity(firstProductName, 4); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); + }); + + it('should show correct total cart price with 2 products and flat rate', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(secondProductName); + await shopper.goToCart(); + + await shopper.setCartQuantity(firstProductName, 1); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); + }); + + it('should show correct total cart price with 2 products without flat rate', async () => { + await page.reload(); + + // Set shipping country to Spain + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('Spain'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); + }); + }); +}; + +module.exports = runCartCalculateShippingTest; diff --git a/tests/e2e/specs/front-end/test-cart-calculate-shipping.js b/tests/e2e/specs/front-end/test-cart-calculate-shipping.js new file mode 100644 index 00000000000..6ee84f7b8f2 --- /dev/null +++ b/tests/e2e/specs/front-end/test-cart-calculate-shipping.js @@ -0,0 +1,6 @@ +/* + * Internal dependencies + */ +const { runCartCalculateShippingTest } = require( '@woocommerce/e2e-core-tests' ); + +runCartCalculateShippingTest(); From 9fdbaae76e5c6a32fbaba90e4e7717e18e3b0c86 Mon Sep 17 00:00:00 2001 From: Veljko Date: Wed, 7 Apr 2021 17:52:58 +0200 Subject: [PATCH 03/41] Add changelog and update spaces --- tests/e2e/core-tests/CHANGELOG.md | 1 + tests/e2e/core-tests/README.md | 1 + .../front-end-cart-calculate-shipping.test.js | 74 +++++++++---------- 3 files changed, 39 insertions(+), 37 deletions(-) diff --git a/tests/e2e/core-tests/CHANGELOG.md b/tests/e2e/core-tests/CHANGELOG.md index bf220a9d338..6d546e5571d 100644 --- a/tests/e2e/core-tests/CHANGELOG.md +++ b/tests/e2e/core-tests/CHANGELOG.md @@ -6,6 +6,7 @@ - Shopper Checkout Login Account - Shopper My Account Create Account +- Shopper Cart Calculate Shipping ## Fixed diff --git a/tests/e2e/core-tests/README.md b/tests/e2e/core-tests/README.md index 26f58a36c67..75d272ab1dd 100644 --- a/tests/e2e/core-tests/README.md +++ b/tests/e2e/core-tests/README.md @@ -79,6 +79,7 @@ The functions to access the core tests are: - `runCheckoutCreateAccountTest` - Shopper can create an account during checkout - `runCheckoutLoginAccountTest` - Shopper can login to an account during checkout - `runMyAccountCreateAccountTest` - Shopper can create an account via my account page + - `runCartCalculateShippingTest` - Shopper can calculate shipping in the cart ### REST API diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 2a8d87da894..59c980a620c 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -33,7 +33,7 @@ const runCartCalculateShippingTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(firstProductName); - await createSimpleProduct(secondProductName, secondProductPrice); + await createSimpleProduct(secondProductName, secondProductPrice); await merchant.openSettings('shipping'); // Delete existing shipping zones. @@ -61,31 +61,31 @@ const runCartCalculateShippingTest = () => { // Add a new shipping zone for France with Flat rate & Local pickup await addShippingZoneAndMethod(shippingZoneNameFR, shippingCountryFR, ' ', 'flat_rate'); - await page.waitFor(1000); // to avoid flakiness in headless + await page.waitFor(1000); // to avoid flakiness in headless await page.click('a.wc-shipping-zone-method-settings', {text: 'Flat rate'}); await clearAndFillInput('#woocommerce_flat_rate_cost', '5'); await page.click('.wc-backbone-modal-main button#btn-ok'); - // Add additional method Local pickup for the same location - await page.waitFor(1000); // to avoid flakiness in headless - await page.click('button.wc-shipping-zone-add-method', {text:'Add shipping method'}); - await page.waitForSelector('.wc-shipping-zone-method-selector'); - await page.select('select[name="add_method_id"]', 'local_pickup'); - await page.click('button#btn-ok'); - await page.waitForSelector('#zone_locations'); + // Add additional method Local pickup for the same location + await page.waitFor(1000); // to avoid flakiness in headless + await page.click('button.wc-shipping-zone-add-method', {text:'Add shipping method'}); + await page.waitForSelector('.wc-shipping-zone-method-selector'); + await page.select('select[name="add_method_id"]', 'local_pickup'); + await page.click('button#btn-ok'); + await page.waitForSelector('#zone_locations'); await merchant.logout(); }); it('allows customer to calculate Free Shipping if in Germany', async () => { await shopper.goToShop(); - await shopper.addToCartFromShopPage(firstProductName); - await shopper.goToCart(); - - // Set shipping country to Germany + await shopper.addToCartFromShopPage(firstProductName); + await shopper.goToCart(); + + // Set shipping country to Germany await expect(page).toClick('a.shipping-calculator-button'); await expect(page).toClick('#select2-calc_shipping_country-container'); await selectOptionInSelect2('Germany'); - await expect(page).toClick('button[name="calc_shipping"]'); + await expect(page).toClick('button[name="calc_shipping"]'); // Verify shipping costs await page.waitForSelector('.order-total'); @@ -93,54 +93,54 @@ const runCartCalculateShippingTest = () => { await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPrice}`}); }); - it('allows customer to calculate Flat rate and Local pickup if in France', async () => { - await page.reload(); + it('allows customer to calculate Flat rate and Local pickup if in France', async () => { + await page.reload(); - // Set shipping country to France + // Set shipping country to France await expect(page).toClick('a.shipping-calculator-button'); await expect(page).toClick('#select2-calc_shipping_country-container'); await selectOptionInSelect2('France'); - await expect(page).toClick('button[name="calc_shipping"]'); + await expect(page).toClick('button[name="calc_shipping"]'); // Verify shipping costs await page.waitForSelector('.order-total'); await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); await expect(page).toMatchElement('.order-total .amount', {text: `$${firstProductPriceWithFlatRate}`}); - }); + }); - it('should show correct total cart price after updating quantity', async () => { - await shopper.setCartQuantity(firstProductName, 4); + it('should show correct total cart price after updating quantity', async () => { + await shopper.setCartQuantity(firstProductName, 4); await expect(page).toClick('button', {text: 'Update cart'}); await uiUnblocked(); - await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); - }); + await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); + }); - it('should show correct total cart price with 2 products and flat rate', async () => { - await shopper.goToShop(); - await shopper.addToCartFromShopPage(secondProductName); - await shopper.goToCart(); + it('should show correct total cart price with 2 products and flat rate', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(secondProductName); + await shopper.goToCart(); - await shopper.setCartQuantity(firstProductName, 1); - await expect(page).toClick('button', {text: 'Update cart'}); - await uiUnblocked(); - await page.waitForSelector('.order-total'); + await shopper.setCartQuantity(firstProductName, 1); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await page.waitForSelector('.order-total'); await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); - }); + }); - it('should show correct total cart price with 2 products without flat rate', async () => { - await page.reload(); + it('should show correct total cart price with 2 products without flat rate', async () => { + await page.reload(); - // Set shipping country to Spain + // Set shipping country to Spain await expect(page).toClick('a.shipping-calculator-button'); await expect(page).toClick('#select2-calc_shipping_country-container'); await selectOptionInSelect2('Spain'); - await expect(page).toClick('button[name="calc_shipping"]'); + await expect(page).toClick('button[name="calc_shipping"]'); // Verify shipping costs await page.waitForSelector('.order-total'); await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); - }); + }); }); }; From 86e83b6560c50fa6e817e0cc0552fcad434e649e Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Tue, 6 Apr 2021 23:48:18 -0300 Subject: [PATCH 04/41] reset onboarding, shipping, tracking --- tests/e2e/api/src/models/index.ts | 1 + .../onboarding-tasklist.test.js | 13 +++++ tests/e2e/utils/src/components.js | 5 +- tests/e2e/utils/src/flows/index.js | 2 + tests/e2e/utils/src/flows/with-rest-api.js | 57 +++++++++++++++++++ 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/utils/src/flows/with-rest-api.js diff --git a/tests/e2e/api/src/models/index.ts b/tests/e2e/api/src/models/index.ts index 13ce569f196..c29fdce7188 100644 --- a/tests/e2e/api/src/models/index.ts +++ b/tests/e2e/api/src/models/index.ts @@ -3,3 +3,4 @@ export * from './model'; export * from './settings'; export * from './shared-types'; export * from './coupons'; +//export * from './orders'; diff --git a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js index 4c31fff7c95..f56ad8d4133 100644 --- a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js +++ b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js @@ -1,10 +1,12 @@ /* eslint-disable jest/no-export, jest/no-disabled-tests */ + /** * Internal dependencies */ const { merchant, completeOnboardingWizard, + withRestApi, } = require( '@woocommerce/e2e-utils' ); /** @@ -17,6 +19,17 @@ const { const runOnboardingFlowTest = () => { describe('Store owner can go through store Onboarding', () => { + it( 'can reset onboarding to default settings', async () => { + await withRestApi.resetOnboarding(); + }); + + it( 'can reset shipping zones to default settings', async () => { + await withRestApi.deleteAllShippingZones(); + }); + + it( 'can reset allow tracking to default settings', async () => { + await withRestApi.resetAllowTracking(); + }); it('can start and complete onboarding when visiting the site for the first time.', async () => { await merchant.runSetupWizard(); diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index c449622937b..ab471990883 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -12,7 +12,8 @@ import { verifyCheckboxIsUnset, selectOptionInSelect2, setCheckbox, - unsetCheckbox + unsetCheckbox, + clearAndFillInput, } from './page-utils'; import factories from './factories'; @@ -67,7 +68,7 @@ const completeOnboardingWizard = async () => { await expect( page ).toFill( '.woocommerce-select-control__control-input', config.get( 'addresses.admin.store.countryandstate' ) ); // Fill the city where the store is located - await expect( page ).toFill( '#inspector-text-control-2', config.get( 'addresses.admin.store.city' ) ); + await clearAndFillInput( '#inspector-text-control-2', config.get( 'addresses.admin.store.city' ) ); // Fill postcode of the store await expect( page ).toFill( '#inspector-text-control-3', config.get( 'addresses.admin.store.postcode' ) ); diff --git a/tests/e2e/utils/src/flows/index.js b/tests/e2e/utils/src/flows/index.js index b4cf27fb868..93e71658f41 100644 --- a/tests/e2e/utils/src/flows/index.js +++ b/tests/e2e/utils/src/flows/index.js @@ -5,10 +5,12 @@ const flowConstants = require( './constants' ); const flowExpressions = require( './expressions' ); const merchant = require( './merchant' ); const shopper = require( './shopper' ); +const { withRestApi } = require( './with-rest-api' ); module.exports = { ...flowConstants, ...flowExpressions, merchant, shopper, + withRestApi, }; diff --git a/tests/e2e/utils/src/flows/with-rest-api.js b/tests/e2e/utils/src/flows/with-rest-api.js new file mode 100644 index 00000000000..680fe3e8868 --- /dev/null +++ b/tests/e2e/utils/src/flows/with-rest-api.js @@ -0,0 +1,57 @@ +import factories from '../factories'; +import { Setting } from '@woocommerce/api'; + +const client = factories.api.withDefaultPermalinks; +const onboardingProfileEndpoint = '/wc-admin/onboarding/profile'; +const shippingZoneEndpoint = '/wc/v3/shipping/zones'; + +/** + * Utility functions that use the REST API to process the requested function. + */ +export const withRestApi = { + /** + * Reset onboarding to equivalent of new site. + * @returns {Promise} + */ + resetOnboarding: async () => { + const onboardingReset = { + completed: false, + industry: [], + business_extensions: [], + skipped: false, + product_types: [], + product_count: '0', + selling_venues: 'no', + revenue: 'none', + theme: '', + setup_client: false, + wccom_connected: false, + }; + + const response = await client.put( onboardingProfileEndpoint, onboardingReset ); + expect( response.statusCode ).toEqual( 200 ); + }, + deleteAllShippingZones: async () => { + const shippingZones = await client.get( shippingZoneEndpoint ); + if ( shippingZones.data && shippingZones.data.length ) { + for ( let z = 0; z < shippingZones.data.length; z++ ) { + // The data store doesn't support deleting the default zone. + if ( shippingZones.data[z].id == 0 ) { + continue; + } + const response = await client.delete( shippingZoneEndpoint + `/${shippingZones.data[z].id}?force=true` ); + expect( response.statusCode ).toBe( 200 ); + } + } + }, + resetAllowTracking: async () => { + const settingsClient = Setting.restRepository( client ); + + const allowTracking = { + id: 'woocommerce_allow_tracking', + value: 'no' + }; + const response = await settingsClient.update( 'advanced', allowTracking.id, allowTracking ); + expect( response.value ).toBe( 'no' ); + } +}; From d025f47449ff371f341ccd5ce59156994bd476fa Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Wed, 7 Apr 2021 22:54:25 -0300 Subject: [PATCH 05/41] allow multiple runs of setup/onboarding --- tests/e2e/config/jest.setup.js | 60 ++++++------------ .../onboarding-tasklist.test.js | 37 ++++++----- tests/e2e/utils/src/flows/constants.js | 62 +++++++++++++------ tests/e2e/utils/src/flows/merchant.js | 5 +- tests/e2e/utils/src/flows/with-rest-api.js | 50 ++++++++++++++- 5 files changed, 135 insertions(+), 79 deletions(-) diff --git a/tests/e2e/config/jest.setup.js b/tests/e2e/config/jest.setup.js index 16b57a8168e..d1e02606fbf 100644 --- a/tests/e2e/config/jest.setup.js +++ b/tests/e2e/config/jest.setup.js @@ -4,11 +4,28 @@ import { switchUserToTest, clearLocalStorage, setBrowserViewport, - factories, + withRestApi, } from '@woocommerce/e2e-utils'; const { merchant } = require( '@woocommerce/e2e-utils' ); +/** + * Add an expect range matcher + * @see https://jestjs.io/docs/expect#expectextendmatchers + */ +expect.extend({ + toBeInRange: function (received, floor, ceiling) { + const pass = received >= floor && received <= ceiling; + const condition = pass ? 'not to be' : 'to be'; + + return { + message: () => + `expected ${received} ${condition} within range ${floor} - ${ceiling}`, + pass, + }; + }, +}); + /** * Navigates to the post listing screen and bulk-trashes any posts which exist. * @@ -38,50 +55,13 @@ async function trashExistingPosts() { await switchUserToTest(); } -/** - * Use api package to delete products. - * - * @return {Promise} Promise resolving once products have been trashed. - */ -async function deleteAllProducts() { - const repository = SimpleProduct.restRepository( factories.api.withDefaultPermalinks ); - let products; - - products = await repository.list(); - while ( products.length > 0 ) { - for( let p = 0; p < products.length; p++ ) { - await repository.delete( products[ p ].id ); - } - products = await repository.list(); - } -} - -/** - * Use api package to delete coupons. - * - * @return {Promise} Promise resolving once coupons have been trashed. - */ -async function deleteAllCoupons() { - const repository = Coupon.restRepository( factories.api.withDefaultPermalinks ); - let coupons; - - coupons = await repository.list(); - - while ( coupons.length > 0 ) { - for (let c = 0; c < coupons.length; c++ ) { - await repository.delete( coupons[ c ].id ); - } - coupons = await repository.list(); - } -} - // Before every test suite run, delete all content created by the test. This ensures // other posts/comments/etc. aren't dirtying tests and tests don't depend on // each other's side-effects. beforeAll( async () => { await trashExistingPosts(); - await deleteAllProducts(); - await deleteAllCoupons(); + await withRestApi.deleteAllProducts(); + await withRestApi.deleteAllCoupons(); await clearLocalStorage(); await setBrowserViewport( 'large' ); } ); diff --git a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js index f56ad8d4133..006cf8ace74 100644 --- a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js +++ b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js @@ -19,17 +19,19 @@ const { const runOnboardingFlowTest = () => { describe('Store owner can go through store Onboarding', () => { - it( 'can reset onboarding to default settings', async () => { - await withRestApi.resetOnboarding(); - }); + if ( process.env.E2E_RETEST == '1' ) { + it('can reset onboarding to default settings', async () => { + await withRestApi.resetOnboarding(); + }); - it( 'can reset shipping zones to default settings', async () => { - await withRestApi.deleteAllShippingZones(); - }); + it('can reset shipping zones to default settings', async () => { + await withRestApi.deleteAllShippingZones(); + }); - it( 'can reset allow tracking to default settings', async () => { - await withRestApi.resetAllowTracking(); - }); + it('can reset allow tracking to default settings', async () => { + await withRestApi.resetAllowTracking(); + }); + } it('can start and complete onboarding when visiting the site for the first time.', async () => { await merchant.runSetupWizard(); @@ -46,16 +48,17 @@ const runTaskListTest = () => { }); // Query for all tasks on the list const taskListItems = await page.$$('.woocommerce-list__item-title'); - expect(taskListItems).toHaveLength(6); + expect(taskListItems.length).toBeInRange( 5, 6 ); - const [ setupTaskListItem ] = await page.$x( '//div[contains(text(),"Set up shipping")]' ); - await Promise.all([ + // Work around for https://github.com/woocommerce/woocommerce-admin/issues/6761 + if ( taskListItems.length == 6 ) { // Click on "Set up shipping" task to move to the next step - setupTaskListItem.click(), - - // Wait for shipping setup section to load - page.waitForNavigation({waitUntil: 'networkidle0'}), - ]); + const [ setupTaskListItem ] = await page.$x( '//div[contains(text(),"Set up shipping")]' ); + await setupTaskListItem.click(); + } else { + await merchant.openSettings( 'shipping' ); + } + await page.waitForNavigation({waitUntil: 'networkidle0'}); // Wait for "Proceed" button to become active await page.waitForSelector('button.is-primary:not(:disabled)'); diff --git a/tests/e2e/utils/src/flows/constants.js b/tests/e2e/utils/src/flows/constants.js index bcf4d6b3419..0d68dd5f1ce 100644 --- a/tests/e2e/utils/src/flows/constants.js +++ b/tests/e2e/utils/src/flows/constants.js @@ -2,31 +2,53 @@ * External dependencies */ const config = require( 'config' ); - const baseUrl = config.get( 'url' ); +/** + * WordPress core dashboard pages. + * @type {string} + */ export const WP_ADMIN_LOGIN = baseUrl + 'wp-login.php'; -export const WP_ADMIN_DASHBOARD = baseUrl + 'wp-admin'; -export const WP_ADMIN_PLUGINS = baseUrl + 'wp-admin/plugins.php'; -export const WP_ADMIN_SETUP_WIZARD = baseUrl + 'wp-admin/admin.php?page=wc-admin'; -export const WP_ADMIN_ALL_ORDERS_VIEW = baseUrl + 'wp-admin/edit.php?post_type=shop_order'; -export const WP_ADMIN_ALL_PRODUCTS_VIEW = baseUrl + 'wp-admin/edit.php?post_type=product'; -export const WP_ADMIN_NEW_COUPON = baseUrl + 'wp-admin/post-new.php?post_type=shop_coupon'; -export const WP_ADMIN_NEW_ORDER = baseUrl + 'wp-admin/post-new.php?post_type=shop_order'; -export const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=product'; -export const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab='; -export const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php'; -export const WP_ADMIN_NEW_SHIPPING_ZONE = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=shipping&zone_id=new'; -export const WP_ADMIN_ANALYTICS_PAGES = baseUrl + 'wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2F'; -export const WP_ADMIN_ALL_USERS_VIEW = baseUrl + 'wp-admin/users.php'; - +export const WP_ADMIN_DASHBOARD = baseUrl + 'wp-admin/'; +export const WP_ADMIN_PLUGINS = WP_ADMIN_DASHBOARD + 'plugins.php'; +export const WP_ADMIN_PERMALINK_SETTINGS = WP_ADMIN_DASHBOARD + 'options-permalink.php'; +export const WP_ADMIN_ALL_USERS_VIEW = WP_ADMIN_DASHBOARD + 'users.php'; +/** + * WooCommerce core post type pages. + * @type {string} + */ +export const WP_ADMIN_POST_TYPE = WP_ADMIN_DASHBOARD + 'edit.php?post_type='; +export const WP_ADMIN_NEW_POST_TYPE = WP_ADMIN_DASHBOARD + 'post-new.php?post_type='; +export const WP_ADMIN_ALL_COUPONS_VIEW = WP_ADMIN_POST_TYPE + 'shop_coupon'; +export const WP_ADMIN_NEW_COUPON = WP_ADMIN_NEW_POST_TYPE + 'shop_coupon'; +export const WP_ADMIN_ALL_ORDERS_VIEW = WP_ADMIN_POST_TYPE + 'shop_order'; +export const WP_ADMIN_NEW_ORDER = WP_ADMIN_NEW_POST_TYPE + 'shop_order'; +export const WP_ADMIN_ALL_PRODUCTS_VIEW = WP_ADMIN_POST_TYPE + 'product'; +export const WP_ADMIN_NEW_PRODUCT = WP_ADMIN_NEW_POST_TYPE + 'product'; +/** + * WooCommerce settings pages. + * @type {string} + */ +export const WP_ADMIN_PLUGIN_PAGE = WP_ADMIN_DASHBOARD + 'admin.php?page='; +export const WP_ADMIN_WC_HOME = WP_ADMIN_PLUGIN_PAGE + 'wc-admin'; +export const WP_ADMIN_SETUP_WIZARD = WP_ADMIN_WC_HOME + '&path=%2Fsetup-wizard'; +export const WP_ADMIN_ANALYTICS_PAGES = WP_ADMIN_WC_HOME + '&path=%2Fanalytics%2F'; +export const WP_ADMIN_WC_SETTINGS = WP_ADMIN_PLUGIN_PAGE + 'wc-settings&tab='; +export const WP_ADMIN_NEW_SHIPPING_ZONE = WP_ADMIN_WC_SETTINGS + 'shipping&zone_id=new'; +/** + * Shop pages. + * @type {string} + */ export const SHOP_PAGE = baseUrl + 'shop'; export const SHOP_PRODUCT_PAGE = baseUrl + '?p='; export const SHOP_CART_PAGE = baseUrl + 'cart'; export const SHOP_CHECKOUT_PAGE = baseUrl + 'checkout/'; export const SHOP_MY_ACCOUNT_PAGE = baseUrl + 'my-account/'; - -export const MY_ACCOUNT_ORDERS = baseUrl + 'my-account/orders'; -export const MY_ACCOUNT_DOWNLOADS = baseUrl + 'my-account/downloads'; -export const MY_ACCOUNT_ADDRESSES = baseUrl + 'my-account/edit-address'; -export const MY_ACCOUNT_ACCOUNT_DETAILS = baseUrl + 'my-account/edit-account'; +/** + * Customer account pages. + * @type {string} + */ +export const MY_ACCOUNT_ORDERS = SHOP_MY_ACCOUNT_PAGE + 'orders'; +export const MY_ACCOUNT_DOWNLOADS = SHOP_MY_ACCOUNT_PAGE + 'downloads'; +export const MY_ACCOUNT_ADDRESSES = SHOP_MY_ACCOUNT_PAGE + 'edit-address'; +export const MY_ACCOUNT_ACCOUNT_DETAILS = SHOP_MY_ACCOUNT_PAGE + 'edit-account'; diff --git a/tests/e2e/utils/src/flows/merchant.js b/tests/e2e/utils/src/flows/merchant.js index d8c4c7ad390..55904df2611 100644 --- a/tests/e2e/utils/src/flows/merchant.js +++ b/tests/e2e/utils/src/flows/merchant.js @@ -1,6 +1,8 @@ /** * External dependencies */ +import {WP_ADMIN_WC_HOME} from "./constants"; + const config = require( 'config' ); /** @@ -119,7 +121,8 @@ const merchant = { }, runSetupWizard: async () => { - await page.goto( WP_ADMIN_SETUP_WIZARD, { + const setupWizard = process.env.E2E_RETEST == '1' ? WP_ADMIN_SETUP_WIZARD : WP_ADMIN_WC_HOME; + await page.goto( setupWizard, { waitUntil: 'networkidle0', } ); }, diff --git a/tests/e2e/utils/src/flows/with-rest-api.js b/tests/e2e/utils/src/flows/with-rest-api.js index 680fe3e8868..d9a4baadc77 100644 --- a/tests/e2e/utils/src/flows/with-rest-api.js +++ b/tests/e2e/utils/src/flows/with-rest-api.js @@ -1,10 +1,35 @@ import factories from '../factories'; -import { Setting } from '@woocommerce/api'; +import {Coupon, Setting, SimpleProduct} from '@woocommerce/api'; const client = factories.api.withDefaultPermalinks; const onboardingProfileEndpoint = '/wc-admin/onboarding/profile'; const shippingZoneEndpoint = '/wc/v3/shipping/zones'; +/** + * Utility function to delete all merchant created data store objects. + * + * @param repository + * @param defaultObjectId + * @returns {Promise} + */ +const deleteAllRepositoryObjects = async ( repository, defaultObjectId = null ) => { + let objects; + const minimum = defaultObjectId == null ? 0 : 1; + + objects = await repository.list(); + + while ( objects.length > minimum ) { + for (let o = 0; o < objects.length; o++ ) { + // Skip default data store object + if ( objects[ o ].id == defaultObjectId ) { + continue; + } + await repository.delete( objects[ o ].id ); + } + objects = await repository.list(); + } +}; + /** * Utility functions that use the REST API to process the requested function. */ @@ -31,6 +56,29 @@ export const withRestApi = { const response = await client.put( onboardingProfileEndpoint, onboardingReset ); expect( response.statusCode ).toEqual( 200 ); }, + /** + * Use api package to delete coupons. + * + * @return {Promise} Promise resolving once coupons have been deleted. + */ + deleteAllCoupons: async () => { + const repository = Coupon.restRepository( client ); + await deleteAllRepositoryObjects( repository ); + }, + /** + * Use api package to delete products. + * + * @return {Promise} Promise resolving once products have been deleted. + */ + deleteAllProducts: async () => { + const repository = SimpleProduct.restRepository( client ); + await deleteAllRepositoryObjects( repository ); + }, + /** + * Use api package to delete shipping zones. + * + * @return {Promise} Promise resolving once shipping zones have been deleted. + */ deleteAllShippingZones: async () => { const shippingZones = await client.get( shippingZoneEndpoint ); if ( shippingZones.data && shippingZones.data.length ) { From 4732a09b2395ad1861952d70de2121d36d902565 Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Wed, 7 Apr 2021 23:06:00 -0300 Subject: [PATCH 06/41] minor fixes from visual diff --- tests/e2e/api/src/models/index.ts | 1 - .../specs/activate-and-setup/onboarding-tasklist.test.js | 2 +- tests/e2e/utils/src/flows/merchant.js | 3 +-- tests/e2e/utils/src/flows/with-rest-api.js | 1 - 4 files changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/e2e/api/src/models/index.ts b/tests/e2e/api/src/models/index.ts index c29fdce7188..13ce569f196 100644 --- a/tests/e2e/api/src/models/index.ts +++ b/tests/e2e/api/src/models/index.ts @@ -3,4 +3,3 @@ export * from './model'; export * from './settings'; export * from './shared-types'; export * from './coupons'; -//export * from './orders'; diff --git a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js index 006cf8ace74..a87d49195fd 100644 --- a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js +++ b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js @@ -56,7 +56,7 @@ const runTaskListTest = () => { const [ setupTaskListItem ] = await page.$x( '//div[contains(text(),"Set up shipping")]' ); await setupTaskListItem.click(); } else { - await merchant.openSettings( 'shipping' ); + await merchant.openNewShipping(); } await page.waitForNavigation({waitUntil: 'networkidle0'}); diff --git a/tests/e2e/utils/src/flows/merchant.js b/tests/e2e/utils/src/flows/merchant.js index 55904df2611..32756b6d02e 100644 --- a/tests/e2e/utils/src/flows/merchant.js +++ b/tests/e2e/utils/src/flows/merchant.js @@ -1,8 +1,6 @@ /** * External dependencies */ -import {WP_ADMIN_WC_HOME} from "./constants"; - const config = require( 'config' ); /** @@ -20,6 +18,7 @@ const { WP_ADMIN_PERMALINK_SETTINGS, WP_ADMIN_PLUGINS, WP_ADMIN_SETUP_WIZARD, + WP_ADMIN_WC_HOME, WP_ADMIN_WC_SETTINGS, WP_ADMIN_NEW_SHIPPING_ZONE, WP_ADMIN_ANALYTICS_PAGES, diff --git a/tests/e2e/utils/src/flows/with-rest-api.js b/tests/e2e/utils/src/flows/with-rest-api.js index d9a4baadc77..492ae662881 100644 --- a/tests/e2e/utils/src/flows/with-rest-api.js +++ b/tests/e2e/utils/src/flows/with-rest-api.js @@ -17,7 +17,6 @@ const deleteAllRepositoryObjects = async ( repository, defaultObjectId = null ) const minimum = defaultObjectId == null ? 0 : 1; objects = await repository.list(); - while ( objects.length > minimum ) { for (let o = 0; o < objects.length; o++ ) { // Skip default data store object From ca4d690c5cd07eeefc29a6ab5e3392bad9de9d96 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 09:19:47 +0200 Subject: [PATCH 07/41] Try with 45s timeout --- tests/e2e/env/bin/e2e-test-integration.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/e2e/env/bin/e2e-test-integration.js b/tests/e2e/env/bin/e2e-test-integration.js index 46d457d974b..3cdb11bde66 100755 --- a/tests/e2e/env/bin/e2e-test-integration.js +++ b/tests/e2e/env/bin/e2e-test-integration.js @@ -40,7 +40,7 @@ let testEnvVars = { NODE_ENV: 'test-e2e', NODE_CONFIG_DIR: nodeConfigDirs.join( ':' ), node_config_dev: program.dev ? 'yes' : 'no', - jest_test_timeout: program.dev ? 120000 : 30000, + jest_test_timeout: program.dev ? 120000 : 45000, }; if ( ! JEST_PUPPETEER_CONFIG ) { From 615bb66d412a7d3a6c0bc4121eb717f22dcbb434 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 10:09:12 +0200 Subject: [PATCH 08/41] Revert timeout back and split test --- .../front-end-cart-calculate-shipping.test.js | 27 ------------------- tests/e2e/env/bin/e2e-test-integration.js | 2 +- 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 59c980a620c..6a8aa527e88 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -114,33 +114,6 @@ const runCartCalculateShippingTest = () => { await uiUnblocked(); await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); }); - - it('should show correct total cart price with 2 products and flat rate', async () => { - await shopper.goToShop(); - await shopper.addToCartFromShopPage(secondProductName); - await shopper.goToCart(); - - await shopper.setCartQuantity(firstProductName, 1); - await expect(page).toClick('button', {text: 'Update cart'}); - await uiUnblocked(); - await page.waitForSelector('.order-total'); - await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); - await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); - }); - - it('should show correct total cart price with 2 products without flat rate', async () => { - await page.reload(); - - // Set shipping country to Spain - await expect(page).toClick('a.shipping-calculator-button'); - await expect(page).toClick('#select2-calc_shipping_country-container'); - await selectOptionInSelect2('Spain'); - await expect(page).toClick('button[name="calc_shipping"]'); - - // Verify shipping costs - await page.waitForSelector('.order-total'); - await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); - }); }); }; diff --git a/tests/e2e/env/bin/e2e-test-integration.js b/tests/e2e/env/bin/e2e-test-integration.js index 3cdb11bde66..46d457d974b 100755 --- a/tests/e2e/env/bin/e2e-test-integration.js +++ b/tests/e2e/env/bin/e2e-test-integration.js @@ -40,7 +40,7 @@ let testEnvVars = { NODE_ENV: 'test-e2e', NODE_CONFIG_DIR: nodeConfigDirs.join( ':' ), node_config_dev: program.dev ? 'yes' : 'no', - jest_test_timeout: program.dev ? 120000 : 45000, + jest_test_timeout: program.dev ? 120000 : 30000, }; if ( ! JEST_PUPPETEER_CONFIG ) { From 6574db5c2c48a6e7bf4598b239c61aea7f3f269c Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 10:43:07 +0200 Subject: [PATCH 09/41] Add additional test scenarios --- .../front-end-cart-calculate-shipping.test.js | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 6a8aa527e88..f2885988bcf 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -55,7 +55,9 @@ const runCartCalculateShippingTest = () => { } catch (error) { // Prevent an error here causing the test to fail. } + }); + it('can prepare the shipping zones for the test', async () => { // Add a new shipping zone Germany with Free shipping await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); @@ -72,8 +74,6 @@ const runCartCalculateShippingTest = () => { await page.select('select[name="add_method_id"]', 'local_pickup'); await page.click('button#btn-ok'); await page.waitForSelector('#zone_locations'); - - await merchant.logout(); }); it('allows customer to calculate Free Shipping if in Germany', async () => { @@ -114,6 +114,33 @@ const runCartCalculateShippingTest = () => { await uiUnblocked(); await expect(page).toMatchElement('.order-total .amount', {text: `$${fourProductPriceWithFlatRate}`}); }); + + it('should show correct total cart price with 2 products and flat rate', async () => { + await shopper.goToShop(); + await shopper.addToCartFromShopPage(secondProductName); + await shopper.goToCart(); + + await shopper.setCartQuantity(firstProductName, 1); + await expect(page).toClick('button', {text: 'Update cart'}); + await uiUnblocked(); + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.shipping .amount', {text: '$5.00'}); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPriceWithFlatRate}`}); + }); + + it('should show correct total cart price with 2 products without flat rate', async () => { + await page.reload(); + + // Set shipping country to Spain + await expect(page).toClick('a.shipping-calculator-button'); + await expect(page).toClick('#select2-calc_shipping_country-container'); + await selectOptionInSelect2('Spain'); + await expect(page).toClick('button[name="calc_shipping"]'); + + // Verify shipping costs + await page.waitForSelector('.order-total'); + await expect(page).toMatchElement('.order-total .amount', {text: `$${twoProductsPrice}`}); + }); }); }; From b195e354a22ad8aa4c4a53f281df7749728507f8 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 11:44:54 +0200 Subject: [PATCH 10/41] Make test more granular --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index f2885988bcf..f5fe1fcff2d 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -33,9 +33,12 @@ const runCartCalculateShippingTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(firstProductName); + await merchant.openSettings('general'); await createSimpleProduct(secondProductName, secondProductPrice); await merchant.openSettings('shipping'); + }); + it('can remove the existing shippings if they are present', async () => { // Delete existing shipping zones. try { let zone = await page.$( '.wc-shipping-zone-delete' ); From 7a1ba36fc9d775c05b797cd37abf2a834607add1 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 12:41:02 +0200 Subject: [PATCH 11/41] Added new component and updated tests --- .../wp-admin-settings-shipping-zones.test.js | 25 ++-------------- .../front-end-cart-calculate-shipping.test.js | 28 ++--------------- tests/e2e/utils/CHANGELOG.md | 1 + tests/e2e/utils/README.md | 1 + tests/e2e/utils/src/components.js | 30 ++++++++++++++++++- 5 files changed, 35 insertions(+), 50 deletions(-) diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js index e7da3ffe377..6e5b8fb51c9 100644 --- a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js +++ b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js @@ -10,8 +10,7 @@ const { addShippingZoneAndMethod, clearAndFillInput, selectOptionInSelect2, - evalAndClick, - uiUnblocked, + deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); const config = require( 'config' ); @@ -28,27 +27,7 @@ const runAddNewShippingZoneTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(); - await merchant.openSettings('shipping'); - - // Delete existing shipping zones. - try { - let zone = await page.$( '.wc-shipping-zone-delete' ); - if ( zone ) { - // WP action links aren't clickable because they are hidden with a left=-9999 style. - await page.evaluate(() => { - document.querySelector('.wc-shipping-zone-name .row-actions') - .style - .left = '0'; - }); - while ( zone ) { - await evalAndClick( '.wc-shipping-zone-delete' ); - await uiUnblocked(); - zone = await page.$( '.wc-shipping-zone-delete' ); - } - } - } catch (error) { - // Prevent an error here causing the test to fail. - } + await deleteAllShippingZones(); }); it('add shipping zone for San Francisco with free Local pickup', async () => { diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index f5fe1fcff2d..aa9baaee694 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -8,7 +8,7 @@ const { createSimpleProduct, addShippingZoneAndMethod, clearAndFillInput, - evalAndClick, + deleteAllShippingZones, uiUnblocked, selectOptionInSelect2, } = require( '@woocommerce/e2e-utils' ); @@ -33,33 +33,9 @@ const runCartCalculateShippingTest = () => { beforeAll(async () => { await merchant.login(); await createSimpleProduct(firstProductName); - await merchant.openSettings('general'); await createSimpleProduct(secondProductName, secondProductPrice); - await merchant.openSettings('shipping'); + await deleteAllShippingZones(); }); - - it('can remove the existing shippings if they are present', async () => { - // Delete existing shipping zones. - try { - let zone = await page.$( '.wc-shipping-zone-delete' ); - if ( zone ) { - // WP action links aren't clickable because they are hidden with a left=-9999 style. - await page.evaluate(() => { - document.querySelector('.wc-shipping-zone-name .row-actions') - .style - .left = '0'; - }); - while ( zone ) { - await evalAndClick( '.wc-shipping-zone-delete' ); - await uiUnblocked(); - zone = await page.$( '.wc-shipping-zone-delete' ); - } - } - } catch (error) { - // Prevent an error here causing the test to fail. - } - }); - it('can prepare the shipping zones for the test', async () => { // Add a new shipping zone Germany with Free shipping await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); diff --git a/tests/e2e/utils/CHANGELOG.md b/tests/e2e/utils/CHANGELOG.md index 07e70e130fe..561ee7f4105 100644 --- a/tests/e2e/utils/CHANGELOG.md +++ b/tests/e2e/utils/CHANGELOG.md @@ -1,6 +1,7 @@ # Unreleased - `emptyCart()` Shopper flow helper that empties the cart +- `deleteAllShippingZones` Delete all the existing shipping zones # 0.1.4 diff --git a/tests/e2e/utils/README.md b/tests/e2e/utils/README.md index f6b5c662e4f..bffe722c41c 100644 --- a/tests/e2e/utils/README.md +++ b/tests/e2e/utils/README.md @@ -124,6 +124,7 @@ describe( 'Cart page', () => { | `removeCoupon` | | helper method that removes a single coupon within cart or checkout | | `selectOrderAction` | `action` | Helper method to select an order action in the `Order Actions` postbox | | `clickUpdateOrder` | `noticeText`, `waitForSave` | Helper method to click the Update button on the order details page | +| `deleteAllShippingZones` | | Delete all the existing shipping zones | ### Test Utilities diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index c449622937b..addeed491ff 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -12,7 +12,8 @@ import { verifyCheckboxIsUnset, selectOptionInSelect2, setCheckbox, - unsetCheckbox + unsetCheckbox, + evalAndClick, } from './page-utils'; import factories from './factories'; @@ -538,6 +539,32 @@ const deleteAllEmailLogs = async () => { } }; +/** + * Delete all the existing shipping zones. + */ +const deleteAllShippingZones = async () => { + await merchant.openSettings('shipping'); + // Delete existing shipping zones. + try { + let zone = await page.$( '.wc-shipping-zone-delete' ); + if ( zone ) { + // WP action links aren't clickable because they are hidden with a left=-9999 style. + await page.evaluate(() => { + document.querySelector('.wc-shipping-zone-name .row-actions') + .style + .left = '0'; + }); + while ( zone ) { + await evalAndClick( '.wc-shipping-zone-delete' ); + await uiUnblocked(); + zone = await page.$( '.wc-shipping-zone-delete' ); + }; + }; + } catch (error) { + // Prevent an error here causing the test to fail. + }; +}; + export { completeOnboardingWizard, createSimpleProduct, @@ -551,4 +578,5 @@ export { createSimpleProductWithCategory, clickUpdateOrder, deleteAllEmailLogs, + deleteAllShippingZones, }; From 4fed8f8dab92f1e901009d8ade607413b65e4e01 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 15:09:59 +0200 Subject: [PATCH 12/41] Add missing jest/global --- .../shopper/front-end-cart-calculate-shipping.test.js | 9 +++++++++ tests/e2e/utils/src/components.js | 1 + 2 files changed, 10 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index aa9baaee694..ae32e9bc1d0 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -13,6 +13,15 @@ const { selectOptionInSelect2, } = require( '@woocommerce/e2e-utils' ); +/** + * External dependencies + */ + const { + it, + describe, + beforeAll, +} = require( '@jest/globals' ); + const config = require( 'config' ); const firstProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; const secondProductPrice = '4.99'; diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index addeed491ff..7e52fa090af 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -544,6 +544,7 @@ const deleteAllEmailLogs = async () => { */ const deleteAllShippingZones = async () => { await merchant.openSettings('shipping'); + // Delete existing shipping zones. try { let zone = await page.$( '.wc-shipping-zone-delete' ); From a9ce07c02040bcbff8856f58b447a7333047395f Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 17:11:29 +0200 Subject: [PATCH 13/41] Update test --- .../merchant/wp-admin-settings-shipping-zones.test.js | 9 +++++++++ .../shopper/front-end-cart-calculate-shipping.test.js | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js index 6e5b8fb51c9..c6bae31d94f 100644 --- a/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js +++ b/tests/e2e/core-tests/specs/merchant/wp-admin-settings-shipping-zones.test.js @@ -13,6 +13,15 @@ const { deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); +/** + * External dependencies + */ +const { + it, + describe, + beforeAll, +} = require( '@jest/globals' ); + const config = require( 'config' ); const simpleProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; const simpleProductName = config.get( 'products.simple.name' ); diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index ae32e9bc1d0..83d2c05a3e3 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -1,4 +1,5 @@ /* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */ + /** * Internal dependencies */ @@ -16,7 +17,7 @@ const { /** * External dependencies */ - const { +const { it, describe, beforeAll, From d4d93f9239bac14ba73122eceec1e6e217d866df Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 8 Apr 2021 18:18:59 +0200 Subject: [PATCH 14/41] Remove shipping method deletion --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 83d2c05a3e3..879f5f17f5d 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -9,7 +9,6 @@ const { createSimpleProduct, addShippingZoneAndMethod, clearAndFillInput, - deleteAllShippingZones, uiUnblocked, selectOptionInSelect2, } = require( '@woocommerce/e2e-utils' ); @@ -44,9 +43,8 @@ const runCartCalculateShippingTest = () => { await merchant.login(); await createSimpleProduct(firstProductName); await createSimpleProduct(secondProductName, secondProductPrice); - await deleteAllShippingZones(); - }); - it('can prepare the shipping zones for the test', async () => { + await merchant.openNewShipping(); + // Add a new shipping zone Germany with Free shipping await addShippingZoneAndMethod(shippingZoneNameDE, shippingCountryDE, ' ', 'free_shipping'); From fcbbb12a8a4055e61ad0c3cf44d6a82edaa7a1ac Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Fri, 9 Apr 2021 16:15:00 -0300 Subject: [PATCH 15/41] add retry support --- tests/e2e/config/jest.setup.js | 17 ------ .../onboarding-tasklist.test.js | 33 +++++++---- .../specs/activate-and-setup/setup.test.js | 1 - .../front-end-checkout-create-account.test.js | 9 ++- ...ront-end-my-account-create-account.test.js | 10 +++- tests/e2e/env/CHANGELOG.md | 8 +++ tests/e2e/env/src/setup/jest.setup.js | 17 ++++++ tests/e2e/utils/src/components.js | 35 ++++++------ tests/e2e/utils/src/flows/constants.js | 6 ++ tests/e2e/utils/src/flows/with-rest-api.js | 55 ++++++++++++++++--- 10 files changed, 130 insertions(+), 61 deletions(-) diff --git a/tests/e2e/config/jest.setup.js b/tests/e2e/config/jest.setup.js index d1e02606fbf..b879aca4516 100644 --- a/tests/e2e/config/jest.setup.js +++ b/tests/e2e/config/jest.setup.js @@ -9,23 +9,6 @@ import { const { merchant } = require( '@woocommerce/e2e-utils' ); -/** - * Add an expect range matcher - * @see https://jestjs.io/docs/expect#expectextendmatchers - */ -expect.extend({ - toBeInRange: function (received, floor, ceiling) { - const pass = received >= floor && received <= ceiling; - const condition = pass ? 'not to be' : 'to be'; - - return { - message: () => - `expected ${received} ${condition} within range ${floor} - ${ceiling}`, - pass, - }; - }, -}); - /** * Navigates to the post listing screen and bulk-trashes any posts which exist. * diff --git a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js index a87d49195fd..04b7776b60c 100644 --- a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js +++ b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js @@ -7,19 +7,25 @@ const { merchant, completeOnboardingWizard, withRestApi, + addShippingZoneAndMethod, + IS_RETEST_MODE, } = require( '@woocommerce/e2e-utils' ); /** * External dependencies */ +const config = require( 'config' ); const { it, describe, + beforeAll } = require( '@jest/globals' ); +const shippingZoneNameUS = config.get( 'addresses.customer.shipping.country' ); + const runOnboardingFlowTest = () => { describe('Store owner can go through store Onboarding', () => { - if ( process.env.E2E_RETEST == '1' ) { + if ( IS_RETEST_MODE ) { it('can reset onboarding to default settings', async () => { await withRestApi.resetOnboarding(); }); @@ -28,8 +34,10 @@ const runOnboardingFlowTest = () => { await withRestApi.deleteAllShippingZones(); }); - it('can reset allow tracking to default settings', async () => { - await withRestApi.resetAllowTracking(); + it('can reset to default settings', async () => { + await withRestApi.resetSettingsGroupToDefault('general'); + await withRestApi.resetSettingsGroupToDefault('products'); + await withRestApi.resetSettingsGroupToDefault('tax'); }); } @@ -55,18 +63,19 @@ const runTaskListTest = () => { // Click on "Set up shipping" task to move to the next step const [ setupTaskListItem ] = await page.$x( '//div[contains(text(),"Set up shipping")]' ); await setupTaskListItem.click(); + await page.waitForNavigation({waitUntil: 'networkidle0'}); + + // Wait for "Proceed" button to become active + await page.waitForSelector('button.is-primary:not(:disabled)'); + await page.waitFor(3000); + + // Click on "Proceed" button to save shipping settings + await page.click('button.is-primary'); + await page.waitFor(3000); } else { await merchant.openNewShipping(); + await addShippingZoneAndMethod(shippingZoneNameUS); } - await page.waitForNavigation({waitUntil: 'networkidle0'}); - - // Wait for "Proceed" button to become active - await page.waitForSelector('button.is-primary:not(:disabled)'); - await page.waitFor(3000); - - // Click on "Proceed" button to save shipping settings - await page.click('button.is-primary'); - await page.waitFor(3000); }); }); }; diff --git a/tests/e2e/core-tests/specs/activate-and-setup/setup.test.js b/tests/e2e/core-tests/specs/activate-and-setup/setup.test.js index 1af767c7e03..6ebc3fe961e 100644 --- a/tests/e2e/core-tests/specs/activate-and-setup/setup.test.js +++ b/tests/e2e/core-tests/specs/activate-and-setup/setup.test.js @@ -6,7 +6,6 @@ const { HTTPClientFactory } = require( '@woocommerce/api' ); const { it, describe, - beforeAll, } = require( '@jest/globals' ); /** diff --git a/tests/e2e/core-tests/specs/shopper/front-end-checkout-create-account.test.js b/tests/e2e/core-tests/specs/shopper/front-end-checkout-create-account.test.js index f26e57fad85..f173b1f8b60 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-checkout-create-account.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-checkout-create-account.test.js @@ -9,6 +9,7 @@ uiUnblocked, setCheckbox, settingsPageSaveChanges, + withRestApi, } = require( '@woocommerce/e2e-utils' ); /** @@ -22,14 +23,16 @@ const { const config = require( 'config' ); const simpleProductName = config.get( 'products.simple.name' ); +const customerBilling = config.get( 'addresses.customer.billing' ); const runCheckoutCreateAccountTest = () => { describe('Shopper Checkout Create Account', () => { beforeAll(async () => { - await merchant.login(); await createSimpleProduct(); + await withRestApi.deleteCustomerByEmail( customerBilling.email ); // Set checkbox for creating an account during checkout + await merchant.login(); await merchant.openSettings('account'); await setCheckbox('#woocommerce_enable_signup_and_login_from_checkout'); await settingsPageSaveChanges(); @@ -44,7 +47,7 @@ const runCheckoutCreateAccountTest = () => { it('can create an account during checkout', async () => { // Fill all the details for a new customer - await shopper.fillBillingDetails(config.get('addresses.customer.billing')); + await shopper.fillBillingDetails( customerBilling ); await uiUnblocked(); // Set checkbox for creating account during checkout @@ -58,7 +61,7 @@ const runCheckoutCreateAccountTest = () => { it('can verify that the customer has been created', async () => { await merchant.login(); await merchant.openAllUsersView(); - await expect(page).toMatchElement('td.email.column-email > a', {text: 'john.doe@example.com'}); + await expect(page).toMatchElement('td.email.column-email > a', { text: customerBilling.email }); }); }); }; diff --git a/tests/e2e/core-tests/specs/shopper/front-end-my-account-create-account.test.js b/tests/e2e/core-tests/specs/shopper/front-end-my-account-create-account.test.js index c48e9cd9e9f..c467ad029d4 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-my-account-create-account.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-my-account-create-account.test.js @@ -7,25 +7,29 @@ const { merchant, setCheckbox, settingsPageSaveChanges, + withRestApi, } = require( '@woocommerce/e2e-utils' ); +const customerEmailAddress = 'john.doe.test@example.com'; + const runMyAccountCreateAccountTest = () => { describe('Shopper My Account Create Account', () => { beforeAll(async () => { + await withRestApi.deleteCustomerByEmail( customerEmailAddress ); await merchant.login(); // Set checkbox in the settings to enable registration in my account await merchant.openSettings('account'); await setCheckbox('#woocommerce_enable_myaccount_registration'); await settingsPageSaveChanges(); - + await merchant.logout(); }); it('can create a new account via my account', async () => { await shopper.gotoMyAccount(); await page.waitForSelector('.woocommerce-form-register'); - await expect(page).toFill('input#reg_email', 'john.doe.test@example.com'); + await expect(page).toFill('input#reg_email', customerEmailAddress); await expect(page).toClick('button[name="register"]'); await page.waitForNavigation({waitUntil: 'networkidle0'}); await expect(page).toMatchElement('h1', 'My account'); @@ -33,7 +37,7 @@ const runMyAccountCreateAccountTest = () => { // Verify user has been created successfully await merchant.login(); await merchant.openAllUsersView(); - await expect(page).toMatchElement('td.email.column-email > a', {text: 'john.doe.test@example.com'}); + await expect(page).toMatchElement('td.email.column-email > a', {text: customerEmailAddress}); }); }); }; diff --git a/tests/e2e/env/CHANGELOG.md b/tests/e2e/env/CHANGELOG.md index 4b0fa6d81e5..7d775b20294 100644 --- a/tests/e2e/env/CHANGELOG.md +++ b/tests/e2e/env/CHANGELOG.md @@ -1,5 +1,13 @@ # Unreleased +## Added + +- `toBeInRange` expect numeric range matcher +- constants + - `WP_ADMIN_POST_TYPE` + - `WP_ADMIN_NEW_POST_TYPE` + - `WP_ADMIN_ALL_COUPONS_VIEW` + - `WP_ADMIN_WC_HOME` # 0.2.1 diff --git a/tests/e2e/env/src/setup/jest.setup.js b/tests/e2e/env/src/setup/jest.setup.js index a312c46635e..2fca6769587 100644 --- a/tests/e2e/env/src/setup/jest.setup.js +++ b/tests/e2e/env/src/setup/jest.setup.js @@ -101,6 +101,23 @@ function removePageEvents() { } ); } +/** + * Add an expect range matcher. + * @see https://jestjs.io/docs/expect#expectextendmatchers + */ +expect.extend({ + toBeInRange: function (received, floor, ceiling) { + const pass = received >= floor && received <= ceiling; + const condition = pass ? 'not to be' : 'to be'; + + return { + message: () => + `expected ${received} ${condition} within range ${floor} - ${ceiling}`, + pass, + }; + }, +}); + /** * Adds a page event handler to emit uncaught exception to process if one of * the observed console logging types is encountered. diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index ab471990883..8b66ae0ef7c 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -5,7 +5,7 @@ /** * Internal dependencies */ -import { merchant } from './flows'; +import { merchant, IS_RETEST_MODE } from './flows'; import { clickTab, uiUnblocked, @@ -68,7 +68,7 @@ const completeOnboardingWizard = async () => { await expect( page ).toFill( '.woocommerce-select-control__control-input', config.get( 'addresses.admin.store.countryandstate' ) ); // Fill the city where the store is located - await clearAndFillInput( '#inspector-text-control-2', config.get( 'addresses.admin.store.city' ) ); + await expect( page ).toFill( '#inspector-text-control-2', config.get( 'addresses.admin.store.city' ) ); // Fill postcode of the store await expect( page ).toFill( '#inspector-text-control-3', config.get( 'addresses.admin.store.postcode' ) ); @@ -82,23 +82,20 @@ const completeOnboardingWizard = async () => { // Click on "Continue" button to move to the next step await page.click( 'button.is-primary', { text: 'Continue' } ); - // Wait for usage tracking pop-up window to appear - await page.waitForSelector( '.components-modal__header-heading' ); - await expect( page ).toMatchElement( - '.components-modal__header-heading', { text: 'Build a better WooCommerce' } - ); + // Wait for usage tracking pop-up window to appear on a new site + if ( IS_RETEST_MODE ) { + await page.waitForSelector('.components-modal__header-heading'); + await expect(page).toMatchElement( + '.components-modal__header-heading', {text: 'Build a better WooCommerce'} + ); - // Query for "Continue" buttons - const continueButtons = await page.$$( 'button.is-primary' ); - expect( continueButtons ).toHaveLength( 2 ); + // Query for "Continue" buttons + const continueButtons = await page.$$( 'button.is-primary' ); + expect( continueButtons ).toHaveLength( 2 ); - await Promise.all( [ - // Click on "Continue" button of the usage pop-up window to move to the next step - continueButtons[1].click(), - - // Wait for "In which industry does the store operate?" section to load - page.waitForNavigation( { waitUntil: 'networkidle0' } ), - ] ); + await continueButtons[1].click(); + } + await page.waitForNavigation( { waitUntil: 'networkidle0' } ); // Industry section @@ -159,6 +156,10 @@ const completeOnboardingWizard = async () => { await waitAndClickPrimary(); // End of onboarding wizard + if ( process.env.E2E_RETEST == '1' ) { + // Home screen modal can't be reset via the rest api. + return; + } // Wait for homescreen welcome modal to appear await page.waitForSelector( '.woocommerce__welcome-modal__page-content__header' ); diff --git a/tests/e2e/utils/src/flows/constants.js b/tests/e2e/utils/src/flows/constants.js index 0d68dd5f1ce..58ad331e930 100644 --- a/tests/e2e/utils/src/flows/constants.js +++ b/tests/e2e/utils/src/flows/constants.js @@ -52,3 +52,9 @@ export const MY_ACCOUNT_ORDERS = SHOP_MY_ACCOUNT_PAGE + 'orders'; export const MY_ACCOUNT_DOWNLOADS = SHOP_MY_ACCOUNT_PAGE + 'downloads'; export const MY_ACCOUNT_ADDRESSES = SHOP_MY_ACCOUNT_PAGE + 'edit-address'; export const MY_ACCOUNT_ACCOUNT_DETAILS = SHOP_MY_ACCOUNT_PAGE + 'edit-account'; + +/** + * Test control flags. + * @type {boolean} + */ +export const IS_RETEST_MODE = process.env.E2E_RETEST == '1'; diff --git a/tests/e2e/utils/src/flows/with-rest-api.js b/tests/e2e/utils/src/flows/with-rest-api.js index 492ae662881..61afdc6e714 100644 --- a/tests/e2e/utils/src/flows/with-rest-api.js +++ b/tests/e2e/utils/src/flows/with-rest-api.js @@ -4,6 +4,7 @@ import {Coupon, Setting, SimpleProduct} from '@woocommerce/api'; const client = factories.api.withDefaultPermalinks; const onboardingProfileEndpoint = '/wc-admin/onboarding/profile'; const shippingZoneEndpoint = '/wc/v3/shipping/zones'; +const userEndpoint = '/wp/v2/users'; /** * Utility function to delete all merchant created data store objects. @@ -91,14 +92,52 @@ export const withRestApi = { } } }, - resetAllowTracking: async () => { - const settingsClient = Setting.restRepository( client ); - - const allowTracking = { - id: 'woocommerce_allow_tracking', - value: 'no' + deleteCustomerByEmail: async ( emailAddress ) => { + const query = { + search: emailAddress, + context: 'edit', }; - const response = await settingsClient.update( 'advanced', allowTracking.id, allowTracking ); - expect( response.value ).toBe( 'no' ); + const customers = await client.get( userEndpoint, query ); + + if ( customers.data && customers.data.length ) { + for ( let c = 0; c < customers.data.length; c++ ) { + const deleteUser = { + id: customers.data[c].id, + force: true, + reassign: 1, + } + await client.delete( userEndpoint + `/${ deleteUser.id }`, deleteUser ); + } + } + }, + /** + * Reset a settings group to default values except selects. + * @param settingsGroup + * @returns {Promise} + */ + resetSettingsGroupToDefault: async ( settingsGroup ) => { + const settingsClient = Setting.restRepository( client ); + const settings = await settingsClient.list( settingsGroup ); + if ( ! settings.length ) { + return; + } + + for ( let s = 0; s < settings.length; s++ ) { + // The rest api doesn't allow selects to be set to ''. + if ( settings[s].type == 'select' && settings[s].default == '' ) { + continue; + } + const defaultSetting = { + group_id: settingsGroup, + id: settings[s].id, + value: settings[s].default, + }; + + const response = await settingsClient.update( settingsGroup, defaultSetting.id, defaultSetting ); + // Multi-selects have a default '' but return an empty []. + if ( settings[s].type != 'multiselect' ) { + expect( response.value ).toBe( defaultSetting.value ); + } + } } }; From c94ddb880381e900877ca5ced8937a6971f93638 Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Fri, 9 Apr 2021 16:39:30 -0300 Subject: [PATCH 16/41] update package changelogs, minor fixes from full PR review --- tests/e2e/core-tests/CHANGELOG.md | 8 ++++++++ .../specs/activate-and-setup/onboarding-tasklist.test.js | 1 - tests/e2e/env/CHANGELOG.md | 5 ----- tests/e2e/utils/CHANGELOG.md | 9 +++++++++ tests/e2e/utils/src/components.js | 4 ++-- tests/e2e/utils/src/flows/merchant.js | 3 ++- tests/e2e/utils/src/flows/with-rest-api.js | 6 ++++++ 7 files changed, 27 insertions(+), 9 deletions(-) diff --git a/tests/e2e/core-tests/CHANGELOG.md b/tests/e2e/core-tests/CHANGELOG.md index bf220a9d338..bcba59aea11 100644 --- a/tests/e2e/core-tests/CHANGELOG.md +++ b/tests/e2e/core-tests/CHANGELOG.md @@ -1,5 +1,13 @@ # Unreleased +## Added + +- Support for re-running setup and shopper tests + +## Fixed + +- Checkout create account test would fail if configuration value `addresses.customer.billing.email` was not `john.doe@example.com` + # 0.1.3 ## Added diff --git a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js index 04b7776b60c..34ee3c04272 100644 --- a/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js +++ b/tests/e2e/core-tests/specs/activate-and-setup/onboarding-tasklist.test.js @@ -18,7 +18,6 @@ const config = require( 'config' ); const { it, describe, - beforeAll } = require( '@jest/globals' ); const shippingZoneNameUS = config.get( 'addresses.customer.shipping.country' ); diff --git a/tests/e2e/env/CHANGELOG.md b/tests/e2e/env/CHANGELOG.md index 7d775b20294..fa331747ea3 100644 --- a/tests/e2e/env/CHANGELOG.md +++ b/tests/e2e/env/CHANGELOG.md @@ -3,11 +3,6 @@ ## Added - `toBeInRange` expect numeric range matcher -- constants - - `WP_ADMIN_POST_TYPE` - - `WP_ADMIN_NEW_POST_TYPE` - - `WP_ADMIN_ALL_COUPONS_VIEW` - - `WP_ADMIN_WC_HOME` # 0.2.1 diff --git a/tests/e2e/utils/CHANGELOG.md b/tests/e2e/utils/CHANGELOG.md index 07e70e130fe..e1b9055658c 100644 --- a/tests/e2e/utils/CHANGELOG.md +++ b/tests/e2e/utils/CHANGELOG.md @@ -1,6 +1,15 @@ # Unreleased +## Added + - `emptyCart()` Shopper flow helper that empties the cart +- constants + - `WP_ADMIN_POST_TYPE` + - `WP_ADMIN_NEW_POST_TYPE` + - `WP_ADMIN_ALL_COUPONS_VIEW` + - `WP_ADMIN_WC_HOME` + - `IS_RETEST_MODE` +- `withRestApi` flow containing utility functions that manage data with the rest api # 0.1.4 diff --git a/tests/e2e/utils/src/components.js b/tests/e2e/utils/src/components.js index 8b66ae0ef7c..73bda6b7060 100644 --- a/tests/e2e/utils/src/components.js +++ b/tests/e2e/utils/src/components.js @@ -83,7 +83,7 @@ const completeOnboardingWizard = async () => { await page.click( 'button.is-primary', { text: 'Continue' } ); // Wait for usage tracking pop-up window to appear on a new site - if ( IS_RETEST_MODE ) { + if ( ! IS_RETEST_MODE ) { await page.waitForSelector('.components-modal__header-heading'); await expect(page).toMatchElement( '.components-modal__header-heading', {text: 'Build a better WooCommerce'} @@ -156,7 +156,7 @@ const completeOnboardingWizard = async () => { await waitAndClickPrimary(); // End of onboarding wizard - if ( process.env.E2E_RETEST == '1' ) { + if ( IS_RETEST_MODE ) { // Home screen modal can't be reset via the rest api. return; } diff --git a/tests/e2e/utils/src/flows/merchant.js b/tests/e2e/utils/src/flows/merchant.js index 32756b6d02e..97861cce98f 100644 --- a/tests/e2e/utils/src/flows/merchant.js +++ b/tests/e2e/utils/src/flows/merchant.js @@ -23,6 +23,7 @@ const { WP_ADMIN_NEW_SHIPPING_ZONE, WP_ADMIN_ANALYTICS_PAGES, WP_ADMIN_ALL_USERS_VIEW, + IS_RETEST_MODE, } = require( './constants' ); const baseUrl = config.get( 'url' ); @@ -120,7 +121,7 @@ const merchant = { }, runSetupWizard: async () => { - const setupWizard = process.env.E2E_RETEST == '1' ? WP_ADMIN_SETUP_WIZARD : WP_ADMIN_WC_HOME; + const setupWizard = IS_RETEST_MODE ? WP_ADMIN_SETUP_WIZARD : WP_ADMIN_WC_HOME; await page.goto( setupWizard, { waitUntil: 'networkidle0', } ); diff --git a/tests/e2e/utils/src/flows/with-rest-api.js b/tests/e2e/utils/src/flows/with-rest-api.js index 61afdc6e714..1deefb851bd 100644 --- a/tests/e2e/utils/src/flows/with-rest-api.js +++ b/tests/e2e/utils/src/flows/with-rest-api.js @@ -92,6 +92,12 @@ export const withRestApi = { } } }, + /** + * Delete a customer account by their email address if the user exists. + * + * @param emailAddress Customer user account email address. + * @returns {Promise} + */ deleteCustomerByEmail: async ( emailAddress ) => { const query = { search: emailAddress, From 6c7c420d257e62eacd8c37b2e32ee3f19be77972 Mon Sep 17 00:00:00 2001 From: roykho Date: Mon, 12 Apr 2021 09:28:30 -0700 Subject: [PATCH 17/41] Set US:CA as the default store location --- includes/admin/class-wc-admin-dashboard-setup.php | 2 +- .../admin/settings/class-wc-settings-general.php | 2 +- includes/wc-core-functions.php | 12 ++++++------ tests/legacy/unit-tests/countries/countries.php | 4 +++- 4 files changed, 11 insertions(+), 9 deletions(-) diff --git a/includes/admin/class-wc-admin-dashboard-setup.php b/includes/admin/class-wc-admin-dashboard-setup.php index 580bdc00b2e..4360241b37f 100644 --- a/includes/admin/class-wc-admin-dashboard-setup.php +++ b/includes/admin/class-wc-admin-dashboard-setup.php @@ -172,7 +172,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard_Setup', false ) ) : */ private function populate_payment_tasks() { $is_woo_payment_installed = is_plugin_active( 'woocommerce-payments/woocommerce-payments.php' ); - $country = explode( ':', get_option( 'woocommerce_default_country', '' ) )[0]; + $country = explode( ':', get_option( 'woocommerce_default_country', 'US:CA' ) )[0]; // woocommerce-payments requires its plugin activated and country must be US. if ( ! $is_woo_payment_installed || 'US' !== $country ) { diff --git a/includes/admin/settings/class-wc-settings-general.php b/includes/admin/settings/class-wc-settings-general.php index 8535dd7f956..28864828d0d 100644 --- a/includes/admin/settings/class-wc-settings-general.php +++ b/includes/admin/settings/class-wc-settings-general.php @@ -81,7 +81,7 @@ class WC_Settings_General extends WC_Settings_Page { 'title' => __( 'Country / State', 'woocommerce' ), 'desc' => __( 'The country and state or province, if any, in which your business is located.', 'woocommerce' ), 'id' => 'woocommerce_default_country', - 'default' => 'GB', + 'default' => 'US:CA', 'type' => 'single_select_country', 'desc_tip' => true, ), diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php index 6564d77f698..fd6c6aed831 100644 --- a/includes/wc-core-functions.php +++ b/includes/wc-core-functions.php @@ -390,7 +390,7 @@ function wc_locate_template( $template_name, $template_path = '', $default_path // Look within passed path within the theme - this is priority. if ( false !== strpos( $template_name, 'product_cat' ) || false !== strpos( $template_name, 'product_tag' ) ) { $cs_template = str_replace( '_', '-', $template_name ); - $template = locate_template( + $template = locate_template( array( trailingslashit( $template_path ) . $cs_template, $cs_template, @@ -1270,7 +1270,7 @@ function wc_format_country_state_string( $country_string ) { * @return array */ function wc_get_base_location() { - $default = apply_filters( 'woocommerce_get_base_location', get_option( 'woocommerce_default_country' ) ); + $default = apply_filters( 'woocommerce_get_base_location', get_option( 'woocommerce_default_country', 'US:CA' ) ); return wc_format_country_state_string( $default ); } @@ -1286,7 +1286,7 @@ function wc_get_base_location() { */ function wc_get_customer_default_location() { $set_default_location_to = get_option( 'woocommerce_default_customer_address', 'base' ); - $default_location = '' === $set_default_location_to ? '' : get_option( 'woocommerce_default_country', '' ); + $default_location = '' === $set_default_location_to ? '' : get_option( 'woocommerce_default_country', 'US:CA' ); $location = wc_format_country_state_string( apply_filters( 'woocommerce_customer_default_location', $default_location ) ); // Geolocation takes priority if used and if geolocation is possible. @@ -2269,9 +2269,9 @@ function wc_prevent_dangerous_auto_updates( $should_update, $plugin ) { include_once dirname( __FILE__ ) . '/admin/plugin-updates/class-wc-plugin-updates.php'; } - $new_version = wc_clean( $plugin->new_version ); - $plugin_updates = new WC_Plugin_Updates(); - $version_type = Constants::get_constant( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE' ); + $new_version = wc_clean( $plugin->new_version ); + $plugin_updates = new WC_Plugin_Updates(); + $version_type = Constants::get_constant( 'WC_SSR_PLUGIN_UPDATE_RELEASE_VERSION_TYPE' ); if ( ! is_string( $version_type ) ) { $version_type = 'none'; } diff --git a/tests/legacy/unit-tests/countries/countries.php b/tests/legacy/unit-tests/countries/countries.php index 73f41fbd55c..d2e6c0e76d4 100644 --- a/tests/legacy/unit-tests/countries/countries.php +++ b/tests/legacy/unit-tests/countries/countries.php @@ -5,6 +5,8 @@ * @package WooCommerce\Tests\Countries */ +// phpcs:disable WordPress.Files.FileName + /** * WC_Countries tests. */ @@ -178,7 +180,7 @@ class WC_Tests_Countries extends WC_Unit_Test_Case { update_option( 'woocommerce_default_country', 'NO' ); $this->assertEquals( 'VAT', $countries->tax_or_vat() ); - update_option( 'woocommerce_default_country', 'US' ); + update_option( 'woocommerce_default_country', 'US:CA' ); $this->assertEquals( 'Tax', $countries->tax_or_vat() ); } From a88bc666de5454e8aafde16f07ca1d17d40f4570 Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Mon, 12 Apr 2021 13:32:38 -0300 Subject: [PATCH 18/41] enable smoke test --- .github/workflows/smoke-test-daily.yml | 29 +++++++++++++++----------- 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/.github/workflows/smoke-test-daily.yml b/.github/workflows/smoke-test-daily.yml index 5572a76e0ef..141546494cc 100644 --- a/.github/workflows/smoke-test-daily.yml +++ b/.github/workflows/smoke-test-daily.yml @@ -4,7 +4,7 @@ on: - cron: '25 3 * * *' jobs: login-run: - name: Log into smoke test site. + name: Daily smoke test on trunk. runs-on: ubuntu-18.04 steps: @@ -18,21 +18,26 @@ jobs: - name: Checkout code. uses: actions/checkout@v2 with: - path: package/woocommerce + ref: trunk - - name: Run npm install. - working-directory: package/woocommerce - run: npm install - - - name: Move current directory to code. We will install zip file in this dir later. - run: mv ./package/woocommerce/* ./code/woocommerce - - - name: Run login test. - working-directory: code/woocommerce + - name: Install prerequisites. + run: | + npm install + composer install --no-dev + npm run build:assets + npm install jest + + - name: Run smoke test. env: SMOKE_TEST_URL: ${{ secrets.SMOKE_TEST_URL }} SMOKE_TEST_ADMIN_USER: ${{ secrets.SMOKE_TEST_ADMIN_USER }} SMOKE_TEST_ADMIN_PASSWORD: ${{ secrets.SMOKE_TEST_ADMIN_PASSWORD }} SMOKE_TEST_CUSTOMER_USER: ${{ secrets.SMOKE_TEST_CUSTOMER_USER }} SMOKE_TEST_CUSTOMER_PASSWORD: ${{ secrets.SMOKE_TEST_CUSTOMER_PASSWORD }} - run: npx wc-e2e test:e2e ./tests/e2e/specs/activate-and-setup/test-activation.js + WC_E2E_SCREENSHOTS: 1 + E2E_RETEST: 1 + E2E_SLACK_TOKEN: ${{ secrets.SMOKE_TEST_SLACK_TOKEN }} + E2E_SLACK_CHANNEL: ${{ secrets.SMOKE_TEST_SLACK_CHANNEL }} + run: | + npx wc-e2e docker:up + npx wc-e2e test:e2e From 4480e110f43b858ee90a9cb68623291c8632f80a Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Mon, 12 Apr 2021 14:33:00 -0300 Subject: [PATCH 19/41] update core tests & utils readmes --- tests/e2e/core-tests/README.md | 5 ++++ tests/e2e/utils/README.md | 55 ++++++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/tests/e2e/core-tests/README.md b/tests/e2e/core-tests/README.md index d6c4d04c005..335229f363a 100644 --- a/tests/e2e/core-tests/README.md +++ b/tests/e2e/core-tests/README.md @@ -30,6 +30,11 @@ runShopperTests(); ``` +## Retrying/Re-running tests + +On a new site, the setup and activation tests prepare the site for the remainder of the tests. To retry/rerun the test suite on a site where setup/onboarding test have already run use the environment variable `E2E_RETEST=1`. + + ## Test functions The functions to access the core tests are: diff --git a/tests/e2e/utils/README.md b/tests/e2e/utils/README.md index 2c366aabaf8..8119b274fdf 100644 --- a/tests/e2e/utils/README.md +++ b/tests/e2e/utils/README.md @@ -31,6 +31,50 @@ describe( 'Cart page', () => { } ); ~~~ +### Retries + +This package provides support for enabling retries in tests: + +- In the test environment set `E2E_RETEST=1`. +- To add conditional logic to your tests use the boolean constant `IS_RETEST_MODE`. + +### Available constants + +#### Dashboard + +- `WP_ADMIN_LOGIN` - WordPress login +- `WP_ADMIN_DASHBOARD` - WordPress dashboard +- `WP_ADMIN_PLUGINS` - Plugin list +- `WP_ADMIN_PERMALINK_SETTINGS` - Permalink settings +- `WP_ADMIN_ALL_USERS_VIEW` - WordPress user list +- `WP_ADMIN_POST_TYPE` - Post listing +- `WP_ADMIN_NEW_POST_TYPE` - New post +- `WP_ADMIN_ALL_COUPONS_VIEW` - Coupons list +- `WP_ADMIN_NEW_COUPON` - New coupon +- `WP_ADMIN_ALL_ORDERS_VIEW` - Orders list +- `WP_ADMIN_NEW_ORDER` - New Order +- `WP_ADMIN_ALL_PRODUCTS_VIEW` - Products list +- `WP_ADMIN_NEW_PRODUCT` - New product +- `WP_ADMIN_IMPORT_PRODUCTS` - Import products +- `WP_ADMIN_PLUGIN_PAGE` - Plugin settings page root +- `WP_ADMIN_WC_HOME` - WooCommerce home screen +- `WP_ADMIN_SETUP_WIZARD` - WooCommerce setup/onboarding wizard +- `WP_ADMIN_ANALYTICS_PAGES` - WooCommerce analytics page root +- `WP_ADMIN_WC_SETTINGS` - WooCommerce settings page root +- `WP_ADMIN_NEW_SHIPPING_ZONE` - WooCommerce new shipping zone + +#### Front end + +- `SHOP_PAGE` - Shop page +- `SHOP_PRODUCT_PAGE` - Single product page +- `SHOP_CART_PAGE` - Cart page +- `SHOP_CHECKOUT_PAGE` - Checkout page +- `SHOP_MY_ACCOUNT_PAGE` - Customer account page +- `MY_ACCOUNT_ORDERS` - Customer orders +- `MY_ACCOUNT_DOWNLOADS` - Customer downloads +- `MY_ACCOUNT_ADDRESSES` - Customer addresses +- `MY_ACCOUNT_ACCOUNT_DETAILS` - Customer account details + ## Test Function ### Merchant `merchant` @@ -82,6 +126,17 @@ describe( 'Cart page', () => { | `searchForProduct` | | Searching for a product name and landing on its detail page | | `emptyCart` | | Removes any products and coupons that are in the cart | +### REST API `withRestApi` + +| Function | Parameters | Description | +|----------|------------|-------------| +| `resetOnboarding` | | Reset onboarding settings | +| `deleteAllCoupons` | | Permanently delete all coupons | +| `deleteAllProducts` | | Permanently delete all products | +| `deleteAllShippingZones` | | Permanently delete all shipping zones except the default | +| `deleteCustomerByEmail` | `emailAddress` | Delete customer user account. Posts are reassigned to user ID 1 | +| `resetSettingsGroupToDefault` | `settingsGroup` | Reset settings in settings group to default except `select` fields | + ### Page Utilities | Function | Parameters | Description | From ded5c9c7c41303abc121e47bbddd7b2ace18bf83 Mon Sep 17 00:00:00 2001 From: roykho Date: Mon, 12 Apr 2021 14:13:27 -0700 Subject: [PATCH 20/41] Update unit tests to reflect new base address --- .../helpers/class-wc-helper-customer.php | 26 +++++++------- tests/legacy/unit-tests/account/functions.php | 2 +- tests/legacy/unit-tests/customer/crud.php | 14 ++++---- tests/legacy/unit-tests/customer/customer.php | 2 +- .../unit-tests/formatting/functions.php | 2 +- .../order/class-wc-tests-crud-orders.php | 8 ++--- tests/legacy/unit-tests/privacy/export.php | 12 +++---- .../rest-api/Helpers/CustomerHelper.php | 26 +++++++------- .../rest-api/Tests/Version2/customers.php | 24 ++++++------- .../rest-api/Tests/Version3/customers.php | 36 +++++++++---------- tests/legacy/unit-tests/tax/tax.php | 4 +-- .../util/class-wc-tests-core-functions.php | 4 +-- 12 files changed, 80 insertions(+), 80 deletions(-) diff --git a/tests/legacy/framework/helpers/class-wc-helper-customer.php b/tests/legacy/framework/helpers/class-wc-helper-customer.php index fe6b9ba644d..c814ac104d7 100644 --- a/tests/legacy/framework/helpers/class-wc-helper-customer.php +++ b/tests/legacy/framework/helpers/class-wc-helper-customer.php @@ -17,15 +17,15 @@ class WC_Helper_Customer { 'id' => 0, 'date_modified' => null, 'country' => 'US', - 'state' => 'PA', - 'postcode' => '19123', - 'city' => 'Philadelphia', + 'state' => 'CA', + 'postcode' => '94110', + 'city' => 'San Francisco', 'address' => '123 South Street', 'address_2' => 'Apt 1', 'shipping_country' => 'US', - 'shipping_state' => 'PA', - 'shipping_postcode' => '19123', - 'shipping_city' => 'Philadelphia', + 'shipping_state' => 'CA', + 'shipping_postcode' => '94110', + 'shipping_city' => 'San Francisco', 'shipping_address' => '123 South Street', 'shipping_address_2' => 'Apt 1', 'is_vat_exempt' => false, @@ -46,15 +46,15 @@ class WC_Helper_Customer { $customer = new WC_Customer(); $customer->set_billing_country( 'US' ); $customer->set_first_name( 'Justin' ); - $customer->set_billing_state( 'PA' ); - $customer->set_billing_postcode( '19123' ); - $customer->set_billing_city( 'Philadelphia' ); + $customer->set_billing_state( 'CA' ); + $customer->set_billing_postcode( '94110' ); + $customer->set_billing_city( 'San Francisco' ); $customer->set_billing_address( '123 South Street' ); $customer->set_billing_address_2( 'Apt 1' ); $customer->set_shipping_country( 'US' ); - $customer->set_shipping_state( 'PA' ); - $customer->set_shipping_postcode( '19123' ); - $customer->set_shipping_city( 'Philadelphia' ); + $customer->set_shipping_state( 'CA' ); + $customer->set_shipping_postcode( '94110' ); + $customer->set_shipping_city( 'San Francisco' ); $customer->set_shipping_address( '123 South Street' ); $customer->set_shipping_address_2( 'Apt 1' ); $customer->set_username( $username ); @@ -70,7 +70,7 @@ class WC_Helper_Customer { * @return array */ public static function get_expected_store_location() { - return array( 'GB', '', '', '' ); + return array( 'US', 'CA', '', '' ); } /** diff --git a/tests/legacy/unit-tests/account/functions.php b/tests/legacy/unit-tests/account/functions.php index b9b5756b1c6..ca57ba3bf5e 100644 --- a/tests/legacy/unit-tests/account/functions.php +++ b/tests/legacy/unit-tests/account/functions.php @@ -179,7 +179,7 @@ class WC_Tests_Account_Functions extends WC_Unit_Test_Case { public function test_wc_get_account_formatted_address() { $customer = WC_Helper_Customer::create_customer(); - $this->assertEquals( '123 South Street
Apt 1
Philadelphia, PA 19123
United States (US)', wc_get_account_formatted_address( 'billing', $customer->get_id() ) ); + $this->assertEquals( '123 South Street
Apt 1
San Francisco, CA 94110', wc_get_account_formatted_address( 'billing', $customer->get_id() ) ); $customer->delete( true ); } diff --git a/tests/legacy/unit-tests/customer/crud.php b/tests/legacy/unit-tests/customer/crud.php index 41c801d6538..2b070bbc309 100644 --- a/tests/legacy/unit-tests/customer/crud.php +++ b/tests/legacy/unit-tests/customer/crud.php @@ -324,16 +324,16 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case { update_option( 'woocommerce_tax_based_on', 'shipping' ); $taxable = $customer->get_taxable_address(); $this->assertEquals( 'US', $taxable[0] ); - $this->assertEquals( 'PA', $taxable[1] ); + $this->assertEquals( 'CA', $taxable[1] ); $this->assertEquals( '11111', $taxable[2] ); $this->assertEquals( 'Test', $taxable[3] ); update_option( 'woocommerce_tax_based_on', 'billing' ); $taxable = $customer->get_taxable_address(); $this->assertEquals( 'US', $taxable[0] ); - $this->assertEquals( 'PA', $taxable[1] ); - $this->assertEquals( '19123', $taxable[2] ); - $this->assertEquals( 'Philadelphia', $taxable[3] ); + $this->assertEquals( 'CA', $taxable[1] ); + $this->assertEquals( '94110', $taxable[2] ); + $this->assertEquals( 'San Francisco', $taxable[3] ); update_option( 'woocommerce_tax_based_on', 'base' ); $taxable = $customer->get_taxable_address(); @@ -431,7 +431,7 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case { */ public function test_customer_is_customer_outside_base() { $customer = WC_Helper_Customer::create_customer(); - $this->assertTrue( $customer->is_customer_outside_base() ); + $this->assertFalse( $customer->is_customer_outside_base() ); update_option( 'woocommerce_tax_based_on', 'base' ); $customer->set_billing_address_to_base(); $this->assertFalse( $customer->is_customer_outside_base() ); @@ -444,9 +444,9 @@ class WC_Tests_CustomerCRUD extends WC_Unit_Test_Case { public function test_customer_sessions() { $session = WC_Helper_Customer::create_mock_customer(); // set into session.... - $this->assertEquals( '19123', $session->get_billing_postcode() ); + $this->assertEquals( '94110', $session->get_billing_postcode() ); $this->assertEquals( '123 South Street', $session->get_billing_address() ); - $this->assertEquals( 'Philadelphia', $session->get_billing_city() ); + $this->assertEquals( 'San Francisco', $session->get_billing_city() ); $session->set_billing_address( '124 South Street' ); $session->save(); diff --git a/tests/legacy/unit-tests/customer/customer.php b/tests/legacy/unit-tests/customer/customer.php index 05b093e102d..de73d7ccdaa 100644 --- a/tests/legacy/unit-tests/customer/customer.php +++ b/tests/legacy/unit-tests/customer/customer.php @@ -83,7 +83,7 @@ class WC_Tests_Customer extends WC_Unit_Test_Case { // Customer is going with the Free Shipping option, and the store calculates tax based on the customer's billing address. WC_Helper_Customer::set_chosen_shipping_methods( array( 'free_shipping' ) ); WC_Helper_Customer::set_tax_based_on( 'billing' ); - $this->assertEquals( $customer->is_customer_outside_base(), true ); + $this->assertEquals( $customer->is_customer_outside_base(), false ); // Customer is going with the Free Shipping option, and the store calculates tax based on the store base location. WC_Helper_Customer::set_chosen_shipping_methods( array( 'free_shipping' ) ); diff --git a/tests/legacy/unit-tests/formatting/functions.php b/tests/legacy/unit-tests/formatting/functions.php index 533f5ed1a5a..7ddc4ba9865 100644 --- a/tests/legacy/unit-tests/formatting/functions.php +++ b/tests/legacy/unit-tests/formatting/functions.php @@ -618,7 +618,7 @@ class WC_Tests_Formatting_Functions extends WC_Unit_Test_Case { // Ex tax label. $calc_taxes = get_option( 'woocommerce_calc_taxes' ); update_option( 'woocommerce_calc_taxes', 'yes' ); - $this->assertEquals( '£1,111.17 (ex. VAT)', wc_price( '1111.17', array( 'ex_tax_label' => true ) ) ); + $this->assertEquals( '£1,111.17 (ex. tax)', wc_price( '1111.17', array( 'ex_tax_label' => true ) ) ); update_option( 'woocommerce_calc_taxes', $calc_taxes ); } diff --git a/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php b/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php index 190f4257c19..2444987f2ae 100644 --- a/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php +++ b/tests/legacy/unit-tests/order/class-wc-tests-crud-orders.php @@ -1245,7 +1245,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $order->set_billing_country( 'US' ); $order->set_billing_city( 'Portland' ); $order->set_billing_postcode( '97266' ); - $this->assertEquals( '123 Test St.
Portland, 97266
United States (US)', $order->get_formatted_billing_address( 'none' ) ); + $this->assertEquals( '123 Test St.
Portland, 97266', $order->get_formatted_billing_address( 'none' ) ); $this->assertTrue( $order->has_billing_address() ); $this->assertFalse( $order->has_shipping_address() ); @@ -1265,7 +1265,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $order->set_shipping_country( 'US' ); $order->set_shipping_city( 'Portland' ); $order->set_shipping_postcode( '97266' ); - $this->assertEquals( '123 Test St.
Portland, 97266
United States (US)', $order->get_formatted_shipping_address( 'none' ) ); + $this->assertEquals( '123 Test St.
Portland, 97266', $order->get_formatted_shipping_address( 'none' ) ); $this->assertFalse( $order->has_billing_address() ); $this->assertTrue( $order->has_shipping_address() ); @@ -1498,7 +1498,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $object->set_billing_state( 'Boulder' ); $object->set_billing_postcode( '00001' ); $object->set_billing_country( 'US' ); - $this->assertEquals( 'Fred Flintstone
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001
United States (US)', $object->get_formatted_billing_address() ); + $this->assertEquals( 'Fred Flintstone
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001', $object->get_formatted_billing_address() ); } /** @@ -1515,7 +1515,7 @@ class WC_Tests_CRUD_Orders extends WC_Unit_Test_Case { $object->set_shipping_state( 'Boulder' ); $object->set_shipping_postcode( '00001' ); $object->set_shipping_country( 'US' ); - $this->assertEquals( 'Barney Rubble
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001
United States (US)', $object->get_formatted_shipping_address() ); + $this->assertEquals( 'Barney Rubble
Bedrock Ltd.
34 Stonepants avenue
Rockville
Bedrock, BOULDER 00001', $object->get_formatted_shipping_address() ); } /** diff --git a/tests/legacy/unit-tests/privacy/export.php b/tests/legacy/unit-tests/privacy/export.php index 0d8db0ee39e..68d8b7fe85a 100644 --- a/tests/legacy/unit-tests/privacy/export.php +++ b/tests/legacy/unit-tests/privacy/export.php @@ -86,15 +86,15 @@ class WC_Test_Privacy_Export extends WC_Unit_Test_Case { ), array( 'name' => 'Billing City', - 'value' => 'Philadelphia', + 'value' => 'San Francisco', ), array( 'name' => 'Billing Postal/Zip Code', - 'value' => '19123', + 'value' => '94110', ), array( 'name' => 'Billing State', - 'value' => 'PA', + 'value' => 'CA', ), array( 'name' => 'Billing Country / Region', @@ -114,15 +114,15 @@ class WC_Test_Privacy_Export extends WC_Unit_Test_Case { ), array( 'name' => 'Shipping City', - 'value' => 'Philadelphia', + 'value' => 'San Francisco', ), array( 'name' => 'Shipping Postal/Zip Code', - 'value' => '19123', + 'value' => '94110', ), array( 'name' => 'Shipping State', - 'value' => 'PA', + 'value' => 'CA', ), array( 'name' => 'Shipping Country / Region', diff --git a/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php b/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php index 5751cf31f32..2dfcbdbb4e6 100644 --- a/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php +++ b/tests/legacy/unit-tests/rest-api/Helpers/CustomerHelper.php @@ -26,15 +26,15 @@ class CustomerHelper { 'id' => 0, 'date_modified' => null, 'country' => 'US', - 'state' => 'PA', - 'postcode' => '19123', - 'city' => 'Philadelphia', + 'state' => 'CA', + 'postcode' => '94110', + 'city' => 'San Francisco', 'address' => '123 South Street', 'address_2' => 'Apt 1', 'shipping_country' => 'US', - 'shipping_state' => 'PA', - 'shipping_postcode' => '19123', - 'shipping_city' => 'Philadelphia', + 'shipping_state' => 'CA', + 'shipping_postcode' => '94110', + 'shipping_city' => 'San Francisco', 'shipping_address' => '123 South Street', 'shipping_address_2' => 'Apt 1', 'is_vat_exempt' => false, @@ -55,15 +55,15 @@ class CustomerHelper { $customer = new WC_Customer(); $customer->set_billing_country( 'US' ); $customer->set_first_name( 'Justin' ); - $customer->set_billing_state( 'PA' ); - $customer->set_billing_postcode( '19123' ); - $customer->set_billing_city( 'Philadelphia' ); + $customer->set_billing_state( 'CA' ); + $customer->set_billing_postcode( '94110' ); + $customer->set_billing_city( 'San Francisco' ); $customer->set_billing_address( '123 South Street' ); $customer->set_billing_address_2( 'Apt 1' ); $customer->set_shipping_country( 'US' ); - $customer->set_shipping_state( 'PA' ); - $customer->set_shipping_postcode( '19123' ); - $customer->set_shipping_city( 'Philadelphia' ); + $customer->set_shipping_state( 'CA' ); + $customer->set_shipping_postcode( '94110' ); + $customer->set_shipping_city( 'San Francisco' ); $customer->set_shipping_address( '123 South Street' ); $customer->set_shipping_address_2( 'Apt 1' ); $customer->set_username( $username ); @@ -79,7 +79,7 @@ class CustomerHelper { * @return array */ public static function get_expected_store_location() { - return array( 'GB', '', '', '' ); + return array( 'US', 'CA', '', '' ); } /** diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php b/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php index f9a4d5acca1..cebf6cdad9c 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version2/customers.php @@ -70,9 +70,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -83,9 +83,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, @@ -315,9 +315,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -328,9 +328,9 @@ class Customers_V2 extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, diff --git a/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php b/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php index 8d4508bade4..15e02ae4c9b 100644 --- a/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php +++ b/tests/legacy/unit-tests/rest-api/Tests/Version3/customers.php @@ -77,9 +77,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -90,9 +90,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, @@ -147,9 +147,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -160,9 +160,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, @@ -387,9 +387,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', 'email' => '', 'phone' => '', @@ -400,9 +400,9 @@ class Customers extends WC_REST_Unit_Test_Case { 'company' => '', 'address_1' => '123 South Street', 'address_2' => 'Apt 1', - 'city' => 'Philadelphia', - 'state' => 'PA', - 'postcode' => '19123', + 'city' => 'San Francisco', + 'state' => 'CA', + 'postcode' => '94110', 'country' => 'US', ), 'is_paying_customer' => false, diff --git a/tests/legacy/unit-tests/tax/tax.php b/tests/legacy/unit-tests/tax/tax.php index 9269f766526..8862aa848cd 100644 --- a/tests/legacy/unit-tests/tax/tax.php +++ b/tests/legacy/unit-tests/tax/tax.php @@ -117,8 +117,8 @@ class WC_Tests_Tax extends WC_Unit_Test_Case { */ public function test_get_base_tax_rates() { $tax_rate = array( - 'tax_rate_country' => 'GB', - 'tax_rate_state' => '', + 'tax_rate_country' => 'US', + 'tax_rate_state' => 'CA', 'tax_rate' => '20.0000', 'tax_rate_name' => 'VAT', 'tax_rate_priority' => '1', diff --git a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php index a782089e51b..8f5b1419fbe 100644 --- a/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php +++ b/tests/legacy/unit-tests/util/class-wc-tests-core-functions.php @@ -348,8 +348,8 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case { public function test_wc_get_base_location() { $default = wc_get_base_location(); - $this->assertEquals( 'GB', $default['country'] ); - $this->assertEquals( '', $default['state'] ); + $this->assertEquals( 'US', $default['country'] ); + $this->assertEquals( 'CA', $default['state'] ); } /** From b47cd85af0ae0ee859c8a0c92129281a1975d696 Mon Sep 17 00:00:00 2001 From: Caleb Burks Date: Mon, 12 Apr 2021 18:56:23 -0500 Subject: [PATCH 21/41] Add docblock --- includes/class-wc-logger.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/includes/class-wc-logger.php b/includes/class-wc-logger.php index ef2184f43f1..c0b5ae33ee1 100644 --- a/includes/class-wc-logger.php +++ b/includes/class-wc-logger.php @@ -142,6 +142,15 @@ class WC_Logger implements WC_Logger_Interface { $timestamp = time(); foreach ( $this->handlers as $handler ) { + /** + * Filter the logging message. Returning null will prevent logging from occuring since 5.2. + * + * @since 3.1 + * @param string $message Log message. + * @param string $level One of: emergency, alert, critical, error, warning, notice, info, or debug. + * @param array $context Additional information for log handlers. + * @param object $handler The handler object, such as WC_Log_Handler_File. Available since 5.2. + */ $message = apply_filters( 'woocommerce_logger_log_message', $message, $level, $context, $handler ); if ( null !== $message ) { From 07f72c80b42bbf3be822c5499d450e191ff47382 Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Tue, 13 Apr 2021 08:25:22 -0300 Subject: [PATCH 22/41] fix spacing Co-authored-by: Greg <71906536+zhongruige@users.noreply.github.com> --- .github/workflows/smoke-test-daily.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/smoke-test-daily.yml b/.github/workflows/smoke-test-daily.yml index 141546494cc..d168350f512 100644 --- a/.github/workflows/smoke-test-daily.yml +++ b/.github/workflows/smoke-test-daily.yml @@ -27,7 +27,7 @@ jobs: npm run build:assets npm install jest - - name: Run smoke test. + - name: Run smoke test. env: SMOKE_TEST_URL: ${{ secrets.SMOKE_TEST_URL }} SMOKE_TEST_ADMIN_USER: ${{ secrets.SMOKE_TEST_ADMIN_USER }} From aea8e1655fd3a2f02c95d098f97407bc76f5d034 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Albert=20Juh=C3=A9=20Lluveras?= Date: Tue, 13 Apr 2021 20:06:33 +0200 Subject: [PATCH 23/41] Update WooCommerce Blocks package to 4.9.1 --- composer.json | 2 +- composer.lock | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/composer.json b/composer.json index da6ef18a12f..7d363c2ccba 100644 --- a/composer.json +++ b/composer.json @@ -22,7 +22,7 @@ "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", "woocommerce/woocommerce-admin": "2.1.5", - "woocommerce/woocommerce-blocks": "4.7.2" + "woocommerce/woocommerce-blocks": "4.9.1" }, "require-dev": { "bamarni/composer-bin-plugin": "^1.4" diff --git a/composer.lock b/composer.lock index 874d83c7834..99c54366482 100644 --- a/composer.lock +++ b/composer.lock @@ -579,16 +579,16 @@ }, { "name": "woocommerce/woocommerce-blocks", - "version": "v4.7.2", + "version": "v4.9.1", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git", - "reference": "942e58553b1a299ad04842e7f0d7465d9e029ac3" + "reference": "62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/942e58553b1a299ad04842e7f0d7465d9e029ac3", - "reference": "942e58553b1a299ad04842e7f0d7465d9e029ac3", + "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce", + "reference": "62f32bfb45dfcb2ba3ca349a6ed0a8cf48ddefce", "shasum": "" }, "require": { @@ -624,9 +624,9 @@ ], "support": { "issues": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues", - "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v4.7.2" + "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v4.9.1" }, - "time": "2021-04-13T16:06:16+00:00" + "time": "2021-04-13T16:11:16+00:00" } ], "packages-dev": [ From 0916dd3246b42c4da23fddf2a44d18dd5f2f206e Mon Sep 17 00:00:00 2001 From: Caleb Burks Date: Tue, 13 Apr 2021 17:21:00 -0500 Subject: [PATCH 24/41] Update docblock --- includes/class-wc-logger.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/includes/class-wc-logger.php b/includes/class-wc-logger.php index c0b5ae33ee1..fed86dea651 100644 --- a/includes/class-wc-logger.php +++ b/includes/class-wc-logger.php @@ -143,13 +143,13 @@ class WC_Logger implements WC_Logger_Interface { foreach ( $this->handlers as $handler ) { /** - * Filter the logging message. Returning null will prevent logging from occuring since 5.2. + * Filter the logging message. Returning null will prevent logging from occuring since 5.3. * * @since 3.1 * @param string $message Log message. * @param string $level One of: emergency, alert, critical, error, warning, notice, info, or debug. * @param array $context Additional information for log handlers. - * @param object $handler The handler object, such as WC_Log_Handler_File. Available since 5.2. + * @param object $handler The handler object, such as WC_Log_Handler_File. Available since 5.3. */ $message = apply_filters( 'woocommerce_logger_log_message', $message, $level, $context, $handler ); From 2c13c994b20c8127389cfa398d3f46dc207a6f54 Mon Sep 17 00:00:00 2001 From: Ron Rennick Date: Wed, 14 Apr 2021 10:05:03 -0300 Subject: [PATCH 25/41] add screenshot utility --- tests/e2e/env/CHANGELOG.md | 3 ++ tests/e2e/env/README.md | 6 +++ tests/e2e/env/package-lock.json | 2 +- tests/e2e/env/src/setup/jest.failure.js | 25 +++-------- tests/e2e/env/utils/index.js | 2 + tests/e2e/env/utils/take-screenshot.js | 37 +++++++++++++++ tests/e2e/utils/src/page-utils.js | 60 ++++++++----------------- 7 files changed, 74 insertions(+), 61 deletions(-) create mode 100644 tests/e2e/env/utils/take-screenshot.js diff --git a/tests/e2e/env/CHANGELOG.md b/tests/e2e/env/CHANGELOG.md index 4b0fa6d81e5..0448af10265 100644 --- a/tests/e2e/env/CHANGELOG.md +++ b/tests/e2e/env/CHANGELOG.md @@ -1,5 +1,8 @@ # Unreleased +## Added + +- `takeScreenshotFor` utility function to take screenshots within tests # 0.2.1 diff --git a/tests/e2e/env/README.md b/tests/e2e/env/README.md index 121e52440f1..ea1be7a0a9d 100644 --- a/tests/e2e/env/README.md +++ b/tests/e2e/env/README.md @@ -79,6 +79,12 @@ The test sequencer provides a screenshot function for test failures. To enable s WC_E2E_SCREENSHOTS=1 npx wc-e2e test:e2e ``` +To take adhoc in test screenshots use + +```js +await takeScreenshotFor( 'name of current step' ); +``` + Screenshots will be saved to `tests/e2e/screenshots`. This folder is cleared at the beginning of each test run. ### Jest Puppeteer Config diff --git a/tests/e2e/env/package-lock.json b/tests/e2e/env/package-lock.json index 0b7e8c5a069..2766327b895 100644 --- a/tests/e2e/env/package-lock.json +++ b/tests/e2e/env/package-lock.json @@ -1,6 +1,6 @@ { "name": "@woocommerce/e2e-environment", - "version": "0.2.0", + "version": "0.2.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/tests/e2e/env/src/setup/jest.failure.js b/tests/e2e/env/src/setup/jest.failure.js index 31a906a10ee..7eb0947a784 100644 --- a/tests/e2e/env/src/setup/jest.failure.js +++ b/tests/e2e/env/src/setup/jest.failure.js @@ -4,10 +4,8 @@ import { sendFailedTestMessageToSlack, } from '../slack'; -const path = require( 'path' ); -const mkdirp = require( 'mkdirp' ); import { bind } from 'jest-each'; -const { getAppRoot } = require( '../../utils' ); +const { takeScreenshotFor } = require( '../../utils' ); /** * Override the test case method so we can take screenshots of assertion failures. @@ -88,22 +86,11 @@ const screenshotTest = async ( testName, callback ) => { try { await callback(); } catch ( e ) { - const testTitle = testName.replace( /\.$/, '' ); - const appPath = getAppRoot(); - const savePath = path.resolve( appPath, 'tests/e2e/screenshots' ); - const filePath = path.join( - savePath, - `${ testTitle }.png`.replace( /[^a-z0-9.-]+/gi, '-' ) - ); - - mkdirp.sync( savePath ); - await page.screenshot( { - path: filePath, - fullPage: true, - } ); - - await sendFailedTestMessageToSlack( testTitle ); - await sendFailedTestScreenshotToSlack( filePath ); + const { title, filePath } = await takeScreenshotFor( testName ); + await sendFailedTestMessageToSlack( title ); + if ( filePath ) { + await sendFailedTestScreenshotToSlack( filePath ); + } throw ( e ); } diff --git a/tests/e2e/env/utils/index.js b/tests/e2e/env/utils/index.js index ce89ae395f7..bb6331f46bb 100644 --- a/tests/e2e/env/utils/index.js +++ b/tests/e2e/env/utils/index.js @@ -1,6 +1,7 @@ const getAppRoot = require( './app-root' ); const { getAppName, getAppBase } = require( './app-name' ); const { getTestConfig, getAdminConfig } = require( './test-config' ); +const takeScreenshotFor = require( './take-screenshot' ); module.exports = { getAppBase, @@ -8,4 +9,5 @@ module.exports = { getAppName, getTestConfig, getAdminConfig, + takeScreenshotFor, }; diff --git a/tests/e2e/env/utils/take-screenshot.js b/tests/e2e/env/utils/take-screenshot.js new file mode 100644 index 00000000000..634da95dfab --- /dev/null +++ b/tests/e2e/env/utils/take-screenshot.js @@ -0,0 +1,37 @@ +const path = require( 'path' ); +const mkdirp = require( 'mkdirp' ); +const getAppRoot = require( './app-root' ); + +/** + * Take a screenshot if browser context exists. + * @param message + * @returns {Promise<{filePath: string, title: string}|{filePath: *, title: *}>} + */ +const takeScreenshotFor = async ( message ) => { + const title = message.replace( /\.$/, '' ); + const appPath = getAppRoot(); + const savePath = path.resolve( appPath, 'tests/e2e/screenshots' ); + const filePath = path.join( + savePath, + `${ title }.png`.replace( /[^a-z0-9.-]+/gi, '-' ) + ); + + mkdirp.sync( savePath ); + try { + await page.screenshot({ + path: filePath, + fullPage: true, + }); + } catch ( error ) { + return { + title: 'no screenshot', + filePath: '', + }; + } + return { + title, + filePath, + }; +}; + +module.exports = takeScreenshotFor; diff --git a/tests/e2e/utils/src/page-utils.js b/tests/e2e/utils/src/page-utils.js index 4bf9024989e..7e7648462e0 100644 --- a/tests/e2e/utils/src/page-utils.js +++ b/tests/e2e/utils/src/page-utils.js @@ -9,7 +9,7 @@ import { pressKeyWithModifier } from '@wordpress/e2e-test-utils'; * @param {string} selector * @param {string} value */ -const clearAndFillInput = async ( selector, value ) => { +export const clearAndFillInput = async ( selector, value ) => { await page.waitForSelector( selector ); await page.focus( selector ); await pressKeyWithModifier( 'primary', 'a' ); @@ -21,14 +21,14 @@ const clearAndFillInput = async ( selector, value ) => { * * @param {string} tabName Tab label */ -const clickTab = async ( tabName ) => { +export const clickTab = async ( tabName ) => { await expect( page ).toClick( '.wc-tabs > li > a', { text: tabName } ); }; /** * Save changes on a WooCommerce settings page. */ -const settingsPageSaveChanges = async () => { +export const settingsPageSaveChanges = async () => { await page.focus( 'button.woocommerce-save-button' ); await Promise.all( [ page.waitForNavigation( { waitUntil: 'networkidle0' } ), @@ -39,7 +39,7 @@ const settingsPageSaveChanges = async () => { /** * Save changes on Permalink settings page. */ -const permalinkSettingsPageSaveChanges = async () => { +export const permalinkSettingsPageSaveChanges = async () => { await page.focus( '.wp-core-ui .button-primary' ); await Promise.all( [ page.waitForNavigation( { waitUntil: 'networkidle0' } ), @@ -52,7 +52,7 @@ const permalinkSettingsPageSaveChanges = async () => { * * @param {string} selector */ -const setCheckbox = async( selector ) => { +export const setCheckbox = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -66,7 +66,7 @@ const setCheckbox = async( selector ) => { * * @param {string} selector */ -const unsetCheckbox = async( selector ) => { +export const unsetCheckbox = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -78,7 +78,7 @@ const unsetCheckbox = async( selector ) => { /** * Wait for UI blocking to end. */ -const uiUnblocked = async () => { +export const uiUnblocked = async () => { await page.waitForFunction( () => ! Boolean( document.querySelector( '.blockUI' ) ) ); }; @@ -90,7 +90,7 @@ const uiUnblocked = async () => { * @param {string} publishVerification * @param {string} trashVerification */ -const verifyPublishAndTrash = async ( button, publishNotice, publishVerification, trashVerification ) => { +export const verifyPublishAndTrash = async ( button, publishNotice, publishVerification, trashVerification ) => { // Wait for auto save await page.waitFor( 2000 ); @@ -124,7 +124,7 @@ const verifyPublishAndTrash = async ( button, publishNotice, publishVerification * * @param {string} selector Selector of the checkbox that needs to be verified. */ -const verifyCheckboxIsSet = async( selector ) => { +export const verifyCheckboxIsSet = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -136,7 +136,7 @@ const verifyCheckboxIsSet = async( selector ) => { * * @param {string} selector Selector of the checkbox that needs to be verified. */ -const verifyCheckboxIsUnset = async( selector ) => { +export const verifyCheckboxIsUnset = async( selector ) => { await page.focus( selector ); const checkbox = await page.$( selector ); const checkboxStatus = ( await ( await checkbox.getProperty( 'checked' ) ).jsonValue() ); @@ -149,7 +149,7 @@ const verifyCheckboxIsUnset = async( selector ) => { * @param {string} selector Selector of the input field that needs to be verified. * @param {string} value Value of the input field that needs to be verified. */ -const verifyValueOfInputField = async( selector, value ) => { +export const verifyValueOfInputField = async( selector, value ) => { await page.focus( selector ); const field = await page.$( selector ); const fieldValue = ( await ( await field.getProperty( 'value' ) ).jsonValue() ); @@ -161,7 +161,7 @@ const verifyValueOfInputField = async( selector, value ) => { * * @param {string} selector Selector of the filter link to be clicked. */ -const clickFilter = async ( selector ) => { +export const clickFilter = async ( selector ) => { await page.waitForSelector( selector ); await page.focus( selector ); await Promise.all( [ @@ -175,7 +175,7 @@ const clickFilter = async ( selector ) => { * * If there's more than 20 items, it moves all 20 items on the current page. */ -const moveAllItemsToTrash = async () => { +export const moveAllItemsToTrash = async () => { await setCheckbox( '#cb-select-all-1' ); await expect( page ).toSelect( '#bulk-action-selector-top', 'Move to Trash' ); await Promise.all( [ @@ -191,7 +191,7 @@ const moveAllItemsToTrash = async () => { * * @param {string} selector Selector of the filter link to be clicked. */ -const evalAndClick = async ( selector ) => { +export const evalAndClick = async ( selector ) => { // We use this when `expect(page).toClick()` is unable to find the element // See: https://github.com/puppeteer/puppeteer/issues/1769#issuecomment-637645219 page.$eval( selector, elem => elem.click() ); @@ -203,7 +203,7 @@ const evalAndClick = async ( selector ) => { * @param {string} value Value of what to be selected * @param {string} selector Selector of the select2 search field */ -const selectOptionInSelect2 = async ( value, selector = 'input.select2-search__field' ) => { +export const selectOptionInSelect2 = async ( value, selector = 'input.select2-search__field' ) => { await page.waitForSelector(selector); await page.click(selector); await page.type(selector, value); @@ -218,7 +218,7 @@ const selectOptionInSelect2 = async ( value, selector = 'input.select2-search__f * @param {string} orderId Order ID * @param {string} customerName Customer's full name attached to order ID. */ -const searchForOrder = async (value, orderId, customerName) => { +export const searchForOrder = async (value, orderId, customerName) => { await clearAndFillInput('#post-search-input', value); await expect(page).toMatchElement('#post-search-input', value); await expect(page).toClick('#search-submit'); @@ -234,7 +234,7 @@ const searchForOrder = async (value, orderId, customerName) => { * @param couponCode string * @returns {Promise} */ -const applyCoupon = async ( couponCode ) => { +export const applyCoupon = async ( couponCode ) => { try { await expect(page).toClick('a', {text: 'Click here to enter your code'}); await uiUnblocked(); @@ -254,7 +254,7 @@ const applyCoupon = async ( couponCode ) => { * @param couponCode Coupon name. * @returns {Promise} */ -const removeCoupon = async ( couponCode ) => { +export const removeCoupon = async ( couponCode ) => { await expect(page).toClick('[data-coupon="'+couponCode.toLowerCase()+'"]', {text: '[Remove]'}); await uiUnblocked(); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon has been removed.'}); @@ -266,32 +266,10 @@ const removeCoupon = async ( couponCode ) => { * * @param {string} action The action to take on the order. */ -const selectOrderAction = async ( action ) => { +export const selectOrderAction = async ( action ) => { await page.select( 'select[name=wc_order_action]', action ); await Promise.all( [ page.click( '.wc-reload' ), page.waitForNavigation( { waitUntil: 'networkidle0' } ), ] ); } - -export { - clearAndFillInput, - clickTab, - settingsPageSaveChanges, - permalinkSettingsPageSaveChanges, - setCheckbox, - unsetCheckbox, - uiUnblocked, - verifyPublishAndTrash, - verifyCheckboxIsSet, - verifyCheckboxIsUnset, - verifyValueOfInputField, - clickFilter, - moveAllItemsToTrash, - evalAndClick, - selectOptionInSelect2, - searchForOrder, - applyCoupon, - removeCoupon, - selectOrderAction, -}; From fc5499f9b8eddb6eba023d5643d732f44c7fe1ce Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Wed, 24 Mar 2021 12:47:15 -0400 Subject: [PATCH 26/41] Bump WooCommerce Admin version to 2.2.0-beta.2 --- composer.json | 2 +- composer.lock | 40 +++++----------------------------------- 2 files changed, 6 insertions(+), 36 deletions(-) diff --git a/composer.json b/composer.json index da6ef18a12f..7a0af66954e 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "pelago/emogrifier": "3.1.0", "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", - "woocommerce/woocommerce-admin": "2.1.5", + "woocommerce/woocommerce-admin": "2.2.0-beta.2", "woocommerce/woocommerce-blocks": "4.7.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 874d83c7834..dfc2253c628 100644 --- a/composer.lock +++ b/composer.lock @@ -85,9 +85,6 @@ "GPL-2.0-or-later" ], "description": "A wrapper for defining constants in a more testable way.", - "support": { - "source": "https://github.com/Automattic/jetpack-constants/tree/v1.5.1" - }, "time": "2020-10-28T19:00:31+00:00" }, { @@ -218,10 +215,6 @@ "zend", "zikula" ], - "support": { - "issues": "https://github.com/composer/installers/issues", - "source": "https://github.com/composer/installers/tree/v1.10.0" - }, "funding": [ { "url": "https://packagist.com", @@ -296,10 +289,6 @@ "geolocation", "maxmind" ], - "support": { - "issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues", - "source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.6.0" - }, "time": "2019-12-19T22:59:03+00:00" }, { @@ -374,10 +363,6 @@ "email", "pre-processing" ], - "support": { - "issues": "https://github.com/MyIntervals/emogrifier/issues", - "source": "https://github.com/MyIntervals/emogrifier" - }, "time": "2019-12-26T19:37:31+00:00" }, { @@ -427,10 +412,6 @@ "container-interop", "psr" ], - "support": { - "issues": "https://github.com/php-fig/container/issues", - "source": "https://github.com/php-fig/container/tree/master" - }, "time": "2017-02-14T16:28:37+00:00" }, { @@ -484,9 +465,6 @@ ], "description": "Symfony CssSelector Component", "homepage": "https://symfony.com", - "support": { - "source": "https://github.com/symfony/css-selector/tree/master" - }, "time": "2017-05-01T15:01:29+00:00" }, { @@ -522,24 +500,20 @@ ], "description": "Action Scheduler for WordPress and WooCommerce", "homepage": "https://actionscheduler.org/", - "support": { - "issues": "https://github.com/woocommerce/action-scheduler/issues", - "source": "https://github.com/woocommerce/action-scheduler/tree/master" - }, "time": "2020-05-12T16:22:33+00:00" }, { "name": "woocommerce/woocommerce-admin", - "version": "2.1.5", + "version": "2.2.0-beta.2", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-admin.git", - "reference": "71c233d8463f551430edbe1877e51d19a4bb2df6" + "reference": "6229ea56742380149c966af0e5fdca725f54f754" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/71c233d8463f551430edbe1877e51d19a4bb2df6", - "reference": "71c233d8463f551430edbe1877e51d19a4bb2df6", + "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/6229ea56742380149c966af0e5fdca725f54f754", + "reference": "6229ea56742380149c966af0e5fdca725f54f754", "shasum": "" }, "require": { @@ -674,10 +648,6 @@ "isolation", "tool" ], - "support": { - "issues": "https://github.com/bamarni/composer-bin-plugin/issues", - "source": "https://github.com/bamarni/composer-bin-plugin/tree/master" - }, "time": "2020-05-03T08:27:20+00:00" } ], @@ -693,5 +663,5 @@ "platform-overrides": { "php": "7.0" }, - "plugin-api-version": "2.0.0" + "plugin-api-version": "1.1.0" } From 63dbdddf64ba784ca919e3baa2b5d7b8c99f1cfc Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Fri, 26 Mar 2021 12:28:22 -0400 Subject: [PATCH 27/41] Update to rc1 --- composer.json | 2 +- composer.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index 7a0af66954e..e3cb0ce95a7 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "pelago/emogrifier": "3.1.0", "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", - "woocommerce/woocommerce-admin": "2.2.0-beta.2", + "woocommerce/woocommerce-admin": "2.2.0-rc.1", "woocommerce/woocommerce-blocks": "4.7.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index dfc2253c628..5b66b273b3c 100644 --- a/composer.lock +++ b/composer.lock @@ -504,16 +504,16 @@ }, { "name": "woocommerce/woocommerce-admin", - "version": "2.2.0-beta.2", + "version": "2.2.0-rc.1", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-admin.git", - "reference": "6229ea56742380149c966af0e5fdca725f54f754" + "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/6229ea56742380149c966af0e5fdca725f54f754", - "reference": "6229ea56742380149c966af0e5fdca725f54f754", + "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/d1364ec144a0a580fac1b47f657a652363fcc7cd", + "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd", "shasum": "" }, "require": { From 1d4368f38408ff9769989986f1d2eccf3c9f7718 Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Wed, 14 Apr 2021 12:55:12 -0400 Subject: [PATCH 28/41] Bump WooCommerce Admin version to 2.2.1 --- composer.json | 2 +- composer.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/composer.json b/composer.json index e3cb0ce95a7..ec4f2ec5cd3 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "pelago/emogrifier": "3.1.0", "psr/container": "1.0.0", "woocommerce/action-scheduler": "3.1.6", - "woocommerce/woocommerce-admin": "2.2.0-rc.1", + "woocommerce/woocommerce-admin": "2.2.1", "woocommerce/woocommerce-blocks": "4.7.2" }, "require-dev": { diff --git a/composer.lock b/composer.lock index 5b66b273b3c..43c7cdd1659 100644 --- a/composer.lock +++ b/composer.lock @@ -504,16 +504,16 @@ }, { "name": "woocommerce/woocommerce-admin", - "version": "2.2.0-rc.1", + "version": "2.2.1", "source": { "type": "git", "url": "https://github.com/woocommerce/woocommerce-admin.git", - "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd" + "reference": "78cc9c5ef7de5be5bd0f9208483e5ae97422be9a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/d1364ec144a0a580fac1b47f657a652363fcc7cd", - "reference": "d1364ec144a0a580fac1b47f657a652363fcc7cd", + "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/78cc9c5ef7de5be5bd0f9208483e5ae97422be9a", + "reference": "78cc9c5ef7de5be5bd0f9208483e5ae97422be9a", "shasum": "" }, "require": { From d37a31927eeaae1924ff8477478af9f9445e9edc Mon Sep 17 00:00:00 2001 From: Joshua Flowers Date: Wed, 14 Apr 2021 13:10:35 -0400 Subject: [PATCH 29/41] Update composer.lock --- composer.lock | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/composer.lock b/composer.lock index 43c7cdd1659..bbba8925e66 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "aaad3b20adf49ba997d4be94865087c6", + "content-hash": "11158f53934e897bd84be190a184ec87", "packages": [ { "name": "automattic/jetpack-autoloader", @@ -51,9 +51,6 @@ "GPL-2.0-or-later" ], "description": "Creates a custom autoloader for a plugin or theme.", - "support": { - "source": "https://github.com/Automattic/jetpack-autoloader/tree/2.10.1" - }, "time": "2021-03-30T15:15:59+00:00" }, { @@ -545,11 +542,7 @@ ], "description": "A modern, javascript-driven WooCommerce Admin experience.", "homepage": "https://github.com/woocommerce/woocommerce-admin", - "support": { - "issues": "https://github.com/woocommerce/woocommerce-admin/issues", - "source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.1.5" - }, - "time": "2021-04-02T16:48:38+00:00" + "time": "2021-04-02T19:30:03+00:00" }, { "name": "woocommerce/woocommerce-blocks", @@ -596,10 +589,6 @@ "gutenberg", "woocommerce" ], - "support": { - "issues": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues", - "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v4.7.2" - }, "time": "2021-04-13T16:06:16+00:00" } ], From 7296cb66d464aff38b39c0d6e29f657fe2cd927c Mon Sep 17 00:00:00 2001 From: Claudio Sanches Date: Wed, 14 Apr 2021 16:27:19 -0300 Subject: [PATCH 30/41] Revert "add portugal states" --- i18n/states.php | 25 ++----------------------- 1 file changed, 2 insertions(+), 23 deletions(-) diff --git a/i18n/states.php b/i18n/states.php index 99ee2aef131..6065e0771f8 100644 --- a/i18n/states.php +++ b/i18n/states.php @@ -534,7 +534,7 @@ return array( 'SO' => __( 'Sololá', 'woocommerce' ), 'SU' => __( 'Suchitepéquez', 'woocommerce' ), 'TO' => __( 'Totonicapán', 'woocommerce' ), - 'ZA' => __( 'Zacapa', 'woocommerce' ), + 'ZA' => __( 'Zacapa', 'woocommerce' ) ), 'HK' => array( // Hong Kong states. 'HONG KONG' => __( 'Hong Kong Island', 'woocommerce' ), @@ -1296,28 +1296,7 @@ return array( ), 'PL' => array(), 'PR' => array(), - 'PT' => array( // Portugal states. Ref: https://github.com/unicode-org/cldr/blob/release-38-1/common/subdivisions/en.xml#L4139-L4159 - 'PT-01' => __( 'Aveiro', 'woocommerce' ), - 'PT-02' => __( 'Beja', 'woocommerce' ), - 'PT-03' => __( 'Braga', 'woocommerce' ), - 'PT-04' => __( 'Bragança', 'woocommerce' ), - 'PT-05' => __( 'Castelo Branco', 'woocommerce' ), - 'PT-06' => __( 'Coimbra', 'woocommerce' ), - 'PT-07' => __( 'Évora', 'woocommerce' ), - 'PT-08' => __( 'Faro', 'woocommerce' ), - 'PT-09' => __( 'Guarda', 'woocommerce' ), - 'PT-10' => __( 'Leiria', 'woocommerce' ), - 'PT-11' => __( 'Lisbon', 'woocommerce' ), - 'PT-12' => __( 'Portalegre', 'woocommerce' ), - 'PT-13' => __( 'Porto', 'woocommerce' ), - 'PT-14' => __( 'Santarém', 'woocommerce' ), - 'PT-15' => __( 'Setúbal', 'woocommerce' ), - 'PT-16' => __( 'Viana do Castelo', 'woocommerce' ), - 'PT-17' => __( 'Vila Real', 'woocommerce' ), - 'PT-18' => __( 'Viseu', 'woocommerce' ), - 'PT-20' => __( 'Azores', 'woocommerce' ), - 'PT-30' => __( 'Madeira', 'woocommerce' ), - ), + 'PT' => array(), 'PY' => array( // Paraguay states. 'PY-ASU' => __( 'Asunción', 'woocommerce' ), 'PY-1' => __( 'Concepción', 'woocommerce' ), From a07523243420b8ad64c4c60475a1ed829aaa2c74 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 10:06:06 +0200 Subject: [PATCH 31/41] Updated code for calculating prices --- .../shopper/front-end-cart-calculate-shipping.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 879f5f17f5d..4efc8ac54e9 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -26,10 +26,10 @@ const config = require( 'config' ); const firstProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99'; const secondProductPrice = '4.99'; const fourProductPrice = firstProductPrice * 4; -var twoProductsPrice = eval([firstProductPrice,secondProductPrice].join('+')); -var firstProductPriceWithFlatRate = eval([firstProductPrice,5].join('+')); -var fourProductPriceWithFlatRate = eval([fourProductPrice,5].join('+')); -var twoProductsPriceWithFlatRate = eval([twoProductsPrice,5].join('+')); +var twoProductsPrice = (+firstProductPrice) + (+secondProductPrice); +var firstProductPriceWithFlatRate = (+firstProductPrice) + (+5); +var fourProductPriceWithFlatRate = (+fourProductPrice) + (+5); +var twoProductsPriceWithFlatRate = (+twoProductsPrice) + (+5); const firstProductName = 'First Product'; const secondProductName = 'Second Product'; const shippingZoneNameDE = 'Germany Free Shipping'; From c887830d68aad6e568949df620aeeb1f21407ee9 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Thu, 15 Apr 2021 10:35:33 +0200 Subject: [PATCH 32/41] Update changelog and readme for 5.2.2, change stable tag to 5.2.2 --- changelog.txt | 6 ++++++ readme.txt | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 4cfdac0fc66..4b636018665 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,11 @@ == Changelog == += 5.2.2 2021-04-15 = + +**WooCommerce** + +* Fix - Can't grant permission for download from order details page. #29691 + = 5.2.1 2021-04-14 = **WooCommerce** diff --git a/readme.txt b/readme.txt index 76ce7b54471..6c7b73bf3ba 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Tags: e-commerce, store, sales, sell, woo, shop, cart, checkout, downloadable, d Requires at least: 5.5 Tested up to: 5.7 Requires PHP: 7.0 -Stable tag: 5.2.1 +Stable tag: 5.2.2 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html @@ -160,6 +160,12 @@ WooCommerce comes with some sample data you can use to see how products look; im == Changelog == += 5.2.2 2021-04-15 = + +**WooCommerce** + +* Fix - Can't grant permission for download from order details page. #29691 + = 5.2.1 2021-04-14 = **WooCommerce** From 950d08b7a5d5babcd1cf75550baad174e65099b9 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 13:28:25 +0200 Subject: [PATCH 33/41] Add new e2e test shopper order email receiving --- tests/e2e/core-tests/CHANGELOG.md | 1 + tests/e2e/core-tests/README.md | 1 + tests/e2e/core-tests/specs/index.js | 7 ++- .../front-end-order-email-receiving.test.js | 57 +++++++++++++++++++ .../front-end/test-order-email-receiving.js | 6 ++ 5 files changed, 70 insertions(+), 2 deletions(-) create mode 100644 tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js create mode 100644 tests/e2e/specs/front-end/test-order-email-receiving.js diff --git a/tests/e2e/core-tests/CHANGELOG.md b/tests/e2e/core-tests/CHANGELOG.md index 789e7afc3fb..d2a04ff9f9a 100644 --- a/tests/e2e/core-tests/CHANGELOG.md +++ b/tests/e2e/core-tests/CHANGELOG.md @@ -3,6 +3,7 @@ ## Added - Support for re-running setup and shopper tests +- Shopper Order Email Receiving ## Fixed diff --git a/tests/e2e/core-tests/README.md b/tests/e2e/core-tests/README.md index ef2cd6a45be..091025e0718 100644 --- a/tests/e2e/core-tests/README.md +++ b/tests/e2e/core-tests/README.md @@ -86,6 +86,7 @@ The functions to access the core tests are: - `runCheckoutLoginAccountTest` - Shopper can login to an account during checkout - `runMyAccountCreateAccountTest` - Shopper can create an account via my account page - `runCartRedirectionTest` - Shopper is redirected to the cart page after adding to cart + - `runOrderEmailReceivingTest` - Shopper can receive an email for his order ### REST API diff --git a/tests/e2e/core-tests/specs/index.js b/tests/e2e/core-tests/specs/index.js index 8ffcff1742c..4e1debc641c 100644 --- a/tests/e2e/core-tests/specs/index.js +++ b/tests/e2e/core-tests/specs/index.js @@ -22,6 +22,7 @@ const runVariableProductUpdateTest = require( './shopper/front-end-variable-prod const runCheckoutCreateAccountTest = require( './shopper/front-end-checkout-create-account.test' ); const runCheckoutLoginAccountTest = require( './shopper/front-end-checkout-login-account.test' ); const runCartRedirectionTest = require( './shopper/front-end-cart-redirection.test' ); +const runOrderEmailReceivingTest = require( './shopper/front-end-order-email-receiving.test' ); // Merchant tests const runAddNewShippingZoneTest = require ( './merchant/wp-admin-settings-shipping-zones.test' ); @@ -70,7 +71,8 @@ const runShopperTests = () => { runVariableProductUpdateTest(); runCheckoutCreateAccountTest(); runCheckoutLoginAccountTest(); - runCartRedirectionTest(); + runCartRedirectionTest(); + runOrderEmailReceivingTest(); }; const runMerchantTests = () => { @@ -144,8 +146,9 @@ module.exports = { runAddShippingClassesTest, runAnalyticsPageLoadsTest, runCheckoutCreateAccountTest, - runImportProductsTest, + runImportProductsTest, runCheckoutLoginAccountTest, runCartRedirectionTest, runMyAccountCreateAccountTest, + runOrderEmailReceivingTest, }; diff --git a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js new file mode 100644 index 00000000000..ff517948dcd --- /dev/null +++ b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js @@ -0,0 +1,57 @@ +/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */ +/** + * Internal dependencies + */ + const { + shopper, + merchant, + createSimpleProduct, + uiUnblocked, +} = require( '@woocommerce/e2e-utils' ); + +let simplePostIdValue; +let orderId; +const config = require( 'config' ); +const simpleProductName = config.get( 'products.simple.name' ); +const customerEmail = config.get( 'addresses.customer.billing.email' ); +const storeName = 'WooCommerce Core E2E Test Suite'; + +/** + * External dependencies + */ +const { + it, + describe, + beforeAll, +} = require( '@jest/globals' ); + +const runOrderEmailReceivingTest = () => { + describe('Shopper Order Email Receiving', () => { + beforeAll(async () => { + await merchant.login(); + simplePostIdValue = await createSimpleProduct(); + await merchant.logout(); + }); + + it('should receive order email after purchasing an item', async () => { + await shopper.login(); + + // Go to the shop and purchase an item + await shopper.goToProduct(simplePostIdValue); + await shopper.addToCart(simpleProductName); + await shopper.goToCheckout(); + await uiUnblocked(); + await shopper.placeOrder(); + // Get order ID from the order received html element on the page + orderId = await page.$$eval(".woocommerce-order-overview__order strong", elements => elements.map(item => item.textContent)); + + // Verify the new order email has been received + await merchant.login(); + await merchant.openEmailLog(); + await expect( page ).toMatchElement( '.column-receiver', { text: customerEmail } ); + await expect( page ).toMatchElement( '.column-subject', { text: `[${storeName}]: New order #${orderId}` } ); + }); + }); +}; + +module.exports = runOrderEmailReceivingTest; diff --git a/tests/e2e/specs/front-end/test-order-email-receiving.js b/tests/e2e/specs/front-end/test-order-email-receiving.js new file mode 100644 index 00000000000..a85e21d0c22 --- /dev/null +++ b/tests/e2e/specs/front-end/test-order-email-receiving.js @@ -0,0 +1,6 @@ +/* + * Internal dependencies + */ +const { runOrderEmailReceivingTest } = require( '@woocommerce/e2e-core-tests' ); + +runOrderEmailReceivingTest(); From 5c633e1c3b628254776a70477a73662ee3105454 Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 14:01:28 +0200 Subject: [PATCH 34/41] Add deleting email logs if any --- .../specs/shopper/front-end-order-email-receiving.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js index ff517948dcd..69b9124f0e3 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js @@ -7,6 +7,7 @@ merchant, createSimpleProduct, uiUnblocked, + deleteAllEmailLogs, } = require( '@woocommerce/e2e-utils' ); let simplePostIdValue; @@ -29,6 +30,7 @@ const runOrderEmailReceivingTest = () => { describe('Shopper Order Email Receiving', () => { beforeAll(async () => { await merchant.login(); + await deleteAllEmailLogs(); simplePostIdValue = await createSimpleProduct(); await merchant.logout(); }); From 1bc0b25f0cd1a12a352079cd12dde72783c737dc Mon Sep 17 00:00:00 2001 From: Veljko Date: Thu, 15 Apr 2021 14:30:06 +0200 Subject: [PATCH 35/41] Fix spaces --- .../specs/shopper/front-end-order-email-receiving.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js index 69b9124f0e3..da466cae6de 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-order-email-receiving.test.js @@ -7,7 +7,7 @@ merchant, createSimpleProduct, uiUnblocked, - deleteAllEmailLogs, + deleteAllEmailLogs, } = require( '@woocommerce/e2e-utils' ); let simplePostIdValue; @@ -30,7 +30,7 @@ const runOrderEmailReceivingTest = () => { describe('Shopper Order Email Receiving', () => { beforeAll(async () => { await merchant.login(); - await deleteAllEmailLogs(); + await deleteAllEmailLogs(); simplePostIdValue = await createSimpleProduct(); await merchant.logout(); }); From a0c965964b6c97cb28ca38b0605d1cfe30493074 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Thu, 15 Apr 2021 17:16:00 +0200 Subject: [PATCH 36/41] Add a GitHub action for automatic assignment of milestone to merged PRs The milestone is chosen as follows: 1. List all the open milestones with a title of "X.Y.Z" 2. Sort them desc using verson_compare 3. foreach them in order, and take the last one not having a corresponding release branch ("release/X.Y") --- .../pull-request-post-merge-processing.yml | 32 ++++ .../scripts/assign-milestone-to-merged-pr.php | 144 ++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 .github/workflows/pull-request-post-merge-processing.yml create mode 100644 .github/workflows/scripts/assign-milestone-to-merged-pr.php diff --git a/.github/workflows/pull-request-post-merge-processing.yml b/.github/workflows/pull-request-post-merge-processing.yml new file mode 100644 index 00000000000..d7ada48dbd4 --- /dev/null +++ b/.github/workflows/pull-request-post-merge-processing.yml @@ -0,0 +1,32 @@ +name: "Pull request post-merge processing" +on: + pull_request: + types: [closed] + +jobs: + assign-milestone: + name: "Assign milestone to merged pull request" + if: github.event.pull_request.merged == true && ! github.event.pull_request.milestone + runs-on: ubuntu-latest + steps: + - name: "Get the milestone changer script" + run: | + curl \ + --silent \ + --fail \ + --header 'Authorization: bearer ${{ secrets.GITHUB_TOKEN }}' \ + --header 'User-Agent: GitHub action to set the milestone for a pull request' \ + --header 'Accept: application/vnd.github.v3.raw' \ + --remote-name \ + --location $GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/assign-milestone-to-merged-pr.php + env: + GITHUB_API_URL: ${{ env.GITHUB_API_URL }} + - name: Install PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '7.4' + - name: "Run the milestone changer script" + run: php assign-milestone-to-merged-pr.php + env: + PULL_REQUEST_ID: ${{ github.event.pull_request.node_id }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/scripts/assign-milestone-to-merged-pr.php b/.github/workflows/scripts/assign-milestone-to-merged-pr.php new file mode 100644 index 00000000000..deb4ab0875a --- /dev/null +++ b/.github/workflows/scripts/assign-milestone-to-merged-pr.php @@ -0,0 +1,144 @@ + "$keyword { $body }" ); + $context = stream_context_create( + array( + 'http' => array( + 'method' => 'POST', + 'header' => array( + 'Accept: application/json', + 'Content-Type: application/json', + 'User-Agent: GitHub action to set the milestone for a pull request', + 'Authorization: bearer ' . $github_token, + ), + 'content' => json_encode( $data ), + ), + ) + ); + + $result = file_get_contents( $graphql_api_url, false, $context ); + return json_decode( $result, true ); +} + +// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped, WordPress.WP.AlternativeFunctions From b09ddd7984af145f5de1cc0c61d6088b3e4068d6 Mon Sep 17 00:00:00 2001 From: Nestor Soriano Date: Fri, 16 Apr 2021 13:06:49 +0200 Subject: [PATCH 37/41] Add a GitHub action to manually trigger the generation of a release zip file --- .github/workflows/build-release-zip-file.yml | 30 ++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/build-release-zip-file.yml diff --git a/.github/workflows/build-release-zip-file.yml b/.github/workflows/build-release-zip-file.yml new file mode 100644 index 00000000000..2f6dd819e20 --- /dev/null +++ b/.github/workflows/build-release-zip-file.yml @@ -0,0 +1,30 @@ +name: Build release zip file +on: + workflow_dispatch: + inputs: + ref: + description: 'By default the zip file is generated from the branch the workflow runs from, but you can specify an explicit reference to use instead here (e.g. refs/tags/tag_name). The resulting file will be available as an artifact on the workflow run.' + required: false + default: '' +jobs: + build: + name: Build release zip file + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + with: + ref: ${{ github.event.inputs.ref || github.ref }} + - name: Build the zip file + id: build + uses: woocommerce/action-build@v2 + - name: Unzip the file (prevents double zip problem) + run: unzip ${{ steps.build.outputs.zip_path }} -d zipfile + - name: Upload the zip file as an artifact + uses: actions/upload-artifact@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + name: woocommerce + path: zipfile + retention-days: 7 From 23e09d33ddef81450033fc0afe23f1f70428205f Mon Sep 17 00:00:00 2001 From: Veljko Date: Fri, 16 Apr 2021 14:11:27 +0200 Subject: [PATCH 38/41] Add shipping zones remover --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 4efc8ac54e9..4f5af5c8bca 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -11,6 +11,7 @@ const { clearAndFillInput, uiUnblocked, selectOptionInSelect2, + deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); /** @@ -43,6 +44,7 @@ const runCartCalculateShippingTest = () => { await merchant.login(); await createSimpleProduct(firstProductName); await createSimpleProduct(secondProductName, secondProductPrice); + await deleteAllShippingZones(); await merchant.openNewShipping(); // Add a new shipping zone Germany with Free shipping From 5da39b4ff0f9fc0e8e0c7472664375afee56fa6b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Soriano?= Date: Fri, 16 Apr 2021 15:48:38 +0200 Subject: [PATCH 39/41] Enclose action step name in double quotes for consistency. Co-authored-by: Leif Singer --- .github/workflows/pull-request-post-merge-processing.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request-post-merge-processing.yml b/.github/workflows/pull-request-post-merge-processing.yml index d7ada48dbd4..1347ed5e5e1 100644 --- a/.github/workflows/pull-request-post-merge-processing.yml +++ b/.github/workflows/pull-request-post-merge-processing.yml @@ -21,7 +21,7 @@ jobs: --location $GITHUB_API_URL/repos/${{ github.repository }}/contents/.github/workflows/scripts/assign-milestone-to-merged-pr.php env: GITHUB_API_URL: ${{ env.GITHUB_API_URL }} - - name: Install PHP + - name: "Install PHP" uses: shivammathur/setup-php@v2 with: php-version: '7.4' From 1c7bec0489b49e00b274255c733f5aaa96171ea5 Mon Sep 17 00:00:00 2001 From: Veljko Date: Fri, 16 Apr 2021 21:22:34 +0200 Subject: [PATCH 40/41] Remove shipping zones remover --- .../specs/shopper/front-end-cart-calculate-shipping.test.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js index 4f5af5c8bca..4efc8ac54e9 100644 --- a/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js +++ b/tests/e2e/core-tests/specs/shopper/front-end-cart-calculate-shipping.test.js @@ -11,7 +11,6 @@ const { clearAndFillInput, uiUnblocked, selectOptionInSelect2, - deleteAllShippingZones, } = require( '@woocommerce/e2e-utils' ); /** @@ -44,7 +43,6 @@ const runCartCalculateShippingTest = () => { await merchant.login(); await createSimpleProduct(firstProductName); await createSimpleProduct(secondProductName, secondProductPrice); - await deleteAllShippingZones(); await merchant.openNewShipping(); // Add a new shipping zone Germany with Free shipping From 3ada9fc5623b42f14f247baaabcf05683fca2494 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?N=C3=A9stor=20Soriano?= Date: Mon, 19 Apr 2021 14:46:45 +0200 Subject: [PATCH 41/41] Change GH API query for milestones to get only the open ones. Co-authored-by: Vedanshu Jain --- .github/workflows/scripts/assign-milestone-to-merged-pr.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/scripts/assign-milestone-to-merged-pr.php b/.github/workflows/scripts/assign-milestone-to-merged-pr.php index deb4ab0875a..0258813e209 100644 --- a/.github/workflows/scripts/assign-milestone-to-merged-pr.php +++ b/.github/workflows/scripts/assign-milestone-to-merged-pr.php @@ -35,7 +35,7 @@ echo "Getting the list of milestones...\n"; $query = " repository(owner:\"$repo_owner\", name:\"$repo_name\") { - milestones(first: 10, orderBy: {field: CREATED_AT, direction: DESC}) { + milestones(first: 10, states: [OPEN], orderBy: {field: CREATED_AT, direction: DESC}) { nodes { id title @@ -48,7 +48,7 @@ $json = do_graphql_api_request( $query ); $milestones = $json['data']['repository']['milestones']['nodes']; $milestones = array_map( function( $x ) { - return 'OPEN' === $x['state'] && 1 === preg_match( '/^\d+\.\d+\.\d+$/D', $x['title'] ) ? $x : null; + return 1 === preg_match( '/^\d+\.\d+\.\d+$/D', $x['title'] ) ? $x : null; }, $milestones );