From d56c81dc3d7f402513156cd18d1aeb62c5f0ed31 Mon Sep 17 00:00:00 2001 From: mattwr18 Date: Sat, 2 Nov 2019 16:45:57 +0100 Subject: [PATCH] Add test for NotificationsTable and refactor --- .../NotificationList/NotificationList.spec.js | 45 +---- .../NotificationList/NotificationList.vue | 2 +- .../NotificationsTable.spec.js | 174 ++++++++++++++++++ .../NotificationsTable.story.js | 2 +- .../NotificationsTable/NotificationsTable.vue | 4 +- webapp/components/utils/Notifications.js | 43 +++++ 6 files changed, 225 insertions(+), 45 deletions(-) create mode 100644 webapp/components/NotificationsTable/NotificationsTable.spec.js create mode 100644 webapp/components/utils/Notifications.js diff --git a/webapp/components/NotificationList/NotificationList.spec.js b/webapp/components/NotificationList/NotificationList.spec.js index c8e95e067..c48daefe6 100644 --- a/webapp/components/NotificationList/NotificationList.spec.js +++ b/webapp/components/NotificationList/NotificationList.spec.js @@ -3,8 +3,8 @@ import NotificationList from './NotificationList' import Notification from '../Notification/Notification' import Vuex from 'vuex' import Filters from '~/plugins/vue-filters' - import Styleguide from '@human-connection/styleguide' +import { notifications } from '~/components/utils/Notifications' const localVue = createLocalVue() @@ -38,40 +38,7 @@ describe('NotificationList.vue', () => { stubs = { NuxtLink: RouterLinkStub, } - propsData = { - notifications: [ - { - read: false, - from: { - __typename: 'Post', - id: 'post-1', - title: 'some post title', - slug: 'some-post-title', - contentExcerpt: 'this is a post content', - author: { - id: 'john-1', - slug: 'john-doe', - name: 'John Doe', - }, - }, - }, - { - read: false, - from: { - __typename: 'Post', - id: 'post-2', - title: 'another post title', - slug: 'another-post-title', - contentExcerpt: 'this is yet another post content', - author: { - id: 'john-1', - slug: 'john-doe', - name: 'John Doe', - }, - }, - }, - ], - } + propsData = { notifications } }) describe('shallowMount', () => { @@ -110,15 +77,11 @@ describe('NotificationList.vue', () => { describe('click on a notification', () => { beforeEach(() => { - wrapper - .findAll('.notification-mention-post') - .at(1) - .trigger('click') + wrapper.find('.notification-mention-post').trigger('click') }) it("emits 'markAsRead' with the id of the notification source", () => { - expect(wrapper.emitted('markAsRead')).toBeTruthy() - expect(wrapper.emitted('markAsRead')[0]).toEqual(['post-2']) + expect(wrapper.emitted('markAsRead')[0]).toEqual(['post-1']) }) }) }) diff --git a/webapp/components/NotificationList/NotificationList.vue b/webapp/components/NotificationList/NotificationList.vue index d956f6129..fd2d6366c 100644 --- a/webapp/components/NotificationList/NotificationList.vue +++ b/webapp/components/NotificationList/NotificationList.vue @@ -20,7 +20,7 @@ export default { props: { notifications: { type: Array, - required: true, + default: () => [], }, }, methods: { diff --git a/webapp/components/NotificationsTable/NotificationsTable.spec.js b/webapp/components/NotificationsTable/NotificationsTable.spec.js new file mode 100644 index 000000000..59b8953e9 --- /dev/null +++ b/webapp/components/NotificationsTable/NotificationsTable.spec.js @@ -0,0 +1,174 @@ +import { config, mount, createLocalVue, RouterLinkStub } from '@vue/test-utils' +import Styleguide from '@human-connection/styleguide' +import VTooltip from 'v-tooltip' +import Vuex from 'vuex' +import NotificationsTable from './NotificationsTable' +import Filters from '~/plugins/vue-filters' +import { notifications } from '~/components/utils/Notifications' +const localVue = createLocalVue() + +localVue.use(Styleguide) +localVue.use(Filters) +localVue.use(VTooltip) +localVue.use(Vuex) +localVue.filter('truncate', string => string) + +config.stubs['client-only'] = '' + +describe('NotificationsTable.vue', () => { + let wrapper, mocks, propsData, stubs + const postNotification = notifications[0] + const commentNotification = notifications[1] + + beforeEach(() => { + mocks = { + $t: jest.fn(string => string), + } + stubs = { + NuxtLink: RouterLinkStub, + } + propsData = {} + }) + + describe('mount', () => { + const Wrapper = () => { + const store = new Vuex.Store({ + getters: { + 'auth/isModerator': () => false, + 'auth/user': () => { + return {} + }, + }, + }) + return mount(NotificationsTable, { + propsData, + mocks, + localVue, + store, + stubs, + }) + } + + beforeEach(() => { + wrapper = Wrapper() + }) + + describe('no notifications', () => { + it('renders HcEmpty component', () => { + expect(wrapper.find('.hc-empty').exists()).toBe(true) + }) + }) + + describe('given notifications', () => { + beforeEach(() => { + propsData.notifications = notifications + wrapper = Wrapper() + }) + + it('renders a table', () => { + expect(wrapper.find('.ds-table').exists()).toBe(true) + }) + + describe('renders 4 columns', () => { + it('for icon', () => { + expect(wrapper.vm.fields.icon).toBeTruthy() + }) + + it('for user', () => { + expect(wrapper.vm.fields.user).toBeTruthy() + }) + + it('for post', () => { + expect(wrapper.vm.fields.post).toBeTruthy() + }) + + it('for content', () => { + expect(wrapper.vm.fields.content).toBeTruthy() + }) + }) + + describe('Post', () => { + let firstRowNotification + beforeEach(() => { + firstRowNotification = wrapper.findAll('tbody tr').at(0) + }) + + it('renders the author', () => { + const username = firstRowNotification.find('.username') + expect(username.text()).toEqual(postNotification.from.author.name) + }) + + it('renders the reason for the notification', () => { + const dsTexts = firstRowNotification.findAll('.ds-text') + const reason = dsTexts.filter( + element => element.text() === 'notifications.reason.mentioned_in_post', + ) + expect(reason.exists()).toBe(true) + }) + + it('renders a link to the Post', () => { + const postLink = firstRowNotification.find('a.notification-mention-post') + expect(postLink.text()).toEqual(postNotification.from.title) + }) + + it("renders the Post's content", () => { + const boldTags = firstRowNotification.findAll('b') + const content = boldTags.filter( + element => element.text() === postNotification.from.contentExcerpt, + ) + expect(content.exists()).toBe(true) + }) + }) + + describe('Comment', () => { + let secondRowNotification + beforeEach(() => { + secondRowNotification = wrapper.findAll('tbody tr').at(1) + }) + + it('renders the author', () => { + const username = secondRowNotification.find('.username') + expect(username.text()).toEqual(commentNotification.from.author.name) + }) + + it('renders the reason for the notification', () => { + const dsTexts = secondRowNotification.findAll('.ds-text') + const reason = dsTexts.filter( + element => element.text() === 'notifications.reason.mentioned_in_comment', + ) + expect(reason.exists()).toBe(true) + }) + + it('renders a link to the Post', () => { + const postLink = secondRowNotification.find('a.notification-mention-post') + expect(postLink.text()).toEqual(commentNotification.from.post.title) + }) + + it("renders the Post's content", () => { + const boldTags = secondRowNotification.findAll('b') + const content = boldTags.filter( + element => element.text() === commentNotification.from.contentExcerpt, + ) + expect(content.exists()).toBe(true) + }) + }) + + describe('unread status', () => { + it('does not have class `notification-status`', () => { + expect(wrapper.find('.notification-status').exists()).toBe(false) + }) + + it('clicking on a Post link emits `markNotificationAsRead`', () => { + wrapper.find('a.notification-mention-post').trigger('click') + expect(wrapper.emitted().markNotificationAsRead[0][0]).toEqual(postNotification.from.id) + }) + + it('adds class `notification-status` when read is true', () => { + postNotification.read = true + wrapper = Wrapper() + expect(wrapper.find('.notification-status').exists()).toBe(true) + }) + }) + }) + }) +}) diff --git a/webapp/components/NotificationsTable/NotificationsTable.story.js b/webapp/components/NotificationsTable/NotificationsTable.story.js index 6815d7275..d58f4ff73 100644 --- a/webapp/components/NotificationsTable/NotificationsTable.story.js +++ b/webapp/components/NotificationsTable/NotificationsTable.story.js @@ -7,7 +7,7 @@ import { post } from '~/components/PostCard/PostCard.story.js' import { user } from '~/components/User/User.story.js' helpers.init() -const notifications = [ +export const notifications = [ { read: true, reason: 'mentioned_in_post', diff --git a/webapp/components/NotificationsTable/NotificationsTable.vue b/webapp/components/NotificationsTable/NotificationsTable.vue index 17d062cf8..e2b9badf5 100644 --- a/webapp/components/NotificationsTable/NotificationsTable.vue +++ b/webapp/components/NotificationsTable/NotificationsTable.vue @@ -23,7 +23,7 @@ /> - + {{ $t(`notifications.reason.${scope.row.reason}`) }} @@ -43,7 +43,7 @@ diff --git a/webapp/components/utils/Notifications.js b/webapp/components/utils/Notifications.js new file mode 100644 index 000000000..dfbb1b817 --- /dev/null +++ b/webapp/components/utils/Notifications.js @@ -0,0 +1,43 @@ +export const notifications = [ + { + read: false, + reason: 'mentioned_in_post', + from: { + __typename: 'Post', + id: 'post-1', + title: 'some post title', + slug: 'some-post-title', + contentExcerpt: 'this is a post content', + author: { + id: 'john-1', + slug: 'john-doe', + name: 'John Doe', + }, + }, + }, + { + read: false, + reason: 'mentioned_in_comment', + from: { + __typename: 'Comment', + id: 'comment-2', + contentExcerpt: 'this is yet another post content', + post: { + id: 'post-1', + title: 'some post on a comment', + slug: 'some-post-on-a-comment', + contentExcerpt: 'this is a post content', + author: { + id: 'john-1', + slug: 'john-doe', + name: 'John Doe', + }, + }, + author: { + id: 'jane-1', + slug: 'jane-doe', + name: 'Jane Doe', + }, + }, + }, +]