Page Object Model File:
var loginPage = function() {
console.log('Constructor~!');
};
loginPage.prototype = {
constructor: loginPage,
login: function () {
console.log('now I doing something');
browser.sleep(10000);
},
searchForElements: function () {
console.log('action that is after I login');
browser.sleep(20000);
},
addAnotherUser: function () {
console.log('now I doing something way into the future');
},
};
module.exports = loginPage;
Protractor Test File:
var loginPage = require("../pages/test.page.js");
describe('Creating new account', function(){
it('account will be created',function(){
loginPage = new loginPage();
loginPage.login();
console.log('On the page');
loginPage.searchForElements();
loginPage.addAnotherUser();
});
});
When I run this using protractor the console immediately prints out:
Constructor~!
now I doing something
On the page
action that is after I login
now I doing something way into the future
I would have thought that it wouldn't echo out the 'On the page' until after the browser has waited 10 seconds.
How can I sync up the browser and the javascript so that the searchForElements function doesn't run until the browser has completed the login function?
Related
I want to show a preloader over all the contents when a page is loading and hide it when the page load is finished and show the content (I'm not talking about internal links- like when you type an address in the browser and waiting for the page to load.)
Like this demo: https://demo.app-framework.com/
I’ve tried this:
var app = new Framework7({
// App root element
root: '#app',
// App Name
name: 'My App',
// App id
id: 'com.myapp.test',
on: {
init: function () {
console.log('App initialized');
},
pageInit: function () {
console.log('Page initialized');
app.preloader.hide();
},
}
// ... other parameters
});
var mainView = app.views.create('.view-main');
app.preloader.show();
But it doesn't work it shows the loader like other elements and doesn't hide it, I'm not sure if its something possible. I would appreciate if someone can point me in the right direction.
That's because in the pageInit event you are referring to a variable which is not initialised by the time you are calling (var app), please find the code snippet usefull.
var app = new Framework7({
// App root element
root: '#app',
// App Name
name: 'My App',
// App id
id: 'com.myapp.test',
on: {
init: function () {
console.log('App initialized');
},
pageInit: function () {
console.log('Page initialized');
//app.preloader.hide(); //app is not yet initialized this will return an undefined error.
},
}
// ... other parameters
});
var mainView = app.views.create('.view-main');
app.preloader.show(); //var app is initialized by now
app.on('pageInit', function (page) {
console.log('Page is now initialized');
app.preloader.hide();
});
The docs on Page has a section on Page Events. https://framework7.io/docs/page.html#page-name
Use app.preloader.show(); on an early event, and use app.preloader.hide(); when you want it removed.
pageBeforeIn: function (e, page) {
app.preloader.show();
},
pageAfterIn: function (e, page) {
app.preloader.hide();
},
Before I can reach the site to be tested I have to visit a login (non-angular) page first
var url = 'http://localhost:9999/login?usern=bar';
browser.driver.get(url);
Although that is a non-angular page, passing the ?usern=bar into the url the server gives an HTTP CODE of 302, and redirects to the page /new-user. Inside the new-user page I have to click a button before I can begin testing
But whatever I do I always get
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
There is something wrong in my flow, because I can see the new-user page, but the button is not clicked (and long after that the errors appear)
The spec file:
var Site = require('helper/site');
describe('Main', function {
beforeAll(function () {
return Site.login();
});
it('should show the main page', function () {
epect(browser.getCurrentUrl()).toMatch(/\/main/);
});
});
Site.js:
function login() {
browser.driver.get('http://localhost:9999/login?usern=bar');
browser.driver.wait(function () {
return browser.driver.getCurrentUrl().then(function (url) {
return /\/new-user/.test(url);
});
});
element(by.css('.save')).click();
}
module.exports = {
login: login
};
Any help would be appreciated
You have to turn the sync off:
describe('Main', function {
beforeAll(function () {
browser.ignoreSynchronization = true;
return Site.login();
});
it('should show the main page', function () {
browser.ignoreSynchronization = false;
expect(browser.getCurrentUrl()).toMatch(/\/main/);
});
});
Though, think of better places to turn it off and then on again once you are on the main page.
I used browser.waitForAngularEnabled(false) to turn off waiting for angular app. My app used O365 login.
public async HandleO365Login() {
await browser.waitForAngularEnabled(false);
await this.o365usernameTextBox.sendKeys(Constants.USER_EMAIL);
await this.o365NextButton.click();
}
You can turn it on after your angular app gets loaded.
Question
Why does driver work fine(the title is retrieved and tested), but web driver is undefined(unable to getText)?
Expected Result
The tests will complete successfully.
Actual Result
․ Google when at home Page should have correct title: 141ms
1) Google when at home Page when searching should input search term
1 passing (3s)
1 failing
1) Google when at home Page when searching should input search term:
ReferenceError: webdriver is not defined
Files Used
Test File
Used to run the tests by executing command: mocha -t -R list index.js (assuming index.js is the filename)
var fs = require('fs'),
chai = require('chai'),
assert = chai.assert,
expect = chai.expect,
test = require('selenium-webdriver/testing'),
webdriver = require('selenium-webdriver'),
Page = require('./pageobjects/pages/home');
test.describe('Google', function(){
test.before(function(){
driver = new webdriver.Builder().
withCapabilities(webdriver.Capabilities.firefox()).
build();
//initialize driver and webdriver on the Page Object
Page.webdriver = webdriver;
Page.driver = driver;
});
test.describe("", function () {
test.before(function(){
//console.log(Page);
});
test.describe("when at home Page", function () {
test.before(function () {
Page.get(Page.URL);
});
test.it("should have correct title", function () {
Page.getTitle()
.then(function (title) {
assert.equal(title, 'Google');
});
});
test.describe("when searching", function () {
test.it("input search term", function () {
Page.sendKeys(Page.Search.INPUT, 'test');
Page.getText(Page.Search.INPUT)
.then(function (text) {
assert.equal(text, 'test');
});
});
});
test.after(function () {
driver.quit();
});
});
});
});
Page
object used to create pages
var Page = {
getTitle : function getTitle() {
return driver.getTitle();
},
get : function get(url) {
return driver.get(url);
},
sendKeys : function sendKeys(element, text) {
console.log(webdriver);
driver.findElement(webdriver.By.css(element)).sendKeys(text);
},
click : function click(element) {
return driver.findElement(webdriver.By.css(element)).click();
}
};
module.exports = Page;
Home
object that represents a page, uses mixins to get Page's functions
the search file is left out because it is irrelevant to the problem
var Page = require('./page'),
Search = require('../components/search'),
extend = require('extend');
var Home = {
URL : 'http://google.com',
Search : Search
};
module.exports = Home;
//extend home with page
extend(module.exports, Page);
I have a simple route in my app like this:
Dash.PostsNewRoute = Em.Route.extend({
model: function() {
return this.store.createRecord('post');
},
actions: {
saveForm: function() {
this.modelFor('postsNew').save();
}
}
});
Here is the test I've written to test saveForm and ensure that it's been called:
...
context('create new post', function() {
beforeEach(function() {
...
});
it('calls submit on route', function() {
var mock;
mock = sinon.mock(testHelper.lookup('route', 'posts.new'));
mock.expects('actions.saveForm').once();
this.submitButton.click();
mock.verify();
mock.restore();
});
});
However, I get an error with this implementation:
Attempted to wrap undefined property actions.saveForm as function
If I change the route and it's test like this, it'll work:
// Moving the save out of action and call it
Dash.PostsNewRoute = Em.Route.extend({
model: function() {
this.store.createRecord('post');
},
save: function() {
this.modelFor('postsNew').save()
},
actions: {
saveForm: function() {
this.save();
}
}
});
The new test:
it('calls submit on route', function() {
var mock;
mock = sinon.mock(testHelper.lookup('route', 'posts.new'));
mock.expects('save').once();
this.submitButton.click();
mock.verify();
mock.restore();
});
This way the test will pass. Is it possible to test actions.saveForm directly? Is the limitation of sinon that prevents me from accessing actions.saveForm?
You could mock the actions hash and set expectation for it like so:
mock = sinon.mock(testHelper.lookup('controller', 'posts_new')._actions);
mock.expects('save').once();
this.submitButton.click();
mock.verify();
mock.restore();
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