Commit 2ec15024ee7 for woocommerce
commit 2ec15024ee73e153adcbe9242c62a434bfe7e2af
Author: Sanket Parmar <sanket.parmar11@gmail.com>
Date: Fri Oct 16 14:24:08 2026 +0530
Show Cart cross-sells add-to-cart errors in the Cart block notices (#69851)
Show cross-sell add-to-cart errors in Cart block
diff --git a/plugins/woocommerce/changelog/69816-fix-cart-cross-sells-add-error-notice b/plugins/woocommerce/changelog/69816-fix-cart-cross-sells-add-error-notice
new file mode 100644
index 00000000000..003b542dcd1
--- /dev/null
+++ b/plugins/woocommerce/changelog/69816-fix-cart-cross-sells-add-error-notice
@@ -0,0 +1,4 @@
+Significance: patch
+Type: fix
+
+Show an error when a product from the Cart block's cross-sells list cannot be added to the cart, on Cart pages using the cross-sells inner block.
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-store-add-to-cart.ts b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-store-add-to-cart.ts
new file mode 100644
index 00000000000..2ea6d5f5606
--- /dev/null
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/test/use-store-add-to-cart.ts
@@ -0,0 +1,62 @@
+/**
+ * External dependencies
+ */
+import { act, renderHook } from '@testing-library/react';
+import { useDispatch } from '@wordpress/data';
+
+/**
+ * Internal dependencies
+ */
+import { useStoreAddToCart } from '../use-store-add-to-cart';
+
+jest.mock( '@wordpress/data', () => ( {
+ ...jest.requireActual( '@wordpress/data' ),
+ useDispatch: jest.fn(),
+} ) );
+
+jest.mock( '../cart/use-store-cart', () => ( {
+ useStoreCart: () => ( { cartItems: [], cartIsLoading: false } ),
+} ) );
+
+describe( 'useStoreAddToCart', () => {
+ const createErrorNotice = jest.fn();
+
+ beforeEach( () => {
+ createErrorNotice.mockClear();
+ ( useDispatch as jest.Mock ).mockReturnValue( {
+ addItemToCart: jest
+ .fn()
+ .mockRejectedValue( new Error( 'Out of stock' ) ),
+ createErrorNotice,
+ removeNotice: jest.fn(),
+ } );
+ } );
+
+ it( 'shows add to cart errors in the All Products context by default', async () => {
+ const { result } = renderHook( () => useStoreAddToCart( 1 ) );
+
+ await act( async () => {
+ await result.current.addToCart();
+ } );
+
+ expect( createErrorNotice ).toHaveBeenCalledWith(
+ 'Out of stock',
+ expect.objectContaining( { context: 'wc/all-products' } )
+ );
+ } );
+
+ it( 'shows add to cart errors in the given notice context', async () => {
+ const { result } = renderHook( () =>
+ useStoreAddToCart( 1, 'wc/cart' )
+ );
+
+ await act( async () => {
+ await result.current.addToCart();
+ } );
+
+ expect( createErrorNotice ).toHaveBeenCalledWith(
+ 'Out of stock',
+ expect.objectContaining( { context: 'wc/cart' } )
+ );
+ } );
+} );
diff --git a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/use-store-add-to-cart.ts b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/use-store-add-to-cart.ts
index a42d55b3491..436718f64b6 100644
--- a/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/use-store-add-to-cart.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/base/context/hooks/use-store-add-to-cart.ts
@@ -43,12 +43,16 @@ const getQuantityFromCartItems = (
* action for adding a single quantity of the product _to_ the cart.
*
*
- * @param {number} productId The product id to be added to the cart.
+ * @param {number} productId The product id to be added to the cart.
+ * @param {string} noticeContext The notice context that shows add to cart errors.
*
* @return {StoreCartItemAddToCart} An object exposing data and actions relating
* to add to cart functionality.
*/
-export const useStoreAddToCart = ( productId: number ): StoreAddToCart => {
+export const useStoreAddToCart = (
+ productId: number,
+ noticeContext = 'wc/all-products'
+): StoreAddToCart => {
const { addItemToCart } = useDispatch( cartStore );
const { cartItems, cartIsLoading } = useStoreCart();
const { createErrorNotice, removeNotice } = useDispatch( 'core/notices' );
@@ -62,12 +66,12 @@ export const useStoreAddToCart = ( productId: number ): StoreAddToCart => {
setAddingToCart( true );
return addItemToCart( productId, quantity )
.then( () => {
- removeNotice( 'add-to-cart' );
+ removeNotice( 'add-to-cart', noticeContext );
} )
.catch( ( error ) => {
createErrorNotice( decodeEntities( error.message ), {
id: 'add-to-cart',
- context: 'wc/all-products',
+ context: noticeContext,
isDismissible: true,
} );
} )
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/cart/cart-cross-sells-product-list/cart-cross-sells-product.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/cart/cart-cross-sells-product-list/cart-cross-sells-product.tsx
index e362a5baa89..dd37f9a5e6a 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/cart/cart-cross-sells-product-list/cart-cross-sells-product.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/cart/cart-cross-sells-product-list/cart-cross-sells-product.tsx
@@ -6,6 +6,7 @@ import {
ProductDataContextProvider,
} from '@woocommerce/shared-context';
import { ProductResponseItem } from '@woocommerce/types';
+import { noticeContexts } from '@woocommerce/base-context';
/**
* Internal dependencies
@@ -60,7 +61,7 @@ const CartCrossSellsProduct = ( {
/>
<ProductPrice />
</div>
- <ProductButton />
+ <ProductButton noticeContext={ noticeContexts.CART } />
</ProductDataContextProvider>
</InnerBlockLayoutContextProvider>
</div>
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/block.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/block.tsx
index bd323c9eb70..c7ac25d3465 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/block.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/block.tsx
@@ -118,6 +118,7 @@ export const AddToCartButton = ( {
className,
style,
collection,
+ noticeContext,
}: AddToCartButtonAttributes ): JSX.Element => {
const {
id,
@@ -128,7 +129,10 @@ export const AddToCartButton = ( {
is_in_stock: isInStock,
} = product;
const { dispatchStoreEvent } = useStoreEvents();
- const { cartQuantity, addingToCart, addToCart } = useStoreAddToCart( id );
+ const { cartQuantity, addingToCart, addToCart } = useStoreAddToCart(
+ id,
+ noticeContext
+ );
const addedToCart = Number.isFinite( cartQuantity ) && cartQuantity > 0;
// Check if this is a cart-contents collection
@@ -356,6 +360,7 @@ export const Block = ( props: BlockAttributes ): JSX.Element => {
}
productEntity={ props.product }
collection={ collection }
+ noticeContext={ props.noticeContext }
/>
) : (
<AddToCartButtonPlaceholder
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/test/block.test.tsx b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/test/block.test.tsx
index 62d94907a7a..92a0023792c 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/test/block.test.tsx
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/test/block.test.tsx
@@ -96,6 +96,12 @@ describe( 'AddToCartButton', () => {
expect( link ).toHaveAttribute( 'href', '/cart/' );
expect( link ).toHaveAttribute( 'rel', 'nofollow' );
} );
+
+ it( 'passes the notice context to the add to cart hook', () => {
+ renderButton( { noticeContext: 'wc/cart' } );
+
+ expect( useStoreAddToCart ).toHaveBeenCalledWith( 1, 'wc/cart' );
+ } );
} );
describe( 'Product Button spacing', () => {
diff --git a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/types.ts b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/types.ts
index 372ba28a9dd..e4161c19707 100644
--- a/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/types.ts
+++ b/plugins/woocommerce/client/blocks/assets/js/blocks/product-elements-blocks/button/types.ts
@@ -21,6 +21,7 @@ export interface BlockAttributes {
product?: ProductEntityResponse | undefined;
isAdmin?: boolean | undefined;
collection?: string | undefined;
+ noticeContext?: string | undefined;
}
export interface AddToCartProductDetails {
@@ -53,4 +54,5 @@ export interface AddToCartButtonAttributes {
};
textAlign?: ( WithClass & WithStyle ) | undefined;
collection?: string | undefined;
+ noticeContext?: string | undefined;
}