# Vue Test Utils
λ·° ν μ€νΈ μ νΈ(Vue Test Utils (opens new window))μ μ½μ΄ ν λ©€λ²κ° μ μν ν μ€ν 보쑰 λΌμ΄λΈλ¬λ¦¬μ λλ€. μ μ€νΈ(Jest) λΏλ§ μλλΌ λ€λ₯Έ ν μ€νΈ λꡬλ μ¬μ©ν μ μμ΅λλ€.
# μ΅μ Vue-CLI (3.x λ²μ  μ΄μ)μμ μ€μΉ λ°©λ²
μλ‘μ΄ νλ‘μ νΈμ κ²½μ° κΈ°λ³Έ νκ²½μ΄ μ€μ λ κΈ°λ³Έ ν리μ
(Default)μ μ¬μ©ν  μ μμ§λ§, λ·° ν
μ€νΈ μ νΈμ μ€μΉνκΈ° μν΄ μλμΒ κ°μ΄ ManuallyΒ selectΒ features μ΅μ
μΒ μ νν΄μ€λλ€.

λ·° ν μ€νΈ μ νΈμ μ€μΉνκΈ° μν΄ Unit Testing μ΅μ μ μ νν΄μ€λλ€.

TIP
λ°©ν₯ν€(β, β)λ‘ νλͺ©μ μ΄λν  μ μκ³  space ν€λ‘ μ ν/ν΄μ , enter ν€λ‘ κ²°μ ν  μ μμ΅λλ€.
# Vue CLI μ΅μ  μ ν
Unit Testing μ΅μ μ μΆκ°νκ³ λλ©΄ μλμ κ°μ΄ μ°¨λ‘λλ‘ μ νν©λλ€.
- λ¨Όμ  μ½λ μ 리 λκ΅¬μΈ Prettierμ λ¬Έλ² κ²μ¬ λκ΅¬μΈ ESLintλ₯Ό μ νν©λλ€.
 

- λ€μμ λ¬Έλ² κ²μ¬ λꡬμ μ€ν μμ μ μ νν©λλ€. μλν°μμ μ μ₯μ λλ₯Ό λλ§λ€ κ²μ¬νλ κ²μΌλ‘ μ νν©λλ€.
 

- λ¨μ ν μ€νΈ λꡬλ μ μ€νΈλ‘ μ νν©λλ€.
 

- μμμ μΆκ°ν ESLintμ ν리ν°μ΄μ μ€μ  λ΄μ©μ package.jsonμ μΆκ°νμ§ μκ³ κ°λ³ μ€μ  νμΌμ κ΄λ¦¬ν©λλ€.
 

# κΈ°μ‘΄ Vue-CLI (2.x λ²μ  μ΄ν)μμ μ€μΉ λ°©λ²
μλμ λͺ λ Ήμ΄λ‘ λ·° ν μ€νΈ μ νΈ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ€μΉν©λλ€.
npm install jest @vue/test-utils vue-jest babel-jest --save-dev
μ λͺ
λ Ήμ΄λ‘ vue test util, jest, vue-jest, babel-jest 4κ°μ λΌμ΄λΈλ¬λ¦¬κ° μ€μΉλ©λλ€.
# babel μ¬μ©νκΈ°
νλ‘μ νΈμ λ°λ²¨(babel) (opens new window)μ μ€μ ν μ μ΄ μλ€λ©΄ μλμ κ°μ΄ μ€μΉν΄μ€λλ€.
npm install @babel/core @babel/preset-env babel-core@^7.0.0-bridge.0 --save-dev
λ°λ²¨μ μλ°μ€ν¬λ¦½νΈ(JavaScript) μ»΄νμΌλ¬λ‘μ μμ±ν μ΅μ μ½λ(ECMAScript 2015 λ²μ  μ΄μ)λ₯Ό μ΄μ  λ²μ (μ€λλ λΈλΌμ°μ  λλ νκ²½)μ νΈννμ¬ λμν μ μλλ‘ μ½λλ₯Ό λ³νν΄μ£Όλ λꡬμ λλ€. μλ₯Ό λ€μ΄ μλ μ½λμ κ°μ΄ ES2015+ λ‘ μμ±λ λ¬Έλ²μ μ΄μ  μλ°μ€ν¬λ¦½νΈ λ¬Έλ²μΌλ‘ λ³νν΄ μ€λλ€.
// λ°λ²¨ μ
λ ₯: ES2015 νμ΄ν ν¨μ
[1, 2, 3].map(n => n + 1);
// λ°λ²¨ μΆλ ₯: λ³νλ μ½λ
[1, 2, 3].map(function(n) {
  return n + 1;
});
λ°λ²¨ ν리μ
μ package.json λλ babel.config.json λλ babel.config.jsμμ μ€μ ν  μ μμ΅λλ€.
// package.json
{
  // ...
  "babel": {
    "presets": ["@babel/preset-env"]
  }
}
// babel.config.json
{
  "presets": ["@babel/preset-env"]
}
// babel.config.js
module.exports = {
  presets: ["@babel/preset-env"] // μλ μ€μ 
  presets: ["@vue/cli-plugin-babel/preset"] // vue cliλ‘ μ€μΉν κ²½μ° μλ μ€μ λ¨
};
μ μ€νΈμ κ΄λ ¨λ νκ²½ μ€μ μ μ μ€νΈ νκ²½ μ€μ  μμ νμΈν΄λ³΄μΈμ.
- transformμ babel-jest
 
# μΉν©(Webpack) λ³μΉ(Alias) μ¬μ©
// package.json
{
  "jest": {
    "moduleNameMapper": {
      // λ³μΉ @(νλ‘μ νΈ/src) μ¬μ©νμ¬ νμ κ²½λ‘μ νμΌμ λ§΅νν©λλ€
      "^@/(.*)$": "<rootDir>/src/$1"
    }
  }
}
// jest.config.js
module.exports = {
  moduleNameMapper: {
    // λ³μΉ @(νλ‘μ νΈ/src) μ¬μ©νμ¬ νμ κ²½λ‘μ νμΌμ λ§΅νν©λλ€
    '^@/(.*)$': '<rootDir>/src/$1'
  },
};
νλ‘μ νΈ κ²½λ‘/src κΉμ§ κ²½λ‘λ₯Ό @ λ³μΉμΌλ‘ λ§΅νν©λλ€.
// 'νλ‘μ νΈ κ²½λ‘/src/' νμμ μ‘΄μ¬νλ νμΌμ μλμ κ°μ΄ κ°μννμ¬ μμ±ν  μ μμ΅λλ€
import HelloWorld from "@/components/HelloWorld.vue";
TIP
νλ‘μ νΈμ μΉν©μ μ¬μ© μ€μ΄κ³ λ³μΉμ μ¬μ©νλ€λ©΄ μ μ€νΈ νκ²½ μ€μ  μλ λμΌνκ² μΆκ°ν΄μ€μΌ ν©λλ€. μΉν©κ³Ό μκ΄μμ΄ ν μ€νΈ μ½λλ₯Ό μν΄ λ³μΉμ μ¬μ©νλ λ°©μλ μΌκ΄μ± μλ κ²½λ‘λ₯Ό μ¬μ©ν μ μμ΄μ μ’μ΅λλ€.
# μ½λ 컀λ²λ¦¬μ§(Code Coverage)
μ μ€νΈλ ν μ€νΈμ μ±κ³΅, μ€ν¨ κ°μλ₯Ό λνλ΄λ κ²°κ³ΌλΏλ§ μλλΌ ν μ€νΈ 컀λ²λ¦¬μ§λ₯Ό λνλ΄λ μ§ν λ³΄κ³ μλ μμ±ν μ μμ΅λλ€.
μλμ κ°μ΄ μ μ€νΈ νκ²½ μ€μ  μ μ μ©ν ν
// packages.json
{
  "jest": {
    "collectCoverage": true,
    "collectCoverageFrom": [
      "**/*.{js,vue}",
      "!**/node_modules/**"
    ]
  }
}
// jest.config.js
module.exports = {
  collectCoverage: true,
  collectCoverageFrom: [
    '**/*.{js,vue}',
    '!**/node_modules/**'
  ]
};
ν μ€νΈλ₯Ό μ€νν΄λ³΄λ©΄ ν°λ―Έλμ μλμ κ°μ΄ ν νμμΌλ‘ κ²°κ³Όλ₯Ό 보μ¬μ€λλ€.
 PASS  tests/unit/example.spec.js
  HelloWorld.vue
    β renders props.msg when passed (14ms)
----------|----------|----------|----------|----------|-------------------|
File      |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files |        0 |        0 |        0 |        0 |                   |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.628s
Ran all test suites.
Done in 2.46s.
κ° μ»€λ²λ¦¬μ§ νλͺ©μ μ€λͺ
- Stmts: μ΅μ ν λ² μ΄μ μ€νλ λͺ λ Ήλ¬Έ(λ³μμ κ° μ μ₯, ν¨μ νΈμΆ λ±) μ½λμ λΉμ¨
 - Branch: μ΅μ ν λ² μ΄μ if, switchμ κ°μ λΆκΈ° μ‘°κ±΄μ΄ μΆ©μ‘±λ λΉμ¨
 - Funcs: μ΅μ ν λ² μ΄μ νΈμΆλ ν¨μμ λΉμ¨
 - Lines: μ΅μ ν λ² μ΄μ μ€νλ μ½λ λΌμΈμ λΉμ¨
 - Uncovered Line: μ½λ 컀λ²λ¦¬μ§μ μΈ‘μ λμ§ μμ μ½λ λΌμΈ μ
 
# μ μ€νΈ νκ²½ μ€μ 
package.json μμ μ€μ  νκ±°λ  jest.config.js μμ μ€μ  ν  μ μμ΅λλ€.
# package.json μ€μ 
μ€μΉνκ³  λμ package.json νμΌμ μλμ μ΅μ
μ μΆκ°ν©λλ€.
{
  // ...
  "jest": {
    // vue-cli ν
μ€νΈ νκ²½ μ€μ μ μ¬μ©ν©λλ€
    // μ£Όμ! preset μ§μ  ν μλμ κ°μ΄ κ°κ° λ€μ μ€μ νλ κ²½μ°, μλ‘ μ€μ ν λ΄μ©μΌλ‘ μ μ©λ©λλ€
    "preset": "@vue/cli-plugin-unit-jest",
    "moduleFileExtensions": [
      "js",
      "json",
      // λͺ¨λ  vue νμΌ(`*.vue`)μ μ²λ¦¬νκΈ° μν΄ Jestμκ² μλ €μ€λλ€
      "vue"
    ],
    "transform": {
      // `vue-jest`λ₯Ό μ¬μ©νμ¬ λͺ¨λ  vue νμΌ(`*.vue`)μ μ²λ¦¬ν©λλ€
      ".*\\.(vue)$": "vue-jest",
      // `babel-jest`λ₯Ό μ¬μ©νμ¬ λͺ¨λ  js νμΌ(`*.js`)μ μ²λ¦¬ν©λλ€
      ".*\\.(js)$": "babel-jest",
    },
    "moduleNameMapper": {
      // λ³μΉ @(νλ‘μ νΈ/src) μ¬μ©νμ¬ νμ κ²½λ‘μ νμΌμ λ§΅νν©λλ€
      "^@/(.*)$": "<rootDir>/src/$1"
    },
    "testMatch": [
      // __tests__ κ²½λ‘ νμμ μλ λͺ¨λ  js/ts/jsx/tsx νμΌμ ν
μ€νΈ λμμΌλ‘ μ§μ ν©λλ€
      "**/__tests__/**/*.[jt]s?(x)",
      // νμΌ μ΄λ¦μ 'xxx.spec' λλ 'xxx.test'λΌλ μ΄λ¦μ΄ λΆμ¬μΈ λͺ¨λ  js/ts/jsx/tsx νμΌμ ν
μ€νΈ λμμΌλ‘ μ§μ ν©λλ€
      "**/?(*.)+(spec|test).[jt]s?(x)"
    ],
    // node_modules κ²½λ‘ νμμ μλ λͺ¨λ  ν
μ€νΈ νμΌμ λμμμ μ μΈν©λλ€
    "testPathIgnorePatterns": ["/node_modules/"],
    "collectCoverage": true,
    "collectCoverageFrom": [
      "**/*.{js,vue}",
      "!**/node_modules/**"
    ]
  }
}
WARNING
JSON νμΌμ΄λ―λ‘ λ³΅μ¬ν΄ λΆμ¬λ£μ λ μ£Όμμ μ κ±°ν΄μ£ΌμΈμ.
# jest.config.js μ€μ 
Vue-CLIλ₯Ό μ΄μ©νμ¬ Unit Testingμ μ ννλ€λ©΄ jest.config.js νμΌμ μλμΌλ‘ μμ±ν©λλ€. npmμΌλ‘ μ§μ  μ€μΉνκ±°λ, μμ§ νμΌμ΄ μ‘΄μ¬νμ§ μλλ€λ©΄ νλ‘μ νΈ κ²½λ‘(μ΅μμ)μ jest.config.js νμΌμ μμ±ν΄μ€λλ€.
module.exports = {
  // (vue-cliλ‘ μ€μΉ μ κΈ°λ³Έ μΈν
λ¨) vue-cli ν
μ€νΈ νκ²½ μ€μ μ μ¬μ©ν©λλ€
  // μ£Όμ! preset μ§μ  ν μλμ κ°μ΄ κ°κ° λ€μ μ€μ νλ κ²½μ°, μλ‘ μ€μ ν λ΄μ©μΌλ‘ μ μ©λ©λλ€
  preset: "@vue/cli-plugin-unit-jest",
  moduleFileExtensions: [
    'js',
    'json',
    // λͺ¨λ  vue νμΌ(`*.vue`)μ μ²λ¦¬νκΈ° μν΄ Jestμκ² μλ €μ€λλ€
    'vue',
  ],
  transform: {
    // `vue-jest`λ₯Ό μ¬μ©νμ¬ λͺ¨λ  vue νμΌ(`*.vue`)μ μ²λ¦¬ν©λλ€
    '.*\\.(vue)$': 'vue-jest',
    // `babel-jest`λ₯Ό μ¬μ©νμ¬ λͺ¨λ  js νμΌ(`*.js`)μ μ²λ¦¬ν©λλ€
    '.*\\.(js)$': 'babel-jest',
  },
  moduleNameMapper: {
    // λ³μΉ @(νλ‘μ νΈ/src) μ¬μ©νμ¬ νμ κ²½λ‘μ νμΌμ λ§΅νν©λλ€
    '^@/(.*)$': '<rootDir>/src/$1'
  },
  testMatch: [
    // __tests__ κ²½λ‘ νμμ μλ λͺ¨λ  js/ts/jsx/tsx νμΌμ ν
μ€νΈ λμμΌλ‘ μ§μ ν©λλ€
    '**/__tests__/**/*.[jt]s?(x)',
    // 'xxx.spec' λλ 'xxx.test'λΌλ μ΄λ¦μ λͺ¨λ  js/ts/jsx/tsx νμΌμ ν
μ€νΈ λμμΌλ‘ μ§μ ν©λλ€
    '**/?(*.)+(spec|test).[jt]s?(x)'
  ],
  // node_modules κ²½λ‘ νμμ μλ λͺ¨λ  ν
μ€νΈ νμΌμ λμμμ μ μΈν©λλ€
  testPathIgnorePatterns: ['/node_modules/'],
  collectCoverage: true,
  collectCoverageFrom: [
    '**/*.{js,vue}',
    '!**/node_modules/**'
  ],
};
TIP
jest.config.js νμΌλ‘ λΆλ¦¬νλ©΄ νκ²½ μ€μ  λΆλΆλ§ λͺ¨μλμ μ μμ΄μ μ μ§λ³΄μκ° μ¬μμ§λλ€. μλ°μ€ν¬λ¦½νΈ νμΌμ΄λ―λ‘ μ£Όμ μμ±λ κ°λ₯ν©λλ€.
κ° μ€μ μ λν μμΈ μ€λͺ
preset
- μ΄λ―Έ ν μ€νΈμ νμν κΈ°λ³Έ μ€μ μ κ°μΆ μΈλΆ νκ²½ μ€μ μ μ¬μ©ν©λλ€.
 @vue/cli-plugin-unit-jestμ κ²½μ° vue-cli νκ²½μ λ§μΆ° κΈ°λ³Έμ μΌλ‘ μΈν λ ν μ€νΈ νκ²½ μ€μ μ μ¬μ©ν©λλ€.- κΈ°λ³Έμ μΌλ‘ μΈν νλ λ΄μ©μ vue-cli github (opens new window)μμ νμΈν΄λ³΄μΈμ.
 
moduleFileExtensions
- λͺ¨λμμ μ¬μ©ν νμΌ νμ₯λͺ μ μ§μ ν©λλ€.
 
transform
- λ³νκΈ°(transformer, μ°μΈ‘)λ₯Ό μ¬μ©νμ¬ μ§μ ν λμ(μ’μΈ‘)μ λ³νν©λλ€.
 
moduleNameMapper
- λͺ¨λ μ΄λ¦(μ°μΈ‘)μ νΉμ  μ΄λ¦(μ’μΈ‘)μΌλ‘ λ§΅ννμ¬ μΉνν©λλ€.
 '^@/(.*)$': '<rootDir>/src/$1'μμ$1μ μ’μΈ‘ μ κ· ννμ(Regular Expression) μ€(.*)μ μΉνλμ΄,<rootDir>/src/νμμ λͺ¨λ νμΌμ κ°λ¦¬ν΅λλ€.
testMatch
- ν μ€νΈ μ€ν μ λμμΌλ‘ ν¬ν¨μν¬ νμΌμ μ§μ ν©λλ€.
 
testPathIgnorePatterns
testMatchμμ μ§μ ν λμ μ€ μλμ μΌλ‘ ν μ€νΈ λμμμ μ μΈν κ²½λ‘ λλ νΉμ  ν¨ν΄μ κ°μ§ λμμ μ§μ ν©λλ€.node_modulesνμμλ λΌμ΄λΈλ¬λ¦¬ λͺ¨λμ΄ μ€μΉλμ΄ μμΌλ μΌλ°μ μΌλ‘ λμμμ μ μΈν©λλ€.
collectCoverage
- 컀λ²λ¦¬μ§ μ 보μ μμ§ μ¬λΆλ₯Ό μ€μ ν©λλ€.
 - ν
μ€νΈ 컀λ²λ¦¬μ§λ₯Ό λνλ΄λ μ§ν 보고μλ₯Ό μμ±ν©λλ€.
trueμΌ κ²½μ°, ν μ€νΈ μ€νν λλ§λ€ μλμΌλ‘ μμ±ν©λλ€.falseμΌ κ²½μ°, μ μ€νΈλ₯Ό λͺ λ Ήμ΄λ‘ μ€νν λ--coverageλ₯Ό ν¬ν¨ν΄μ£Όλ©΄ μμ±ν©λλ€.
 - κ²°κ³Όλ 
ν°λ―Έλλλνλ‘μ νΈ/lcov-report/index.htmlμ μ΄μ΄λ³΄λ©΄ νμΈν μ μμ΅λλ€. 
collectCoverageFrom
- 컀λ²λ¦¬μ§λ₯Ό μμ§ν λμμ μ§μ ν©λλ€.
 - μ μ€μ μ κ²½μ°, λͺ¨λ js νμΌκ³Ό vue νμΌμ λνμ¬ μμ§νλ©° node_modulesμ μ‘΄μ¬νλ νμΌμ λμμμ μ μΈν©λλ€.
 
μμΈν λ΄μ©μ Jest 곡μ λ¬Έμμ Configuring Jest (opens new window)μμ νμΈν΄λ³΄μΈμ.
μ΄μ  λ€μ μ±ν°μμ κ°λ¨ν ν μ€νΈ μ½λλ₯Ό μμ±ν΄λ³΄κ² μ΅λλ€.