Jest is a widely used JavaScript testing framework. It can be used “zero-config” with sensible defaults, but you can tweak it with numerous configuration options. It turns out you can also tweak it to mess with your own head.

Angry jester

I recently wasted a morning trying to work out why my Jest tests were running just fine locally, but weren’t even being found when run in AWS CodeBuild:

> jest

No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
No files found in /codebuild/output/src323229886/src/backend.

After throwing in a heap of debugging, and even toying with CodeBuild breakpoints, I inevitably reached my facepalm moment. And boy did I feel silly…

Ignorance is a choice

Take a look at this seemingly innocuous config snippet:

const config: Config = {
  modulePathIgnorePatterns: ['build/'],
  ...
};

For various reasons I can no longer fully recall (which is a lesson in itself), I have historically chosen to ignore the build directory in TypeScript projects to hide it from Jest’s module loading. I’d never given it much thought until now; it’s just one of those boilerplate snippets I find myself carelessly repeating whenever I add Jest to a project.

Computer says no

My carelessness went unnoticed until I put together an AWS CodePipeline to run tests in CodeBuild before deployment, and to my surprise, the job failed.

Hmm. Cue much head scratching and aforementioned debugging. I eventually went back to check the Jest configuration docs, which state that care is needed when defining ignore patterns, else you might end up accidentally ignoring all your tests when run in a Continuous Integration build environment. Well now, that sounds familiar…

Let’s look again at the error message:

> jest

No tests found, exiting with code 1
Run with `--passWithNoTests` to exit with code 0
No files found in /codebuild/output/src323229886/src/backend.

As you can see, CodeBuild puts everything under a directory named “codebuild”, which includes the word “build” …. which I am explicitly instructing Jest to ignore.

Homer disappears into a hedge

Rooting for the bad guy

Because path patterns in Jest config match anywhere in the absolute path to a resource, not just within the project directory, the recommendation is to use the <rootDir> token to match strictly within your project:

const config: Config = {
  modulePathIgnorePatterns: ['<rootDir>/build/'],
};

Et voilà: the tests are found, and the job passes ✅

Every day is a school day

Even salty old coding dogs need an occasional reminder: RTFM!

In fact, when using ts-jest transformer as I normally do, I have no need to ignore the build directory in my Jest config, as I can rely on includes / excludes in my test tsconfig.json. Therefore I will be removing that line from my personal TypeScript / Jest boilerplate from now on.

But the use of <rootDir> is encouraged for most of Jest’s path pattern config properties, including coveragePathIgnorePatterns, moduleNameMapper, watchPathIgnorePatterns and more, so this is a valuable lesson learned. Ignore at your peril!