1414 * limitations under the License.
1515 */
1616import { describe , test , expect , vi , beforeEach } from 'vitest' ;
17- import { render , screen , waitFor } from '@testing-library/react' ;
17+ import { render , screen , fireEvent , waitFor } from '@testing-library/react' ;
1818import { getTranslation } from '@salesforce/storefront-next-runtime/i18n' ;
1919
2020const { t } = getTranslation ( ) ;
@@ -168,7 +168,7 @@ describe('CartContent', () => {
168168 } ) ;
169169
170170 describe ( 'Line item secondary actions' , ( ) => {
171- test ( 'renders remove and wishlist controls for each cart item with itemId' , async ( ) => {
171+ test ( 'renders remove, edit, and wishlist controls for each cart item with itemId' , async ( ) => {
172172 renderCartContent ( {
173173 basket : mockBasket ,
174174 productsByItemId : mockProductMap ,
@@ -177,6 +177,8 @@ describe('CartContent', () => {
177177
178178 expect ( screen . getByTestId ( 'remove-item-item-1' ) ) . toBeInTheDocument ( ) ;
179179 expect ( screen . getByTestId ( 'remove-item-item-2' ) ) . toBeInTheDocument ( ) ;
180+ expect ( screen . getByTestId ( 'edit-item-item-1' ) ) . toBeInTheDocument ( ) ;
181+ expect ( screen . getByTestId ( 'edit-item-item-2' ) ) . toBeInTheDocument ( ) ;
180182 expect ( await screen . findByTestId ( 'cart-add-wishlist-item-1' ) ) . toBeInTheDocument ( ) ;
181183 expect ( await screen . findByTestId ( 'cart-add-wishlist-item-2' ) ) . toBeInTheDocument ( ) ;
182184 } ) ;
@@ -197,8 +199,10 @@ describe('CartContent', () => {
197199 } ) ;
198200
199201 expect ( screen . queryByTestId ( 'remove-item-item-1' ) ) . not . toBeInTheDocument ( ) ;
202+ expect ( screen . queryByTestId ( 'edit-item-item-1' ) ) . not . toBeInTheDocument ( ) ;
200203 expect ( screen . queryByTestId ( 'cart-add-wishlist-item-1' ) ) . not . toBeInTheDocument ( ) ;
201204 expect ( screen . getByTestId ( 'remove-item-item-2' ) ) . toBeInTheDocument ( ) ;
205+ expect ( screen . getByTestId ( 'edit-item-item-2' ) ) . toBeInTheDocument ( ) ;
202206 expect ( await screen . findByTestId ( 'cart-add-wishlist-item-2' ) ) . toBeInTheDocument ( ) ;
203207 } ) ;
204208
@@ -269,4 +273,191 @@ describe('CartContent', () => {
269273 expect ( screen . queryByTestId ( 'cart-add-wishlist-item-1' ) ) . not . toBeInTheDocument ( ) ;
270274 } ) ;
271275 } ) ;
276+
277+ describe ( 'CartItemEditButton Integration' , ( ) => {
278+ test ( 'renders edit buttons for each cart item' , ( ) => {
279+ renderCartContent ( {
280+ basket : mockBasket ,
281+ productsByItemId : mockProductMap ,
282+ bonusProductsById : mockBonusProductsById ,
283+ } ) ;
284+
285+ expect ( screen . getByTestId ( 'edit-item-item-1' ) ) . toBeInTheDocument ( ) ;
286+ expect ( screen . getByTestId ( 'edit-item-item-2' ) ) . toBeInTheDocument ( ) ;
287+
288+ const editButtons = screen . getAllByText ( t ( 'actionCard:edit' ) ) ;
289+ expect ( editButtons ) . toHaveLength ( 2 ) ;
290+ } ) ;
291+
292+ test ( 'applies correct className to edit buttons' , ( ) => {
293+ renderCartContent ( {
294+ basket : mockBasket ,
295+ productsByItemId : mockProductMap ,
296+ bonusProductsById : mockBonusProductsById ,
297+ } ) ;
298+
299+ const editButton1 = screen . getByTestId ( 'edit-item-item-1' ) ;
300+ const editButton2 = screen . getByTestId ( 'edit-item-item-2' ) ;
301+
302+ expect ( editButton1 ) . toHaveClass ( 'pl-0' ) ;
303+ expect ( editButton2 ) . toHaveClass ( 'pl-0' ) ;
304+ } ) ;
305+
306+ test ( 'opens product modal when edit button is clicked' , ( ) => {
307+ renderCartContent ( {
308+ basket : mockBasket ,
309+ productsByItemId : mockProductMap ,
310+ bonusProductsById : mockBonusProductsById ,
311+ } ) ;
312+
313+ expect ( screen . queryByRole ( 'dialog' ) ) . not . toBeInTheDocument ( ) ;
314+
315+ const editButton = screen . getByTestId ( 'edit-item-item-1' ) ;
316+ fireEvent . click ( editButton ) ;
317+
318+ expect ( screen . getByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ;
319+ expect ( screen . getByText ( t ( 'editItem:title' ) ) ) . toBeInTheDocument ( ) ;
320+ } ) ;
321+
322+ test ( 'can close modal using close button' , ( ) => {
323+ renderCartContent ( {
324+ basket : mockBasket ,
325+ productsByItemId : mockProductMap ,
326+ bonusProductsById : mockBonusProductsById ,
327+ } ) ;
328+
329+ const editButton = screen . getByTestId ( 'edit-item-item-1' ) ;
330+ fireEvent . click ( editButton ) ;
331+
332+ expect ( screen . getByRole ( 'dialog' ) ) . toBeInTheDocument ( ) ;
333+
334+ const closeButton = screen . getByRole ( 'button' , { name : / c l o s e / i } ) ;
335+ fireEvent . click ( closeButton ) ;
336+
337+ expect ( screen . queryByRole ( 'dialog' ) ) . not . toBeInTheDocument ( ) ;
338+ } ) ;
339+
340+ test ( 'does not render edit buttons when product has no itemId' , ( ) => {
341+ const basketWithoutItemIds = {
342+ ...mockBasket ,
343+ productItems : [
344+ { quantity : 2 , productId : 'product-1' } ,
345+ { itemId : 'item-2' , quantity : 1 , productId : 'product-2' } ,
346+ ] ,
347+ } ;
348+
349+ renderCartContent ( {
350+ basket : basketWithoutItemIds ,
351+ productsByItemId : mockProductMap ,
352+ bonusProductsById : mockBonusProductsById ,
353+ } ) ;
354+
355+ expect ( screen . queryByTestId ( 'edit-item-item-1' ) ) . not . toBeInTheDocument ( ) ;
356+ expect ( screen . getByTestId ( 'edit-item-item-2' ) ) . toBeInTheDocument ( ) ;
357+ } ) ;
358+ } ) ;
359+
360+ describe ( 'Edit button visibility (CartItemEditButton presence)' , ( ) => {
361+ function renderWith ( productsByItemId : Record < string , any > ) {
362+ const basket = {
363+ basketId : 'b1' ,
364+ productItems : [ { itemId : 'item-1' , quantity : 1 , productId : 'p1' } ] ,
365+ } ;
366+ return renderCartContent ( { basket, productsByItemId, bonusProductsById : mockBonusProductsById } ) ;
367+ }
368+
369+ const editBtn = ( ) => screen . queryByTestId ( 'edit-item-item-1' ) ;
370+
371+ test ( 'standard product does not show CartItemEditButton' , ( ) => {
372+ renderWith ( { 'item-1' : { id : 'p1' , type : { item : true } } } as any ) ;
373+ expect ( editBtn ( ) ) . not . toBeInTheDocument ( ) ;
374+ } ) ;
375+
376+ test ( 'product with variants shows CartItemEditButton' , ( ) => {
377+ renderWith ( { 'item-1' : { id : 'p1' , variants : [ { } as any ] } } as any ) ;
378+ expect ( editBtn ( ) ) . toBeInTheDocument ( ) ;
379+ } ) ;
380+
381+ test ( 'missing product details mapping shows CartItemEditButton' , ( ) => {
382+ const basket = { basketId : 'b1' , productItems : [ { itemId : 'item-1' , quantity : 1 , productId : 'p1' } ] } ;
383+ renderCartContent ( {
384+ basket,
385+ productsByItemId : { } as any ,
386+ bonusProductsById : mockBonusProductsById ,
387+ } ) ;
388+ expect ( editBtn ( ) ) . toBeInTheDocument ( ) ;
389+ } ) ;
390+
391+ test ( 'bundle product shows CartItemEditButton' , ( ) => {
392+ renderWith ( { 'item-1' : { id : 'p1' , type : { bundle : true } } } as any ) ;
393+ expect ( editBtn ( ) ) . toBeInTheDocument ( ) ;
394+ } ) ;
395+
396+ test ( 'parent product shows CartItemEditButton' , ( ) => {
397+ renderWith ( { 'item-1' : { id : 'p1' , type : { master : true } } } as any ) ;
398+ expect ( editBtn ( ) ) . toBeInTheDocument ( ) ;
399+ } ) ;
400+
401+ test ( 'choice-based bonus product does not show CartItemEditButton' , ( ) => {
402+ const basket = {
403+ basketId : 'b1' ,
404+ productItems : [
405+ {
406+ itemId : 'item-1' ,
407+ quantity : 1 ,
408+ productId : 'p1' ,
409+ bonusProductLineItem : true ,
410+ bonusDiscountLineItemId : 'bonus-discount-choice-1' ,
411+ } ,
412+ ] ,
413+ bonusDiscountLineItems : [
414+ {
415+ id : 'bonus-discount-choice-1' ,
416+ promotionId : 'promo-choice-1' ,
417+ maxBonusItems : 3 ,
418+ bonusProducts : [ { productId : 'p1' , productName : 'Choice Bonus Product 1' } ] ,
419+ } ,
420+ ] ,
421+ } ;
422+
423+ renderCartContent ( {
424+ basket : basket as any ,
425+ productsByItemId : { 'item-1' : { id : 'p1' , variants : [ { } as any ] } } as any ,
426+ bonusProductsById : { p1 : { id : 'p1' , name : 'Choice Bonus Product 1' } } as any ,
427+ } ) ;
428+
429+ expect ( editBtn ( ) ) . not . toBeInTheDocument ( ) ;
430+ expect ( screen . getByTestId ( 'remove-item-item-1' ) ) . toBeInTheDocument ( ) ;
431+ } ) ;
432+
433+ test ( 'auto bonus product does not show CartItemEditButton' , ( ) => {
434+ const basket = {
435+ basketId : 'b1' ,
436+ productItems : [
437+ {
438+ itemId : 'item-1' ,
439+ quantity : 1 ,
440+ productId : 'p1' ,
441+ bonusProductLineItem : true ,
442+ bonusDiscountLineItemId : 'bonus-discount-auto-1' ,
443+ } ,
444+ ] ,
445+ bonusDiscountLineItems : [
446+ {
447+ id : 'bonus-discount-auto-1' ,
448+ promotionId : 'promo-auto-1' ,
449+ maxBonusItems : 1 ,
450+ } ,
451+ ] ,
452+ } ;
453+
454+ renderCartContent ( {
455+ basket : basket as any ,
456+ productsByItemId : { 'item-1' : { id : 'p1' , variants : [ { } as any ] } } as any ,
457+ bonusProductsById : mockBonusProductsById ,
458+ } ) ;
459+
460+ expect ( editBtn ( ) ) . not . toBeInTheDocument ( ) ;
461+ } ) ;
462+ } ) ;
272463} ) ;
0 commit comments