Search code examples
javascripttypescriptnpmcommonjskarma-mocha

karma-typescript confused by .d.ts typings into failing to bind to npm package code


I'm importing an npm package into my project with a package.json like this:

{
  // ...
  "browser": "dist/umd/index.js",
  "main": "dist/cjs/index.js",
  "module": "dist/fesm2015/index.mjs",
  "esm2015": "dist/index.js",
  "fesm2015": "dist/fesm2015/index.mjs",
  "typings": "dist/index",
  "sideEffects": false,
  "exports": {
    "node": {
      "module": "./dist/fesm2015/index.mjs",
      "require": "./dist/cjs/index.js"
    },
    "browser": {
      "module": "./dist/fesm2015/index.mjs",
      "default": "./dist/umd/index.js"
    },
    "default": "./dist/cjs/index.js"
  },
  // ...
}

(I really, really wanted to have "type": "module" in the above package, but that creates a whole other world of pain trying to make karma and other tools happy.)

I can build and run my project that uses the above npm package just fine, and I can run mocha unit tests outside of karma without any problem. However, when running under karma, I get errors like this:

20 06 2021 10:58:05.127:INFO [Chrome 91.0.4472.106 (Mac OS 10.15.7)]: Connected on socket 9qHeabxqGGw_tCrRAAAB with id 99567255
Chrome 91.0.4472.106 (Mac OS 10.15.7) @tubular/util should blend colors correctly FAILED
        TypeError: math_1.round is not a function
            at colorFromRGB (src/browser-graphics-util.js:2:2895)
            at Object.blendColors (src/browser-graphics-util.js:2:1803)
            at Context.<anonymous> (src/index.spec.js:60:45)
Chrome 91.0.4472.106 (Mac OS 10.15.7): Executed 30 of 30 (1 FAILED) (0.818 secs / 0.789 secs)
TOTAL: 1 FAILED, 29 SUCCESS

It seems that my project code isn't correctly binding to the code in the imported npm package, and all tests that depend on code from that package fail.

If I perform a little manual surgery on the contents of my node_modules directory, and modify the package.json of the imported npm package by removing "typings": "dist/index", karma is once again happy, and all my tests succeed.

Why, why for deity-of-your-choice's sake, does the existence of typings make any difference to karma-typescript about the success or failure of binding to the code in the npm package?

I definitely want that package (which is a package I created in another project) to provide TypeScript typings, so permanently getting rid of typings is NOT an option. How do I tell karma or karma-typescript to either ignore these typings, or simply not get so confused by them?

Here is my current karma.conf.js:

module.exports = function (config) {
  config.set({
    frameworks: ['chai', 'karma-typescript', 'mocha'],
    files: [
      'src/**/*.ts'
    ],
    preprocessors: {
      'src/**/*.ts': 'karma-typescript'
    },
    reporters: ['progress', 'karma-typescript'],
    browsers: ['Chrome'],
    karmaTypescriptConfig: {
      tsconfig: './tsconfig.karma.json'
    },
  });
};

And tsconfig.karma.json, which simply exists to make karma build CommonJS modules instead of ESM modules:

{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "module": "commonjs",
    "target": "ES2015"
  },
  "exclude": [
    "dist",
    "node_modules"
  ]
}

UPDATE:

Another bit of information on this problem. If I use an explicit import like this:

import { max, min, round } from '../node_modules/@tubular/math/dist/cjs';

...instead of:

import { max, min, round } from '@tubular/math';

...the problem goes away, which confirms that this is a module resolution problem.

So what is it about module resolution that's changed while running in karma with karma-typescript? Are there settings I can use to tweak module resolution?


Solution

  • I figured it out.

    karma-typescript is dependent on browser-resolve, and my imported package.json had a "browser" entry, but meant for a somewhat different purpose, and clearly not at all compatible with how karma-typescript uses browser-resolve.

    As long as I take out my "browser" field, the "typings" field can stay, and no longer causes my tests to fail.