diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index 9c67126e2..2bec6cebb 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -267,7 +267,7 @@ jobs:
report_name: Coverage Webapp
type: lcov
result_path: ./coverage/lcov.info
- min_coverage: 52
+ min_coverage: 65
token: ${{ github.token }}
##############################################################################
diff --git a/webapp/components/ComponentSlider/ComponentSlider.spec.js b/webapp/components/ComponentSlider/ComponentSlider.spec.js
new file mode 100644
index 000000000..25bf3e7f4
--- /dev/null
+++ b/webapp/components/ComponentSlider/ComponentSlider.spec.js
@@ -0,0 +1,64 @@
+import { mount } from '@vue/test-utils'
+import ComponentSlider from './ComponentSlider.vue'
+
+const localVue = global.localVue
+
+describe('ComponentSlider.vue', () => {
+ let wrapper
+ let mocks
+ let propsData
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ propsData = {
+ sliderData: {
+ sliderIndex: 0,
+ sliderSelectorCallback: jest.fn().mockResolvedValue(true),
+ sliders: [
+ {
+ validated: true,
+ button: {
+ icon: 'smile',
+ callback: jest.fn().mockResolvedValue(true),
+ sliderCallback: jest.fn().mockResolvedValue(true),
+ },
+ },
+ {
+ validated: true,
+ button: {
+ icon: 'smile',
+ callback: jest.fn().mockResolvedValue(true),
+ sliderCallback: jest.fn().mockResolvedValue(true),
+ },
+ },
+ ],
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(ComponentSlider, {
+ mocks,
+ localVue,
+ propsData,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('click on next Button', async () => {
+ await wrapper.find('.base-button[data-test="next-button"]').trigger('click')
+ await wrapper.vm.$nextTick()
+ expect(propsData.sliderData.sliderSelectorCallback).toHaveBeenCalled()
+ })
+ })
+})
diff --git a/webapp/components/FollowButton.spec.js b/webapp/components/FollowButton.spec.js
new file mode 100644
index 000000000..000745081
--- /dev/null
+++ b/webapp/components/FollowButton.spec.js
@@ -0,0 +1,47 @@
+import { mount } from '@vue/test-utils'
+import FollowButton from './FollowButton.vue'
+
+const localVue = global.localVue
+
+describe('FollowButton.vue', () => {
+ let mocks
+ let propsData
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ mutate: jest.fn(),
+ },
+ }
+ propsData = {}
+ })
+
+ describe('mount', () => {
+ let wrapper
+ const Wrapper = () => {
+ return mount(FollowButton, { mocks, propsData, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders button and text', () => {
+ expect(mocks.$t).toHaveBeenCalledWith('followButton.follow')
+ expect(wrapper.findAll('.base-button')).toHaveLength(1)
+ })
+
+ it('renders button and text when followed', () => {
+ propsData.isFollowed = true
+ wrapper = Wrapper()
+ expect(mocks.$t).toHaveBeenCalledWith('followButton.following')
+ expect(wrapper.findAll('.base-button')).toHaveLength(1)
+ })
+
+ it.skip('toggle the button', async () => {
+ wrapper.find('.base-button').trigger('click') // This does not work since @click.prevent is used
+ expect(wrapper.vm.isFollowed).toBe(true)
+ })
+ })
+})
diff --git a/webapp/components/InviteButton/InviteButton.spec.js b/webapp/components/InviteButton/InviteButton.spec.js
new file mode 100644
index 000000000..f28045612
--- /dev/null
+++ b/webapp/components/InviteButton/InviteButton.spec.js
@@ -0,0 +1,53 @@
+import { config, mount } from '@vue/test-utils'
+import InviteButton from './InviteButton.vue'
+
+config.stubs['v-popover'] = ''
+
+describe('InviteButton.vue', () => {
+ let wrapper
+ let mocks
+ let propsData
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ navigator: {
+ clipboard: {
+ writeText: jest.fn(),
+ },
+ },
+ }
+ propsData = {}
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(InviteButton, { mocks, propsData })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.contains('.invite-button')).toBe(true)
+ })
+
+ it('open popup', () => {
+ wrapper.find('.base-button').trigger('click')
+ expect(wrapper.contains('.invite-button')).toBe(true)
+ })
+
+ it('invite codes not available', async () => {
+ wrapper.find('.base-button').trigger('click') // open popup
+ wrapper.find('.invite-button').trigger('click') // click copy button
+ expect(mocks.$t).toHaveBeenCalledWith('invite-codes.not-available')
+ })
+
+ it.skip('invite codes copied to clipboard', async () => {
+ wrapper.find('.base-button').trigger('click') // open popup
+ wrapper.find('.invite-button').trigger('click') // click copy button
+ expect(mocks.$t).toHaveBeenCalledWith('invite-codes.not-available')
+ })
+ })
+})
diff --git a/webapp/components/Logo/Logo.spec.js b/webapp/components/Logo/Logo.spec.js
new file mode 100644
index 000000000..a712a529b
--- /dev/null
+++ b/webapp/components/Logo/Logo.spec.js
@@ -0,0 +1,29 @@
+import { mount } from '@vue/test-utils'
+import Logo from './Logo.vue'
+
+const localVue = global.localVue
+
+describe('Logo.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Logo, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.ds-logo')).toHaveLength(1)
+ })
+ })
+})
diff --git a/webapp/components/Modal.spec.js b/webapp/components/Modal.spec.js
index 3ebff8771..c08c90f51 100644
--- a/webapp/components/Modal.spec.js
+++ b/webapp/components/Modal.spec.js
@@ -131,6 +131,42 @@ describe('Modal.vue', () => {
})
})
})
+
+ describe('store/modal data contains an user', () => {
+ it('passes user name to report modal', () => {
+ state.data = {
+ type: 'user',
+ resource: {
+ id: 'u456',
+ name: 'Username',
+ },
+ }
+ wrapper = Wrapper()
+ expect(wrapper.find(DisableModal).props()).toEqual({
+ type: 'user',
+ name: 'Username',
+ id: 'u456',
+ })
+ })
+ })
+
+ describe('store/modal data contains no valid datatype', () => {
+ it('passes something as datatype to modal', () => {
+ state.data = {
+ type: 'something',
+ resource: {
+ id: 's456',
+ name: 'Username',
+ },
+ }
+ wrapper = Wrapper()
+ expect(wrapper.find(DisableModal).props()).toEqual({
+ type: 'something',
+ name: null,
+ id: 's456',
+ })
+ })
+ })
})
})
})
diff --git a/webapp/components/NotificationList/NotificationList.spec.js b/webapp/components/NotificationList/NotificationList.spec.js
index ce20a2765..219c1fdbb 100644
--- a/webapp/components/NotificationList/NotificationList.spec.js
+++ b/webapp/components/NotificationList/NotificationList.spec.js
@@ -81,4 +81,23 @@ describe('NotificationList.vue', () => {
})
})
})
+
+ describe('shallowMount with no notifications', () => {
+ const Wrapper = () => {
+ return shallowMount(NotificationList, {
+ propsData: {},
+ mocks,
+ store,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders Notification.vue zero times', () => {
+ expect(wrapper.findAll(Notification)).toHaveLength(0)
+ })
+ })
})
diff --git a/webapp/components/PageFooter/PageFooter.spec.js b/webapp/components/PageFooter/PageFooter.spec.js
new file mode 100644
index 000000000..0edc0fed2
--- /dev/null
+++ b/webapp/components/PageFooter/PageFooter.spec.js
@@ -0,0 +1,44 @@
+import { config, mount } from '@vue/test-utils'
+import PageFooter from './PageFooter.vue'
+import links from '~/constants/links.js'
+
+const localVue = global.localVue
+
+config.stubs['nuxt-link'] = ''
+
+describe('PageFooter.vue', () => {
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $env: {
+ VERSION: 'v1.0.0',
+ },
+ links,
+ }
+ })
+
+ describe('mount', () => {
+ let wrapper
+ const Wrapper = () => {
+ return mount(PageFooter, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders three links', () => {
+ expect(wrapper.findAll('a')).toHaveLength(3)
+ })
+
+ it('renders four nuxt-links', () => {
+ expect(wrapper.findAll('.nuxt-link')).toHaveLength(4)
+ })
+
+ it('renders version', () => {
+ expect(wrapper.find('.ds-footer').text()).toContain('v1.0.0')
+ })
+ })
+})
diff --git a/webapp/components/Password/Change.spec.js b/webapp/components/Password/Change.spec.js
index 8416a0fce..95b7c1a3a 100644
--- a/webapp/components/Password/Change.spec.js
+++ b/webapp/components/Password/Change.spec.js
@@ -126,21 +126,18 @@ describe('ChangePassword.vue', () => {
})
})
- // TODO This is not a valid testcase - we have to decide if we catch the same password on clientside
- /* describe('mutation rejects', () => {
+ describe('mutation rejects', () => {
beforeEach(async () => {
await wrapper.find('input#oldPassword').setValue('supersecret')
await wrapper.find('input#password').setValue('supersecret')
await wrapper.find('input#passwordConfirmation').setValue('supersecret')
+ await wrapper.find('form').trigger('submit')
})
it('displays error message', async () => {
- await wrapper.find('form').trigger('submit')
- await mocks.$apollo.mutate
-
expect(mocks.$toast.error).toHaveBeenCalledWith('Ouch!')
})
- }) */
+ })
})
})
})
diff --git a/webapp/components/PasswordReset/ChangePassword.spec.js b/webapp/components/PasswordReset/ChangePassword.spec.js
index b1b55cb06..d6f451604 100644
--- a/webapp/components/PasswordReset/ChangePassword.spec.js
+++ b/webapp/components/PasswordReset/ChangePassword.spec.js
@@ -76,6 +76,22 @@ describe('ChangePassword ', () => {
})
})
})
+
+ describe('password reset not successful', () => {
+ beforeEach(() => {
+ mocks.$apollo.mutate = jest.fn().mockRejectedValue({
+ message: 'Ouch!',
+ })
+ wrapper = Wrapper()
+ wrapper.find('input#password').setValue('supersecret')
+ wrapper.find('input#passwordConfirmation').setValue('supersecret')
+ wrapper.find('form').trigger('submit')
+ })
+
+ it('display a toast error', () => {
+ expect(mocks.$toast.error).toHaveBeenCalled()
+ })
+ })
})
})
})
diff --git a/webapp/components/PasswordReset/Request.spec.js b/webapp/components/PasswordReset/Request.spec.js
index 83459814e..e601030c6 100644
--- a/webapp/components/PasswordReset/Request.spec.js
+++ b/webapp/components/PasswordReset/Request.spec.js
@@ -95,5 +95,20 @@ describe('Request', () => {
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
})
})
+
+ describe('backend throws an error', () => {
+ beforeEach(() => {
+ mocks.$apollo.mutate = jest.fn().mockRejectedValue({
+ message: 'Ouch!',
+ })
+ wrapper = Wrapper()
+ wrapper.find('input#email').setValue('mail@gmail.com')
+ wrapper.find('form').trigger('submit')
+ })
+
+ it('display a toast error', () => {
+ expect(mocks.$toast.error).toHaveBeenCalled()
+ })
+ })
})
})
diff --git a/webapp/components/Registration/Signup.spec.js b/webapp/components/Registration/Signup.spec.js
index 36b16903c..dda0cbb9d 100644
--- a/webapp/components/Registration/Signup.spec.js
+++ b/webapp/components/Registration/Signup.spec.js
@@ -76,6 +76,21 @@ describe('Signup', () => {
expect(mocks.$t).toHaveBeenCalledWith(...expected)
})
+ describe('mutation is rejected', () => {
+ beforeEach(async () => {
+ mocks.$apollo.mutate = jest.fn().mockRejectedValue({
+ message: 'Ouch!',
+ })
+ wrapper = Wrapper()
+ wrapper.find('input#email').setValue('mail@example.org')
+ await wrapper.find('form').trigger('submit')
+ })
+
+ it('displays error message', async () => {
+ expect(mocks.$toast.error).toHaveBeenCalledWith('Ouch!')
+ })
+ })
+
describe('after animation', () => {
beforeEach(jest.runAllTimers)
diff --git a/webapp/components/ShoutButton.spec.js b/webapp/components/ShoutButton.spec.js
new file mode 100644
index 000000000..c3af134c1
--- /dev/null
+++ b/webapp/components/ShoutButton.spec.js
@@ -0,0 +1,57 @@
+import { mount } from '@vue/test-utils'
+import ShoutButton from './ShoutButton.vue'
+import Vue from 'vue'
+
+const localVue = global.localVue
+
+describe('ShoutButton.vue', () => {
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ mutate: jest.fn(),
+ },
+ }
+ })
+
+ describe('mount', () => {
+ let wrapper
+ const Wrapper = () => {
+ return mount(ShoutButton, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders button and text', () => {
+ expect(mocks.$t).toHaveBeenCalledWith('shoutButton.shouted')
+ expect(wrapper.findAll('.base-button')).toHaveLength(1)
+ expect(wrapper.findAll('.shout-button-text')).toHaveLength(1)
+ expect(wrapper.vm.shouted).toBe(false)
+ expect(wrapper.vm.shoutedCount).toBe(0)
+ })
+
+ it('toggle the button', async () => {
+ mocks.$apollo.mutate = jest.fn().mockResolvedValue({ data: { shout: 'WeDoShout' } })
+ wrapper.find('.base-button').trigger('click')
+ expect(wrapper.vm.shouted).toBe(true)
+ expect(wrapper.vm.shoutedCount).toBe(1)
+ await Vue.nextTick()
+ expect(wrapper.vm.shouted).toBe(true)
+ expect(wrapper.vm.shoutedCount).toBe(1)
+ })
+
+ it('toggle the button, but backend fails', async () => {
+ mocks.$apollo.mutate = jest.fn().mockRejectedValue({ message: 'Ouch!' })
+ await wrapper.find('.base-button').trigger('click')
+ expect(wrapper.vm.shouted).toBe(true)
+ expect(wrapper.vm.shoutedCount).toBe(1)
+ await Vue.nextTick()
+ expect(wrapper.vm.shouted).toBe(false)
+ expect(wrapper.vm.shoutedCount).toBe(0)
+ })
+ })
+})
diff --git a/webapp/components/features/ReportsTable/ReportsTable.spec.js b/webapp/components/features/ReportsTable/ReportsTable.spec.js
index a9baeea4f..c80e4fea5 100644
--- a/webapp/components/features/ReportsTable/ReportsTable.spec.js
+++ b/webapp/components/features/ReportsTable/ReportsTable.spec.js
@@ -34,7 +34,7 @@ describe('ReportsTable', () => {
describe('given no reports', () => {
beforeEach(() => {
- propsData = { ...propsData, reports: [] }
+ propsData = { ...propsData }
wrapper = Wrapper()
})
diff --git a/webapp/components/generic/SearchableInput/SearchableInput.spec.js b/webapp/components/generic/SearchableInput/SearchableInput.spec.js
index 53c361997..e0e9f9831 100644
--- a/webapp/components/generic/SearchableInput/SearchableInput.spec.js
+++ b/webapp/components/generic/SearchableInput/SearchableInput.spec.js
@@ -120,5 +120,15 @@ describe('SearchableInput.vue', () => {
query: { search: 'ab' },
})
})
+
+ it('replaces irregular whitespace with a single space', async () => {
+ select.element.value = 'peter lustig'
+ select.trigger('input')
+ select.trigger('keyup.enter')
+ expect(mocks.$router.push).toHaveBeenCalledWith({
+ path: '/search/search-results',
+ query: { search: 'peter lustig' },
+ })
+ })
})
})
diff --git a/webapp/layouts/basic.spec.js b/webapp/layouts/basic.spec.js
new file mode 100644
index 000000000..5094a970b
--- /dev/null
+++ b/webapp/layouts/basic.spec.js
@@ -0,0 +1,34 @@
+import { config, shallowMount } from '@vue/test-utils'
+import Basic from './basic.vue'
+
+const localVue = global.localVue
+
+config.stubs.nuxt = ''
+
+describe('basic.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('shallow mount', () => {
+ const Wrapper = () => {
+ return shallowMount(Basic, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.layout-blank')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/layouts/blank.spec.js b/webapp/layouts/blank.spec.js
new file mode 100644
index 000000000..a3ea3120c
--- /dev/null
+++ b/webapp/layouts/blank.spec.js
@@ -0,0 +1,34 @@
+import { config, shallowMount } from '@vue/test-utils'
+import Blank from './blank.vue'
+
+const localVue = global.localVue
+
+config.stubs.nuxt = ''
+
+describe('blank.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('shallow mount', () => {
+ const Wrapper = () => {
+ return shallowMount(Blank, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.layout-blank')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/layouts/default.spec.js b/webapp/layouts/default.spec.js
new file mode 100644
index 000000000..3d465ce76
--- /dev/null
+++ b/webapp/layouts/default.spec.js
@@ -0,0 +1,52 @@
+import Vuex from 'vuex'
+import { config, shallowMount } from '@vue/test-utils'
+import Default from './default.vue'
+
+const localVue = global.localVue
+localVue.directive('scrollTo', jest.fn())
+
+config.stubs.nuxt = ''
+config.stubs['client-only'] = ''
+config.stubs['nuxt-link'] = ''
+
+describe('default.vue', () => {
+ let wrapper
+ let mocks
+ let store
+
+ beforeEach(() => {
+ mocks = {
+ $route: {
+ matched: [{ name: 'index' }],
+ },
+ $scrollTo: jest.fn(),
+ $t: jest.fn(),
+ $env: {
+ INVITE_REGISTRATION: true,
+ },
+ }
+ store = new Vuex.Store({
+ getters: {
+ 'auth/isLoggedIn': () => true,
+ },
+ })
+ })
+
+ describe('shallow mount', () => {
+ const Wrapper = () => {
+ return shallowMount(Default, {
+ store,
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.layout-default')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/package.json b/webapp/package.json
index 84cdcbc7c..7abe34e4a 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -24,9 +24,17 @@
"verbose": true,
"collectCoverageFrom": [
"**/*.{js,vue}",
+ "!**/?(*.)+(spec|test|story).js?(x)",
"!**/node_modules/**",
"!**/.nuxt/**",
- "!**/?(*.)+(spec|test).js?(x)"
+ "!**/storybook/**",
+ "!**/coverage/**",
+ "!**/config/**",
+ "!**/maintenance/**",
+ "!**/plugins/**",
+ "!**/.eslintrc.js",
+ "!**/.prettierrc.js",
+ "!**/nuxt.config.js"
],
"coverageReporters": [
"lcov"
@@ -41,10 +49,10 @@
"vue"
],
"moduleNameMapper": {
- "^@/(.*)$": "/src/$1",
- "^~/(.*)$": "/$1",
+ "\\.(svg)$": "/test/fileMock.js",
"\\.(css|less)$": "identity-obj-proxy",
- "\\.(svg)$": "/test/fileMock.js"
+ "^@/(.*)$": "/src/$1",
+ "^~/(.*)$": "/$1"
},
"setupFiles": [
"/test/registerContext.js",
diff --git a/webapp/pages/admin.spec.js b/webapp/pages/admin.spec.js
new file mode 100644
index 000000000..fc3849fc4
--- /dev/null
+++ b/webapp/pages/admin.spec.js
@@ -0,0 +1,34 @@
+import { config, mount } from '@vue/test-utils'
+import admin from './admin.vue'
+
+config.stubs['nuxt-child'] = ''
+
+const localVue = global.localVue
+
+describe('admin.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(admin, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/categories.spec.js b/webapp/pages/admin/categories.spec.js
new file mode 100644
index 000000000..55715e74b
--- /dev/null
+++ b/webapp/pages/admin/categories.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import Categories from './categories.vue'
+
+const localVue = global.localVue
+
+describe('categories.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Categories, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/donations.spec.js b/webapp/pages/admin/donations.spec.js
new file mode 100644
index 000000000..2bc219dce
--- /dev/null
+++ b/webapp/pages/admin/donations.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import Donations from './donations.vue'
+
+const localVue = global.localVue
+
+describe('donations.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Donations, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/hashtags.spec.js b/webapp/pages/admin/hashtags.spec.js
new file mode 100644
index 000000000..cd2d308d1
--- /dev/null
+++ b/webapp/pages/admin/hashtags.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import Hashtags from './hashtags.vue'
+
+const localVue = global.localVue
+
+describe('hashtags.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Hashtags, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/invite.spec.js b/webapp/pages/admin/invite.spec.js
new file mode 100644
index 000000000..e3e882119
--- /dev/null
+++ b/webapp/pages/admin/invite.spec.js
@@ -0,0 +1,35 @@
+import { mount } from '@vue/test-utils'
+import Invite from './invite.vue'
+
+const localVue = global.localVue
+
+describe('invite.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ loading: false,
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Invite, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.ds-section')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/notifications.spec.js b/webapp/pages/admin/notifications.spec.js
new file mode 100644
index 000000000..c9acf81a6
--- /dev/null
+++ b/webapp/pages/admin/notifications.spec.js
@@ -0,0 +1,35 @@
+import { mount } from '@vue/test-utils'
+import Notifications from './notifications.vue'
+
+const localVue = global.localVue
+
+describe('notifications.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ loading: false,
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Notifications, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/organizations.spec.js b/webapp/pages/admin/organizations.spec.js
new file mode 100644
index 000000000..d019d9485
--- /dev/null
+++ b/webapp/pages/admin/organizations.spec.js
@@ -0,0 +1,35 @@
+import { mount } from '@vue/test-utils'
+import Organizations from './organizations.vue'
+
+const localVue = global.localVue
+
+describe('organizations.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ loading: false,
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Organizations, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/pages.spec.js b/webapp/pages/admin/pages.spec.js
new file mode 100644
index 000000000..e0c3c9fb4
--- /dev/null
+++ b/webapp/pages/admin/pages.spec.js
@@ -0,0 +1,35 @@
+import { mount } from '@vue/test-utils'
+import Pages from './pages.vue'
+
+const localVue = global.localVue
+
+describe('pages.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ loading: false,
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Pages, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/admin/settings.spec.js b/webapp/pages/admin/settings.spec.js
new file mode 100644
index 000000000..78a5beb94
--- /dev/null
+++ b/webapp/pages/admin/settings.spec.js
@@ -0,0 +1,35 @@
+import { mount } from '@vue/test-utils'
+import Settings from './settings.vue'
+
+const localVue = global.localVue
+
+describe('settings.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ loading: false,
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Settings, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/code-of-conduct.spec.js b/webapp/pages/code-of-conduct.spec.js
new file mode 100644
index 000000000..75e244c79
--- /dev/null
+++ b/webapp/pages/code-of-conduct.spec.js
@@ -0,0 +1,38 @@
+import { mount } from '@vue/test-utils'
+import CodeOfConduct from './code-of-conduct.vue'
+import VueMeta from 'vue-meta'
+
+const localVue = global.localVue
+localVue.use(VueMeta, { keyName: 'head' })
+
+describe('code-of-conduct.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: (t) => t,
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(CodeOfConduct, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('has correct content', () => {
+ expect(wrapper.vm.$metaInfo.title).toBe('site.code-of-conduct')
+ })
+ })
+})
diff --git a/webapp/pages/data-privacy.spec.js b/webapp/pages/data-privacy.spec.js
new file mode 100644
index 000000000..a919bb742
--- /dev/null
+++ b/webapp/pages/data-privacy.spec.js
@@ -0,0 +1,38 @@
+import { mount } from '@vue/test-utils'
+import DataPrivacy from './data-privacy.vue'
+import VueMeta from 'vue-meta'
+
+const localVue = global.localVue
+localVue.use(VueMeta, { keyName: 'head' })
+
+describe('data-privacy.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: (t) => t,
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(DataPrivacy, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('has correct content', () => {
+ expect(wrapper.vm.$metaInfo.title).toBe('site.data-privacy')
+ })
+ })
+})
diff --git a/webapp/pages/imprint.spec.js b/webapp/pages/imprint.spec.js
new file mode 100644
index 000000000..1a84b5794
--- /dev/null
+++ b/webapp/pages/imprint.spec.js
@@ -0,0 +1,38 @@
+import { mount } from '@vue/test-utils'
+import Imprint from './imprint.vue'
+import VueMeta from 'vue-meta'
+
+const localVue = global.localVue
+localVue.use(VueMeta, { keyName: 'head' })
+
+describe('imprint.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: (t) => t,
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Imprint, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('has correct content', () => {
+ expect(wrapper.vm.$metaInfo.title).toBe('site.imprint')
+ })
+ })
+})
diff --git a/webapp/pages/login.spec.js b/webapp/pages/login.spec.js
new file mode 100644
index 000000000..09c1b066e
--- /dev/null
+++ b/webapp/pages/login.spec.js
@@ -0,0 +1,74 @@
+import Vuex from 'vuex'
+import { config, mount } from '@vue/test-utils'
+import login from './login.vue'
+
+const localVue = global.localVue
+
+config.stubs['client-only'] = ''
+config.stubs['nuxt-link'] = ''
+
+describe('Login.vue', () => {
+ let store
+ let mocks
+ let wrapper
+ let asyncData
+ let tosVersion
+ let redirect
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $i18n: {
+ locale: () => 'en',
+ },
+ }
+ asyncData = false
+ tosVersion = '0.0.0'
+ redirect = jest.fn()
+ })
+
+ describe('mount', () => {
+ const Wrapper = async () => {
+ store = new Vuex.Store({
+ getters: {
+ 'auth/user': () => {
+ return { termsAndConditionsAgreedVersion: tosVersion }
+ },
+ },
+ })
+ if (asyncData) {
+ const data = login.data ? login.data() : {}
+ const aData = await login.asyncData({
+ store,
+ redirect,
+ })
+ login.data = function () {
+ return { ...data, ...aData }
+ }
+ }
+ return mount(login, {
+ store,
+ mocks,
+ localVue,
+ })
+ }
+
+ it('renders', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.findAll('.login-form')).toHaveLength(1)
+ })
+
+ it('renders with asyncData and wrong TOS Version', async () => {
+ asyncData = true
+ wrapper = await Wrapper()
+ expect(redirect).not.toHaveBeenCalled()
+ })
+
+ it('renders with asyncData and correct TOS Version', async () => {
+ asyncData = true
+ tosVersion = '0.0.4'
+ wrapper = await Wrapper()
+ expect(redirect).toBeCalledWith('/')
+ })
+ })
+})
diff --git a/webapp/pages/logout.spec.js b/webapp/pages/logout.spec.js
new file mode 100644
index 000000000..4ec777bf6
--- /dev/null
+++ b/webapp/pages/logout.spec.js
@@ -0,0 +1,43 @@
+import { mount } from '@vue/test-utils'
+import Logout from './logout.vue'
+
+const localVue = global.localVue
+
+describe('logout.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $store: {
+ dispatch: jest.fn(),
+ },
+ $router: {
+ replace: jest.fn(),
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Logout, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('logs out and redirects to login', () => {
+ expect(mocks.$store.dispatch).toBeCalledWith('auth/logout')
+ expect(mocks.$router.replace).toBeCalledWith('/login')
+ })
+ })
+})
diff --git a/webapp/pages/moderation.spec.js b/webapp/pages/moderation.spec.js
new file mode 100644
index 000000000..2eeae9f7c
--- /dev/null
+++ b/webapp/pages/moderation.spec.js
@@ -0,0 +1,34 @@
+import { config, mount } from '@vue/test-utils'
+import moderation from './moderation.vue'
+
+config.stubs['nuxt-child'] = ''
+
+const localVue = global.localVue
+
+describe('moderation.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(moderation, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/moderation/index.spec.js b/webapp/pages/moderation/index.spec.js
new file mode 100644
index 000000000..249752aa3
--- /dev/null
+++ b/webapp/pages/moderation/index.spec.js
@@ -0,0 +1,30 @@
+import { config, mount } from '@vue/test-utils'
+import Moderation from './index.vue'
+
+const localVue = global.localVue
+config.stubs['client-only'] = ''
+
+describe('moderation/index.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Moderation, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/password-reset.spec.js b/webapp/pages/password-reset.spec.js
new file mode 100644
index 000000000..01052e89c
--- /dev/null
+++ b/webapp/pages/password-reset.spec.js
@@ -0,0 +1,71 @@
+import Vuex from 'vuex'
+import { config, mount } from '@vue/test-utils'
+import PasswordReset from './password-reset.vue'
+
+const localVue = global.localVue
+
+config.stubs['client-only'] = ''
+config.stubs['nuxt-child'] = ''
+
+describe('password-reset.vue', () => {
+ let wrapper
+ let mocks
+ let asyncData
+ let store
+ let redirect
+ let isLoggedIn
+
+ beforeEach(() => {
+ mocks = {
+ $t: (t) => t,
+ $i18n: {
+ locale: () => 'en',
+ },
+ }
+ asyncData = false
+ isLoggedIn = false
+ redirect = jest.fn()
+ })
+
+ describe('mount', () => {
+ const Wrapper = async () => {
+ store = new Vuex.Store({
+ getters: {
+ 'auth/isLoggedIn': () => isLoggedIn,
+ },
+ })
+ if (asyncData) {
+ const data = PasswordReset.data ? PasswordReset.data() : {}
+ const aData = await PasswordReset.asyncData({
+ store,
+ redirect,
+ })
+ PasswordReset.data = function () {
+ return { ...data, ...aData }
+ }
+ }
+ return mount(PasswordReset, {
+ mocks,
+ localVue,
+ })
+ }
+
+ it('renders', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('renders with asyncData and not loggedIn', async () => {
+ asyncData = true
+ wrapper = await Wrapper()
+ expect(redirect).not.toHaveBeenCalled()
+ })
+
+ it('renders with asyncData and loggedIn', async () => {
+ asyncData = true
+ isLoggedIn = true
+ wrapper = await Wrapper()
+ expect(redirect).toBeCalledWith('/')
+ })
+ })
+})
diff --git a/webapp/pages/password-reset/change-password.spec.js b/webapp/pages/password-reset/change-password.spec.js
new file mode 100644
index 000000000..cad031c95
--- /dev/null
+++ b/webapp/pages/password-reset/change-password.spec.js
@@ -0,0 +1,35 @@
+import { mount } from '@vue/test-utils'
+import changePassword from './change-password.vue'
+
+const localVue = global.localVue
+
+describe('enter-nonce.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $route: {
+ query: jest.fn().mockResolvedValue({ email: 'peter@lustig.de', nonce: '12345' }),
+ },
+ $apollo: {
+ loading: false,
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(changePassword, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.ds-form')).toHaveLength(1)
+ })
+ })
+})
diff --git a/webapp/pages/password-reset/enter-nonce.spec.js b/webapp/pages/password-reset/enter-nonce.spec.js
new file mode 100644
index 000000000..664e1f7ca
--- /dev/null
+++ b/webapp/pages/password-reset/enter-nonce.spec.js
@@ -0,0 +1,34 @@
+import { config, mount } from '@vue/test-utils'
+import enterNonce from './enter-nonce.vue'
+
+const localVue = global.localVue
+
+config.stubs['nuxt-link'] = ''
+
+describe('enter-nonce.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $route: {
+ query: jest.fn().mockResolvedValue({ email: 'peter@lustig.de' }),
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(enterNonce, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.ds-form')).toHaveLength(1)
+ })
+ })
+})
diff --git a/webapp/pages/password-reset/request.spec.js b/webapp/pages/password-reset/request.spec.js
new file mode 100644
index 000000000..f9bcefd79
--- /dev/null
+++ b/webapp/pages/password-reset/request.spec.js
@@ -0,0 +1,55 @@
+import { config, mount } from '@vue/test-utils'
+import request from './request.vue'
+
+const localVue = global.localVue
+
+// config.stubs['sweetalert-icon'] = ''
+config.stubs['nuxt-link'] = ''
+
+describe('request.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ /* $toast: {
+ success: jest.fn(),
+ error: jest.fn(),
+ }, */
+ $t: jest.fn(),
+ $apollo: {
+ loading: false,
+ // mutate: jest.fn().mockResolvedValue({ data: { reqestPasswordReset: true } }),
+ },
+ /* $router: {
+ push: jest.fn()
+ } */
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(request, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.ds-form')).toHaveLength(1)
+ })
+
+ it.skip('calls "handlePasswordResetRequested" on submit', async () => {
+ await jest.useFakeTimers()
+ await wrapper.find('input#email').setValue('mail@example.org')
+ await wrapper.findAll('.ds-form').trigger('submit')
+ await jest.runAllTimers()
+ expect(wrapper.emitted('handleSubmitted')).toEqual([[{ email: 'mail@example.org' }]])
+ expect(mocks.$router.push).toHaveBeenCalledWith({
+ path: 'enter-nonce',
+ query: { email: 'mail@example.org' },
+ })
+ })
+ })
+})
diff --git a/webapp/pages/post/_id.spec.js b/webapp/pages/post/_id.spec.js
new file mode 100644
index 000000000..7e6812002
--- /dev/null
+++ b/webapp/pages/post/_id.spec.js
@@ -0,0 +1,37 @@
+import { config, mount } from '@vue/test-utils'
+import _id from './_id.vue'
+
+const localVue = global.localVue
+
+config.stubs['nuxt-child'] = ''
+
+describe('post/_id.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $route: {
+ params: {
+ id: '1234',
+ slug: 'my-post',
+ },
+ },
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(_id, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.post-side-navigation')).toHaveLength(1)
+ })
+ })
+})
diff --git a/webapp/pages/post/_id/_slug/index.spec.js b/webapp/pages/post/_id/_slug/index.spec.js
index bc54edf53..4289bb53d 100644
--- a/webapp/pages/post/_id/_slug/index.spec.js
+++ b/webapp/pages/post/_id/_slug/index.spec.js
@@ -4,6 +4,7 @@ import Vue from 'vue'
import PostSlug from './index.vue'
import CommentList from '~/components/CommentList/CommentList'
import HcHashtag from '~/components/Hashtag/Hashtag'
+import VueMeta from 'vue-meta'
config.stubs['client-only'] = ''
config.stubs['nuxt-link'] = ''
@@ -11,6 +12,7 @@ config.stubs['router-link'] = ''
const localVue = global.localVue
localVue.directive('scrollTo', jest.fn())
+localVue.use(VueMeta, { keyName: 'head' })
describe('PostSlug', () => {
let wrapper, Wrapper, backendData, mocks, stubs
@@ -91,6 +93,11 @@ describe('PostSlug', () => {
return wrapper
}
+ it('has correct content', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.vm.$metaInfo.title).toBe('loading')
+ })
+
describe('given author is `null`', () => {
it('does not crash', async () => {
backendData = {
diff --git a/webapp/pages/post/create.spec.js b/webapp/pages/post/create.spec.js
new file mode 100644
index 000000000..951edba03
--- /dev/null
+++ b/webapp/pages/post/create.spec.js
@@ -0,0 +1,29 @@
+import { mount } from '@vue/test-utils'
+import create from './create.vue'
+
+const localVue = global.localVue
+
+describe('create.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(create, { mocks, localVue })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.contribution-form')).toHaveLength(1)
+ })
+ })
+})
diff --git a/webapp/pages/post/edit/_id.spec.js b/webapp/pages/post/edit/_id.spec.js
new file mode 100644
index 000000000..ea8ec61d8
--- /dev/null
+++ b/webapp/pages/post/edit/_id.spec.js
@@ -0,0 +1,82 @@
+import Vuex from 'vuex'
+import { mount } from '@vue/test-utils'
+import _id from './_id.vue'
+
+const localVue = global.localVue
+
+describe('post/_id.vue', () => {
+ let wrapper
+ let mocks
+ let store
+ let asyncData
+ let error
+ let userId
+ let authorId
+
+ beforeEach(() => {
+ asyncData = false
+ error = jest.fn()
+ })
+
+ describe('mount', () => {
+ const Wrapper = async () => {
+ mocks = {
+ $t: jest.fn(),
+ $i18n: {
+ locale: () => 'en',
+ },
+ apolloProvider: {
+ defaultClient: {
+ query: jest.fn().mockResolvedValue({
+ data: {
+ Post: [{ author: { id: authorId } }],
+ },
+ }),
+ },
+ },
+ }
+ store = new Vuex.Store({
+ getters: {
+ 'auth/user': () => {
+ return { id: userId }
+ },
+ },
+ })
+ if (asyncData) {
+ const data = _id.data ? _id.data() : {}
+ const aData = await _id.asyncData({
+ app: mocks,
+ store,
+ error,
+ params: { id: '123' },
+ })
+ _id.data = function () {
+ return { ...data, ...aData }
+ }
+ }
+ return mount(_id, { store, mocks, localVue })
+ }
+
+ it('renders', async () => {
+ asyncData = false
+ wrapper = await Wrapper()
+ expect(wrapper.findAll('.contribution-form')).toHaveLength(1)
+ })
+
+ it('renders with asyncData of different users', async () => {
+ asyncData = true
+ authorId = 'some-author'
+ userId = 'some-user'
+ wrapper = await Wrapper()
+ expect(error).toBeCalledWith({ message: 'error-pages.cannot-edit-post', statusCode: 403 })
+ })
+
+ it('renders with asyncData of same user', async () => {
+ asyncData = true
+ authorId = 'some-author'
+ userId = 'some-author'
+ wrapper = await Wrapper()
+ expect(error).not.toHaveBeenCalled()
+ })
+ })
+})
diff --git a/webapp/pages/profile/_id.spec.js b/webapp/pages/profile/_id.spec.js
new file mode 100644
index 000000000..aab216569
--- /dev/null
+++ b/webapp/pages/profile/_id.spec.js
@@ -0,0 +1,33 @@
+import { config, mount } from '@vue/test-utils'
+import _id from './_id.vue'
+
+const localVue = global.localVue
+
+config.stubs['nuxt-child'] = ''
+
+describe('Profile _id.vue', () => {
+ let wrapper
+ let Wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {}
+ })
+
+ describe('mount', () => {
+ Wrapper = () => {
+ return mount(_id, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.findAll('.nuxt-child')).toHaveLength(1)
+ })
+ })
+})
diff --git a/webapp/pages/registration.spec.js b/webapp/pages/registration.spec.js
index b83cb6ad4..74fb7d710 100644
--- a/webapp/pages/registration.spec.js
+++ b/webapp/pages/registration.spec.js
@@ -1,3 +1,4 @@
+import Vuex from 'vuex'
import { config, mount } from '@vue/test-utils'
import Registration from './registration.vue'
import Vue from 'vue'
@@ -13,6 +14,10 @@ describe('Registration', () => {
let wrapper
let Wrapper
let mocks
+ let asyncData
+ let store
+ let redirect
+ let isLoggedIn
beforeEach(() => {
mocks = {
@@ -25,10 +30,42 @@ describe('Registration', () => {
},
$env: {},
}
+ asyncData = false
+ isLoggedIn = false
+ redirect = jest.fn()
})
describe('mount', () => {
- Wrapper = () => {
+ Wrapper = async () => {
+ if (asyncData) {
+ store = new Vuex.Store({
+ getters: {
+ 'auth/isLoggedIn': () => isLoggedIn,
+ },
+ })
+ const data = {
+ method: mocks,
+ overwriteSliderData: {
+ collectedInputData: {
+ inviteCode: null,
+ email: null,
+ emailSend: !!null,
+ nonce: null,
+ },
+ },
+ publicRegistration: false,
+ inviteRegistration: false,
+ }
+ const aData = await Registration.asyncData({
+ store,
+ redirect,
+ })
+ Registration.data = function () {
+ return { ...data, ...aData }
+ }
+ } else {
+ Registration.data = Registration.backupData ? Registration.backupData : Registration.data
+ }
return mount(Registration, {
mocks,
localVue,
@@ -43,25 +80,25 @@ describe('Registration', () => {
}
})
- it('no "method" query in URI show "RegistrationSlideNoPublic"', () => {
+ it('no "method" query in URI show "RegistrationSlideNoPublic"', async () => {
mocks.$route.query = {}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.hc-empty').exists()).toBe(true)
expect(wrapper.find('.enter-invite').exists()).toBe(false)
expect(wrapper.find('.enter-email').exists()).toBe(false)
})
describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
- it('no "email" query in URI', () => {
+ it('no "email" query in URI', async () => {
mocks.$route.query = { method: 'invite-mail' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').exists()).toBe(true)
})
describe('"email=user%40example.org" query in URI', () => {
- it('have email displayed', () => {
+ it('have email displayed', async () => {
mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
})
@@ -71,7 +108,7 @@ describe('Registration', () => {
email: 'user@example.org',
nonce: '64835',
}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
await Vue.nextTick()
const form = wrapper.find('.enter-nonce')
expect(form.vm.formData.nonce).toEqual('64835')
@@ -80,15 +117,15 @@ describe('Registration', () => {
})
describe('"method=invite-code" in URI show "RegistrationSlideNoPublic"', () => {
- it('no "inviteCode" query in URI', () => {
+ it('no "inviteCode" query in URI', async () => {
mocks.$route.query = { method: 'invite-code' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.hc-empty').exists()).toBe(true)
})
- it('"inviteCode=AAAAAA" query in URI', () => {
+ it('"inviteCode=AAAAAA" query in URI', async () => {
mocks.$route.query = { method: 'invite-code', inviteCode: 'AAAAAA' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.hc-empty').exists()).toBe(true)
})
})
@@ -102,24 +139,24 @@ describe('Registration', () => {
}
})
- it('no "method" query in URI show "RegistrationSlideInvite"', () => {
+ it('no "method" query in URI show "RegistrationSlideInvite"', async () => {
mocks.$route.query = {}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-invite').exists()).toBe(true)
expect(wrapper.find('.enter-email').exists()).toBe(false)
})
describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
- it('no "inviteCode" query in URI', () => {
+ it('no "inviteCode" query in URI', async () => {
mocks.$route.query = { method: 'invite-mail' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').exists()).toBe(true)
})
describe('"email=user%40example.org" query in URI', () => {
- it('have email displayed', () => {
+ it('have email displayed', async () => {
mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
})
@@ -129,7 +166,7 @@ describe('Registration', () => {
email: 'user@example.org',
nonce: '64835',
}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
await Vue.nextTick()
const form = wrapper.find('.enter-nonce')
expect(form.vm.formData.nonce).toEqual('64835')
@@ -138,15 +175,15 @@ describe('Registration', () => {
})
describe('"method=invite-code" in URI show "RegistrationSlideInvite"', () => {
- it('no "inviteCode" query in URI', () => {
+ it('no "inviteCode" query in URI', async () => {
mocks.$route.query = { method: 'invite-code' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-invite').exists()).toBe(true)
})
it('"inviteCode=AAAAAA" query in URI have invite code in input', async () => {
mocks.$route.query = { method: 'invite-code', inviteCode: 'AAAAAA' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
await Vue.nextTick()
const form = wrapper.find('.enter-invite')
expect(form.vm.formData.inviteCode).toEqual('AAAAAA')
@@ -162,24 +199,24 @@ describe('Registration', () => {
}
})
- it('no "method" query in URI show "RegistrationSlideEmail"', () => {
+ it('no "method" query in URI show "RegistrationSlideEmail"', async () => {
mocks.$route.query = {}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-email').exists()).toBe(true)
expect(wrapper.find('.enter-invite').exists()).toBe(false)
})
describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
- it('no "inviteCode" query in URI', () => {
+ it('no "inviteCode" query in URI', async () => {
mocks.$route.query = { method: 'invite-mail' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').exists()).toBe(true)
})
describe('"email=user%40example.org" query in URI', () => {
- it('have email displayed', () => {
+ it('have email displayed', async () => {
mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
})
@@ -189,7 +226,7 @@ describe('Registration', () => {
email: 'user@example.org',
nonce: '64835',
}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
await Vue.nextTick()
const form = wrapper.find('.enter-nonce')
expect(form.vm.formData.nonce).toEqual('64835')
@@ -198,9 +235,9 @@ describe('Registration', () => {
})
describe('"method=invite-code" in URI show "RegistrationSlideEmail"', () => {
- it('no "inviteCode" query in URI', () => {
+ it('no "inviteCode" query in URI', async () => {
mocks.$route.query = { method: 'invite-code' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-email').exists()).toBe(true)
expect(wrapper.find('.enter-invite').exists()).toBe(false)
})
@@ -215,24 +252,24 @@ describe('Registration', () => {
}
})
- it('no "method" query in URI show "RegistrationSlideEmail"', () => {
+ it('no "method" query in URI show "RegistrationSlideEmail"', async () => {
mocks.$route.query = {}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-email').exists()).toBe(true)
expect(wrapper.find('.enter-invite').exists()).toBe(false)
})
describe('"method=invite-mail" in URI show "RegistrationSlideNonce"', () => {
- it('no "inviteCode" query in URI', () => {
+ it('no "inviteCode" query in URI', async () => {
mocks.$route.query = { method: 'invite-mail' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').exists()).toBe(true)
})
describe('"email=user%40example.org" query in URI', () => {
- it('have email displayed', () => {
+ it('have email displayed', async () => {
mocks.$route.query = { method: 'invite-mail', email: 'user@example.org' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-nonce').text()).toContain('user@example.org')
})
@@ -242,7 +279,7 @@ describe('Registration', () => {
email: 'user@example.org',
nonce: '64835',
}
- wrapper = Wrapper()
+ wrapper = await Wrapper()
await Vue.nextTick()
const form = wrapper.find('.enter-nonce')
expect(form.vm.formData.nonce).toEqual('64835')
@@ -251,15 +288,15 @@ describe('Registration', () => {
})
describe('"method=invite-code" in URI show "RegistrationSlideInvite"', () => {
- it('no "inviteCode" query in URI', () => {
+ it('no "inviteCode" query in URI', async () => {
mocks.$route.query = { method: 'invite-code' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
expect(wrapper.find('.enter-invite').exists()).toBe(true)
})
it('"inviteCode=AAAAAA" query in URI have invite code in input', async () => {
mocks.$route.query = { method: 'invite-code', inviteCode: 'AAAAAA' }
- wrapper = Wrapper()
+ wrapper = await Wrapper()
await Vue.nextTick()
const form = wrapper.find('.enter-invite')
expect(form.vm.formData.inviteCode).toEqual('AAAAAA')
@@ -267,6 +304,25 @@ describe('Registration', () => {
})
})
+ it('renders', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.is('.login-form')).toBe(true)
+ })
+
+ // The asyncTests must go last
+ it('renders with asyncData and not loggedIn', async () => {
+ asyncData = true
+ wrapper = await Wrapper()
+ expect(redirect).not.toHaveBeenCalled()
+ })
+
+ it('renders with asyncData and loggedIn', async () => {
+ asyncData = true
+ isLoggedIn = true
+ wrapper = await Wrapper()
+ expect(redirect).toBeCalledWith('/')
+ })
+
// copied from webapp/components/Registration/Signup.spec.js as testing template
// describe('with invitation code', () => {
// let action
diff --git a/webapp/pages/search/search-results.spec.js b/webapp/pages/search/search-results.spec.js
new file mode 100644
index 000000000..c594f3e56
--- /dev/null
+++ b/webapp/pages/search/search-results.spec.js
@@ -0,0 +1,61 @@
+import { config, mount } from '@vue/test-utils'
+import searchResults from './search-results.vue'
+import VueMeta from 'vue-meta'
+
+const localVue = global.localVue
+localVue.use(VueMeta, { keyName: 'head' })
+
+config.stubs['client-only'] = ''
+
+describe('search-results.vue', () => {
+ let wrapper
+ let mocks
+ let asyncData
+ let query
+
+ beforeEach(() => {
+ mocks = {
+ $t: (t) => t,
+ }
+ asyncData = false
+ query = {}
+ })
+
+ describe('mount', () => {
+ const Wrapper = async () => {
+ if (asyncData) {
+ const data = searchResults.data ? searchResults.data() : {}
+ const aData = await searchResults.asyncData({
+ query,
+ })
+ searchResults.data = function () {
+ return { ...data, ...aData }
+ }
+ }
+ return mount(searchResults, { mocks, localVue })
+ }
+
+ it('renders', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.findAll('.search-results')).toHaveLength(1)
+ })
+
+ it('has correct content', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.vm.$metaInfo.title).toBe('search.title')
+ })
+
+ it('renders with asyncData and no query', async () => {
+ asyncData = true
+ wrapper = await Wrapper()
+ expect(wrapper.vm.search).toBe(null)
+ })
+
+ it('renders with asyncData and query', async () => {
+ asyncData = true
+ query = { search: 'hello' }
+ wrapper = await Wrapper()
+ expect(wrapper.vm.search).toBe('hello')
+ })
+ })
+})
diff --git a/webapp/pages/settings.spec.js b/webapp/pages/settings.spec.js
new file mode 100644
index 000000000..353f1e6b8
--- /dev/null
+++ b/webapp/pages/settings.spec.js
@@ -0,0 +1,34 @@
+import { config, mount } from '@vue/test-utils'
+import settings from './settings.vue'
+
+const localVue = global.localVue
+
+config.stubs['nuxt-child'] = ''
+
+describe('settings.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(settings, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/data-download.spec.js b/webapp/pages/settings/data-download.spec.js
new file mode 100644
index 000000000..b50c8d046
--- /dev/null
+++ b/webapp/pages/settings/data-download.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import DataDownload from './data-download.vue'
+
+const localVue = global.localVue
+
+describe('data-download.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(DataDownload, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/delete-account.spec.js b/webapp/pages/settings/delete-account.spec.js
new file mode 100644
index 000000000..aa8ffd954
--- /dev/null
+++ b/webapp/pages/settings/delete-account.spec.js
@@ -0,0 +1,42 @@
+import Vuex from 'vuex'
+import { mount } from '@vue/test-utils'
+import DeleteAccount from './delete-account.vue'
+
+const localVue = global.localVue
+
+describe('delete-account.vue', () => {
+ let wrapper
+ let mocks
+ let store
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ store = new Vuex.Store({
+ getters: {
+ 'auth/user': () => {
+ return { id: 'u343', name: 'Delete MyAccount' }
+ },
+ },
+ })
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(DeleteAccount, {
+ store,
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.delete-data')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/embeds.spec.js b/webapp/pages/settings/embeds.spec.js
new file mode 100644
index 000000000..75247ddf0
--- /dev/null
+++ b/webapp/pages/settings/embeds.spec.js
@@ -0,0 +1,42 @@
+import Vuex from 'vuex'
+import { mount } from '@vue/test-utils'
+import Embeds from './embeds.vue'
+
+const localVue = global.localVue
+
+describe('embeds.vue', () => {
+ let wrapper
+ let mocks
+ let store
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ store = new Vuex.Store({
+ getters: {
+ 'auth/user': () => {
+ return { id: 'u343', name: 'Delete MyAccount', allowEmbedIframes: true }
+ },
+ },
+ })
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Embeds, {
+ store,
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/invites.spec.js b/webapp/pages/settings/invites.spec.js
new file mode 100644
index 000000000..cbc8d1765
--- /dev/null
+++ b/webapp/pages/settings/invites.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import Invites from './invites.vue'
+
+const localVue = global.localVue
+
+describe('invites.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Invites, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/languages.spec.js b/webapp/pages/settings/languages.spec.js
new file mode 100644
index 000000000..0e3665739
--- /dev/null
+++ b/webapp/pages/settings/languages.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import Languages from './languages.vue'
+
+const localVue = global.localVue
+
+describe('languages.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Languages, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/my-email-address/index.spec.js b/webapp/pages/settings/my-email-address/index.spec.js
index 22654afd0..808aee3be 100644
--- a/webapp/pages/settings/my-email-address/index.spec.js
+++ b/webapp/pages/settings/my-email-address/index.spec.js
@@ -111,6 +111,21 @@ describe('EmailSettingsIndexPage', () => {
expect(wrapper.text()).toContain('registration.signup.form.errors.email-exists')
})
})
+
+ describe('if backend sends any other error', () => {
+ beforeEach(() => {
+ mocks.$apollo.mutate = jest.fn().mockRejectedValue({
+ message: 'Ouch!',
+ })
+ wrapper = Wrapper()
+ wrapper.find('#email').setValue('already-taken@example.org')
+ wrapper.find('form').trigger('submit')
+ })
+
+ it('display a toast error', () => {
+ expect(mocks.$toast.error).toHaveBeenCalled()
+ })
+ })
})
})
})
diff --git a/webapp/pages/settings/my-organizations.spec.js b/webapp/pages/settings/my-organizations.spec.js
new file mode 100644
index 000000000..7f11b9871
--- /dev/null
+++ b/webapp/pages/settings/my-organizations.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import MyOrganizations from './my-organizations.vue'
+
+const localVue = global.localVue
+
+describe('my-organizations.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(MyOrganizations, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/privacy.spec.js b/webapp/pages/settings/privacy.spec.js
new file mode 100644
index 000000000..eb9cb90b3
--- /dev/null
+++ b/webapp/pages/settings/privacy.spec.js
@@ -0,0 +1,70 @@
+import Vuex from 'vuex'
+import { mount } from '@vue/test-utils'
+import Privacy from './privacy.vue'
+
+const localVue = global.localVue
+
+describe('privacy.vue', () => {
+ let wrapper
+ let mocks
+ let store
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ mutate: jest.fn(),
+ },
+ $toast: {
+ success: jest.fn(),
+ error: jest.fn(),
+ },
+ }
+ store = new Vuex.Store({
+ getters: {
+ 'auth/user': () => {
+ return {
+ id: 'u343',
+ name: 'MyAccount',
+ showShoutsPublicly: true,
+ }
+ },
+ },
+ })
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Privacy, {
+ store,
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+
+ it('clicking on submit changes shoutsAllowed to false', async () => {
+ wrapper.find('#allow-shouts').trigger('click')
+ await wrapper.vm.$nextTick()
+ wrapper.find('.base-button').trigger('click')
+ expect(wrapper.vm.shoutsAllowed).toBe(false)
+ })
+
+ it('clicking on submit with a server error shows a toast and shoutsAllowed is still true', async () => {
+ mocks.$apollo.mutate = jest.fn().mockRejectedValue({ message: 'Ouch!' })
+ wrapper.find('#allow-shouts').trigger('click')
+ await wrapper.vm.$nextTick()
+ await wrapper.find('.base-button').trigger('click')
+ await wrapper.vm.$nextTick()
+ expect(mocks.$toast.error).toHaveBeenCalledWith('Ouch!')
+ expect(wrapper.vm.shoutsAllowed).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/settings/privacy.vue b/webapp/pages/settings/privacy.vue
index 14f27bf8f..71fd31946 100644
--- a/webapp/pages/settings/privacy.vue
+++ b/webapp/pages/settings/privacy.vue
@@ -52,6 +52,7 @@ export default {
},
})
} catch (error) {
+ this.shoutsAllowed = !this.shoutsAllowed
this.$toast.error(error.message)
}
},
diff --git a/webapp/pages/settings/security.spec.js b/webapp/pages/settings/security.spec.js
new file mode 100644
index 000000000..dee9e640a
--- /dev/null
+++ b/webapp/pages/settings/security.spec.js
@@ -0,0 +1,32 @@
+import { mount } from '@vue/test-utils'
+import Security from './security.vue'
+
+const localVue = global.localVue
+
+describe('security.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: jest.fn(),
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(Security, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('.base-card')).toBe(true)
+ })
+ })
+})
diff --git a/webapp/pages/terms-and-conditions-confirm.spec.js b/webapp/pages/terms-and-conditions-confirm.spec.js
new file mode 100644
index 000000000..098e73a92
--- /dev/null
+++ b/webapp/pages/terms-and-conditions-confirm.spec.js
@@ -0,0 +1,74 @@
+import Vuex from 'vuex'
+import { config, mount } from '@vue/test-utils'
+import TermsAndConditionsConfirm from './terms-and-conditions-confirm.vue'
+import VueMeta from 'vue-meta'
+
+const localVue = global.localVue
+localVue.use(VueMeta, { keyName: 'head' })
+
+config.stubs['nuxt-link'] = ''
+
+describe('terms-and-conditions-confirm.vue', () => {
+ let wrapper
+ let mocks
+ let store
+ let asyncData
+ let tosAgree
+ let redirect
+
+ beforeEach(() => {
+ mocks = {
+ $t: (t) => t,
+ }
+ asyncData = false
+ tosAgree = false
+ redirect = jest.fn()
+ })
+
+ describe('mount', () => {
+ const Wrapper = async () => {
+ store = new Vuex.Store({
+ getters: {
+ 'auth/termsAndConditionsAgreed': () => tosAgree,
+ },
+ })
+ if (asyncData) {
+ const data = TermsAndConditionsConfirm.data ? TermsAndConditionsConfirm.data() : {}
+ const aData = await TermsAndConditionsConfirm.asyncData({
+ store,
+ redirect,
+ })
+ TermsAndConditionsConfirm.data = function () {
+ return { ...data, ...aData }
+ }
+ }
+ return mount(TermsAndConditionsConfirm, {
+ mocks,
+ localVue,
+ })
+ }
+
+ it('renders', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('has correct content', async () => {
+ wrapper = await Wrapper()
+ expect(wrapper.vm.$metaInfo.title).toBe('termsAndConditions.newTermsAndConditions')
+ })
+
+ it('renders with asyncData and did not agree to TOS', async () => {
+ asyncData = true
+ wrapper = await Wrapper()
+ expect(redirect).not.toHaveBeenCalled()
+ })
+
+ it('renders with asyncData and did agree to TOS', async () => {
+ asyncData = true
+ tosAgree = true
+ wrapper = await Wrapper()
+ expect(redirect).toBeCalledWith('/')
+ })
+ })
+})
diff --git a/webapp/pages/terms-and-conditions.spec.js b/webapp/pages/terms-and-conditions.spec.js
new file mode 100644
index 000000000..d6ae6dce7
--- /dev/null
+++ b/webapp/pages/terms-and-conditions.spec.js
@@ -0,0 +1,38 @@
+import { mount } from '@vue/test-utils'
+import TermsAndConditions from './terms-and-conditions.vue'
+import VueMeta from 'vue-meta'
+
+const localVue = global.localVue
+localVue.use(VueMeta, { keyName: 'head' })
+
+describe('terms-and-conditions.vue', () => {
+ let wrapper
+ let mocks
+
+ beforeEach(() => {
+ mocks = {
+ $t: (t) => t,
+ }
+ })
+
+ describe('mount', () => {
+ const Wrapper = () => {
+ return mount(TermsAndConditions, {
+ mocks,
+ localVue,
+ })
+ }
+
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ it('renders', () => {
+ expect(wrapper.is('div')).toBe(true)
+ })
+
+ it('has correct content', () => {
+ expect(wrapper.vm.$metaInfo.title).toBe('site.termsAndConditions')
+ })
+ })
+})
diff --git a/webapp/test/fileMock.js b/webapp/test/fileMock.js
index 0e56c5b5f..c77f5e0de 100644
--- a/webapp/test/fileMock.js
+++ b/webapp/test/fileMock.js
@@ -1 +1,3 @@
-module.exports = 'test-file-stub'
+module.exports = {
+ render: () => 'test-file-stub',
+}