2

I have a large Angular project written in Typescript which is turned into a bundle by Webpack. When using Karma I have been getting a page reload issue which I cannot resolve. Therefore I have switched to trying Mocha but I cannot get this to work properly. I have followed the accepted answer to this question to get me this far.

First problem

Perhaps someone can tell me what I'm doing wrong or show me the right way to set this up.

I run the webpack-dev-server for testing like this:

./node_modules/.bin/webpack-dev-server --config webpack.test.config.js

This gives me a web page where I can see the test run output. If I change any of my Typescript the bundle is rebuilt and the hot module reload kicks in but then I get an error on the web page:

TypeError: Cannot read property 'call' of undefined
    at callFn (eval at <anonymous> (test/test.build.js:8459:9), <anonymous>:4471:20)
    at Hook.Runnable.run (eval at <anonymous> (test/test.build.js:8459:9), <anonymous>:4464:7)
    at next (eval at <anonymous> (test/test.build.js:8459:9), <anonymous>:4810:10)
    at eval (eval at <anonymous> (test/test.build.js:8459:9), <anonymous>:4832:5)
    at timeslice (eval at <anonymous> (test/test.build.js:8459:9), <anonymous>:75:27)

If I refresh the page then the tests run again.

Second problem

My directive test that used to work now breaks because the scope object is not the same as it used to be. The scope I pass into the $compile function does not have the directive's functions on it. These are now on scope.$$childTail I don't know if this is a side-effect of switching to Mocha or something I have done wrong.

webpack.config.js

var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');

module.exports = {
      devtool: 'inline-source-map', //just do inline source maps instead of the default
      module: {
        loaders: [
          { test: /\.css$/, loader: "style-loader!css-loader" },
          {
            test: /\.json$/,
            loader: 'json',
          },
          {
            test: /\.ts(x?)$/,
            exclude: /node_modules/,
            loader: 'babel-loader!ts-loader',
            //loader: 'babel-loader?presets[]=es2015&presets[]=react!ts-loader'
          },
          {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
            //loader: 'babel-loader?presets[]=es2015&presets[]=react!ts-loader'
          },
        {
            test: /masonry|imagesloaded|fizzy\-ui\-utils|desandro\-|outlayer|get\-size|doc\-ready|eventie|eventemitter/,
            loader: 'imports?define=>false&this=>window'
        }
        ],
      },
      resolve: {
        root: [ path.resolve('./ng/ng') ],
        extensions: ['', '.ts', '.tsx', '.js', '.css'],
       alias: {
           'react-dom': 'react/lib/ReactDOM',
      //    'react$'      : path.resolve(__dirname, 'node_modules/react/dist/react-with-addons.js'),
          'react/addons': path.resolve(__dirname, 'node_modules/react-addons/index.js'),
          'xeditable.css': path.resolve(__dirname, 'node_modules/angular-xeditable/dist/css/xeditable.css'),
          'textAngular.css': path.resolve(__dirname, 'node_modules/textangular/dist/textAngular.css'),
       }
      },
      externals: {
        'cheerio': 'window',
        'react': 'React',
        'react-addons': 'React',
        'react-dom': 'ReactDOM',
        'react-dom/server': true,
        //'react-addons-test-utils': true,
        'ChemDoodle': true,
        //'react': true,
        //'react/addons': true,
        //'react/lib/ExecutionEnvironment': true,
        //'react/lib/ReactContext': true
      },
      entry: {
               itracker: './ng/ng/app.ts',
      },
      output: {
        //path: '.',
        //publicPath: '/website/js/',
        path: path.resolve('.'),
        publicPath: 'http://localhost:3000/assets/bundles/', // Tell django to use this URL to load packages and not use STATIC_URL + bundle_name
        //filename: 'itracker.bundle.js'
        filename: "[name]-[hash].js",
      },
      plugins: [
        new webpack.HotModuleReplacementPlugin(),
        new webpack.NoErrorsPlugin(), // don't reload if there is an error
        new BundleTracker({filename: './webpack-stats.json'}),
        //new webpack.optimize.OccurenceOrderPlugin(),
        // Export a global jQuery
        new webpack.ProvidePlugin({
          $: "jquery",
          jQuery: "jquery",
          "window.jQuery": "jquery"
      })
      ]
}

webpack.test.config.js

var path = require('path');
var webpack = require('webpack')
var BundleTracker = require('webpack-bundle-tracker')

var config = require('./webpack.config.js');
const index = path.resolve(__dirname, './test/test_index.js');

config.entry = { tests: 'mocha!'+ index };

config.module.loaders = [
        {
            test: /\.ts(x?)$/,
            exclude: /node_modules/,
            loader: 'babel-loader!ts-loader',
        },
        {
            test: /\.js$/,
            exclude: /node_modules/,
            loader: 'babel-loader',
        },
        {
            test: /masonry|imagesloaded|fizzy\-ui\-utils|desandro\-|outlayer|get\-size|doc\-ready|eventie|eventemitter/,
            loader: 'imports?define=>false&this=>window'
        },
        {
            test: /(\.jpg|\.jpeg|\.png|\.gif)$/,
            loader: 'null-loader'
        },
        {
            test: /(\.css|\.less|\.scss)$/,
            loader: 'null-loader'
        },
        {
            test: /\.html$/,
            loader: 'ngtemplate?relativeTo=' + __dirname + '&prefix=/website/js!html'
        }
];

// config.plugins = config.plugins.concat([
//     // keeps hashes consistent between compilations
//     new webpack.optimize.OccurenceOrderPlugin(),

// ]);

config.output = {
    filename: 'test.build.js',
    path: 'test/',
    publicPath: 'http://0.0.0.0:3000/test',
};

config.devServer = {
    host: '0.0.0.0',
    port: 3000,
    hot: true,
    inline: true,
    historyApiFallback: true,
    watchOptions: {
        aggregateTimeout: 300,
        poll: 1000
    }
};

config.target = 'web';

module.exports = config;

test_index.js

// Add all tests to context so they are put in bundle
const context = require.context('.', true, /.+[st]\.spec\.tsx?$/);
context.keys().forEach(context);

// Add all partials to context so they are put in bundle
var templates = require.context('../partials', true, /\.html$/);
templates.keys().forEach(function(key) {  
  templates(key);
});

module.exports = context;

test.html

<!DOCTYPE html>
<html>
    <head>
        <title>Mocha</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="stylesheet" href="./node_modules/mocha/mocha.css" />

        <script src="/node_modules/react/dist/react-with-addons.js"></script>
        <script src="/node_modules/react-dom/dist/react-dom.js"></script>

        <script src="/test/test.build.js"></script>
    </head>
    <body>
    </body>
</html>
Community
  • 1
  • 1
Robin Elvin
  • 1,207
  • 12
  • 28

0 Answers0