I'm trying to make some basic tests on directives on an e2e scenario. The code works just fine
and I can render the new element to the browser. Here the code I'm using.
Here the directive code.
'use strict';
var directives = angular.module('lelylan.directives', [])
directives.directive('device', ['Device', function(Device) {
var definition = {
restrict: 'E',
replace: true,
templateUrl: 'js/templates/device.html',
scope: { id: '#' }
};
definition.link = function postLink(scope, element, attrs) {
scope.$watch('id', function(value){
var device = Device.get({ id: scope.id }, function() {
scope.device = device;
});
});
};
return definition
}]);
Here the Device service code.
// Service Device
'use strict';
angular.module('lelylan.services', ['ngResource']).
factory('Device', ['$resource', '$http', function($resource, $http) {
var token = 'df39d56eaa83cf94ef546cebdfb31241327e62f8712ddc4fad0297e8de746f62';
$http.defaults.headers.common["Authorization"] = 'Bearer ' + token;
var resource = $resource(
'http://localhost:port/devices/:id',
{ port: ':3001', id: '#id' },
{ update: { method: 'PUT' } }
);
return resource;
}]);
Here the app code.
'use strict';
angular.module('lelylan', ['lelylan.services', 'lelylan.directives'])
And here the index.html.
<!doctype html>
<html lang="en" ng-app="lelylan">
<head>
<meta charset="utf-8">
<title>Lelylan Components</title>
<link rel="stylesheet" href="css/app.css"/>
</head>
<body>
<device id="50c61ff1d033a9b610000001"></device>
<!-- In production use: <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.4/angular.min.js"></script> -->
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-resource.js"></script>
<script src="js/app.js"></script>
<script src="js/services.js"></script>
<script src="js/directives.js"></script>
</body>
</html>
After reading the Angular documentation and trying different solutions I came up with the following
test where I try mock my Backend requests. The problem is that the request still hits the real service. It
looks like I'm not able to intercept the requests.
// e2e test
'use strict';
describe('directives', function() {
var resource = { id: '1', uri: 'http://localhost:3001/devices/1' };
var myAppDev = angular.module('myAppDev', ['lelylan', 'ngMockE2E']);
myAppDev.run(function($httpBackend) {
$httpBackend.when('GET', 'http://localhost:3001/devices/1').respond(resource);
$httpBackend.when('GET', /\/templates\//).passThrough();
});
beforeEach(function() {
browser().navigateTo('../../app/index.html');
});
describe('when renders a device', function() {
it('renders the title', function() {
expect(element('.device .name').text()).toEqual('Closet dimmer');
});
it('renders the last time update', function() {
expect(element('.device .updated-at').text()).toEqual('2012-12-20T18:40:19Z');
})
});
});
I think I'm missing some configurations, but I can't really understand which ones.
Thanks a lot.
Reading the the last comment in this question I came with the final solution.
Actually I was missing one important step, due to the fact that I had to use an HTML file that uses the mocked application. Let's make the code speak.
1) I've created an HTML file with the test environment. The main difference is related to the fact that I've set the ng-app=test and I've added two new JS files. The first is /test/e2e/app-test.js and is where I've created the test module and the second is /test/lib/angular-mocks.js.
<!doctype html>
<html lang="en" ng-app="test">
<head>
<meta charset="utf-8">
<title>Lelylan Test</title>
<link rel="stylesheet" href="css/app.css"/>
</head>
<body>
<device id="1"></device>
<script src="lib/angular/angular.js"></script>
<script src="lib/angular/angular-resource.js"></script>
<script src="js/app.js"></script>
<script src="js/settings.js"></script>
<script src="js/services.js"></script>
<script src="js/controllers.js"></script>
<script src="js/filters.js"></script>
<script src="js/directives.js"></script>
<!-- Test application with mocked requests -->
<script src="../test/e2e/app-test.js"></script>
<script src="../test/lib/angular/angular-mocks.js"></script>
</body>
</html>
Now, lets see how we implement the test module. In here I define a module that is exactly as my main module (lelylan), with the addition of ngMockE2E that lets you access to $httpBackend and mock the HTTP requests.
'use strict';
var resource = { id: '1', uri: 'http://localhost:3001/devices/1' };
var test = angular.module('test', ['lelylan', 'ngMockE2E']);
test.run(function($httpBackend) {
$httpBackend.when('GET', 'http://localhost:3001/devices/1').respond(resource);
$httpBackend.when('GET', /\/templates\//).passThrough();
});
Nothing more. Run scripts/e2e-test.sh and you're done.
Related
I want to make a dashboard with widgets. The data (json object) that must be displayed on widgets cam from server by ajax request at every n seconds. Every widget has uuid type identifier. I have tryed using directive isolated scope, but it didn't work form me with uuid type. Here is my Plunker example.
How to make this code working?
Or maybe there is better ways to acomplish this goal with angularjs ?
index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="//code.angularjs.org/snapshot/angular.min.js"></script>
<script src="script.js"></script>
</head>
<body ng-app="dashboard">
<div ng-controller="widgetController as ctrl">
<widget id="ctrl.cbdf9d33-8d7a-43f7-a8b5-5b011edd2402"></widget>
<widget id="ctrl.5ed23c32-a443-45eb-932e-8ff1d23a912f"></widget>
<widget id="ctrl.2de16396-88a3-48cd-b42a-bc30bdd80064"></widget>
</div>
</body>
</html>
script.js
(function(angular) {
'use strict';
angular.module('dashboard', [])
.controller('widgetController', ['$interval', '$http', function($interval, $http) {
var vm = this;
var updateWidgetsLoop = $interval(function() {
$http({
method: 'GET',
url: 'server.json'
}).then(function successCallback(response) {
var widgets = response.data;
angular.forEach(widgets, function(widget, key) {
vm[key] = widget;
});
});
}, 5000);
}])
.directive('widget', function() {
return {
restrict: 'E',
scope: {
id: '='
},
template: '<div>{{id.value}}</div>',
};
});
})(window.angular);
server.json
{
"cbdf9d33-8d7a-43f7-a8b5-5b011edd2402" : {"value": 10},
"5ed23c32-a443-45eb-932e-8ff1d23a912f" : {"value": 20},
"2de16396-88a3-48cd-b42a-bc30bdd80064" : {"value": 30}
}
Change you html code
<widget id="ctrl.cbdf9d33-8d7a-43f7-a8b5-5b011edd2402"></widget>
to
<widget id="ctrl['cbdf9d33-8d7a-43f7-a8b5-5b011edd2402']"></widget>
It should work. Good Luck :-)
Working Plunker https://plnkr.co/edit/SmJtaItdB7lrgxu0GbiP?p=preview
Hope it solved you problem :-)
im fairly new to angular. im trying to understand why this doesnt work:
error recieved is:
Uncaught Error: [$injector:modulerr] Failed to instantiate module phonecatApp due to:
Error: [$injector:modulerr] Failed to instantiate module phoneList due to:
TypeError: Cannot read property 'controller' of undefined
angular.
module('phoneList').
component(name, component);
var name = 'phoneList';
var component = {
templateUrl: 'phone-list/phone-list.template.html',
controller: ['$http', function PhoneListController($http) {
var self = this;
self.orderProp = 'age';
$http.get('phones/phones.json').then(function(response) {
self.phones = response.data;
});
}]
};
how can i fix this ?
i know i can do this but i prefer decomposing the object as above. please advise
angular.
module('phoneList').
component('phoneList', {
templateUrl: 'phone-list/phone-list.template.html',
controller: ['$http', function PhoneListController($http) {
var self = this;
self.orderProp = 'age';
$http.get('phones/phones.json').then(function(response) {
self.phones = response.data;
});
}]
});
Have you tried to define the name and component vars before using them in .component(name, component) ? Like:
var name = 'phoneList';
var component = {
templateUrl: 'phone-list/phone-list.template.html',
controller: ['$http', function PhoneListController($http) {
var self = this;
self.orderProp = 'age';
$http.get('phones/phones.json').then(function(response) {
self.phones = response.data;
});
}]
};
angular.
module('phoneList').
component(name, component);
this is the index.html. i already have app.module.js defining this
'use strict';
// Define the `phonecatApp` module
angular.module('phonecatApp', [
'ngRoute',
'phoneDetail',
'phoneList'
]);
<!doctype html>
<html lang="en" ng-app="phonecatApp">
<head>
<meta charset="utf-8">
<title>Google Phone Gallery</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/angular-route/angular-route.js"></script>
<script src="app.module.js"></script>
<script src="app.config.js"></script>
<script src="phone-list/phone-list.module.js"></script>
<script src="phone-list/phone-list.component.js"></script>
<script src="phone-detail/phone-detail.module.js"></script>
<script src="phone-detail/phone-detail.component.js"></script>
</head>
<body>
<div ng-view></div>
</body>
</html>
this is not the issue. my example is straight from the angularjs tutorial with the above only difference of separating the component object from the component itself.
I'm to setup standalone jasmine testing. I believe I have everything setup correctly. When I run my first test:
describe('Logon Controller', function() {
var controller, $scope;
beforeEach(module("app"));
//beforeEach(inject(function ($rootScope, $controller) {
// scope = $rootScope.$new();
// contoller = $controller('logonCtrl', {
// $scope: scope
// });
//}));
beforeEach(inject(function ($rootScope) {
scope = $rootScope.$new();
}));
//it('should say hello', function ($controller, $rootScope) {
// //var scope = $rootScope.$new();
// var controller = $controller('logonCtrl', { $scope: $scope });
// //expect(angular.isFunction(scope.get)).toEqual("Hello There :)");
// expect(scope.Hello()).toEqual("Hello There :)");
// expect($scope.Hello).toBeDefined();
//});
it('should say hello', inject(function ($controller, $rootScope) {
//var scope = $rootScope.$new();
var controller = $controller('logonCtrl', {$scope: $scope});
//expect(angular.isFunction(scope.get)).toEqual("Hello There :)");
//expect(scope.Hello()).toEqual("Hello There :)");
expect($scope.Hello).toBeDefined();
}));
});
I get this error message: Error: [$injector:modulerr] http://errors.angularjs.org/1.3.11/$injector/modulerr?p0=app.............
Here is my app module config.
var app = angular.module('app', ['ui.router','ngMaterial']);
Here is my controller:
app.controller('logonCtrl', ['$scope', '$state', '$interval', function ($scope, $state, $interval) {
$scope.hello = function() {};
});
]);
I am using the standalone version of Jasmine 2.2.0. I have no clue what the issue could be, everything I have done is pretty basic stuff. Any help would be very much appreciated.
UPDATE: here is what my SpecRunner.html looks like:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Jasmine Spec Runner v2.2.0</title>
<link rel="shortcut icon" type="image/png" href="JasmineUnitTest/lib/jasmine-2.2.0/jasmine_favicon.png">
<link rel="stylesheet" href="JasmineUnitTest/lib/jasmine-2.2.0/jasmine.css">
<script type="text/javascript" src="JasmineUnitTest/lib/jasmine-2.2.0/jasmine.js"></script>
<script type="text/javascript" src="JasmineUnitTest/lib/jasmine-2.2.0/jasmine-html.js"></script>
<script type="text/javascript" src="JasmineUnitTest/lib/jasmine-2.2.0/boot.js"></script>
<script type="text/javascript" src="JasmineUnitTest/lib/jasmine-2.2.0/angular.min.js"></script>
<script type="text/javascript" src="JasmineUnitTest/lib/jasmine-2.2.0/angular-mocks.js"></script>
<!-- include source files here... -->
<script type="text/javascript" src="js/controllers/logonCtrl.js"></script>
<!-- include spec files here... -->
<script type="text/javascript" src="JasmineUnitTest/specs/logonController-spec.js"></script>
</head>
<body>
</body>
</html>
It looks like the $injector fails to find some of your dependencies. Are you sure the script containing your controller is properly loaded ?
I'm new on AngularJs.
I have trouble injecting a service into a controller in AngularJS.
I read many tutorials and topics on stackoverflow, but I can't fix my issues because the controller & service use the same module like this:
var myModule = angular.module("myModule", []);
myModule.service("myService", MyService);
myModule.controller("MyController", function($scope, myService) {
myService.doIt();
});
My project works when the service & controller use the same module, but I want each one to use its own module because many controllers should use this service.
(I try to minimize the code)
index.html :
<!doctype html>
<html lang="en" ng-app="interfaceApp">
<meta http-equiv="Access-Control-Allow-Origin" content="*">
<head>
<meta charset="utf-8">
<title>Interface de consulation</title>
<link rel="stylesheet" href="resources/css/bootstrap.css">
<link rel="stylesheet" href="resources/css/app.css">
<link rel="stylesheet" href="resources/css/animations.css">
<script src="resources/vendors/jquery/jquery.js"></script>
<script src="resources/vendors/angular/angular.min.js"></script>
<script src="resources/vendors/angular/angular-animate.js"></script>
<script src="resources/vendors/angular/angular-route.js"></script>
<script src="resources/vendors/angular/angular-resource.js"></script>
<!--personal script-->
<script src="js/controllers/router.js"></script>
<script src="js/animations/animations.js"></script>
<script src="js/filters/filters.js"></script>
<script src="js/services/services.js"></script>
<script src="js/services/deserializer.js"></script>
<script src="js/directives/directives.js"></script>
<!-- load my controller -->
<script src="js/controllers/phoneController.js"></script>
<script src="js/controllers/specimenController.js"></script>
<script src="js/controllers/localisationController.js"></script>
</head>
<body>
<!-- MAIN CONTENT AND INJECTED VIEWS -->
<div class="view-container">
<div ng-view class="view-frame"></div>
</div>
</body>
</html>
router.js:
'use strict';
/* App Module */
var interfaceApp = angular.module('interfaceApp', [
'ngRoute',
'phoneModules',
'localisationModules',
'specimenModules',
'interfaceFilters',
'interfaceDirectives',
'interfaceAnimations',
'interfaceServices',
// 'DeserializerService' // Error: [$injector:modulerr]
]);
interfaceApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: 'partials/home.html',
controller: 'MainCtrl'
}).
when('/specimens', {
templateUrl: 'partials/specimen/list.html',
controller: 'specimenListeCtrl'
}).
when('/specimens/:specimensId', {
templateUrl: 'partials/specimen/detail.html',
controller: 'specimenDetailCtrl'
}).
otherwise({
redirectTo: '/'
});
}]);
js/controllers/specimenController.js :
'use strict';
/* Controllers */
var specimenModules = angular.module('specimenModules', ['ngRoute']);
...
var referencedTag={"mediasSet":"#mediasSet","determinations":"#determinationID"};
specimenModules.controller('specimenListeCtrl', ['$scope', '$http', 'DeserializerService',
function ($scope,$http,DeserializerService) {
var request = 'http://localhost:8888/ui/specimens?limit=10&r_medias=false&orderby=d_determinationid';
$http.get(request).success(function(data) {
DeserializerService.startDeserializer(data,referencedTag);
$scope.specimens=data;
});
}
]);
js/services/deserializer.js :
var deserializerModule = angular.module('DeserializerModule', []);
deserializerModule.service('DeserializerService', function() {
***//specimenModules.service('deserializerService', function() { // work but i dont want to use specimenModules her***
this.referencedTag= [];
this.startDeserializer= function(data,refTag) {
this.referencedTag=refTag;
this.deserializer(data);
}
this.deserializer= function(data) {
...
}
});
I tried many combinations, but all failed giving error like :
Error: [$injector:modulerr]
Error: [$injector:unpr]
but i don't see where it come from on firebug ( the error dont give a line or file )
ERROR:
Error: [$injector:unpr] http://errors.angularjs.org/1.2.17/$injector/unpr?p0=DeserializerServiceProvider%20%3C-%20DeserializerService
u/<#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:6:443
ec/l.$injector<#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:36:139
c#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:34:195
ec/p.$injector<#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:36:209
c#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:34:195
d#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:34:409
f/<.instantiate#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:35:101
Od/this.$get</<#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:66:463
ngViewFillContentFactory/<.link#http://localhost/rec-interface/resources/vendors/angular/angular-route.js:913:1
N#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:54:85
g#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:47:55
v/<#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:46:253
O/<#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:47:485
x#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:51:245
update#http://localhost/rec-interface/resources/vendors/angular/angular-route.js:871:1
Yd/this.$get</h.prototype.$broadcast#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:113:355
updateRoute/<#http://localhost/rec-interface/resources/vendors/angular/angular-route.js:552:15
ze/e/l.promise.then/D#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:99:243
ze/e/l.promise.then/D#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:99:243
ze/f/<.then/<#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:100:407
Yd/this.$get</h.prototype.$eval#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:111:110
Yd/this.$get</h.prototype.$digest#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:108:180
Yd/this.$get</h.prototype.$apply#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:111:449
g#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:72:113
x#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:76:463
ve/</v.onreadystatechange#http://localhost/rec-interface/resources/vendors/angular/angular.min.js:78:1
<div ng-view="" class="view-frame ng-scope">
Thanks for your help, any advice or critics are welcomed.
many thank #jcubic you are right it work !!!
it need double "injection", one for module and one for service name:
var specimenModules = angular.module('specimenModules', ['ngRoute','DeserializerModule']);
...
specimenModules.controller('specimenListeCtrl', ['$scope', '$http', 'DeserializerService', function ($scope,$http,DeserializerService) { ... }])
thanks
I'm working on an AngularJS app that uses a custom directive. I'm also trying to use unit testing in my app. So, I'm trying to leverage Jasmine for that. Currently, My unit test is the problem. Currently, it looks like the following:
myDirective.spec.js
describe('Directive: myDirective', function () {
describe('Function: myProcedure', function () {
it('should word', function ($rootScope, $compile) {
var e = angular.element('<div><br /></div>');
console.log($compile);
$compile(e)($rootScope);
expect(true).toBe(true);
});
});
});
This test is throwing an exception. When the console.log line is ran, it prints: 'undefined'. The next line throws an error to Jasmine that says: 'TypeError: undefined is not a function'.
Its like I'm not injecting the $compile service. However, I believe I'm doing so. My test runner looks like the following:
<html ng-app="testApp">
<head>
<title></title>
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular.min.js"></script>
<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="index.html.js"></script>
<script type="text/javascript" src="directives/myDirective.js"></script>
<script type="text/javascript" src="tests/unit/myDirective.spec.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jasmine/2.0.0/jasmine.css" />
</head>
<body>
run tests
</body>
</html>
Why cannot I not run this basic test? What am I doing wrong?
First you must add angular mocks:
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.2.13/angular-mocks.js">
</script>
then load the modules and inject $compile/$rootScope in beforeEach blocks:
describe('Directive: myDirective', function () {
var $compile;
var $rootScope;
beforeEach(module('testApp'));
beforeEach(inject(function(_$compile_, _$rootScope_){
$compile = _$compile_;
$rootScope = _$rootScope_;
}));
describe('Function: myProcedure', function () {
it('should word', function () {
var e = angular.element('<div><br /></div>');
$compile(e)($rootScope);
expect(true).toBe(true);
});
});
});
Check unit testing docs: http://docs.angularjs.org/guide/dev_guide.unit-testing#directives
The it() function provided by jasmine won't do any injection for you, so you need to inject your angular components into your tests. Modify your test as follows:
describe('Directive: myDirective', function () {
describe('Function: myProcedure', function () {
it('should word', function () {
inject(function ($rootScope, $compile) {
var e = angular.element('<div><br /></div>');
//rest of code goes here
});
You also need a reference to the angular.mocks library.
I have come across this problem just now and this is what made my day (in the very end of it actually).just add "module('ng');" along with module('yourAppModule'). It should work.