I moved from automation framework development with java to protractor & javascript so this is new to me. In my protractor framework I need to create a base screen js file with global functions that can be called from other screens js files. See the following example. How to make login.js inheritance all functions from base.js so the test in loginTest.js will work when calling base.js functions directly from login.js?
base.js
var base= function(){
var that = {
navigateToLogin: function(url){
browser.get(url);
browser.driver.manage().window().maximize();
return require('login.js');
},
click: function(element, page){
element.click();
console.log('LOG: Clicked on element ' + element);
return that || page;
},
insert: function(element, text){
element.clear().then(function() {
element.sendKeys(text);
console.log('LOG: Insert text: ' +text);
});
return that;
},
};
return that;
};
module.exports = new base();
login.js
var login = function(){
var that = {
func1: function() {
// do something
return that
},
func2: function() {
// do something
return that;
},
};
return that;
};
module.exports = new login();
loginTests.js
describe('Login tests - ', function() {
var loginPage = require('login.js');
describe('Success login: ', function () {
beforeEach(function () {
loginPage.navigateToLogin(“http://login.url”);
});
it("Success login as admin",function(){
loginPage.insert(“element(by.name("username"))”,”admin#mail”l)
.insert(“element(by.name("password"))”,”12345”)
.click(“element(by.name("loginButton"))”,“home.js”);
});
});
});
If you are using node.js > 4 (5 and more) try to use ES6 classes -
basepage.js:
class BasePage {
constructor() {
}
open() {
browser.get(url);
browser.driver.manage().window().maximize();
}
}
exports = BasePage
loginpage.js:
class LoginPage extends BasePage {
constructor() {
super()
}
login(username, password) {
//do your login stuff here
}
}
exports = LoginPage
Then in your test:
let LoginPage = require('loginpage.js');
describe('Login tests - ', function () {
let loginPage = new LoginPage()
beforeEach(function () {
loginPage.open('/login')
})
it("Success login as admin", function () {
loginPage.login('admin', '123456')
})
})
Related
I have written some service in angular. Check this PLUNKER.
Injecting CommonService, $rootRouter, ModalService in RouteService.
I am stuck with unit testing these services. You can see sample spec file at PLUNKER.
EDIT: Whatever test I have at plunker are not working as expected. Am not sure what I am doing wrong.
How to test goTo and getActivePage methods in RouteService?
How to test getProperty and setProperty methods in CommonService?
Here is code.
First service is RouteService
'use strict';
angular.module('mysampleapp')
.service('RouteService',
function(CommonService, $rootRouter, ModalService) {
console.log('RRRRRRRRRRRRRRRRRRRRRRRRRRRoute');
return {
goTo: goTo,
getActivePage: getActivePage
};
function goTo(page) {
var valid = CommonService.getProperty('isValidationSuccess');
switch (page) {
case 'AboutUs':
if (valid) {
CommonService.setProperty('activeMenu', page);
$rootRouter.navigate([page]);
} else {
ModalService.openModal('Analysis Error', 'Complete Application Group configuration prior to running analysis.', 'Error');
}
break;
default:
CommonService.setProperty('activeMenu', page);
$rootRouter.navigate([page]);
break;
}
}
function getActivePage() {
return CommonService.getProperty('activeMenu');
}
});
Another is CommonService
'use strict';
angular.module('mysampleapp')
.service('CommonService',
function() {
var obj = {
/* All page validation check before perform analysis */
isValidationSuccess: false,
/* Highlight the menu */
activeMenu: 'HomeMenu'
};
function setProperty(key, value) {
obj[key] = value;
}
function getProperty(key) {
return obj[key];
}
function getAllProperties() {
return obj;
}
return {
setProperty: setProperty,
getProperty: getProperty,
getAllProperties: getAllProperties
};
}
);
In your plunker you forgot to create the mysampleapp module before adding services to it:
angular.module('mysampleapp', []);
The test for setters and getters of CommonService should be pretty simple:
describe('CommonService', function () {
var commonService;
beforeEach(module('mysampleapp'));
beforeEach(inject(function (_CommonService_) {
commonService = _CommonService_;
}));
it('should set and get property', function () {
commonService.setProperty('isValidationSuccess', 'Perform');
expect(commonService.getProperty('isValidationSuccess')).toBe('Perform');
});
});
Unit tests for services in most cases should be islolated from other services. If you going to testing CommonService you must mock other services, such as CommonService and etc. Main reason that you do not have to worry how to run for another service, because in this test you expecting that other services will work correctly.
describe('RouteService', function () {
'use strict';
var RouteService,
ModalService,
CommonService,
mockedValue,
$rootRouter;
beforeEach(module('mysampleapp'));
beforeEach(inject(function (_RouteService_, _ModalService_, _CommonService_, _$rootRouter_) {
RouteService = _RouteService_;
ModalService = _ModalService_;
CommonService = _CommonService_;
$rootRouter = _$rootRouter_;
$rootRouter.navigate = jasmine.createSpy();
ModalService.openModal = jasmine.createSpy(); //sometimes open modal return promise, and you should check it to
CommonService.getProperty = jasmine.createSpy().and.callFake(function () {
return mockedValue;
});
CommonService.setProperty = jasmine.createSpy().and.callFake(function () {
return mockedValue;
});
}));
it('should exist', function () {
expect(RouteService).toBeDefined();
});
it('should get active page', function () {
RouteService.getActivePage();
expect(CommonService.getProperty).toHaveBeenCalled(); //this test make sens only for make you coverage 100%, in you case i mean
});
describe('goTo method', function () {
it('should check if it is valid page', function () {
RouteService.goTo();
expect(CommonService.getProperty).toHaveBeenCalled();
});
it('should set property if page is "about as" and if it is valid page, and should navigate to this page', function () {
mockedValue = true;
var page = 'AboutUs';
RouteService.goTo(page);
expect(CommonService.setProperty).toHaveBeenCalledWith('activeMenu', page);
expect($rootRouter.navigate).toHaveBeenCalledWith([page]);
expect(ModalService.openModal).not.toHaveBeenCalled();
});
it('should open modal with error if "about as" is not valid page', function () {
var isValid = mockedValue = false;
var page = 'AboutUs';
RouteService.goTo(page);
expect(ModalService.openModal).toHaveBeenCalled();
expect(CommonService.setProperty).not.toHaveBeenCalled();
expect($rootRouter.navigate).not.toHaveBeenCalled();
});
it('should set property and navigate to page', function () {
var page = 'Test Page';
RouteService.goTo(page);
expect(CommonService.setProperty).toHaveBeenCalledWith('activeMenu', page);
expect($rootRouter.navigate).toHaveBeenCalledWith([page]);
expect(ModalService.openModal).not.toHaveBeenCalled();
});
});
});
Is it possible to use method overriding in Vue.js?
var SomeClassA = Vue.extend({
methods: {
someFunction: function() {
// ClassA some stuff
}
}
});
var SomeClassB = SomeClassA.extend({
methods: {
someFunction: function() {
// CALL SomeClassA.someFunction
}
}
});
I want to call ClassA someFunction from ClassB someFunction. Is it even possible?
No, vue doesn't work with a direct inheritance model. You can't A.extend an component, as far as I know. It's parent-child relationships work mainly through props and events.
There are however three solutions:
1. Passing props (parent-child)
var SomeComponentA = Vue.extend({
methods: {
someFunction: function () {
// ClassA some stuff
}
}
});
var SomeComponentB = Vue.extend({
props: [ 'someFunctionParent' ],
methods: {
someFunction: function () {
// Do your stuff
this.someFunctionParent();
}
}
});
and in the template of SomeComponentA:
<some-component-b someFunctionParent="someFunction"></some-component-b>
2. Mixins
If this is common functionality that you want to use in other places, using a mixin might be more idiomatic:
var mixin = {
methods: {
someFunction: function() {
// ...
}
}
};
var SomeComponentA = Vue.extend({
mixins: [ mixin ],
methods: {
}
});
var SomeComponentB = Vue.extend({
methods: {
someFunctionExtended: function () {
// Do your stuff
this.someFunction();
}
}
});
3. Calling parent props (parent-child, ugly)
// In someComponentB's 'someFunction':
this.$parent.$options.methods.someFunction(...);
In case someone's interested in a JustWorksTM solution:
var FooComponent = {
template: '<button #click="fooMethod()" v-text="buttonLabel"></button>',
data: function () {
return {
foo: 1,
bar: 'lorem',
buttonLabel: 'Click me',
}
},
methods: {
fooMethod: function () {
alert('called from FooComponent');
},
barMethod: function () {
alert('called from FooComponent');
},
}
}
var FooComponentSpecialised = {
extends: FooComponent,
data: function () {
return {
buttonLabel: 'Specialised click me',
zar: 'ipsum',
}
},
methods: {
fooMethod: function () {
FooComponent.methods.fooMethod.call(this);
alert('called from FooComponentSpecialised');
},
}
}
jsfiddle: https://jsfiddle.net/7b3tx0aw/2/
More info:
This solution is for devs that can't use TypeScript for some reason (which I think allows defining vue components as classes, which in turn allows full inheritance feature-set).
Further elaboration about the solution (whys and hows): https://github.com/vuejs/vue/issues/2977
This ain't that ugly, considering that no rocket science is used here (calling anonymous functions with the this pointer replaced should be no magic for any decent js dev).
How to use Function.prototype.call()
Reference https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call
Sample code:
function Product(name, price) {
this.name = name;
this.price = price;
}
function Food(name, price) {
Product.call(this, name, price);
this.category = 'food';
}
console.log(new Food('cheese', 5).name);
// expected output: "cheese"
In case someone asks for a solution here is mine and works fine :
var SomeClassA = {
methods: {
someFunction: function () {
this.defaultSomeFunction();
},
// defaultSomeFunction acts like parent.someFunction() so call it in inheritance
defaultSomeFunction: function () {
// ClassA some stuff
},
},
};
var SomeClassB = {
extends: SomeClassA,
methods: {
someFunction: function () {
// Replace the wanted SomeClassA::someFunction()
this.defaultSomeFunction();
// Add custom code here
},
},
};
using juste extends from https://v2.vuejs.org/v2/api/#extends replaces the usage of Vue.extends()
I'd like to test a Vue.js component, and I'm failing at that. Simply put, I'm setting a component property, and I want to assert that it is set correctly. If that matters, the module is loaded with exports, and the JS is output using Webpack.
// component
exports = module.exports = {};
module.exports = {
data: function () {
return {
active: false
};
},
methods: {
'close': function () {
console.log(this.active); // -> true
this.active = false;
console.log(this.active); // -> false
}
}
};
// component-test
var modal = require('../../resources/src/js/components/_component.js');
var assert = require('assert');
describe('close()', function () {
beforeEach(function () {
modal.data.active = true;
});
it('should set modal to inactive', function () {
console.log(modal.data.active); // -> true
modal.methods.close();
console.log(modal.data.active); // -> true
assert.equal(modal.data.active, false);
});
});
This should give you a hint on how to load vue components when testing;
var modalComponent = require('../../resources/src/js/components/_component.js');
var assert = require('assert');
//load the component with a vue instance
vm = new Vue({
template: '<div><test v-ref:test-component></test></div>',
components: {
'test': modalComponent
}
}).$mount();
var modal = vm.$refs.testComponent;
describe('close()', function () {
beforeEach(function () {
modal.active = true;
});
it('should set modal to inactive', function () {
console.log(modal.active); // -> true
modal.close();
console.log(modal.active); // -> false
assert.equal(modal.active, false);
});
});
https://github.com/eddyerburgh/avoriaz is now the official testing library for Vue.js checkout the documentation on getting setup to make assertions on your components https://eddyerburgh.gitbooks.io/avoriaz/content/
I'm trying to write a simple test using page objects pattern - based on the 'docs/page-objects'.
I created a file describing the page object and other using this page object to test a page.
//page object
var LoginPage = function() {
this.userInput = browser.driver.findElement(by.id('username'));
this.pwdInput = browser.driver.findElement(by.id('password'));
this.btnEnter = browser.driver.findElement(by.id('btnLogin'));
this.get = function(){
browser.get('http://example.com');
};
this.setUser = function (user){
this.userInput.sendKeys(user);
};
this.setPasswd = function (password) {
this.pwdInput.sendKeys(password);
};
this.clickBtnEnter = function (){
btnEnter.click();
};};
The spec file:
var loginPage = require('./LoginPage.js');
describe('myApp', function() {
it('should save contract config', function (){
loginPage.get();
loginPage.setUser('userid');
loginPage.setPasswd('passwd');
loginPage.clickBtnEnter();
});
});
The following error is shown when I run this test: TypeError: Object # has no method 'get' - at this line: loginPage.get();.
When I was searching for this problem I found various approaches about using page objects in Protractor, such as Astrolable.
Now I am not sure about the correct usage of page objects.
Do you have any ideas about how I can fix this test?
Thank you guys.
Try this:
Ensure you have the following in your LoginPage.js file
module.exports = LoginPage;
Add the missing new keyword
var LoginPage = require('./LoginPage.js');
var loginPage = new LoginPage();
After trying the above syntax (no success) I rewrote the page object using the Astrolable. Now it works! My test looks like this:
//pageobject
'use strict';
var env = require('./environment.js')
var LoginPage = function () {
browser.driver.get('http://example.com');
};
LoginPage.prototype = Object.create({}, {
userInput: { get: function() { return browser.driver.findElement(by.id('username'));}},
pwdInput: { get: function() { return browser.driver.findElement(by.id('password'));}},
btnEnter: { get: function() { return browser.driver.findElement(by.id('btnLogin'));}},
setUser: { value: function (loginName) {
this.userInput.sendKeys(loginName);
}},
setPasswd: { value: function (loginPass) {
this.pwdInput.sendKeys(loginPass);
}},
clickBtnEnter: { get: function() { return this.btnEnter.click();}}
});
module.exports = LoginPage;
Spec file:
'use strict';
var loginPage = require('./LoginPage.js');
describe('myApp', function() {
var poLogin = new loginPage();
it('should save contract config', function (){
poLogin.setUser('userid');
poLogin.setPasswd('passwd');
poLogin.clickBtnEnter;
});
});
Now it is working fine.
Thanks for answering.
var MODULE = (function() {
var app = {
hi: "hi mom", // I can't access this. Oh' what do I do?
onSubmitClick: function() {
$('button').click(function() {
console.log(hi); // I want to access the above hi variable..eeek!
})
},
run: function() {
this.onSubmitClick()
}
}
return app
}());
var newApp = MODULE;
newApp.run();
hi is not a variable, it is a property of the object app
var MODULE = (function () {
var app = {
hi: "hi mom",
onSubmitClick: function () {
$('button').click(function () {
console.log(app.hi); //use the app object and access the property
})
},
run: function () {
this.onSubmitClick()
}
}
return app
}());
var newApp = MODULE;
newApp.run();
Demo: Fiddle
You can do something like this also.
var app = {
hi: "hi mom",
onSubmitClick: function (cthis) {
$('button').click(function () {
alert(cthis.hi); //use the app object and access the property
})
},
run: function () {
this.onSubmitClick(this);
//-------------------^ this is referring app
}
}
Demo