Update vue-test-utils and follow updated docs

https://vue-test-utils.vuejs.org/guides/#writing-asynchronous-tests-using-nexttick-new
This commit is contained in:
roschaefer 2020-01-10 23:56:49 +01:00
parent 9a0234f340
commit 8c29ad947b
13 changed files with 117 additions and 66 deletions

View File

@ -1,5 +1,6 @@
import { mount } from '@vue/test-utils'
import CategoriesSelect from './CategoriesSelect'
import Vue from 'vue'
const localVue = global.localVue
@ -55,8 +56,9 @@ describe('CategoriesSelect.vue', () => {
})
describe('toggleCategory', () => {
beforeEach(() => {
beforeEach(async () => {
wrapper.vm.categories = categories
await Vue.nextTick()
democracyAndPolitics = wrapper.findAll('button').at(0)
democracyAndPolitics.trigger('click')
})

View File

@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils'
import CommentForm from './CommentForm'
import Vue from 'vue'
import MutationObserver from 'mutation-observer'
global.MutationObserver = MutationObserver
@ -74,6 +74,7 @@ describe('CommentForm.vue', () => {
it('calls `clear` method when the cancel button is clicked', async () => {
wrapper.vm.updateEditorContent('ok')
await Vue.nextTick()
await wrapper.find('.cancelBtn').trigger('submit')
expect(cancelMethodSpy).toHaveBeenCalledTimes(1)
})

View File

@ -1,6 +1,7 @@
import { config, mount } from '@vue/test-utils'
import ContributionForm from './ContributionForm.vue'
import Vue from 'vue'
import Vuex from 'vuex'
import PostMutations from '~/graphql/PostMutations.js'
import CategoriesSelect from '~/components/CategoriesSelect/CategoriesSelect'
@ -147,31 +148,31 @@ describe('ContributionForm.vue', () => {
dataPrivacyButton.trigger('click')
})
it('title should not be empty', async () => {
it('title cannot be empty', async () => {
postTitleInput.setValue('')
wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
it('title should not be too long', async () => {
it('title cannot be too long', async () => {
postTitleInput.setValue(postTitleTooLong)
wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
it('title should not be too short', async () => {
it('title cannot be too short', async () => {
postTitleInput.setValue(postTitleTooShort)
wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
it('content should not be empty', async () => {
it('content cannot be empty', async () => {
await wrapper.vm.updateEditorContent('')
await wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
it('should have at least one category', async () => {
it('has at least one category', async () => {
dataPrivacyButton = await wrapper
.find(CategoriesSelect)
.find('[data-test="category-buttons-cat12"]')
@ -180,8 +181,9 @@ describe('ContributionForm.vue', () => {
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
it('should have not have more than three categories', async () => {
it('has no more than three categories', async () => {
wrapper.vm.form.categoryIds = ['cat4', 'cat9', 'cat15', 'cat27']
await Vue.nextTick()
wrapper.find('form').trigger('submit')
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
@ -209,10 +211,12 @@ describe('ContributionForm.vue', () => {
wrapper.find(CategoriesSelect).setData({ categories })
englishLanguage = wrapper.findAll('li').filter(language => language.text() === 'English')
englishLanguage.trigger('click')
await Vue.nextTick()
dataPrivacyButton = await wrapper
.find(CategoriesSelect)
.find('[data-test="category-buttons-cat12"]')
dataPrivacyButton.trigger('click')
await Vue.nextTick()
})
it('creates a post with valid title, content, and at least one category', async () => {
@ -278,10 +282,12 @@ describe('ContributionForm.vue', () => {
wrapper.find(CategoriesSelect).setData({ categories })
englishLanguage = wrapper.findAll('li').filter(language => language.text() === 'English')
englishLanguage.trigger('click')
await Vue.nextTick()
dataPrivacyButton = await wrapper
.find(CategoriesSelect)
.find('[data-test="category-buttons-cat12"]')
dataPrivacyButton.trigger('click')
await Vue.nextTick()
})
it('shows an error toaster when apollo mutation rejects', async () => {
@ -370,6 +376,7 @@ describe('ContributionForm.vue', () => {
it('supports updating categories', async () => {
expectedParams.variables.categoryIds.push('cat3')
wrapper.find(CategoriesSelect).setData({ categories })
await Vue.nextTick()
const healthWellbeingButton = await wrapper
.find(CategoriesSelect)
.find('[data-test="category-buttons-cat3"]')

View File

@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils'
import DeleteData from './DeleteData.vue'
import Vue from 'vue'
import Vuex from 'vuex'
const localVue = global.localVue
@ -168,6 +168,7 @@ describe('DeleteData.vue', () => {
it('shows an error toaster when the mutation rejects', async () => {
enableDeletionInput = wrapper.find('.enable-deletion-input input')
enableDeletionInput.setValue(deleteAccountName)
await Vue.nextTick()
deleteAccountBtn = wrapper.find('.ds-button-danger')
await deleteAccountBtn.trigger('click')
// second submission causes mutation to reject

View File

@ -1,5 +1,5 @@
import { mount } from '@vue/test-utils'
import Vue from 'vue'
import MasonryGrid from './MasonryGrid'
const localVue = global.localVue
@ -13,29 +13,29 @@ describe('MasonryGrid', () => {
masonryGridItem = wrapper.vm.$children[0]
})
it('adds the "reset-grid-height" class when itemsCalculating is more than 0', () => {
it('adds the "reset-grid-height" class when itemsCalculating is more than 0', async () => {
wrapper.setData({ itemsCalculating: 1 })
await Vue.nextTick()
expect(wrapper.classes()).toContain('reset-grid-height')
})
it('removes the "reset-grid-height" class when itemsCalculating is 0', () => {
it('removes the "reset-grid-height" class when itemsCalculating is 0', async () => {
wrapper.setData({ itemsCalculating: 0 })
await Vue.nextTick()
expect(wrapper.classes()).not.toContain('reset-grid-height')
})
it('adds 1 to itemsCalculating when a child emits "calculating-item-height"', () => {
it('adds 1 to itemsCalculating when a child emits "calculating-item-height"', async () => {
wrapper.setData({ itemsCalculating: 0 })
masonryGridItem.$emit('calculating-item-height')
await Vue.nextTick()
expect(wrapper.vm.itemsCalculating).toBe(1)
})
it('subtracts 1 from itemsCalculating when a child emits "finished-calculating-item-height"', () => {
it('subtracts 1 from itemsCalculating when a child emits "finished-calculating-item-height"', async () => {
wrapper.setData({ itemsCalculating: 2 })
masonryGridItem.$emit('finished-calculating-item-height')
await Vue.nextTick()
expect(wrapper.vm.itemsCalculating).toBe(1)
})
})

View File

@ -5,6 +5,7 @@ import DisableModal from './Modal/DisableModal.vue'
import ReportModal from './Modal/ReportModal.vue'
import Vuex from 'vuex'
import { getters, mutations } from '../store/modal'
import Vue from 'vue'
const localVue = global.localVue
@ -89,8 +90,9 @@ describe('Modal.vue', () => {
})
describe('child component emits close', () => {
it('turns empty', () => {
it('turns empty', async () => {
wrapper.find(DisableModal).vm.$emit('close')
await Vue.nextTick()
expect(wrapper.contains(DisableModal)).toBe(false)
})
})

View File

@ -1,5 +1,6 @@
import { config, shallowMount, mount } from '@vue/test-utils'
import ReportModal from './ReportModal.vue'
import Vue from 'vue'
const localVue = global.localVue
@ -151,9 +152,11 @@ describe('ReportModal.vue', () => {
})
describe('click confirm button', () => {
beforeEach(() => {
beforeEach(async () => {
wrapper.find('.ds-radio-option-label').trigger('click')
await Vue.nextTick()
wrapper.find('button.confirm').trigger('click')
await Vue.nextTick()
})
it('calls report mutation', () => {

View File

@ -62,14 +62,6 @@ export default {
showCropper: false,
}
},
watch: {
error() {
const that = this
setTimeout(function() {
that.error = false
}, 2000)
},
},
methods: {
template() {
return `<div class="dz-preview dz-file-preview">
@ -82,6 +74,9 @@ export default {
verror(file, message) {
this.error = true
this.$toast.error(file.status, message)
setTimeout(() => {
this.error = false
}, 2000)
},
transformImage(file) {
this.file = file

View File

@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils'
import Vue from 'vue'
import Upload from '.'
const localVue = global.localVue
@ -57,8 +58,9 @@ describe('Upload', () => {
expect(mocks.$toast.error).toHaveBeenCalledWith(fileError.status, message)
})
it('changes error status from false to true to false', () => {
it('changes error status from false to true to false', async () => {
wrapper.vm.verror(fileError, message)
await Vue.nextTick()
expect(wrapper.vm.error).toEqual(true)
jest.runAllTimers()
expect(wrapper.vm.error).toEqual(false)

View File

@ -45,14 +45,16 @@ describe('SearchableInput.vue', () => {
expect(wrapper.find('.is-open').exists()).toBe(true)
})
it('opens the select dropdown and blurs after focused on', () => {
it('opens the select dropdown and blurs after focused on', async () => {
select.trigger('blur')
await Vue.nextTick()
expect(wrapper.find('.is-open').exists()).toBe(false)
})
it('is clearable', () => {
it('is clearable', async () => {
select.trigger('input')
select.trigger('keyup.esc')
await Vue.nextTick()
expect(wrapper.find('.is-open').exists()).toBe(false)
})
@ -88,11 +90,10 @@ describe('SearchableInput.vue', () => {
select.trigger('input')
const post = wrapper.find('.search-post')
post.trigger('click')
await Vue.nextTick().then(() => {
expect(mocks.$router.push).toHaveBeenCalledWith({
name: 'post-id-slug',
params: { id: 'post-by-jenny', slug: 'user-post-by-jenny' },
})
await Vue.nextTick()
expect(mocks.$router.push).toHaveBeenCalledWith({
name: 'post-id-slug',
params: { id: 'post-by-jenny', slug: 'user-post-by-jenny' },
})
})
@ -102,11 +103,10 @@ describe('SearchableInput.vue', () => {
const users = wrapper.findAll('.userinfo')
const bob = users.filter(item => item.text() === '@bob-der-baumeister')
bob.trigger('click')
await Vue.nextTick().then(() => {
expect(mocks.$router.push).toHaveBeenCalledWith({
name: 'profile-id-slug',
params: { id: 'u2', slug: 'bob-der-baumeister' },
})
await Vue.nextTick()
expect(mocks.$router.push).toHaveBeenCalledWith({
name: 'profile-id-slug',
params: { id: 'u2', slug: 'bob-der-baumeister' },
})
})
})

View File

@ -106,7 +106,7 @@
"@vue/cli-shared-utils": "~4.1.2",
"@vue/eslint-config-prettier": "~6.0.0",
"@vue/server-test-utils": "~1.0.0-beta.30",
"@vue/test-utils": "~1.0.0-beta.29",
"@vue/test-utils": "~1.0.0-beta.30",
"async-validator": "^3.2.3",
"babel-core": "~7.0.0-bridge.0",
"babel-eslint": "~10.0.3",

View File

@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils'
import flushPromises from 'flush-promises'
import MySocialMedia from './my-social-media.vue'
import Vuex from 'vuex'
import Vue from 'vue'
const localVue = global.localVue
@ -48,10 +49,10 @@ describe('my-social-media.vue', () => {
submitButton = wrapper.find('button')
})
it('requires the link to be a valid url', () => {
it('requires the link to be a valid url', async () => {
input.setValue('some value')
form.trigger('submit')
await Vue.nextTick()
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
@ -59,19 +60,19 @@ describe('my-social-media.vue', () => {
mocks.$apollo.mutate.mockRejectedValue({ message: 'Ouch!' })
input.setValue(newSocialMediaUrl)
form.trigger('submit')
await Vue.nextTick()
await flushPromises()
expect(mocks.$toast.error).toHaveBeenCalledTimes(1)
})
describe('success', () => {
beforeEach(() => {
beforeEach(async () => {
mocks.$apollo.mutate.mockResolvedValue({
data: { CreateSocialMedia: { id: 's2', url: newSocialMediaUrl } },
})
input.setValue(newSocialMediaUrl)
form.trigger('submit')
await Vue.nextTick()
})
it('sends the new url to the backend', () => {
@ -84,13 +85,11 @@ describe('my-social-media.vue', () => {
it('displays a success message', async () => {
await flushPromises()
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
})
it('clears the form', async () => {
await flushPromises()
expect(input.value).toBe(undefined)
expect(submitButton.vm.$attrs.disabled).toBe(true)
})
@ -127,19 +126,18 @@ describe('my-social-media.vue', () => {
})
})
it('does not accept a duplicate url', () => {
input = wrapper.find('input#addSocialMedia')
input.setValue(socialMediaUrl)
it('does not accept a duplicate url', async () => {
wrapper.find('input#addSocialMedia').setValue(socialMediaUrl)
form.trigger('submit')
await Vue.nextTick()
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
})
describe('editing social media link', () => {
beforeEach(() => {
beforeEach(async () => {
const editButton = wrapper.find('a[name="edit"]')
editButton.trigger('click')
await Vue.nextTick()
input = wrapper.find('input#editSocialMedia')
})
@ -149,28 +147,29 @@ describe('my-social-media.vue', () => {
expect(addInput.exists()).toBe(false)
})
it('sends the new url to the backend', () => {
it('sends the new url to the backend', async () => {
const expected = expect.objectContaining({
variables: { id: 's1', url: newSocialMediaUrl },
})
input.setValue(newSocialMediaUrl)
form.trigger('submit')
await Vue.nextTick()
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
})
it('allows the user to cancel editing', () => {
it('allows the user to cancel editing', async () => {
const cancelButton = wrapper.find('button#cancel')
cancelButton.trigger('click')
await Vue.nextTick()
expect(wrapper.find('input#editSocialMedia').exists()).toBe(false)
})
})
describe('deleting social media link', () => {
beforeEach(() => {
beforeEach(async () => {
const deleteButton = wrapper.find('a[name="delete"]')
deleteButton.trigger('click')
await Vue.nextTick()
})
it('sends the link id to the backend', () => {
@ -184,7 +183,6 @@ describe('my-social-media.vue', () => {
it('displays a success message', async () => {
await flushPromises()
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
})
})

View File

@ -2861,13 +2861,14 @@
"@types/cheerio" "^0.22.10"
cheerio "^1.0.0-rc.2"
"@vue/test-utils@~1.0.0-beta.29":
version "1.0.0-beta.29"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.29.tgz#c942cf25e891cf081b6a03332b4ae1ef430726f0"
integrity sha512-yX4sxEIHh4M9yAbLA/ikpEnGKMNBCnoX98xE1RwxfhQVcn0MaXNSj1Qmac+ZydTj6VBSEVukchBogXBTwc+9iA==
"@vue/test-utils@~1.0.0-beta.30":
version "1.0.0-beta.30"
resolved "https://registry.yarnpkg.com/@vue/test-utils/-/test-utils-1.0.0-beta.30.tgz#d5f26d1e2411fdb7fa7fdedb61b4b4ea4194c49d"
integrity sha512-Wyvcha9fNk8+kzTDwb3xWGjPkCPzHSYSwKP6MplrPTG/auhqoad7JqUEceZLc6u7AU4km2pPQ8/m9s0RgCZ0NA==
dependencies:
dom-event-types "^1.0.0"
lodash "^4.17.4"
lodash "^4.17.15"
pretty "^2.0.0"
"@webassemblyjs/ast@1.8.5":
version "1.8.5"
@ -5577,6 +5578,15 @@ concat-stream@^1.5.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
condense-newlines@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/condense-newlines/-/condense-newlines-0.2.1.tgz#3de985553139475d32502c83b02f60684d24c55f"
integrity sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=
dependencies:
extend-shallow "^2.0.1"
is-whitespace "^0.3.0"
kind-of "^3.0.2"
config-chain@^1.1.12:
version "1.1.12"
resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.12.tgz#0fde8d091200eb5e808caf25fe618c02f48e4efa"
@ -9255,6 +9265,11 @@ is-utf8@^0.2.0:
resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
is-whitespace@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/is-whitespace/-/is-whitespace-0.3.0.tgz#1639ecb1be036aec69a54cbb401cfbed7114ab7f"
integrity sha1-Fjnssb4DauxppUy7QBz77XEUq38=
is-window@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-window/-/is-window-1.0.2.tgz#2c896ca53db97de45d3c33133a65d8c9f563480d"
@ -9747,6 +9762,17 @@ js-base64@^2.1.8:
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
js-beautify@^1.6.12:
version "1.10.2"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.2.tgz#88c9099cd6559402b124cfab18754936f8a7b178"
integrity sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ==
dependencies:
config-chain "^1.1.12"
editorconfig "^0.15.3"
glob "^7.1.3"
mkdirp "~0.5.1"
nopt "~4.0.1"
js-beautify@^1.6.14:
version "1.10.0"
resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.10.0.tgz#9753a13c858d96828658cd18ae3ca0e5783ea672"
@ -12720,6 +12746,15 @@ pretty-time@^1.1.0:
resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e"
integrity sha512-28iF6xPQrP8Oa6uxE6a1biz+lWeTOAPKggvjB8HAs6nVMKZwf5bG++632Dx614hIWgUPkgivRfG+a8uAXGTIbA==
pretty@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pretty/-/pretty-2.0.0.tgz#adbc7960b7bbfe289a557dc5f737619a220d06a5"
integrity sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=
dependencies:
condense-newlines "^0.2.1"
extend-shallow "^2.0.1"
js-beautify "^1.6.12"
prismjs@^1.8.4, prismjs@~1.17.0:
version "1.17.1"
resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.17.1.tgz#e669fcbd4cdd873c35102881c33b14d0d68519be"
@ -14064,6 +14099,11 @@ serve-static@1.14.1, serve-static@^1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.17.1"
server-destroy@^1.0.1:
version "1.0.1"