Search code examples
typescripttestingkarma-mochakarma-webpack

Karma, Webpack,Babel strange import behaviour


PROBLEM:

When I first import a module the exported function is undefined. On exception the module is defined.

Why is it undefined!?!?


SCENARIO:

Main File

import { UserClass } from './user';
import { query, Client } from 'faunadb';
import { FaunaClass } from '../class';

console.log('init', typeof UserClass, typeof FaunaClass, typeof query);

export function initialise (client : Client) {

  return new Promise((resolve, reject) => {
    const CLASSES : (typeof FaunaClass)[] = [
      UserClass
    ];

    let count = 0;
    const total = CLASSES.length;

    console.log('classes', CLASSES);

    CLASSES.forEach(cl =>
      client.query(query.CreateClass({ name: cl.className }))
        .then(checkDone)
        .catch(reject));

    function checkDone () {
      count += 1;

      if (total === count) {
        resolve();
      }

    }

  })
    .catch(e => {
      console.log('on catch', UserClass);
      console.log(e.message);
    });

}

as you can see there are a few console logs inside this function. The output on karma start is:

PhantomJS 2.1.1 (Windows 8 0.0.0) LOG: 'init', 'undefined', 'undefined', 'object'

PhantomJS 2.1.1 (Windows 8 0.0.0) LOG: 'classes', [undefined]

PhantomJS 2.1.1 (Windows 8 0.0.0) LOG: 'on catch', function UserClass() { ... }

PhantomJS 2.1.1 (Windows 8 0.0.0) LOG: 'undefined is not an object (evaluating 'cl.className')'

PhantomJS 2.1.1 (Windows 8 0.0.0): Executed 1 of 1 SUCCESS (0.933 secs / 0.928 secs)

UserClass.ts:

import { FaunaClass } from '../class';

export class UserClass extends FaunaClass {

  static className = 'users';

}

** CONFIGURATION FILES:**

karma.conf.js

const webpackConfig = require('./webpack.config');
const webpack = require('webpack');

module.exports = function(config) {
  config.set({
    basePath: '',
    frameworks: ['mocha', 'chai', 'sinon'],

    files: [
      'src/**/*.spec.ts'
    ],

    preprocessors: {
      '**/*.ts': ['webpack', 'sourcemap']
    },

    webpack: {
      module: webpackConfig.module,
      resolve: webpackConfig.resolve,
      devtool: 'inline-source-map'
    },

    // Webpack please don't spam the console when running in karma!
    webpackServer: { noInfo: true },

    reporters: ['progress'],
    colors: true,
    autoWatch: true,
    logLevel: config.LOG_INFO,
    browsers: ['PhantomJS'],
    singleRun: false,
    concurrency: 'Infinity'
  });
};

Webpack Config:

var path = require('path');

module.exports = {
  entry: './handler.ts',
  target: 'node',
  module: {
    loaders: [
      {
        test: /\.tsx?$/,
        loaders: ['babel-loader', 'ts-loader'],
        exclude: [/node_modules/]
      },
      { test: /\.json$/, loader: 'json-loader' },
    ]
  },
  resolve: {
    extensions: ['.ts', '.js', '.tsx', '.jsx']
  },
  output: {
    libraryTarget: 'commonjs',
    path: path.join(__dirname, '.webpack'),
    filename: 'handler.js'
  }
};

So as you can see the logging of the UserClass is undefined at the start, and when an exception is thrown within the promise, the class becomes defined.

I have a feeling that for some reason it is executing code before the UserClass has been exported, which is causing it to be undefined in that moment.

Either that or my configuration files are completely broken.


Solution

  • The reason this was happening was because a circular import loop. I simply just had to change where the code was running from. (or the order of the imports)