Preparing an automated testing using javascript for testing a module - javascript

The module has three pages which change one by one when clicked on the next or prev button. I am able to click it by writing the click method twice. How do I make it work in one test? Do I have to use a loop or any other way. Please suggest JavaScript, my arrow environment is new to me. We are using nodejs.
Secondly, they are adding an auto rotate feature to this module, for which also I have to prepare automation test. Please suggest how to go about automating testing this feature.
http://att.yahoo.com/
(check Attspotlight module)
For your convenience, here is the current code I wrote for the module:
YUI.add("cdt-att-spotlight-func-tests", function(Y) {
'use strict';
var Utils = Y.Media.Cdt.FuncTestUtils;
Y.Media.Cdt.FuncTestUtils.DebugMode=true;
var selectors = {
module: "#mediabcarouselmixedlpca_2",
/*title: ".heading",
numberSlot: ".yui-carousel-pagination",
clickButtons: ".ymg-nav-buttons",*/
nextButton: ".yui-carousel-next",
prevButton: ".yui-carousel-prev",
visibleImage:".img-wrap",
/*linkText_bestdeals: ".txt",
linkText_CheckGoPhone:".txt",
linkText_greatdeals:".txt",*/
linkText: ".txt"
};
var suite = new Y.Test.Suite("Cdt Att Spotlight Func Test Suite");
suite.add(new Y.Test.Case({
setUp: function() {
// Find our module...
this.module = Y.one(selectors.module);
// Define our components...
this.components = {
nextButton: this.module.one(selectors.nextButton),
prevButton: this.module.one(selectors.prevButton),
visibleImage: Utils.track.selector(this.module, selectors.visibleImage),
linkText: this.module.one(selectors.linkText)
};
this.module.scrollIntoView();
},
"Verify MediaCdtAttSpotlight module loaded": function() {
this.module.should.be.visibleToUser();
},
"Verify Image showed in the module": function() {
var visibleImage = this.components.visibleImage.current();
this.wait(function() {
visibleImage.should.be.visibleToUser();
}, 2000);
},
"Verify the Link Text is visible": function() {
this.components.linkText.should.be.visibleToUser();
},
"Verify clicking next button to scroll left": function() {
this.components.nextButton.simulate("click");
this.wait(function() {
}, 3000);
},
"Verify clicking next button1 to scroll left": function() {
this.components.nextButton.simulate("click");
this.wait(function() {
}, 3000);
},
"Verify clicking prev button to scroll right": function() {
this.components.prevButton.simulate("click");
this.wait(function() {
}, 2000);
},
"Verify clicking prev button1 to scroll right": function() {
this.components.prevButton.simulate("click");
this.wait(function() {
}, 2000);
}
}));
Y.Test.Runner.add(suite);
}, "0.1", { requires: ["test", "node", "node-event-simulate", "chai-yui", "cdt-func-test-utils"]});

Note: This question is targeted towards nodejs module testing in general, not Arrow. I don't want to delete it as the author is looking for clarification of some things in the comments of my anwser. I will be happy to delete this anwser if it is requested.
I would reccomend mocha http://visionmedia.github.io/mocha/. It is a great testing framework that is very popular. When combined with the module should, you can write simple tests, like this.
require('should');
describe('Array', function(){
describe('#indexOf()', function(done){
it('should return -1 when the value is not present', function(){
[1,2,3].indexOf(5).should.equal(-1);
[1,2,3].indexOf(0).should.equal(-1);
done();
})
})
})
You can then set up a free web service called travis ci https://travis-ci.org/ to run your tests whenever you push to github. I am using these services for my modules and am very happy.

Related

Make a 'common' login.js include; with nightwatch.js tests

When writing tests for my web app; I have to first simulate login before the rest of my tests can run and see inner pages. Right now I'm working on modulating the code, so that way I can just make an 'include' for the common function; such as my login. But as soon as I move the below code in a separate file, and call the include via require - it no longer runs as expected.
ie. the below logs in and allows my other functions, if, included in the same file. above my other inner screen functions.
// Login screen, create opportunity
this.LoginScreen = function(browser) {
browser
.url(Data.urls.home)
.waitForElementVisible('#login', 2000, false)
.click('#login')
.waitForElementVisible('div.side-panel.open', 4000, false)
.waitForElementVisible('input#email', 2000, false)
.waitForElementVisible('input#password', 2000, false)
.click('input#email')
.pause(500)
.setValue('input#email', Data.ProjMan.username)
.click('input#password')
.pause(500)
.setValue('input#password', Data.ProjMan.password)
.click('input#email')
.pause(500)
.click('div.form.login-form .btn')
.pause(5000)
Errors.checkForErrors(browser);
};
// Inner functions run after here, sequentially
But as soon as I move the above in a separate file, for instance; Logins.js, then call it at the top of the original test file with. (yes, correct path).
var Logins = require("../../lib/Logins.js");
It just doesn't simulate the login anymore. Any thoughts? Should I remove the this.LoginScreen function wrapper, and call it differently to execute from the external file, or do I need to fire it from the original file again, aside from the external require path?
I have also tried wrapping 'module.exports = {' around the login function from separate file, but still failing.
Nightwatch allows you to run your Page object based tests i.e you can externalize your common test functions and use them in your regular tests. This can be achieved using 'page_objects_path' property. I have added the common 'login' functionality and used it in sample 'single test' in the project here.
Working:
Place your common function in .js file and place it under a folder(ex: tests/pages/login.js) and pass the folder path in nighwatch config file as below:
nightwatch_config = {
src_folders : [ 'tests/single' ],
page_objects_path: ['tests/pages'],
Below is an example of common login function (login.js):
var loginCommands = {
login: function() {
return this.waitForElementVisible('body', 1000)
.verify.visible('#userName')
.verify.visible('#password')
.verify.visible('#submit')
.setValue('#userName', 'Enter Github user name')
.setValue('#password', 'Enter Github password')
.waitForElementVisible('body', 2000)
}
};
module.exports = {
commands: [loginCommands],
url: function() {
return 'https://github.com/login';
},
elements: {
userName: {
selector: '//input[#name=\'login\']',
locateStrategy: 'xpath'
},
password: {
selector: '//input[#name=\'password\']',
locateStrategy: 'xpath'
},
submit: {
selector: '//input[#name=\'commit\']',
locateStrategy: 'xpath'
}
}
};
Now, in your regular test file, create an object for the common function as below and use it.
module.exports = {
'Github login Functionality' : function (browser) {
//create an object for login
var login = browser.page.login();
//execute the login method from //tests/pages/login.js file
login.navigate().login();
//You can continue with your tests below:
// Also, you can use similar Page objects to increase reusability
browser
.pause(3000)
.end();
}
};
The above answer is absolutly correct however I did struggle with how to supply login user details.
This is what I ended up using:
var loginCommands = {
login: function() {
return this.waitForElementVisible('body', 1000)
.setValue("#email", "<some rnd email address>")
.setValue('#password', "<some rnd password>")
.click('button[type=submit]')
.pause(1000)
}
};
module.exports = {
commands: [loginCommands],
url: function() {
return 'https://example.com/login';
}
};
This can be used in the same way as the accepted answer just posting for others who come searching.

Using execute command in Page Objects in Nightwatch JS

I have a problem with implementing Page Object in Nightwatch. Let's say that I have a login scenario. I need to scroll to the element - I'm using for thar execute function.
module.exports = {
'Login' : function (browser) {
browser.url(this.launchUrl)
.setValue('input[name=username]', 'admin')
.setValue('input[name=password]', 'password')
.execute(function () {
document.querySelector('input[type=submit]').scrollIntoView();
}, [])
.click('input[type=submit]');
browser.end();
}
}
I'd like to refactor this login code into Page Object like that
module.exports = {
url: function() {
return this.api.launchUrl;
},
commands: [scrolling],
elements: {
usernameField: {
selector: 'input[name=username]'
},
passwordField: {
selector: 'input[name=password]'
},
submit: {
selector: 'input[type=submit]'
}
}
};
I'd like to 'hide' also this execute command and pack it into commands, like that:
var scrolling = {
scroll: function(){
return this.execute(function () {
document.querySelector(input[type=submit]').scrollIntoView();
}, []);
}
};
Unfortunately it seems that execute command doesn't work with Page Object.
How I can overcome this issue with executing JavaScript code when I want to use Page Object? How can I encapsulate it?
The answer was very simple
1) There was a quotation mark missing in a selector.
2) Using execute() in Object Pattern it is needed to run it using this.api :
this.api.execute(function () {
document.querySelector('input[type=submit]').scrollIntoView();
}, []);
Found the answer
ForthStCheck:function(){
this.api.execute('scrollTo(0,500)')
this.waitForElementVisible('#forthStationPlayBtn',5000)
}

callbacks/promises for the re-usable methods in Protractor

Should we write callbacks/promises for the re-usable methods in Page Object Pattern based testing in Protractor?
For example .. I have the below test code and Page Objects and its working fine without issues. But should I add callbacks for re-usable methods in page class?
describe('This is a test suite for Login cases',function(){
beforeEach(function() {
LoginPage.goHome();
LoginPage.doLogin();
});
afterEach(function() {
LoginPage.doLogout();
});
it('Scenario1_Login_VerifyFirstName',function(){
//Some Test step
});
Page Class:
var Login = {
PageElements: {
emailInput: element(by.css('.email')),
passwordInput: element(by.css('.password')),
loginForm: element(by.css('.form')),
logout: element(by.linkText('LOG OUT'))
},
goHome: function goHome() {
browser.get('/signin');
browser.driver.manage().window().maximize();
},
doLogin: function doLogin() {
this.PageElements.emailInput.sendKeys(UserName);
this.PageElements.passwordInput.sendKeys(Password);
this.PageElements.loginForm.submit();
},
doLogout: function doLogout() {
browser.wait(EC.elementToBeClickable(this.PageElements.profileLink));
this.PageElements.profileLink.click();
this.PageElements.logout.click();
}
};
module.exports = Login;
Yes you can.
By simply returning values or promises:
goHome: function() {
browser.get('/home');
return browser.getTitle();
},
And should resolve them on spec level inside "it" blocks like below:
it('Page should have a title', function() {
expect(Page.goHome()).toEqual('Home Page');
});

load data from module before test executes

(I asked this question recently and accepted an answer but it's still not what I need.) I really need to create dynamic tests from data loaded from a module. Each item from the array will have it's own describe statement with certain protractor actions. My previous post has an answer that says to use an it statement, but I can't do that because there's too much going on.
My main problem is that the data doesn't get loaded in time for the describe. I had another suggestion to use VCR.js or something similar but I don't think those will work because I'm using a module. Is there a way I can save the data to a separate file and load it in? Would that be a good way to go?
var data = require('get-data'); //custom module here
describe('Test', function() {
var itemsArr;
beforeAll(function(done) {
data.get(function(err, result) {
itemsArr = result; //load data from module
done();
});
})
//error: Cannot read property 'forEach' of undefined
describe('check each item', function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
function checkItem (item) {
var itemName = item.name;
describe(itemName, function() {
console.log('describe');
it('should work', function() {
console.log('it');
expect(true).toBeTruthy();
});
});
}
});
UPDATE:
I used Eugene's answer and came up with this. I can't test each individual study how I want because the it statement doesn't fire. Is this problem even solvable??
describe('check each item', function () {
it('should load data', function (done) {
browser.wait(itemsPromise, 5000);
itemsPromise.then(function(itemsArr) {
expect(itemsArr).toBeTruthy();
studyArr = itemsArr.filter(function (item) {
return item.enabled && _.contains(item.tags, 'study');
});
studyCount = studyArr.length;
expect(studies.count()).toEqual(studyCount);
checkItems(studyArr);
done();
});
});
function checkItems (itemsArr) {
itemsArr.forEach(function (item) {
describe(item.id, function () {
console.log('checkItems', item.id);
// doesn't work
it('should work', function (done) {
expect(false).toBeTruthy();
done();
});
});
});
}
});
You're trying to do something that Jasmine does not allow: generating tests after the test suite has started. See this comment on an issue of Jasmine:
Jasmine doesn't support adding specs once the suite has started running. Usually, when I've needed to do this, I've been able to know the list of options ahead of time and just loop through them to make the it calls. [...]
("adding specs" === "adding tests")
The point is that you can generate tests dynamically but only before the test suite has started executing tests. One corollary of this is that the test generation cannot be asynchronous.
Your second attempt does not work because it is trying to add tests to a suite that is already running.
Your first attempt is closer to what you need but it does not work either because describe calls its callback immediately, so beforeAll has not run by the time your describe tries to generate the tests.
Solutions
It all boils down to computing the value of itemsArr before the test suite start executing tests.
You could create a .getSync method that would return results synchronously. Your code would then be something like:
var data = require('get-data'); //custom module here
var itemsArr = data.getSync();
describe('Test', function() {
describe('check each item', function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
[...]
If writing .getSync function is not possible, you could have an external process be responsible for producing a JSON output that you could then deserialize into itemsArr. You'd execute this external process with one of the ...Sync functions of child_process.
Here's an example of how the 2nd option could work. I've created a get-data.js file with the following code which uses setTimeout to simulate an asynchronous operation:
var Promise = require("bluebird"); // Bluebird is a promise library.
var get = exports.get = function () {
return new Promise(function (resolve, reject) {
var itemsArr = [
{
name: "one",
param: "2"
},
{
name: "two",
param: "2"
}
];
setTimeout(function () {
resolve(itemsArr);
}, 1000);
});
};
// This is what we run when were are running this module as a "script" instead
// of a "module".
function main() {
get().then(function (itemsArr) {
console.log(JSON.stringify(itemsArr));
});
};
// Check whether we are a script or a module...
if (require.main === module) {
main();
}
Then, inside the spec file:
var child_process = require('child_process');
var itemsArr = JSON.parse(child_process.execFileSync(
"/usr/bin/node", ["get-data.js"]));
describe('Test', function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
function checkItem (item) {
var itemName = item.name;
describe(itemName, function() {
console.log('describe');
it('should work', function() {
console.log('it');
expect(true).toBeTruthy();
});
});
}
});
I've tested the code above using jasmine-node. And the following file structure:
.
├── data.js
├── get-data.js
└── test
└── foo.spec.js
./node_modules has bluebird and jasmine-node in it. This is what I get:
$ ./node_modules/.bin/jasmine-node --verbose test
describe
describe
it
it
Test - 5 ms
one - 4 ms
should work - 4 ms
two - 1 ms
should work - 1 ms
Finished in 0.007 seconds
2 tests, 2 assertions, 0 failures, 0 skipped
Try to use a promise, something like:
var deferred = protractor.promise.defer();
var itemsPromise = deferred.promise;
beforeAll(function() {
data.get(function(err, result) {
deferred.fulfill(result);
});
})
And then:
describe('check each item', function() {
itemsPromise.then(function(itemsArr) {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
});
Another solution I can think of is to use browser.wait to wait until itemsArr becomes not empty.
Is your get-data module doing some browser things with protractor? If so, you will need to set/get itemsArr within the context of the controlFlow. Otherwise it will read all the code in the get-data module, but defer its execution and not wait for it to finish before moving right along to those expect statements.
var data = require('get-data'); //custom module here
var itemsArr;
describe('Test', function() {
beforeAll(function() {
// hook into the controlFlow and set the value of the variable
browser.controlFlow().execute(function() {
data.get(function(err, result) {
itemsArr = result; //load data from module
});
});
});
//error: Cannot read property 'forEach' of undefined
describe('check each item', function() {
// hook into the controlFlow and get the value of the variable (at that point in time)
browser.controlFlow().execute(function() {
itemsArr.forEach(function(item) {
checkItem(item);
});
});
});
function checkItem (item) {
var itemName = item.name;
describe(itemName, function() {
console.log('describe');
it('should work', function() {
console.log('it');
expect(true).toBeTruthy();
});
});
}
});

Protractor and Angular: How to test two pages in an app, one after the other?

I would like to run Protractor tests on two separate pages in my Angular app: /dashboard and /articles.
The complication is that I have to log in to the app manually.
Currently I have this setup:
var LoginPage = function() {
ptor = protractor.getInstance();
this.login = function(url) {
ptor.get(url);
ptor.findElement(protractor.By.model('email')).sendKeys(config.LOGIN_EMAIL);
ptor.findElement(protractor.By.model('password')).sendKeys(config.LOGIN_PASS);
ptor.findElement(protractor.By.tagName('button')).click();
};
};
describe('The dashboard', function() {
console.log('logging in');
var loginPage = new LoginPage();
loginPage.login(config.DASHBOARD_URL);
console.log('logged in');
it('has a heading', function() {
console.log('testing dashboard 1');
heading = ptor.findElement(protractor.By.tagName('h1'));
expect(heading.getText()).toEqual(config.DASHBOARD_HEADING);
});
});
describe('The article widget', function() {
console.log('logging in');
var loginPage = new LoginPage();
loginPage.login(config.ARTICLE_URL);
console.log('logged in');
it('has a heading', function() {
console.log('testing article 1');
heading = ptor.findElement(protractor.By.tagName('h1'));
expect(heading.getText()).toEqual(config.ARTICLES_HEADING);
});
});
This gives me the following output:
Selenium standalone server started at http://192.168.2.9:56791/wd/hub
logging in
LoginPage
logged in
logging in
LoginPage
logged in
testing dashboard 1
Ftesting article 1
It looks as though both the describe sections are kicking off in parallel. How can I force the following sequence of events, while still structuring the code in a sensible way?
Load dashboard page
Log in
Run dashboard tests
Load article page (Assume we are already logged in)
Run article tests
You can move the login to another file.
Then, in your protractor configuration file do this:
exports.config = {
specs: [
'spec/login.js',
'spec/dashboard_test.js',
'spec/article_test.js'
],
...
};
Login will run before the other tests
describe('my app', function(){
beforeEach(function(){
login()...
})
describe('dashboard');
describe('the article widget')
});
The Protractor documentation recommends
put your log-in code into an onPrepare function, which will be run once before any of your tests.
For example in your protractor.conf
onPrepare: function() {
browser.driver.get('http://localhost/login.html');
browser.driver.findElement(by.id('username')).sendKeys('Jane');
browser.driver.findElement(by.id('password')).sendKeys('1234');
browser.driver.findElement(by.id('clickme')).click();
// Login takes some time, so wait until it's done.
// For the test app's login, we know it's done when it redirects to
// index.html.
return browser.driver.wait(function() {
return browser.driver.getCurrentUrl().then(function(url) {
return /index/.test(url);
});
}, 10000);
}
I had a similar issue with my e2e protractor tests. Describe blocks were being executed in parallel, causing my tests to fail.
My code before the fix was something like:
describe('test1', function() {
it('do foo1', function() {..});
describe('do test1', function() {..});
});
describe('test2', function() {
it('do foo2', function() {..});
describe('do test2', function() {..});
});
Both the describe blocks were being executed in parallel causing my tests to fail. The fix was to enclose the it blocks in describe blocks.
Code after the fix:
describe('test1', function() {
describe('foo1', function() {
it('do foo1', function() {..});
});
describe('do test1', function() {..});
});
describe('test2', function() {
describe('foo2', function() {
it('do foo2', function() {..});
});
describe('do test2', function() {..});
});
Link to a similar issue on protractor github: https://github.com/angular/protractor/issues/592

Categories

Resources