Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jasmine: how to spy on inner object method call?

I have two prototypes I want to test:

var Person = function() {};

Person.prototype.pingChild = function(){
   var boy = new Child();
   boy.getAge();
}

var Child = function() {};

Child.prototype.getAge = function() {
    return 42;
};

What exactly I want to test: to check that getAge() method is called inside of the pingChild() method

That is Jasmine specs I try to use for this purpose:

describe("Person", function() {
    it("calls the getAge() function", function() {
        var fakePerson = new Person();
        var chi = new Child();
        spyOn(fakePerson, "getAge");
        fakePerson.pingChild();
        expect(chi.getAge).toHaveBeenCalled();
    });
});

describe("Person", function() {
    it("calls the getAge() function", function() {
        var fakePerson = new Person();
        spyOn(fakePerson, "getAge");
        fakePerson.pingChild();
        expect(fakePerson.getAge).toHaveBeenCalled();
    });
});

describe("Person", function() {
    it("calls the getAge() function", function() {
        var fakePerson = new Person();
        var chi = new Child();
        spyOn(chi, "getAge");
        fakePerson.pingChild();
        expect(chi.getAge).toHaveBeenCalled();
    });
});

but all of them shows just errors:

  • getAge() method does not exist
  • getAge() method does not exist
  • Expected spy getAge to have been called

So, is there any way to test such cases using Jasmine, and if yes - how can it be done?

like image 532
Victoria Agafonova Avatar asked Aug 28 '13 09:08

Victoria Agafonova


2 Answers

You have yo spy on the prototype of Child object.

describe("Person", function () {
  it("calls the getAge() function", function () {
    var spy = spyOn(Child.prototype, "getAge");
    var fakePerson = new Person();
    fakePerson.pingChild();
    expect(spy).toHaveBeenCalled();
  });
});
like image 102
Andreas Köberle Avatar answered Oct 28 '22 10:10

Andreas Köberle


I don't think it's possible because inner object is not accesible from outside the parent object. It's all about the scope of your objects.

You could either expose your Child object in Person object by doing this:

var Person = function() {
    this.boy = new Child();
};

Person.prototype.pingChild = function(){
   this.boy.getAge();
}

And then:

describe("Person", function() {
    it("calls the getAge() function", function() {
        var fakePerson = new Person();
        var chi = fakePerson.boy;
        spyOn(chi, "getAge");
        fakePerson.pingChild();
        expect(chi.getAge).toHaveBeenCalled();
    });
});

Or delegate the initialization of the Child outside the Person object:

var Person = function(child) {
    this.boy = child;
};

Person.prototype.pingChild = function(){
   this.boy.getAge();
}

And then:

describe("Person", function() {
    it("calls the getAge() function", function() {
        var chi = new Child();
        var fakePerson = new Person(chi);
        spyOn(chi, "getAge");
        fakePerson.pingChild();
        expect(chi.getAge).toHaveBeenCalled();
    });
});
like image 39
margabit Avatar answered Oct 28 '22 10:10

margabit