Nightwatch js Using page objects as variable in all steps - javascript

I have some page object document with code:
var gmailItemClicks = {
composeClick: function () {
return this.section.leftToolbarSection.click('#compose');
}
};
module.exports = {
commands: [gmailItemClicks],
sections: {
leftToolbarSection: {
selector: '.nH.oy8Mbf.nn.aeN',
elements: {
compose: { selector: '.T-I.J-J5-Ji.T-I-KE.L3' },
}
},
};
and the test file with many steps, like this:
module.exports = {
'1st step': function (client) {
gmail.composeClick();
},
'2d step': function (client) {
gmail.composeClick();
}
}
i can use 'gmail' variable if it is in every step like this:
module.exports = {
'1st step': function (client) {
var gmail = client.page.gmail();
gmail.composeClick();
},
'2d step': function (client) {
var gmail = client.page.gmail();
gmail.composeClick();
}
}
but i want to separate this var from the test code in the steps. I tried to use
const gmail = require('./../pages/gmail');
in the test before module.exports bloсk, and i tried to use globals.js file with the same syntax, but i get the error " ✖ TypeError: gmail.composeClick is not a function".
Now i have just one big function where are all steps used variable declared once inside the func, but the log of test looks ugly, i cant to see when the one step started and where it was stopped.
What i missed?

you could create the object in the before block. Here is how it would look like in my code:
(function gmailSpec() {
let gmailPage;
function before(client) {
gmailPage = client.page.gmail();
gmailPage.navigate()
}
function after(client) {
client.end();
}
function firstStep() {
gmailPage.composeClick()
}
function secondStep() {
gmailPage.composeClick()
}
module.exports = {
before,
after,
'1st step': firstStep,
'2nd step': secondStep
}
}());
Hope that helps you :)

Related

How do I test functions using jest

If I have the following js file how would I test the getTextValue and getRadioValue functions using Jest:
function getTextValue(textArea) {
return document.getElementById(textArea).value;
}
function getRadioValue(radioGroup) {
.....
return returnedValue;
}
export default class alpha {
constructor() {
...
}
myMethod() {
const answers = {
answers: [
{ id: "1", text: getRadioValue("a")},
{ id: "2", text: getTextValue("b")}
]
};
}
}
I'd like my test to be something like:
action: myMethod is called,
expect: getTextValue toHaveReturnedWith(Element)
You should make a test file for exemple alphaTest.spec.js in your test folder:
import alpha from '/yourfolder'
describe('Alpha', () => {
test('getValue should have returned element', () => {
// act
alpha.myMethod()
// assert
expect(getTextValue).toHaveReturnedWith("b")
})
}
You don't have document context in the node environment.
You have to use the library which emulates browser functionality and populates all the necessary functions you have like document.getElementById etc.
One option is to use JSDOM and create testing HTML snippet for it.
const jsdom = require("jsdom");
const { JSDOM } = jsdom;
const textareaValue = 'My-value';
const dom = new JSDOM(`
<!DOCTYPE html>
<body>
<textarea id="textarea" value="${textareaValue}"></textarea>
</body>
`);
const { document } = dom;
function getTextValue(textArea) {
return document.getElementById(textArea).value;
}
export default class Alpha {
myMethod() {
return { id: 1, text: getTextValue("textarea")};
}
}
describe('Alpha', () => {
it('should parse textare value', () => {
const alpha = new Alpha();
expect(alpha.myMethod()).toEqual({
id: 1,
text: textareaValue
});
});
});
If you want to test complex logic and interaction with different Browser APIs better to use
Cypress, Selenium, etc. These things run actual browsers while testing but are not really recommended for just unit tests. So, option one, to use JSDOM is recommended for your case.

Accessing non-existent property of module.exports inside circular dependency NodeJS

Im having some issues when using module.exports inside NodeJS, and I've followed multiple guides, and im almost certain Im doing it right.
I have to scripts, main.js and event.js. Im trying to share a function from main.js to event.js, but its not working. Here is the code:
Main.js
function Scan(){
if(fs.readdirSync('./events/').length === 0){
console.log(colors.yellow('Events Folder Empty, Skipping Scan'))
} else {
var events = fs.readdirSync('./events/').filter(file => file.endsWith('.json'))
for(const file of events){
let rawdata = fs.readFileSync('./events/' + file);
let cJSON = JSON.parse(rawdata);
}
events.sort()
tevent = events[0]
StartAlerter()
}
}
module.exports = { Scan };
Event.js
const main = require('../main')
main.Scan;
This returns the error:
(node:19292) Warning: Accessing non-existent property 'Scan' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
What am I doing wrong?
I discovered that the arrangement had no effect in the error.
I simply changed the way I exported the function from the Main.js
from:
module.exports = { Scan };
to:
exports.Scan = Scan
And in Event.js, I was able to access the file like this
const main = require("./Main.js");
let result = main.Scan();
This solved my problem, I hope it helps another developer 😎
Problem solved, heres what I did differently:
module.exports = { Scan };
Is declared before the Scan function is defined, like so:
module.exports = { Scan };
function Scan(){
//Code
}
Then in event.js, I wrote
const main = require('../main')
As it is now a module, and can be used with the require() function.
Then to execute the funciton in event.js, I write
main.Scan()
To execute it.
better try :
module.exports = Scan;
I am gonna answer it using a simple example, like in this case below:
File A has 3 functions to process database activity: function
addDB, updateDB, and delData;
File B has 2 functions to process User activity on smartphone:
function addHistory, and editHistory;
Function updateDB in file A is calling function editHis in file B, and function editHistory is calling function updateDB in file A. This is what we called circular-dependency. And we need to prevent it by only giving output of state from editHistory and the rest will be processed inside file A.
//ORIGINAL FUNCTIONS which caused CIRCULAR DEPENDENCY
function updateDB() {
//process update function here
//call function in fileB
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
response = {
state: 1,
message: "success",
};
}
});
return response;
}
//THIS is the WRONG ONE
function editHistory() {
//process function to edit History here
//call function in fileA
const file = require("fileA.js");
await file.updateDB(data).then((output) => { //You should not call it here
if(output["message"] === "success") {
output = {
state: 1,
message: "success",
};
}
});
return output;
}
//==================================================//
//THE FIX
function updateDB() {
//process function here
const history = require("fileB.js");
await history.editHistory(data).then((output) => {
if(output["message"] === "success"){
await updateDB(data).then((output) => {
response = {
state: 1,
message: "success",
};
});
} else {
log("Error");
}
});
return response;
}
function editHistory() {
//process function to edit History here
// No more calling to function inside the file A
output = {
state: 1,
message: "success",
};
return output;
}

Cannot access variables outside scope in browser context

Using protractor for angular e2e tests. I have a scope problem with the addMockModule. The spec states:
The JavaScript to load the module. Note that this will be executed in
the browser context, so it cannot access variables from outside its
scope.
https://angular.github.io/protractor/#/api?view=Protractor.prototype.addMockModule
browser.addMockModule('modName', function() {
angular.module('modName', []).value('foo', 'bar');
});
Problem: I am trying to pass another function Mockr to my mock module. I want to set and get a mock id.
steps.js
var mockData = require('../../mocks/data.js');
var Mockr = require('../../mocks/mockr.js');
var steps = function() {
this.Before(function(scenario, done) {
browser.addMockModule('httpBackEndMock', mockData.module, Mockr );
done();
});
};
module.exports = steps;
data.js
exports.module = function ( Mockr ) {
angular.module('httpBackEndMock', ['ngMockE2E'])
.run(function($httpBackend) {
// cannot access Mockr here...
// since this is in browser context scope,
// how can I access Mockr???
// like: Mockr.getMockId();
});
};
mockr.js
module.exports = {
id: 5,
setMockId: function(id) {
module.exports.id = id;
},
getMockId: function() {
return module.exports.id;
}
};

How do I chain Intern Page Object function calls?

Following the Intern user guide, I wrote a simple page object:
define(function(require) {
function ListPage(remote) {
this.remote = remote;
}
ListPage.prototype = {
constructor: ListPage,
doSomething: function(value) {
return this.remote
.get(require.toUrl('http://localhost:5000/index.html'))
.findByCssSelector("[data-tag-test-id='element-of-interest']")
.click().end();
}
};
return ListPage;
});
In the test, I want to call doSomething twice in a row, like this:
define(function(require) {
var registerSuite = require('intern!object');
var ListPage = require('../support/pages/ListPage');
registerSuite(function() {
var listPage;
return {
name: 'test suite name',
setup: function() {
listPage = new ListPage(this.remote);
},
beforeEach: function() {
return listPage
.doSomething('Value 1')
.doSomething('Value 2');
},
'test function': function() {
// ...
}
};
});
});
However, when I run the test, I get this error:
TypeError: listPage.doSomething(...).doSomething is not a function
I tried some approaches described in this question, to no avail.
A better way to implement page objects with Intern is as helper functions rather than Command wrappers. Groups of related helper functions can then be used to create Page Object modules.
// A helper function can take config parameters and returns a function
// that will be used as a Command chain `then` callback.
function doSomething(value) {
return function () {
return this.parent
.findByCssSelector('whatever')
.click()
}
}
// ...
registerSuite(function () {
name: 'test suite',
'test function': function () {
return this.remote.get('page')
// In a Command chain, a call to the helper is the argument
// to a `then`
.then(doSomething('value 1'))
.then(doSomething('value 2'));
}
}

Accessing javascript object property within nested function

Good day,
I have created an object that will manage data access. My app will be using a couple different datastores, so I have created a simple factory to switch between providers:
var dataProvider = {
company: {
getAllCompanies: function (callback) {
var impl = factory.createProvider(implInstance.current)
impl.company.getAllCompanies(callback);
}
}
projects: {
getAllProjects: function (callback) {
var impl = factory.createProvider(implInstance.current)
impl.projects.getAllProjects(callback);
}
}
}
That is all well and good, but I'd rather have my impl variable at the dataProvider level. I'm unsure how I would properly access it though, as 'this' doesn't provide me the right scope when I'm nested so deeply. I'd like something like the following:
var dataProvider = {
impl: function () { return factory.createProvider(implInstance.current) },
company: {
getAllCompanies: function (callback) {
//THIS WON'T WORK
this.impl.company.getAllCompanies(callback);
}
}
Thanks!
You'd want to use the module design pattern for this:
var dataProvider = (function () {
var getImpl = function () {
return factory.createProvider(implInstance.current);
};
return {
company: {
getAllCompanies: function (callback) {
getImpl().company.getAllCompanies(callback);
}
},
projects: {
getAllProjects: function (callback) {
getImpl().projects.getAllProjects(callback);
}
}
}
})();

Categories

Resources