Jest Less Import Error

· 4 min read · 754 Words · -Views -Comments

Recently encountered UT errors in a frontend project. At first I was completely confused, but gradually unraveled the issue through careful analysis. Documenting this here.

Error Phenomenon

Error CODE

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:
     • 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:
    https://jestjs.io/docs/en/configuration.html

    Details:

    /xxx/xx/B.less:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){.searchRow {
                                                                                             ^

    SyntaxError: Unexpected token .

      31 | 
      32 | 
    > 33 | import styles from 'app/xxx/xx/B.less';
         | ^

Initial Analysis

  1. Why does a specific component’s LESS file cause issues

    This error seemed strange because many components import LESS files, so why did only this one fail? At first I thought there might be some invisible corrupted characters or spaces in the LESS file that weren’t visible to the naked eye. But after reformatting and checking, I couldn’t find anything.

    So I compared it with other components and found one difference with the failing LESS file - it was imported by two components. For example, component A has style A.less, component A itself imports style A.less, and component B also imports A.less. I quickly copied B.less out and reran UT - it passed.

  2. Why did the Main component UT fail

    Since it was confirmed to be a component LESS import issue, this part was easier to analyze. The Main component imports route configuration, and the route configuration file imports major components. So when UT runs, it executes these imports and thus reports the error.

  3. Runtime OK but UT not OK - Jest configuration? Since runtime doesn’t report errors, it means the code is fine. So I looked at the current jest configuration and had an epiphany:

Modules imported via absolute app paths don't go through `identity-obj-proxy`, and the failing line was an app path import, so the LESS wasn't successfully mocked.

I tried adding the following rule:

Reran UT - it passed.

Best Solution

Although the above configuration addition can solve the problem, what’s the best solution? This is worth considering.

The above issue reveals that the current Jest configuration does have shortcomings. If you import LESS from app paths, UT will fail. But realistically speaking, is there currently a need to import LESS from absolute app paths? No.

Because as shown above, it actually imports duplicate LESS files. Just in terms of bundle size, it essentially packages duplicate LESS files. Since there’s CSS module, the two don’t interfere with each other. But since the goal is to reuse this style, the current issue is just using the wrong approach.

Correct Approach

If you need to reuse such LESS:

  1. One method is to put it in the root component’s index.less, where CSS is global.

  2. If not placed there, it can be placed at the common parent component level of both components. For example, if these two components are component A and component B, they have a common parent component C, so put the style on C. Then A and B can naturally reuse it.

  1. CSS Modularization

CSS modularization is now a very mature CSS style management solution. Why call it management? Because with it, it actually solves the long-standing annoying CSS conflict issues. At the same time, CSS modularization also provides an outlet for global styles. This makes management quite elegant.

  1. import styles from ‘index.less’

This import method turns CSS usage into JS usage. So if we move positions or rename CSS, it can be automatically modified. This unifies CSS and JS. Isn’t that great.

  1. identity-obj-proxy in jest

This module is designed to solve the use of non-JS resources in our UT tested components, such as CSS, PNG, SVG, etc. In testing, many things need to be mocked. Tests always aim to check our core logic with the lowest fabrication cost and most realistic testing points.

Summary

At this point, this problem is solved and understood. Happy. There are still many pitfalls in frontend development. But all methods follow the same principles. Let’s encourage each other.

Authors
Developer, digital product enthusiast, tinkerer, sharer, open source lover