diff --git a/extensions/likes/js/src/forum/components/PostLikedNotification.js b/extensions/likes/js/src/forum/components/PostLikedNotification.js index a9d16c2c11..78ddb6dda2 100644 --- a/extensions/likes/js/src/forum/components/PostLikedNotification.js +++ b/extensions/likes/js/src/forum/components/PostLikedNotification.js @@ -19,6 +19,6 @@ export default class PostLikedNotification extends Notification { } excerpt() { - return truncate(this.attrs.notification.subject().contentPlain(), 200); + return truncate(this.attrs.notification.subject().contentPlain() || '', 200); } } diff --git a/extensions/likes/js/tests/unit/forum/PostLikedNotification.test.ts b/extensions/likes/js/tests/unit/forum/PostLikedNotification.test.ts new file mode 100644 index 0000000000..c6531b6747 --- /dev/null +++ b/extensions/likes/js/tests/unit/forum/PostLikedNotification.test.ts @@ -0,0 +1,69 @@ +import bootstrapForum from '@flarum/jest-config/src/bootstrap/forum'; +import app from 'flarum/forum/app'; +import Notification from 'flarum/common/models/Notification'; +import PostLikedNotification from '../../../src/forum/components/PostLikedNotification'; + +beforeAll(() => { + bootstrapForum(); + app.boot(); + + // jsdom has no innerText, which a post's plain content is read from. + if (!('innerText' in HTMLElement.prototype)) { + Object.defineProperty(HTMLElement.prototype, 'innerText', { + get(this: HTMLElement) { + return this.textContent; + }, + }); + } + + app.store.pushPayload({ + data: { type: 'discussions', id: '1', attributes: { slug: '1-a-discussion', title: 'A discussion' } }, + } as any); +}); + +function likedNotification(post: { id: string; attributes: Record }) { + app.store.pushPayload({ + data: { type: 'posts', ...post, relationships: { discussion: { data: { type: 'discussions', id: '1' } } } }, + } as any); + + return new Notification( + { + id: post.id, + type: 'notifications', + attributes: { contentType: 'postLiked', content: null, createdAt: new Date(), isRead: false }, + relationships: { subject: { data: { type: 'posts', id: post.id } } }, + }, + app.store + ); +} + +/** What the notification renders, as it appears in the notification list. */ +function render(notification: Notification) { + const root = document.createElement('div'); + + m.render(root, m(PostLikedNotification, { notification })); + + return root.querySelector('.Notification'); +} + +describe('the post liked notification', () => { + it('shows an excerpt of a liked comment', () => { + const notification = likedNotification({ + id: '10', + attributes: { number: 2, contentType: 'comment', contentHtml: '

The liked comment

' }, + }); + + expect(render(notification)?.textContent).toContain('The liked comment'); + }); + + // The API accepts a like on any post type, and other types have no text. A + // notification that can't render takes the whole notification list with it. + it('renders for a liked post that has no text', () => { + const notification = likedNotification({ + id: '11', + attributes: { number: 3, contentType: 'discussionRenamed', content: ['Old title', 'New title'] }, + }); + + expect(render(notification)).not.toBeNull(); + }); +});