Testing Vue.js Component - javascript

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/

Related

How can I use a Global Mixin method from a Vue instance

Let's suppose that I have the following situation, using a Global Mixin to create a global helper method with Vue:
import Vue from "vue";
Vue.mixin({
methods: {
replaceString: function (word) {
return word.toLowerCase().replace(/\W/g, '');
}
}
});
let vm = new Vue({
methods: {
doSomething: function() {
console.log(this.replaceString('Hello World'); //helloword
}
}
});
I know that I can invoke the method inside the other methods, inside of the component and their childs. But how can I invoke the mixin method "replaceString" from the Vue instance "vm"?
I tried to use "vm.replaceString", but keeps returning "undefined".
Few changes to your code and it works:
You should change the definition of your mixin (var mixin instead of Vue.mixin)
Import the mixin to your new vue component (mixins = [mixin])
import Vue from "vue";
var mixin = {
methods: {
replaceString: function (word) {
return word.toLowerCase().replace(/\W/g, '');
}
}
};
let vm = new Vue({
mixins: [mixin]
methods: {
doSomething: function() {
console.log(this.replaceString('Hello World'); //helloword
}
}
});
I think this chunk o code is what you are looking for:
var mixin = {
methods: {
foo: function () {
console.log('foo')
},
conflicting: function () {
console.log('from mixin')
}
}
}
var vm = new Vue({
mixins: [mixin],
methods: {
bar: function () {
console.log('bar')
},
conflicting: function () {
console.log('from self')
}
}
})
vm.foo() // => "foo"
vm.bar() // => "bar"
vm.conflicting() // => "from self"
From the docs

How to inheritance functions from a base js file in Protractor?

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')
})
})

unit test angular service not able to reach function inside service + jasmine

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();
});
});
});

cant update jasmine spy

Hi I have a Angular service that uses another service that loads data from the local storage on init.
angular
.module('app')
.factory('localStorage', function ($window)
{
if (!$window.localStorage)
{
// throw Error
}
return $window.localStorage;
});
angular
.module('app')
.factory('session', function (localStorage)
{
var container = JSON.parse(localStorage.getItem('sessionContainer'));
return {
getUser: getUser
};
});
Now i want to test the session service.
describe('SessionService', function ()
{
var service;
var localStorageMock;
// Load the module.
beforeEach(module('appRegistration'));
// Create mocks.
beforeEach(function ()
{
logMock = {};
localStorageMock = jasmine.createSpyObj('localStorageServiceMockSpy', ['setItem', 'getItem']);
localStorageMock.getItem.and.returnValue('{}');
module(function ($provide)
{
$provide.value('localStorage', localStorageMock);
});
inject(function (_session_)
{
service = _session_;
});
});
it('should call `getItem` on the `localStorageService` service', function ()
{
expect(localStorageMock.getItem).toHaveBeenCalledWith('sessionContainer');
});
describe('getUser method', function ()
{
it('should return an empty object when the user is not set', function ()
{
var result = service.getUser();
expect(result).toEqual({});
});
it('should return the user data', function ()
{
// localStorageMock.getItem.and.returnValue('{"user":{"some":"data"}}');
var result = service.getUser();
expect(result).toEqual({some: 'user data'});
});
});
});
As you can see in the should return the user data section.
I need a way to update the container so getUser returns the expected data.
I tried to update the getItem spy, but this does not work. The localStorageMock is already injected in the session service when i want to change the spy.
Any help?
The most simple way is to have a variable with mocked value that is common for both function scopes:
var getItemValue;
beforeEach({
localStorage: {
getItem: jasmine.createSpy().and.callFake(function () {
return getItemValue;
}),
setItem: jasmine.createSpy()
}
});
...
it('should return the user data', function ()
{
getItemValue = '{"user":{"some":"data"}}';
inject(function (_session_) {
service = _session_;
});
var result = service.getUser();
expect(result).toEqual({some: 'user data'});
});
Notice that inject should be moved from beforeEach to it for all specs (the specs that don't involve getItemValue may use shorter syntax, it('...', inject(function (session) { ... }))).
This reveals the flaw in service design that makes it test-unfriendly.
The solution is to make container lazily evaluated, so there is time to mock it after the app was bootstrapped with inject:
.factory('session', function (localStorage)
{
var containerCache;
function getUser() {
...
return this.container;
}
return {
get container() {
return (containerCache === undefined)
? (containerCache = JSON.parse(localStorage.getItem('sessionContainer')))
: containerCache;
},
getUser: getUser
};
});
Additionally, this makes possible to test session.container as well. In this case localStorageMock.getItem spy value may be redefined whenever needed.

Protractor Page objects - TypeError: Object #<Object> has no method 'methodName'

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.

Categories