Re-run Jest when jest.config changes - jestjs

I am working with a jests.config.js file:
// jest.config.js
module.exports = {
verbose: true,
setupFiles: ["./helpers/setup/environment.js"],
testMatch: ["**/__tests__/v2/tests.cloud.js"],
globals: {
_: true,
},
watchPathIgnorePatterns: ["./src/dataset", "./logs"],
};
I run Jest with watch:
jest --watch
In order to develop each test on its own I change the test file on testMatch every time I move on to the next test I am writing. Is there a way for the watch to reload the Jest config itself when the configuration file changes?

There are plenty other options
CLI [TestPathPattern]
if you run jest --help you'll see you can pass TestPathPattern to match test files
$ jest --help
Usage: jest.js [--config=<pathToConfigFile>] [TestPathPattern]
--onlyChanged, -o
Jest will attempt to run only tests related to the changed (in the current repository) files.
watch mode (p)
While in --watch mode you can press P and enter regex to select which file to run

Ended up writing a short NodeJS script:
const fs = require("fs");
const { spawn } = require("child_process");
const filename = "../jest.config.js";
let jest;
const run = () => {
if (jest) {
jest.kill();
}
jest = spawn("jest", ["--watch"], { stdio: "inherit" });
};
run();
fs.watch(filename, run);
process.on("SIGINT", function() {
console.log("Caught interrupt signal");
process.exit();
});

Related

Is it possible to collect coverage on code loaded with vm.runInContext with Jest?

I'm working on a legacy JS project which is not using any require/import. When deploying, the files are just concatenated and the result is sent to a server.
In order to write tests with jest, I created a custom environment to load all the JS files in the global context so that I can call the functions in the test file.
For example:
src/index.js
function sum(x, y) {
return x + y;
}
src/index.spec.js
it('should sum two numbers', () => {
expect(sum(1, 2)).toBe(3);
});
jest.config.js
module.exports = {
clearMocks: true,
collectCoverage: true,
collectCoverageFrom: [
"src/**/*.js",
],
coverageDirectory: "coverage",
coverageProvider: "v8",
testEnvironment: "./jest.env.js",
};
jest.env.js
const NodeEnvironment = require('jest-environment-node').TestEnvironment;
const fs = require('fs');
const vm = require("vm");
const path = require("path");
class CustomEnv extends NodeEnvironment {
constructor(config, context) {
super(config, context);
this.loadContext();
}
loadContext() {
const js = fs.readFileSync('./src/index.js', 'utf8');
const context = vm.createContext(this.global);
vm.runInContext(js, context, {
filename: path.resolve('./src/index.js'),
displayErrors: true,
});
Object.assign(this.global, context);
}
}
module.exports = CustomEnv;
When I run npx jest, the test is executed but the coverage is empty...
Any idea on how to fix the coverage?
I've created a minimal reproducible repo here: https://github.com/GP4cK/jest-coverage-run-in-context/tree/main. You can just clone it, run npm i and npm t.
Note: I'm happy to change v8 to babel or load the context differently if it makes it easier.

Webpack handlebars-loader temaplate file does not resolve in mocha unit test

I am using handlebars-loader to use handlebar templates with webpack.
I have the following code structure. I am able to build code using webpack but when I run mocha unit tests the handlebar template fails to resolve.
webpack.config.js
const path = require('path');
module.exports = (env) => {
// Rest of webpack.config.js
module: {
rules: [
{ test: /\.handlebars$/, loader: "handlebars-loader" }
]
};
};
index.ts
import EmailTemplate from './templates/email.handlebars';
export const handler = async (event, _context) => {
let emailResponse = EmailTemplate({ code: '123' });
return emailResponse;
};
Error when running unit tests
Cannot find module './templates/email.handlebars' or its corresponding type declarations.
import EmailTemplate from './templates/email.handlebars';
I was able to run unit test after requiring handlebars-loader while running unit test command.
Also converted import to require while using handlebars templates in code.
index.ts
const EmailTemplate = require('./templates/email.handlebars');
export const handler = async (event, _context) => {
let emailResponse = EmailTemplate({ code: '123' });
return emailResponse;
};
And while running mocha test added --require handlebars-loader
node_modules/.bin/_mocha --require ts-node/register --require handlebars-loader functionName/test/**/*.spec.ts

gulp build with browser sync and react not reloading page

I have a gulpfile with the following build task:
var gulp = require('gulp'),
source = require('vinyl-source-stream'),
buffer = require('vinyl-buffer'),
babelify = require('babelify'),
browserify = require('browserify'),
uglify = require('gulp-uglify'),
sourcemaps = require('gulp-sourcemaps'),
bs = require('browser-sync').create('BrowserSync');
gulp.task('build', function () {
return browserify({entries: './src/app.js', debug: true})
.transform("babelify", { presets: ['es2015','react'] })
.bundle()
.pipe(source('app.js'))
.pipe(buffer())
.pipe(sourcemaps.init())
.pipe(uglify())
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('./dist/js'))
.pipe(bs.reload({stream: true}));
});
The process builds my files perfectly, however my browser does not load. Why doesn't my browser reload? And how do I achieve the desired behavior? I feel like I am missing something about BrowserSync.
NOTE: I am fairly confident BrowserSync is working properly as I call bs.reload() in another task, and the page reloads perfectly. Happy to paste in more code however if needed.
Here is a snippet from a starter project that I started a while back that does what you are mentioning...
/*...*/
gulp.task('watchify', () => {
let args = merge(watchify.args, { debug: true })
let bundler = watchify(browserify('./src/js/app.js', args)).transform(babelify, { presets: ["es2015", "react"] })
bundle(bundler)
bundler.on('update', () => {
bundle(bundler)
})
})
function bundle(bundler) {
return bundler.bundle()
.on('error', map_error)
.pipe(source('app.js'))
.pipe(buffer())
.pipe(rename('app.min.js'))
.pipe(sourcemaps.init({ loadMaps: true }))
// capture sourcemaps from transforms
.pipe(uglify())
.pipe(sourcemaps.write('./maps'))
.pipe(gulp.dest('./dist/js'))
.pipe(sync.reload({
stream: true
}))
}
/*...*/
// watching multiple files with a task 'watch'
gulp.task('default', () => {
gulp.watch('src/js/**/*.js', ['watchify']);
});
The gulp task that started browsersync was run by gulp as it was triggered in the default task.
Then I ran gulp build manually from the terminal, and here was the issue. This manual command thus did not have access to the instance of browsersync that was created by the default gulp process.
So having gulp build run automatically with the instantiated version available did the trick.

Remote debug node in docker container - sourcemaps in WebStorm

I have problems debugging contenerized application using WebStorm (or IntelliJ) remote debugging option which works perfect when trying to remote debug application running locally.
Here are the relevant parts of my gulp config file:
gulp.task("mainCompile", () =>
gulp.src(`${config.src.main.baseDir}/**/*.js`, {base: "./src"})
.pipe(plugins.sourcemaps.init())
.pipe(plugins.babel())
.pipe(plugins.sourcemaps.write(".", {
includeContent: false,
sourceRoot: "../src"
}))
.pipe(gulp.dest(config.build.baseDir))
);
gulp.task("nodemon", ["copyResources", "compile"], () =>
plugins.nodemon({
execMap: {
js: "node --debug-brk"
},
script: path.join(config.build.mainDir, "index.js"),
ext: "js yaml",
delay: 2500,
debug: true,
verbose: true,
watch: config.src.main.baseDir,
tasks: ["copyNonJs", "yamlToJson", "compile"]
})
);
And the part of compose config. As you can see I mount the project root at /app in the container.
server:
image: justmarried/jmserver:development-latest
build:
context: .
dockerfile: containers/develop/Dockerfile
ports:
- 2701:2701
- 5858:5858
volumes:
- ./:/app
Remote debugger attaches but stops only for breakpoints defined in index.js (or if I put a breakpoint inside "build" dir which is not what I want). When the app is fully loaded I get this:
As you can see index.js gets mapped perfectly but none of the other files do. Tried to inline code into sourcemaps but it didn't help. Is it a bug in WebStorm (newest, 2017.1.3)?
One more observation. When I do "show actual source" of any files in build dir in scripts tab in debug tab I get sth. like this:
(function (exports, require, module, __filename, __dirname) { "use strict";
var _httpStatus = require("http-status");
var _httpStatus2 = _interopRequireDefault(_httpStatus);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
module.exports = {
get: function get(req, res) {
res.status(_httpStatus2.default.OK).json({
text: "Hi there!"
});
}
};
//# sourceMappingURL=ping.js.map
});
But when I do "show source" I get
"use strict";
var _httpStatus = require("http-status");
var _httpStatus2 = _interopRequireDefault(_httpStatus);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
module.exports = {
get: function get(req, res) {
res.status(_httpStatus2.default.OK).json({
text: "Hi there!"
});
}
};
//# sourceMappingURL=ping.js.map
Of course the actual source of that file resides in the src/main dir not build/main dir and is:
import HttpStatus from "http-status";
module.exports = {
get(req, res) {
res.status(HttpStatus.OK).json({
text: "Hi there!"
});
}
};
The contents of that ping.js.map is:
{"version":3,"sources":["main/handlers/ping.js"],"names":["module","exports","get","req","res","status","OK","json","text"],"mappings":";;AAAA;;;;;;AAEAA,OAAOC,OAAP,GAAiB;AACfC,KADe,eACXC,GADW,EACNC,GADM,EACD;AACZA,QAAIC,MAAJ,CAAW,qBAAWC,EAAtB,EAA0BC,IAA1B,CAA+B;AAC7BC,YAAM;AADuB,KAA/B;AAGD;AALc,CAAjB","file":"ping.js","sourceRoot":"../../../src"}

Gulp doesn't notice my file changes

I'm working on a project with a few others. While they get Gulp to work, it doesn't seem to work on my computer, even through our code is identical.
When I write the 'gulp' command, I get this:
[10:51:17] Starting 'browserify'...
[10:51:19] Finished 'browserify' after 2.37 s
[10:51:19] Starting 'default'...
[10:51:19] Finished 'default' after 17 μs
But when I save the changes in the files Gulp is suppose to be watching, the 'update' event doesnt seem to be triggered.
Here is the Gulp file
var gulp = require("gulp"),
jest = require("gulp-jest"),
source = require('vinyl-source-stream'),
browserify = require('browserify'),
watchify = require('watchify'),
reactify = require('reactify');
require("harmonize")();
var paths = {
scripts: "src/**/*.js",
tests: "__tests__"
};
gulp.task("jest", function () {
return gulp.src(paths.tests).pipe(jest({
scriptPreprocessor: "preprocessor.js",
unmockedModulePathPatterns: [
"../node_modules/react"
],
testPathIgnorePatterns: [
"node_modules",
"spec/support"
],
moduleFileExtensions: [
"js",
"json",
"react"
]
}));
});
gulp.task('browserify', function() {
var bundler = browserify({
entries: ['./src/js/TopLevel.js'],
transform: [reactify],
debug: true,
cache: {}, packageCache: {}, fullPaths: true
});
var watcher = watchify(bundler);
return watcher
.on('update', function () { // When any files update
var updateStart = Date.now();
console.log('Updating!');
watcher.bundle() // Create new bundle that uses the cache for high performance
.pipe(source('main.js'))
.pipe(gulp.dest('./public/assets/js'));
console.log('Updated!', (Date.now() - updateStart) + 'ms');
})
.bundle() // Create the initial bundle when starting the task
.pipe(source('main.js'))
.pipe(gulp.dest('./public/assets/js'));
});
gulp.task("watch", function() {
gulp.watch("src/**/*.js", ["jest"]);
gulp.watch("__tests__/*.js", ["jest"]);
});
gulp.task("default", ["browserify"]);
However, I don't think there is anything wrong with the code, as it works for my other team members.
Any help and comments are highly appreciated!
Try this:
gulp.task("watch", function() {
gulp.watch("./src/**/*.js", ["jest"]);
gulp.watch("./__tests__/*.js", ["jest"]);
});
If you are only running gulp in the command line the watch task will not trigger since the default task is only running browserify, just change your default task to this.
gulp.task("default", ["browserify", "watch"]);

Resources