diff --git a/.drone.star b/.drone.star index 5dedfc6b1a1..fada65f5ef5 100644 --- a/.drone.star +++ b/.drone.star @@ -216,21 +216,6 @@ config = { "screenShots": True, "retry": False, }, - "webUINotification": { - "type": NOTIFICATIONS, - "suites": { - "oC10Notification": [ - "webUINotifications", - "webUISharingNotifications", - "webUISharingNotificationsToRoot", - ], - }, - "extraEnvironment": { - "EXPECTED_FAILURES_FILE": "%s/tests/acceptance/expected-failures-with-oc10-server-oauth2-login.md" % dir["web"], - }, - "screenShots": True, - "notificationsAppNeeded": True, - }, "webUIFederation": { "type": FEDERATED, "suites": { @@ -245,22 +230,6 @@ config = { "federatedServerNeeded": True, "federatedServerVersion": OC10_VERSION, }, - "webUI-XGA-Notifications": { - "type": NOTIFICATIONS, - "suites": { - "oC10XGAPortraitNotifications": [ - "webUINotifications", - "webUISharingNotifications", - "webUISharingNotificationsToRoot", - ], - }, - "extraEnvironment": { - "EXPECTED_FAILURES_FILE": "%s/tests/acceptance/expected-failures-XGA-with-oc10-server-oauth2-login.md" % dir["web"], - "SCREEN_RESOLUTION": "768x1024", - }, - "notificationsAppNeeded": True, - "filterTags": "@smokeTest and not @skipOnXGAPortraitResolution and not @skip and not @skipOnOC10 and not @notToImplementOnOC10", - }, "webUI-XGA": { "type": FULL, "suites": { @@ -337,22 +306,6 @@ config = { }, "filterTags": "@smokeTest and not @skipOnXGAPortraitResolution and not @skip and not @skipOnOC10 and not @notToImplementOnOC10", }, - "webUI-Notifications-iPhone": { - "type": NOTIFICATIONS, - "suites": { - "oC10iPhoneNotifications": [ - "webUINotifications", - "webUISharingNotifications", - "webUISharingNotificationsToRoot", - ], - }, - "extraEnvironment": { - "EXPECTED_FAILURES_FILE": "%s/tests/acceptance/expected-failures-Iphone-oc10-server-oauth2-login.md" % dir["web"], - "SCREEN_RESOLUTION": "375x812", - }, - "notificationsAppNeeded": True, - "filterTags": "@smokeTest and not @skipOnIphoneResolution and not @skip and not @skipOnOC10 and not @notToImplementOnOC10", - }, "webUI-iPhone": { "type": FULL, "suites": { @@ -436,7 +389,6 @@ config = { ], "suites": { "oCISBasic": [ - "webUINotifications", "webUIPrivateLinks", "webUIPreview", "webUIAccount", @@ -446,7 +398,6 @@ config = { "oCISSharingBasic": [ "webUISharingAcceptShares", "webUIRestrictSharing", - "webUISharingNotifications", ], "webUIFavorites": "oCISFavorites", "oCISFiles1": [ @@ -537,25 +488,6 @@ config = { "filterTags": "not @skip and not @skipOnOCIS and not @notToImplementOnOCIS", "screenShots": True, }, - "webUI-notifications-oc10-integration": { - "type": NOTIFICATIONS, - "suites": { - "oC10IntegrationNotifications": [ - "webUINotifications", - "webUISharingNotifications", - "webUISharingNotificationsToRoot", - ], - }, - "extraEnvironment": { - "WEB_UI_CONFIG": "%s" % dir["oc10IntegrationAppOauthConfig"], - "SERVER_HOST": "http://owncloud/index.php/apps/web/index.html", - "EXPECTED_FAILURES_FILE": "%s/tests/acceptance/expected-failures-with-oc10-server-oauth2-login-and-web-integration-app.md" % dir["web"], - }, - "filterTags": "not @skip and not @skipOnOC10 and not @notToImplementOnOC10 and not @openIdLogin and @smokeTest", - "oc10IntegrationAppIncluded": True, - "notificationsAppNeeded": True, - "screenShots": True, - }, "webUI-oc10-integration": { "type": FULL, "suites": { @@ -663,15 +595,6 @@ rootSharingTestSuites = [ "webUISharingPermissionToRoot", ] -notificationsTestSuites = [ - "webUINotifications", - "webUISharingNotifications", -] - -notificationsRootTestSuites = [ - "webUISharingNotificationsToRoot", -] - basicTestSuites = [ "webUIAccount", "webUICreateFilesFolders", @@ -776,15 +699,11 @@ def checkTestSuites(): expected += basicTestSuites if ("runningOnOCIS" not in test or test["runningOnOCIS"] != True): expected += rootSharingTestSuites - elif (test["type"] == NOTIFICATIONS): - expected += notificationsTestSuites - if ("runningOnOCIS" not in test or test["runningOnOCIS"] != True): - expected += notificationsRootTestSuites elif (test["type"] == FEDERATED): expected += federatedTestSuites + federatedRootTestSuites if ("runningOnOCIS" in test and test["runningOnOCIS"] == True): - expected += notificationsTestSuites + ocisSpecificTestSuites + expected += ocisSpecificTestSuites if (sorted(suites) != sorted(expected)): print("Error: Suites dont match " + testGroupName) diff --git a/changelog/unreleased/enhancement-notifications-ocis b/changelog/unreleased/enhancement-notifications-ocis new file mode 100644 index 00000000000..38c466f36d0 --- /dev/null +++ b/changelog/unreleased/enhancement-notifications-ocis @@ -0,0 +1,7 @@ +Enhancement: Make notifications work with oCIS + +Notifications now work when running oCIS as backend. + +https://github.com/owncloud/web/pull/8518 +https://github.com/owncloud/web/issues/8519 +https://github.com/owncloud/web/issues/8520 diff --git a/packages/web-app-files/src/views/shares/SharedWithMe.vue b/packages/web-app-files/src/views/shares/SharedWithMe.vue index 364984d9a5a..698f5d881bb 100644 --- a/packages/web-app-files/src/views/shares/SharedWithMe.vue +++ b/packages/web-app-files/src/views/shares/SharedWithMe.vue @@ -228,7 +228,11 @@ export default defineComponent({ async created() { await this.loadResourcesTask.perform() - this.scrollToResourceFromRoute(this.acceptedItems) + this.scrollToResourceFromRoute([ + ...this.acceptedItems, + ...this.pendingItems, + ...this.declinedItems + ]) } }) diff --git a/packages/web-runtime/src/App.vue b/packages/web-runtime/src/App.vue index 03bc15b531e..51295953aca 100644 --- a/packages/web-runtime/src/App.vue +++ b/packages/web-runtime/src/App.vue @@ -42,7 +42,7 @@ diff --git a/packages/web-runtime/src/components/Topbar/TopBar.vue b/packages/web-runtime/src/components/Topbar/TopBar.vue index 750667994b8..09988514ef5 100644 --- a/packages/web-runtime/src/components/Topbar/TopBar.vue +++ b/packages/web-runtime/src/components/Topbar/TopBar.vue @@ -53,11 +53,6 @@ export default { type: Array, required: false, default: () => [] - }, - activeNotifications: { - type: [Array, Boolean], - required: false, - default: () => [] } }, setup() { diff --git a/packages/web-runtime/src/helpers/notifications.ts b/packages/web-runtime/src/helpers/notifications.ts new file mode 100644 index 00000000000..580b5869de8 --- /dev/null +++ b/packages/web-runtime/src/helpers/notifications.ts @@ -0,0 +1,25 @@ +import { RouteLocationNamedRaw } from 'vue-router' + +export interface NotificationAction { + label: string + link: string + type: string + primary: boolean +} + +export interface Notification { + notification_id: string + app: string + user: string + datetime: string + subject: string + message?: string + messageRich?: string + messageRichParameters?: any + object_type?: string + object_id?: string + link?: string + actions?: NotificationAction[] + computedMessage?: string + computedLink?: RouteLocationNamedRaw +} diff --git a/packages/web-runtime/src/layouts/Application.vue b/packages/web-runtime/src/layouts/Application.vue index 5a8a80989f9..91305eb10b2 100644 --- a/packages/web-runtime/src/layouts/Application.vue +++ b/packages/web-runtime/src/layouts/Application.vue @@ -4,7 +4,7 @@

- +
@@ -98,7 +98,6 @@ export default defineComponent({ ...mapGetters([ 'apps', 'activeMessages', - 'activeNotifications', 'capabilities', 'configuration', 'getExtensionsWithNavItems', diff --git a/packages/web-runtime/src/store/app.ts b/packages/web-runtime/src/store/app.ts index d7d4568940b..de507e4434f 100644 --- a/packages/web-runtime/src/store/app.ts +++ b/packages/web-runtime/src/store/app.ts @@ -1,10 +1,5 @@ const state = { messages: [], - notifications: { - loading: true, - failed: false, - data: [] - }, quickActions: {} } @@ -14,50 +9,6 @@ const actions = { }, deleteMessage(context, mId) { context.commit('REMOVE_MESSAGE', mId) - }, - fetchNotifications(context, client) { - context.commit('LOADING_NOTIFICATIONS', true) - - return client.requests - .ocs({ - service: 'apps/notifications', - action: 'api/v1/notifications' - }) - .then((response) => { - if (response.headers.get('Content-Length') === '0') { - return - } - response.json().then((json) => { - if (response.ok) { - context.commit('UPDATE_NOTIFICATIONS', json.ocs.data) - } else { - context.commit('ERROR_NOTIFICATIONS', json.ocs.meta.message) - } - context.commit('LOADING_NOTIFICATIONS', false) - }) - }) - .catch((error) => { - context.commit('ERROR_NOTIFICATIONS', error) - context.commit('LOADING_NOTIFICATIONS', false) - }) - }, - deleteNotification(context, { client, notification }) { - client.requests - .ocs({ - service: 'apps/notifications', - action: 'api/v1/notifications/' + notification, - method: 'DELETE' - }) - .then((response) => { - if (response.ok) { - context.commit('DELETE_NOTIFICATION', notification) - } else { - context.commit('ERROR_NOTIFICATIONS', response.ocs.meta.status) - } - }) - .catch((error) => { - context.commit('ERROR_NOTIFICATIONS', error) - }) } } @@ -73,22 +24,6 @@ const mutations = { REMOVE_MESSAGE(state, item) { state.messages.splice(state.messages.indexOf(item), 1) }, - LOADING_NOTIFICATIONS(state, loading) { - state.notifications.loading = loading - }, - ERROR_NOTIFICATIONS(state, failed) { - state.notifications.failed = failed - }, - UPDATE_NOTIFICATIONS(state, notifications) { - state.notifications.data = notifications - }, - DELETE_NOTIFICATION(state, notification) { - const data = state.notifications.data.filter((n) => { - return n.notification_id !== notification - }) - state.notifications.data = data - }, - ADD_QUICK_ACTIONS(state, quickActions) { state.quickActions = Object.assign(state.quickActions, quickActions) } @@ -97,11 +32,6 @@ const mutations = { const getters = { activeMessages: (state) => { return state.messages - }, - activeNotifications: (state) => { - return state.notifications.data.length && !state.notifications.failed - ? state.notifications.data - : false } } diff --git a/packages/web-runtime/tests/unit/components/Topbar/Notification.spec.ts b/packages/web-runtime/tests/unit/components/Topbar/Notification.spec.ts deleted file mode 100644 index f46d48d70f3..00000000000 --- a/packages/web-runtime/tests/unit/components/Topbar/Notification.spec.ts +++ /dev/null @@ -1,212 +0,0 @@ -import Notifications from 'web-runtime/src/components/Topbar/Notifications.vue' -import { mockDeep } from 'jest-mock-extended' -import { OwnCloudSdk } from 'web-client/src/types' -import { - createStore, - defaultComponentMocks, - defaultPlugins, - mount, - shallowMount, - defaultStoreMockOptions -} from 'web-test-helpers' - -const testData = { - selectors: { - notificationBell: '#oc-notification-bell', - ocIconStub: 'oc-icon-stub', - actionButton: '.oc-ml-s', - resolveNotificationButton: '#resolve-notification-button', - link: '.oc-width-1-1 > p > a', - subject: 'h4', - message: '.oc-text-small' - }, - notifications: { - emptyActions: [ - { - notification_id: 1, - subject: 'Test', - message: 'This is a test message', - actions: [] - } - ], - get singleAction() { - return [ - { - ...this.emptyActions[0], - actions: [ - { - label: 'Test Action', - link: 'http://some.link' - } - ] - } - ] - }, - twoActiveNotifications: [ - { - subject: 'First Notification', - message: 'This is first test message', - actions: [] - }, - { - subject: 'Second Notification', - message: 'This is second test message', - actions: [] - } - ], - linkActions: [ - { - link: 'http://test.link', - actions: [] - } - ] - } -} - -describe('Notification component', () => { - const { selectors } = testData - - describe('when active notification contains a message', () => { - it('displays the notification message', () => { - const { wrapper } = getWrapper({ - mountType: shallowMount, - activeNotifications: testData.notifications.emptyActions - }) - const messageElement = wrapper.find(selectors.message) - - expect(messageElement.exists()).toBeTruthy() - expect(messageElement.text()).toBe('This is a test message') - }) - - it('displays the notification subject', () => { - const { wrapper } = getWrapper({ - mountType: shallowMount, - activeNotifications: testData.notifications.emptyActions - }) - const subjectElement = wrapper.find(selectors.subject) - - expect(subjectElement.exists()).toBeTruthy() - expect(subjectElement.text()).toBe('Test') - }) - }) - - describe('active notifications actions', () => { - describe('when active notification action is empty', () => { - const client = mockDeep({}) - const { wrapper } = getWrapper({ - activeNotifications: testData.notifications.emptyActions, - mocks: { $client: client } - }) - - it('does not display the action button', () => { - expect(wrapper.find(selectors.actionButton).exists()).toBeFalsy() - }) - - it('displays the resolve notification button', () => { - expect(wrapper.find(selectors.resolveNotificationButton).exists()).toBeTruthy() - }) - - it('dispatches deleteNotification when resolve notification is clicked', () => { - const notificationSpy = jest.spyOn(wrapper.vm, 'deleteNotification') - client.requests.ocs.mockImplementation(() => Promise.resolve(new Response())) - - const resolveNotificationButton = wrapper.find(selectors.resolveNotificationButton) - - expect(resolveNotificationButton.exists()).toBeTruthy() - resolveNotificationButton.trigger('click') - expect(notificationSpy).toHaveBeenCalledTimes(1) - expect(notificationSpy).toHaveBeenCalledWith({ client, notification: 1 }) - }) - }) - - describe('when active notification action has an action', () => { - const { wrapper, mocks } = getWrapper({ - activeNotifications: testData.notifications.singleAction - }) - - it('displays the action button with action label', () => { - const actionButton = wrapper.find(selectors.actionButton) - - expect(actionButton.exists()).toBeTruthy() - expect(actionButton.text()).toBe('Test Action') - }) - - it("doesn't display the resolve notification button", () => { - expect(wrapper.find(selectors.resolveNotificationButton).exists()).toBeFalsy() - }) - - it('calls executeRequest when action button is clicked', async () => { - const actionButton = wrapper.find(selectors.actionButton) - - await actionButton.trigger('click') - expect(mocks.$client.requests.ocs).toHaveBeenCalledTimes(1) - }) - }) - }) - - describe('active notifications links', () => { - it('does not display link if no link is given', () => { - const { wrapper } = getWrapper({ - mountType: shallowMount, - activeNotifications: testData.notifications.emptyActions - }) - const linkButton = wrapper.find(selectors.link) - - expect(linkButton.exists()).toBeFalsy() - }) - - it('displays link if a link is given', () => { - const { wrapper } = getWrapper({ - mountType: shallowMount, - activeNotifications: testData.notifications.linkActions - }) - const linkButton = wrapper.find(selectors.link) - - expect(linkButton.exists()).toBeTruthy() - expect(linkButton.text()).toBe('http://test.link') - }) - }) - - describe('when active notification has multiple notifications', () => { - it('displays all notifications from active notifications', () => { - const { wrapper } = getWrapper({ - mountType: shallowMount, - activeNotifications: testData.notifications.twoActiveNotifications - }) - const subject = wrapper.findAll(selectors.subject) - const message = wrapper.findAll(selectors.message) - - expect(subject).toHaveLength(2) - expect(message).toHaveLength(2) - expect(subject.at(0).text()).toBe('First Notification') - expect(subject.at(1).text()).toBe('Second Notification') - expect(message.at(0).text()).toBe('This is first test message') - expect(message.at(1).text()).toBe('This is second test message') - }) - }) -}) - -function getWrapper({ mountType = mount, mocks = {}, activeNotifications = [] } = {}) { - const localMocks = { ...defaultComponentMocks(), ...mocks } - const jsonResponse = { - json: jest.fn().mockImplementation(() => Promise.resolve({ ocs: { data: [] } })) - } - localMocks.$client.requests.ocs.mockImplementation(() => - Promise.resolve(mockDeep(jsonResponse)) - ) - const storeOptions = { ...defaultStoreMockOptions } - storeOptions.getters.activeNotifications.mockImplementation(() => activeNotifications) - const store = createStore(storeOptions) - return { - mocks: localMocks, - storeOptions, - wrapper: mountType(Notifications, { - global: { - renderStubDefaultSlot: true, - plugins: [...defaultPlugins(), store], - mocks: localMocks, - stubs: { 'oc-icon': true } - } - }) - } -} diff --git a/packages/web-runtime/tests/unit/components/Topbar/NotificationBell.spec.ts b/packages/web-runtime/tests/unit/components/Topbar/NotificationBell.spec.ts index 0953e9eb2f2..f545e3d9e28 100644 --- a/packages/web-runtime/tests/unit/components/Topbar/NotificationBell.spec.ts +++ b/packages/web-runtime/tests/unit/components/Topbar/NotificationBell.spec.ts @@ -34,7 +34,7 @@ describe('NotificationBell', () => { notificationCount: 0 } }) - expect(wrapper.find('#oc-notification-bell').attributes('aria-label')).toEqual('Notifications') + expect(wrapper.find('#oc-notifications-bell').attributes('aria-label')).toEqual('Notifications') }) it('animates when notification count changes', async () => { const { wrapper } = getWrapper({ diff --git a/packages/web-runtime/tests/unit/components/Topbar/Notifications.spec.ts b/packages/web-runtime/tests/unit/components/Topbar/Notifications.spec.ts new file mode 100644 index 00000000000..90d37a7d4ca --- /dev/null +++ b/packages/web-runtime/tests/unit/components/Topbar/Notifications.spec.ts @@ -0,0 +1,240 @@ +import Notifications from 'web-runtime/src/components/Topbar/Notifications.vue' +import { Notification, NotificationAction } from 'web-runtime/src/helpers/notifications' +import { mock, mockDeep } from 'jest-mock-extended' +import { + createStore, + defaultComponentMocks, + defaultPlugins, + shallowMount, + defaultStoreMockOptions +} from 'web-test-helpers' +import { OwnCloudSdk } from 'web-client/src/types' +import { SpaceResource } from 'web-client' + +const selectors = { + notificationBellStub: 'notification-bell-stub', + avatarImageStub: 'avatar-image-stub', + noNewNotifications: '.oc-notifications-no-new', + markAll: '.oc-notifications-mark-all', + notificationsLoading: '.oc-notifications-loading', + notificationItem: '.oc-notifications-item', + notificationSubject: '.oc-notifications-subject', + notificationMessage: '.oc-notifications-message', + notificationLink: '.oc-notifications-link', + notificationActions: '.oc-notifications-actions' +} + +describe('Notification component', () => { + it('renders the notification bell and no notifications if there are none', () => { + const { wrapper } = getWrapper() + expect(wrapper.find(selectors.notificationBellStub).exists()).toBeTruthy() + expect(wrapper.find(selectors.noNewNotifications).exists()).toBeTruthy() + expect(wrapper.find(selectors.markAll).exists()).toBeFalsy() + }) + it('renders a set of notifications', async () => { + const notifications = [mock({ messageRich: undefined })] + const { wrapper } = getWrapper({ notifications }) + await wrapper.vm.fetchNotificationsTask.last + expect(wrapper.find(selectors.noNewNotifications).exists()).toBeFalsy() + expect(wrapper.findAll(selectors.notificationItem).length).toBe(notifications.length) + }) + it('renders the loading state', async () => { + const notifications = [mock({ messageRich: undefined })] + const { wrapper } = getWrapper({ notifications }) + await wrapper.vm.fetchNotificationsTask.last + wrapper.vm.loading = true + await wrapper.vm.$nextTick() + expect(wrapper.find(selectors.notificationsLoading).exists()).toBeTruthy() + }) + it('marks all notifications as read', async () => { + const notifications = [mock({ messageRich: undefined })] + const { wrapper, mocks } = getWrapper({ notifications }) + await wrapper.vm.fetchNotificationsTask.last + await wrapper.find(selectors.markAll).trigger('click') + expect(wrapper.find(selectors.notificationItem).exists()).toBeFalsy() + expect(mocks.$clientService.owncloudSdk.requests.ocs).toHaveBeenCalledTimes(2) + }) + describe('avatar', () => { + it('loads based on the username', async () => { + const notification = mock({ + messageRich: undefined, + user: 'einstein' + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + const avatarImageStub = wrapper.findComponent(selectors.avatarImageStub) + expect(avatarImageStub.attributes('userid')).toEqual(notification.user) + expect(avatarImageStub.attributes('user-name')).toEqual(notification.user) + }) + it('loads based on the rich parameters', async () => { + const displayname = 'Albert Einstein' + const name = 'einstein' + const notification = mock({ + messageRich: undefined, + messageRichParameters: { user: { displayname, name } } + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + const avatarImageStub = wrapper.findComponent(selectors.avatarImageStub) + expect(avatarImageStub.attributes('userid')).toEqual(name) + expect(avatarImageStub.attributes('user-name')).toEqual(displayname) + }) + }) + describe('subject', () => { + it('displays if no message given', async () => { + const notification = mock({ + messageRich: undefined, + message: undefined + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + expect(wrapper.find(selectors.notificationSubject).exists()).toBeTruthy() + }) + }) + describe('message', () => { + it('displays simple message if messageRich not given', async () => { + const notification = mock({ + messageRich: undefined, + message: 'some message' + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + wrapper.vm.showDrop() + await wrapper.vm.$nextTick() + expect(wrapper.find(selectors.notificationMessage).text()).toEqual(notification.message) + }) + it('displays rich message and interpolates the text', async () => { + const notification = mock({ + messageRich: '{user} shared {resource} with you', + messageRichParameters: { + user: { displayname: 'Albert Einstein' }, + resource: { name: 'someFile.txt' } + } + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + wrapper.vm.showDrop() + await wrapper.vm.$nextTick() + expect(wrapper.find(selectors.notificationMessage).text()).toEqual( + 'Albert Einstein shared someFile.txt with you' + ) + }) + }) + describe('link', () => { + it('displays if given directly', async () => { + const notification = mock({ + messageRich: undefined, + link: 'http://some-link.com' + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + expect(wrapper.find(selectors.notificationLink).exists()).toBeTruthy() + }) + describe('if given via messageRichParameters', () => { + it('renders notification as link for shares', async () => { + const notification = mock({ + messageRich: '{user} shared {resource} with you', + object_type: 'share', + messageRichParameters: { + user: { displayname: 'Albert Einstein' }, + resource: { name: 'someFile.txt' }, + share: { id: '1' } + } + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + wrapper.vm.showDrop() + await wrapper.vm.$nextTick() + const routerLink = wrapper.findComponent( + `${selectors.notificationItem} router-link-stub` + ) + expect(routerLink.props('to').name).toEqual('files-shares-with-me') + expect(routerLink.props('to').query).toEqual({ + scrollTo: notification.messageRichParameters.share.id + }) + }) + it('renders notification as link for spaces', async () => { + const spaceMock = mock({ + fileId: '1', + getDriveAliasAndItem: () => 'driveAlias', + disabled: false + }) + const notification = mock({ + messageRich: '{user} added you to space {space}', + object_type: 'storagespace', + messageRichParameters: { + user: { displayname: 'Albert Einstein' }, + space: { name: 'someFile.txt', id: `${spaceMock.fileId}!2` } + } + }) + const { wrapper } = getWrapper({ notifications: [notification], spaces: [spaceMock] }) + await wrapper.vm.fetchNotificationsTask.last + wrapper.vm.showDrop() + await wrapper.vm.$nextTick() + const routerLink = wrapper.findComponent( + `${selectors.notificationItem} router-link-stub` + ) + expect(routerLink.props('to').params).toEqual({ + driveAliasAndItem: 'driveAlias' + }) + }) + }) + }) + describe('actions', () => { + it('display if given', async () => { + const notification = mock({ + messageRich: undefined, + actions: [mock()] + }) + const { wrapper } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + expect(wrapper.find(selectors.notificationActions).exists()).toBeTruthy() + }) + it('remove the notification when triggered', async () => { + const notification = mock({ + notification_id: '1', + messageRich: undefined, + actions: [mock({ link: 'http://some-link.com' })] + }) + const { wrapper, mocks } = getWrapper({ notifications: [notification] }) + await wrapper.vm.fetchNotificationsTask.last + expect(wrapper.find(selectors.notificationItem).exists()).toBeTruthy() + const jsonResponse = { + json: jest.fn().mockResolvedValue({ ocs: { data: {} } }) + } + mocks.$clientService.owncloudSdk.requests.ocs.mockResolvedValue( + mockDeep(jsonResponse) + ) + await wrapper.find(`${selectors.notificationActions} button`).trigger('click') + await wrapper.vm.$nextTick() + expect(wrapper.find(selectors.notificationItem).exists()).toBeFalsy() + }) + }) +}) + +function getWrapper({ mocks = {}, notifications = [], spaces = [] } = {}) { + const localMocks = { ...defaultComponentMocks(), ...mocks } + const clientMock = mockDeep() + const jsonResponse = { + json: jest.fn().mockResolvedValue({ ocs: { data: notifications } }), + headers: {} + } + clientMock.requests.ocs.mockResolvedValue(mockDeep(jsonResponse)) + localMocks.$clientService.owncloudSdk = clientMock + + const storeOptions = { ...defaultStoreMockOptions } + storeOptions.modules.runtime.modules.spaces.getters.spaces.mockReturnValue(spaces) + const store = createStore(storeOptions) + return { + mocks: localMocks, + storeOptions, + wrapper: shallowMount(Notifications, { + global: { + renderStubDefaultSlot: true, + plugins: [...defaultPlugins(), store], + mocks: localMocks, + stubs: { 'avatar-image': true, OcButton: false } + } + }) + } +} diff --git a/packages/web-runtime/tests/unit/components/Topbar/TopBar.spec.ts b/packages/web-runtime/tests/unit/components/Topbar/TopBar.spec.ts index af1e63423db..bfb0dd0093b 100644 --- a/packages/web-runtime/tests/unit/components/Topbar/TopBar.spec.ts +++ b/packages/web-runtime/tests/unit/components/Topbar/TopBar.spec.ts @@ -33,7 +33,6 @@ describe('Top Bar component', () => { it('Displays applications menu', () => { const { wrapper } = getWrapper() expect(wrapper.find('applications-menu-stub').exists()).toBeTruthy() - expect(wrapper.html()).toMatchSnapshot() }) it('should display notifications bell', () => { const { wrapper } = getWrapper({ diff --git a/packages/web-runtime/tests/unit/components/Topbar/__snapshots__/NotificationBell.spec.ts.snap b/packages/web-runtime/tests/unit/components/Topbar/__snapshots__/NotificationBell.spec.ts.snap index 96eb92024b1..22f03052fdc 100644 --- a/packages/web-runtime/tests/unit/components/Topbar/__snapshots__/NotificationBell.spec.ts.snap +++ b/packages/web-runtime/tests/unit/components/Topbar/__snapshots__/NotificationBell.spec.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`NotificationBell should match snapshot 1`] = ` -