10

How can I use Jest to test React components written in CoffeeScript + React jsx?

The only CoffeeScript example provided with Jest uses plain CoffeeScript, and doesn't work with CoffeeScript + React JSX (syntax error when it reaches a <).

What I have tried

first attempt: execSync

// preprocessor.js
var execSync = require('exec-sync');

module.exports = {
  process: function (src, path) {
    return execSync('browserify -t coffee-reactify ' + path);
  }
};

This works, but takes too much time (a good 12 seconds for a dummy test).

Then I tried:

second attempt: coffee-react-transform

// preprocessor.js
var coffee = require('coffee-script');
var transform = require('coffee-react-transform');

module.exports = {
  process: function(src, path) {
    if (path.match(/\.coffee$/)) {
      return coffee.compile(transform(src), {'bare': true});
    }
    return src;
  }
};

This throws a strange error, like:

TypeError: function() {...} has no method 'getPooled'

The only Google result for "has no method 'getPooled'" is this gist, that shows exactly the error I get, but offers no other insights.

third possible attempt

I think I could use coffee-reactify, but it returns a stream, which is asynchronous, while the process function in preprocess.js is used synchronously, and have found no way, so far, to read a stream synchronously.

What can I do?

giorgian
  • 3,795
  • 1
  • 30
  • 48
  • I have not used `coffee-react-transform` but from the docs it seems like it should be used without first compiling the coffeescript? e.g. `return transform(src)` instead of `return coffee.compile(transform(src), {'bare': true});`? – Nick Tomlin Nov 25 '14 at 17:37
  • `transform(src)` returns regular ("de-reactified") coffeescript, which must then be compiled into javascript. – giorgian Nov 25 '14 at 20:05
  • after some head scratching on my part I _think_ I have gotten this working locally. – Nick Tomlin Nov 26 '14 at 17:44

3 Answers3

8

I think your second approach was correct, except you did not (I'm guessing here) add react to "unmockedModulePathPatterns" in the jest property of package.json. That is typically the result of the getPooled error in my experience.

The following works for me:

package.json

  // ...
  "jest": {
    "unmockedModulePathPatterns": ["<rootDir>/node_modules/react"],
    "testFileExtensions": [
      "js",
      "coffee"
    ],
    "scriptPreprocessor": "<rootDir>/preprocessor.js"
  }

preprocessor.js

// I found it simpler to use coffee-react,
// since it does the jsx transform and coffeescript compilation 
var coffee = require('coffee-react');

module.exports = {
  process: function(src, path) {
    if (path.match(/\.coffee$/)) {
      return coffee.compile(src, {bare: true});
    }
    return src;
  }
};

This whole process is difficult troubleshoot because errors can happen anywhere during the jsx -> coffee -> js -> jest pipeline and get silently swallowed. I found it most helpful to troubleshoot this by running the transform in a separate file to make sure the jsx -> coffee and coffee -> js happened properly, and then run the jest preprocessor.

Nick Tomlin
  • 28,402
  • 11
  • 61
  • 90
  • Of course you're right! I had tried to tell Jest not to mock `node_modules/react/lib/CallbackQueue.js` (the module that defines `getPooled`), but that didn't work... – giorgian Nov 26 '14 at 20:45
  • 1
    Any idea on how to do this and also support ES6/ES2015 modules? – Tyler Collier Feb 10 '16 at 07:21
4

I have just published a boiler plate unit test for Jest that works with React & CoffeeScript.

https://github.com/Cotidia/jest-react-coffeescript

The preprocessor needs to be as follows:

var coffee = require('coffee-script');
var ReactTools = require('react-tools');

module.exports = {
  process: function(src, path) {
    // console.log('src', src);
    if (path.match(/\.coffee$/)) {

        // First we compile the coffeescript files to JSX
        compiled_to_js = coffee.compile(src, {bare: true});

        // Then we compile the JSX to React
        compiled_to_react = ReactTools.transform(compiled_to_js)

      return compiled_to_react;
    }
    return src;
  }
};
guillaumepiot
  • 381
  • 2
  • 7
1

Based on user2534631's template project, I enhanced to use coffee-react-transform to compile CJSX files.

https://github.com/redice/jest-react-coffeescript

var coffee = require('coffee-script');
var transform = require('coffee-react-transform');

module.exports = {
  process: function(src, path) {
    if (coffee.helpers.isCoffee(path)) {
      compiled_cjx = transform(src);
      compiled_to_react = coffee.compile(compiled_cjx, {bare: true});

      return compiled_to_react;
    }

    return src;
  }
};

So use CJSX syntax to write React components.

render: ->
  <label>
    <input
      type="checkbox"
      checked={this.state.isChecked}
      onChange={this.onChange} />
    {if this.state.isChecked then this.props.labelOn else this.props.labelOff}
  </label>
xmlredice
  • 49
  • 2