Refactored and created the tests of DeletePostCallback

Created a folder `utils` for PostHelpers.js.
Fixed a new incoming problem of the master with deleting Posts on the User Profile.

Co-Authored-By: mattwr18 <mattwr18@gmail.com>
This commit is contained in:
Wolfgang Huß 2019-06-13 19:23:13 +02:00
parent cd0074ec86
commit 482ac1572b
15 changed files with 233 additions and 150 deletions

View File

@ -25,12 +25,12 @@ describe('Comment.vue', () => {
success: jest.fn(),
error: jest.fn(),
},
$apollo: {
mutate: jest.fn().mockResolvedValue(),
},
$filters: {
truncate: a => a,
},
$apollo: {
mutate: jest.fn().mockResolvedValue(),
},
}
getters = {
'auth/user': () => {

View File

@ -15,7 +15,6 @@
placement="bottom-end"
resource-type="comment"
:resource="comment"
:callbacks="{ confirm: deleteCommentCallback, cancel: null }"
:modalsData="menuModalsData"
style="float-right"
:is-owner="isAuthor(author.id)"
@ -49,9 +48,20 @@ export default {
},
dateTime: { type: [Date, String], default: null },
},
data() {
return {
menuModalsData: {
computed: {
...mapGetters({
user: 'auth/user',
isModerator: 'auth/isModerator',
}),
displaysComment() {
return !this.unavailable || this.isModerator
},
author() {
if (this.deleted) return {}
return this.comment.author || {}
},
menuModalsData() {
return {
delete: {
titleIdent: 'delete.comment.title',
messageIdent: 'delete.comment.message',
@ -72,20 +82,7 @@ export default {
},
},
},
},
}
},
computed: {
...mapGetters({
user: 'auth/user',
isModerator: 'auth/isModerator',
}),
displaysComment() {
return !this.unavailable || this.isModerator
},
author() {
if (this.deleted) return {}
return this.comment.author || {}
}
},
},
methods: {

View File

@ -2,7 +2,7 @@ import { shallowMount, mount, createLocalVue } from '@vue/test-utils'
import Vuex from 'vuex'
import Styleguide from '@human-connection/styleguide'
import ConfirmModal from './ConfirmModal.vue'
import PostHelpers from '~/components/PostHelpers'
import { postMenuModalsData } from '~/components/utils/PostHelpers'
const localVue = createLocalVue()
@ -23,7 +23,7 @@ describe('ConfirmModal.vue', () => {
type: 'contribution',
id: 'p23',
name: postName,
modalData: PostHelpers.postMenuModalsData(postName, confirmCallback, cancelCallback).delete,
modalData: postMenuModalsData(postName, confirmCallback, cancelCallback).delete,
}
mocks = {
$t: jest.fn(),
@ -143,7 +143,8 @@ describe('ConfirmModal.vue', () => {
it('does call the confirm callback', () => {
expect(confirmCallback).toHaveBeenCalledTimes(1)
})
it('emits close', () => {
it('emits "close"', () => {
expect(wrapper.emitted().close).toHaveLength(1)
})

View File

@ -16,10 +16,6 @@ describe('DisableModal.vue', () => {
type: 'contribution',
id: 'c42',
name: 'blah',
callbacks: {
confirm: jest.fn(),
cancel: jest.fn(),
},
}
mocks = {
$filters: {
@ -33,8 +29,12 @@ describe('DisableModal.vue', () => {
$apollo: {
mutate: jest
.fn()
.mockResolvedValueOnce({ enable: 'u4711' })
.mockRejectedValue({ message: 'Not Authorised!' }),
.mockResolvedValueOnce({
enable: 'u4711',
})
.mockRejectedValue({
message: 'Not Authorised!',
}),
},
location: {
reload: jest.fn(),

View File

@ -17,10 +17,6 @@ describe('ReportModal.vue', () => {
propsData = {
type: 'contribution',
id: 'c43',
callbacks: {
confirm: jest.fn(),
cancel: jest.fn(),
},
}
mocks = {
$t: jest.fn(),

View File

@ -66,9 +66,9 @@ export default {
},
async confirm() {
this.loading = true
// TODO: Use the "modalData" structure introduced in "ConfirmModal" and refactor this here. Be aware that all the Jest tests have to be refactored as well !!!
// await this.modalData.buttons.confirm.callback()
try {
// TODO: Use the "modalData" structure introduced in "ConfirmModal" and refactor this here. Be aware that all the Jest tests have to be refactored as well !!!
// await this.modalData.buttons.confirm.callback()
await this.$apollo.mutate({
mutation: gql`
mutation($id: ID!) {

View File

@ -0,0 +1,130 @@
import { config, shallowMount, mount, createLocalVue, RouterLinkStub } from '@vue/test-utils'
import Styleguide from '@human-connection/styleguide'
import Vuex from 'vuex'
import Filters from '~/plugins/vue-filters'
import PostCard from '.'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Styleguide)
localVue.use(Filters)
config.stubs['no-ssr'] = '<span><slot /></span>'
config.stubs['v-popover'] = '<span><slot /></span>'
describe('PostCard', () => {
let store
let stubs
let mocks
let propsData
let getters
let Wrapper
let wrapper
beforeEach(() => {
propsData = {
post: {
id: 'p23',
name: 'It is a post',
author: {
id: 'u1',
},
disabled: false,
},
}
store = new Vuex.Store({
getters: {
'auth/user': () => {
return {}
},
},
})
stubs = {
NuxtLink: RouterLinkStub,
}
mocks = {
$t: jest.fn(),
$toast: {
success: jest.fn(),
error: jest.fn(),
},
$apollo: {
mutate: jest.fn().mockResolvedValue(),
},
}
getters = {
'auth/user': () => {
return {}
},
}
})
describe('shallowMount', () => {
Wrapper = () => {
return shallowMount(PostCard, {
store,
propsData,
mocks,
localVue,
})
}
beforeEach(jest.useFakeTimers)
describe('test Post callbacks', () => {
beforeEach(() => {
wrapper = Wrapper()
})
describe('deletion of Post from Page by invoking "deletePostCallback()"', () => {
beforeEach(() => {
wrapper.vm.deletePostCallback()
})
describe('after timeout', () => {
beforeEach(jest.runAllTimers)
it('does call mutation', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
})
it('mutation is successful', () => {
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
})
it('emits "removePostFromList"', () => {
expect(wrapper.emitted().removePostFromList).toHaveLength(1)
})
})
})
})
})
describe('mount', () => {
Wrapper = () => {
const store = new Vuex.Store({
getters,
})
return mount(PostCard, {
stubs,
mocks,
propsData,
store,
localVue,
})
}
describe('given a post', () => {
beforeEach(() => {
propsData.post = {
title: "It's a title",
}
})
it('renders title', () => {
expect(Wrapper().text()).toContain("It's a title")
})
})
})
})

View File

@ -70,7 +70,7 @@ import HcCategory from '~/components/Category'
import HcRibbon from '~/components/Ribbon'
// import { randomBytes } from 'crypto'
import { mapGetters } from 'vuex'
import PostHelpers from '~/components/PostHelpers'
import { postMenuModalsData, deletePostMutationData } from '~/components/utils/PostHelpers'
export default {
name: 'HcPostCard',
@ -103,7 +103,7 @@ export default {
return this.user.id === this.post.author.id
},
menuModalsData() {
return PostHelpers.postMenuModalsData(
return postMenuModalsData(
// "this.post" may not always be defined at the beginning
this.post ? this.$filters.truncate(this.post.title, 30) : '',
this.deletePostCallback,
@ -113,7 +113,7 @@ export default {
methods: {
async deletePostCallback() {
try {
await this.$apollo.mutate(PostHelpers.deletePostMutationData(this.post.id))
await this.$apollo.mutate(deletePostMutationData(this.post.id))
this.$toast.success(this.$t('delete.contribution.success'))
this.$emit('removePostFromList')
} catch (err) {

View File

@ -1,61 +0,0 @@
import { config, mount, createLocalVue, RouterLinkStub } from '@vue/test-utils'
import PostCard from '.'
import Styleguide from '@human-connection/styleguide'
import Vuex from 'vuex'
import Filters from '~/plugins/vue-filters'
const localVue = createLocalVue()
localVue.use(Vuex)
localVue.use(Styleguide)
localVue.use(Filters)
config.stubs['no-ssr'] = '<span><slot /></span>'
config.stubs['v-popover'] = '<span><slot /></span>'
describe('PostCard', () => {
let stubs
let mocks
let propsData
let getters
beforeEach(() => {
propsData = {}
stubs = {
NuxtLink: RouterLinkStub,
}
mocks = {
$t: jest.fn(),
}
getters = {
'auth/user': () => {
return {}
},
}
})
const Wrapper = () => {
const store = new Vuex.Store({
getters,
})
return mount(PostCard, {
stubs,
mocks,
propsData,
store,
localVue,
})
}
describe('given a post', () => {
beforeEach(() => {
propsData.post = {
title: "It's a title",
}
})
it('renders title', () => {
expect(Wrapper().text()).toContain("It's a title")
})
})
})

View File

@ -22,7 +22,9 @@ describe('CommentList.vue', () => {
let data
propsData = {
post: { id: 1 },
post: {
id: 1,
},
}
store = new Vuex.Store({
getters: {
@ -33,6 +35,9 @@ describe('CommentList.vue', () => {
})
mocks = {
$t: jest.fn(),
$filters: {
truncate: a => a,
},
$apollo: {
queries: {
Post: {
@ -49,13 +54,24 @@ describe('CommentList.vue', () => {
describe('shallowMount', () => {
const Wrapper = () => {
return mount(CommentList, { store, mocks, localVue, propsData, data })
return mount(CommentList, {
store,
mocks,
localVue,
propsData,
data,
})
}
beforeEach(() => {
wrapper = Wrapper()
wrapper.setData({
comments: [{ id: 'c1', contentExcerpt: 'this is a comment' }],
comments: [
{
id: 'c1',
contentExcerpt: 'this is a comment',
},
],
})
})

View File

@ -56,7 +56,7 @@ describe('PostSlug', () => {
beforeEach(jest.useFakeTimers)
describe('test "PostHelpers"', () => {
describe('test Post callbacks', () => {
beforeEach(() => {
wrapper = Wrapper()
wrapper.setData({
@ -70,22 +70,14 @@ describe('PostSlug', () => {
})
})
describe('deletion of Post from Page by invoking "deletePostCallback(`page`)"', () => {
describe('deletion of Post from Page by invoking "deletePostCallback()"', () => {
beforeEach(() => {
wrapper.vm.deletePostCallback('page')
wrapper.vm.deletePostCallback()
})
describe('after timeout', () => {
beforeEach(jest.runAllTimers)
it('not emits "deletePost"', () => {
expect(wrapper.emitted().deletePost).toBeFalsy()
})
it('does go to index (main) page', () => {
expect(mocks.$router.history.push).toHaveBeenCalledTimes(1)
})
it('does call mutation', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
})
@ -93,6 +85,10 @@ describe('PostSlug', () => {
it('mutation is successful', () => {
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
})
it('does go to index (main) page', () => {
expect(mocks.$router.history.push).toHaveBeenCalledTimes(1)
})
})
})
})

View File

@ -71,7 +71,7 @@ import HcUser from '~/components/User'
import HcShoutButton from '~/components/ShoutButton.vue'
import HcCommentForm from '~/components/comments/CommentForm'
import HcCommentList from '~/components/comments/CommentList'
import PostHelpers from '~/components/PostHelpers'
import { postMenuModalsData, deletePostMutationData } from '~/components/utils/PostHelpers'
export default {
name: 'PostSlug',
@ -211,7 +211,7 @@ export default {
},
computed: {
menuModalsData() {
return PostHelpers.postMenuModalsData(
return postMenuModalsData(
// "this.post" may not always be defined at the beginning
this.post ? this.$filters.truncate(this.post.title, 30) : '',
this.deletePostCallback,
@ -224,7 +224,7 @@ export default {
},
async deletePostCallback() {
try {
await this.$apollo.mutate(PostHelpers.deletePostMutationData(this.post.id))
await this.$apollo.mutate(deletePostMutationData(this.post.id))
this.$toast.success(this.$t('delete.contribution.success'))
this.$router.history.push('/') // Redirect to index (main) page
} catch (err) {

View File

@ -1,17 +1,17 @@
import { shallowMount, createLocalVue } from '@vue/test-utils'
import ProfileSlug from './_slug.vue'
import { config, mount } from '@vue/test-utils'
import HcUserProfile from './_slug.vue'
import Vuex from 'vuex'
import Styleguide from '@human-connection/styleguide'
import Vue from 'vue'
const localVue = createLocalVue()
config.stubs['ds-space'] = '<span><div>Hello, Wolle</div></span>'
localVue.use(Vuex)
localVue.use(Styleguide)
Vue.use(Vuex)
describe('ProfileSlug', () => {
let wrapper
let Wrapper
let mocks
let getters
beforeEach(() => {
mocks = {
@ -21,6 +21,12 @@ describe('ProfileSlug', () => {
},
$t: jest.fn(),
// If you mocking router, than don't use VueRouter with lacalVue: https://vue-test-utils.vuejs.org/guides/using-with-vue-router.html
$route: {
params: {
id: '4711',
slug: 'john-doe',
},
},
$router: {
history: {
push: jest.fn(),
@ -34,13 +40,24 @@ describe('ProfileSlug', () => {
mutate: jest.fn().mockResolvedValue(),
},
}
getters = {
'auth/user': () => {
return {
slug: 'john-doe',
id: '4711',
}
},
}
})
describe('shallowMount', () => {
describe('mount', () => {
Wrapper = () => {
return shallowMount(ProfileSlug, {
const store = new Vuex.Store({
getters,
})
return mount(HcUserProfile, {
store,
mocks,
localVue,
})
}
@ -52,27 +69,13 @@ describe('ProfileSlug', () => {
})
describe('deletion of Post from List by invoking "deletePostCallback(`list`)"', () => {
beforeEach(() => {
wrapper.vm.deletePostCallback('list')
})
beforeEach(() => {})
describe('after timeout', () => {
beforeEach(jest.runAllTimers)
it.skip('emits "deletePost"', () => {
expect(wrapper.emitted().deletePost).toHaveLength(1)
})
it.skip('does not go to index (main) page', () => {
expect(mocks.$router.history.push).not.toHaveBeenCalled()
})
it.skip('does call mutation', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
})
it.skip('mutation is successful', () => {
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
it('fetches the user', () => {
expect(wrapper.is('div')).toBe(true)
})
})
})

View File

@ -204,7 +204,7 @@
:key="post.id"
:post="post"
:width="{ base: '100%', md: '100%', xl: '50%' }"
@removePostFromList="user.contributions.splice(index, 1)"
@removePostFromList="activePosts.splice(index, 1)"
/>
</template>
<template v-else-if="$apollo.loading">
@ -252,6 +252,7 @@ const tabToFilterMapping = ({ tab, id }) => {
}
export default {
name: 'HcUserProfile',
components: {
User,
HcPostCard,
@ -273,6 +274,7 @@ export default {
return {
User: [],
Post: [],
activePosts: [],
voted: false,
page: 1,
pageSize: 6,
@ -302,12 +304,6 @@ export default {
offset() {
return (this.page - 1) * this.pageSize
},
activePosts() {
if (!this.Post) {
return []
}
return this.uniq(this.Post.filter(post => !post.deleted))
},
socialMediaLinks() {
const { socialMedia = [] } = this.user
return socialMedia.map(socialMedia => {
@ -330,6 +326,9 @@ export default {
throw new Error('User not found!')
}
},
Post(val) {
this.activePosts = this.setActivePosts()
},
},
methods: {
handleTab(tab) {
@ -363,6 +362,12 @@ export default {
fetchPolicy: 'cache-and-network',
})
},
setActivePosts() {
if (!this.Post) {
return []
}
return this.uniq(this.Post.filter(post => !post.deleted))
},
},
apollo: {
Post: {