Jest: .png์˜ "๊ตฌ๋ฌธ ์˜ค๋ฅ˜: ์œ ํšจํ•˜์ง€ ์•Š๊ฑฐ๋‚˜ ์˜ˆ๊ธฐ์น˜ ์•Š์€ ํ† ํฐ"

์— ๋งŒ๋“  2017๋…„ 01์›” 21์ผ  ยท  33์ฝ”๋ฉ˜ํŠธ  ยท  ์ถœ์ฒ˜: facebook/jest

๊ฐ„๋‹จํ•œ ๋ชจ๋“ˆ์„ ํ…Œ์ŠคํŠธํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ ๋‹ค์Œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

Test suite failed to run

    /home/matheusml/Projects/react-completo/src/assets/images/dribble-logo.png:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){๏ฟฝPNG
                                                                                             ^
    SyntaxError: Invalid or unexpected token

      at transformAndBuildScript (node_modules/jest-runtime/build/transform.js:320:12)
      at Object.<anonymous> (src/components/container/Container.js:4:46)
      at Object.<anonymous> (src/components/App.js:4:44)

์ด๊ฒƒ์€ ํ…Œ์ŠคํŠธ์ž…๋‹ˆ๋‹ค:

import React from 'react';
import renderer from 'react-test-renderer';
import { Router } from 'react-router';

import App from './App';

test('App', () => {
  const component = renderer.create(
    <App />
  );
  let tree = component.toJSON();
  expect(tree).toMatchSnapshot();
});

์ด๊ฒƒ์€ ๋‚ด package.json์ž…๋‹ˆ๋‹ค.

"jest": {
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|svg)$": "./src/config/fileMock.js",
      "\\.(css|scss)$": "identity-obj-proxy"
    }
  }

๊ทธ๋ฆฌ๊ณ  ์ด๊ฒƒ์€ ํŒŒ์ผMock.js์ž…๋‹ˆ๋‹ค:

module.exports = 'test-file-stub';

๊ฐ์‚ฌ ํ•ด์š”!

๊ฐ€์žฅ ์œ ์šฉํ•œ ๋Œ“๊ธ€

๋‚˜๋Š” ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์—ˆ๊ณ  assetsTransformer.js ๋ฅผ ๋งŒ๋“ค์–ด ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

const path = require('path');

module.exports = {
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
  },
};

๊ทธ๋Ÿฐ ๋‹ค์Œ package.json์˜ jest ๊ตฌ์„ฑ์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
"jest": { "moduleNameMapper": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetsTransformer.js", "\\.(css|less)$": "<rootDir>/assetsTransformer.js" } },

์ถœ์ฒ˜: https://facebook.github.io/jest/docs/webpack.html#content

๋ชจ๋“  33 ๋Œ“๊ธ€

http://facebook.github.io/jest/docs/tutorial-webpack.html#content ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

ํŽธ์ง‘: ์ƒˆ ๋งํฌ๋Š” https://jestjs.io/docs/en/webpack ์ž…๋‹ˆ๋‹ค.

@matheusml ์ด๊ฑฐ ์ „ํ˜€ ํ•ด๊ฒฐํ•˜์…จ๋‚˜์š”? @cpojer ์ €๋„ ์ด ๋ฌธ์ œ๊ฐ€ ์žˆ์Œ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์†Œ์Šค ์™ธ๋ถ€์— ์ •์  ์ž์‚ฐ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ฆ‰ ๋‚ด ๋””๋ ‰ํ† ๋ฆฌ ๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

|-fonts
|-img
\_styles
src
|-components
|-pages
...

๋‚ด jest ๊ตฌ์„ฑ์€ ๋งํฌ์— ์ œ๊ณต๋œ ์˜ˆ์ œ์™€ ์œ ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

"jest": {
    "collectCoverageFrom": [ "src/**/*.{js,jsx}" ],
    "moduleNameMapper": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "tests/__mocks__/fileMock.js"
    }
  }

์ด๋ฏธ์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ํ•˜๋ฉด ํ…Œ์ŠคํŠธ๊ฐ€ ์‹คํŒจํ•ฉ๋‹ˆ๋‹ค.

import thumbnail from 'img/thumbnail.png'

public ๋””๋ ‰ํ† ๋ฆฌ๋ฅผ moduleDirectories ์— ํฌํ•จํ•˜์ง€ ์•Š์œผ๋ฉด Cannot find module 'img/thumbnail.png' from 'MyModule.js' ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์˜ˆ์ƒ๋˜๋Š” ์ผ์ž…๋‹ˆ๊นŒ? ๋ชจ๋“ˆ ๋งคํ•‘์ด ์ด๋ฏธ ์„ค์ •๋˜์–ด ์žˆ์ง€๋งŒ ๊ฐ€์ ธ์˜ค๊ธฐ ์ด๋ฒคํŠธ์˜ ์กด์žฌ๋ฅผ ์‹ค์ œ๋กœ ๊ฒ€์ฆํ•ด์•ผ ํ•ฉ๋‹ˆ๊นŒ? ๊ทธ๋ ‡์ง€ ์•Š์œผ๋ฉด ์œ„์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฆ„ ๋งคํผ์—์„œ ๋‹ค๋ฅธ ์œ ํ˜•์˜ ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์‹œ๋„ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ฐ™์€ ๋ฌธ์ œ์— ์ง๋ฉดํ•˜๊ณ  ์žˆ์œผ๋ฉฐ reactjs ์„œ๋ฒ„ ๋ Œ๋”๋ง์„ ๊ตฌํ˜„ํ•˜๋ ค๊ณ ํ•ฉ๋‹ˆ๋‹ค. ์ด์— ๋Œ€ํ•œ ๋ชจ๋“  ์ˆ˜์ • ์‚ฌํ•ญ.

๋‚˜๋Š” ์ด๊ฒƒ์„ ๋‚ด babelrc์— ๋„ฃ์—ˆ๊ณ  ๋ชจ๋“  ๊ฒƒ์ด ์ž‘๋™ํ•˜๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค.

{
"์‚ฌ์ „ ์„ค์ •": ["es2015", "๋ฐ˜์‘"]
}

๊ฐ™์€ ์œ ํ˜• ์˜ค๋ฅ˜

SyntaxError: Unexpected token <
      /media/sibin/F_WORK/<path>/<icon-name>.svg:1
      ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){<?xml version="1.0" encoding="UTF-8"?>
                                                                                               ^
      SyntaxError: Unexpected token <

์ €๋„ ์ด ๋ฌธ์ œ๋ฅผ ๊ฒช๊ณ  ์žˆ๋Š” ๊ฒƒ ๊ฐ™์Šต๋‹ˆ๋‹ค. png๊ฐ€ ํ•„์š”ํ•  ๋•Œ๋งŒ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){๏ฟฝPNG
                                                                                             ^
    SyntaxError: Invalid or unexpected token

๊ฐ™์€ ์˜ค๋ฅ˜๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ž…๋‹ˆ๋‹ค. ๋ˆ„๊ตฐ๊ฐ€ ๊ณ ์ณ์ฃผ๋‚˜์š”?

.mp3์™€ ๋™์ผํ•œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์•„๋ฌด ๊ฒƒ๋„ ๋„์›€์ด ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด์™€ ๊ฐ™์€ ์˜ค๋ฅ˜๋Š” ์˜ˆ๋ฅผ ๋“ค์–ด ๋ชจ๋“ˆ ์ด๋ฆ„ ๋งคํผ์— ์ ˆ๋Œ€ ๊ฒฝ๋กœ๊ฐ€ ์„ค์ •๋œ ์‚ฌ์ „ ์„ค์ •์„ ์‚ฌ์šฉํ•œ ๊ฒฐ๊ณผ์ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์ด ๊ฒฝ์šฐ๋Š” ๋‹ค์Œ ๋ฆด๋ฆฌ์Šค์—์„œ ์ˆ˜์ •๋ฉ๋‹ˆ๋‹ค.

๋‚˜๋Š” ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ์žˆ์—ˆ๊ณ  assetsTransformer.js ๋ฅผ ๋งŒ๋“ค์–ด ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค.

const path = require('path');

module.exports = {
  process(src, filename, config, options) {
    return 'module.exports = ' + JSON.stringify(path.basename(filename)) + ';';
  },
};

๊ทธ๋Ÿฐ ๋‹ค์Œ package.json์˜ jest ๊ตฌ์„ฑ์— ๋‹ค์Œ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
"jest": { "moduleNameMapper": { "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/assetsTransformer.js", "\\.(css|less)$": "<rootDir>/assetsTransformer.js" } },

์ถœ์ฒ˜: https://facebook.github.io/jest/docs/webpack.html#content

์ œ ๊ฒฝ์šฐ์—๋Š” <rootDir> ๊ฐ€ Jest์—์„œ ์ œ๊ณตํ•œ ํ† ํฐ ์ด๋ผ๋Š” ๊ฒƒ์„ ๊นจ๋‹ซ์ง€ ๋ชปํ•˜๊ณ  ๊ต์ฒดํ•ด์•ผ ํ•˜๋Š” ํ† ํฐ์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ์Šต๋‹ˆ๋‹ค. moduleNameMapper ํ•ญ๋ชฉ์— ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

@bombellos๊ฐ€ ์–ธ๊ธ‰ํ•œ assetTransformer.js ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ ์›นํŒฉ๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ ์— ๋Œ€ํ•œ ์ง€์นจ์„ ๋”ฐ๋ž์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์—ฌ์ „ํžˆ ๊ฐ™์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

PNG:

 FAIL  components/__tests__/List.js
  โ— Test suite failed to run

    /assets/images/logo-header.png:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){๏ฟฝPNG
                                                                                             ^

    SyntaxError: Invalid or unexpected token

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
      at Object.<anonymous> (components/PageHeader.js:15:19)
      at Object.<anonymous> (components/Main.js:10:436)

SVG:

 FAIL  ui/Button/__tests__/snapshot.test.js
  โ— fixture 'TextAndIcon' snapshots are rendered correctly

    /assets/icons/fontawesome/regular.svg:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
                                                                                             ^

    SyntaxError: Unexpected token <

      at ScriptTransformer._transformAndBuildScript (node_modules/jest-runtime/build/script_transformer.js:305:17)
      at Icon (ui/Icon.js:31:17)
      at resolve (node_modules/react-dom/cjs/react-dom-server.node.development.js:2599:14)
      at ReactDOMServerRenderer.render (node_modules/react-dom/cjs/react-dom-server.node.development.js:2746:22)
      at ReactDOMServerRenderer.read (node_modules/react-dom/cjs/react-dom-server.node.development.js:2722:19)
      at Object.renderToStaticMarkup (node_modules/react-dom/cjs/react-dom-server.node.development.js:2991:25)

๋‚ด ํด๋” ๊ตฌ์กฐ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.

<rootDir>
  assets
    *.png, *.svg, ...
  components
    *.js
  ui
    *.js

๋ถ„๋ช…ํžˆ ํŒŒ์ผ์€ ์กฐ๋กฑ๋˜์ง€ ์•Š๊ณ  ์—ฌ์ „ํžˆ ๋กœ๋“œ๋˜์ง€๋งŒ ์ด๊ฒƒ์„ ๋””๋ฒ„๊น…ํ•˜๋Š” ๋ฐฉ๋ฒ•์— ๋Œ€ํ•œ ๋‹จ์„œ๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค.

.babelrc:

{
  "presets": [
    ["es2015", {"modules": false}],
    "react",
    "stage-1",
    ["env", {
      "targets": {
        "browsers": [
          "last 3 versions",
          "> 1%",
          "Firefox ESR",
          "iOS 9"
        ]
      }
    }]

  ],
  "plugins": [
    "react-hot-loader/babel",
    "transform-class-properties",
    "transform-react-jsx-source",
    "glamorous-displayname",
    "wildcard"
  ],
  "env": {
    "development": {
      "plugins": [
        ["transform-runtime", {
          "polyfill": true
        }]
      ]
    },
    "test": {
      "plugins": ["transform-es2015-modules-commonjs"]
    }
  }
}

ํŒจํ‚ค์ง€.json:

  "jest": {
    "snapshotSerializers": [
      "jest-glamor-react",
      "enzyme-to-json/serializer"
    ],
    "moduleFileExtensions": ["js"],
    "moduleDirectories": ["node_modules"],
    "transform": {
      "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/config/jest/assetsTransformer.js"
    }
  },

๋‚˜๋Š” ๋ฐ”๋ณด์ž…๋‹ˆ๋‹ค. ๋‚ด ๋ฃจํŠธ ํด๋”์— package.json ์˜ ์„ค์ •์„ ๋ฎ์–ด์“ด ๋˜ ๋‹ค๋ฅธ jest.config.js $ ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์•„์ง ์‹คํ–‰๋˜๊ณ  ์žˆ์ง€๋Š” ์•Š์ง€๋งŒ ๋” ์ด์ƒ ์ด ํŠน์ • ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค. ๋‹ค์Œ์€ ์ค‘์š”ํ•œ ์‚ฌํ•ญ์ž…๋‹ˆ๋‹ค(๋ฐ˜์‘ 16๊ณผ ํ•จ๊ป˜ ํšจ์†Œ 3์œผ๋กœ ์ธํ•ด ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ๊ตฌ์„ฑ์ด ์žˆ์Œ์„ ์œ ์˜ํ•˜์‹ญ์‹œ์˜ค).

.babelrc

{
  "presets": [
    "es2015",
    "react",
    "stage-1",
    "env"

  ],
  "plugins": [
    "react-hot-loader/babel",
    "transform-class-properties",
    "transform-react-jsx-source",
    "glamorous-displayname",
    "wildcard"
  ],
  "env": {
    "development": {
      "plugins": [
        ["transform-runtime", {
          "polyfill": true
        }]
      ]
    }
  }
}

jest.config.js

// this helps: https://github.com/facebook/jest/issues/2081#issuecomment-332406033
module.exports = {
  verbose: true,
  setupFiles: ['./jest.setup.js'],
  snapshotSerializers: ['jest-glamor-react', 'enzyme-to-json/serializer'],
  moduleFileExtensions: ['js', 'jsx'],
  transform: {
    '^.+\\.jsx?$': 'babel-jest',
    '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$':
      '<rootDir>/config/jest/assetsTransformer.js',
  },
};

jest.setup.js

import 'raf/polyfill';
import Enzyme from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

Enzyme.configure({ adapter: new Adapter() });

๊ทธ๊ฒƒ์ด ๋ˆ„๊ตฐ๊ฐ€๋ฅผ ๋•๊ธฐ๋ฅผ ๋ฐ”๋ž๋‹ˆ๋‹ค.

svg ํŒŒ์ผ์— ๋ฌธ์ œ๊ฐ€ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค. identity-obj-proxy ๋กœ ์กฐ๋กฑํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค.

    "moduleNameMapper": {
      "\\.(css|scss|svg)$": "identity-obj-proxy"
    },

์ด ๋ฌธ์ œ๋ฅผ ์กฐ์‚ฌํ•˜๋Š” ์‚ฌ๋žŒ์€ @timgivois ๋ฐฉ์‹์ด ์ €์—๊ฒŒ ์ž˜ ๋งž์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•œ ์ข…์†์„ฑ์„ ์–ป์œผ๋ ค๋ฉด npm install --save-dev identity-obj-proxy ๋ฅผ ์„ค์น˜ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

  "jest": {
    "moduleNameMapper": {
      ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "identity-obj-proxy"
    }
  }

@mbaranovski ์˜ ์†”๋ฃจ์…˜์ด ์ž‘๋™ํ•˜๋Š” ๋™์•ˆ ๊ทธ์˜ ์˜๋„๊ฐ€ ๊ทธ๊ฒƒ์„ ๋ณ€์••๊ธฐ๋กœ ์‚ฌ์šฉํ•˜๋ ค๋Š” ๊ฒƒ์ธ์ง€ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹ค์Œ ์ถœ๋ ฅ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค(src ์†์„ฑ์— ์ฃผ์˜).

<img alt="ImgName" height="28" src={ Object { "process": [Function], } } width="112" />

๊ธฐ๋ณธ์ ์œผ๋กœ ํ•ด๋‹น ๋ชจ๋“ˆ์—์„œ SVG๊ฐ€ ํ•„์š”ํ•œ ์œ„์น˜๋กœ ๋ชจ๋“  ๊ฒƒ์„ ๋งคํ•‘ํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ•ด๋‹น ๋ชจ๋“ˆ์„ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ฐ„๋‹จํžˆ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

module.exports = {}

์œ„์—์„œ ์„ค๋ช…ํ•œ ๋‹ค๋ฅธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์€ identity-obj-proxy๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

@magnusart

"jest": {
    "moduleNameMapper": {
      ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "identity-obj-proxy"
    }
  }

๊ทธ๊ฒƒ์€ ๋‚ด ํ•˜๋ฃจ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”!!.

@mbaranovski ํ…Œ์ŠคํŠธ๋ฅผ ์œ„ํ•ด jest๋งŒ ์‹คํ–‰ํ–ˆ์„ ๋•Œ ์ž˜ ์ž‘๋™ํ–ˆ์Šต๋‹ˆ๋‹ค. ์Šฌํ”„๊ฒŒ๋„ create-react-app์—์„œ ๋ฐ˜์‘ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๋ ค๊ณ  ํ•  ๋•Œ

Out of the box, Create React App only supports overriding these Jest options

์ด์— ๋Œ€ํ•œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์žˆ์Šต๋‹ˆ๊นŒ? ์•„๋‹ˆ๋ฉด ์œ ์ผํ•œ ํ•ด๊ฒฐ์ฑ…์€ create-react-app์„ ๊บผ๋‚ด๋Š” ๊ฒƒ์ž…๋‹ˆ๊นŒ?

CRA๊ฐ€ ํ•ด๋‹น ์˜ต์…˜์„ ์ง€์›ํ•˜์ง€ ์•Š๋Š”๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์˜ต์…˜์„ ๋‹ซ๊ณ  ์‹ถ์–ดํ•˜๋Š” ์ด์œ ๋ฅผ ์ž˜ ๋ชจ๋ฅด๊ฒ ์Šต๋‹ˆ๋‹ค. ์•„๋งˆ๋„ ์ข‹์€ ์ด์œ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค. ๐Ÿ™‚

/cc @gaearon

๋‹ค๋ฅธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•:

npm i --save-dev jest-transform-stub
"jest": {
  "transform": {
    ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "jest-transform-stub"
  }
}

๋ฐ˜์‘ ๋„ค์ดํ‹ฐ๋ธŒ ๋ชจ๋“ˆ์— ์ด๋ฏธ์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. assetsTransformer , identity-obj-proxy ๋ฐ jest-transform-stub ์‹œ๋„ํ–ˆ์Šต๋‹ˆ๋‹ค. assetTransformer๋งŒ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

์•ˆ๋…•ํ•˜์„ธ์š” @sibinx7 : https://github.com/facebook/jest/issues/2663/#issuecomment -317109798์„ ํ†ตํ•ด ํ•ด๋‹น ๋ฌธ์ œ๋ฅผ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.

์—ฌ๊ธฐ์— ์žˆ๋Š” ๋ชจ๋“  ์†”๋ฃจ์…˜์ด ์ €์—๊ฒŒ ์ ํ•ฉํ•˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— jest-react-native ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ–ˆ์Šต๋‹ˆ๋‹ค. react-native-router-flux -package ์•ˆ์— ์žˆ๋Š” PNG ํŒŒ์ผ์— ๋ฌธ์ œ๊ฐ€ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๋‚ด ๋ฌธ์ œ๊ฐ€ ๋‹ค๋ฅธ ๊ฒƒ์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

๋‹ค์Œ์€ ๋‚ด package.json ํŒŒ์ผ์˜ ์ผ๋ถ€์ž…๋‹ˆ๋‹ค.

{
  // ... 
  "devDependencies": {
    // ...
    "jest": "^23.4.1",
    "jest-react-native": "^18.0.0",
  },
  "jest": {
    "preset": "jest-react-native",
    "verbose": true,
    "modulePathIgnorePatterns": [
      "<rootDir>/node_modules/react-native/Libraries/react-native/",
      "<rootDir>/node_modules/react-native/packager/"
    ],
    "transformIgnorePatterns": [
      "node_modules/(?!((jest-)?react-native|react-clone-referenced-element|react-navigation|react-native-router-flux))"
    ]
  },
  // ...
}

์ด ๊ฒฝ์šฐ ๋ณ€ํ™˜ ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ xml ํŒŒ์ผ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ ์•ฝ๊ฐ„์˜ ์ˆ˜์ •:

jest.config.js

module.exports = {
    transform: {
        ".+.(xml|bpmn)": "<rootDir>/src/__tests__/transformers/xmlTransformer.ts"
    },
}

/src/__tests__/transformers/xmlTransformer.ts (๊ฒฝ๋กœ๋ฅผ ์ˆ˜์ •ํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.ํ”„๋กœ์ ํŠธ์˜ ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ๋„์šฐ๋ฏธ์ž…๋‹ˆ๋‹ค).

module.exports = {
    process() {
        return 'module.exports = {};';
    },
    getCacheKey() {
        // The output is always the same.
        return 'xmlTransform';
    },
};

์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—ฌ๊ธฐ ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

http://facebook.github.io/jest/docs/tutorial-webpack.html#content ๋ฅผ ํ™•์ธํ•˜์„ธ์š”.

์ฃผ์–ด์ง„ ๋งํฌ๊ฐ€ ๊นจ์กŒ์Šต๋‹ˆ๋‹ค

@magnusart

"jest": {
    "moduleNameMapper": {
      ".+\\.(css|styl|less|sass|scss|png|jpg|ttf|woff|woff2)$": "identity-obj-proxy"
    }
  }

๊ทธ๊ฒƒ์€ ๋‚ด ํ•˜๋ฃจ๋ฅผ ์ €์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐ์‚ฌ ํ•ด์š”!!.

๋‚˜๋Š” ์ด๊ฒƒ์—์„œ ์‹ ํ˜ธ๋ฅผ ๋ฐ›์•„ babel-jest ๋ฅผ ์„ค์น˜ํ•œ ๋‹ค์Œ identity-obj-proxy ๋ฅผ babel-jest ๋กœ ๋ฐ”๊ฟ‰๋‹ˆ๋‹ค.

๋˜๋Š” ์ด๊ฒƒ์„ ์‚ฌ์šฉํ•˜์‹ญ์‹œ์˜ค https://github.com/eddyerburgh/jest-transform-stub

@eddyerburgh ์˜ ์†”๋ฃจ์…˜๋งŒ์ด ์ €์—๊ฒŒ ํšจ๊ณผ์ ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

@magnusart
๋‹น์‹ ์€ ๋‚ด ํ•˜๋ฃจ๋ฅผ ์ €์žฅ, ๊ทธ๊ฒƒ์€ ์ž˜ ์ž‘๋™

./node_modules/react-native-gesture-handler/jestSetup.js ๋ฅผ setupFiles ์— ์ถ”๊ฐ€ํ•œ ํ›„ ์ด png ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค( react-native-gesture-handler ๋กœ ๋†๋‹ด ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋ ค๋Š” ์‹œ๋„์˜€์Šต๋‹ˆ๋‹ค).

๋‚˜๋Š” https://github.com/facebook/jest/issues/2663#issuecomment -341384494 ( @magnusart using identity-obj-proxy )๋ฅผ ์‹œ๋„ํ–ˆ์ง€๋งŒ ์–ด๋–ค ์ด์œ ๋กœ๋“  enzyme ๋ฅผ ๊นจ๋œจ๋ ธ์Šต๋‹ˆ๋‹ค( enzyme ์˜ mock ๋ฅผ ํ•จ์ˆ˜๊ฐ€ ์•„๋‹Œ ๊ธฐํ˜ธ๋กœ ์‚ฌ์šฉ). ๊ทธ๋Ÿฐ ๋‹ค์Œ https://github.com/facebook/jest/issues/2663#issuecomment -369040789 (@eddyerburgh
jest-transform-stub )๋ฅผ ์‚ฌ์šฉํ–ˆ์ง€๋งŒ ์•„๋ฌด ๊ฒƒ๋„ ํ•˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ, ๋‚˜๋Š” https://github.com/facebook/jest/issues/2663#issuecomment -274270387 ( @cpojer ์ฒ˜์Œ ์— webpack ์†”๋ฃจ์…˜)์„ ์‹œ๋„ํ–ˆ๊ณ  ๊ทธ๊ฒƒ์ด ๋‚˜๋ฅผ ์œ„ํ•ด ์ผํ•˜๋Š” ์œ ์ผํ•œ ๊ฒƒ์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋ˆ„๊ตฌ๋“ ์ง€ SVG์—์„œ ์ด ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ์•„๋งˆ๋„ ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค. https://www.npmjs.com/package/jest-svg-transformer

๋‚ด jest.config.ts ํŒŒ์ผ์—๋งŒ ์ด ์ฝ”๋“œ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

transform: { '^.+\\.tsx?$': 'babel-jest', '^.+\\.svg$': 'jest-svg-transformer', },

๊ทธ๋ฆฌ๊ณ  ์ด ํŒŒ์ผ์˜ ์ฝ”๋“œ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
Captura de Tela 2020-11-09 aฬ€s 13 17 01

์—ฌ๋Ÿฌ๋ถ„์€ moduleNameMapper๋ฅผ ๋ฌด์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์™œ๋ƒํ•˜๋ฉด ์ œ๊ฐ€ babel๊ณผ ํ•จ๊ป˜ ์‚ฌ์šฉ์ž ์ง€์ • ๊ฐ€์ ธ์˜ค๊ธฐ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

์ด ํŽ˜์ด์ง€๊ฐ€ ๋„์›€์ด ๋˜์—ˆ๋‚˜์š”?
0 / 5 - 0 ๋“ฑ๊ธ‰