8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

TypeScript で実装した Nuxt.js/Store をテストする

Posted at

TypeScript で実装した Nuxt.js/Store をテストしたい

成果物

出来上がりはこちらに
https://github.com/hirose504/nuxt-typescript-vuex-module-decorators-test

準備

create nuxt-app

$ yarn create nuxt-app nuxt-typescript-vuex-module-decorators-test
yarn create v1.21.1
create-nuxt-app v2.14.0
✨  Generating Nuxt.js project in nuxt-typescript-vuex-module-decorators-test
? Project name nuxt-typescript-vuex-module-decorators-test
? Project description My posh Nuxt.js project
? Author name hirose504
? Choose the package manager Yarn
? Choose UI framework None
? Choose custom server framework None (Recommended)
? Choose Nuxt.js modules (Press <space> to select, <a> to toggle all, <i> to invert selection)
? Choose linting tools ESLint, Prettier
? Choose test framework Jest
? Choose rendering mode Universal (SSR)
? Choose development tools jsconfig.json (Recommended for VS Code)

🎉  Successfully created project nuxt-typescript-vuex-module-decorators-test

  To get started:

	cd nuxt-typescript-vuex-module-decorators-test
	yarn dev

  To build & start for production:

	cd nuxt-typescript-vuex-module-decorators-test
	yarn build
	yarn start

  To test:

	cd nuxt-typescript-vuex-module-decorators-test
	yarn test

✨  Done in 182.69s.

typescript setup

https://typescript.nuxtjs.org/ja/guide/setup.html
https://typescript.nuxtjs.org/ja/guide/runtime.html
https://typescript.nuxtjs.org/ja/guide/lint.html

add vuex-module-decorators

$ yarn add vuex-module-decorators
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -9,6 +9,7 @@
       "esnext.asynciterable",
       "dom"
     ],
+    "experimentalDecorators": true,
     "esModuleInterop": true,
     "allowJs": true,
     "sourceMap": true,

add ts-jest

$ yarn add --dev ts-jest @types/jest
--- a/jest.config.js
+++ b/jest.config.js
@@ -4,14 +4,16 @@ module.exports = {
     '^~/(.*)$': '<rootDir>/$1',
     '^vue$': 'vue/dist/vue.common.js'
   },
-  moduleFileExtensions: ['js', 'vue', 'json'],
+  moduleFileExtensions: ['ts', 'js', 'vue', 'json'],
   transform: {
+    '^.+\\.ts$': 'ts-jest',
     '^.+\\.js$': 'babel-jest',
     '.*\\.(vue)$': 'vue-jest'
   },
   collectCoverage: true,
   collectCoverageFrom: [
     '<rootDir>/components/**/*.vue',
-    '<rootDir>/pages/**/*.vue'
+    '<rootDir>/pages/**/*.vue',
+    '<rootDir>/store/**/*.ts'
   ]
 }
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -26,7 +26,8 @@
     },
     "types": [
       "@types/node",
-      "@nuxt/types"
+      "@nuxt/types",
+      "@types/jest"
     ]
   },
   "exclude": [

実装

https://ja.nuxtjs.org/guide/vuex-store/ をベースに TypeScript で書く

types

~/types/index.d.ts
export type Todo = {
  text: string
  done: boolean
}

store

~/store/todos.ts
import { Module, VuexModule, Mutation } from 'vuex-module-decorators'
import { Todo } from '~/types'

@Module({ name: 'todos', stateFactory: true, namespaced: true })
export default class TodosModule extends VuexModule {
  list: Todo[] = []

  @Mutation
  add(text: string) {
    this.list.push({
      text,
      done: false
    })
  }

  @Mutation
  remove(todo: Todo) {
    this.list.splice(this.list.indexOf(todo), 1)
  }

  @Mutation
  toggle(todo: Todo) {
    todo.done = !todo.done
  }
}
~/store/index.ts
import { Store } from 'vuex'
import { initialiseStores } from '~/utils/store-accessor'
const initializer = (store: Store<any>) => initialiseStores(store)
export const plugins = [initializer]
export * from '~/utils/store-accessor'
~/utils/store-accessor.ts
/* eslint-disable import/no-mutable-exports */
import { Store } from 'vuex'
import { getModule } from 'vuex-module-decorators'
import TodosModule from '~/store/todos'

let todosStore: TodosModule

function initialiseStores(store: Store<any>): void {
  todosStore = getModule(TodosModule, store)
}

export { initialiseStores, todosStore }

pages

~/pages/todos.vue
<template>
  <ul>
    <li v-for="todo in todos" :key="todo.index">
      <input type="checkbox" :checked="todo.done" @change="toggle(todo)" />>
      <span :class="{ done: todo.done }">{{ todo.text }}</span>
    </li>
    <li>
      <input placeholder="What needs to be done?" @keyup.enter="addTodo" />
    </li>
  </ul>
</template>

<script>
import { mapMutations } from 'vuex'

export default {
  computed: {
    todos() {
      return this.$store.state.todos.list
    }
  },
  methods: {
    addTodo(e) {
      this.$store.commit('todos/add', e.target.value)
      e.target.value = ''
    },
    ...mapMutations({
      toggle: 'todos/toggle'
    })
  }
}
</script>

<style>
.done {
  text-decoration: line-through;
}
</style>

テスト

~/test/store/todos.test.ts
import { createStore } from '~/.nuxt/store'
import { initialiseStores, todosStore } from '~/utils/store-accessor'

describe('TodosModule', () => {
  beforeEach(() => {
    initialiseStores(createStore())
  })

  test('init', () => {
    expect(todosStore.list).toEqual([])
  })

  test('add', () => {
    todosStore.add('test')
    expect(todosStore.list).toEqual([{ text: 'test', done: false }])
  })

  test('remove', () => {
    todosStore.add('aaaa')
    todosStore.add('bbbb')
    todosStore.add('cccc')
    todosStore.remove(todosStore.list[1])
    expect(todosStore.list).toEqual([
      { text: 'aaaa', done: false },
      { text: 'cccc', done: false }
    ])
  })

  test('toggle', () => {
    todosStore.add('aaaa')
    todosStore.add('bbbb')
    todosStore.add('cccc')
    todosStore.toggle(todosStore.list[1])
    expect(todosStore.list).toEqual([
      { text: 'aaaa', done: false },
      { text: 'bbbb', done: true },
      { text: 'cccc', done: false }
    ])
  })
})

実行

$ yarn test                                                                                                           master
yarn run v1.21.1
$ jest
 PASS  test/store/todos.test.ts
 PASS  test/Logo.spec.js
------------|----------|----------|----------|----------|-------------------|
File        |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
------------|----------|----------|----------|----------|-------------------|
All files   |    70.83 |        0 |       60 |    66.67 |                   |
 components |      100 |      100 |      100 |      100 |                   |
  Logo.vue  |      100 |      100 |      100 |      100 |                   |
 pages      |        0 |        0 |        0 |        0 |                   |
  index.vue |        0 |      100 |        0 |        0 |              1,28 |
  todos.vue |        0 |        0 |        0 |        0 |     1,14,19,24,25 |
 store      |      100 |      100 |      100 |      100 |                   |
  index.ts  |      100 |      100 |      100 |      100 |                   |
  todos.ts  |      100 |      100 |      100 |      100 |                   |
------------|----------|----------|----------|----------|-------------------|

Test Suites: 2 passed, 2 total
Tests:       5 passed, 5 total
Snapshots:   0 total
Time:        5.098s
Ran all test suites.
✨  Done in 8.17s.
8
9
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
9

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?