Update UI, component tests

- enforce that a post cannot be created or updated with no categories nor more than 3 categories
This commit is contained in:
Matt Rider 2019-08-20 15:53:07 +02:00
parent e79347637c
commit c614e4de47
2 changed files with 91 additions and 51 deletions

View File

@ -28,6 +28,7 @@ describe('ContributionForm.vue', () => {
let cancelBtn
let mocks
let propsData
let categoryIds
const postTitle = 'this is a title for a post'
const postTitleTooShort = 'xx'
let postTitleTooLong = ''
@ -60,6 +61,7 @@ describe('ContributionForm.vue', () => {
content: postContent,
contentExcerpt: postContent,
language: 'en',
categoryIds,
},
},
}),
@ -175,6 +177,23 @@ describe('ContributionForm.vue', () => {
wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
it('should have at least one category', async () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent)
wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
it('should have not have more than three categories', async () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent)
wrapper.vm.form.categoryIds = ['cat4', 'cat9', 'cat15', 'cat27']
wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
})
describe('valid form submission', () => {
@ -186,7 +205,7 @@ describe('ContributionForm.vue', () => {
content: postContent,
language: 'en',
id: null,
categoryIds: null,
categoryIds: ['cat12'],
imageUpload: null,
image: null,
},
@ -194,11 +213,13 @@ describe('ContributionForm.vue', () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent)
categoryIds = ['cat12']
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
})
it('with title and content', () => {
wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
it('creates a post with valid title, content, and at least one category', async () => {
await wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it("sends a fallback language based on a user's locale", () => {
@ -214,14 +235,6 @@ describe('ContributionForm.vue', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it('supports adding categories', async () => {
const categoryIds = ['cat12', 'cat15', 'cat37']
expectedParams.variables.categoryIds = categoryIds
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
await wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it('supports adding a teaser image', async () => {
expectedParams.variables.imageUpload = imageUpload
wrapper.find(TeaserImage).vm.$emit('addTeaserImage', imageUpload)
@ -260,6 +273,8 @@ describe('ContributionForm.vue', () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
await wrapper.vm.updateEditorContent(postContent)
categoryIds = ['cat12']
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
})
it('shows an error toaster when apollo mutation rejects', async () => {
@ -307,35 +322,54 @@ describe('ContributionForm.vue', () => {
expect(wrapper.vm.form.content).toEqual(propsData.contribution.content)
})
it('calls the UpdatePost apollo mutation', async () => {
expectedParams = {
mutation: PostMutations().UpdatePost,
variables: {
title: postTitle,
content: postContent,
language: propsData.contribution.language,
id: propsData.contribution.id,
categoryIds: ['cat12'],
image,
imageUpload: null,
},
}
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
wrapper.vm.updateEditorContent(postContent)
await wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
describe('valid update', () => {
beforeEach(() => {
mocks.$apollo.mutate = jest.fn().mockResolvedValueOnce({
data: {
UpdatePost: {
title: postTitle,
slug: 'this-is-a-title-for-a-post',
content: postContent,
contentExcerpt: postContent,
language: 'en',
categoryIds,
},
},
})
wrapper = Wrapper()
expectedParams = {
mutation: PostMutations().UpdatePost,
variables: {
title: postTitle,
content: postContent,
language: propsData.contribution.language,
id: propsData.contribution.id,
categoryIds,
image,
imageUpload: null,
},
}
})
it('supports updating categories', async () => {
const categoryIds = ['cat3', 'cat51', 'cat37']
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
wrapper.vm.updateEditorContent(postContent)
expectedParams.variables.categoryIds = categoryIds
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
await wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
it('calls the UpdatePost apollo mutation', async () => {
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
wrapper.vm.updateEditorContent(postContent)
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
it('supports updating categories', async () => {
const categoryIds = ['cat3', 'cat51', 'cat37']
postTitleInput = wrapper.find('.ds-input')
postTitleInput.setValue(postTitle)
wrapper.vm.updateEditorContent(postContent)
expectedParams.variables.categoryIds = categoryIds
wrapper.find(CategoriesSelect).vm.$emit('updateCategories', categoryIds)
await wrapper.find('.submit-button-for-test').trigger('click')
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expect.objectContaining(expectedParams))
})
})
})
})

View File

@ -57,7 +57,7 @@
type="submit"
icon="check"
:loading="loading"
:disabled="disabledByContent || errors"
:disabled="failsValidations || errors"
primary
@click.prevent="submit"
>
@ -101,7 +101,7 @@ export default {
image: null,
language: null,
languageOptions: [],
categoryIds: null,
categoryIds: [],
},
formSchema: {
title: { required: true, min: 3, max: 64 },
@ -109,12 +109,11 @@ export default {
},
id: null,
loading: false,
disabledByContent: true,
slug: null,
users: [],
contentMin: 3,
contentMax: 2000,
failsValidations: true,
hashtags: [],
}
},
@ -129,9 +128,9 @@ export default {
this.slug = contribution.slug
this.form.title = contribution.title
this.form.content = contribution.content
this.manageContent(this.form.content)
this.form.image = contribution.image
this.form.categoryIds = this.categoryIds(contribution.categories)
this.manageContent(this.form.content)
},
},
},
@ -175,11 +174,11 @@ export default {
imageUpload: teaserImage,
},
})
.then(res => {
.then(({ data }) => {
this.loading = false
this.$toast.success(this.$t('contribution.success'))
this.disabledByContent = true
const result = res.data[this.id ? 'UpdatePost' : 'CreatePost']
this.failedValidations = true
const result = data[this.id ? 'UpdatePost' : 'CreatePost']
this.$router.push({
name: 'post-id-slug',
@ -189,7 +188,7 @@ export default {
.catch(err => {
this.$toast.error(err.message)
this.loading = false
this.disabledByContent = false
this.failedValidations = false
})
},
updateEditorContent(value) {
@ -202,8 +201,7 @@ export default {
const str = content.replace(/<\/?[^>]+(>|$)/gm, '')
// Set counter length of text
this.form.contentLength = str.length
// Enable save button if requirements are met
this.disabledByContent = !(this.contentMin <= str.length && str.length <= this.contentMax)
this.validatePost()
},
availableLocales() {
orderBy(locales, 'name').map(locale => {
@ -212,6 +210,7 @@ export default {
},
updateCategories(ids) {
this.form.categoryIds = ids
this.validatePost()
},
addTeaserImage(file) {
this.form.teaserImage = file
@ -223,6 +222,13 @@ export default {
})
return categoryIds
},
validatePost() {
const passesContentValidations =
this.form.contentLength >= this.contentMin && this.form.contentLength <= this.contentMax
const passesCategoryValidations =
this.form.categoryIds.length > 0 && this.form.categoryIds.length <= 3
this.failsValidations = !(passesContentValidations && passesCategoryValidations)
},
},
apollo: {
User: {