End-to-End Testing AngularJS app with Jasmine - javascript

I have an AngularJS app. I would like to implement some end-to-end testing that I can run on-demand. In an effort to do this, I've built a basic test screen with the following:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Test Results</title>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine-html.js"></script>
<script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/boot.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.9/angular-mocks.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine.css" />
<!-- Load the Test Files-->
<script type="text/javascript" src="e2e/tests.e2e.js"></script>
</head>
<body>
run tests
</body>
</html>
My tests.e2e.js file looks like the following:
'use strict';
describe('MyApp', function() {
browser.get('http://localhost:11000/index.html');
describe('Welcome Screen', function () {
});
});
When click "run tests" in my test runner, I get an error that says:
MyApp encountered a declaration exception
ReferenceError: browser is not defined
My question is, what am I doing wrong? The examples I've seen use browser to basically start the app. However, I can't seem to figure out how to do end-to-end tests on-demand.
Thank you for any help you can provide.

(function (module) {
var myController = function ($scope, $http) {
$http.get("/api/myData")
.then(function (result) {
$scope.data= result.data;
});
};
module.controller("MyController",
["$scope", "$http", myController]);
}(angular.module("myApp")));
describe("myApp", function () {
beforeEach(module('myApp'));
describe("MyController", function () {
var scope, httpBackend;
beforeEach(inject(function ($rootScope, $controller, $httpBackend, $http) {
scope = $rootScope.$new();
httpBackend = $httpBackend;
httpBackend.when("GET", "/api/myData").respond([{}, {}, {}]);
$controller('MyController', {
$scope: scope,
$http: $http
});
}));
it("should have 3 row", function () {
httpBackend.flush();
expect(scope.data.length).toBe(3);
});
});
});

Related

Module Exceptions in Angularjs and $exceptionHandler

In the documentation of Angular 1 for $exceptionHandler it says:
Any uncaught exception in angular expressions is delegated to this service.
https://code.angularjs.org/1.3.20/docs/api/ng/service/$exceptionHandler
Yet when I get a module initialisation error (Uncaught Error: [$injector:modulerr] Failed to instantiate module app due to: ...) it does not seem to get logged via the $exceptionHandler.
I want to be able to log these Errors to Sentry via Raven and am having trouble finding a solution to this.
This is an example of what i am trying to achieve:
// Main App module
angular.module('app', ['app.welcome', 'app.contact'])
.factory('$exceptionHandler', [function() {
return function myExceptionHandler(exception, cause) {
// why does the module initialisation error not get caught here..?
console.log("[ERROR] ", exception.message);
};
}]);
// a module I forgot to load..
// app.module('app.contact', []);
// another sub module
angular.
module('app.welcome', [])
.controller('ExampleController', ['$scope', '$window', function($scope, $window) {
$scope.test = function() {
$window.alert('test');
};
}]);
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="ExampleController">
<button ng-click="test()">Test</button>
</body>
</html>
Here is a snippet which raise an error because $q is not injected, do whatever you want in custom exception handler.
angular.module('app', []);
angular.
module('app')
.controller('ExampleController', ['$scope', function($scope) {
$scope.test = function() {
$q.when("foo");
};
}])
.factory('$exceptionHandler', [function() {
return function myExceptionHandler(exception, cause) {
console.log("[ERROR] ", exception.message);
};
}]);
<!doctype html>
<html lang="en" ng-app="app">
<head>
<meta charset="utf-8">
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.6.4/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-controller="ExampleController">
<button ng-click="test()">Raise Error</button>
</body>
</html>

Problems with uploading a file and parsing with AngularJS

Trying to build a simple application that allows a user to upload a file, and upon clicking the 'add' button, It parses the file and displays the result within the browser.
I am using IntelliJ to generate the AngularJS application stub, and modifying it accordingly.
My attempt is below:
view1.html
<!DOCTYPE html>
<html lang="en" ng-app>
<head>
<meta charset="utf-8">
<title>My HTML File</title>
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">
<link rel="stylesheet" href="../app.css">
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/ng-file-upload/ng-file-upload-shim.js"></script> <!-- for no html5 browsers support -->
<script src="bower_components/ng-file-upload/ng-file-upload.js"></script>
<!--<script src="view1.js"></script>-->
</head>
<body>
<div ng-controller="View1Ctrl">
<input type="file" id="file" name="file"/>
<br/>
<button ng-click="add()">Add</button>
<p>{{data}}</p>
</div>
</body>
</html>
view1.js
'use strict';
angular.module('myApp.view1', ['ngRoute'])
.config(['$routeProvider', function($routeProvider) {
$routeProvider.when('/view1', {
templateUrl: 'view1/view1.html',
controller: 'View1Ctrl'
});
}])
.controller('View1Ctrl', ['$scope', function ($scope) {
$scope.data = 'none';
$scope.add = function() {
var f = document.getElementById('file').files[0],
r = new FileReader();
r.onloadend = function(e) {
$scope.data = e.target.result;
}
r.readAsArrayBuffer(f);
}
}]);
view1_test.js
'use strict';
describe('myApp.view1 module', function() {
beforeEach(module('myApp.view1'));
describe('view1 controller', function(){
it('should ....', inject(function($controller, $rootScope) {
//spec body
// var view1Ctrl = $controller('View1Ctrl');
var $scope = $rootScope.$new(),
ctrl = $controller('View1Ctrl', {
$scope: $scope
// $User: {}
});
expect(ctrl).toBeDefined();
}));
});
});
app.js
'use strict';
// Declare app level module which depends on views, and components
angular.module('myApp', [
'ngRoute',
'myApp.view1',
'myApp.view2',
'myApp.version'
]).
config(['$routeProvider', function($routeProvider) {
$routeProvider.otherwise({redirectTo: '/view1'});
}]);
I am not sure where I could potentially be going wrong? I viewed quite a few questions to this and tried multiple different approaches but I cannot get this to work despite all of my tests passing.
The issue was around my view1.js file. I found the Papa Parse library extremely useful.
Here is my solution used from the open source Papa Parse community:
Papa.parse(fileInput[0], {
complete: function(results) {
console.log("Complete!", results.data);
$.each(results.data, function(i, el) {
var row = $("<tr/>");
row.append($("<td/>").text(i));
$.each(el, function(j, cell) {
if (cell !== "")
row.append($("<td/>").text(cell));
});
$("#results tbody").append(row);
});
}
});

ui-router not replacing ui-view in index.html

I have set up a basic AngularJS app in VS and cannot get the ui-router functionality working. I have looked at videos, blogs, SO answers and as far as I can tell I am doing everything right, although, I am brand new to web development.
First, here is the solution structure:
and the code...
index.html:
<!DOCTYPE html>
<html>
<head>
<title>Example</title>
<meta charset="utf-8" />
</head>
<body ng-app="app">
<div ui-view></div>
<script src="bower_components/angular/angular.js"></script>
<script src="app/app.js"></script>
<script src="bower_components/angular-ui-router/release/angular-ui-router.js"></script>
</body>
</html>
app.js:
(function () {
'use strict';
angular.module('app', ['ui.router']);
})();
app.states.js:
(function () {
'use strict';
angular.module('app')
.config(function ($stateProvider, $urlRouterProvider) {
$urlRouterProvider.otherwise('/');
$stateProvider
.state('home', {
url: '/',
templateUrl: 'templates/test.html',
controller: 'testCtrl',
controllerAs: 'vm'
})
});
})();
test.html:
<div>
<p>TEST PAGE</p>
</div>
testCtrl.js:
(function () {
'use strict';
angular.module('app')
.controller('testCtrl', testCtrl);
testCtrl.$inject = ['$state'];
function testCtrl($state) {
var vm = this;
var userAuthenticated = false;
init();
function init() {
$state.go('home');
};
};
})();
Can anyone see anywhere I have made a mistake?
There is a working example
I would say, that I miss these lines in your index.html
...
<script src="app/app.states.js"></script>
<script src="templates/testCtrl.js"></script>
That will loade the crucial state definition, and related controller. Check it in action here

AngularJS: Browser ignores my Controller Definition (Dependency Injection)

I am using angular-translate in my project but I am unable to define a controller that has a dependency injection of $translate. The code isn't executed in the browser. I checked JSHint already...
index.html
<html ng-app='ngApp'>
<body>
<div ng-controller="orderFormCtr">
<ul>
<li>{{'TITLE' | translate}}</li>
<li translate="TITLE"></li>
</ul>
</div>
<script src="bower_components/angular/angular.js"></script>
<script src="bower_components/angular-translate/angular-translate.js"></script>
<script src="app.js"></script>
</body>
</html>
app.js
angular.module('ngApp', ['pascalprecht.translate']);
// this code works
angular.module('ngApp').config(['$translateProvider', function ($translateProvider) {
$translateProvider.translations('en', {
TITLE: 'Hello'
});
$translateProvider.translations('de', {
TITLE: 'Hallo'
});
}]);
// the browser ignores this code
angular.module('ngApp').controller('orderFormCtr', ['$scope', '$translate', function ($scope, $translate) {
alert("Controller Code executed");
}]);
var app = angular.module('ngApp', ['pascalprecht.translate']);
// this code works
app.config(['$translateProvider', function ($translateProvider) {
$translateProvider.translations('en', {
TITLE: 'Hello'
});
$translateProvider.translations('de', {
TITLE: 'Hallo'
});
$translateProvider.preferredLanguage('en');
//or translateProvider.determinePreferredLanguage()
}]);
// the browser ignores this code
app.controller('orderFormCtr', ['$scope', '$translate', function ($scope, $translate) {
alert("Controller Code executed");
}]);
http://jsbin.com/miqazola/1/

Jasmine test for Angular can't find my controller

I'm having trouble setting up Jasmine tests for an Angular app. Jasmine can't find my controller (I suspect it can't find my app at all).
Here is a sample that demonstrates the problem I'm running into:
angular.module('testMod', [])
.controller('testController', ['$scope', function($scope) {
$scope.person = {name: 'Jim', age: 14};
function innerFunction() {}
}]);
Test:
describe('testMod suite', function() {
var $rootScope, myController;
beforeEach( inject(function($injector) {
angular.module('testMod');
$rootScope = $injector.get('$rootScope');
var $controller = $injector.get('$controller');
myController = $controller('testController', {$scope: $rootScope});
}) );
it('works', function() {
expect( typeof myController.innerFunction).toBe('function');
});
});
It fails on the line
myController = $controller('testController', {$scope: $rootScope});
The error I'm seeing is:
Error: [ng:areq] Argument 'testController' is not a function, got undefined
I'm using the standalone SpecRunner.html for Jasmine, with my app and spec loaded:
<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Jasmine Spec Runner v2.0.0</title>
<link rel="shortcut icon" type="image/png" href="lib/jasmine-2.0.0/jasmine_favicon.png">
<link rel="stylesheet" type="text/css" href="lib/jasmine-2.0.0/jasmine.css">
<script type="text/javascript" src="lib/jasmine-2.0.0/jasmine.js"></script>
<script type="text/javascript" src="lib/jasmine-2.0.0/jasmine-html.js"></script>
<script type="text/javascript" src="lib/jasmine-2.0.0/boot.js"></script>
<!-- angular-mock must be loaded AFTER Jasmine -->
<script type="text/javascript" src="../src/angular-1.2.5.min.js"></script>
<script type="text/javascript" src="../src/angular-mock-1.2.5.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="../src/testMod.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="spec/testMod.Test.js"></script>
</head>
<body>
</body>
</html>
Any suggestions are appreciated - I've been struggling with this for a while now.
There are several problems with your test:
You are not injecting scope properly.
You are not using scope properly.
There is a toBeDefined() method to check if function is defined no need to type check.
Change the code in your test to
describe('testMod suite', function() {
var $rootScope, testController;
beforeEach(module('testMod'));
beforeEach(inject(function($controller, $rootScope) {
myScope = $rootScope.$new();
ctrl = $controller('testController', {
$scope: myScope
});
}));
it('works', function() {
expect( myScope.innerFunction).toBeDefined();
});
});
Also, change your angular controller code to:
angular.module('testMod', [])
.controller('testController', ['$scope', function($scope) {
$scope.person = {name: 'Jim', age: 14};
$scope.innerFunction = function() {}
}]);

Categories