Jest: Support for RequireJS

Created on 15 May 2014  ·  84Comments  ·  Source: facebook/jest

If I understand it correctly, there is currently no way of using this with RequireJS rather than CommonJS style require(). Are there any plans of adding support for RequireJS? Is it even feasible?

Most helpful comment

babel-plugin-transform-amd-to-commonjs can prove useful for solving the problem of Jest+AMD, particularly if you're already using something like babel-jest.

I've set up an example project which shows how you can have Jest transparently require AMD files by running the transform in the test environment.

I'm unsure of the details of such an approach in an actual project - in particular a good approach for config-sharing between Jest/RequireJS/Webpack/etc. Jest support for .js configurations file would be a step towards a more reusable solution (see https://github.com/facebook/jest/issues/2140).

All 84 comments

++

It's on our roadmap to support module system add-ons for Jest (like require.js, es6 modules, etc), but unfortunately we're not quite there yet.

Let's leave this issue open to track progress on this, though -- I think it would be pretty useful to support require.js loaders

@jeffmo webpack supports commonjs/es6/amd. If we could bring jest in as a plugin we could probably get all that stuff for free.

++

we have many projects at a big organization and planing to use jest but we are 100% requirejs. Any eta on requirejs integration?

++

I would also like to try out jest, but current project I'm on is using RequireJS.

:+1:

Someone suggested using this as a shim, has anyone tried it?

https://github.com/Jakobo/redefine

_Feasible with caveats_. I implemented a little build with nodefy in some random repo that could do the trick as a stop-gap. See scripts.cjs under packages.

Litmus test: Your AMD module aliases align with the corresponding module under node_modules. If the litmus test fails, but you're desperate, you could nodefy pure AMD modules and/or add symlinks to node_modules, but the idea makes me sad. From my perspective, the externals that I use tend to implement UMD and install by npm to names aligned with my AMD aliases--no big deal.

(I checked out uRequire before nodefy, but the CommonJS template renders it functionally equivalent to nodefy--I'll take the targeted tool. I also checked out amdefine, but jest uses regex matching on 'require'--maybe there's an anonymous AMD angle? There's always UMD, but coding UMD with scattered document references sounds like bad manners.)

+1

++

We are using react, backbone, and requirejs in all of our new client side code. I would love to be able to use jest and ease some of the pain of testing react. It would be nice to get things down to the unit level. Currently our tests for the react code are being done with rspec and a webdriver. While this works it is less than ideal for obvious reasons.

Is there any practical workaround yet? The main issue I am running into is the define statements that wrap the react components.

+1

@petehunt Turned me on to Webpack, so this is something to consider as well.

+1

Can someone point me to an example of jasmine/webpack or jest/webpack running browser tests with code coverage?

++

When can we expect support for requirejs ?

+1

+1

+1

+1

+1

+1

If you use module.exports instead of return for your define call you can add this to your preprocessor.

Works for me :thumbsup:

// preprocessor.js
var ReactTools = require('react-tools');
module.exports = {
  process: function(src) {
    if (/define\(.*?\{/.test(src)) {
      //Remove AMD ceremony for use without require.js or almond.js
      src = src.replace(/define\(.*?\{/, '')
        .replace(/(}\);|}\))$/,'');
    }

    return ReactTools.transform(src);
  }
};

++

+1

+1

+1 for RequireJS support

+1

@charliedowler Would you mind illustrating a little more this approach. I'm giving it a try and running into a couple of issues. I started by adding

if (typeof(module) == 'object' && module.exports) { module.exports = <my_element>;  }

Yet, I'm using return, so I'm getting a parser error from the pre-processor. I thought I could get away by extending the RegEx to also match the last return. But it doesn't seem to be working at all. I keep getting the "illegal return statement" error. Probably something wrong with the expression, and it's not catching it.

if (/define\(.*?\{/.test(src)) {
  src = src.replace(/(define\(.*?\{|return.*[\s]}\);?$)/g,'');  
}

Is there a way for me to write src to stdout? A simple console.log is not working.

And lastly, assuming I get all this to work. How are you handling dependencies? Like for instance React?

+1

Ah! I had been playing with (and very much enjoying jest). Tried to pull it into an actual project today and found out no requireJS support :sob: ... deal breaker for all current "real" projects. Sad indeed. It was surely an exciting idea!

:+1:

+1

+1

:+1:

:thumbsup:

:+1:

:+1:

So I have solved this by using webpack to compile my AMD modules and tests together. This allowed me to also use all kinds of additional loaders with my tests. https://github.com/ninjapanzer/Backbone-Flux-React-Webpack

:+1:

+1

+1

+1

Thank you for reporting this issue and appreciate your patience. We've notified the core team for an update on this issue. We're looking for a response within the next 30 days or the issue may be closed.

+1

@facebook-github-bot-4 please do it!

+1

+1

++

I've been working on Jestpack which is a replacement for Jest's 'HasteModuleLoader' to support Webpack. As a result it means you can use any module system Webpack supports including AMD.

On a side note does anybody know of any large(ish) open source projects using Jest other than those using FB style haste modules as it would be really useful for testing the performance of Jestpack?

I also have been working on jest-requirejs which is more of an attempt at a standard jest preprocessor which analyzes the project main.js config file then performs a deamdify, which removes the define wrapper, rewrites the require paths based on the details of the main.js' specified baseUrl and paths, and then passes the transformed file to jest as usual.

Still working on plugin/loader syntax, and rewriting jest.dontMock(""), jest.setMock("") and require.requireActual("") paths inside the test environment.

Hey guys this is really awesome. I like the idea of Jestpack and I've been meaning to make it much easier to support additional module resolvers. Finally I also want to revamp the website and recommend solutions like Jestpack as part of the Getting Started guide (that I have in my head :) ). @richardscarrott and @sterpe please let me know if you need anything.

Also cc @mwolson and @ColCh

(To everyone else: please stop upvoting comments, it is not helpful. If you want something built for jest, please send a pull request. Code wins arguments! Personally I can't prioritize features only because people in the community need them and I don't use _all the module loaders_ that are out there myself.).

Jestpack is interesting, though I'm not a fan of having to create one entry point per test. https://github.com/Ticketmaster/jest-webpack-alias solves the problem a bit more generically, at the cost of some preprocessing, and possible yet-undiscovered bugs due to reimplementing webpack's module resolution code.

Also: Getting Started guides should probably mention that it's a good idea to limit which files your preprocessor runs on, if you have one, otherwise it slows down test runs considerably.

preprocessors are only run once and you can provide a cache key function. jest won't re-run your preprocessor if a file hasn't changed.

That may be, but even the first run was enough to add about ~10 seconds to execution of our test suite.

Agreed that that isn't fast. At FB the first run takes almost twice as long as subsequent runs but personally I don't see any other to solve this – we are using babel and other custom transforms at FB; we can't run tests without a preprocessor :)

The preprocessor caching was biting me while developing the requirejs preprocessor. I mostly still use [email protected] which did not have caching I believe?

It should work fine with 0.5!

Webpack is very fast in dev-watch mode.

Because:

  1. Webpack keeps their runtime in memory (without reloads)
  2. Compilled source code is located in memory too.

So, in my Jest preprocessor I've implemented only (2) point.

In shorten, a package (Jestpack, right...) on top of Jest and Webpack will resolve all issues with performance - just keep Jest and Webpack runtime in memory, compile files in memory FS and execute test cases in memory FS.

That's my point of view...

But we have another trouble now: It's not possible to inject memory FS into Jest for now.

I thought about using private Jest cache API - for injecting compilled source right into cache. May be it's a hack, so I was wrong here: jest-webpack/issues/4#issuecomment-98623189

Ah, I should mention, that Karma with Webpack as preprocessor is working very slow too. So, I think that main performance drop is because of webpack runtime reloads between files.

@cpojer I figured it was your intention to eventually make module loaders configurable as it was already optioned out so I thought I'd give it a stab with Jestpack. The only real problem I ran into was understanding the logic for discovering manual mocks for node_modules https://github.com/facebook/jest/issues/509, I ended up just going with a solution that made sense to me but if you're able to provide any insight on that issue it would be nice to align Jestpack's module loader with the HasteModuleLoader.

@mwolson The reason Jestpack uses a separate entry point per test file is to ensure it can still take advantage of Jest's multi processes.

moduleLoader can already be specified as part of the config, actually.

++

We would like this as well. Jest seems like an awesome piece of software but can't rewrite everything we've got to account for no RequireJS support.

+1

Is anyone from the community interested in working on this? I'd be happy to support people through this and make an official Jest plugin. It is unlikely we will heavily invest into this at FB anytime soon. The Jest team is very small (1.5 people) and we can't get to work on all these features, unfortunately.

Based on the current state of the JavaScript community and standard it doesn't seem like require js itself has a huge future for authoring JavaScript code. We now have a standardized module system in ES2015. Babel and Jest are now fully integrated and work well together. I will recommend anyone to switch to CommonJS or ES2015 modules, which will make more tooling available to you out of the box.

require JS also has a document here on how to convert CommonJS to require.js which can be used for production deploys, see: http://requirejs.org/docs/commonjs.html

Personally I see no upside in writing code using require JS. I'd also be happy to help write a codemod that can help transform require JS codebases to CommonJS. Another challenge could be to write a requireJS to CommonJS babel plugin and pluck it into Jest's preprocessor.

@cpojer I was somewhat successful with the preprocessor approach here https://github.com/sterpe/jest-requirejs/blob/master/index.js but only implemented a transform for !text/ plugins so far. Our team moved off of requirejs entirely so i haven't had a reason to continue down that path.

I agree, I see little value in using RequireJS for authoring code. It makes sense to me to compile CommonJS/ES2015 module code to requirejs for production, but it doesn't seem great to write code with this style manually.

I just did migration from RequireJS to webpack. There are more than 300 components in our codebase. The whole process was surprisingly easy and painless.

The tool I have used was https://github.com/Skookum/recast-to-cjs for converting code from AMD to CommonJS style.

Also with the help of https://github.com/facebook/jscodeshift, we migrated our code base from React 0.11 to 0.14 within a few days.

Hope this might help someone in the same situation.

@tendant nice! That is exactly what I was talking about before :) Glad it worked so well for you.

Since this is closed, does that mean that Facebook is not going to add support for this?

If by Facebook you mean me, then yes, it is unlikely there will be "official" support. That shouldn't prevent you from contributing to Jest and getting this feature in but I believe most people have moved on to ES modules or CommonJS these days.

Yeah, I know. Unfortunately, I can't move away from these dependencies because it's for work.

babel-plugin-transform-amd-to-commonjs can prove useful for solving the problem of Jest+AMD, particularly if you're already using something like babel-jest.

I've set up an example project which shows how you can have Jest transparently require AMD files by running the transform in the test environment.

I'm unsure of the details of such an approach in an actual project - in particular a good approach for config-sharing between Jest/RequireJS/Webpack/etc. Jest support for .js configurations file would be a step towards a more reusable solution (see https://github.com/facebook/jest/issues/2140).

@msrose this is awesome. Thank you so much for sharing this.

I understand this is an old issue. A simple transform could work:

exports.process = function (content) {
  return 'function define(name, deps, body) { module.exports = body.apply(undefined, deps.map(require)); }' + content;
}

I think the transform of AMD -> CJS can be done in multiple ways, e.g., deamdify, injected wrapper, etc. The problem, still unsolved, is Require-style loader/plugin syntaxes. That's the stuff like fooTemplate = require('tpl!foo.tpl') and barJson = require('json!bar.json') (as relatively common ones). But there were quite a lot of these and real world require-js projects are littered with this kind of syntax.

It would be great if there were an easy way to directly re-use the existing require-js plugins in the transform system that ultimately feeds into jest|'s module loader.

+1

ReferenceError: define is not defined

+1

FAIL srcApp.test.js
● Test suite failed to run

ReferenceError: define is not defined

You should use umd instead of amd. If that's not feasible, you should add a transform (eg the babel plugin linked above).

When it comes to the loader! syntax, we won't support that (we don't support it for Webpack either). Workaround there is to transform the imports (removing the loaders) and let Jest transform using its transform config. Related discussion: #4868

Was this page helpful?
0 / 5 - 0 ratings