Skip to content

Vue-i18n-jest

vue-jest transformer for i18n custom blocks.

vue i18n을 SFC로 사용하고 있을 때, vue test utils에서 jestmocking 객체로 사용해도 언어 테이블이 불려지지 않는 현상을 해결하는 vue-jest Transformer.

Usage

vue-jest의 transform에 vue-i18n-jest를 넘기면 된다.

WARNING

@vue/vue2-jest를 설치해도 3번째 줄의 vue-jest이름을 변경해선 안된다

module.exports = {
  globals: {
    'vue-jest': {
      transform: {
        'i18n': 'vue-i18n-jest'
      }
    }
  }
}

Examples

vue i18n, jest, vue test utils를 조합한 테스트 방법: 1

INFORMATION

참고로 vue-test-utils는 vue-cli의 플러그인에서 사용되며, vue-cli플러그인은 vue-jest를 함께 사용한다.

package.json

{
  "name": "@recc/recc_plugin_annotation",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build --no-clean --dest ../recc_plugin_annotation/www",
    "test:unit": "vue-cli-service test:unit",
    "test:e2e": "vue-cli-service test:e2e",
    "lint": "vue-cli-service lint"
  },
  "dependencies": {
    "@recc/api": "^2.0.0-dev9-2",
    "core-js": "^3.8.3",
    "global": "^4.4.0",
    "register-service-worker": "^1.7.2",
    "vue": "^2.6.14",
    "vue-class-component": "^7.2.3",
    "vue-i18n": "^8.26.3",
    "vue-property-decorator": "^9.1.2",
    "vue-router": "^3.5.1",
    "vuetify": "^2.6.0",
    "vuex": "^3.6.2"
  },
  "devDependencies": {
    "@intlify/vue-i18n-loader": "^1.1.0",
    "@mdi/js": "^6.6.96",
    "@types/jest": "^27.0.1",
    "@typescript-eslint/eslint-plugin": "^5.4.0",
    "@typescript-eslint/parser": "^5.4.0",
    "@vue/cli-plugin-babel": "~5.0.0",
    "@vue/cli-plugin-e2e-cypress": "~5.0.0",
    "@vue/cli-plugin-eslint": "~5.0.0",
    "@vue/cli-plugin-pwa": "~5.0.0",
    "@vue/cli-plugin-router": "~5.0.0",
    "@vue/cli-plugin-typescript": "~5.0.0",
    "@vue/cli-plugin-unit-jest": "~5.0.0",
    "@vue/cli-plugin-vuex": "~5.0.0",
    "@vue/cli-service": "~5.0.0",
    "@vue/eslint-config-typescript": "^9.1.0",
    "@vue/test-utils": "^1.1.3",
    "@vue/vue2-jest": "^27.0.0-alpha.2",
    "babel-jest": "^27.0.6",
    "cypress": "^8.3.0",
    "eslint": "^7.32.0",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-vue": "^8.0.3",
    "jest": "^27.0.5",
    "lint-staged": "^11.1.2",
    "prettier": "^2.6.2",
    "roboto-fontface": "^0.10.0",
    "sass": "^1.32.7",
    "sass-loader": "^12.0.0",
    "ts-jest": "^27.0.4",
    "typescript": "~4.5.5",
    "vue-cli-plugin-i18n": "~2.3.1",
    "vue-cli-plugin-vuetify": "~2.4.8",
    "vue-i18n-jest": "^1.1.1",
    "vue-template-compiler": "^2.6.14",
    "vuetify-loader": "^1.7.0"
  },
  "eslintConfig": {
    "root": true,
    "env": {
      "node": true
    },
    "extends": [
      "plugin:vue/essential",
      "eslint:recommended",
      "@vue/typescript/recommended",
      "plugin:prettier/recommended"
    ],
    "parserOptions": {
      "ecmaVersion": 2020
    },
    "rules": {},
    "overrides": [
      {
        "files": [
          "**/__tests__/*.{j,t}s?(x)",
          "**/tests/unit/**/*.spec.{j,t}s?(x)"
        ],
        "env": {
          "jest": true
        }
      }
    ]
  },
  "prettier": {
    "printWidth": 88,
    "tabWidth": 2,
    "useTabs": false,
    "semi": true,
    "singleQuote": true,
    "quoteProps": "as-needed",
    "trailingComma": "all",
    "bracketSpacing": false,
    "bracketSameLine": false,
    "arrowParens": "avoid",
    "htmlWhitespaceSensitivity": "ignore",
    "vueIndentScriptAndStyle": false,
    "endOfLine": "lf"
  },
  "browserslist": [
    "> 1%",
    "last 2 versions",
    "not dead"
  ],
  "jest": {
    "preset": "@vue/cli-plugin-unit-jest/presets/typescript-and-babel",
    "globals": {
      "vue-jest": {
        "transform": {
          "i18n": "vue-i18n-jest"
        }
      }
    },
    "setupFiles": [
      "./tests/unit/setup.ts"
    ]
  },
  "gitHooks": {
    "pre-commit": "lint-staged"
  },
  "lint-staged": {
    "*.{js,jsx,vue,ts,tsx}": "vue-cli-service lint"
  }
}

src/views/HomeView.vue

<template>
  <hello-answer
    title="ANSWER PLUGIN"
    @change:dark="onChangeDark"
    @change:lang="onChangeLang"
  ></hello-answer>
</template>

<script lang="ts">
import {Vue, Component} from 'vue-property-decorator';
import HelloAnswer from '@/components/HelloAnswer.vue';

@Component({
  components: {
    HelloAnswer,
  },
})
export default class HomeView extends Vue {
  onChangeDark(dark: boolean) {
    this.$vuetify.theme.dark = dark;
  }

  onChangeLang(lang: string) {
    this.$i18n.locale = lang;
    this.$vuetify.lang.current = lang;
  }
}
</script>

tests/unit/setup.ts

import Vue from 'vue';
import Vuetify from 'vuetify';
import VueI18n from 'vue-i18n';
import VueRouter from 'vue-router';
import Vuex from 'vuex';

Vue.use(Vuetify);
Vue.use(VueI18n);
Vue.use(VueRouter);
Vue.use(Vuex);

tests/unit/HomeView.spec.ts

import {createLocalVue, shallowMount} from '@vue/test-utils';
import VueRouter from 'vue-router';
import {Store} from 'vuex';
import Vuetify from 'vuetify';
import VueI18n from 'vue-i18n';
import HelloAnswer from '@/components/HelloAnswer.vue';

describe('HelloAnswer.vue', () => {
  const localVue = createLocalVue();

  let router!: VueRouter;
  let store!: Store<object>;
  let vuetify!: Vuetify;
  let i18n!: VueI18n;

  beforeEach(() => {
    router = new VueRouter({});
    store = new Store({});
    vuetify = new Vuetify({});
    i18n = new VueI18n({silentTranslationWarn: true});
  });

  it('title props', () => {
    const title = 'TEST TITLE';
    const helloTitle = `Welcom to ${title}!`;
    const wrapper = shallowMount(HelloAnswer, {
      localVue,
      router,
      store,
      vuetify,
      i18n,
      propsData: {title},
    });

    expect(wrapper.find('.hello-answer').text()).toMatch(helloTitle);
  });
});

See also

Favorite site

References


  1. recc의 플러그인 프로젝트에 사용됨. recc-plugin-annotation