diff --git a/backend/src/middleware/notifications/notificationsMiddleware.js b/backend/src/middleware/notifications/notificationsMiddleware.js
index 2bc53ab7c..5419771ea 100644
--- a/backend/src/middleware/notifications/notificationsMiddleware.js
+++ b/backend/src/middleware/notifications/notificationsMiddleware.js
@@ -41,7 +41,6 @@ const publishNotifications = async (context, promises) => {
notifications.forEach((notificationAdded, index) => {
pubsub.publish(NOTIFICATION_ADDED, { notificationAdded })
if (notificationAdded.to.sendNotificationEmails) {
- // Wolle await
sendMail(
notificationTemplate({
email: notificationsEmailAddresses[index].email,
diff --git a/cypress/integration/UserProfile.SocialMedia/I_add_a_social_media_link.js b/cypress/integration/UserProfile.SocialMedia/I_add_a_social_media_link.js
index 9253709f9..ca2e36818 100644
--- a/cypress/integration/UserProfile.SocialMedia/I_add_a_social_media_link.js
+++ b/cypress/integration/UserProfile.SocialMedia/I_add_a_social_media_link.js
@@ -1,9 +1,12 @@
import { When } from "cypress-cucumber-preprocessor/steps";
When('I add a social media link', () => {
- cy.get('input#addSocialMedia')
- .type('https://freeradical.zone/peter-pan')
- .get('button')
+ cy.get('button')
.contains('Add link')
.click()
+ .get('#editSocialMedia')
+ .type('https://freeradical.zone/peter-pan')
+ .get('button')
+ .contains('Save')
+ .click()
})
\ No newline at end of file
diff --git a/cypress/integration/UserProfile.SocialMedia/I_have_added_a_social_media_link.js b/cypress/integration/UserProfile.SocialMedia/I_have_added_a_social_media_link.js
index 203b97032..93e35bf28 100644
--- a/cypress/integration/UserProfile.SocialMedia/I_have_added_a_social_media_link.js
+++ b/cypress/integration/UserProfile.SocialMedia/I_have_added_a_social_media_link.js
@@ -2,9 +2,12 @@ import { Given } from "cypress-cucumber-preprocessor/steps";
Given('I have added a social media link', () => {
cy.visit('/settings/my-social-media')
- .get('input#addSocialMedia')
- .type('https://freeradical.zone/peter-pan')
.get('button')
.contains('Add link')
.click()
+ .get('#editSocialMedia')
+ .type('https://freeradical.zone/peter-pan')
+ .get('button')
+ .contains('Save')
+ .click()
})
\ No newline at end of file
diff --git a/webapp/components/_new/features/MySomethingList/MySomethingList.spec.js b/webapp/components/_new/features/MySomethingList/MySomethingList.spec.js
new file mode 100644
index 000000000..513207110
--- /dev/null
+++ b/webapp/components/_new/features/MySomethingList/MySomethingList.spec.js
@@ -0,0 +1,128 @@
+import { mount } from '@vue/test-utils'
+import MySomethingList from './MySomethingList.vue'
+import Vue from 'vue'
+
+const localVue = global.localVue
+
+describe('MySomethingList.vue', () => {
+ let wrapper
+ let propsData
+ let data
+ let mocks
+
+ beforeEach(() => {
+ propsData = {
+ useFormData: { dummy: '' },
+ useItems: [{ id: 'id', dummy: 'dummy' }],
+ namePropertyKey: 'dummy',
+ callbacks: { edit: jest.fn(), submit: jest.fn(), delete: jest.fn() },
+ }
+ data = () => {
+ return {}
+ }
+ mocks = {
+ $t: jest.fn(),
+ $apollo: {
+ mutate: jest.fn(),
+ },
+ $toast: {
+ error: jest.fn(),
+ success: jest.fn(),
+ },
+ }
+ })
+
+ describe('mount', () => {
+ let form, slots
+ const Wrapper = () => {
+ slots = {
+ 'list-item': '
',
+ 'edit-item': '',
+ }
+ return mount(MySomethingList, {
+ propsData,
+ data,
+ mocks,
+ localVue,
+ slots,
+ })
+ }
+
+ describe('given existing item', () => {
+ beforeEach(() => {
+ wrapper = Wrapper()
+ })
+
+ describe('for each item it', () => {
+ it('displays the item as slot "list-item"', () => {
+ expect(wrapper.find('.list-item').exists()).toBe(true)
+ })
+
+ it('displays the edit button', () => {
+ expect(wrapper.find('.base-button[data-test="edit-button"]').exists()).toBe(true)
+ })
+
+ it('displays the delete button', () => {
+ expect(wrapper.find('.base-button[data-test="delete-button"]').exists()).toBe(true)
+ })
+ })
+
+ describe('editing item', () => {
+ beforeEach(async () => {
+ const editButton = wrapper.find('.base-button[data-test="edit-button"]')
+ editButton.trigger('click')
+ await Vue.nextTick()
+ })
+
+ it('disables adding items while editing', () => {
+ const submitButton = wrapper.find('.base-button[data-test="add-save-button"]')
+ expect(submitButton.text()).not.toContain('settings.social-media.submit')
+ })
+
+ it('allows the user to cancel editing', async () => {
+ expect(wrapper.find('.edit-item').exists()).toBe(true)
+ const cancelButton = wrapper.find('button#cancel')
+ cancelButton.trigger('click')
+ await Vue.nextTick()
+ expect(wrapper.find('.edit-item').exists()).toBe(false)
+ })
+ })
+
+ describe('calls callback functions', () => {
+ it('calls edit', async () => {
+ const editButton = wrapper.find('.base-button[data-test="edit-button"]')
+ editButton.trigger('click')
+ await Vue.nextTick()
+ const expectedItem = expect.objectContaining({ id: 'id', dummy: 'dummy' })
+ expect(propsData.callbacks.edit).toHaveBeenCalledTimes(1)
+ expect(propsData.callbacks.edit).toHaveBeenCalledWith(expect.any(Object), expectedItem)
+ })
+
+ it('calls submit', async () => {
+ form = wrapper.find('form')
+ form.trigger('submit')
+ await Vue.nextTick()
+ form.trigger('submit')
+ await Vue.nextTick()
+ const expectedItem = expect.objectContaining({ id: '' })
+ expect(propsData.callbacks.submit).toHaveBeenCalledTimes(1)
+ expect(propsData.callbacks.submit).toHaveBeenCalledWith(
+ expect.any(Object),
+ true,
+ expectedItem,
+ { dummy: '' },
+ )
+ })
+
+ it('calls delete', async () => {
+ const deleteButton = wrapper.find('.base-button[data-test="delete-button"]')
+ deleteButton.trigger('click')
+ await Vue.nextTick()
+ const expectedItem = expect.objectContaining({ id: 'id', dummy: 'dummy' })
+ expect(propsData.callbacks.delete).toHaveBeenCalledTimes(1)
+ expect(propsData.callbacks.delete).toHaveBeenCalledWith(expect.any(Object), expectedItem)
+ })
+ })
+ })
+ })
+})
diff --git a/webapp/components/_new/features/MySomethingList/MySomethingList.vue b/webapp/components/_new/features/MySomethingList/MySomethingList.vue
new file mode 100644
index 000000000..fbfcca932
--- /dev/null
+++ b/webapp/components/_new/features/MySomethingList/MySomethingList.vue
@@ -0,0 +1,185 @@
+
+
+
+
+
+ {{
+ isCreation
+ ? $t('settings.social-media.addNewTitle')
+ : $t('settings.social-media.editTitle', { name: editingItem[namePropertyKey] })
+ }}
+
+
+
+
+
+
+
+
+
+
+
+
+ |
+
+
+
+
+
+
+
+
+
+
+
+ {{ isEditing ? $t('actions.save') : $t('settings.social-media.submit') }}
+
+
+ {{ $t('actions.cancel') }}
+
+
+
+
+
+
+
+
+
diff --git a/webapp/components/_new/features/SocialMedia/SocialMediaListItem.spec.js b/webapp/components/_new/features/SocialMedia/SocialMediaListItem.spec.js
new file mode 100644
index 000000000..c7359d873
--- /dev/null
+++ b/webapp/components/_new/features/SocialMedia/SocialMediaListItem.spec.js
@@ -0,0 +1,36 @@
+import { shallowMount } from '@vue/test-utils'
+import SocialMediaListItem from './SocialMediaListItem.vue'
+
+describe('SocialMediaListItem.vue', () => {
+ let wrapper
+ let propsData
+ const socialMediaUrl = 'https://freeradical.zone/@mattwr18'
+ const faviconUrl = 'https://freeradical.zone/favicon.ico'
+
+ beforeEach(() => {
+ propsData = {}
+ })
+
+ describe('shallowMount', () => {
+ const Wrapper = () => {
+ return shallowMount(SocialMediaListItem, { propsData })
+ }
+
+ describe('given existing social media links', () => {
+ beforeEach(() => {
+ propsData = { item: { id: 's1', url: socialMediaUrl, favicon: faviconUrl } }
+ wrapper = Wrapper()
+ })
+
+ describe('for each link item it', () => {
+ it('displays the favicon', () => {
+ expect(wrapper.find(`img[src="${faviconUrl}"]`).exists()).toBe(true)
+ })
+
+ it('displays the url', () => {
+ expect(wrapper.find(`a[href="${socialMediaUrl}"]`).exists()).toBe(true)
+ })
+ })
+ })
+ })
+})
diff --git a/webapp/components/_new/features/SocialMedia/SocialMediaListItem.vue b/webapp/components/_new/features/SocialMedia/SocialMediaListItem.vue
new file mode 100644
index 000000000..75dea7ba8
--- /dev/null
+++ b/webapp/components/_new/features/SocialMedia/SocialMediaListItem.vue
@@ -0,0 +1,18 @@
+
+
+
+ {{ item.url }}
+
+
+
+
diff --git a/webapp/locales/de.json b/webapp/locales/de.json
index 9816e167a..a98f0a320 100644
--- a/webapp/locales/de.json
+++ b/webapp/locales/de.json
@@ -773,6 +773,8 @@
"name": "Sicherheit"
},
"social-media": {
+ "addNewTitle": "Neuen Link hinzufügen",
+ "editTitle": "Link \"{name}\" ändern",
"name": "Soziale Netzwerke",
"placeholder": "Deine Webadresse des Sozialen Netzwerkes",
"requireUnique": "Dieser Link existiert bereits",
diff --git a/webapp/locales/en.json b/webapp/locales/en.json
index 11b920056..f6606b933 100644
--- a/webapp/locales/en.json
+++ b/webapp/locales/en.json
@@ -773,6 +773,8 @@
"name": "Security"
},
"social-media": {
+ "addNewTitle": "Add new link",
+ "editTitle": "Edit link \"{name}\"",
"name": "Social media",
"placeholder": "Your social media url",
"requireUnique": "You added this url already",
diff --git a/webapp/pages/settings/my-social-media.spec.js b/webapp/pages/settings/my-social-media.spec.js
index 1aadbb750..7136e1e7c 100644
--- a/webapp/pages/settings/my-social-media.spec.js
+++ b/webapp/pages/settings/my-social-media.spec.js
@@ -33,7 +33,7 @@ describe('my-social-media.vue', () => {
})
describe('mount', () => {
- let form, input, submitButton
+ let form, input
const Wrapper = () => {
const store = new Vuex.Store({
getters,
@@ -42,11 +42,12 @@ describe('my-social-media.vue', () => {
}
describe('adding social media link', () => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = Wrapper()
form = wrapper.find('form')
- input = wrapper.find('input#addSocialMedia')
- submitButton = wrapper.find('button')
+ form.trigger('submit')
+ await Vue.nextTick()
+ input = wrapper.find('input#editSocialMedia')
})
it('requires the link to be a valid url', async () => {
@@ -79,7 +80,6 @@ describe('my-social-media.vue', () => {
const expected = expect.objectContaining({
variables: { url: newSocialMediaUrl },
})
-
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
})
@@ -88,10 +88,10 @@ describe('my-social-media.vue', () => {
expect(mocks.$toast.success).toHaveBeenCalledTimes(1)
})
- it('clears the form', async () => {
+ it('switches back to list', async () => {
await flushPromises()
- expect(input.value).toBe(undefined)
- expect(submitButton.vm.$attrs.disabled).toBe(true)
+ const submitButton = wrapper.find('.base-button[data-test="add-save-button"]')
+ expect(submitButton.text()).not.toContain('settings.social-media.submit')
})
})
})
@@ -100,10 +100,9 @@ describe('my-social-media.vue', () => {
beforeEach(() => {
getters = {
'auth/user': () => ({
- socialMedia: [{ id: 's1', url: socialMediaUrl }],
+ socialMedia: [{ id: 's1', url: socialMediaUrl, favicon: faviconUrl }],
}),
}
-
wrapper = Wrapper()
form = wrapper.find('form')
})
@@ -116,18 +115,12 @@ describe('my-social-media.vue', () => {
it('displays the url', () => {
expect(wrapper.find(`a[href="${socialMediaUrl}"]`).exists()).toBe(true)
})
-
- it('displays the edit button', () => {
- expect(wrapper.find('.base-button[data-test="edit-button"]').exists()).toBe(true)
- })
-
- it('displays the delete button', () => {
- expect(wrapper.find('.base-button[data-test="delete-button"]').exists()).toBe(true)
- })
})
it('does not accept a duplicate url', async () => {
- wrapper.find('input#addSocialMedia').setValue(socialMediaUrl)
+ form.trigger('submit')
+ await Vue.nextTick()
+ wrapper.find('input#editSocialMedia').setValue(socialMediaUrl)
form.trigger('submit')
await Vue.nextTick()
expect(mocks.$apollo.mutate).not.toHaveBeenCalled()
@@ -141,12 +134,6 @@ describe('my-social-media.vue', () => {
input = wrapper.find('input#editSocialMedia')
})
- it('disables adding new links while editing', () => {
- const addInput = wrapper.find('input#addSocialMedia')
-
- expect(addInput.exists()).toBe(false)
- })
-
it('sends the new url to the backend', async () => {
const expected = expect.objectContaining({
variables: { id: 's1', url: newSocialMediaUrl },
@@ -156,13 +143,6 @@ describe('my-social-media.vue', () => {
await Vue.nextTick()
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
})
-
- 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', () => {
@@ -176,7 +156,6 @@ describe('my-social-media.vue', () => {
const expected = expect.objectContaining({
variables: { id: 's1' },
})
-
expect(mocks.$apollo.mutate).toHaveBeenCalledTimes(1)
expect(mocks.$apollo.mutate).toHaveBeenCalledWith(expected)
})
diff --git a/webapp/pages/settings/my-social-media.vue b/webapp/pages/settings/my-social-media.vue
index 5753fc405..a985371d6 100644
--- a/webapp/pages/settings/my-social-media.vue
+++ b/webapp/pages/settings/my-social-media.vue
@@ -1,97 +1,73 @@
-
-
- {{ $t('settings.social-media.name') }}
-
-
-
-
-
-
-
-
- {{ link.url }}
-
- |
-
-
-
-
-
-
-
-
+
+ {{ $t('settings.social-media.name') }}
+
+
+
+
+
-
-
- {{ editingLink.id ? $t('actions.save') : $t('settings.social-media.submit') }}
-
-
- {{ $t('actions.cancel') }}
-
-
-
-
-
+
+
+
-
-