diff --git a/webapp/components/CategoriesSelect/CategoriesSelect.spec.js b/webapp/components/CategoriesSelect/CategoriesSelect.spec.js index b633e5811..82f5e61eb 100644 --- a/webapp/components/CategoriesSelect/CategoriesSelect.spec.js +++ b/webapp/components/CategoriesSelect/CategoriesSelect.spec.js @@ -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') }) diff --git a/webapp/components/CommentForm/CommentForm.spec.js b/webapp/components/CommentForm/CommentForm.spec.js index 47bc01982..bcfea323c 100644 --- a/webapp/components/CommentForm/CommentForm.spec.js +++ b/webapp/components/CommentForm/CommentForm.spec.js @@ -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) }) diff --git a/webapp/components/ContributionForm/ContributionForm.spec.js b/webapp/components/ContributionForm/ContributionForm.spec.js index a52169bd1..789b4e5cf 100644 --- a/webapp/components/ContributionForm/ContributionForm.spec.js +++ b/webapp/components/ContributionForm/ContributionForm.spec.js @@ -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"]') diff --git a/webapp/components/DeleteData/DeleteData.spec.js b/webapp/components/DeleteData/DeleteData.spec.js index abcdf9101..739bbe732 100644 --- a/webapp/components/DeleteData/DeleteData.spec.js +++ b/webapp/components/DeleteData/DeleteData.spec.js @@ -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 diff --git a/webapp/components/MasonryGrid/MasonryGrid.spec.js b/webapp/components/MasonryGrid/MasonryGrid.spec.js index b42b9b221..00e7859d8 100644 --- a/webapp/components/MasonryGrid/MasonryGrid.spec.js +++ b/webapp/components/MasonryGrid/MasonryGrid.spec.js @@ -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) }) }) diff --git a/webapp/components/Modal.spec.js b/webapp/components/Modal.spec.js index 2dae4285a..c309d5684 100644 --- a/webapp/components/Modal.spec.js +++ b/webapp/components/Modal.spec.js @@ -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) }) }) diff --git a/webapp/components/Modal/ReportModal.spec.js b/webapp/components/Modal/ReportModal.spec.js index b151f3c7b..de95cce99 100644 --- a/webapp/components/Modal/ReportModal.spec.js +++ b/webapp/components/Modal/ReportModal.spec.js @@ -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', () => { diff --git a/webapp/components/TeaserImage/TeaserImage.vue b/webapp/components/TeaserImage/TeaserImage.vue index a08b9e0ef..c2bf56459 100644 --- a/webapp/components/TeaserImage/TeaserImage.vue +++ b/webapp/components/TeaserImage/TeaserImage.vue @@ -62,14 +62,6 @@ export default { showCropper: false, } }, - watch: { - error() { - const that = this - setTimeout(function() { - that.error = false - }, 2000) - }, - }, methods: { template() { return `
@@ -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 diff --git a/webapp/components/Upload/spec.js b/webapp/components/Upload/spec.js index d9878ea2d..e60429974 100644 --- a/webapp/components/Upload/spec.js +++ b/webapp/components/Upload/spec.js @@ -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) diff --git a/webapp/components/generic/SearchableInput/SearchableInput.spec.js b/webapp/components/generic/SearchableInput/SearchableInput.spec.js index db314630f..0ebcda63f 100644 --- a/webapp/components/generic/SearchableInput/SearchableInput.spec.js +++ b/webapp/components/generic/SearchableInput/SearchableInput.spec.js @@ -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' }, }) }) }) diff --git a/webapp/package.json b/webapp/package.json index 1e56f3201..2928fe343 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -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", diff --git a/webapp/pages/settings/my-social-media.spec.js b/webapp/pages/settings/my-social-media.spec.js index b1c9e0649..dd3c1c2c3 100644 --- a/webapp/pages/settings/my-social-media.spec.js +++ b/webapp/pages/settings/my-social-media.spec.js @@ -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) }) }) diff --git a/webapp/yarn.lock b/webapp/yarn.lock index 38208d897..20dbb098c 100644 --- a/webapp/yarn.lock +++ b/webapp/yarn.lock @@ -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"