Ts-node: `jsdom-global` compatibility

Created on 2 Feb 2016  路  8Comments  路  Source: TypeStrong/ts-node

Thanks for writing ts-node for TypeScript register!

Hi, I'm writing browser mock test in jsdom.
The source code relies heavily on DOM and BOM, so I opted jsdom-global for better import behavior.

Both my source code and test code are written in TypeScript. And I use ts-node for ts extension register.

However, it seems jsdom-global breaks ts-node (or vice-versa). Something wrong with sourcemap.

Minimal setup:

npm install mocha ts-node jsdom jsdom-global
tsd install mocha node

Test code:

/// <reference path='../typings/tsd.d.ts' />

import * as assert from 'assert'
// import jsdom from 'jsdom-global'
var jsdom = require('jsdom-global')
jsdom()

describe('test sourcemap', () => {
    it('should report sourcemap', () => {
        assert(false)
    })
})
> mocha --compilers ts:ts-node/register
/tmp/node_modules/source-map-support/source-map-support.js:407
      var hasStack = (arguments[1] && arguments[1].stack);
TypeError: Invalid URL
npm ERR! Test failed.  See above for more details.

And when I changed the compiler to babel (and test file extension to js). Error is reported as expected.

> mocha --compilers js:babel-register



  test sourcemap
    1) should report sourcemap


  0 passing (46ms)
  1 failing

  1) test sourcemap should report sourcemap:

      AssertionError: false == true
      + expected - actual

      -false
      +true

      at Context.<anonymous> (index.js:10:3)
external

Most helpful comment

I identified the underlying issue here. When using jsdom-global with source-map-support, source-map-support believes that it is running in the browser because XMLHttpRequest exists globally.

Passing in an environment option to install() to force the "node" environment when registering with source-map-support fixes this issue.

  // Install source map support and read from cache.
  sourceMapSupport.install({
    environment: "node",
    retrieveFile (fileName) {
      if (project.files[fileName]) {
        return getOutput(fileName)
      }
    }
  })

ts-node can either fix this or you can work around it by registering source-map-support yourself first and setting the right environment.

require('source-map-support').install({
    environment: "node"
});

All 8 comments

I think both js-dom and source-map-support, on which ts-node depends, snatched error handling to handle uncaught exception. JS-dom mocks browser environment so it naturally needs this hack. But I wonder why source-map-support requires this? And it just rudely exits the process :cold_sweat:

I'd create an issue on https://github.com/evanw/node-source-map-support and see if there's a way to resolve this.

never mind

@HerringtonDarkholme Did you manage to resolve this?

@blakeembrey I have to write up my own register script. However, it seems to work fine with mocha. ts-node still helps a lot for reference implementation. Thank ts-node!

This is closed but I was having the same issue with jsdom-global so I just wanted to add a possible solution in case anybody else comes across this, as I was bashing my head against my desk for hours before I found a solution.

I essentially could not run any mocha tests w/ ts-dom & jsdom-global (in this case I was trying to use Teaspoon, which required me to setup a window/document with jsdom). When tests would pass all would be fine, but if any test failed I would get the same error as above:

/node_modules/ts-node/node_modules/source-map-support/source-map-support.js:407
var hasStack = (arguments[1] && arguments[1].stack);
TypeError: Invalid URL

I had to scrap using jsdom-global completely, however, I was able to get away with just using jsdom, and adding the following into my own test_helper file:

import * as jsdom from 'jsdom';

const doc = jsdom.jsdom('<!doctype html><html><body></body></html>');
const win = doc.defaultView;

global['document'] = doc;
global['window'] = win;
global['navigator'] = {userAgent: 'node.js'};
global['HTMLElement'] = global['window'].HTMLElement;

Then running:

mocha --require ./src/test/helpers/test_helper.ts './src/test/**/*.ts' --compilers ts:ts-node/register

Worked as expected.

I identified the underlying issue here. When using jsdom-global with source-map-support, source-map-support believes that it is running in the browser because XMLHttpRequest exists globally.

Passing in an environment option to install() to force the "node" environment when registering with source-map-support fixes this issue.

  // Install source map support and read from cache.
  sourceMapSupport.install({
    environment: "node",
    retrieveFile (fileName) {
      if (project.files[fileName]) {
        return getOutput(fileName)
      }
    }
  })

ts-node can either fix this or you can work around it by registering source-map-support yourself first and setting the right environment.

require('source-map-support').install({
    environment: "node"
});

@nmalaguti Thanks for the catch, I [will] do that here.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

conordickinson picture conordickinson  路  4Comments

dakom picture dakom  路  3Comments

cibergarri picture cibergarri  路  3Comments

aj-r picture aj-r  路  3Comments

mattdell picture mattdell  路  4Comments