Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test a function in a component that calls method to parent component

Hello stackoverflow community.

I am working on an Angular project (1.5.6), using a component structure and currently writing some unit tests. I am still learning a lot about unit tests – especially in relation with Angular – and was hoping I can ask you for help for the following issue:

I try to test a component, that receives a callback method from it's parent component. I am trying to mock the method foo (see below the code example). And unfortunately does this method call the parent controller.

So when I try to test it, it complains, that the method is undefined. Then I thought I could mock it with spyOn, but then I get the error Error: <spyOn> : foobar() method does not exist

So I think I am unable to mock that method.

Module:

angular.module("myApp")
.component("sample", {
    "templateUrl": "components/sample/sample.html",
    "controller": "SampleController",
    "controllerAs": "sampleCtrl",
    "bindings": {
        "config": "<",
        "foobar": "&"
    }
})
.controller("SampleController",
           ["$scope",
    function($scope) {
        this.isActive = true;

        this.foo = function() {
             // do stuff
             this.isActive = false;

             // also do
             this.foobar();
        };
    }
);

Unit Test

describe("Component: SampleComponent", function() {

    beforeEach(module("myApp"));

    var sampleComponent, scope, $httpBackend;

    beforeEach(inject(function($componentController, $rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        sampleComponent = $componentController("sample", {
            "$scope": scope
        }); 
        $httpBackend = _$httpBackend_;
    }));

    it("should do set isActive to false on 'foo' and call method...", function() {
        spyOn(sampleComponent, "foobar")

        expect(sampleComponent.isActive).toBe(true);
        expect(sampleComponent).toBe("");
        expect(sampleComponent.foobar).not.toHaveBeenCalled();

        sampleComponent.foo();

        expect(sampleComponent.foobar).toHaveBeenCalled();
        expect(sampleComponent.foobar.calls.count()).toBe(1);
        expect(sampleComponent.isActive).toBe(false);
    });
});

I hope I didn't add any bugs to this, but this above is approximately what I am trying to do. Any suggestions are welcome and if the approach is wrong or more information needed, please let me know!

like image 362
skofgar Avatar asked Jan 29 '26 01:01

skofgar


1 Answers

After the help from @estus (see comments in question) - I learned that I can use createSpy to resolve this issue.

    it("should do set isActive to false on 'foo' and call method...", function() {
        sampleComponent.foobar = jasmine.createSpy();

        expect(sampleComponent.isActive).toBe(true);
        expect(sampleComponent).toBe("");
        expect(sampleComponent.foobar).not.toHaveBeenCalled();

        sampleComponent.foo();

        expect(sampleComponent.foobar).toHaveBeenCalled();
        expect(sampleComponent.foobar.calls.count()).toBe(1);
        expect(sampleComponent.isActive).toBe(false);
    });

Some additional sources I used were:

  • http://angular-tips.com/blog/2014/03/introduction-to-unit-test-spies/
  • How does the createSpy work in Angular + Jasmine?
like image 102
skofgar Avatar answered Jan 31 '26 19:01

skofgar



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!