AngularJS - scenario.js code - angularjs

In the application building tutorial on angularjs.org, step-8, testing part, what does the following lines of code mean-
element.all(by.css('.phones li a')).first().click();
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
Thanks in advance!
PS:
The exact URL is- https://docs.angularjs.org/tutorial/step_08 and the code file (scenarios.js) is-
'use strict';
// Angular E2E Testing Guide:
// https://docs.angularjs.org/guide/e2e-testing
describe('PhoneCat Application', function() {
describe('phoneList', function() {
beforeEach(function() {
browser.get('index.html');
});
it('should filter the phone list as a user types into the search box', function() {
var phoneList = element.all(by.repeater('phone in $ctrl.phones'));
var query = element(by.model('$ctrl.query'));
expect(phoneList.count()).toBe(20);
query.sendKeys('nexus');
expect(phoneList.count()).toBe(1);
query.clear();
query.sendKeys('motorola');
expect(phoneList.count()).toBe(8);
});
it('should be possible to control phone order via the drop-down menu', function() {
var queryField = element(by.model('$ctrl.query'));
var orderSelect = element(by.model('$ctrl.orderProp'));
var nameOption = orderSelect.element(by.css('option[value="name"]'));
var phoneNameColumn = element.all(by.repeater('phone in $ctrl.phones').column('phone.name'));
function getNames() {
return phoneNameColumn.map(function(elem) {
return elem.getText();
});
}
queryField.sendKeys('tablet'); // Let's narrow the dataset to make the assertions shorter
expect(getNames()).toEqual([
'Motorola XOOM\u2122 with Wi-Fi',
'MOTOROLA XOOM\u2122'
]);
nameOption.click();
expect(getNames()).toEqual([
'MOTOROLA XOOM\u2122',
'Motorola XOOM\u2122 with Wi-Fi'
]);
});
it('should render phone specific links', function() {
var query = element(by.model('$ctrl.query'));
query.sendKeys('nexus');
element.all(by.css('.phones li a')).first().click();
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
});
});
});

It is testing of the routing to /phones/nexus-s.
It is written in Protractor.
The first line reads the DOM and finds all the .phones li a css rules. It then takes only the first one and calls click() on it.
element.all(by.css('.phones li a')).first().click();
The second line expects the output of the function browser.getLocationAbsUrl() to be the string /phone/nexus-s
expect(browser.getLocationAbsUrl()).toBe('/phones/nexus-s');
So all in all the test framework clicks a button and expects it to be routed to a new page.

Related

Can an "it" block be called multiple times in different spec files using Page Objects

I am fairly new to Protractor and Page Objects. I am trying to get the header to show across multiple pages. I have a header_page.js and a header_spec.js. I can verify that the header is present once within the header_spec.js (which is presently only pointing to the home page). What I would like to do is call the test for the header each time I visit a page.
var HomePage = require('../pages/home_page.js');
var HeaderPage = require('../pages/header_page.js');
describe('When visiting a page'. function(){
var headerPage = new HeaderPage();
var inbox_page = new HomePage();
beforeEach(function () {
inbox_page.visit();
});
it('header menu selector should be present', function(){
header_menu = headerPage.hdr_menu;
header_menu.click();
expect('header_menu').not.toBe(null);
});
});
});
I am not sure how to call this test from page2_spec.js..page3_spec.js as each page is different but should all contain a header. I am trying to avoid code duplication and would like to avoid calling the "it" block from each page. Do I use a helper file or can I move the it block inside the header_page.js..currently looks like this:
module.exports = function(){
this.hdr_menu = element(by.css('#pick-group-btn'));
this.hdr_img = element(by.css('PeopleAdmin logo'));
}
you can call a test spec to other specs by wrapping your spec in a function and exporting it "requiring" that module So in your case you can export header_spec.js to other modules such as page2_spec.js or page3_spec.js by :
var HomePage = require('../pages/home_page.js');
var HeaderPage = require('../pages/header_page.js');
var commHeader = function(){
describe('When visiting a page'. function(){
var headerPage = new HeaderPage();
var inbox_page = new HomePage();
beforeEach(function () {
inbox_page.visit();
});
it('header menu selector should be present', function(){
header_menu = headerPage.hdr_menu;
header_menu.click();
expect('header_menu').not.toBe(null);
});
});
});
}
module.exports = commHeader;
Then in you page2_spec.js file you can import this module like this :
var commHeader = require('your path to spec/commHeader.js');
describe('When visiting page 2 validate Header first'. function(){
var headerTest = new commHeader();
headerTest.commHeader();
it('page 2 element validations', function(){
//here the page 2 test goes
});
});
});

Testing component that opens md-dialog

I am trying to write a unit test for an Angular component that opens a dialog, but am unable to do so because I cannot trigger the closing of the dialog.
How can I cause the md dialog to resolve from the test case?
I have created a repository with a basic example where the problem can be reproduced, and copied the central bits below. There is an index.html to manually verify that the code is working, a test case that displays the problem and an example of how the tests are written in the md code.
Repository - https://github.com/gseabrook/md-dialog-test-issue
The component is extremely basic
angular
.module('test', ['ngMaterial'])
.component('dialogTest', {
template: '<button ng-click="showDialog()">Show Dialog</button>',
controller: function($scope, $mdDialog) {
var self = this;
$scope.showDialog = function() {
self.dialogOpen = true;
var confirm = $mdDialog.confirm()
.title('Dialog title')
.ok('OK')
.cancel('Cancel');
$mdDialog.show(confirm).then(function(result) {
self.dialogOpen = false;
}, function() {
self.dialogOpen = false;
});
}
}
});
And the test is also very simple
it("should open then close the dialog", function() {
var controller = element.controller("dialogTest");
expect(controller.dialogOpen).toEqual(undefined);
expect(element.find('button').length).toEqual(1);
element.find('button').triggerHandler('click');
expect(controller.dialogOpen).toBeTruthy();
rootScope.$apply();
material.flushInterimElement();
element.find('button').eq(2).triggerHandler('click');
rootScope.$apply();
material.flushInterimElement();
expect(controller.dialogOpen).toBeFalsy();
});
I managed to resolve the issue by setting the root element as the problem seemed to be related to element being compiled in the test being unconnected with the root element that angular-material appended the dialog too.
I've updated the github repository with the full code, but the important bits are
beforeEach(module(function($provide) {
rootElem = angular.element("<div></div>")
$provide.value('$rootElement', rootElem);
}));
beforeEach(inject(function(_$rootScope_, _$compile_, $mdDialog, _$material_) {
...
element = getCompiledElement();
angular.element(window.document.body).append(rootElem);
angular.element(rootElem).append(element);
}));

Pass a variable in sendKeys e2e testing using protractor

I am new to e2e testing and I am writing e2e test cases for my angular aplication. Here I am creating a patient and I want to book an appointment for the same patient.
This is the code
it('Add Patient', function(){
var fname = element(by.model('newrecord.firstName')).sendKeys('Riaz');
element( by.css('[ng-click="ok()"]') ).click();
});
it('Create Appointment', function(){
element(by.model('newrecord.patientId')).sendKeys(fname);
});
I am getting the below error
ReferenceError: fname is not defined
How to pass variable to sendKeys?
// Page Object
var recordPage = {
firstNameElm: element(by.model('newrecord.firstName')),
patientIdElm: element(by.model('newrecord.patientId')),
okBtnElm: element(by.css('[ng-click="ok()"]')),
};
// Test data
var testData = {
patient: {
idTxt: 'Riaz001',
firstName: 'Riaz',
},
};
it('adds patient', function() {
recordPage.firstNameElm.sendKeys(testData.patient.firstName);
recordPage.okBtnElm.click();
});
it('creates an appointment', function() {
// not sure what you want to send here but should be text not an ElementFinder
recordPage.patientIdElm.sendKeys(testData.patient.idTxt);
});

protractor expect currenturl fails

I'm trying to get an e2e test running against my local server and test that the resulting url (after a navigational button has been clicked) is the correct result. However the resulting url is always false.
My code is shown below:
HTML:
//http://localhost/#/current_Page
<html>
<head><title></title></head>
<body>
//should change the current url to
//http://localhost/#/new_page
<button class="button" ng-click="change_page()">Change Page</button>
</html>
TEST CODE:
var protractor = require('protractor');
require('protractor/jasminewd');
describe('Tests', function() {
var ptor;
describe('Test 1', function() {
var ptor = protractor.getInstance();
ptor.get('#/current_page');
it('change page and current url', function() {
ptor.findElement(protractor.By.className('.button').click().then(function() {
expect(ptor.currentUrl()).toContain('#/new_page');
});
});
}, 30000);
});
The issue is the current url after clicking the button remains #/current_url and does not change to the expected result #/new_page.
Does anyone know where I have gone wrong?
After search for the answer to this question I figured it out myself
The current url does not fail, I was not waiting for the promise to return to angular. The ammended code below shows where I had gone wrong
var protractor = require('protractor');
require('protractor/jasminewd');
describe('Tests', function() {
var ptor;
describe('Test 1', function() {
var ptor = protractor.getInstance();
ptor.get('#/current_page');
it('change page and current url', function() {
ptor.findElement(protractor.By.className('.button').click().then(function() {
ptor.waitForAngular();
expect(ptor.currentUrl()).toContain('#/new_page');
});
});
}, 30000);
});
This then waits for angular to route to the new page and update any bindings and then proceeds to check the expected result which is now what I would expect it to be.
Please be advised that this does not solve all issues relating to unexpected getCurrentUrl() results. if using driver.findElement() you may need to refer to JulieMR's answer to this question
I hope this helps someone stuck on this issue.
In Protractor 1.5.0 protractor.getInstance(); isn't working anymore, so you have to use browser instead.
var protractor = require('protractor');
require('protractor/jasminewd');
describe('Tests', function() {
describe('Test 1', function() {
browser.get('#/current_page');
it('change page and current url', function() {
ptor.findElement(protractor.By.className('.button').click().then(function() {
browser.waitForAngular();
expect(browser.getCurrentUrl()).toContain('#/new_page');
});
});
}, 30000);
});
You can also write a custom expected condition to wait for current url to being equal a desired one. Besides, use browser and element notations:
browser.get("#/current_page");
it("change page and current url", function() {
element(by.css(".button")).click();
browser.wait(urlChanged("#/new_page")), 5000);
});
where urlChanged is:
var urlChanged = function(url) {
return function () {
return browser.getCurrentUrl().then(function(actualUrl) {
return actualUrl.indexOf(url) >= 0;
});
};
};
Or, a Protractor>=4.0.0 solution and the urlContains expected condition:
element(by.css(".button")).click();
var EC = protractor.ExpectedConditions;
browser.wait(EC.urlContains("#/new_page"), 5000);

Missing injection for test (unkown provider)

I am trying to write unit tests for my Angular.js application but I cannot manage to inject what I need (it is not able to find a suitable provider).
Does anyone see what I missed?
Firefox 21.0 (Linux) filter staticList should convert static list object into its display value FAILED
Error: Unknown provider: staticListProvider <- staticList in /path/to/my-app/public/third-party/angular/angular.js (line 2734)
createInjector/providerInjector<#/path/to/my-app/public/third-party/angular/angular.js:2734
getService#/path/to/my-app/public/third-party/angular/angular.js:2862
createInjector/instanceCache.$injector<#/path/to/my-app/public/third-party/angular/angular.js:2739
getService#/path/to/my-app/public/third-party/angular/angular.js:2862
invoke#/path/to/my-app/public/third-party/angular/angular.js:2880
workFn#/path/to/my-app/test/lib/angular/angular-mocks.js:1778
angular.mock.inject#/path/to/my-app/test/lib/angular/angular-mocks.js:1764
#/path/to/my-app/test/unit/filtersSpec.js:19
#/path/to/my-app/test/unit/filtersSpec.js:16
#/path/to/my-app/test/unit/filtersSpec.js:3
The application:
angular.module('myApp', ['myAppFilters', 'ui.bootstrap', '$strap.directives']).
// Some other stuff
The filters:
"use strict";
angular.module('myAppFilters', []).
filter('staticList', function () {
return function (listItem) {
if (!listItem) {
return '';
}
return listItem.value;
};
});
The test:
'use strict';
describe('filter', function () {
beforeEach(angular.module('myAppFilters'));
describe('staticList', function () {
it('should convert static list object into its display value',
inject(function (staticList) {
expect(undefined).toBe('');
expect({key: 'A', value: 'B'}).toBe('B');
}));
});
});
The Karma configuration:
basePath = '../';
files = [
JASMINE,
JASMINE_ADAPTER,
'public/third-party/jquery/*.js',
'public/third-party/angular/angular.js',
'public/third-party/angular/i18n/angular-*.js',
'public/third-party/moment/moment.min.js',
'public/third-party/moment/moment-*.js',
'public/js/**/*.js',
'test/lib/**/*.js',
'test/unit/**/*.js'
];
colors = true;
autoWatch = true;
browsers = ['Firefox'];
junitReporter = {
outputFile: 'test_out/unit.xml',
suite: 'unit'
};
If anybody wants to see the full code, the application repository is here: https://github.com/adericbourg/GestionCourrier
Thanks a lot,
Alban
In your inject code
it('should convert static list object into its display value',
inject(function (staticList) {
expect(undefined).toBe('');
expect({key: 'A', value: 'B'}).toBe('B');
}));
replace "inject(function (staticList)" with "inject(function (staticListFilter)". This is some random convention angular is following. You can check comments on this page for more info http://docs.angularjs.org/tutorial/step_09
I faced similar problem, but in my case my filter name contained suffix 'Filter' which caused the same injection problem.
.filter('assetLabelFilter', function(){
return function(assets, selectedLabels){
// Implementation here
};
});
I was finally able to solve the problem by manually injecting the filter to my test
'use strict';
describe('assetLabelFilter', function() {
beforeEach(module('filters.labels'));
var asset1 = {labels: ['A']};
var asset2 = {labels: ['B']};
var asset3 = {labels: []};
var asset4 = {labels: ['A', 'B']};
var assets = [asset1, asset2, asset3, asset4];
var assetLabelFilter;
beforeEach(inject(function($filter) {
assetLabelFilter = $filter('assetLabelFilter');
}));
it('should return only assets with selected label', function() {
var selectedLabels = ['B'];
expect(assetLabelFilter(assets, selectedLabels)).toEqual([asset2, asset4]);
});
});
The nice answer above made me realize that in order to use the angular tutorial way:
it('should ', inject(function(assetLabelFilter) {
var selectedLabels = ['B'];
expect(assetLabelFilter(assets, selectedLabels)).toEqual([asset2, asset4]);
}));
The filter name can't have the suffix 'Filter' because it is magic word as mentioned in the answer above.
To demonstrate the scenario I also created a Plunker

Resources