@@ -667,6 +667,123 @@ describe('shouldShowSimpleProductOutOfStockButton', () => {
667667 } ) ;
668668} ) ;
669669
670+ const configurableSparseVariantMissingChildStockStatusProps = {
671+ ...defaultProps ,
672+ product : {
673+ ...defaultProps . product ,
674+ __typename : 'ConfigurableProduct' ,
675+ stock_status : 'IN_STOCK' ,
676+ media_gallery_entries : [ ] ,
677+ price_range : {
678+ maximum_price : {
679+ final_price : {
680+ value : 10 ,
681+ currency : 'USD'
682+ } ,
683+ discount : {
684+ amount_off : 0
685+ }
686+ }
687+ } ,
688+ configurable_options : [
689+ {
690+ attribute_code : 'color' ,
691+ attribute_id : '179' ,
692+ id : 1 ,
693+ label : 'Color' ,
694+ values : [
695+ {
696+ __typename : 'ConfigurableProductOptionsValues' ,
697+ uid : 'c1' ,
698+ default_label : 'A' ,
699+ label : 'A' ,
700+ store_label : 'A' ,
701+ use_default_value : true ,
702+ value_index : 10 ,
703+ swatch_data : null ,
704+ media_gallery_entries : [ ]
705+ } ,
706+ {
707+ __typename : 'ConfigurableProductOptionsValues' ,
708+ uid : 'c2' ,
709+ default_label : 'B' ,
710+ label : 'B' ,
711+ store_label : 'B' ,
712+ use_default_value : true ,
713+ value_index : 11 ,
714+ swatch_data : null ,
715+ media_gallery_entries : [ ]
716+ }
717+ ]
718+ } ,
719+ {
720+ attribute_code : 'size' ,
721+ attribute_id : '190' ,
722+ id : 2 ,
723+ label : 'Size' ,
724+ values : [
725+ {
726+ __typename : 'ConfigurableProductOptionsValues' ,
727+ uid : 's1' ,
728+ default_label : 'S' ,
729+ label : 'S' ,
730+ store_label : 'S' ,
731+ use_default_value : true ,
732+ value_index : 100 ,
733+ swatch_data : null ,
734+ media_gallery_entries : [ ]
735+ } ,
736+ {
737+ __typename : 'ConfigurableProductOptionsValues' ,
738+ uid : 's2' ,
739+ default_label : 'M' ,
740+ label : 'M' ,
741+ store_label : 'M' ,
742+ use_default_value : true ,
743+ value_index : 101 ,
744+ swatch_data : null ,
745+ media_gallery_entries : [ ]
746+ }
747+ ]
748+ }
749+ ] ,
750+ variants : [
751+ {
752+ __typename : 'ConfigurableVariant' ,
753+ attributes : [
754+ {
755+ code : 'color' ,
756+ value_index : 10 ,
757+ __typename : 'ConfigurableAttributeOption'
758+ } ,
759+ {
760+ code : 'size' ,
761+ value_index : 100 ,
762+ __typename : 'ConfigurableAttributeOption'
763+ }
764+ ] ,
765+ product : {
766+ __typename : 'SimpleProduct' ,
767+ sku : 'child-1' ,
768+ media_gallery_entries : [ ] ,
769+ price_range : {
770+ maximum_price : {
771+ final_price : {
772+ value : 10 ,
773+ currency : 'USD'
774+ } ,
775+ discount : {
776+ amount_off : 0
777+ }
778+ }
779+ } ,
780+ custom_attributes : [ ]
781+ }
782+ }
783+ ]
784+ }
785+ } ;
786+
670787describe ( 'shouldShowConfigurableProductOutOfStockButton' , ( ) => {
671788 test ( 'is false if product is in stock and no option is selected but disabled' , ( ) => {
672789 const tree = createTestInstance (
@@ -739,6 +856,34 @@ describe('shouldShowConfigurableProductOutOfStockButton', () => {
739856 expect ( talonProps . isOutOfStock ) . toBeTruthy ( ) ;
740857 expect ( talonProps . isAddToCartDisabled ) . toBeTruthy ( ) ;
741858 } ) ;
859+
860+ test ( 'is false when sparse catalog omits child stock_status but selection is salable' , ( ) => {
861+ const tree = createTestInstance (
862+ < Component
863+ { ...configurableSparseVariantMissingChildStockStatusProps }
864+ />
865+ ) ;
866+
867+ const { root } = tree ;
868+
869+ act ( ( ) => {
870+ root . findByType ( 'i' ) . props . talonProps . handleSelectionChange (
871+ '179' ,
872+ 10
873+ ) ;
874+ } ) ;
875+ act ( ( ) => {
876+ root . findByType ( 'i' ) . props . talonProps . handleSelectionChange (
877+ '190' ,
878+ 100
879+ ) ;
880+ } ) ;
881+
882+ const { talonProps } = root . findByType ( 'i' ) . props ;
883+
884+ expect ( talonProps . isOutOfStock ) . toBeFalsy ( ) ;
885+ expect ( talonProps . isAddToCartDisabled ) . toBeFalsy ( ) ;
886+ } ) ;
742887} ) ;
743888
744889describe ( 'shouldShowWishlistButton' , ( ) => {
@@ -1040,13 +1185,13 @@ test('calls generic mutation when no deprecated operation props are passed', asy
10401185 Object {
10411186 "variables": Object {
10421187 "cartId": "ThisIsMyCart",
1043- "entered_options": Array [
1044- Object {
1045- "uid": "NDA=",
1046- "value": "Strive Shoulder Pac",
1047- },
1048- ],
10491188 "product": Object {
1189+ "entered_options": Array [
1190+ Object {
1191+ "uid": "NDA=",
1192+ "value": "Strive Shoulder Pac",
1193+ },
1194+ ],
10501195 "quantity": 2,
10511196 "sku": "MySimpleProductSku",
10521197 },
@@ -1055,6 +1200,65 @@ test('calls generic mutation when no deprecated operation props are passed', asy
10551200 ` ) ;
10561201} ) ;
10571202
1203+ test ( 'sends selected_options inside product for configurable add to cart (no entered_options)' , async ( ) => {
1204+ const mockAddProductToCart = jest . fn ( ) . mockResolvedValue ( { } ) ;
1205+ let useMutationCall = 0 ;
1206+ // useProductFullDetail registers four useMutation hooks per render (configurable,
1207+ // simple, addProductToCart, createEmptyCart). Slot 2 is addProductsToCart.
1208+ useMutation . mockImplementation ( ( ) => {
1209+ const slot = useMutationCall % 4 ;
1210+ useMutationCall += 1 ;
1211+ if ( slot === 2 ) {
1212+ return [ mockAddProductToCart , { error : null , loading : false } ] ;
1213+ }
1214+ return [ jest . fn ( ) , { error : null , loading : false } ] ;
1215+ } ) ;
1216+
1217+ try {
1218+ const tree = createTestInstance (
1219+ < Component
1220+ product = { configurableProductWithTwoOptionGroupProps . product }
1221+ />
1222+ ) ;
1223+ const { root } = tree ;
1224+
1225+ act ( ( ) => {
1226+ root . findByType ( 'i' ) . props . talonProps . handleSelectionChange (
1227+ '179' ,
1228+ 14
1229+ ) ;
1230+ } ) ;
1231+ act ( ( ) => {
1232+ root . findByType ( 'i' ) . props . talonProps . handleSelectionChange (
1233+ '190' ,
1234+ 45
1235+ ) ;
1236+ } ) ;
1237+
1238+ await act ( async ( ) => {
1239+ await root . findByType ( 'i' ) . props . talonProps . handleAddToCart ( {
1240+ quantity : 1
1241+ } ) ;
1242+ } ) ;
1243+
1244+ expect ( mockAddProductToCart ) . toHaveBeenCalledTimes ( 1 ) ;
1245+ const { variables } = mockAddProductToCart . mock . calls [ 0 ] [ 0 ] ;
1246+ expect ( variables . product ) . toMatchObject ( {
1247+ sku : configurableProductWithTwoOptionGroupProps . product . sku ,
1248+ quantity : 1 ,
1249+ selected_options : [ '20' , '80' ]
1250+ } ) ;
1251+ expect ( variables . product . entered_options ) . toBeUndefined ( ) ;
1252+ } finally {
1253+ useMutation . mockImplementation ( ( ) => [
1254+ jest . fn ( ) ,
1255+ {
1256+ error : null
1257+ }
1258+ ] ) ;
1259+ }
1260+ } ) ;
1261+
10581262test ( 'it returns text when render prop is executed' , ( ) => {
10591263 const tree = createTestInstance ( < Component { ...defaultProps } /> ) ;
10601264 const { root } = tree ;
0 commit comments