AngularJS - how to write a unit test containing the momentjs library? - angularjs

I am writing an app with AngularJS 1.5.3.
I want to test one of my services and I want to use momentjs in the tests.
test example:
it('should have the correct number of weeks in the calendar month for Feb', function () {
var dateString = '2018-02-01';
Calendar.data.currentCalendarMonth = moment(dateString).startOf('month');
Calendar.buildMonth();
var start = moment(dateString).startOf('month').isoWeek();
var end = moment(dateString).endOf('month').isoWeek();
expect(end - start + 1).toBe(Object.keys(Calendar.data.weeks).length);
});
When I run the tests I get this error:
TypeError: moment(...).year(...).week is not a function
I have tried to import momentjs in my karma config file but it had no effect.
Edit: Moment is listed as a dependency in my bower config file. I tried to put the moment files before my files in karma config but it didn't help the result.
moment(...).year(...).week is used in my Calendar service but not in my unit test there.

Related

Gulp Compiling Angularjs 1 Scripts in, incorrect order

Why does this happen? When I compile the scripts using GULP the console will display errors, explaining that my directives and/or my controllers are not registered. Then to correct this error I create the app variable within the controller file and it then renders a new error, then I put the app variable declaration back and everything works fine.
This is my Gulp Script
var gulp = require('gulp'),
plugins = require('gulp-load-plugins')({
pattern: ['gulp-*', 'gulp.*'],
replaceString: /\bgulp[\-.]/
});
var path = {
jsFiles: "./js/**",
scriptFile: "scripts.min.js",
output: "dist/assets/"
};
var options = {
ie8: true,
warnings: true,
mangle: true
};
gulp.task('scripts', function (cb) {
return gulp.src(path.jsFiles)
.pipe(plugins.sourcemaps.init())
.pipe(plugins.jsdoc3(cb))
.pipe(plugins.concat(path.scriptFile))
.pipe(plugins.babel())
.pipe(plugins.ngAnnotate())
.pipe(plugins.uglify(options))
.pipe(plugins.sourcemaps.write("../../maps"))
.pipe(gulp.dest(path.output))
})
TLDR: MY Gulp task sometimes compiles the AngularJS directives and controllers out of order rendering my app declaration undefined.
When you pass globe to the
gulp.src
No ordered is guaranteed, so it is possible to get wrong order time to time. But gulp.src also accepts array of the pathes you need to include and this should guarantee the order
So, try to split your bundle and pass path to the angular.min.js as a first element like this:
gulp.src(['path/to/angular.min.js', 'path/to/your/code'])
You should sort angular files, and there are some libs that does that.
https://www.npmjs.com/package/gulp-angular-filesort is one of them.

Require .js file into my angular controller

I have a resampler.js file which does audio resampling. This file requires 2 other .js files:
var WebAudioLoader = require('webaudioloader');
var WavEncoder = require("wav-encoder");
I want to use this resampler in my angular controller like:
resampler(URL, 192000, function (event) { });
When i run my app i get the error: require is not defined
I read about the browserify library which lets include npm libraries for the browser but I am still unable to make it work.
Any ideas?

How to create a bundle using gulp without using "require" everywhere

Thanks for reading. I am new to gulp, so apologizing if its a dumb question. I have an AngularJS project with the following folder structure:
app/
app.js
modules/
mod1/
index.js
mod1.js
another.js
mod2/
... same structure as mod1
To create a bundle using browserify I am using this:
gulp.task('bundle', function() {
return browserify('app/app.js')
.bundle()
.pipe(vinylSource('bundle.js'))
.pipe(gulp.dest('public/js'));
});
To make this work, I have include require('mod1') ..require('another') and so on.
I always have to make sure that I am requiring the script that I need to use.
My goal is to create a bundle that includes all javascript file inside my app folder starting from app.js without getting into dependency conflicts and without me writing require('somefile').
You can get that by just using the gulp-concat plugin.
You just specify the paths to search. Because you're using angular and need the modules defined before everything else, I'd add the app first, then all the module definitions, then remaining directives and controllers etc after.
var gulp = require('gulp');
var concat = require('gulp-concat');
gulp.task('app-js', function() {
return gulp.src([
'./app/app.js',
'./app/**/mod*.js',
'./app/**/*.js',
])
.pipe(concat('bundle.js'))
.pipe(gulp.dest('public/js'))
});

Angular Karma Unit Test: How to inject a mock service in karma configuration instead of in all test specs

Recently, I have added a security feature to an existing angular app. Here is what I got afterwards:
Chrome 3X.0.2125 (Linux) ERROR
Some of your tests did a full page reload!
Chrome 3X.0.2125 (Linux): Executed 23 of 102 (skipped 2) ERROR
This is how I have set up the security feature:
angular.module('myapp', [/*..I have omitted..*/])
.run(function(MyLoginSerivce, /*.. I have omitted ..*/)){
if(!MyLoginService.isLoggedIn()){
MyLoginService.redirectForLogin();
}else{
/* other logics */
}
}
I knew I have to add the following code to each and every test spec. But it sounds silly adding it to dozens of test files.
beforeEach(module(function($provide){
$provide.value("MyLoginServce", {
isLoggedIn: function(){
return true;
},
redirectForLogin: function {}
});
}));
Is there a way to tell Karma that use a mock service and add that piece of code only once and in one place?
Thanks
Current solution
Step 1: I saved this in a separate file, e.g. ./test/mocked.login.service.js:
var mockedLoginService = {
isLoggedIn: function(){
return true;
},
redirectForLogin: function {}
});
Step 2: I include the file in karma.conf.js, by inserting 'test/mocked.login.service.js'
Step 3: I just use it in my tests like the following:
beforeEach(module(function($provide){
$provide.value("MyLoginServce", mockedLoginService
}));
You can extract the mocked service into a separate js file as an object, include that file in the karma.conf files list, then use that object as a global in your specs.

Code coverage for Protractor tests in AngularJS

I am running some e2e tests in my angularJS app with protractor (as recommended in the angularJS documentation).
I've googled around and cannot find any information on how to measure coverage for my protractor tests.
I think I'm missing something here... is there any way to get a code coverage report for protractor e2e tests? Or is it simply a feature for unit tests?
This is achievable using Istanbul. Here is the process, with some example configurations that I've extracted from our project (not tested):
Instrument your code using the command istanbul instrument. Make sure that istanbul's coverage variable is __coverage__.
// gulpfile.js
gulp.task('concat', function () {
gulp.src(PATH.src)
// Instrument for protractor-istanbul-plugin:
.pipe(istanbul({coverageVariable: '__coverage__'}))
.pipe(concat('scripts.js'))
.pipe(gulp.dest(PATH.dest))
});
Configure Protractor with the plugin protractor-istanbul-plugin.
// spec-e2e.conf.js
var istanbulPlugin = require('protractor-istanbul-plugin');
exports.config = {
// [...]
plugins: [{ inline: istanbulPlugin }]
};
Run your tests.
Extract the reports using istanbul report.
This approach has worked for me and is easy to combine with coverage reports from unit tests as well. To automate, I've put step 1 into my gulpfile.js and step 3 and 4 in the test and posttest scripts in package.json, more or less like this:
// In package.json:
"scripts": {
"test": "gulp concat && protractor tests/spec-e2e.conf.js",
"posttest": "istanbul report --include coverage/**/.json --dir reports/coverage cobertura"
},
if you are using grunt - you can use grunt-protractor-coverage plugin, it will do the job for you. You will have to instrument the code first and then use the mentioned plugin to create coverage reports for you.
To add to ryanb's answer, I haven't tried this but you should be able to use something like gulp-istanbul to instrument the code and override the default coverage variable, then define an onComplete function on the jasmineNodeOpts object in your Protractor config file. It gets called once right before everything is closed down.
exports.config = {
// ...
jasmineNodeOpts: {
onComplete: function(){
browser.driver.executeScript("return __coverage__;").then(function(val) {
fs.writeFileSync("/path/to/coverage.json", JSON.stringify(val));
});
}
}
};
I initially tried the onComplete method suggested by daniellmb, but getting the coverage results only at the end will not include all the results if there were multiple page loads during the tests. Here's a gist that sums up how I got things working, but basically I had to create a reporter that added coverage results to the instanbul collector every time a spec finished, and then wrote the reports in the onComplete method. I also had to use a "waitPlugin" as suggested by sjelin to prevent protractor from exiting before the results were written.
https://gist.github.com/jbarrus/286cee4294a6537e8217
I managed to get it working, but it's a hack at the moment. I use one of the existing grunt istanbul plugins to instrument the code. Then I made a dummy spec that grabs the 'coverage' global variable and write it to a file. After that, you can create a report with any of the reporting plugins.
The (very over-simplified) test looks like:
describe('Output the code coverage objects', function() {
it('should output the coverage object.', function() {
browser.driver.executeScript("return __coverage__;").then(function(val) {
fs.writeFileSync("/path/to/coverage.json", JSON.stringify(val));
});
});
});

Resources