Testing Routines and Angular Views
About Me
-
Name: Tomas Miliauskas
-
Company: Wix
-
Main Focus: Client Side Engineering
-
Email/Hangouts: tomasm@wix.com
Testing Routines and Angular Views
One Important Note
MANUAL
TESTING
Testing === Automated Testing
1. Testing
What is Software Testing?
Software testing is a method of assessing the functionality of a software program.
http://whatis.techtarget.com
What is the proper way to test your software?
Perform testing in an environment that is close to what user actually gets.
Just probably it would take ages to test everything...
So we break testing into levels
e2e testing
integration testing
unit testing
2. Testing in AngularJS
Protractor
was designed to test e2e/integration
Karma + Jasmine/Mocha
-
Modules
-
Controllers
-
Filters
-
Services
-
Directives
are to unit test the main routines
3. Issues
Some real world example
Option 1/3
Option 2/3
Option 3/3
Wanna guess the winner?
How would we test it in regular way?
function openApp(option) {
browser.addMockModule('mockModule', function (opt) {
angular.module('mockModule', []).run(function (experiments, hotelState) {
experiments.UpgradeSection = opt;
experiments.HideGreedyPopup = true;
hotelState.upgraded = false;
});
}, option);
browser.get('http://localhost:9000/back-office-v2.html');
}
1. Define the mocks
describe('A/B test for upgrade button', function () {
var upgrade;
function openApp(option) { ... }
it('should display upgrade button at the bottom', function () {
openApp('bottom');
upgrade = $('#upgrade-bar');
expect(upgrade.isDisplayed()).toBe(true);
});
it('should display upgrade button on the top-right corner', function () {
openApp('top-right');
upgrade = $('.upgrade-section');
expect(upgrade.isDisplayed()).toBe(true);
});
it('should display upgrade button inside the menu', function () {
openApp('menu');
upgrade = $('.upgrade-section-2');
expect(upgrade.isDisplayed()).toBe(true);
});
});
2. Test each case
Finished in 6.052 s
Overall it takes: 14.950 s
3. Run tests using Protractor...
Taking notes
- Full application needs to be loaded for each test
- Server has to be up and running
- All the external/internal dependencies will be loaded
- Styles and images will be loaded
- Proper setup has to be initiated.
- Functionality is not important here to test
- Debugging can be time-consuming
4. The Idea
Let's get back to the different levels of testing
e2e testing
integration testing
unit testing
Test the
While doing TDD, we test almost everything
around 5000 tests in total
Let's try to unit test
views & templates?
5. Walk-through
the solution
1. Setup karma.conf.js
-
load views and templates
-
npm install karma-ng-html2js-preprocessor
-
add ng-html2js to preprocessors list
-
specify additional options for ng-html2js
1. Setup karma.conf.js
module.exports = function (config) {
config.set({
plugins: [
'karma-jasmine',
'karma-phantomjs-launcher',
'karma-ng-html2js-preprocessor'
],
ngHtml2JsPreprocessor: { ... },
frameworks: ['jasmine'],
files: [
...
'app/template/**/*.html',
'app/views/**/*.html'
]
...
});
};
2. Mock/stub your modules, services & filters
beforeEach(function () {
module('backOfficeApp', function ($provide, $filterProvider) {
$provide.constant('hotelState', { ... });
$provide.constant('$wix', {
Dashboard: { ... },
Billing: { ... },
Extensions: { ... }
});
$filterProvider.register('translate', function () {
return function (str) {
return str;
};
});
});
});
Note: mocking/stubbing is optional
3. Create a scope object
var $rootScope;
beforeEach(function () {
inject(function ($injector) {
$rootScope = $injector.get('$rootScope');
});
$scope = $rootScope.$new();
$scope.vm = {}; // for controller as syntax
$scope.vm.experiments = {};
$scope.vm.premiumManager = {
showBoUpgradeBar: jasmine.createSpy().andReturn(true),
upgradeFromBo: jasmine.createSpy(),
ready: jasmine.createSpy()
};
});
4. Use $templateCache service to retrieve your view/template
var $templateCache, template;
beforeEach(function () {
inject(function ($injector) {
$templateCache = $injector.get('$templateCache');
});
template = $templateCache.get('views/layout.html');
});
Note: template id === path to a template
5. Compile your view/template
-
save your element into a variable
-
Inject Angular $compile service
-
pass template/view and scope object
-
call $scope.$digest()
-
put your template/view inside a <div> element
5. Compile your view/template
var $templateCache, $rootScope, $compile, $scope, template;
beforeEach(function () {
module('backOfficeApp', function () { ... });
inject(function ($injector) {
$templateCache = $injector.get('$templateCache');
$rootScope = $injector.get('$rootScope');
$compile = $injector.get('$compile');
});
template = ...;
$scope = ...
});
function compile() {
var elem = $compile(angular.element('<div></div>').html(template))($scope);
$scope.$digest();
return elem;
}
6. Write unit tests
describe('A/B test for upgrade button', function () {
var $templateCache, $rootScope, $compile, $scope, template;
beforeEach(function () { ... });
function compile() { ... }
it('should display upgrade button at the bottom', function () {
$scope.experiments.UpgradeSection = 'bottom';
expect(compile().find('#upgrade-bar').length).toBe(1);
});
it('should display upgrade button on the top-right corner', function () {
$scope.experiments.UpgradeSection = 'top-right';
expect(compile().find('.upgrade-section').length).toBe(1);
});
it('should display upgrade button inside the menu', function () {
$scope.experiments.UpgradeSection = 'menu';
expect(compile().find('.upgrade-section-2').length).toBe(1);
});
});
Finished in 0.063 s
Overall it takes: 7.180 s
So, let's run our unit tests...
...and it's even faster when watch task is running in the background
So what happens behind the scenes?
Let's Wrap Things Up
Compare the time difference
Time in total: 14,950 s vs. 7,180 s
Finished in: 6,052 s vs. 0,063 s
Pros
-
does not contradict testing philosophy
-
shorter tests runtime
-
simple setup and debugging
-
easier to mock/stub things
-
gives you more control in tests
-
helps you to reduce complexity of your tests
-
better tests performance
Cons
-
risk of mixing responsibilities of your tests
-
no test coverage
-
elements are not appended to actual DOM
-
losing integration between components
-
might take time to master
For the record...
Thanks for attending
Testing Routines and Angular Views
By Tomas Miliauskas
Testing Routines and Angular Views
- 1,657