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 <info@nielslange.de>
This commit is contained in:
Thomas Roberts 2023-03-13 03:45:48 +00:00 committed by GitHub
parent 4067541ac2
commit f708214246
4 changed files with 233 additions and 6 deletions

View File

@ -6,6 +6,7 @@ import {
CartShippingRate, CartShippingRate,
} from '@woocommerce/type-defs/cart'; } from '@woocommerce/type-defs/cart';
import { getSetting } from '@woocommerce/settings'; import { getSetting } from '@woocommerce/settings';
import { LOCAL_PICKUP_ENABLED } from '@woocommerce/block-settings';
/** /**
* Get the number of packages in a shippingRates array. * Get the number of packages in a shippingRates array.
@ -36,6 +37,9 @@ export const isPackageRateCollectable = (
export const hasCollectableRate = ( export const hasCollectableRate = (
chosenRates: string[] | string chosenRates: string[] | string
): boolean => { ): boolean => {
if ( ! LOCAL_PICKUP_ENABLED ) {
return false;
}
if ( Array.isArray( chosenRates ) ) { if ( Array.isArray( chosenRates ) ) {
return !! chosenRates.find( ( rate ) => return !! chosenRates.find( ( rate ) =>
collectableMethodIds.includes( rate ) collectableMethodIds.includes( rate )

View File

@ -6,20 +6,27 @@ import {
isPackageRateCollectable, isPackageRateCollectable,
} from '@woocommerce/base-utils'; } from '@woocommerce/base-utils';
import { CartShippingRate } from '@woocommerce/type-defs/cart'; import { CartShippingRate } from '@woocommerce/type-defs/cart';
import * as blockSettings from '@woocommerce/block-settings';
jest.mock( '@woocommerce/settings', () => { jest.mock( '@woocommerce/settings', () => {
return { return {
__esModule: true,
...jest.requireActual( '@woocommerce/settings' ), ...jest.requireActual( '@woocommerce/settings' ),
getSetting: ( setting: string ) => { getSetting: jest.fn().mockImplementation( ( setting: string ) => {
if ( setting === 'collectableMethodIds' ) { if ( setting === 'collectableMethodIds' ) {
return [ 'local_pickup' ]; return [ 'local_pickup' ];
} }
return jest return jest
.requireActual( '@woocommerce/settings' ) .requireActual( '@woocommerce/settings' )
.getSetting( setting ); .getSetting( setting );
}, } ),
}; };
} ); } );
jest.mock( '@woocommerce/block-settings', () => ( {
__esModule: true,
...jest.requireActual( '@woocommerce/block-settings' ),
LOCAL_PICKUP_ENABLED: true,
} ) );
describe( 'hasCollectableRate', () => { describe( 'hasCollectableRate', () => {
it( 'correctly identifies if an array contains a collectable rate', () => { it( 'correctly identifies if an array contains a collectable rate', () => {
const ratesToTest = [ 'flat_rate', 'local_pickup' ]; const ratesToTest = [ 'flat_rate', 'local_pickup' ];
@ -27,6 +34,12 @@ describe( 'hasCollectableRate', () => {
const ratesToTest2 = [ 'flat_rate', 'free_shipping' ]; const ratesToTest2 = [ 'flat_rate', 'free_shipping' ];
expect( hasCollectableRate( ratesToTest2 ) ).toBe( false ); 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', () => { describe( 'isPackageRateCollectable', () => {

View File

@ -15,7 +15,7 @@ import {
getToggleIdByLabel, getToggleIdByLabel,
switchBlockInspectorTabWhenGutenbergIsInstalled, switchBlockInspectorTabWhenGutenbergIsInstalled,
} from '@woocommerce/blocks-test-utils'; } from '@woocommerce/blocks-test-utils';
import { visitAdminPage } from '@wordpress/e2e-test-utils';
/** /**
* Internal dependencies * Internal dependencies
*/ */
@ -27,6 +27,7 @@ import {
SHIPPING_DETAILS, SHIPPING_DETAILS,
SIMPLE_PHYSICAL_PRODUCT_NAME, SIMPLE_PHYSICAL_PRODUCT_NAME,
SIMPLE_VIRTUAL_PRODUCT_NAME, SIMPLE_VIRTUAL_PRODUCT_NAME,
BASE_URL,
} from '../../../../utils'; } from '../../../../utils';
import { createCoupon } from '../../../utils'; import { createCoupon } from '../../../utils';
@ -35,9 +36,92 @@ let coupon;
describe( 'Shopper → Checkout', () => { describe( 'Shopper → Checkout', () => {
beforeAll( async () => { 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(); await shopper.block.emptyCart();
} ); } );
describe( 'Local pickup', () => {
beforeAll( async () => {
// Enable local pickup.
await visitAdminPage(
'admin.php',
'page=wc-settings&tab=shipping&section=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&section=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', () => { describe( 'Payment Methods', () => {
it( 'User can change payment methods', async () => { it( 'User can change payment methods', async () => {
await shopper.block.emptyCart(); await shopper.block.emptyCart();
@ -94,8 +178,12 @@ describe( 'Shopper → Checkout', () => {
await shopper.block.goToShop(); await shopper.block.goToShop();
await shopper.addToCartFromShopPage( SIMPLE_PHYSICAL_PRODUCT_NAME ); await shopper.addToCartFromShopPage( SIMPLE_PHYSICAL_PRODUCT_NAME );
await shopper.block.goToCheckout(); await shopper.block.goToCheckout();
await page.waitForSelector( '#checkbox-control-0' ); await page.waitForSelector(
await unsetCheckbox( '#checkbox-control-0' ); '.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.fillShippingDetails( SHIPPING_DETAILS );
await shopper.block.fillBillingDetails( BILLING_DETAILS ); await shopper.block.fillBillingDetails( BILLING_DETAILS );
await shopper.block.placeOrder(); await shopper.block.placeOrder();

View File

@ -2,7 +2,7 @@
/** /**
* Plugin Name: Woo Test Helper * Plugin Name: Woo Test Helper
* Description: A helper plugin to control settings within Woo e2e tests. * Description: A helper plugin to control settings within Woo e2e tests.
* Version: 0.0.1 * Version: 0.0.2
* Author: Automattic * Author: Automattic
* Author URI: https://automattic.com * Author URI: https://automattic.com
* Text Domain: woo-test-helper * 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' ) ); 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' );