From f7082142465af6e4b0887dcca081234efd832898 Mon Sep 17 00:00:00 2001 From: Thomas Roberts <5656702+opr@users.noreply.github.com> Date: Mon, 13 Mar 2023 03:45:48 +0000 Subject: [PATCH] Add E2E test for third-party local pickup methods (https://github.com/woocommerce/woocommerce-blocks/pull/8543) * Add third party local pickup method to woo-test-helper plugin * Add test to check for checkout with local pickup * Ensure local pickup is disabled when done with tests * Add a more reliable selector for the "use same address for billing" box * Prevent local pickup rates showing if local pickup is not enabled * Check billing details after placing local pickup order * Change local pickup unit test so rates dont show if localPickup disabled * Use existing const instead of getSetting * Update tests to mock constant from @woocommerce/block-settings --------- Co-authored-by: Niels Lange --- .../assets/js/base/utils/shipping-rates.ts | 4 + .../js/base/utils/test/shipping-rates.ts | 17 ++- .../shopper/cart-checkout/checkout.test.js | 94 ++++++++++++- .../mocks/woo-test-helper/woo-test-helper.php | 124 +++++++++++++++++- 4 files changed, 233 insertions(+), 6 deletions(-) diff --git a/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts b/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts index 13a4a4036d2..f5c61e6bd14 100644 --- a/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts +++ b/plugins/woocommerce-blocks/assets/js/base/utils/shipping-rates.ts @@ -6,6 +6,7 @@ import { CartShippingRate, } from '@woocommerce/type-defs/cart'; import { getSetting } from '@woocommerce/settings'; +import { LOCAL_PICKUP_ENABLED } from '@woocommerce/block-settings'; /** * Get the number of packages in a shippingRates array. @@ -36,6 +37,9 @@ export const isPackageRateCollectable = ( export const hasCollectableRate = ( chosenRates: string[] | string ): boolean => { + if ( ! LOCAL_PICKUP_ENABLED ) { + return false; + } if ( Array.isArray( chosenRates ) ) { return !! chosenRates.find( ( rate ) => collectableMethodIds.includes( rate ) diff --git a/plugins/woocommerce-blocks/assets/js/base/utils/test/shipping-rates.ts b/plugins/woocommerce-blocks/assets/js/base/utils/test/shipping-rates.ts index c28e7babeae..6121834f6aa 100644 --- a/plugins/woocommerce-blocks/assets/js/base/utils/test/shipping-rates.ts +++ b/plugins/woocommerce-blocks/assets/js/base/utils/test/shipping-rates.ts @@ -6,20 +6,27 @@ import { isPackageRateCollectable, } from '@woocommerce/base-utils'; import { CartShippingRate } from '@woocommerce/type-defs/cart'; +import * as blockSettings from '@woocommerce/block-settings'; jest.mock( '@woocommerce/settings', () => { return { + __esModule: true, ...jest.requireActual( '@woocommerce/settings' ), - getSetting: ( setting: string ) => { + getSetting: jest.fn().mockImplementation( ( setting: string ) => { if ( setting === 'collectableMethodIds' ) { return [ 'local_pickup' ]; } return jest .requireActual( '@woocommerce/settings' ) .getSetting( setting ); - }, + } ), }; } ); +jest.mock( '@woocommerce/block-settings', () => ( { + __esModule: true, + ...jest.requireActual( '@woocommerce/block-settings' ), + LOCAL_PICKUP_ENABLED: true, +} ) ); describe( 'hasCollectableRate', () => { it( 'correctly identifies if an array contains a collectable rate', () => { const ratesToTest = [ 'flat_rate', 'local_pickup' ]; @@ -27,6 +34,12 @@ describe( 'hasCollectableRate', () => { const ratesToTest2 = [ 'flat_rate', 'free_shipping' ]; expect( hasCollectableRate( ratesToTest2 ) ).toBe( false ); } ); + it( 'returns false for all rates if local pickup is disabled', () => { + // Attempt to assign to const or readonly variable error on next line is OK because it is mocked by jest + blockSettings.LOCAL_PICKUP_ENABLED = false; + const ratesToTest = [ 'flat_rate', 'local_pickup' ]; + expect( hasCollectableRate( ratesToTest ) ).toBe( false ); + } ); } ); describe( 'isPackageRateCollectable', () => { diff --git a/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/checkout.test.js b/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/checkout.test.js index 0a3eb12f26f..40aeed75443 100644 --- a/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/checkout.test.js +++ b/plugins/woocommerce-blocks/tests/e2e/specs/shopper/cart-checkout/checkout.test.js @@ -15,7 +15,7 @@ import { getToggleIdByLabel, switchBlockInspectorTabWhenGutenbergIsInstalled, } from '@woocommerce/blocks-test-utils'; - +import { visitAdminPage } from '@wordpress/e2e-test-utils'; /** * Internal dependencies */ @@ -27,6 +27,7 @@ import { SHIPPING_DETAILS, SIMPLE_PHYSICAL_PRODUCT_NAME, SIMPLE_VIRTUAL_PRODUCT_NAME, + BASE_URL, } from '../../../../utils'; import { createCoupon } from '../../../utils'; @@ -35,9 +36,92 @@ let coupon; describe( 'Shopper → Checkout', () => { beforeAll( async () => { + // Check that Woo Collection is enabled. + await page.goto( + `${ BASE_URL }?check_third_party_local_pickup_method` + ); + // eslint-disable-next-line jest/no-standalone-expect + await expect( page ).toMatch( 'Woo Collection' ); + await shopper.block.emptyCart(); } ); + describe( 'Local pickup', () => { + beforeAll( async () => { + // Enable local pickup. + await visitAdminPage( + 'admin.php', + 'page=wc-settings&tab=shipping§ion=pickup_location' + ); + + const localPickupCheckbox = await page.waitForXPath( + '//input[@name="local_pickup_enabled"]' + ); + const isCheckboxChecked = await page.evaluate( + ( checkbox ) => checkbox.checked, + localPickupCheckbox + ); + + if ( isCheckboxChecked === true ) { + return; + } + + // eslint-disable-next-line jest/no-standalone-expect + await expect( page ).toClick( 'label', { + text: 'Enable local pickup', + } ); + // eslint-disable-next-line jest/no-standalone-expect + await expect( page ).toClick( 'button', { + text: 'Save changes', + } ); + } ); + afterAll( async () => { + // Disable local pickup. + await visitAdminPage( + 'admin.php', + 'page=wc-settings&tab=shipping§ion=pickup_location' + ); + + const localPickupCheckbox = await page.waitForXPath( + '//input[@name="local_pickup_enabled"]' + ); + const isCheckboxChecked = await page.evaluate( + ( checkbox ) => checkbox.checked, + localPickupCheckbox + ); + + // Skip this if it's already unchecked. + if ( isCheckboxChecked === false ) { + return; + } + + // eslint-disable-next-line jest/no-standalone-expect + await expect( page ).toClick( 'label', { + text: 'Enable local pickup', + } ); + // eslint-disable-next-line jest/no-standalone-expect + await expect( page ).toClick( 'button', { + text: 'Save changes', + } ); + } ); + it( 'The shopper can choose a local pickup option', async () => { + await shopper.block.emptyCart(); + await shopper.block.goToShop(); + await shopper.addToCartFromShopPage( SIMPLE_PHYSICAL_PRODUCT_NAME ); + await shopper.block.goToCheckout(); + await expect( page ).toClick( + '.wc-block-checkout__shipping-method-option-title', + { + text: 'Local Pickup', + } + ); + expect( page ).toMatch( 'Woo Collection' ); + await shopper.block.fillBillingDetails( BILLING_DETAILS ); + await shopper.block.placeOrder(); + await shopper.block.verifyBillingDetails( BILLING_DETAILS ); + } ); + } ); + describe( 'Payment Methods', () => { it( 'User can change payment methods', async () => { await shopper.block.emptyCart(); @@ -94,8 +178,12 @@ describe( 'Shopper → Checkout', () => { await shopper.block.goToShop(); await shopper.addToCartFromShopPage( SIMPLE_PHYSICAL_PRODUCT_NAME ); await shopper.block.goToCheckout(); - await page.waitForSelector( '#checkbox-control-0' ); - await unsetCheckbox( '#checkbox-control-0' ); + await page.waitForSelector( + '.wc-block-checkout__use-address-for-billing input[type="checkbox"]' + ); + await unsetCheckbox( + '.wc-block-checkout__use-address-for-billing input[type="checkbox"]' + ); await shopper.block.fillShippingDetails( SHIPPING_DETAILS ); await shopper.block.fillBillingDetails( BILLING_DETAILS ); await shopper.block.placeOrder(); diff --git a/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php b/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php index 491b7f4e0d4..5869cc351ed 100644 --- a/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php +++ b/plugins/woocommerce-blocks/tests/mocks/woo-test-helper/woo-test-helper.php @@ -2,7 +2,7 @@ /** * Plugin Name: Woo Test Helper * Description: A helper plugin to control settings within Woo e2e tests. - * Version: 0.0.1 + * Version: 0.0.2 * Author: Automattic * Author URI: https://automattic.com * Text Domain: woo-test-helper @@ -125,3 +125,125 @@ function setup_cross_sells() { update_post_meta( $id_product->ID, '_crosssell_ids', wp_list_pluck( $id_cross_sells, 'ID' ) ); } } + +/** + * Registers a third party local pickup method, this will have a different ID to the ones we add in the WC Settings. + */ +function register_third_party_local_pickup_method() { + /** + * This function initialises our local pickup method. + */ + function woo_collection_shipping_init() { + + /** + * Custom Local Pickup method. + */ + class Woo_Collection_Shipping_Method extends WC_Shipping_Method { + + /** + * Min amount to be valid. + * + * @var integer + */ + public $min_amount = 0; + + /** + * Requires option. + * + * @var string + */ + public $requires = ''; + + /** + * Constructor. + * + * @param int $instance_id Shipping method instance. + */ + public function __construct( $instance_id = 0 ) { + $this->id = 'woo_collection_shipping'; + $this->instance_id = absint( $instance_id ); + $this->title = 'Woo Collection'; + $this->method_title = __( 'Woo Collection', 'woo-gutenberg-products-block' ); + $this->method_description = __( 'Get your order shipped to an Woo Collection point.', 'woo-gutenberg-products-block' ); + $this->supports = array( + 'instance-settings', + 'instance-settings-modal', + 'local-pickup', + ); + + $this->init(); + } + + /** + * Initialize Woo Collection shipping. + */ + public function init() { + } + + /** + * See if Woo Collection shipping is available based on the package and cart. + * + * @param array $package Shipping package. + * @return bool + */ + public function is_available( $package ) { + return true; + } + + /** + * Called to calculate shipping rates for this method. Rates can be added using the add_rate() method. + * + * @param array $package Shipping package. + * @uses WC_Shipping_Method::add_rate() + */ + public function calculate_shipping( $package = array() ) { + $this->add_rate( + array( + 'label' => $this->title, + 'cost' => 0, + 'taxes' => false, + 'package' => $package, + ) + ); + } + } + } + + // Use this hook to initialize your new custom method. + add_action( 'woocommerce_shipping_init', 'woo_collection_shipping_init' ); + + /** + * Adds the Woo Collection shipping method to the list of available methods in WooCommerce. + * @param array $methods The current list of methods. + * @return array The modified list of methods. + */ + function add_woo_collection_shipping( $methods ) { + $methods['woo_collection_shipping'] = 'Woo_Collection_Shipping_Method'; + + return $methods; + } + add_filter( 'woocommerce_shipping_methods', 'add_woo_collection_shipping' ); +} +register_third_party_local_pickup_method(); + +/** + * Define URL endpoint for setting up third party local pickup method. + */ +function check_third_party_local_pickup_method() { + // phpcs:disable WordPress.Security.NonceVerification.Recommended + if ( isset( $_GET['check_third_party_local_pickup_method'] ) ) { + add_action( + 'woocommerce_blocks_loaded', + function () { + $method_titles = array_map( + function ( $method ) { + return $method->title; + }, + wc()->shipping()->get_shipping_methods() + ); + exit( wp_kses( implode( ', ', $method_titles ), array() ) ); + } + ); + } +} +add_action( 'plugins_loaded', 'check_third_party_local_pickup_method' );