diff --git a/front/package.json b/front/package.json
index e79ffcbebab4b40238fa5aa98eae3097b1b13b1f..2818757a3ff86411842020921c08c732ad25c47b 100644
--- a/front/package.json
+++ b/front/package.json
@@ -9,6 +9,7 @@
     "start": "node build/dev-server.js",
     "build": "node build/build.js",
     "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
+    "unit-watch": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js",
     "e2e": "node test/e2e/runner.js",
     "test": "npm run unit && npm run e2e",
     "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
diff --git a/front/src/store/auth.js b/front/src/store/auth.js
index d8bd197f33fabd1938fe65a5c71ca950314b663f..6021f30fa9c0d919e9a112ec02c8ca62f5025b1d 100644
--- a/front/src/store/auth.js
+++ b/front/src/store/auth.js
@@ -44,6 +44,7 @@ export default {
       state.token = value
       if (value) {
         state.tokenData = jwtDecode(value)
+        console.log(state.tokenData)
       } else {
         state.tokenData = {}
       }
diff --git a/front/src/store/player.js b/front/src/store/player.js
index 74b0b9f9ea72dcbc38d0c3cefc6fa90d1647fc49..9e50d6c194b2afa1afeb3c273607cdeed2d227eb 100644
--- a/front/src/store/player.js
+++ b/front/src/store/player.js
@@ -61,8 +61,8 @@ export default {
     }
   },
   actions: {
-    incrementVolume (context, value) {
-      context.commit('volume', context.state.volume + value)
+    incrementVolume ({commit, state}, value) {
+      commit('volume', state.volume + value)
     },
     stop (context) {
     },
diff --git a/front/test/unit/karma.conf.js b/front/test/unit/karma.conf.js
index da5a2187663e2479f48a0c2ccefac20927c0f049..47b46880704756d08b5654c074ad2aa44b91f8b4 100644
--- a/front/test/unit/karma.conf.js
+++ b/front/test/unit/karma.conf.js
@@ -21,7 +21,7 @@ module.exports = function (config) {
     preprocessors: {
       './index.js': ['webpack', 'sourcemap']
     },
-    captureTimeout: 5000,
+    captureTimeout: 15000,
     retryLimit: 1,
     webpack: webpackConfig,
     webpackMiddleware: {
diff --git a/front/test/unit/specs/store/auth.spec.js b/front/test/unit/specs/store/auth.spec.js
index 6ef558f6e0b0a89e252d2e46794221d5730d6299..8be2708f3324b60d533a190dc0d3d53fb665d588 100644
--- a/front/test/unit/specs/store/auth.spec.js
+++ b/front/test/unit/specs/store/auth.spec.js
@@ -1,52 +1,108 @@
-import store from '@/store/player'
+import store from '@/store/auth'
 
-describe('mutations', () => {
-  it('set volume', () => {
-    // mock state
-    const state = { volume: 0 }
-    // apply mutation
-    store.mutations.volume(state, 0.9)
-    // assert result
-    expect(state.volume).to.equal(0.9)
-  })
-  it('set volume max 1', () => {
-    // mock state
-    const state = { volume: 0 }
-    // apply mutation
-    store.mutations.volume(state, 2)
-    // assert result
-    expect(state.volume).to.equal(1)
-  })
-  it('set volume min to 0', () => {
-    // mock state
-    const state = { volume: 0.5 }
-    // apply mutation
-    store.mutations.volume(state, -2)
-    // assert result
-    expect(state.volume).to.equal(0)
-  })
-  it('increment volume', () => {
-    // mock state
-    const state = { volume: 0 }
-    // apply mutation
-    store.mutations.incrementVolume(state, 0.1)
-    // assert result
-    expect(state.volume).to.equal(0.1)
+import { testAction } from '../../utils'
+
+describe('store/auth', () => {
+  describe('mutations', () => {
+    it('profile', () => {
+      const state = {}
+      store.mutations.profile(state, {})
+      expect(state.profile).to.deep.equal({})
+    })
+    it('username', () => {
+      const state = {}
+      store.mutations.username(state, 'world')
+      expect(state.username).to.equal('world')
+    })
+    it('authenticated true', () => {
+      const state = {}
+      store.mutations.authenticated(state, true)
+      expect(state.authenticated).to.equal(true)
+    })
+    it('authenticated false', () => {
+      const state = {
+        username: 'dummy',
+        token: 'dummy',
+        tokenData: 'dummy',
+        profile: 'dummy',
+        availablePermissions: 'dummy'
+      }
+      store.mutations.authenticated(state, false)
+      expect(state.authenticated).to.equal(false)
+      expect(state.username).to.equal(null)
+      expect(state.token).to.equal(null)
+      expect(state.tokenData).to.equal(null)
+      expect(state.profile).to.equal(null)
+      expect(state.availablePermissions).to.deep.equal({})
+    })
+    it('token null', () => {
+      const state = {}
+      store.mutations.token(state, null)
+      expect(state.token).to.equal(null)
+      expect(state.tokenData).to.deep.equal({})
+    })
+    it('token real', () => {
+      // generated on http://kjur.github.io/jsjws/tool_jwt.html
+      const state = {}
+      let token = 'eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2p3dC1pZHAuZXhhbXBsZS5jb20iLCJzdWIiOiJtYWlsdG86bWlrZUBleGFtcGxlLmNvbSIsIm5iZiI6MTUxNTUzMzQyOSwiZXhwIjoxNTE1NTM3MDI5LCJpYXQiOjE1MTU1MzM0MjksImp0aSI6ImlkMTIzNDU2IiwidHlwIjoiaHR0cHM6Ly9leGFtcGxlLmNvbS9yZWdpc3RlciJ9.'
+      let tokenData = {
+        iss: 'https://jwt-idp.example.com',
+        sub: 'mailto:mike@example.com',
+        nbf: 1515533429,
+        exp: 1515537029,
+        iat: 1515533429,
+        jti: 'id123456',
+        typ: 'https://example.com/register'
+      }
+      store.mutations.token(state, token)
+      expect(state.token).to.equal(token)
+      expect(state.tokenData).to.deep.equal(tokenData)
+    })
+    it('permissions', () => {
+      const state = { availablePermissions: {} }
+      store.mutations.permission(state, {key: 'admin', status: true})
+      expect(state.availablePermissions).to.deep.equal({admin: true})
+    })
   })
-  it('increment volume max 1', () => {
-    // mock state
-    const state = { volume: 0 }
-    // apply mutation
-    store.mutations.incrementVolume(state, 2)
-    // assert result
-    expect(state.volume).to.equal(1)
+  describe('getters', () => {
+    it('header', () => {
+      const state = { token: 'helloworld' }
+      expect(store.getters['header'](state)).to.equal('JWT helloworld')
+    })
   })
-  it('increment volume min to 0', () => {
-    // mock state
-    const state = { volume: 0.5 }
-    // apply mutation
-    store.mutations.incrementVolume(state, -2)
-    // assert result
-    expect(state.volume).to.equal(0)
+  describe('actions', () => {
+    it('logout', (done) => {
+      testAction({
+        action: store.actions.logout,
+        params: {state: {}},
+        expectedMutations: [
+          { type: 'authenticated', payload: false }
+        ]
+      }, done)
+    })
+    it('check jwt null', (done) => {
+      testAction({
+        action: store.actions.check,
+        params: {state: {}},
+        expectedMutations: [
+          { type: 'authenticated', payload: false }
+        ]
+      }, done)
+    })
+    it('check jwt set', (done) => {
+      testAction({
+        action: store.actions.check,
+        params: {state: {token: 'test', username: 'user'}},
+        expectedMutations: [
+          { type: 'authenticated', payload: true },
+          { type: 'username', payload: 'user' },
+          { type: 'token', payload: 'test' }
+        ],
+        expectedActions: [
+          { type: 'fetchProfile' },
+          { type: 'refreshToken' }
+        ]
+      }, done)
+    })
   })
 })
diff --git a/front/test/unit/specs/store/favorites.spec.js b/front/test/unit/specs/store/favorites.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..6d4314ca661a2ffbb3865d3a4edc53a2b40b1cc8
--- /dev/null
+++ b/front/test/unit/specs/store/favorites.spec.js
@@ -0,0 +1,52 @@
+import store from '@/store/favorites'
+
+import { testAction } from '../../utils'
+
+describe('store/favorites', () => {
+  describe('mutations', () => {
+    it('track true', () => {
+      const state = { tracks: [] }
+      store.mutations.track(state, {id: 1, value: true})
+      expect(state.tracks).to.deep.equal([1])
+      expect(state.count).to.deep.equal(1)
+    })
+    it('track false', () => {
+      const state = { tracks: [1] }
+      store.mutations.track(state, {id: 1, value: false})
+      expect(state.tracks).to.deep.equal([])
+      expect(state.count).to.deep.equal(0)
+    })
+  })
+  describe('getters', () => {
+    it('isFavorite true', () => {
+      const state = { tracks: [1] }
+      expect(store.getters['isFavorite'](state)(1)).to.equal(true)
+    })
+    it('isFavorite false', () => {
+      const state = { tracks: [] }
+      expect(store.getters['isFavorite'](state)(1)).to.equal(false)
+    })
+  })
+  describe('actions', () => {
+    it('toggle true', (done) => {
+      testAction({
+        action: store.actions.toggle,
+        payload: 1,
+        params: {getters: {isFavorite: () => false}},
+        expectedActions: [
+          { type: 'set', payload: {id: 1, value: true} }
+        ]
+      }, done)
+    })
+    it('toggle true', (done) => {
+      testAction({
+        action: store.actions.toggle,
+        payload: 1,
+        params: {getters: {isFavorite: () => true}},
+        expectedActions: [
+          { type: 'set', payload: {id: 1, value: false} }
+        ]
+      }, done)
+    })
+  })
+})
diff --git a/front/test/unit/specs/store/player.spec.js b/front/test/unit/specs/store/player.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..af0b6b4354394dbc9c1c62186796e62653ca52fb
--- /dev/null
+++ b/front/test/unit/specs/store/player.spec.js
@@ -0,0 +1,153 @@
+import store from '@/store/player'
+
+import { testAction } from '../../utils'
+
+describe('store/player', () => {
+  describe('mutations', () => {
+    it('set volume', () => {
+      const state = { volume: 0 }
+      store.mutations.volume(state, 0.9)
+      expect(state.volume).to.equal(0.9)
+    })
+    it('set volume max 1', () => {
+      const state = { volume: 0 }
+      store.mutations.volume(state, 2)
+      expect(state.volume).to.equal(1)
+    })
+    it('set volume min to 0', () => {
+      const state = { volume: 0.5 }
+      store.mutations.volume(state, -2)
+      expect(state.volume).to.equal(0)
+    })
+    it('increment volume', () => {
+      const state = { volume: 0 }
+      store.mutations.incrementVolume(state, 0.1)
+      expect(state.volume).to.equal(0.1)
+    })
+    it('increment volume max 1', () => {
+      const state = { volume: 0 }
+      store.mutations.incrementVolume(state, 2)
+      expect(state.volume).to.equal(1)
+    })
+    it('increment volume min to 0', () => {
+      const state = { volume: 0.5 }
+      store.mutations.incrementVolume(state, -2)
+      expect(state.volume).to.equal(0)
+    })
+    it('set duration', () => {
+      const state = { duration: 42 }
+      store.mutations.duration(state, 14)
+      expect(state.duration).to.equal(14)
+    })
+    it('set errored', () => {
+      const state = { errored: false }
+      store.mutations.errored(state, true)
+      expect(state.errored).to.equal(true)
+    })
+    it('set looping', () => {
+      const state = { looping: 1 }
+      store.mutations.looping(state, 2)
+      expect(state.looping).to.equal(2)
+    })
+    it('set playing', () => {
+      const state = { playing: false }
+      store.mutations.playing(state, true)
+      expect(state.playing).to.equal(true)
+    })
+    it('set current time', () => {
+      const state = { currentTime: 1 }
+      store.mutations.currentTime(state, 2)
+      expect(state.currentTime).to.equal(2)
+    })
+    it('toggle looping from 0', () => {
+      const state = { looping: 0 }
+      store.mutations.toggleLooping(state)
+      expect(state.looping).to.equal(1)
+    })
+    it('toggle looping from 1', () => {
+      const state = { looping: 1 }
+      store.mutations.toggleLooping(state)
+      expect(state.looping).to.equal(2)
+    })
+    it('toggle looping from 2', () => {
+      const state = { looping: 2 }
+      store.mutations.toggleLooping(state)
+      expect(state.looping).to.equal(0)
+    })
+  })
+  describe('getters', () => {
+    it('durationFormatted', () => {
+      const state = { duration: 12.51 }
+      expect(store.getters['durationFormatted'](state)).to.equal('00:13')
+    })
+    it('currentTimeFormatted', () => {
+      const state = { currentTime: 12.51 }
+      expect(store.getters['currentTimeFormatted'](state)).to.equal('00:13')
+    })
+    it('progress', () => {
+      const state = { currentTime: 4, duration: 10 }
+      expect(store.getters['progress'](state)).to.equal(40)
+    })
+  })
+  describe('actions', () => {
+    it('incrementVolume', (done) => {
+      testAction({
+        action: store.actions.incrementVolume,
+        payload: 0.2,
+        params: {state: {volume: 0.7}},
+        expectedMutations: [
+          { type: 'volume', payload: 0.7 + 0.2 }
+        ]
+      }, done)
+    })
+    it('toggle play false', (done) => {
+      testAction({
+        action: store.actions.togglePlay,
+        params: {state: {playing: false}},
+        expectedMutations: [
+          { type: 'playing', payload: true }
+        ]
+      }, done)
+    })
+    it('toggle play true', (done) => {
+      testAction({
+        action: store.actions.togglePlay,
+        params: {state: {playing: true}},
+        expectedMutations: [
+          { type: 'playing', payload: false }
+        ]
+      }, done)
+    })
+    it('trackEnded', (done) => {
+      testAction({
+        action: store.actions.trackEnded,
+        payload: {test: 'track'},
+        expectedActions: [
+          { type: 'trackListened', payload: {test: 'track'} },
+          { type: 'queue/next', payload: null, options: {root: true} }
+        ]
+      }, done)
+    })
+    it('trackErrored', (done) => {
+      testAction({
+        action: store.actions.trackErrored,
+        payload: {test: 'track'},
+        expectedMutations: [
+          { type: 'errored', payload: true }
+        ],
+        expectedActions: [
+          { type: 'queue/next', payload: null, options: {root: true} }
+        ]
+      }, done)
+    })
+    it('updateProgress', (done) => {
+      testAction({
+        action: store.actions.updateProgress,
+        payload: 1,
+        expectedMutations: [
+          { type: 'currentTime', payload: 1 }
+        ]
+      }, done)
+    })
+  })
+})
diff --git a/front/test/unit/utils.js b/front/test/unit/utils.js
new file mode 100644
index 0000000000000000000000000000000000000000..e67c7687f9ecd65024e513853a57cbbc2d5c1a8e
--- /dev/null
+++ b/front/test/unit/utils.js
@@ -0,0 +1,68 @@
+// helper for testing action with expected mutations
+export const testAction = ({action, payload, params, expectedMutations, expectedActions}, done) => {
+  let mutationsCount = 0
+  let actionsCount = 0
+
+  if (!expectedMutations) {
+    expectedMutations = []
+  }
+  if (!expectedActions) {
+    expectedActions = []
+  }
+  const isOver = () => {
+    return mutationsCount >= expectedMutations.length && actionsCount >= expectedActions.length
+  }
+  // mock commit
+  const commit = (type, payload) => {
+    const mutation = expectedMutations[mutationsCount]
+
+    try {
+      expect(mutation.type).to.equal(type)
+      if (payload) {
+        expect(mutation.payload).to.deep.equal(payload)
+      }
+    } catch (error) {
+      done(error)
+    }
+
+    mutationsCount++
+    if (isOver()) {
+      done()
+    }
+  }
+  // mock dispatch
+  const dispatch = (type, payload, options) => {
+    const a = expectedActions[actionsCount]
+
+    try {
+      expect(a.type).to.equal(type)
+      if (payload) {
+        expect(a.payload).to.deep.equal(payload)
+      }
+      if (a.options) {
+        expect(options).to.deep.equal(a.options)
+      }
+    } catch (error) {
+      done(error)
+    }
+
+    actionsCount++
+    if (isOver()) {
+      done()
+    }
+  }
+
+  // call the action with mocked store and arguments
+  action({ commit, dispatch, ...params }, payload)
+
+  // check if no mutations should have been dispatched
+  if (expectedMutations.length === 0) {
+    expect(mutationsCount).to.equal(0)
+  }
+  if (expectedActions.length === 0) {
+    expect(actionsCount).to.equal(0)
+  }
+  if (isOver()) {
+    done()
+  }
+}