forcedotcom / LightningTestingService

Apache License 2.0
122 stars 35 forks source link

chain spyOn? #77

Closed tylerzika closed 4 years ago

tylerzika commented 6 years ago

When my component loads, I make multiple calls to the server. I'm not sure how to test this. The server calls are as follows:

c:pageContainer -> getOrderInvite()

getOrderInvite() then loads the component

c:shippingAddressUpdateForm -> getShippingDestinationList()

getShippingDestinationList() -> getCountryStatePicklistValues()

So three server calls are enqueued in a chain when my app loads: getOrderInvite() -> getShippingDestinationList() -> getCountryStatePicklistValues()

This is my attempt on chaining spyOn, but it doesn't appear to work.

    describe('c:pageContainer', function(){     
        it('should show the shipping address form', function(done) {
            $T.createComponent("c:pageContainer", {code: "S3UYMUTY"}, true)
            .then(function(component){ 

                var orderInvite = {
                    "Id": "a0Ff0000003FIUEEA4",
                    "Account__c": "001f000000naH9iAAE",
                    "Order_Code__c": "S3UYMUTY",
                    "Order__c": "a09f0000003Bm2jAAC",
                    "Account__r": {
                        "Order_Pickup__c": true,
                        "Id": "001f000000naH9iAAE"
                    },
                    "Order__r": {
                        "Shipping_First_Name__c": "Tyler",
                        "Shipping_Name__c": "Zikaa",
                        "Shipping_Company__c": "55 Degrees",
                        "Shipping_Country__c": "United States of America",
                        "Shipping_State__c": "Alaska",
                        "Shipping_Address__c": "1210 Church St.",
                        "Shipping_City__c": "St. Helena",
                        "Shipping_Phone__c": "7079635513",
                        "Shipping_Zip_Postal__c": "39232",
                        "Status__c": "Complete",
                        "Shipping_Sent__c": true,
                        "No_Wooden_Box__c": true,
                        "Pickup__c": false,
                        "Id": "a09f0000003Bm2jAAC"
                    }
                };

                var res = {getState : function(){return "SUCCESS";}, getReturnValue: function(){return orderInvite;}};
                spyOn($A, "enqueueAction").and.callFake(function(action1) {
                    var cb = action1.getCallback("SUCCESS")
                    cb.fn.apply(cb.s, [res]);

                    var shippingDestinationList = [
                        {
                          "disabled": false,
                          "escapeItem": false,
                          "label": "55 Degrees",
                          "selected": false,
                          "value": "a0Bf00000036M36EAE"
                        },
                        {
                          "disabled": false,
                          "escapeItem": false,
                          "label": "Pickup/Local Delivery",
                          "selected": false,
                          "value": "1"
                        },
                        {
                          "disabled": false,
                          "escapeItem": false,
                          "label": "Ship To Address Below",
                          "selected": true,
                          "value": "0"
                        }
                      ]
                    var res = {getState : function(){return "SUCCESS";}, getReturnValue: function(){return shippingDestinationList;}};
                    spyOn($A, "enqueueAction").and.callFake(function(action2) {
                        var cb = action2.getCallback("SUCCESS")
                        cb.fn.apply(cb.s, [res]);

                        var countryStateListOptions = {
                            "Czech Republic": [
                              {
                                "disabled": false,
                                "escapeItem": false,
                                "label": "Outside US",
                                "selected": false,
                                "value": "Outside US"
                              }
                            ],
                            "Canada": [
                              {
                                "disabled": false,
                                "escapeItem": false,
                                "label": "Alberta",
                                "selected": false,
                                "value": "Alberta"
                              }
                            ],
                            "United States of America": [
                              {
                                "disabled": false,
                                "escapeItem": false,
                                "label": "Alabama",
                                "selected": false,
                                "value": "Alabama"
                              },
                              {
                                "disabled": false,
                                "escapeItem": false,
                                "label": "California",
                                "selected": true,
                                "value": "California"
                              },
                              {
                                "disabled": false,
                                "escapeItem": false,
                                "label": "Oregon",
                                "selected": false,
                                "value": "Oregon"
                              },
                              {
                                "disabled": false,
                                "escapeItem": false,
                                "label": "Alaska",
                                "selected": false,
                                "value": "Alaska"
                              }
                            ]
                          }
                        var res = {getState : function(){return "SUCCESS";}, getReturnValue: function(){return countryStateListOptions;}};
                        spyOn($A, "enqueueAction").and.callFake(function(action3) {
                            var cb = action3.getCallback("SUCCESS")
                            cb.fn.apply(cb.s, [res]);
                        }); 
                    }); 

                });    
                return $T.waitFor(function(){
                    return component.get("v.body").length === 1;
                })
            }).then(function() {
                expect(component.get("v.body").length).toBe(1);                
                done();
            }).catch(function(e) {
                done.fail(e);
            });              
        });
    });

All these server calls need to happen in order to load c:shippingAddressUpdateForm into the v.body of c:pageContainer, which is what I'm testing for.

I'm currently getting

Error: Error in $A.getCallback() [Cannot read property 'getState' of undefined] so the server response.getState() isn't being set properly in my chain.

alec-ng commented 6 years ago

I think your use case will need to use spyOn(f).and.returnValues()

https://jasmine.github.io/2.4/introduction.html#section-Spies:_%3Ccode%3Eand.returnValues%3C/code%3E

I haven't tried this myself, but the idea is to define n number of return values equivalent to the number of callouts your method will do. If you have 3 server calls when your component initializes, you would define three separate return values (in the order you would expect the callouts to be in).

joseph-ortiz commented 6 years ago

i was in a similar situation testing 3 server calls but I had to make three server calls made in the same component and accomplished it by using action.getName() in the spyOn() callback and branch the response based on the action name.

Note: it does add branching logic to your test which can make your code more complex. Still kind of a newbie at Jasmine so I'm not sure if writing your test like this a good practice or not.

spyOn($A, "enqueueAction").and.callFake(function (action) {

     var res = {
         getState: function () {
             return "SUCCESS";
         }
     };
     var cb = action.getCallback("SUCCESS");

     if (action.getName() == 'loadAccount') {
         res.getReturnValue = function () {
             return [{
                 "Name": "Acct 1",
             }];
         }
     } else if (action.getName() == 'loadOrder') {
         res.getReturnValue = function () {
             return [{
                 "Name": "Order 1",
             }];
         }
     };
     cb.fn.apply(cb.s, [res]);
 });