Write component tests, move header close to icon

This commit is contained in:
Matt Rider 2019-06-07 18:13:49 -03:00
parent 7bbf870d8d
commit 18d3e36c19
2 changed files with 197 additions and 35 deletions

View File

@ -0,0 +1,168 @@
import { config, mount, createLocalVue, createWrapper } from '@vue/test-utils'
import DeleteAccount from './DeleteAccount.vue'
import Styleguide from '@human-connection/styleguide'
import Vuex from 'vuex'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Styleguide)
config.stubs['b-switch'] = '<span><slot /></span>'
config.stubs['b-checkbox'] = '<span><slot /></span>'
describe('DeleteAccount.vue', () => {
let mocks
let wrapper
let getters
let actions
let deleteAccountBtn
beforeEach(() => {
mocks = {
$t: jest.fn(),
$apollo: {
mutate: jest
.fn()
.mockResolvedValueOnce({
data: {
DeleteAccount: {
id: 'u343',
},
},
})
.mockRejectedValue({ message: 'Not authorised!' }),
},
$toast: {
error: jest.fn(),
success: jest.fn(),
},
$router: {
history: {
push: jest.fn(),
},
},
}
getters = {
'auth/user': () => {
return { id: 'u343' }
},
}
actions = { 'auth/logout': jest.fn() }
})
describe('mount', () => {
const Wrapper = () => {
const store = new Vuex.Store({
getters,
actions,
})
return mount(DeleteAccount, { mocks, localVue, store })
}
beforeEach(() => {
wrapper = Wrapper()
})
afterEach(() => {
jest.clearAllMocks()
})
it('defaults to deleteContributions to false', () => {
expect(wrapper.vm.deleteContributions).toEqual(false)
})
it('defaults to deleteComments to false', () => {
expect(wrapper.vm.deleteComments).toEqual(false)
})
it('defaults to deleteEnabled to false', () => {
expect(wrapper.vm.deleteEnabled).toEqual(false)
})
it('does not call the delete user mutation if deleteEnabled is false', () => {
deleteAccountBtn = wrapper.find('.ds-button-danger')
deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
describe('calls the delete user mutation', () => {
beforeEach(() => {
wrapper.setData({ deleteEnabled: true })
deleteAccountBtn = wrapper.find('.ds-button-danger')
})
it('if deleteEnabled is true and only deletes user by default', () => {
deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({
variables: {
id: 'u343',
resource: [],
},
}),
)
})
it("deletes a user's posts if requested", () => {
wrapper.setData({ deleteContributions: true })
deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({
variables: {
id: 'u343',
resource: ['Post'],
},
}),
)
})
it("deletes a user's comments if requested", () => {
wrapper.setData({ deleteComments: true })
deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({
variables: {
id: 'u343',
resource: ['Comment'],
},
}),
)
})
it("deletes a user's posts and comments if requested", () => {
wrapper.setData({ deleteContributions: true, deleteComments: true })
deleteAccountBtn.trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(
expect.objectContaining({
variables: {
id: 'u343',
resource: ['Post', 'Comment'],
},
}),
)
})
it('shows a success toaster after successful mutation', async () => {
await deleteAccountBtn.trigger('click')
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
})
it('updates the user in the store', async () => {
await deleteAccountBtn.trigger('click')
expect(mocks.$router.history.push).toHaveBeenCalledWith('/')
})
})
describe('error handling', () => {
it('shows an error toaster when the mutation rejects', async () => {
wrapper.setData({ deleteEnabled: true })
deleteAccountBtn = wrapper.find('.ds-button-danger')
await deleteAccountBtn.trigger('click')
// second submission causes mutation to reject
await deleteAccountBtn.trigger('click')
await mocks.$apollo.mutate
expect(mocks.$toast.error).toHaveBeenCalledWith('Not authorised!')
})
})
})
})

View File

@ -1,21 +1,20 @@
<template>
<div>
<ds-card hover>
<ds-space />
<ds-flex>
<ds-flex-item width="5%" />
<ds-flex-item>
<ds-icon name="warning" size="xxx-large" class="delete-warning-icon" />
</ds-flex-item>
<ds-flex-item width="80%">
<ds-heading>{{ $t('settings.delete.name') }}</ds-heading>
</ds-flex-item>
<ds-container>
<ds-space />
<ds-space/>
<ds-container>
<ds-flex>
<ds-flex-item width="8%">
<ds-icon name="warning" size="xxx-large" class="delete-warning-icon"/>
</ds-flex-item>
<ds-flex-item width="80%">
<ds-heading>{{ $t('settings.delete.name') }}</ds-heading>
</ds-flex-item>
<ds-space/>
<ds-heading tag="h4">{{ $t('settings.delete.accountDescription') }}</ds-heading>
</ds-container>
</ds-flex>
<ds-space />
</ds-flex>
</ds-container>
<ds-space/>
<ds-container>
<transition name="slide-up">
<div v-if="deleteEnabled">
@ -24,10 +23,8 @@
<b-checkbox
type="is-danger"
:disabled="!currentUser.contributionsCount"
v-model="formData.deleteContributions"
>
{{ $t('settings.delete.countPosts', { count: currentUser.contributionsCount }) }}
</b-checkbox>
v-model="deleteContributions"
>{{ $t('settings.delete.countPosts', { count: currentUser.contributionsCount }) }}</b-checkbox>
</div>
</div>
<div class="field">
@ -35,10 +32,8 @@
<b-checkbox
type="is-danger"
:disabled="!currentUser.commentsCount"
v-model="formData.deleteComments"
>
{{ $t('settings.delete.countComments', { count: currentUser.commentsCount }) }}
</b-checkbox>
v-model="deleteComments"
>{{ $t('settings.delete.countComments', { count: currentUser.commentsCount }) }}</b-checkbox>
</div>
</div>
<div class="message is-danger">
@ -57,16 +52,14 @@
</div>
</div>
</ds-flex-item>
<ds-flex-item width="20%" />
<ds-flex-item width="20%"/>
<ds-flex-item>
<ds-button
icon="trash"
danger
:disabled="isLoading || !deleteEnabled"
@click="handleSubmit"
>
{{ $t('settings.delete.name') }}
</ds-button>
>{{ $t('settings.delete.name') }}</ds-button>
</ds-flex-item>
</ds-flex>
</ds-container>
@ -75,17 +68,15 @@
</div>
</template>
<script>
import { mapGetters } from 'vuex'
import { mapGetters, mapActions } from 'vuex'
import gql from 'graphql-tag'
export default {
name: 'DeleteAccount',
data() {
return {
formData: {
deleteContributions: false,
deleteComments: false,
},
deleteContributions: false,
deleteComments: false,
deleteEnabled: false,
isLoading: false,
}
@ -96,12 +87,15 @@ export default {
}),
},
methods: {
...mapActions({
logout: 'auth/logout',
}),
handleSubmit() {
let resourceArgs = []
if (this.formData.deleteContributions) {
if (this.deleteContributions) {
resourceArgs.push('Post')
}
if (this.formData.deleteComments) {
if (this.deleteComments) {
resourceArgs.push('Comment')
}
this.$apollo
@ -117,8 +111,8 @@ export default {
})
.then(() => {
this.$toast.success(this.$t('settings.delete.success'))
this.$store.dispatch('auth/logout')
this.$router.replace('/')
this.logout()
this.$router.history.push('/')
})
.catch(error => {
this.$toast.error(error.message)