본문 바로가기
javascript

장치 테스트를 위한 Jest 및 React 테스트 라이브러리 설정

by it-square 2022. 1. 13.
반응형

Create-React-app이 인기 있는 도구가 된 이후, React에 대한 많은 튜토리얼에서 이를 시작 도구로 사용합니다. 하지만 Create-React-App이 우리에게 어떤 역할을 했는지 배우고 툴에 의존하지 않고 테스트 환경도 설정할 수 있도록 스스로 환경을 설정하기로 결정했습니다.

인기 있는 스타터 프로젝트를 관찰하고 이러한 설정을 최상의 방식으로 작성하는 데 필요한 코드를 취했습니다. 따라서 create-react-app의 일부 코드가 표시됩니다.

데모 저장소

완벽한 예를 보고 싶다면, 제가 시연용 상용구를 만들었습니다. https://github.com/tabsteveyang/react-jest-rtl-boilerplate

구성 설정

 

종속성

이것들은 당신에게 필요한 패키지입니다. 별도로 설치하거나 아래 코드를 패키지의 devDependencies 블록에 추가할 수 있습니다.json 파일 및 설치:

"babel-preset-react-app": "^10.0.0",
  "react-app-polyfill": "^2.0.0",
    "react-test-renderer": "^17.0.2",   // (optional) for snapshot test
      "redux-mock-store": "^1.5.4",       // (optional) for mocking redux
        "babel-jest": "^26.6.0",
          "@testing-library/jest-dom": "^5.14.1",
            "@testing-library/react": "^11.2.7",
              "@testing-library/user-event": "^12.8.3",
                "jest": "26.6.0",
                  "jest-circus": "26.6.0",
                    "jest-resolve": "26.6.0",
                      "jest-watch-typeahead": "0.6.1"

진입점

1. 진입점의 파일

 

이것은 환경 변수를 설정하고 명령으로부터 인수를 받은 후 테스트를 시작하기 위해 농담하는 JS 파일입니다.

// jest/scripts/test.js
process.env.BABEL_ENV = 'test'
process.env.NODE_ENV = 'test'
process.env.PUBLIC_URL = ''
const jest = require('jest')
const argv = process.argv.slice(2)
jest.run(argv)

2. 스크립트 업데이트

패키지에서 스크립트 블록의 테스트 특성을 업데이트합니다.json 파일을 사용하면 npm run test를 실행하여 테스트를 시작할 수 있습니다.

"scripts": {
    "test": "node jest/scripts/test.js",
}
 

3. 변환을 위한 JS 파일

JS 파일은 jest가 사용할 수 있는 형태로 특정 확장자의 파일을 변환하기 위한 것이다.

  • babelTransform.js
'use strict'
const babelJest = require('babel-jest')
const hasJsxRuntime = (() => {
    if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
          return false
    }
    try {
          require.resolve('react/jsx-runtime')
          return true
    } catch (e) {
          return false
    }
})()
module.exports = babelJest.createTransformer({
    presets: [
          [
                  require.resolve('babel-preset-react-app'),
            {
                      runtime: hasJsxRuntime ? 'automatic' : 'classic'
            }
                ]
        ],
    babelrc: false,
    configFile: false
})
  • cssTransform.js
 
'use strict'
// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
    process() {
          return 'module.exports = {};'
    },
    getCacheKey() {
          // The output is always the same.
          return 'cssTransform'
    }
}
  • 파일Transform.js
'use strict'
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};`
    }
}

4. 테스트를 실행하기 전에 실행되는 JS 파일

테스트를 실행하기 전에 실행해야 하는 모든 논리를 넣을 파일을 만듭니다. 일반적으로 설정이라고 합니다.tests.js 및 파일의 코드는 다음과 같아야 합니다.

 
// import the modules that most tests will need
import '@testing-library/jest-dom'
import React from 'react'
import ReactDom from 'react-dom'
import PropTypes from 'prop-types'
// if there are some settings like below in your webpack.config.js, you can mock it in this way:
// new webpack.ProvidePlugin({
//   React: 'react',
//   ReactDom: 'react-dom',
//   PropTypes: 'prop-types'
// })
global.React = React
global.ReactDom = ReactDom
global.PropTypes = PropTypes

5. Jest 구성

위의 단계를 마친 후, 우리는 마침내 장난삼아 구성을 작성하고 모든 설정을 연결할 수 있습니다!

서류에 따르면 제이에스트의 구성을 패키지에 넣을 수 있습니다.json 파일 또는 jest.config.js 파일. 구성에 변수를 사용하고 패키지를 보관해야 할 경우를 대비해서 jeast.config.js 파일에 설정을 넣기로 했어요.json 파일을 정리합니다.

module.exports = {
    roots: [
          '<rootDir>/src'
        ],
    collectCoverageFrom: [
          'src/**/*.{js,jsx,ts,tsx}',
          '!src/**/*.d.ts'
        ],
    setupFiles: [
          'react-app-polyfill/jsdom'
        ],
    setupFilesAfterEnv: [
          '<rootDir>/jest/scripts/setupTests.js'
        ],
    testMatch: [
          '<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}',
          '<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}'
        ],
    testEnvironment: 'jsdom',
    transform: {
          '^.+\\.(js|jsx|mjs|cjs|ts|tsx)$': '<rootDir>/jest/transforms/babelTransform.js',
          '^.+\\.css$': '<rootDir>/jest/transforms/cssTransform.js',
          '^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)': '<rootDir>/jest/transforms/fileTransform.js'
    },
    transformIgnorePatterns: [
          '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$',
          '^.+\\.module\\.(css|sass|scss)$'
        ],
    modulePaths: [],
    moduleFileExtensions: [
          'web.js',
          'js',
          'web.ts',
          'ts',
          'web.tsx',
          'tsx',
          'json',
          'web.jsx',
          'jsx',
          'node'
        ],
    watchPlugins: [
          'jest-watch-typeahead/filename',
          'jest-watch-typeahead/testname'
        ],
    resetMocks: true
}
 

웹 팩.config.js 파일에 별칭을 선언했다고 가정합니다. 이 경우 테스트를 실행할 때 별칭이 작동하도록 moduleNameMapper 설정을 추가해야 할 수도 있습니다.

moduleNameMapper: {
    '^@js(.*)$': '<rootDir>/src/js$1',
        '^@scss(.*)$': '<rootDir>/src/scss$1',
            '^@img(.*)$': '<rootDir>/img$1'
},

설정 확인을 위한 첫 번째 테스트 파일

마지막으로 모든 설정을 마친 후 간단한 테스트 파일을 생성하여 예상대로 작동하는지 확인할 수 있습니다.

// src/js/components/_tests_/TestPage.test.jsx,
// for testing: src/js/components/TestPage.jsx file.
import { render, screen } from '@testing-library/react'
import TestPage from '../TestPage'
test('renders Hello World', () => {
    render(<TestPage />)
             const linkElement = screen.getByText(/Hello World/i)
    expect(linkElement).toBeInTheDocument()
})
 

그리고 명령행에서 명령을 실행하여 테스트를 시작합니다.

cd <project_path>
  npm run test

jeast와 상호 작용하려면 코드를 대신 실행할 수 있습니다.
프로세스가 테스트 후 종료되지 않고 사용자가 프로세스를 닫을 때까지 대기합니다.

node run test -- --watch
or
node jest/scripts/test.js --watch

아래 답변을 받으시면 다 준비되었습니다!

 

끝내기

리액트 구성 요소의 유닛 테스트를 위한 환경 설정은 간단한 작업이 아니기 때문에 최종적으로 작동 방법을 파악한 단계를 기록하기로 했습니다.

안타깝게도, 시험지를 작성하는 것 또한 까다롭습니다. 어떻게 대처해야 할지 고민하는 재미가 있지만, 그래도 구체적인 시나리오를 테스트하기 위해 실제로 할 수 있는 것을 더 많이 얻을 수 있었으면 좋겠다. 그래서 저는 고민하면서 얻은 경험을 공유하기 위해 또 다른 글을 쓸 것입니다

 

댓글