Angular 1.x, ES5/ES6 and testing with Karma - javascript

I have an angular app (with a mix of files ES5 and ES6) that i am developing tests for.
The ES6 files I'm transpiling using babel CLI with these options --modules system --module-ids.
Let's say I have samething like this:
ES5 file:
angular.module('app').controller('A', function($scope) {
...
});
ES6 file:
export class B {
constructor($scope) {
this.$scope = $scope
}
...
}
And I have a file called boot.js:
import {B} from 'controllers/B';
angular.module('app').controller('B', B);
and on my page I import the boot file (using es6-module-loader) and bootstrap the angular app:
System.import('boot').then(function() {
angular.bootstrap(document, ['app']);
});
Now, I assume I need to do something similar to the karma tests - I need to load my boot.js before running my tests.
The way I solve the problem is to call System.impot('boot') in my test files - but doesn't seems to be right:
'use strict';
System.import('boot');
describe('Controller: B', function() {
beforeEach(module('app'));
var $scope;
beforeEach(inject(function(_$rootScope_, $controller) {
scope = _$rootScope_.$new();
$controller('B', {$scope: $scope);
}));
it('...', function() {
});
});
Is there a better way to do this?

The solution I ended up finding involved using karma-systemjs.
Include all your tests files on the systemjs/files section:
systemjs: {
files: [
// TEST FILES
],
configFile: 'system.config.js',
config: {
paths: {
'angular-mocks': 'node_modules/angular-mocks/angular-mocks.js'
}
}
}
And on the tests instead of using:
System.import('boot');
Use:
'use strict';
import 'angular-mocks';
import 'angular/boot.js';
describe('Controller: B', function() {
beforeEach(module('app'));
var $scope;
beforeEach(inject(function(_$rootScope_, $controller) {
scope = _$rootScope_.$new();
$controller('B', {$scope: $scope);
}));
it('...', function() {
});
});
Hopefully this will help someone else in the future.

Related

How to dependency injection using ocLazyLoad

I'm using ocLazyLoad and I have some external angular libraries (Like Chart.js and pascalprecht.translate) and I need to lazy load them in some routes, as you know, for the common angular module dependency injection should be like:
var angularApp = angular.module('myApp',
['oc.lazyLoad', 'pascalprecht.translate', 'chart.js']);
Now, I just need to lazy loading pascalprecht.translate in one of my controllers and also lazy loading chart.js, in another controller, but I still need to add inject them to myApp module but I don't know how to inject and I do not use $stateProvider
I tried this my controller that I needed chart.js:
//Load here.
//$ocLazyLoad.load('./panel/dist/test.js');
angular.module('myApp', ['chart.js', [
'./panel/dist/static/chart.min.js',
'./panel/dist/static/angular-chart.min.js'
]]);
$ocLazyLoad.load('./panel/dist/static/chart.min.js');
$ocLazyLoad.load('./panel/dist/static/angular-chart.min.js');
But I got this error:
angular-chart.min.js:10Uncaught Error: Chart.js library needs to
included, see http://jtblin.github.io/angular-chart.js/
First, you do not need to inject chart.js in your dependency injection, this should be your module:
var angularApp = angular.module('myApp', [ 'oc.lazyLoad' ]);
Now, you want to have access to some libraries from different controllers (let's say routes), as you said you do not use $stateProvider which means you do not use ui-router (which is a third-party library to work with routes and URLs).
This is my suggestion (just a simple solution):
angularApp.config(function ($routeProvider, $locationProvider) {
$routeProvider.when('/home', {
templateUrl: 'views/home.html',
controller: 'HomeController',
resolve: {
store: function ($ocLazyLoad) {
return $ocLazyLoad.load(
{
serie: true,
name: "chart.js",
files: [
"./static/chart.min.js",
"./static/chart-angular.min.js",
]
}
);
}
}
});
$routeProvider.when('/needs-translate', {
templateUrl: 'views/needs-translate.html',
controller: 'translateController',
resolve: {
store: function ($ocLazyLoad) {
return $ocLazyLoad.load(
{
serie: true,
name: "pascalprecht.translate",
files: [
"./static/translate.js"
]
}
);
}
}
});
$routeProvider.otherwise({
redirectTo: '/home'
});
// use the HTML5 History API
$locationProvider.hashPrefix = '!';
$locationProvider.html5Mode(true);
});
By the way, if you are using ui.router, this Github issue would be useful for you

Angular js : Uncaught Error: [$injector:nomod] module unavailable

So I'm not sure why this error is returning when serving my project
Uncaught Error: [$injector:nomod] Module 'items.controller' is not
available! You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies as
the second argument.
I feel as thought I've looked at this for too long and I still can't tell what's missing. What am I missing here?
My file structure looks like this...
Inside my items.controller.js
(function () {
'use strict';
angular
.module('items.controller')
.controller('ItemDetailsController', ItemDetailsController);
function ItemDetailsController($state, $timeout, $stateParams, itemsDataService) {
var vm = this;
vm.showItemDetails = showItemDetails;
vm.item = itemsDataService.getById($stateParams.id);
$state.$current.data.pageSubTitle = vm.item.title;
function showItemDetails(id) {
$state.go('itemDetails', {id: id});
}
}
})();
and my items.module.js contains...
(function () {
'use strict';
angular
.module('items', [
'items.controller',
'items.service'
]);
angular.module('items.controller', []);
angular.module('items.service', []);
})();
and within my items.route.js file:
(function () {
'use strict';
angular
.module('items')
.config(routerConfig);
function routerConfig($stateProvider) {
$stateProvider
.state('itemDetails', {
url: '/product/:id',
templateUrl: 'items/itemDetails.html',
controller: 'ItemDetailsController',
controllerAs: 'itemDetails'
})
}
})();
and finally within my index.module.js file:
import { config } from './index.config';
import { routerConfig } from './index.route';
import { runBlock } from './index.run';
import { MainController } from './main/main.controller';
import { ItemDetailsController } from '../app/components/items/items.controller';
import { GithubContributorService } from '../app/components/githubContributor/githubContributor.service';
import { WebDevTecService } from '../app/components/webDevTec/webDevTec.service';
import { NavbarDirective } from '../app/components/navbar/navbar.directive';
import { MalarkeyDirective } from '../app/components/malarkey/malarkey.directive';
angular.module('productsFind', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ngMessages', 'ngAria', 'ngRoute', 'toastr'])
.constant('malarkey', malarkey)
.constant('moment', moment)
.config(config)
.config(routerConfig)
.run(runBlock)
.service('githubContributor', GithubContributorService)
.service('webDevTec', WebDevTecService)
.controller('MainController', MainController)
.controller('ItemDetailsController', ItemDetailsController)
.directive('acmeNavbar', NavbarDirective)
.directive('acmeMalarkey', MalarkeyDirective);
Where have I failed to load it? Thank you in advance for your help. :)
You need to add the line
import '../app/components/items/items.module';
before
import { ItemDetailsController } from '../app/components/items/items.controller'; in your index.module.js file, this is because you're loading modules with ES2015 syntax
later you need to do as #slackmart said previously in his answer: adding the module items to the module productsFind
angular.module('productsFind', ['ngAnimate', 'ngCookies', 'ngTouch', 'ngSanitize', 'ngMessages', 'ngAria', 'ngRoute', 'toastr', 'items'])

Unit-Testing AngularJS: Uncaught Error: [$injector:nomod] Module is not available! and ReferenceError: module is not defined when run Karma

I've a small unitTest in Jasmine run with Karma. But when i run Karma it show errors:
Uncaught Error: [$injector:nomod] Module 'material.controllers' is not
available! You either misspelled the module name or forgot to load it.
If registering a module ensure that you specify the dependencies as
the second argument.
FAILED Unit: LoginController encountered a
declaration exception
ReferenceError: module is not defined
Here are my source code, config Karma file and unitTest.
karma.conf.js
module.exports = function(config) {
config.set({
// base path that will be used to resolve all patterns (eg. files, exclude)
basePath: '',
// frameworks to use
// available frameworks: https://npmjs.org/browse/keyword/karma-adapter
frameworks: ['jasmine'],
// list of files / patterns to load in the browser
files: [
'/home/tanpham/Angular/Dev/libs/angular/angular.js',
'/home/tanpham/Angular/Dev/js/**/*.js',
'/home/tanpham/Angular/Dev/js/*.js',
'/home/tanpham/Angular/Test/*.js'
],
// list of files to exclude
exclude: [
],
// preprocess matching files before serving them to the browser
// available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
preprocessors: {
},
index.html
<body ng-app="material" ng-controller="AppController">
<ui-view></ui-view>
</body>
app.js
angular.module('material.controllers', []);
angular.module('material.services', []);
angular.module('material.directives',[]);
angular.module('material.filters',[]);
var app = angular.module('material', ['ui.router','material.directives','http-auth-interceptor','material.controllers','material.services','material.filters'])
.config(function($stateProvider, $urlRouterProvider,$locationProvider) {
$stateProvider
.state('app', {
url: "/app",
abstract: true,
templateUrl: "views/app.html"
}).state('login', {
url: "/login",
templateUrl: "views/login.html",
controller: "LoginController"
});
$urlRouterProvider.otherwise('/login');
})
loginController
angular.module('material.controllers').controller('LoginController', function($scope) {
$scope.name = "Ari";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
}
});
helloSpec.js
describe('Unit: LoginController', function() {
// Load the module with LoginController
beforeEach(module('material.controllers'));
var ctrl, scope;
// inject the $controller and $rootScope services
// in the beforeEach block
beforeEach(inject(function($controller, $rootScope) {
// Create a new scope that's a child of the $rootScope
scope = $rootScope.$new();
// Create the controller
ctrl = $controller('LoginController', {
$scope: scope
});
}));
it('should create $scope.greeting when calling sayHello',
function() {
expect(scope.greeting).toBeUndefined();
scope.sayHello();
expect(scope.greeting).toEqual("Hello Ari");
});
})
So, i can do with that and my module's name is right?
Check the order in which the angular modules are loaded. As your listing of javascript files in karma conf, see if the module defined files are loaded first before other files that use it.
Adjust the order in this listing, are explicitly load the file where 'material.controllers' module is defined.
files: [
'/home/tanpham/Angular/Dev/libs/angular/angular.js',
'/home/tanpham/Angular/Dev/js/**/*.js',
'/home/tanpham/Angular/Dev/js/*.js',
'/home/tanpham/Angular/Test/*.js'
],
i have met this issue. and solved it.
just add ",[]" behind the module name in the module declare statement。 in this case chaged code will be :
angular.module('material.controllers',[])
.controller('LoginController', function($scope) {
$scope.name = "Ari";
$scope.sayHello = function() {
$scope.greeting = "Hello " + $scope.name;
}
});

Should I instantiate a submodule in large angular apps

I am building a large angular app comprised of various modules
- app
-- member
--- newMember
--- memberDashboard
-- linguistics
-- etc
--- etc etc
In the html I am instantiating individual modules, because I believe there to be a performance improvement over bootstrapping the entire app.
<div ng-app="linguistics">
<div ui-view autoscroll="true"></div>
</div>
However, this means that I have to repeat myself in module configuration. i.e.:
angular.module('linguistics', [
'ui.router',
'ui.bootstrap',
'googlechart',
'babelServices',
'babelFilters'
]).config(function($stateProvider, $urlRouterProvider, $locationProvider, $httpProvider) {
$locationProvider.html5Mode(true);
}).config(function($provide) {
return $provide.decorator('$uiViewScroll', function($delegate, $window) {
return function(uiViewElement) {
//eventually do something more intelligent with the uiViewElement
return $window.scrollTo(0, 0);
};
});
});
html5Mode, scrollTo etc will be repeated across modules. Is there a better way to do this?
I'd add a configuration module, that will handle the grunt work of setting up html5Mode, scrollTo etc.
angular.module('configuration', ['ui.router'])
.config(function ($locationProvider, $provide) {
$locationProvider.html5Mode(true);
// For angular 1.3
$locationProvider.html5Mode({
enabled: true,
requireBase: /* true/false */
});
$provide.decorator('$uiViewScroll', function ($delegate, $window) {
return function (uiViewElement) {
return $window.scrollTo(0, 0);
}
});
});
And then in your subsequent modules:
angular.module('linguistics', ['configuration']);

angular is not defined error when karma test invoked

I'm sure this has something to do with angular-mock.js but I cant figure what I need to do as everything seems to be fine. I'm just going by the default setup from angular-seed app.
Please help get rid of the problem
karma.conf.js
module.exports = function(config){
config.set({
basePath : '../',
files : [
'bower_components/angular/angular.js',
'bower_components/angular-route/angular-route.js',
'bower_components/angular-mocks/angular-mocks.js',
'app/js/**/*.js',
'test/unit/**/*.js'
],
autoWatch : true,
frameworks: ['jasmine'],
browsers : ['Chrome'],
plugins : [
'karma-chrome-launcher',
'karma-firefox-launcher',
'karma-jasmine'
],
junitReporter : {
outputFile: 'test_out/unit.xml',
suite: 'unit'
}
});
};
controllers.js
'use strict';
/* Controllers */
var app = angular.module('myApp.controllers', []);
app.constant('RESTURL', 'http://'+ location.hostname + ':8003');
app.controller('MainCtrl', ['$scope', 'dataService', 'flash', 'mySharedService','facetSearchService', 'facetSelectionService', 'RESTURL', function($scope, dataService, flash, sharedService, facetSearch, facet, RESTURL) {
$scope.RESTURL = RESTURL;
$scope.loading = true;
$scope.data = null;
$scope.resultCount = 0;
$scope.currentPage = 0;
$scope.pageSize = 10;
....
])}
controllerSpec.js
'use strict';
/* jasmine specs for controllers go here */
describe('controllers', function(){
beforeEach(module('myApp.controllers'));
it('should test MainCtrl', inject(function($controller) {
//spec body
var scope = {},
ctrl = $controller('MainCtrl', {$scope:scope});
expect($scope.RESTURL).toBe('http://'+ location.hostname + ':8003'));
}));
});
Project file structure:
I trust you ran "bower install" to install the dependencies?
The paths to bower_components are incorrect. A basepath of "../" will make karma look in the root of your project but your bower_components are in your "app" folder. The "files" in karma.conf need to be prefixed with "app".

Categories

Resources