Learning JS, wondering is it possible in Protractor to do something like
before Test1,3,5,7,9,11 etc(function(){
browser.get('http://192.168.1.117:7777/#/route1');
});
and
before Test2,4,6,8,10 etc(function(){
browser.get('http://192.168.1.117:7777/#/route2');
});
Or the only way to do before is
beforeEach(function(){
browser.get('http://192.168.1.117:7777/#/route');
});
Don't wanna write browser.get every time, but can't use beforeEach cause it's 2 routes, not 1. Excuse me, if my question is ordinary, thanks in advance :)
What i have understood from above question is that you have two different baseUrls and need to use one for a group of test cases and other for remaining test cases.
If I'm right, then answer is "You DON'T have such option". You can do either of following alternative solutions:
Divide the test cases into Groups(say describe block here). The test cases which needs to run one first baseUrl, keep them all in one describe block
describe('group of test cases which uses route1 url', function(){
//you can use beforeEach and/or beforeAll
beforeEach(function(){
browser.get("http://baseUrl1/route1");
})
beforeAll(function() {
browser.get("http://baseUrl1/route1");
})
it('test case1', function(){
});
it('test case2', function(){
});
it('test case3', function(){
});
});
Then another suite, could be in same file:
describe('group of test cases which uses route2 url',function(){
//you can use beforeEach and/or beforeAll
beforeEach(function(){
browser.get("http://baseUrl2/route2");
})
beforeAll(function() {
browser.get("http://baseUrl2/route2");
})
it('test case1', function(){
});
it('test case2', function(){
});
it('test case3', function(){
});
});
Try with "Using Multiple Browsers in the Same Test" http://www.protractortest.org/#/browser-setup
You should just probably organize your tests in specs accordingly:
describe('all tests', function() {
describe('route 1 tests', function() {
beforeEach(function() {
browser.get('route1');
});
...
});
describe('route 2 tests', function() {
beforeEach(function() {
browser.get('route2');
});
...
});
});
Related
I have a strange situation (you can read about the context here. I'm not sure that the answer to this question will answer the question in the link, hence two questions.), where I'd like to modify an AngularJS service after the framework has already been loaded. Here's some code we'd like to do:
<script>
document.onload = function () {
angular.module('common')
.config(function ($provide) {
$provide.factory("$exceptionHandler", function () {
return function (exception) {
throw exception;
};
});
});
}
</script>
This works fine when it's not wrapped in a document.onload. But when it's put in an onload, it doesn't seem to have any effect. How can I modify a service in a document.onload?
For what it's worth, I'm on angular 1.2.
This worked when we tried it:
<script>
window.onload = function () {
angular.element(document.body).injector().invoke(function($log) {
$log.error = function(message) {
throw new Error(message)
};
});
}
</script>
I have a problem I want to test this javascript
$("#ShootBtn").on('click', () => foo.testFunc());
var foo = {
testFunc: function() {
hub.server.shoot(true, username, gameCode);
}
}
I'm using Jasmine as my test framework, and I have tried Karma and Chutzpah as my test runner.
In my test project where I try to refer to the file above I try have tried a lot of different things, but I can't seem to get my head around it. The test looks like this atm.
/// <reference path="../../TankWebApplication/Scripts/jquery-3.3.1.js"/>
/// <reference path="../../TankWebApplication/Scripts/virtualjoystick.js"/>
/// <reference path="../../TankWebApplication/Scripts/gameController.js"/>
describe("DefaultTest",
function () {
beforeEach(function() {
})
it("Test",
function() {
spyOn(foo, 'testFunc');
document.getElementById('ShootBtn').click();
expect(foo.testFunc).toHaveBeenCalled();
});
});
The testFunc haven't been called says:
TypeError: Cannot read property 'click' of null
Which I think means that it cannot click on my shootBtn
Is it impossible to test this, or what do I do wrong?
What you can do is to spy on document.getElementById and make it return an object that has click function :
spyOn(document, "getElementById").andCallFake(() => ({
click: () => foo.testFunc()
}));
jsFiddle
Otherwise, create an element with id = ShootBtn, attach a click handler to it then add it to the body (all this should be done inside your test)
jsFiddle
The following is in foo.js
var analytics = {};
analytics.myLinks = function(){
return 2;
};
analytics.myView = function() {
analytics.myLinks();
};
$('#marquee').on('click', analytics.myView);
The following is my spec file foo.spec.js Fixture is appended using jasmine-fixture utility's affix helper. (https://github.com/searls/jasmine-fixture)
(function() {
describe('click event handlers', function() {
it('calls function when #marquee is clicked on', function() {
affix('#marquee');
spyOn(analytics, 'myView').and.callThrough();
$('#marquee').trigger('click');
expect(analytics.myView).toHaveBeenCalled();
});
it('calls inner function when #marquee is clicked on', function() {
affix('#marquee');
spyOn(analytics, 'myLinks').and.callThrough();
$('#marquee').trigger('click');
expect(analytics.myLinks).toHaveBeenCalled();
});
});
}).call(this);
I am using Karma as my test runner and it throws an error on the above unit test saying
"Expected spy myView to have been called."
and
"Expected spy myLinks to have been called."
I have tried different variations of the same but not sure where I am going wrong. Please help!
I have a bootstrapped Angular (1.2.6) app. This means it doesn't have an explicit ng-app. As such, I've run into all sorts of problems getting Protractor framework'd tests to work (using SauceLabs and grunt-protractor-runner).
The errors vary based on what I try, but generally:
Error: Angular could not be found on the page http://xxx:9000/ :
angular never provided resumeBootstrap
Or...
Error: Error while waiting for Protractor to sync with the page: {}
I've found a few proposed solutions which I've tried. Including those found in this rich thread, as well as here, too. Nothing I do, though, gets things working.
I've tried to use angular.resumeBootstrap in the bootstrapping like so (note I tried multiple variations of this to no avail, including trying to set an ng-app programatically on the document body):
angular.element( document ).ready( function() {
window.name = 'NG_DEFER_BOOTSTRAP!'
angular.bootstrap( document, [ 'app' ] );
setTimeout( angular.resumeBootstrap, 0 );
});
The error for this, as others have found, is weird:
UnknownError: unknown error: [ng:btstrpd] App Already Bootstrapped with this Element
'<body ng-app="" ng-controller="ApplicationController" class=" ng-scope pace-done">'
What's weird/annoying is that, at least looking in Sauce Labs session, it appears that this test is working... it's just weirdly thinking that it's been bootstrapped twice.
I've also tried using various combinations of waitForAngular, wait, and others in the test itself. Here's one variation I've tried:
it( 'should load the home page', function() {
ptor = protractor.getInstance();
ptor.waitForAngular();
ptor.driver.get( 'http://xxx:9000/' );
ptor.driver.wait( function() {
return ptor.getCurrentUrl().then( function() {
return ptor.isElementPresent( by.id( 'signIn' ) ).then( function() {
console.log('we are here!');
return true;
});
});
})
.then( function() {
expect( ptor.isElementPresent( by.id( 'signIn' ) ) ).toBe( true );
});
});
This results in errors like the following:
1) e2e: home should load the home page
Message: timeout: timed out after 20000 msec waiting for spec to complete
Stacktrace: undefined
I've also tried increasing various timeouts in the config file to no avail.
Any help would be much appreciated!
You should separate the test in two 'it'-steps. Like this:
it( 'should load angular', function() {
ptor = protractor.getInstance();
ptor.waitForAngular();
})
it( 'should load the home page', function() {
ptor.driver.get( 'http://xxx:9000/' );
ptor.driver.wait( function() {
return ptor.getCurrentUrl().then( function() {
return ptor.isElementPresent( by.id( 'signIn' ) ).then( function() {
console.log('we are here!');
return true;
});
});
})
.then( function() {
expect( ptor.isElementPresent( by.id( 'signIn' ) ) ).toBe( true );
});
});
The problem with protractor is that every command runs without waiting for the prior step to complete. So, ptor.waitForAngular() and ptor.driver.get( 'http://xxx:9000/' ) are running at almost the same time. If you separate these into two steps, protractor moves on after the first 'it'-step is done.
My Protractor e2e tests are inconsistently passing and failing.
It seems this could be due to asynchronous javascript, as discussed here:
Protractor : How to wait for page complete after click a button?.
However, here it's mentioned that Protractor tests automatically execute sequentially / synchronously:
https://github.com/angular/protractor/issues/909
My test script:
describe('Login', function() {
var ptor;
beforeEach(function() {
browser.get('https://127.0.0.1:8443');
ptor = protractor.getInstance();
element(by.id('splash')).click();
browser.ignoreSynchronization = true; // <-- to proceed beyond splash screen
});
describe('with correct email and password', function() {
beforeEach(function() {
element(by.id('email')).sendKeys('admin#email.com');
element(by.id('password')).sendKeys('adminpassword');
element(by.id('loginButton')).click();
});
afterEach(function() {
ptor.findElement(by.id('logout')).then(function(elem) {
elem.click();
});
});
it('does not show alert', function() { // <-- sometimes passes, sometimes fails
expect(browser.isElementPresent(by.css('.alert-danger'))).toBe(false);
});
it('changes route to /admin', function() { // <-- sometimes passes, sometimes fails
expect(browser.getCurrentUrl()).toMatch(/\/admin/);
});
});
});
In the two tests above, either both tests will pass, or one/both of the tests will fail with these messages:
Failures:
1) Login with correct email and password does not show alert
Message:
NoSuchElementError: no such element
...
==== async task ====
WebDriver.findElement(By.id("logout"))
...
or
Failures:
1) Login with correct email and password changes route to /admin
Message:
NoSuchElementError: no such element
...
==== async task ====
WebDriver.findElement(By.id("logout"))
...
Thoughts / help much appreciated.
I was able to resolve the issue based on the following:
Avishay's answer here about adding ptor.waitForAngular():
No element found using locator: by.model() error
Changing browser.get to ptor.get, as in Harri Siirak's answer here:
Protractor times out waiting for sync with page when using $resource
juliemr's comment here about ignoreSynchronization being an instance variable, and changing browser.ignoreSynchronization=true to ptor.ignoreSynchronization=true:
https://github.com/angular/protractor/issues/49
glepretre's answer here about using .then():
Protractor : How to wait for page complete after click a button?
As mentioned by Nguyen Vu Hoang's comment to the original question, I am testing a pure Angular app with what I think is pure Protractor (no webdriver calls). I know ptor.ignoreSynchronization=true should not be required in this case, but for some reason, the tests are not proceeding at button click without this setting.
My new spec:
describe('Login', function() {
var ptor;
beforeEach(function() {
ptor = protractor.getInstance();
ptor.ignoreSynchronization = true;
ptor.waitForAngular();
ptor.get('https://127.0.0.1:8443');
ptor.findElement(by.id('splash')).then(function(elem) {
elem.click();
});
});
describe('with correct email and password', function() {
beforeEach(function() {
ptor.findElement(by.id('email')).then(function(elem) {
elem.sendKeys('admin#email.com');
});
ptor.findElement(by.id('password')).then(function(elem) {
elem.sendKeys('adminpassword');
});
ptor.findElement(by.id('loginButton')).then(function(elem) {
elem.click();
});
});
afterEach(function() {
ptor.findElement(by.id('logout')).then(function(elem) {
elem.click();
});
});
it('does not show alert', function() {
expect(ptor.isElementPresent(by.css('.alert-danger'))).toBe(false);
});
it('changes route to /admin', function() {
expect(ptor.getCurrentUrl()).toMatch(/\/admin/);
});
});
});
There is also an another technique to make your tests more stable: Explicit Waits and Expected Conditions (docs).
I've found using Expected Conditions especially useful when testing against non-angular pages or angular applications that have a lot of animations involved.
For example, you can wait for an element to be clickable before making a click:
var EC = protractor.ExpectedConditions;
var link = element(by.id("mylink"));
browser.wait(EC.elementToBeClickable(link), "10000", "The link is still not clickable");
link.click();
There are also other built-in Expected Conditions, such as:
presenseOf()
visibilityOf()
alertIsPresent()
textToBePresentInElementValue()
etc
And, it is easy to write a custom Expected Condition, example use case:
Testing link style changes
You can also combine Expected Conditions using and, or and not, e.g.:
var urlChanged = function() {
return browser.getCurrentUrl().then(function(url) {
return url != 'http://www.angularjs.org';
});
};
// condition to wait for url to change, title to contain 'foo', and $('abc') element to contain text 'bar'
var condition = EC.and(urlChanged, EC.titleContains('foo'), EC.textToBePresentInElement($('abc'), 'bar'));
$('navButton').click();
browser.wait(condition, 5000); //wait for condition to be true.
browser.ignoreSynchronization = true; has a global effect for all your tests. you may have to set it back to false, so protractor waits for angular to be finished rendering the page. e.g. in or before your second beforeEach function