From dd81f08be473f9e86a4223f44c193ff7abf23d36 Mon Sep 17 00:00:00 2001 From: frosso Date: Wed, 5 Feb 2025 16:56:04 +0100 Subject: [PATCH 1/4] fix: attribute selection from PDPs with tokenized ECE --- changelog/fix-tokenized-ece-attribute-selection | 4 ++++ .../compatibility/wc-product-page.js | 14 ++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) create mode 100644 changelog/fix-tokenized-ece-attribute-selection diff --git a/changelog/fix-tokenized-ece-attribute-selection b/changelog/fix-tokenized-ece-attribute-selection new file mode 100644 index 00000000000..8a4efea2cdb --- /dev/null +++ b/changelog/fix-tokenized-ece-attribute-selection @@ -0,0 +1,4 @@ +Significance: patch +Type: fix + +fix: attribute selection from PDPs with tokenized ECE diff --git a/client/tokenized-express-checkout/compatibility/wc-product-page.js b/client/tokenized-express-checkout/compatibility/wc-product-page.js index 3c242f046cf..94282905e91 100644 --- a/client/tokenized-express-checkout/compatibility/wc-product-page.js +++ b/client/tokenized-express-checkout/compatibility/wc-product-page.js @@ -73,12 +73,14 @@ addFilter( // The Store API accepts the variable attribute's label, rather than an internal identifier: // https://github.com/woocommerce/woocommerce-blocks/blob/trunk/src/StoreApi/docs/cart.md#add-item // It's an unfortunate hack that doesn't work when labels have special characters in them. - attribute: document.querySelector( - `label[for="${ attributeName.replace( - 'attribute_', - '' - ) }"]` - ).innerHTML, + attribute: Array.from( + document.querySelector( + `label[for="${ attributeName.replace( + 'attribute_', + '' + ) }"]` + ).childNodes + )[ 0 ], value: $select.val() || '', } ); } ); From 3e4d683e2c006fd8a9369d559b578a7dfec5e4b9 Mon Sep 17 00:00:00 2001 From: frosso Date: Wed, 12 Feb 2025 14:21:57 +0100 Subject: [PATCH 2/4] further fix --- .../tokenized-express-checkout/compatibility/wc-product-page.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/tokenized-express-checkout/compatibility/wc-product-page.js b/client/tokenized-express-checkout/compatibility/wc-product-page.js index 94282905e91..a682cd008ea 100644 --- a/client/tokenized-express-checkout/compatibility/wc-product-page.js +++ b/client/tokenized-express-checkout/compatibility/wc-product-page.js @@ -80,7 +80,7 @@ addFilter( '' ) }"]` ).childNodes - )[ 0 ], + )[ 0 ].textContent, value: $select.val() || '', } ); } ); From 72043d34802cbfbdcef5deae21048864b4548df2 Mon Sep 17 00:00:00 2001 From: frosso Date: Wed, 12 Feb 2025 18:03:30 +0100 Subject: [PATCH 3/4] WIP tests --- .../__tests__/wc-product-page.test.js | 199 ++++++++++++++++++ .../compatibility/wc-product-page.js | 32 +-- 2 files changed, 219 insertions(+), 12 deletions(-) create mode 100644 client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js diff --git a/client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js b/client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js new file mode 100644 index 00000000000..6b74db0f020 --- /dev/null +++ b/client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js @@ -0,0 +1,199 @@ +/* eslint-disable jsx-a11y/accessible-emoji */ + +/** + * External dependencies + */ +import { applyFilters } from '@wordpress/hooks'; +import { render } from '@testing-library/react'; + +/** + * Internal dependencies + */ +import '../wc-product-page'; + +describe( 'ECE product page compatibility', () => { + it( 'returns the variation data', () => { + render( +
+ + + + + + + + + + + +
+ + + +
+ + + +
+
+ +
+
+ ); + const productData = applyFilters( + 'wcpay.express-checkout.cart-add-item', + { + variation: [], + } + ); + + expect( productData ).toStrictEqual( { + id: 10, + variation: [ + { + attribute: 'Color', + value: 'red', + }, + { + attribute: 'attribute_pa_color', + value: 'red', + }, + { + attribute: 'Logo', + value: 'Yes', + }, + { + attribute: 'attribute_logo', + value: 'Yes', + }, + ], + } ); + } ); + it( 'ensures compatibility with plugins modifying the DOM with additional markup', () => { + // this markup is simulating the output of the "woo-variation-swatches" plugin. + render( +
+ + + + + + + + + + + + + + + +
+ + : Medium + + +
+ + : Blue + + +
+ + : Yes 👍 + + +
+
+ +
+
+ ); + const productData = applyFilters( + 'wcpay.express-checkout.cart-add-item', + { + variation: [], + } + ); + + expect( productData ).toStrictEqual( { + id: 10, + variation: [ + { + attribute: 'Size😆', + value: 'Medium', + }, + { + attribute: 'attribute_size%f0%9f%98%86', + value: 'Medium', + }, + { + attribute: 'Color ✏️', + value: 'Green', + }, + { + attribute: 'attribute_color-%e2%9c%8f%ef%b8%8f', + value: 'Green', + }, + { + attribute: 'Autograph choice ✏️', + value: 'Yes 👍', + }, + { + attribute: 'attribute_autograph-choice-%e2%9c%8f%ef%b8%8f', + value: 'Yes 👍', + }, + ], + } ); + } ); +} ); diff --git a/client/tokenized-express-checkout/compatibility/wc-product-page.js b/client/tokenized-express-checkout/compatibility/wc-product-page.js index a682cd008ea..001b233da30 100644 --- a/client/tokenized-express-checkout/compatibility/wc-product-page.js +++ b/client/tokenized-express-checkout/compatibility/wc-product-page.js @@ -37,14 +37,16 @@ addFilter( 'wcpay.express-checkout.cart-add-item', 'automattic/wcpay/express-checkout', ( productData ) => { - const $variationInformation = jQuery( '.single_variation_wrap' ); - if ( ! $variationInformation.length ) { + const variationInformation = document.querySelector( + '.single_variation_wrap' + ); + if ( ! variationInformation ) { return productData; } - const productId = $variationInformation - .find( 'input[name="product_id"]' ) - .val(); + const productId = variationInformation.querySelector( + 'input[name="product_id"]' + ).value; return { ...productData, id: parseInt( productId, 10 ), @@ -55,24 +57,24 @@ addFilter( 'wcpay.express-checkout.cart-add-item', 'automattic/wcpay/express-checkout', ( productData ) => { - const $variationsForm = jQuery( '.variations_form' ); - if ( ! $variationsForm.length ) { + const variationsForm = document.querySelector( '.variations_form' ); + if ( ! variationsForm ) { return productData; } const attributes = []; - const $variationSelectElements = $variationsForm.find( + const variationSelectElements = variationsForm.querySelectorAll( '.variations select' ); - $variationSelectElements.each( function () { - const $select = jQuery( this ); + Array.from( variationSelectElements ).forEach( function ( select ) { const attributeName = - $select.data( 'attribute_name' ) || $select.attr( 'name' ); + select.dataset.attribute_name || select.dataset.name; attributes.push( { // The Store API accepts the variable attribute's label, rather than an internal identifier: // https://github.com/woocommerce/woocommerce-blocks/blob/trunk/src/StoreApi/docs/cart.md#add-item // It's an unfortunate hack that doesn't work when labels have special characters in them. + // fallback until https://github.com/woocommerce/woocommerce/pull/55317 has been consolidated in WC Core. attribute: Array.from( document.querySelector( `label[for="${ attributeName.replace( @@ -81,7 +83,13 @@ addFilter( ) }"]` ).childNodes )[ 0 ].textContent, - value: $select.val() || '', + value: select.value || '', + } ); + + // proper logic for https://github.com/woocommerce/woocommerce/pull/55317 . + attributes.push( { + attribute: attributeName, + value: select.value || '', } ); } ); From 049ec123c155afc6b24f425f26bb3fd6195f5801 Mon Sep 17 00:00:00 2001 From: frosso Date: Wed, 12 Feb 2025 18:17:30 +0100 Subject: [PATCH 4/4] more compatibility --- .../compatibility/__tests__/wc-product-page.test.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js b/client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js index 6b74db0f020..feee04a80d9 100644 --- a/client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js +++ b/client/tokenized-express-checkout/compatibility/__tests__/wc-product-page.test.js @@ -96,8 +96,12 @@ describe( 'ECE product page compatibility', () => { - - : Medium +