Search code examples
javascripttypescriptjestjsglobts-jest

Using jest with files with glob imports


I utilize webpack with webpack-import-glob-loader to import files using glob pattern. So in one of my files (src/store/resources/module.ts) I have a line:

import '../../modules/resources/providers/**/*.resource.ts';

When I run a test with ts-jest it fails and reports the following message:

Cannot find module '../../modules/resources/providers/**/*.resource.ts' from 'src/store/resources/module.ts`

I assume it complains because it can't recognize this import syntax.

How to make jest work for project with glob imports?


Solution

  • I solved this by manually handling the globs inside of a jest preprocessor. Since you need to control processing of the files to handle globs in this approach, you have to manually initialize your processor.

    // config.js
    module.exports = {
      transform: {
        '.': `./path/to/your/processor.js`
    
    // processor.js
    const path = require(`path`);
    const glob = require(`glob`).sync;
    const yourProcessor = // require your processor code - ts-jest, babel-jest, esbuild-jest, etc
    
    module.exports = {
      process(src, filename, config, opts) {
        const dir = path.dirname(filename);
        src = processGlob(src, dir);
        return yourProcessor(src, filename, config, opts);
      },
    };
    
    function processGlob(src, dir) {
      // This will match things like
      //   import './**/*';
      //   import '../../modules/resources/providers/**/*.resource.ts';
      // Takes inspiration from https://github.com/excid3/esbuild-rails/blob/main/src/index.js
      return src.replace(/^import\s'(.*\*.*)';$/m, (_match, pathCapture) => {
        const matcher = /.+\..+/; // Handles '.' results
        const files = glob(pathCapture, {
          cwd: dir,
        })
          .sort()
          .filter((path) => matcher.test(path));
    
        return `${files.map((module, index) => `import * as module${index} from '${module}'`).join(`;`)}`;
      });
    }
    

    In this approach you can only glob once per file (because it uses the .map indexes to add numbers to each import module name). You could keep track of a global count variable instead, if you wanted to have several glob imports in one file.