nrwl / nx

Smart Monorepos · Fast CI
https://nx.dev
MIT License
23.27k stars 2.32k forks source link

svgr + jest not configured #4850

Closed cyrus-za closed 3 years ago

cyrus-za commented 3 years ago

Current Behavior

@nrwl/next/plugins/with-nx allows us to use svgr to import svg's. When running unit tests on components (inside libs), however, this does not go via next.config.js so we need to manually setup jest to handle svgr for each and every library's jest.config.js

Expected Behavior

I expect some sort of jest config baked into the generator

Steps to Reproduce

  1. Setup any new libary e.g. nx g @nrwl/react:lib myLib
  2. Save some random svg in libs/my-lib/assets/my-svg.svg
  3. Open the generated my-lib.tsx file and import the svg
  4. Run nx myLib:test and see how jest falls over

Failure Logs

● Test suite failed to run

    Jest encountered an unexpected token

    This usually means that you are trying to import a file which Jest cannot parse, e.g. it's not plain JavaScript.

    By default, if Jest sees a Babel config, it will use that to transform your files, ignoring "node_modules".

    Here's what you can do:
     • If you are trying to use ECMAScript Modules, see jestjs.io/docs/en/ecmascript-modules for how to enable it.
     • To have some of your "node_modules" files transformed, you can specify a custom "transformIgnorePatterns" in your config.
     • If you need a custom transformation specify a "transform" option in your config.
     • If you simply want to mock your non-JS modules (e.g. binary assets) you can stub them out with the "moduleNameMapper" config option.

    You'll find more details and examples of these config options in the docs:
    jestjs.io/docs/en/configuration.html

Environment

Node : 14.14.0
  OS   : darwin x64
  pnpm : 5.14.3

  nx : Not Found
  @nrwl/angular : Not Found
  @nrwl/cli : 11.3.0
  @nrwl/cypress : 11.3.0
  @nrwl/devkit : 11.3.0
  @nrwl/eslint-plugin-nx : 11.3.0
  @nrwl/express : Not Found
  @nrwl/jest : 11.3.0
  @nrwl/linter : 11.3.0
  @nrwl/nest : Not Found
  @nrwl/next : 11.3.0
  @nrwl/node : 11.3.0
  @nrwl/react : 11.3.0
  @nrwl/schematics : Not Found
  @nrwl/tao : 11.3.0
  @nrwl/web : 11.3.0
  @nrwl/workspace : 11.3.0
  typescript : 4.1.3
quolpr commented 3 years ago

Actually, jest misses a lot of other loaders' support. Here is my modified jest.config.js in each app/lib dir:

module.exports = {
  displayName: 'core',
  preset: '../../jest.preset.js',
  transform: {
    '^.+\\.[tj]sx?$': [
      'babel-jest',
      { cwd: __dirname, configFile: './babel-jest.config.json' },
    ],
    '.+\\.(png|jpg|gif|ttf|woff|woff2|mp4)$': '<rootDir>/../../jest/stub.js',
    '^.+\\.(css|less|scss|sass)$': '<rootDir>/../../jest/stub.js',
    '^.+\\.svg$': '<rootDir>/../../jest/svgTransformer.js',
  },
  moduleNameMapper: {
    '^.+\\.(css|less|sass|scss)$': '<rootDir>/../../jest/fileMock.js',
    '^.+\\.(png|jpg|gif|ttf|woff|woff2|mp4)$':
      '<rootDir>/../../jest/fileMock.js',
  },
  moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx']
};

<rootDir>/jest/stub.js:

module.exports = {
  process: function () {
    return {
      code: 'module.exports = ""',
    };
  },
};

<rootDir>/jest/svgTransformer.js:

const path = require('path');
const camelcase = require('camelcase');

// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html

module.exports = {
  process(src, filename) {
    const assetFilename = JSON.stringify(path.basename(filename));

    if (filename.match(/\.svg$/)) {
      // Based on how SVGR generates a component name:
      // https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
      const pascalCaseFilename = camelcase(path.parse(filename).name, {
        pascalCase: true,
      });
      const componentName = `Svg${pascalCaseFilename}`;
      return `const React = require('react');
      module.exports = {
        __esModule: true,
        default: ${assetFilename},
        ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
          return {
            $$typeof: Symbol.for('react.element'),
            type: 'svg',
            ref: ref,
            key: null,
            props: Object.assign({}, props, {
              children: ${assetFilename}
            })
          };
        }),
      };`;
    }

    return `module.exports = ${assetFilename};`;
  },
};

<rootDir>/jest/fileMock.js:

module.exports = '';

Hope it will help 🙏️

cyrus-za commented 3 years ago

Thanks @quolpr but we got a lot of libs. Not ideal to need to manually modify each of them and to try and get everyone in the team to remember to manually change it when creating a new lib. Best to have it as part of nx, or to have some script in tools/scripts dir

If nx team doesn't respond soon, I'll probably end up making a script for it

github-actions[bot] commented 3 years ago

This issue has been automatically marked as stale because it hasn't had any recent activity. It will be closed in 14 days if no further activity occurs. If we missed this issue please reply to keep it active. Thanks for being a part of the Nx community! 🙏

cyrus-za commented 3 years ago

This is still an isssue...

Lonli-Lokli commented 3 years ago

@vsavkin Can you please reopen it?

aamir-mns commented 2 years ago

Actually, jest misses a lot of other loaders' support. Here is my modified jest.config.js in each app/lib dir: ..... Hope it will help 🙏️

this worked for me although this should be default behaviour from NX

timbakkum commented 2 years ago

there is svgr (and also font) support it seems in the gatsby jest setup, but not for default react libs. Would be nice to have an overview in the docs of what is supported where (with webpack, jest, rollup, babel) and what is the best way to customize without overriding defaults. Now the only way is to look at the source files of the nx presets.

Lonli-Lokli commented 2 years ago

For those who interested in workaround:

1) edit root jest.preset.js

module.exports = {
    ...nxPreset,
    moduleNameMapper: {
     '\\.svg': '<rootDir>/../../testing/svgrMock.js'
    }
};

Please note two /.. after root dir. Due to https://github.com/nrwl/nx/issues/8029 all libs folders are using their src as rootDir

2) add /testing/svgrMock.js module.exports = { ReactComponent: 'IconMock' }

StephenStrickland commented 2 years ago

@Lonli-Lokli I've tried your approach and still cannot get around the error:

 // error TS2307: Cannot find module './brand-icon.svg' or its corresponding type declarations.
 import { ReactComponent as BrandIcon} from './brand-icon.svg';
Lonli-Lokli commented 2 years ago

I've answered in linked topic.

github-actions[bot] commented 1 year ago

This issue has been closed for more than 30 days. If this issue is still occuring, please open a new issue with more recent context.