문제

jest로 테스트로 실행할 때 css파일 import문에서 module을 찾을 수 없다는 에러가 발생합니다.

Test suite failed to run

    Cannot find module 'swiper/css' from 'src/components/home/Reviews.jsx'

    Require stack:
      src/components/home/Reviews.jsx
      src/components/home/Reviews.test.jsx

      11 | import { medias } from '../../designSystem';
      12 |
    > 13 | import 'swiper/css';
         | ^
      14 | import 'swiper/css/navigation';

원인

자바스크립트에서는 css파일을 import할 수 없습니다. 그러다보니 module을 찾을 수 없다는 에러가 발생합니다. webpack에서 되는 이유는 css-loader 처럼 자바스크립트에서 css파일을 임포트할 수 있도록 js로 변환해주는 것을 사용하기 때문입니다.

해결방법

import문이 테스트에 영향을 주지 않기 때문에, mocking해서 처리를 해야 합니다. jest에서는 설정에서 moduleNameMapper 라는 옵션으로 모듈이름과 사용할 모킹 모듈로 매핑할 수 있습니다.

module.exports = {
  // ... 생략

	moduleNameMapper: {
    'swiper/css': '<rootDir>/dummy.js'
  },

  // ... 생략
}

// dummy.js
const nothing = {};

export default nothing;

그러면 테스트를 실행할 때 swiper/css 파일을 import하는 것이 아니라, dummy.js 를 import합니다. dummy.js 는 아무것도 없는 그냥 JavaScript파일입니다. css파일을 기능을 테스트하는데 아무런 영향을 주지 않으므로, 아무것도 안하는 JavaScript파일로 대체하도록 합니다.

만약 dummy.js 처럼 가짜 파일을 만드는게 싫다면, 이러한 가짜 파일을 미리 만들어놓은 걸 사용할 수 있습니다.

npm install  --save-dev identity-obj-proxy

라이브러리를 설치한 후 jest.config.js 에 다음과 같이 설정합니다.

module.exports = {
  // ... 생략

	moduleNameMapper: {
    'swiper/css': 'identity-obj-proxy'
  },

  // ... 생략
}

identity-obj-proxy 라이브러리의 실제 코드를 보면 이 파일도 아무일도 안하고, 주어진 값을 그냥 반환하는 코드인 것을 확인하실 수 있습니다.

// https://github.com/keyz/identity-obj-proxy/blob/master/src/index.js

// ... 생략

idObj = new Proxy({}, {
  get: function getter(target, key) {
    if (key === '__esModule') {
      return false;
    }
    return key;
  }
});

module.exports = idObj;

// other-file.js
import idObj from 'identity-obj-proxy';

console.log(idObj.foo); // 'foo'
console.log(idObj.bar); // 'bar'
console.log(idObj[1]); // '1'

참고