Skip to content
Snippets Groups Projects
auth.spec.js 13.15 KiB
import { assert } from 'chai'
import axios from 'axios'
import { initialState, mutations, getters } from '@/store/auth.js'
import { userSample } from '../samples.js'
import store from './index.spec.js'
import { FakeAxios, assertRejects } from '../testhelpers.js'

describe('auth', () => {
  describe('mutations', () => {
    it('updateUser', () => {
      const state = { user: null }
      mutations.updateUser(state, userSample)
      assert.deepStrictEqual(state.user, userSample)
    })
    it('updateFeatures', () => {
      const state = { features: null }
      mutations.updateFeatures(state, userSample.features)
      assert.deepStrictEqual(state.features, userSample.features)
    })
    it('reset', () => {
      const state = { user: userSample }
      mutations.reset(state)
      assert.deepStrictEqual(state, initialState())
    })
  })

  describe('actions', () => {
    let mock

    before('Setting up mocks', () => {
      mock = new FakeAxios(axios)
    })

    afterEach(() => {
      // Remove any handlers, but leave mocking in place
      mock.reset()
      store.reset()
    })

    after('Removing Axios mock', () => {
      // Remove mocking entirely
      mock.restore()
    })

    describe('get', () => {
      it('should handle normal responses', async () => {
        mock.onGet('/user/').reply(200, userSample)
        mock.onGet('/elements/selection/').reply(200, { count: 0, results: [] })
        await store.dispatch('auth/get')
        const { features, ...user } = userSample
        assert.deepStrictEqual(store.state.auth.user, user)
        assert.deepStrictEqual(store.state.auth.features, features)
        assert.deepStrictEqual(store.history, [
          { action: 'auth/get' },
          { mutation: 'auth/updateUser', payload: user },
          { mutation: 'auth/updateFeatures', payload: features },
          // Corpora and selection are updated when a user logs in successfully
          { action: 'corpora/list', payload: null },
          { action: 'corpora/$_fetch' },
          { action: 'selection/get', payload: {} },
          { mutation: 'selection/reset' }
        ])
      })

      it('should not retrieve the selection without the selection feature', async () => {
        let { features, ...user } = userSample
        features = { ...features, selection: false }
        mock.onGet('/user/').reply(200, { ...user, features })
        await store.dispatch('auth/get')
        assert.deepStrictEqual(store.state.auth.user, user)
        assert.deepStrictEqual(store.state.auth.features, features)
        assert.deepStrictEqual(store.history, [
          { action: 'auth/get' },
          { mutation: 'auth/updateUser', payload: user },
          { mutation: 'auth/updateFeatures', payload: features },
          { action: 'corpora/list', payload: null },
          { action: 'corpora/$_fetch' }
        ])
      })

      it('should handle 403 errors', async () => {
        mock.onGet('/user/').reply(403, { detail: 'oh no!', features: { signup: true } })
        await store.dispatch('auth/get')
        assert.deepStrictEqual(store.history, [
          { action: 'auth/get' },
          { mutation: 'auth/updateUser', payload: false },
          { mutation: 'auth/updateFeatures', payload: { signup: true } }
        ])
        assert.strictEqual(store.state.auth.user, false)
        assert.deepStrictEqual(store.state.auth.features, { signup: true })
      })

      it('should let other errors through', async () => {
        mock.onGet('/user/').reply(500)
        const err = await assertRejects(async () => { await store.dispatch('auth/get') })
        assert.deepStrictEqual(store.history, [
          { action: 'auth/get' }
        ])
        assert.strictEqual(err.message, 'Request failed with status code 500')
      })
    })

    describe('login', () => {
      it('should login', async () => {
        mock.onPost('/user/login/').reply(200, userSample)
        mock.onGet('/elements/selection/').reply(200, { count: 0, results: [] })
        const payload = { email: 'a@a.fr', password: 'aaa' }
        await store.dispatch('auth/login', payload)
        const { features, ...user } = userSample
        assert.deepStrictEqual(store.history, [
          { action: 'auth/login', payload },
          { mutation: 'auth/updateUser', payload: user },
          { mutation: 'auth/updateFeatures', payload: features },
          { action: 'reset', payload: { exclude: ['auth'] } },
          { mutation: 'annotation/reset' },
          { mutation: 'classification/reset' },
          { mutation: 'corpora/reset' },
          { mutation: 'elements/reset' },
          { mutation: 'files/reset' },
          { mutation: 'navigation/reset' },
          { mutation: 'notifications/reset' },
          { mutation: 'process/reset' },
          { mutation: 'selection/reset' },
          { mutation: 'tree/reset' },
          { action: 'corpora/list', payload: null },
          { action: 'corpora/$_fetch' },
          { action: 'selection/get', payload: {} },
          { mutation: 'selection/reset' }
        ])
      })

      it('should not retrieve the selection without the selection feature', async () => {
        let { features, ...user } = userSample
        features = { ...features, selection: false }
        mock.onPost('/user/login/').reply(200, { ...user, features })

        const payload = { email: 'a@a.fr', password: 'aaa' }
        await store.dispatch('auth/login', payload)

        assert.deepStrictEqual(store.history, [
          { action: 'auth/login', payload },
          { mutation: 'auth/updateUser', payload: user },
          { mutation: 'auth/updateFeatures', payload: features },
          { action: 'reset', payload: { exclude: ['auth'] } },
          { mutation: 'annotation/reset' },
          { mutation: 'classification/reset' },
          { mutation: 'corpora/reset' },
          { mutation: 'elements/reset' },
          { mutation: 'files/reset' },
          { mutation: 'navigation/reset' },
          { mutation: 'notifications/reset' },
          { mutation: 'process/reset' },
          { mutation: 'selection/reset' },
          { mutation: 'tree/reset' },
          { action: 'corpora/list', payload: null },
          { action: 'corpora/$_fetch' }
        ])
      })
    })

    describe('register', () => {
      it('should register', async () => {
        mock.onPost('/user/new/').reply(201, userSample)
        mock.onGet('/elements/selection/').reply(200, { count: 0, results: [] })
        const payload = { email: 'a@a.fr', display_name: 'A', password: 'aaa' }
        await store.dispatch('auth/register', payload)
        const { features, ...user } = userSample
        assert.deepStrictEqual(store.history, [
          { action: 'auth/register', payload },
          { mutation: 'auth/updateUser', payload: user },
          { mutation: 'auth/updateFeatures', payload: features },
          { action: 'reset', payload: { exclude: ['auth'] } },
          { mutation: 'annotation/reset' },
          { mutation: 'classification/reset' },
          { mutation: 'corpora/reset' },
          { mutation: 'elements/reset' },
          { mutation: 'files/reset' },
          { mutation: 'navigation/reset' },
          { mutation: 'notifications/reset' },
          { mutation: 'process/reset' },
          { mutation: 'selection/reset' },
          { mutation: 'tree/reset' },
          { action: 'corpora/list', payload: null },
          { action: 'corpora/$_fetch' },
          { action: 'selection/get', payload: {} },
          { mutation: 'selection/reset' }
        ])
      })

      it('should not retrieve the selection without the selection feature', async () => {
        let { features, ...user } = userSample
        features = { ...features, selection: false }
        mock.onPost('/user/new/').reply(201, { ...user, features })

        const payload = { email: 'a@a.fr', display_name: 'A', password: 'aaa' }
        await store.dispatch('auth/register', payload)

        assert.deepStrictEqual(store.history, [
          { action: 'auth/register', payload },
          { mutation: 'auth/updateUser', payload: user },
          { mutation: 'auth/updateFeatures', payload: features },
          { action: 'reset', payload: { exclude: ['auth'] } },
          { mutation: 'annotation/reset' },
          { mutation: 'classification/reset' },
          { mutation: 'corpora/reset' },
          { mutation: 'elements/reset' },
          { mutation: 'files/reset' },
          { mutation: 'navigation/reset' },
          { mutation: 'notifications/reset' },
          { mutation: 'process/reset' },
          { mutation: 'selection/reset' },
          { mutation: 'tree/reset' },
          { action: 'corpora/list', payload: null },
          { action: 'corpora/$_fetch' }
        ])
      })
    })

    it('logout', async () => {
      const { features, ...user } = userSample
      store.setState('auth.user', user)
      store.setState('auth.features', features)
      mock.onDelete('/user/').reply(204)
      await store.dispatch('auth/logout')
      assert.deepStrictEqual(store.history, [
        { action: 'auth/logout' },
        { mutation: 'auth/updateUser', payload: false },
        { action: 'reset', payload: { exclude: ['auth'] } },
        { mutation: 'annotation/reset' },
        { mutation: 'classification/reset' },
        { mutation: 'corpora/reset' },
        { mutation: 'elements/reset' },
        { mutation: 'files/reset' },
        { mutation: 'navigation/reset' },
        { mutation: 'notifications/reset' },
        { mutation: 'process/reset' },
        { mutation: 'selection/reset' },
        { mutation: 'tree/reset' },
        { action: 'corpora/list', payload: null },
        { action: 'corpora/$_fetch' }
      ])
    })

    it('sendResetEmail', async () => {
      mock.onPost('/user/password-reset/').reply(201)
      const payload = { email: 'a@a.fr' }
      await store.dispatch('auth/sendResetEmail', payload)
      assert.deepStrictEqual(store.history, [
        { action: 'auth/sendResetEmail', payload }
      ])
      assert.strictEqual(mock.history.post.length, 1)
      assert.deepStrictEqual(mock.history.post[0].data, payload)
    })

    it('resetPassword', async () => {
      mock.onPost('/user/password-reset/confirm/').reply(201)
      const payload = { uidb64: 'abcdef', token: 't0k3n', password: 'hunter2' }
      await store.dispatch('auth/resetPassword', payload)
      assert.deepStrictEqual(store.history, [
        { action: 'auth/resetPassword', payload }
      ])
      assert.strictEqual(mock.history.post.length, 1)
      assert.deepStrictEqual(mock.history.post[0].data, payload)
    })

    it('raises errors to the component on wrong password reset', async () => {
      mock.onPost('/user/password-reset/confirm/').reply(400, { password: 'This password is too common' })
      const payload = { uidb64: 'abcdef', token: 't0k3n', password: 'root' }
      const error = await assertRejects(async () => store.dispatch('auth/resetPassword', payload))
      assert.strictEqual(error.toString(), 'Error: Request failed with status code 400')
    })
  })

  describe('getters', () => {
    it('hasInfo', () => {
      assert.strictEqual(getters.hasInfo({ user: null }, {}), false)
      assert.strictEqual(getters.hasInfo({ user: false }, {}), true)
      assert.strictEqual(getters.hasInfo({ user: userSample }, {}), true)
    })
    it('isLoggedOn', () => {
      assert.strictEqual(getters.isLoggedOn({ user: null }, { hasInfo: false }), false)
      assert.strictEqual(getters.isLoggedOn({ user: false }, { hasInfo: true }), false)
      assert.strictEqual(getters.isLoggedOn({ user: userSample }, { hasInfo: true }), true)
    })

    it('isAdmin', () => {
      assert.strictEqual(getters.isAdmin(
        { user: null },
        { hasInfo: false, isLoggedOn: false }
      ), false)
      assert.strictEqual(getters.isAdmin(
        { user: false },
        { hasInfo: true, isLoggedOn: false }
      ), false)
      assert.strictEqual(getters.isAdmin(
        { user: { is_admin: false } },
        { hasInfo: true, isLoggedOn: true }
      ), false)
      assert.strictEqual(getters.isAdmin(
        { user: { is_admin: true } },
        { hasInfo: true, isLoggedOn: true }
      ), true)
    })

    it('isVerified', () => {
      assert.strictEqual(getters.isVerified(
        { user: null },
        { hasInfo: false, isLoggedOn: false, isAdmin: false }
      ), false)
      assert.strictEqual(getters.isVerified(
        { user: false },
        { hasInfo: true, isLoggedOn: false, isAdmin: false }
      ), false)
      assert.strictEqual(getters.isVerified(
        { user: { is_admin: true } },
        { hasInfo: true, isLoggedOn: true, isAdmin: true }
      ), true)
      assert.strictEqual(getters.isVerified(
        { user: { is_admin: false, verified_email: false } },
        { hasInfo: true, isLoggedOn: true, isAdmin: false }
      ), false)
      assert.strictEqual(getters.isVerified(
        { user: { is_admin: false, verified_email: true } },
        { hasInfo: true, isLoggedOn: true, isAdmin: false }
      ), true)
    })

    it('hasFeature', () => {
      const hasFeature = getters.hasFeature({ features: { search: true, sv_cheats: false } })
      assert.strictEqual(hasFeature('search'), true)
      assert.strictEqual(hasFeature('sv_cheats'), false)
      assert.strictEqual(hasFeature('unknown'), false)
    })
  })
})