ramana
ramana

Reputation: 48

Code coverage for service call success response in karma

I have a function like this

$scope.openMail=function(mail){
      DocumentTypes.getDocument(function(response){
          $scope.documentTypes=response.result;
          $log.log("documentTypes",$scope.documentTypes);
          })
}

Spec for above fun is

it("should test open mail", function(){
    scope.documentTypes=[{"type":"pdf"},{"type":"xml"}];
    spyOn(documentTypes,"getDocument").and.callFake(function(){
      return scope.documentTypes;
    });
    var mail='back';
    scope.openMail(mail);
    expect(scope.documentTypes).toEqual({"type":"pdf"},{"type":"xml"});


  })

so the code is not covering for function(response){}

so the code is not covering code for <code>function(response){}</code> How can i cover this code in my code coverage? Thanks.

Upvotes: 4

Views: 682

Answers (3)

ethanfar
ethanfar

Reputation: 3778

You have several problems with your test:

  1. You do spyOn(documentTypes,"getDocument") instead of spyOn(DocumentTypes,"getDocument")
  2. Your fake function returns a value (synchronous) rather than call the provided callback (asynchronous)
  3. You start off by initializing scope.documentTypes to the expected result of the test, i.e. the test passes no matter what the code does (unless you get an exception)
  4. More of a problem with your code - The function you're testing does nothing with the input mail parameter

Here's how I would test it:

describe('$scope.openMail', function() {
    beforeEach(function() {
        spyOn(DocumentTypes, 'getDocument');
    });

    it('uses DocumentTypes.getDocument service to get the document types', function() {
        $scope.openMail('test_mail');

        expect(DocumentTypes.getDocument).toHaveBeenCalledWith(jasmine.any(Function));
    });

    describe('provides a callback function that', function() {
        beforeEach(function() {
            DocumentTypes.getDocument.and.callFake(function (callback) {
                callback('test_document_types');
            });
        });

        it('stores the document types on the scope', function() {           
            $scope.openMail('test_mail');

            expect($scope.documentTypes).toEqual('test_document_types');
        });

        // Note: This is optional, depending on whether you test logging or not
        it('logs the document types', function() {           
            spyOn($log, 'log');

            $scope.openMail('test_mail');

            expect($log.log).toHaveBeenCalledWith('documentTypes', 'test_document_types');
        });
    });
});

Upvotes: 2

Marcus
Marcus

Reputation: 350

Assuming you are injecting DocumentTypes into your controller or whatever you have that openMail function in, you can mock it when performing tests. One way of doing that could be to use the $provide service.

This mock could look like this if using karma-chai-spies:

stubs = {
    DocumentTypes: {
        getDocument: chai.spy(function(callback)
        {
            callback({
                result: [
                    "type"
                ]
            });
        })
    }
};

Then provide it using $provide in your unit tests:

beforeEach(function()
{
    module(function($provide)
    {
        $provide.value("DocumentTypes", stubs.DocumentTypes);
    });
});

The test itself could then look something like this using karma-mocha and karma-chai:

it("should test open mail", function()
{
    var controller = $controller('myController', {
        $scope: stubs.$scope
    });

    stubs.$scope.openMail("mail");

    expect(stubs.$scope.documentTypes).to.deep.equal([
        "type"
    ]);
    expect(stubs.DocumentTypes.getDocument).to.have.been.called.once();
});

Upvotes: 0

mindparse
mindparse

Reputation: 7265

I could be totally wrong here, but if that call to DocumentTypes.getDocument(...) is an async call you may need to trigger a digest cycle by calling scope.apply() just after you call scope.openMail(mail)

Upvotes: 0

Related Questions