The execution returns the following error when trying to load multiple js:
TypeError: Cannot read property 'get' of undefined
The solution that I am implementing has a login_steps.js:
var LoginSteps = function() {
var LoginSteps = require("../pages/pages.js");
browser.ignoreSynchronization = true;
this.World = function MyWorld() {
this.page = new LoginSteps();
};
this.Given(/^the page is open$/, function (callback) {
this.page.login_page.get();
callback();
});
};
module.exports = LoginSteps;
A page.js where I want to include all the modules that I need.
var Pages = function() {
module.exports = {
shipments_page: require('./shipments_page.js'),
login_page: require('./login_page.js'),
};
};
module.exports = Pages;
And the modules login_page.js:
var chai = require('chai').use(require('chai-as-promised'));
var expect = chai.expect;
this.get = function() {
browser.get('https://aaa/login');
};
this.setEmail = function(value) {
element(by.id('login-email')).sendKeys(value);
};
this.setPassword = function(value) {
element(by.id('login-password')).sendKeys(value);
};
this.clickAccede = function() {
element(by.id('login-submit')).click()
};
shipment_page.js:
var chai = require('chai').use(require('chai-as-promised'));
var expect = chai.expect;
this.pageIsLoaded = function() {
browser.waitForAngular();
expect(browser.getTitle()).to.be.eventually.equals('title');
};
Then when I execute the test the log shows
Failures:
1) Scenario: User login - features/login.feature:3
Step: Given the page is open - features/login.feature:4
Step Definition: features/steps/login_steps.js:16
Message:
TypeError: Cannot read property 'get' of undefined
at MyWorld.<anonymous> (/Users/mj/IdeaProjects/atpro/features/steps/login_steps.js:17:30)
at process._tickCallback (internal/process/next_tick.js:61:11)
1 scenario (1 failed)
5 steps (1 failed, 4 skipped)
Here is the code that you can try. Its works for me. I modified based on your code snippet. I won't use this pattern in my tests though.You may not want to write protractor-cucumber test using the pattern you are following. One should always use validation/assertions in step definition code. if you do validation in page object, even your validation fails, your test still will show passed.
login_steps.js
var LoginSteps = function() {
var LoginSteps = require("../pages/pages.js");
browser.ignoreSynchronization = true;
this.World = function MyWorld() {
this.page = LoginSteps;
};
this.Given(/^the page is open$/, function (callback) {
this.page.login_page.get();
callback();
});
};
module.exports = LoginSteps;
pages.js:
module.exports = {
shipments_page: require('./shipments_page.js'),
login_page: require('./login_page.js'),
};
If I interpreted correctly this is what you want. You have only to change page.js a little.
module.exports = function() {
this.shipments_page = require('./shipments_page.js');
this.login_page = require('./login_page.js');
};
Please try this. I cannot test at the moment :=)
Related
I keep getting this message saying Newpage is not a constructor i have racked my brains out for the past 5 hours trying to resolve this issue and no progress i have looked at the following sites
How to call a function in another function in protractor
'TypeError: undefined is not a function' using Protractor
Maybe it is something simple i don't know. All I am trying to do is call a function form my page object file. Still no success any help would be appreciated.
my code:
var newPage = require('./newPage.js');
describe('Get Payroll Information', function() {
beforeAll(function(){
var newPageObj = new newPage();
});
var EC = protractor.ExpectedConditions;
var status;
var clientid, weeknum, pdate;
it('Get CycleStatus, Paydate, Weeknumber, Clientid - completed', function () {
const fs = require('fs');
const cycle = $('#cycleStatusID'); // cycle status
const client = $('#clientID'); // clientid
const week = $('#companyIdBar_weekId'); // week number
const payDate = $('#companyIdBar_processDateId');
//------------Get PayDate --------------------------------
.then(() => {
payDate.isPresent().then(function(present){
if(present){
payDate.getText().then(function(text){
pDate = text;
console.log('paydate (' + pDate + ') is displayed');
});
} else {
console.log('pay date not present');
//return;// breaks for loop like (break)
}
})
})
.then(() => {
writeValueToFile(cycleStatus,clientID,weekNum,pDate);
})
.then(() => {
newPageObj.goBack();
console.log('return to support');
});
});// master then promise
});//spec function
Protractor console message
newPage.js Code:
newPage = function(){
function goBack(){
var returnbtn = $('#returnToADPClick');
var search1 = ($$('input[id="toolbarQuickSearch"]').get(0));
returnbtn.click();
browser.wait(EC.elementToBeClickable(search1),20,000);
};
};
module.exports = new newPage();
changed to module.exports = new newPage; // this work now i get
Your newPage.js is exporting an object, not a function/class/constructor. Change the module.exports to just newPage like this:
newPage = function(){
function goBack(){
var returnbtn = $('#returnToADPClick');
var search1 = ($$('input[id="toolbarQuickSearch"]').get(0));
returnbtn.click();
browser.wait(EC.elementToBeClickable(search1),20,000);
};
};
module.exports = newPage;
Failed: newPageObj Object not defined
This is because of the scope of the newPageObj variable - currently it is only defined in the scope of beforeAll. Declare your variable at the higher level:
var newPage = require('./newPage.js');
var newPageObj;
describe('Get Payroll Information', function() {
beforeAll(function() {
newPageObj = new newPage();
});
// ...
});
I have written a file with a number of functions that I wish to use across a variety of E2E tests. I have been trying to test this out and have found some solutions but none work for me.
This is how things stand.
In my TestingFunc.js file I have created the following:
var TestingFunc = function() {
this.login = function(Url) {
browser.ignoreSynchronization = true;
browser.get(Url);
browser.wait(EC.elementToBeClickable(element(by.eeHook('login',null,null))), 300000);
element(by.eeHook('login', null, null)).click();
element(by.eeHook('authenticationEmailField',null,null)).sendKeys(logins.International);
element(by.name('password')).sendKeys(logins.password);
element(by.eeHook('authenticationLoginButton',null,null)).click();
browser.wait(EC.elementToBeClickable(paymentFlow), 100000);
paymentFlow.click();
browser.wait(EC.elementToBeClickable(depositAmount), 7000);
};
};
and I am trying to read it in the following:
var url = 'http://master.mrgreen.avengers.zone/en-US/casino';
var TestingFunc = require("C:/Users/davbor.3DB/MrGreen Google Drive/LetsTest/TestingFunc.js");
describe("The security application", function () {
var test = new TestingFunc();
it("will login to the page", function () {
test.login(url);
});
});
Yet each time I run it I keep getting the error:
Failures:
1) The security application encountered a declaration exception
Message:
TypeError: TestingFunc is not a constructor
Stack:
TypeError: TestingFunc is not a constructor
at Suite.<anonymous> (C:\Users\davbor.3DB\MrGreen Google Drive\LetsTest\Testing.js:6:17)
Not sure what i am missing as I have even asked an in house developer to look at it without success.
var TestingFunc = require("C:/Users/davbor.3DB/MrGreen Google Drive/LetsTest/TestingFunc.js");
1) You should not use full path. Use relative path to this file.
In your Testing.js require should look like this:
var TestingFunc = require("./TestingFunc.js");
2) You should 'export' your function:
var TestingFunc = function() {
this.login = function(Url) {
browser.ignoreSynchronization = true;
browser.get(Url);
browser.wait(EC.elementToBeClickable(element(by.eeHook('login',null,null))), 300000);
element(by.eeHook('login', null, null)).click();
element(by.eeHook('authenticationEmailField',null,null)).sendKeys(logins.International);
element(by.name('password')).sendKeys(logins.password);
element(by.eeHook('authenticationLoginButton',null,null)).click();
browser.wait(EC.elementToBeClickable(paymentFlow), 100000);
paymentFlow.click();
browser.wait(EC.elementToBeClickable(depositAmount), 7000);
};
};
module.exports = TestingFunc;
Check more about nodejs modules here:
https://nodejs.org/api/modules.html
Good day.
In JS/node I'm new.
I'm does made two functions from main code into a separate file and now I can not connect it to the main.
If I fighting over this issue. Help me plz. Something I'm doing wrong.
Here are the features that made:
exports.loadRegistrationForm = function() {
driver.get('http://somesite');
driver.getTitle().then(function(title){
if("sometitle"===title){
driver.findElement(webdriver.By.xpath('html/body/div/header/div/div/div[2]/div[2]/a[1]'))
.click();
};
});
driver.wait(function(){
return driver.isElementPresent(webdriver.By.name('fos_user_registration_form[email]'));
}, 3000, 'Failed to load Registration form');
}
exports.fillingRegistrationForm = function(inputEmail, inputPassword, errElement, errMessage){
driver.findElement(webdriver.By.name('fos_user_registration_form[email]'))
.sendKeys(inputEmail);
driver.findElement(webdriver.By.name('fos_user_registration_form[plainPassword]'))
.sendKeys(inputPassword);
driver.findElement(webdriver.By.id('btn-submit')).click();//сабмит
driver.wait(function(){
return driver.isElementPresent(webdriver.By.xpath(errElement));
}, 3000, 'Элемент не найден');
var flow = webdriver.promise.controlFlow();
function getErrObject(){
errObject = driver.findElement(webdriver.By.xpath(errElement))
.getText()
}
flow.execute(getErrObject).then(function(){
if(errObject.value_ === errMessage){
assert.equal(errObject.value_, errMessage);
console.log('OK')
};
});
}
Here are trying to rewrite part of the core functions:
var assert = require("assert")
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build();
var loadRegistrationForm = require('reusable_function').loadRegistrationForm;
var fillingRegistrationForm = require('./reusable_function').fillingRegistrationForm
describe('Check the Email field of the registration form.', function(){
it('Enter an already registered Email', function(done){
var inputEmail = '123#ya.ru';
var inputPassword = '12345678Aa';
var errElement = "//*[#class='form-errors server-error']";
var errMessage = 'Email already in use';
loadRegistrationForm();
fillingRegistrationForm(inputEmail, inputPassword, errElement, errMessage);
return done();
});
});
In the console error:
ReferenceError: driver is not defined
at exports.loadRegistrationForm (C:\Program Files\nodejs\test\reusable_fun
ction.js:9:5)
at Context.<anonymous> (C:\Program Files\nodejs\test\test2_mocha.js:15:9)
at callFnAsync (C:\Users\Valentine11\AppData\Roaming\npm\node_modules\moch
a\lib\runnable.js:306:8)
at Test.Runnable.run (C:\Users\Valentine11\AppData\Roaming\npm\node_module
s\mocha\lib\runnable.js:261:7)
at Runner.runTest (C:\Users\Valentine11\AppData\Roaming\npm\node_modules\m
ocha\lib\runner.js:421:10)
at C:\Users\Valentine11\AppData\Roaming\npm\node_modules\mocha\lib\runner.
js:528:12
at next (C:\Users\Valentine11\AppData\Roaming\npm\node_modules\mocha\lib\r
unner.js:341:14)
at C:\Users\Valentine11\AppData\Roaming\npm\node_modules\mocha\lib\runner.
js:351:7
at next (C:\Users\Valentine11\AppData\Roaming\npm\node_modules\mocha\lib\r
unner.js:283:14)
at Immediate._onImmediate (C:\Users\Valentine11\AppData\Roaming\npm\node_m
odules\mocha\lib\runner.js:319:5)
What am I doing wrong? Incorrectly write access functions from loadable module? How does it right?
Great thanks.
Upd. Okay I find answer.
Every module in JS have own scope. In module reusable_function no driver variable, hence the error not defined. Driver is a variable in the main module, but it is invisible to the module reusable_function, because it is not included in the scope. So I have defined a variable driver in the module reusable_function and removed this variable from the main module. To delete a variable from the main driver module does not disturb his work, because the variable driver cache and made available during the import module reusable_function.
Reusable_function:
var assert = require("assert")
var webdriver = require('selenium-webdriver');
var driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.chrome()).
build()
exports.loadRegistrationForm = function(){
driver.get('http:...');
driver.getTitle().then(function(title){
if("..."===title){
driver.findElement(webdriver.By.xpath('html/body/div/header/div/div/div[2]/div[2]/a[1]'))
.click();
};
});
driver.wait(function(){
return driver.isElementPresent(webdriver.By.name('fos_user_registration_form[email]'));
}, 3000, 'Failed to load Registration form');
};
exports.fillingRegistrationForm = function(inputEmail, inputPassword, errElement, errMessage){
driver.findElement(webdriver.By.name('fos_user_registration_form[email]'))
.sendKeys(inputEmail);
driver.findElement(webdriver.By.name('fos_user_registration_form[plainPassword]'))
.sendKeys(inputPassword);
driver.findElement(webdriver.By.id('btn-submit')).click();//сабмит
driver.wait(function(){
return driver.isElementPresent(webdriver.By.xpath(errElement));
}, 3000, 'Element not found');
var flow = webdriver.promise.controlFlow();
function getErrObject(){
errObject = driver.findElement(webdriver.By.xpath(errElement))
.getText()
}
flow.execute(getErrObject).then(function(){
if(errObject.value_ === errMessage){
assert.equal(errObject.value_, errMessage);
console.log('OK')
};
});
};
Main module (part of):
var webdriver = require('selenium-webdriver');
var flow = webdriver.promise.controlFlow();
var loadRegistrationForm = require('./reusable_function').loadRegistrationForm
var fillingRegistrationForm = require('./reusable_function').fillingRegistrationForm
describe('Check out Email form field.', function(){
it('Enter already register Email', function(done){
var inputEmail = '123#ya.ru';
var inputPassword = '12345678Aa';
var errElement = "//*[#class='form-errors server-error']";
var errMessage = 'Email already in use';
loadRegistrationForm();
fillingRegistrationForm(inputEmail, inputPassword, errElement, errMessage);
flow.execute(function(){
return done();
});
});
});
Its work.
You have a random funtion execute right above the error line which ends without any code. Remove this and it will work.
I've had no trouble testing my own route handlers but in this case I want to test express's static handler. I can't for the life of me figure out why it's hanging. Clearly there's some callback I'm missing or some event I need to emit.
I tried to make the smallest example I could.
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function createRequest(req) {
var emitter = new events.EventEmitter();
req.on = emitter.on.bind(emitter);
req.once = emitter.once.bind(emitter);
req.addListener = emitter.addListener.bind(emitter);
req.emit = emitter.emit.bind(emitter);
return req;
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = createRequest({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
Setup,
mkdir foo
cd foo
mkdir test
cat > test/test.js # copy and paste code above
^D
npm install express
npm install mocha
node node_modules/mocha/bin/mocha --recursive
it just times out.
What am I missing?
I also tried making the request a Readable stream. No change
var events = require('events');
var express = require('express');
var stream = require('stream');
var util = require('util');
function MockResponse(callback) {
stream.Writable.call(this);
this.headers = {};
this.statusCode = -1;
this.body = undefined;
this.setHeader = function(key, value) {
this.headers[key] = value;
}.bind(this);
this.on('finish', function() {
console.log("finished response");
callback();
});
};
util.inherits(MockResponse, stream.Writable);
MockResponse.prototype._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
function MockMessage(req) {
stream.Readable.call(this);
var self = this;
Object.keys(req).forEach(function(key) {
self[key] = req[key];
});
}
util.inherits(MockMessage, stream.Readable);
MockMessage.prototype._read = function() {
this.push(null);
};
describe('test', function() {
var app;
before(function() {
app = express();
app.use(express.static(__dirname));
});
it('gets test.js', function(done) {
var req = new MockMessage({
url: "http://foo.com/test.js",
method: 'GET',
headers: {
},
});
var res = new MockResponse(responseDone);
app(req, res);
function responseDone() {
console.log("done");
done();
}
});
});
I've still been digging. Look inside static-server I see it creates a Readable stream by calling fs.createReadStream. It does effectively
var s = fs.createReadStream(filename);
s.pipe(res);
So trying that myself works just fine
it('test stream', function(done) {
var s = fs.createReadStream(__dirname + "/test.js");
var res = new MockResponse(responseDone);
s.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
I thought maybe it's something about express waiting for the input stream to finish but that doesn't seem to be it either. If I consume the mock input stream with the response it works just fine
it('test msg->res', function(done) {
var req = new MockMessage({});
var res = new MockResponse(responseDone);
req.pipe(res);
function responseDone() {
console.log("done");
done();
}
});
Any insight what I might be missing would be helpful
Note: while suggestions for 3rd party mocking libraries are appreciated I'm still really looking to understand what I'm missing to do it myself. Even if I eventually switch to some library I still want to know why this isn't working.
I found two issues that prevent the finish callback from being executed.
serve-static uses send module which is used to create file readstream from the path and pipe it to res object. But that module uses on-finished module which checks if finished attribute is set to false in response object, otherwise it destroys the file readstream. So filestream never gets a chance to emit data event.
express initialization overwrites the response object prototype. So the default stream methods like end() method is overwritten by http response prototype:
exports.init = function(app){
return function expressInit(req, res, next){
...
res.__proto__ = app.response;
..
};
};
To prevent this, I added another middleware right before static middleware to reset it back to MockResponse prototype:
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype; //change it back to MockResponse prototype
next();
});
Here are the changes made to make it work with MockResponse:
...
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
};
...
describe('test', function() {
var app;
before(function() {
app = express();
//another middleware to reset the res object
app.use(function(req, res, next){
res.__proto__ = MockResponse.prototype;
next();
});
app.use(express.static(__dirname));
});
...
});
EDIT:
As #gman pointed out, it is possible to use direct property instead of prototype method. In that case the extra middleware to overwrite prototype isn't necessary:
function MockResponse(callback) {
...
this.finished = false; // so `on-finished` module doesn't emit finish event prematurely
//required because of 'send' module
this.getHeader = function(key) {
return this.headers[key];
}.bind(this);
...
//using direct property for _write, write, end - since all these are changed when prototype is changed
this._write = function(chunk, encoding, done) {
if (this.body === undefined) {
this.body = "";
}
this.body += chunk.toString(encoding !== 'buffer' ? encoding : undefined);
done();
};
this.write = stream.Writable.prototype.write;
this.end = stream.Writable.prototype.end;
};
It appears my answer is not complete. For some reason the app works only if the file is not found. First thing to debug is do the following in your shell (or cmd):
export DEBUG=express:router,send
then run the test, you'll get more info.
Meanwhile I am still looking into this, for now, ignore my answer below.
----------- ignore this till I verify that it does work -----------
It seems like express static does not favor the absolute path you give it (__dirname).
Try:
app.use(express.static('.'));
and it will work. Note that your current dir for the mocha runner is 'test/'
I have to admit this is quite a mistery. I tried 'fulling' it by doing:
app.use(express.static(__dirname + '/../test')
but still it didn't work. Even specifying a full path did not solve this. Strange.
Hi I have this simple test:
define(["angular", "angularMocks", "app", "normalizer"], function(angular, mocks, app) {
describe("service: normalizer", function () {
var normalizerService;
beforeEach(module("ADB"));
beforeEach(inject(function(_normalizer_) {
normalizerService = _normalizer_;
}));
var params = {};
var metadata = {};
var data = {};
var response = normalizerService.topLanguagesHybrid(metadata, data, params);
var type = typeof response;
expect(type).toEqual("object");
});
});
The issue is that the normalizer service is never being set, and in cmd I see the following error:
TypeError: 'undefined' is not an object (evaluating 'normalizerService.topLanguagesHybrid')
Note: I am using requirejs in this project and I can see that normalizer service file is being loaded into the browser (with all of its dependencies). It seems that it just not injected.
What did I do wrong?
Link to error
When you defining services, you forgot to define normalizer, so the correct syntax for the same is
define(["angular", "angularMocks", "app", "normalizer"], function(angular, mocks, app, normalizerService) {
describe("service: normalizer", function () {
var normalizerService;
beforeEach(module("ADB"));
var params = {};
var metadata = {};
var data = {};
var response = normalizerService.topLanguagesHybrid(metadata, data, params);
var type = typeof response;
expect(type).toEqual("object");
});
});
You forgot to define the it, for the test scenario, beforeEach runs before each "it" function.
define(["angular", "angularMocks", "app", "normalizer"], function(angular, mocks, app) {
describe("service: normalizer", function () {
var normalizerService;
beforeEach(module("ADB"));
beforeEach(inject(function(_normalizer_) {
normalizerService = _normalizer_;
}));
it('should define topLanguageHybrid method', function() {
var params = {};
var metadata = {};
var data = {};
var response = normalizerService.topLanguagesHybrid(metadata, data, params);
var type = typeof response;
expect(type).toEqual("object");
});
});
});
More info on jasmine: jasmine docs