I'm trying to create a custom transform for Jest, but running into a documentation roadblock which has me asking myself if I'm even on the right track.
Problem
I have a Rails project which is serving a Vue JS app. I want to write Jest tests for the JS app. In order to pass config variables from Rails to the app, I'm using ERB to template a small number of .js
files. For example:
// in server-routes.js.erb
export default {
reports: '<%= Rails.application.config.relative_url_root %><%= Rails.application.routes.url_helpers.reports_path %>',
...
In my Webpack build for the Vue app, I use rails-erb-loader
to preprocess the *.erb
files before they get passed to the rest of the build process.
However, when I run my JS tests, Jest doesn't know anything about ERB loaders (reasonably enough). So my goal is to add a custom transform for Jest to convert the ERB files when running npm test
.
Approach
I thought I might be able to use rails-erb-loader
as a Jest transform:
// package.json
"jest": {
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"moduleDirectories": [
"<rootDir>/node_modules"
],
"transform": {
".*\\.(vue)$": "vue-jest",
"^.+\\.js$": "babel-jest",
"^.+\\.js\\.erb$": "rails-erb-loader"
},
This doesn't work, however, because Jest transforms and Webpack loaders seemingly have different signatures. In particular, Jest expects a process
function:
$ npm test
FAIL app/javascript/ponents/__tests__/dummy.test.js
● Test suite failed to run
TypeError: Jest: a transform must export a `process` function.
> 101 | import ServerRoutes from '../server-routes.js.erb';
| ^
at ScriptTransformer._getTransformer (node_modules/@jest/transform/build/ScriptTransformer.js:291:15)
at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:353:28)
at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:457:40)
at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:513:25)
at app/javascript/ponents/related-media.vue:101:1
at Object.<anonymous> (app/javascript/ponents/related-media.vue:232:3)
And this is where I get stuck, because I can't see where it's documented what the API and behaviour of a process
function should be. In the documentation for the transform
config option there's a single not very helpful example, and that's it as far as docs go, unless I've missed something.
I also note that babel-jest
has a createTransformer
function which sounds like it might be helpful, or at least illuminating, but again I can't find any docs on what it does.
If anyone has pointers on the details of creating custom Jest transforms, or at least some better docs, that would be great! Or, if I'm going about this the wrong way, what should I be doing?
I'm trying to create a custom transform for Jest, but running into a documentation roadblock which has me asking myself if I'm even on the right track.
Problem
I have a Rails project which is serving a Vue JS app. I want to write Jest tests for the JS app. In order to pass config variables from Rails to the app, I'm using ERB to template a small number of .js
files. For example:
// in server-routes.js.erb
export default {
reports: '<%= Rails.application.config.relative_url_root %><%= Rails.application.routes.url_helpers.reports_path %>',
...
In my Webpack build for the Vue app, I use rails-erb-loader
to preprocess the *.erb
files before they get passed to the rest of the build process.
However, when I run my JS tests, Jest doesn't know anything about ERB loaders (reasonably enough). So my goal is to add a custom transform for Jest to convert the ERB files when running npm test
.
Approach
I thought I might be able to use rails-erb-loader
as a Jest transform:
// package.json
"jest": {
"moduleFileExtensions": [
"js",
"json",
"vue"
],
"moduleDirectories": [
"<rootDir>/node_modules"
],
"transform": {
".*\\.(vue)$": "vue-jest",
"^.+\\.js$": "babel-jest",
"^.+\\.js\\.erb$": "rails-erb-loader"
},
This doesn't work, however, because Jest transforms and Webpack loaders seemingly have different signatures. In particular, Jest expects a process
function:
$ npm test
FAIL app/javascript/ponents/__tests__/dummy.test.js
● Test suite failed to run
TypeError: Jest: a transform must export a `process` function.
> 101 | import ServerRoutes from '../server-routes.js.erb';
| ^
at ScriptTransformer._getTransformer (node_modules/@jest/transform/build/ScriptTransformer.js:291:15)
at ScriptTransformer.transformSource (node_modules/@jest/transform/build/ScriptTransformer.js:353:28)
at ScriptTransformer._transformAndBuildScript (node_modules/@jest/transform/build/ScriptTransformer.js:457:40)
at ScriptTransformer.transform (node_modules/@jest/transform/build/ScriptTransformer.js:513:25)
at app/javascript/ponents/related-media.vue:101:1
at Object.<anonymous> (app/javascript/ponents/related-media.vue:232:3)
And this is where I get stuck, because I can't see where it's documented what the API and behaviour of a process
function should be. In the documentation for the transform
config option there's a single not very helpful example, and that's it as far as docs go, unless I've missed something.
I also note that babel-jest
has a createTransformer
function which sounds like it might be helpful, or at least illuminating, but again I can't find any docs on what it does.
If anyone has pointers on the details of creating custom Jest transforms, or at least some better docs, that would be great! Or, if I'm going about this the wrong way, what should I be doing?
Share Improve this question asked Apr 26, 2019 at 14:03 Ian DickinsonIan Dickinson 13.3k12 gold badges45 silver badges70 bronze badges 2- 1 have you found a solution? – Deepak Jha Commented Dec 24, 2019 at 8:20
- did you find a solution? someone did this: github./cpcwood/jest-erb-transformer – Gotey Commented Feb 4, 2021 at 16:37
2 Answers
Reset to default 2You could look at ts-jest. https://github./kulshekhar/ts-jest/blob/master/src/ts-jest-transformer.ts. It is in typescript so is typed
Alternatively find the jest code that initiates the transform process. I don't think it is that difficult to find.
I think the transformer is either created with class constructor or via the factory function createTransformer.
From my understanding for the ts-jest-transformer and jest-erb-transformer it seems you need to export an object with public process
or to export createTransformer
methods which create a transformer object that have a process
method.
a simple code example that runs before ts-jest
transform-example.js
const tsJest = require('ts-jest');
const t = tsJest.createTransformer();
module.exports = {
process(fileContent, filePath, jestConfig) {
const res = t.process(fileContent, filePath, jestConfig)
console.log(filePath);
return res;
}
}
jest.config.js
module.exports = {
transform: {
'^.+\\.tsx?$': ['<rootDir>/transform-example']
}
}
running this would run typescript tests (just like ts-jest) and log all the file paths transformed in the test.