AngularJS with Webpack - Testing with Karma, Mocha, and Chai

Kent C. Dodds
InstructorKent C. Dodds

Share this video with your friends

Send Tweet

Testing in Angular applications takes a bit of setup. Webpack simplifies things considerably. In this lesson you'll see how to test an Angular application built with Webpack using karma, mocha, and chai.

Tristan Smith
Tristan Smith
~ 6 years ago

I'm not too sold on the idea of pulling the tests in via the application instead of loading the application into the test, because the use of the ON_TEST switch means that you are forced to use require which feels wrong when you are building within es6 because you should be using import moduleName from 'module' and that is impossible to do within an if statement, as all imports are required to be at the root of the module (i.e. not within any extra scopes or blocks)

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

I agree that it stinks that you can't put an import statement in a block, but because we're building the application with webpack there's no problem with using require and it is worth having the modularity of this approach even if it means having that little inconsistency. But we all have our opinions.

An alternative approach would be to have an index.test.js in the directory (side-by-side with the index.js file). That wouldn't be too bad. I hope everything else was helpful!

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

Of course, with this approach you would have to specify a different entry for your tests. This is no problem because the entry file is normally pretty small. And if it's not, you can create an index.common.js file that the index.js and index.test.js files import.

River Search
River Search
~ 6 years ago

So glad you're doing this series. Really great so far. There is definitely still a bit of awkwardness involved in using webpack but overall I think it will end up being much cleaner than trying to do everything with gulp - anxious to see more!

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

Interested to know what you would consider "awkwardness." I don't feel like it's awkward at all, but I am eager to know what other people feel about it as this will help direct my lessons.

Tristan Smith
Tristan Smith
~ 6 years ago

I'd have to agree that i'd feel happier doing it this way as opposed to having this weird side case for testing in it that only works within the context of require-able modules.

Also another thing to note is that with es6 modules, as opposed to node modules index.js is not a defaultly loaded script, it's better to point to a specific file so instead of import directives from './directives' you'd be better of doing something like import directives from './directives/common' where you'd have directives/common.js thus your files are compatable with the es6 loader without much System configuration

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

Just a different way to do things. This lesson is how you do stuff with webpack and webpack enables everything that I did. I really like the api and the approach and I feel like it empowers me to build modular scaleable angular (not an easy thing to do).

moti zharfati
moti zharfati
~ 6 years ago

I am little bit confused, don't we need karma or gulp anymore? this method (of resolving files with webpack) is going to work the same with angular 2? I saw a places who try to mix between gulp and webpack, is there a good reason to do that?

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

Good question. I don't use grunt/gulp at all in my project at work. I do use grunt in angular-formly for deploying gh-pages (https://github.com/formly-js/angular-formly). Karma is still used for sure, and it uses the karma-webpack plugin to integrate with webpack. But to run it, we're still using karma start. So karma, in this example, is still very much useful. But I have found other build systems to not be totally useful because webpack just does everything for you from your JS to your CSS and even your images. They all go into the bundle.js file and you just deploy that.

There are some things that webpack WONT bundle. Like fonts or big images. For those, you can tell webpack where to put them. Also, you need to copy your index.html, robots.txt, and other non-bundled resources. In my project, I accomplish this as simply as:

cp app/{index.html,.htaccess,favicon.ico,robots.txt} dist/

and boom, I don't need an entire build config or pipeline just to do something I can do in a bash script.

As far as your question with Angular 2. It will absolutely work! Right now I'm trying to make an example, but Angular 2 is still pretty young so it's been a little bit of a struggle, but it's definitely going to work :-)

moti zharfati
moti zharfati
~ 6 years ago

Thank you!

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

You're very welcome!

Jim
Jim
~ 6 years ago

Great set of episodes. Kent, is it possible to have a future episode on how you can deploy such an app?

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

Awesome idea. I'll add it to my list!

Omer Koren
Omer Koren
~ 6 years ago

Hi, Great tutorial. Thanks. I've tried to clone your code, but it gave me errors. I've downloaded the project, ran npm install, and then npm start - but it gave me this: 0 info it worked if it ends with ok 1 verbose cli [ 'c:\Program Files\nodejs\\node.exe', 1 verbose cli 'c:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js', 1 verbose cli 'start' ] 2 info using npm@2.5.1 3 info using node@v0.12.0 4 verbose node symlink c:\Program Files\nodejs\node.exe 5 verbose run-script [ 'prestart', 'start', 'poststart' ] 6 info prestart webpack-angular@1.0.0 7 info start webpack-angular@1.0.0 8 verbose unsafe-perm in lifecycle true 9 info webpack-angular@1.0.0 Failed to exec start script 10 verbose stack Error: webpack-angular@1.0.0 start: node node_modules/.bin/webpack-dev-server --content-base app 10 verbose stack Exit status 1 10 verbose stack at EventEmitter.<anonymous> (c:\Program Files\nodejs\node_modules\npm\lib\utils\lifecycle.js:213:16) 10 verbose stack at EventEmitter.emit (events.js:110:17) 10 verbose stack at ChildProcess.<anonymous> (c:\Program Files\nodejs\node_modules\npm\lib\utils\spawn.js:14:12) 10 verbose stack at ChildProcess.emit (events.js:110:17) 10 verbose stack at maybeClose (child_process.js:1008:16) 10 verbose stack at Process.ChildProcess._handle.onexit (child_process.js:1080:5) 11 verbose pkgid webpack-angular@1.0.0 12 verbose cwd C:\Users\Yonk\Documents\webPackApp 13 error Windows_NT 6.1.7601 14 error argv "c:\Program Files\nodejs\\node.exe" "c:\Program Files\nodejs\node_modules\npm\bin\npm-cli.js" "start" 15 error node v0.12.0 16 error npm v2.5.1 17 error code ELIFECYCLE 18 error webpack-angular@1.0.0 start: node node_modules/.bin/webpack-dev-server --content-base app 18 error Exit status 1 19 error Failed at the webpack-angular@1.0.0 start script 'node node_modules/.bin/webpack-dev-server --content-base app'. 19 error This is most likely a problem with the webpack-angular package, 19 error not with npm itself. 19 error Tell the author that this fails on your system: 19 error node node_modules/.bin/webpack-dev-server --content-base app 19 error You can get their info via: 19 error npm owner ls webpack-angular 19 error There is likely additional logging output above. 20 verbose exit [ 1, true ] Any idea why?

Omer Koren
Omer Koren
~ 6 years ago

I do have another question that's more controversial. We're currently using requirejs as our AMD library.
In your series, you cover almost everything - from requiring files through bundeling to testing. It's great to know something covers (almost) everything before messing around with it (+1 for the deployment tutorial addition :)). Joel wrote to me that requirejs is a bad practice with angular (even though many claim it's a good one, but I do find requirejs to be a bit... unexpected, especially when it comes to testing). Would you suggest moving from requirejs to webpack as a good practice (or at least a good move)?

Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

First off, about your error. I'm not certain what the problem is. Webpack has a strong community though and if you take that question to StackOverflow, you should receive an answer.

As for AMD, webpack actually can consume AMD modules very nicely. So even if you adopt webpack, you don't have to change all of your code immediately.

That said, AMD is dying in popularity. The BEST is to write your code using as much ES6 as possible.

Note: Webpack is a module loader, not a module system. It simply consumes modules. It can consume AMD, CommonJS, ES6 modules, and even globals.

Good luck!

wil
wil
~ 6 years ago

The karma.config watch property does not work for me. Did it work for you?

Any time a file changed the test harness just plain crashed.

And, I cannot think of a less informative or enlightening test than:

  expect(true).to.be.true;
Kent C. Dodds
Kent C. Doddsinstructor
~ 6 years ago

Hmm... Perhaps you could write-up a stack overflow question or file an issue on Karma's github?

CodeHeaven
CodeHeaven
~ 6 years ago

Oh boy. Is unfortunate that less than 1 year later almost all courses I try to follow will run into problems that I just can't follow what's in the video, and usually into some specific problems that I just cannot solve.

Things move fast, I know, but this is being frustrating...

Mark
Mark
~ 5 years ago

it's mostly due to the node modules they use at the time, then go out of date pretty quickly. I've been looking at their module versions in their package.json's on github and see the version numbers. Then i try to find answers on upgrading those modules

i also am struggling with a lot of these tho :catface:

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

I'm sorry about that. I've been thinking that I should probably update this series. The problem you're most likely running into is the version of babel you're using. This series uses Babel v4 and the latest version of Babel is v6. Version 6 was a hugely breaking change to Babel and how everything works. Try getting things going with Babel 5 and then see if you can then upgrade it to Babel 6 (you'll also need an older version of the babel-loader). Take a look at this guide to help you upgrade.

Lee Blazek
Lee Blazek
~ 5 years ago

Any chance of getting this going with the oc lazyload module?

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

Unfortunately I never personally got that far in my experience and I'm not doing Angular at work anymore so it's unlikely that I'll learn much about ocLazyLoad. Good luck!

Jonathan
Jonathan
~ 5 years ago

Hi,

First of all, I wanted to say that I'm really loving this course. Thanks so much!

However, this part really doesn't work for me.

I'm getting: Unhandled rejection Error: not a directory in MemoryFileSystem.js:144:10

I'm using jasmine instead of mocha & chai, and I have multiple modules (which my main module - "myApp" - depends on - i.e. "myApp.directives", "myApp.services", etc.).

I'm wondering if I'm the only one having problems.

I've got karma-webpack@^1.7.0 and webpack@^1.12.12

When I looked at the karma.conf.js file on the karma-webpack plugin github page, it looked entirely different. But that also didn't work for me.

So is anyone else having trouble? or even a solution (better :))?

Thanks!

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

Hi Jonathan, I think we'll need more info to help with that. I would recommend that you follow the Karma instructions for getting help: https://github.com/karma-runner/karma/blob/master/CONTRIBUTING.md#got-a-question-or-problem

Good luck!

Cameron
Cameron
~ 5 years ago

Kent,

Thanks for the great tutorial. I used it to setup a similar build with typescript. I am having trouble using karma-coverage (Istanbul). Have you used a coverage tool with this style of webpack angular before?

I have seen similar builds online with the test file separate from the index. I can get karma-coverage working, with a build like the one in the tutorial but it includes the whole project not just the files under test.

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

Hi Cameron! I'm glad you've found this series helpful! I've never used TypeScript before, but I'm confident that you should be able to configure karma-coverage in such a way to include only project files in your report. What have you tried?

Linghua
Linghua
~ 5 years ago

I was having this issue 12 03 2016 17:13:45.509:WARN [plugin]: Cannot find plugin "karma-chai".

And npm i -g karma-cli

Solves it, maybe you want to mention it:)

samir shah
samir shah
~ 5 years ago

Thanks you saved my day :)

janppires
janppires
~ 5 years ago

Hi Kent.

What kind of setup is needed to have karma running all the tests and vendor code to be in a separated chunk?

I would like to have only one place were I define my vendor dependencies. We can declare our dependencies as an array in webpack config (entry.vendor : ['angular-resource']). But then Karma complains that does not recognize my dependencies. That happens because I do not declare my vendor dependencies inside entry.app file.

I have been watching also your other course 'Using Webpack for Production JavaScript Applications' but it does not help me, since I am trying to apply the angular structure you define here.

I would love if you could add a video in this series about 'angular+vendor_chuncks+karma' would be awesome.

Thanks!

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

Hi janppires! In this lesson I explain that you should not use the CommonsChunkPlugin in a test environment. When you say:

I do not declare my vendor dependencies inside entry.app file.

Do you mean that you don't explicitly require/import those dependencies in your app's entry file? If not, you should. By using the CommonsChunkPlugin for the vendor entry, those dependencies wont be bundled in the app bundle.

janppires
janppires
~ 5 years ago

Hi Kent.

I managed to have it working like this: Only for production I setup a vendor entry file entry: { vendor : './src/main/webapp/app/vendor.js' }

and using the ON_TEST trick, i declare on my main index.js file: if(ON_TEST) { require('./vendor'); }

So with this, when I am distributing, I bundle a vendor file and use also the CommonsChunckPlugin. When I am testing I include everything (with ON_TEST) but do not use CommonsChunckPlugin, because of the reason you mention. And it works OK. I still do not like the solution, but at least I have only one place where I define my vendor dependencies (vendor.js file).

janppires
janppires
~ 5 years ago

Hi again!

With the structure you define for this angular project, how do you add code coverage?

I cannot apply the explanation you give "Using Webpack for Production JavaScript Applications (Add Code Coverage to tests in a Webpack project)". In this angular project we are using the "alternative usage" of karma-webpack, right? How do I tell to karma which files it should do code coverage?

As it should looks familiar to you, I have this:

var path = require('path');
var webpackConfig = require('./webpack.config');
var entry = path.resolve(webpackConfig.entry.bundle);
var preprocessors = {};
preprocessors[entry] = ['webpack', 'sourcemap'];

module.exports = function(config) {
  config.set({
      browsers: ['PhantomJS'],
      frameworks: ['mocha', 'chai-jquery', 'jquery-2.1.0', 'sinon-chai'],
      reporters: ['mocha', 'coverage'],
      coverageReporter : {
          dir: 'build/reports/web-coverage',
          reporters: [
              {type: 'lcov', subdir: '.'},
              {type: 'json', subdir: '.'},
              {type: 'text-summary'}
          ]
      },
      logLevel: config.LOG_INFO,
      autoWatch: true,
      singleRun: true,
      colors: true,
      port: 9876,
      basePath: '',
      files: [entry],
      exclude: [],
      webpack : webpackConfig,
      preprocessors: preprocessors,
      concurrency: Infinity,
      webpackMiddleware: {noInfo: true},

      // omit plugins to allow automatic inclusion
      // plugins :[]
  })
}

I also was watching this video from you https://www.youtube.com/watch?v=P-1ZZkpEmQA but again, it is not angular, and I don't know what am I missing here! =(

Many thanks!

janppires
janppires
~ 5 years ago

Hi Kent,

I have created an example of my angular app, based on your proposal. But I cannot figure out how should I configure the karma.config file and how should I setup my spec files properly to accept code coverage!

https://github.com/janppires/angular-webpack-demo-project

I am struggling with which files should I preprocess, which files should I add to 'files' array, if karma-coverage already handles with istanbul or if I must add the preloader for it.

I would appreciate your help here!

Many thanks!

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

Here you go :-) https://github.com/janppires/angular-webpack-demo-project/pull/1

janppires
janppires
~ 5 years ago

Cool!!

Thanks a lot!

Cheers!

Justin
Justin
~ 5 years ago

Can you post an example of how to tests a service once you have things set up? I have everything setup correctly but I'm not sure how to write real tests.

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

My favorite example of Angular testing is: https://github.com/zanthrash/yawa

Chris Gaona
Chris Gaona
~ 5 years ago

I've followed your tutorial and for the most part everything seems to be working, but for some reason when I run the karma test, it gives an error saying the following: SyntaxError: Use of reserved word 'import'. I'm trying to figure out what I'm doing wrong. I've been struggling to fix this error for a while now. Any idea why it would be giving this error? Here is my github repo if you have time to take a look: https://github.com/chris-gaona/chris-gaona-portfolio. Thank you!

Kent C. Dodds
Kent C. Doddsinstructor
~ 5 years ago

Hi Chris, based on that error, it sounds like you're ES6 modules aren't being transpiled. Things have changed a bit since I made this course and I think that you'd actually really benefit by going through my Frontend Masters workshop slides (specifically starting here) (the recording isn't available yet). But the slides (and corresponding links/diffs) should be really helpful to you. Good luck!

Suhas
Suhas
~ 5 years ago

Thanks, I was struggling with the same issue.