Include dependencies in Karma test file for Angular app? - javascript

I am trying to get started with Karma tests, adding them to an existing Angular app.
This is my main app definition file:
angular
.module('myApp', [
'ngRoute',
'moduleAdherence'
]);
This is my controller file:
angular
.module('moduleAdherence', [])
.controller('AdherenceCtrl', ['$scope', function ($scope) {
$scope.awesomeThings = [1,2,3,4];
}]);
This is my first stab at a file:
describe('Controller: AdherenceCtrl', function () {
beforeEach(module('myApp'));
var MainCtrl,
scope;
beforeEach(inject(function ($controller, $rootScope) {
scope = $rootScope.$new();
MainCtrl = $controller('AdherenceCtrl', {
$scope: scope
});
}));
it('should attach a list of awesomeThings to the scope', function () {
expect(scope.awesomeThings.length).toBe(4);
});
});
When I try to run this with grunt test, it fails with the following error:
Uncaught Error: [$injector:nomod] Module 'd3' 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.
http://errors.angularjs.org/1.2.0/$injector/nomod?p0=d3
at /Users/me/Dropbox/projects/myapp/app/bower_components/angular/angular.js:1498
I don't understand this, because this controller does not Use D3. I do use D3 elsewhere in the app, in a directive, but I'm not registering it with the module (I use the external D3 file).
Why is Karma noticing D3? Shouldn't it be able to test this controller without D3?

In karma configuration file (karma.conf.js) you need to define all libraries.
etc.
// list of files / patterns to load in the browser
files: [
'app/lib/angular/angular.js',
'app/lib/angular-route/angular-route.js',
'test/lib/angular-mocks.js',
'app/app.js',
'app/controllers/*.js',
'app/services/*.js',
'app/*',
'test/spec/**/*.js'
],

Had a similar problem and my solution (inspired someway by #danba comment) was to load the scripts in the files in the exact same order as they were loaded in the index.html.
In my case globbing patterns like app/scripts/**/*.js were causing trouble to karma which constantly threw errors.
Maybe not the most elegant solution to copy all the scripts definitions but worked in the end so my test could finally get back running. Hope it helps.
EDIT: Editing this because today I probably (and hopefully) got the hang of what was going wrong here. So it seems that Karma does not like globbing patterns when the same module is defined in one file and used in many different files. Let's say that your folder structure is like this:
Suppose that in AuthService.js you have your module definition for all your services in that folder, so that that file starts with:
angular.module('myApp.services', [
'myApp.urls',
'ngCookies'
])
Then in all the other files you're just attaching other services to that same module. In the picture tokenService.js would start with:
angular.module('myApp.services');
If everything stays this way everything will probably work. But if by any chance I define the module the other way round, so the module definition is not anymore in the first file of that folder but on another that Karma reads after AuthService then it will throw an error and refuse to complete the tests.
Solution 1
A solution might be to put the module definition in its own file, starting with an underscore. Finally, let all the siblings files depend on that one(s). So the above folder structure should be:
Solution 2
Another - probably better - solution is to mark the files where the modules are defined with a common suffix/extension for example service.module.js while the files that depend on it could be named normally like authService.js, tokenService.js.
The Karma configuration at that point will become something like:
// list of files / patterns to load in the browser
files: [
'app/lib/angular/angular.js',
'test/lib/angular-mocks.js',
'app/app.js',
'app/**/*.module.js', // <-- first the module definitions...
'app/**/*.js', // <-- ..then all the other files
'test/spec/**/*.js'
],
This way karma will load the modules definitions first and then those file that depend on them.

I also had the same issue, in my case problem occured because there were several files per module which is a bad practice since we can point to not initialized module. Solved this by including just one file per module.

Always load the non minified version of angular into karma.
it will display errors and help you better to find out what to change.
In your case, it's the order of the files being loaded by karma.

Check your index.html that you don't include something by a script tag like.
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.5angular-resource.js"
All your Javascript file need to be in your karma.config.js

Here's a simple solution that worked for me, based on above Solution #1 by #Nobita, AND #danba's comment.
In karma.conf.js, explicitly load the prerequisite file above the pattern that pulls in the rest:
files: [
...
'app/module.js',
'app/*.js'
]
Karma does not seem to mind that the pattern also matches 'module.js'.

Related

How does AngularJS knows where to look for a module to load?

I have an app module defining dependencies (taken from phonecat-Tutorial) in the directory app:
app.module.js:
angular.module('phonecatApp', [
'phoneList' // (*)
]);
Then, in a directory app/phone-list are the module:
phone-list/phone-list.module.js:
angular.module('phoneList', []);
and component:
phone-list/phone-list.component.js:
angular.module('phoneList').component('phoneList', {...});
From registering the module phoneList in the first snippet at (*), how does AngularJS knows where to fetch the module from? Is the mapping from phoneList to phone-list-directory naming a builtin feature?
AngularJS has a dictionnary of modules. The key in this dictionnary is the string that you give your module when you register it with the following line :
angular.module('phoneList', []);
That's why the previous line must always have been executed in javascript before you can use your module by adding a component (like following line) :
angular.module('phoneList').component('phoneList', {...});
or by injecting your module into another module
angular.module('phonecatApp', [
'phoneList'
]);
The code for relevant modules has to be included in scripts included in the page. This is either done by manually adding various script tags or by task runners like grunt, gulp, webpack etc adding them for you.
If dependency module code doesn't exist angular will throw error
In simpler terms - where the code comes from is not angular's responsibility. It has to already exist for angular to work

Require file on runtime & unit test issue

I use require.js to load files at runtime like following
This is working as expected when I run the file in the right context(I mean when the call is coming from the right path.)
module1.js
define(["otherModule"], function(otherModule) {
working!!!
....
Now I want to create some unit test to this file (module1) from
other context (from folder of tests which is found in diffrent location in the project) and I get error
require.js:145 Uncaught Error: Script error for: otherModule
Since it tries to run the get on this path during the Unit Test
which is located in diffrent project structure ...
https://app/path1/path2/path3/otherModule.js
And in runtime which works (from different context) it find it in the path
https://app/path1/path2/path3/path4/path5/otherModule.js
There is additional path4 & path5 in the request that works,
How should I solve it to work on both cases (UT/Runtime) ?
http://requirejs.org
I think you should be able to get it working by applying a RequireJS configuration file, so that the module name is abstracted from its path:
E.g. in the test context, call something like this as initialization step:
require.config({
baseUrl: "/path1/path2/path3"
});
Alternatively, you can also remap single modules like so (this can also be used to inject a different implementation of a specific module for testing etc.):
require.config({
paths: {
"otherModule": "/path1/path2/path3/otherModule"
}
});
See here: http://requirejs.org/docs/api.html#config

Require third party RequireJS modules with Webpack

I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';

angularjs undefined main module when minifying using typescript

I am trying to minify and uglify my angularjs + typescript app using grunt-minified. Currently I am getting an error that my main module for the app is not available when I minify. I know why this is occuring due variable names no longer matching the names of the modules they reference. How would I set up annotation so angular is able to identify my main module after minification?
declare module BB {
}
module BB.MyModule {
// initialize the module
export var module = angular
// load the dependencies
.module("MyModule", [
// dependancies
]);
}
This basic setup is working fine unminified, but MyModule is not defined when I minify it. How would I go about defining for safe minification?
You have:
declare module BB {
}
Probably BB has been minified to something else. That would make module BB.MyModule be different from BB.
Solution: Your code is already safe for minification if the point where you bootstrap angular https://docs.angularjs.org/api/ng/function/angular.bootstrap is minified through the same pipeline as BB.module is passed through.

how to run more than one angular directive modules on Pprod

I am working on jhipster Release 0.7.0 and I have multiple type of directive modules in our jhipster app.first for index page and second for commmon directive.
When we run on Prod profile i got an exception :-
[31mPhantomJS 1.9.7 (Windows 7) ERROR[39m Error: [$injector:nomod]
Module 'common-services' 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.
http://errors.angularjs.org/1.2.11-build.2192+sha.e2173f9/$injector/nomod?p0=common-services
at
D:/github_repo/gather-our-code/src/main/webapp/bower_components/angular/angular.js:1531
same code is working on develop profile ..
Please help me to solve this bug ASAP
The "prod" profile uses JavaScript minification (run by Grunt), which will reduce the size of your JavaScript file.
As this modifies your JavaScript code, it can cause issues, depending on how you write your dependency injection code.
Have you looked at the sample directives that are provided ? Or at the sample controllers ? You must write your dependency injection in the same style.
For example, to inject the $scope:
jhipsterApp.controller('MainController', ['$scope',
function ($scope) {
}]);
This will ensure the minification process won't break dependency injection of the "$scope" variable.
If you can't make it work, you can also exclude your files from the minification process: it depends on your load, but for most applications this is overkill. This is configured in your Gruntfile.js file.

Categories

Resources