Towercap
Towercap

Reputation: 175

Trying to access nested function, "undefined is not a function"

I'm working on some end-to-end tests using JavaScript (Protractor). I've got a PageObjects file that contains the following:

var SomeClass = function() {
    this.get = function() {
        browser.get('http://blah');
    };

    this.person = function() {
        var firstNameInput = element(by.id('firstName'));
        var lastNameInput = element(by.id('lastName'));

        this.setTitle = function(title) {
            element(by.xpath('//select[@id="title"]/option[text()="' + title +'"]')).click();
        };

        this.setFirstName = function(firstName) {
            firstNameInput.sendKeys(firstName);
        };

        this.setLastName = function(lastName) {
            lastNameInput.sendKeys(lastName);
        };
    };
};

module.exports = new SomeClass();

In my spec, I'm trying to access the nested function like this:

describe('some test', function() {
    var someClass = require('./some_class.po.js');
    var data = require('./some_class.data.json');

    it('do stuff', function() {
        someClass.get();
        someClass.person.setTitle(data.title);
        someClass.person.setFirstName(data.firstName);
        someClass.person.setLastName(data.lastName);
    });
});

When I try to run this test, the higher level someClass.get() works just fine, but when it attempts to execute someClass.person.setTitle(data.title), I get a Failed: undefined is not a function message.

Any idea what I'm doing wrong? I'm only using setters, no getters. Don't think I need to return anything.

Upvotes: 3

Views: 770

Answers (1)

Tushar
Tushar

Reputation: 87203

You need to make some changes in your code to access inner functions of person(). Added return this at the end of person(), so that the inner properties and methods of person() can be accessed from outside of the person().

See the changes highlighted in the code below.

var SomeClass = function() {
  this.get = function() {
    browser.get('http://blah');
  };

  this.person = function() {
    var firstNameInput = element(by.id('firstName'));
    var lastNameInput = element(by.id('lastName'));

    this.setTitle = function(title) {
      element(by.xpath('//select[@id="title"]/option[text()="' + title + '"]')).click();
    };

    this.setFirstName = function(firstName) {
      firstNameInput.sendKeys(firstName);
    };

    this.setLastName = function(lastName) {
      lastNameInput.sendKeys(lastName);
    };

    return this;
    // ^^^^^^^^^
  };
};

module.exports = new SomeClass();

Then, you can access setTitle as follow.

someClass.person().setTitle(data.title)
//              ^^ 

Demo

var SomeClass = function() {
  this.person = function() {
    this.setTitle = function(title) {
      document.write(title);
    };

    return this;
    // ^^^^^^^^^
  };
};

var myObj = new SomeClass();
myObj.person().setTitle('Hello World!');

Upvotes: 2

Related Questions