grunt-init and the Jest preprocessor

I like developing with React. I find myself using it more and more, so today I decided to create a project scaffold to automate project creation with grunt-init.

Being obsessive about testing (and conformity), I adopted Jest to test my interfaces, simply because that’s what the good folk over at Facebook use too. As such, unit testing was to be built into my project template right from the beginning. This is where I ran into a problem…

grunt-init calls on a file called template.js. The code in this file typically prompts the user for project-specific details (name, description, homepage, etc.) and writes all the information to the project’s package.json file. You can see my full template here. The following shows the project.json properties that are not configurable by the user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// ...
props.scripts = {
"test": "jest"
};
props.keywords = [];
props.dependencies = {};
props.devDependencies = {
"grunt": "~0.4.x",
"grunt-contrib-clean": "~0.6.x",
"grunt-contrib-concat": "~0.5.x",
"grunt-contrib-connect": "~0.8.x",
"grunt-contrib-copy": "~0.6.x",
"grunt-contrib-livereload": "~0.1.x",
"grunt-contrib-uglify": "~0.6.x",
"grunt-contrib-watch": "^0.6.x",
"grunt-open": "^0.2.x",
"grunt-react": "^0.9.x",
"grunt-regarde": "~0.1.x",
"grunt-usemin": "^2.4.x",
"jest-cli": "^0.1.x",
"jquery": "^2.1.x",
"matchdep": "~0.3.x",
"react": "^0.11.x",
"react-tools": "^0.11.x"
};
// ...
// Generate package.json file.
init.writePackageJSON('package.json', props);

These props primarily consist of the development dependencies I always uses when developing with React. They are written to the file by the init.writePackageJSON function. For those familiar with Jest, you know that package.json needs a little Jest-specific addition for the the script preprocessor, which looks like this:

1
2
3
4
5
6
"jest": {
"scriptPreprocessor": "<rootDir>/__tests__/preprocessor.js",
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react"
]
},

Being somewhat naive, I assumed that I could simply add the jest property to the props object like this:

1
2
3
4
5
6
props.jest = {
"scriptPreprocessor": "<rootDir>/__tests__/preprocessor.js",
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react"
]
};

This does not work. init.writePackageJSON only sets the typical package.json options. The jest property is not typical, and the official documentation is not especially helpful. Here’s the relevant part pertaining to the init.writePackageJSON function:

The callback can be used to post-process properties to add/remove/whatever.

So yes, it is possible. You just have to add/remove/whatever the jest property. After poking around the code a little bit, I figured out that this is how you do it:

1
2
3
4
5
6
7
8
9
10
// Generate package.json file.
init.writePackageJSON('package.json', props, function(pkg, props) {
pkg.jest = {
"scriptPreprocessor": "<rootDir>/__tests__/preprocessor.js",
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react"
]
};
return pkg;
});

See my ever-changing React project template here: https://github.com/RaphaelDeLaGhetto/grunt-init-gebo-react-hai.