angularjs - angular + mocha + typescript + webpack testning


Jag har ett stort Angular-projekt skrivet i Typescript som omvandlas till ett paket av Webpack. När jag använder Karma har jag fått ett problem med att sidan laddas om som jag inte kan lösa. Därför har jag bytt till att prova Mocha men jag kan inte få detta att fungera korrekt. Jag har följt det accepterade svaret på denna fråga för att komma så här långt.

Första problemet

Kanske kan någon berätta för mig vad jag gör fel eller visa mig rätt sätt att ställa in detta.

Jag kör webpack-dev-servern för testning på detta sätt:

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

Detta ger mig en webbsida där jag kan se testkörningens utdata. Om jag ändrar någon av mina Typescript-filer byggs paketet om och hot module reload startar, men då får jag ett fel på webbsidan:

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)

Om jag uppdaterar sidan körs testerna igen.

Andra problemet

Mitt direktivtest som brukade fungera bryts nu eftersom scope-objektet inte är detsamma som tidigare. Scope som jag skickar in i $compile-funktionen har inte direktivets funktioner på sig. Dessa finns nu på scope.$$childTail. Jag vet inte om detta är en bieffekt av att byta till Mocha eller något jag har gjort fel.

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>