Maikel Nait
Maikel Nait

Reputation: 261

Jest + @testing-library/react throws error on a .mjs file from [dom-accessibility-api] library

I'm new to using Jest + @testing-library/react, and on my first attempt, I'm getting an error on a third-party library (probably used by the react-testing-library), which I'm not sure how to fix.

This is my test for the main React App.js component. Basically I try to render it wrapping it with a Redux store, and then verifying that a DOM component exists. Pretty straightforward:

import React from 'react';
import '@testing-library/jest-dom/extend-expect';
import { render } from '@testing-library/react';
import { App } from '../../../src/features/root/App';
import { Provider } from "react-redux";
import { createStore } from "redux";
import { initialState } from '../../../src/features/root/redux/initialState';
import { reducer } from '../../../src/features/root/redux/reducer';

const renderWithProviders = (ui, { reduxState } = {}) => {
  const store = createStore(reducer, reduxState || initialState);
  return render(<Provider store={store}>{ui}</Provider>);
}

describe('root/App', () => {

  it('renders node with correct class name', () => {
    const { getByTestId } = renderWithProviders(<App />, { });
    const mainDiv = getByTestId('id-of-the-div');
    expect(mainDiv).toBeDefined();
  });
});

However, when running the test, Jest is throwing the following error:

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

Details:

/sandbox/node_modules/dom-accessibility-api/dist/accessible-description.mjs:7
import { computeTextAlternative } from "./accessible-name-and-description.mjs";
^^^^^^

SyntaxError: Cannot use import statement outside a module

  at Runtime.createScriptFromCode (node_modules/jest-runtime/build/index.js:1350:14)
  at Object.<anonymous> (node_modules/dom-accessibility-api/sources/index.ts:1:1)

So the key point here is the following:

/sandbox/node_modules/dom-accessibility-api/dist/accessible-description.mjs:7
import { computeTextAlternative } from "./accessible-name-and-description.mjs";
^^^^^^

SyntaxError: Cannot use import statement outside a module

It looks like that particular .mjs file from that library dom-accessibility-api cannot be parsed by Jest. But why is that happening ? In any tutorial for making React tests using react-testing-library and Jest, there seems to be no issues or mentions about this. This is a third-party library that I know nothing about.

Does anyone know how to fix this problem ? My main configuration files:

babel.config.js:

const presets = [    
  'react-app'    
];

module.exports = { presets };

jest.config.js: (I tried many options and simplifications, but to no avail)

module.exports = {
reporters: [
    "default",
    "jest-junit"
  ],
  coverageReporters: [
    "lcov",
    "text",
    "cobertura"
  ],
  collectCoverageFrom: [
    "src/**/*.{js,jsx}"
  ],
  setupFiles: [        
    "<rootDir>/tests/setup.js",
    "jest-localstorage-mock",
    "jest-canvas-mock"
  ],
  snapshotSerializers: [
    "enzyme-to-json/serializer"
  ],
  testMatch: [
    "<rootDir>/tests/**/*.test.js"
  ],
  testEnvironment: "jsdom",
  testURL: "http://localhost",
  transform: {
    "^.+\\.(js|jsx)$": "babel-jest",
    "^.+\\.(ts|tsx|mjs)$": "ts-jest",
    "^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
    "^(?!.*\\.(js|jsx|mjs|css|json|ts)$)": "<rootDir>/config/jest/fileTransform.js"
  },
  transformIgnorePatterns: [
    "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|ts|tsx)$"
  ],
  testPathIgnorePatterns: ["<rootDir>/build/", "<rootDir>/node_modules/"],
  moduleNameMapper: {
    "^react-native$": "react-native-web"
  },
  moduleFileExtensions: [
    "web.js",
    "mjs",
    "js",
    "ts",
    "json",
    "web.jsx",
    "jsx",
    "node"
  ]  
}

/tests/setup.js: (just to initialize Enzyme for other types of tests)

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter(), disableLifecycleMethods: true });

/config/jest/fileTransform.js:

'use strict';

const path = require('path');

// 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) {
    return `module.exports = ${JSON.stringify(path.basename(filename))};`;
  },
};

package.json: (just showing the devDependencies)

"devDependencies": {
 "@babel/core": "^7.12.10",
 "@babel/preset-env": "^7.12.11",
 "@babel/preset-react": "^7.12.10",
 "@babel/preset-typescript": "^7.12.7",
 "@testing-library/jest-dom": "^5.11.9",
 "@testing-library/react": "^11.2.3",
 "axios-mock-adapter": "^1.15.0",
 "babel-eslint": "^10.1.0",
 "babel-jest": "^26.6.3",
 "babel-loader": "^8.2.2",
 "babel-preset-react-app": "^10.0.0",
 "babel-runtime": "^6.26.0",
 "browser-refresh-taglib": "^1",
 "case-sensitive-paths-webpack-plugin": "2.1.1",
 "cross-env": "^5.2.0",
 "enzyme": "^3.11.0",
 "enzyme-adapter-react-16": "^1.15.5",
 "enzyme-to-json": "^3.6.1",
 "eslint": "^7.17.0",
 "eslint-config-react-app": "^6.0.0",
 "eslint-loader": "^4.0.2",
 "eslint-plugin-flowtype": "^5.2.0",
 "eslint-plugin-import": "^2.22.1",
 "eslint-plugin-jsx-a11y": "^6.4.1",
 "eslint-plugin-react": "^7.22.0",
 "eslint-plugin-react-hooks": "^4.2.0",
 "extract-text-webpack-plugin": "3.0.2",
 "html-webpack-plugin": "2.29.0",
 "jest": "^26.6.3",
 "jest-canvas-mock": "^2.2.0",
 "jest-junit": "^5.2.0",
 "jest-localstorage-mock": "^2.3.0",
 "jest-when": "^2.7.0",
 "nock": "^9.2.3",
 "optimizer-plugin-inc": "^4",
 "query-string": "5.1.1",
 "react-dev-utils": "^5.0.0",
 "redux-mock-store": "^1.5.4",
 "redux-thunk": "^2.3.0",
 "sw-precache-webpack-plugin": "0.11.4",
 "ts-jest": "^26.4.4",
 "webpack": "3.8.1",
 "webpack-bundle-analyzer": "^3.0.3",
 "webpack-dev-server": "2.9.4",
 "webpack-hot-middleware": "^2.22.2",
 "webpack-manifest-plugin": "1.3.2"
};

Upvotes: 3

Views: 2959

Answers (3)

yuanhjty
yuanhjty

Reputation: 31

Sepcificy moduleFileExtensions in jest.config.js as follow:

// jest.config.js
module.exports = {
  // ...
  moduleFileExtensions: ["js", "jsx", "ts", "tsx", "json"]
  // ...
}

Jest docs: moduleFileExtensions

Upvotes: 0

ramayac
ramayac

Reputation: 5183

It seems the real fix is to remove/disable the code transforms.

Following Jest 27.4 docs (current version): https://jestjs.io/docs/ecmascript-modules, #1: Ensure you either disable code transforms by passing transform: {} or otherwise configure your transformer to emit ESM rather than the default CommonJS (CJS).

Which is exactly what you did in your jest.config.js file.

Hope this helps to understand the issue better!

Upvotes: 0

Maikel Nait
Maikel Nait

Reputation: 261

Seems I found the solution. Based on this example: react-redux

I have updated and simplified my jest.config.js as follows:

const path = require('path')

module.exports = {

    roots: [path.resolve(__dirname, './tests')],

    reporters: [
        "default",
        "jest-junit"
    ],
    coverageReporters: [
      "lcov",
      "text",
      "cobertura"
    ],
    collectCoverageFrom: [
      "src/**/*.{js,jsx}"
    ],
    setupFiles: [        
      path.resolve(__dirname, "./tests/setup.js"),
      "jest-localstorage-mock",
      "jest-canvas-mock"
    ],
  
    setupFilesAfterEnv: [path.resolve(__dirname, './tests/setupAfterEnv.js')],

    testMatch: [
      "**/tests/**/*.test.js"
    ],
  
    testURL: "http://localhost"
}

and added a setupAfterEnv.js file with just this line:

import '@testing-library/jest-dom/extend-expect'

And so far, the test can pass now...

To be honest, I'm still not sure why previously I was getting that error, I don't think the changes are substantial...

Upvotes: 0

Related Questions