diff options
Diffstat (limited to 'src/components/MessagesList')
6 files changed, 96 insertions, 62 deletions
diff --git a/src/components/MessagesList/MessagesGroup/Message/Message.spec.js b/src/components/MessagesList/MessagesGroup/Message/Message.spec.js index 0d8547759..7a656eb2f 100644 --- a/src/components/MessagesList/MessagesGroup/Message/Message.spec.js +++ b/src/components/MessagesList/MessagesGroup/Message/Message.spec.js @@ -86,7 +86,7 @@ describe('Message.vue', () => { store = new Vuex.Store(testStoreConfig) }) - test('renders rich text message', async() => { + test('renders rich text message', async () => { const wrapper = shallowMount(Message, { localVue, store, @@ -97,7 +97,7 @@ describe('Message.vue', () => { expect(message.attributes('text')).toBe('test message') }) - test('renders emoji as single plain text', async() => { + test('renders emoji as single plain text', async () => { messageProps.isSingleEmoji = true messageProps.message = '🌧️' const wrapper = shallowMount(Message, { @@ -268,6 +268,11 @@ describe('Message.vue', () => { }) describe('rich objects', () => { + /** + * @param message + * @param messageParameters + * @param expectedRichParameters + */ function renderRichObject(message, messageParameters, expectedRichParameters) { messageProps.message = message messageProps.messageParameters = messageParameters @@ -480,7 +485,7 @@ describe('Message.vue', () => { store = new Vuex.Store(testStoreConfig) }) - test('renders author if first message', async() => { + test('renders author if first message', async () => { messageProps.isFirstMessage = true const wrapper = shallowMount(Message, { localVue, @@ -492,7 +497,7 @@ describe('Message.vue', () => { expect(displayName.text()).toBe('user-display-name-1') }) - test('does not render author if not first message', async() => { + test('does not render author if not first message', async () => { messageProps.isFirstMessage = false const wrapper = shallowMount(Message, { localVue, @@ -512,7 +517,7 @@ describe('Message.vue', () => { store = new Vuex.Store(testStoreConfig) }) - test('does not render actions for system messages are available', async() => { + test('does not render actions for system messages are available', async () => { messageProps.systemMessage = 'this is a system message' const wrapper = shallowMount(Message, { @@ -527,7 +532,7 @@ describe('Message.vue', () => { expect(actionsEl.exists()).toBe(false) }) - test('does not render actions for temporary messages', async() => { + test('does not render actions for temporary messages', async () => { messageProps.isTemporary = true const wrapper = shallowMount(Message, { @@ -542,7 +547,7 @@ describe('Message.vue', () => { expect(actionsEl.exists()).toBe(false) }) - test('actions become visible on mouse over', async() => { + test('actions become visible on mouse over', async () => { messageProps.sendingFailure = 'timeout' const wrapper = shallowMount(Message, { localVue, @@ -573,7 +578,7 @@ describe('Message.vue', () => { }) describe('reply action', () => { - test('replies to message', async() => { + test('replies to message', async () => { const replyAction = jest.fn() testStoreConfig.modules.quoteReplyStore.actions.addMessageToBeReplied = replyAction store = new Vuex.Store(testStoreConfig) @@ -607,7 +612,7 @@ describe('Message.vue', () => { }) }) - test('hides reply button when not replyable', async() => { + test('hides reply button when not replyable', async () => { messageProps.isReplyable = false store = new Vuex.Store(testStoreConfig) @@ -626,7 +631,7 @@ describe('Message.vue', () => { }) describe('private reply action', () => { - test('creates a new conversation when replying to message privately', async() => { + test('creates a new conversation when replying to message privately', async () => { const routerPushMock = jest.fn().mockResolvedValue() const createOneToOneConversation = jest.fn() testStoreConfig.modules.conversationsStore.actions.createOneToOneConversation = createOneToOneConversation @@ -667,6 +672,9 @@ describe('Message.vue', () => { }) }) + /** + * @param visible + */ function testPrivateReplyActionVisible(visible) { store = new Vuex.Store(testStoreConfig) @@ -683,25 +691,25 @@ describe('Message.vue', () => { expect(actionButton.exists()).toBe(visible) } - test('hides private reply action for own messages', async() => { + test('hides private reply action for own messages', async () => { // using default message props which have the // actor id set to the current user testPrivateReplyActionVisible(false) }) - test('hides private reply action for one to one conversation type', async() => { + test('hides private reply action for one to one conversation type', async () => { messageProps.actorId = 'another-user' conversationProps.type = CONVERSATION.TYPE.ONE_TO_ONE testPrivateReplyActionVisible(false) }) - test('hides private reply action for guest messages', async() => { + test('hides private reply action for guest messages', async () => { messageProps.actorId = 'guest-user' messageProps.actorType = ATTENDEE.ACTOR_TYPE.GUESTS testPrivateReplyActionVisible(false) }) - test('hides private reply action when current user is a guest', async() => { + test('hides private reply action when current user is a guest', async () => { messageProps.actorId = 'another-user' getActorTypeMock.mockClear().mockReturnValue(() => ATTENDEE.ACTOR_TYPE.GUESTS) testPrivateReplyActionVisible(false) @@ -709,7 +717,7 @@ describe('Message.vue', () => { }) describe('delete action', () => { - test('deletes message', async() => { + test('deletes message', async () => { let resolveDeleteMessage const deleteMessage = jest.fn().mockReturnValue(new Promise((resolve, reject) => { resolveDeleteMessage = resolve })) testStoreConfig.modules.messagesStore.actions.deleteMessage = deleteMessage @@ -755,6 +763,11 @@ describe('Message.vue', () => { expect(wrapper.find('.icon-loading-small').exists()).toBe(false) }) + /** + * @param visible + * @param mockDate + * @param participantType + */ function testDeleteMessageVisible(visible, mockDate, participantType = PARTICIPANT.TYPE.USER) { store = new Vuex.Store(testStoreConfig) @@ -836,7 +849,7 @@ describe('Message.vue', () => { }) }) - test('marks message as unread', async() => { + test('marks message as unread', async () => { const updateLastReadMessageAction = jest.fn().mockResolvedValueOnce() const fetchConversationAction = jest.fn().mockResolvedValueOnce() testStoreConfig.modules.conversationsStore.actions.updateLastReadMessage = updateLastReadMessageAction @@ -888,7 +901,7 @@ describe('Message.vue', () => { }) }) - test('copies message link', async() => { + test('copies message link', async () => { const copyTextMock = jest.fn() // appears even with more restrictive conditions @@ -926,7 +939,7 @@ describe('Message.vue', () => { expect(copyTextMock).toHaveBeenCalledWith('http://localhost/nc-webroot/call/XXTOKENXX#message_123') }) - test('renders clickable custom actions', async() => { + test('renders clickable custom actions', async () => { const handler = jest.fn() const handler2 = jest.fn() const actionsGetterMock = jest.fn().mockReturnValue([{ @@ -977,7 +990,7 @@ describe('Message.vue', () => { store = new Vuex.Store(testStoreConfig) }) - test('lets user retry sending a timed out message', async() => { + test('lets user retry sending a timed out message', async () => { messageProps.sendingFailure = 'timeout' const wrapper = shallowMount(Message, { localVue, diff --git a/src/components/MessagesList/MessagesGroup/Message/MessagePart/FilePreview.spec.js b/src/components/MessagesList/MessagesGroup/Message/MessagePart/FilePreview.spec.js index b0bf9ba99..cee2cb2ca 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessagePart/FilePreview.spec.js +++ b/src/components/MessagesList/MessagesGroup/Message/MessagePart/FilePreview.spec.js @@ -57,12 +57,15 @@ describe('FilePreview.vue', () => { window.devicePixelRatio = oldPixelRatio }) + /** + * @param url + */ function parseRelativeUrl(url) { return new URL('https://localhost' + url) } describe('file preview rendering', () => { - test('renders file preview', async() => { + test('renders file preview', async () => { const wrapper = shallowMount(FilePreview, { localVue, store, @@ -82,7 +85,7 @@ describe('FilePreview.vue', () => { expect(wrapper.find('.loading').exists()).toBe(false) }) - test('renders file preview for guests', async() => { + test('renders file preview for guests', async () => { propsData.link = 'https://localhost/nc-webroot/s/xtokenx' getUserIdMock.mockClear().mockReturnValue(null) @@ -105,7 +108,7 @@ describe('FilePreview.vue', () => { expect(wrapper.find('.loading').exists()).toBe(false) }) - test('calculates preview size based on window pixel ratio', async() => { + test('calculates preview size based on window pixel ratio', async () => { window.devicePixelRatio = 1.5 const wrapper = shallowMount(FilePreview, { @@ -121,7 +124,7 @@ describe('FilePreview.vue', () => { expect(imageUrl.searchParams.get('y')).toBe('576') }) - test('renders small previews when requested', async() => { + test('renders small previews when requested', async () => { propsData.smallPreview = true const wrapper = shallowMount(FilePreview, { @@ -146,7 +149,7 @@ describe('FilePreview.vue', () => { store = new Vuex.Store(testStoreConfig) }) - test('renders progress bar while uploading', async() => { + test('renders progress bar while uploading', async () => { propsData.id = 'temp-123' propsData.index = 'index-1' propsData.uploadId = 1000 @@ -185,7 +188,7 @@ describe('FilePreview.vue', () => { expect(wrapper.find('.loading').exists()).toBe(true) }) - test('renders default mime icon on load error', async() => { + test('renders default mime icon on load error', async () => { const wrapper = shallowMount(FilePreview, { localVue, store, @@ -199,7 +202,7 @@ describe('FilePreview.vue', () => { expect(imageUrl).toBe(imagePath('core', 'filetypes/file')) }) - test('renders generic mime type icon for unknown mime types', async() => { + test('renders generic mime type icon for unknown mime types', async () => { propsData.previewAvailable = 'no' OC.MimeType.getIconUrl.mockReturnValueOnce(imagePath('core', 'image/jpeg')) @@ -239,7 +242,7 @@ describe('FilePreview.vue', () => { return null }) }) - test('directly renders small GIF files', async() => { + test('directly renders small GIF files', async () => { propsData.size = 128 const wrapper = shallowMount(FilePreview, { @@ -255,7 +258,7 @@ describe('FilePreview.vue', () => { .toBe(generateRemoteUrl('dav/files/current-user-id') + '/path/to/test%20%2520.gif') }) - test('directly renders small GIF files (absolute path)', async() => { + test('directly renders small GIF files (absolute path)', async () => { propsData.size = 128 propsData.path = '/path/to/test %20.gif' @@ -272,7 +275,7 @@ describe('FilePreview.vue', () => { .toBe(generateRemoteUrl('dav/files/current-user-id') + '/path/to/test%20%2520.gif') }) - test('directly renders small GIF files for guests', async() => { + test('directly renders small GIF files for guests', async () => { propsData.size = 128 propsData.link = 'https://localhost/nc-webroot/s/xtokenx' getUserIdMock.mockClear().mockReturnValue(null) @@ -290,7 +293,7 @@ describe('FilePreview.vue', () => { .toBe(propsData.link + '/download/test%20%2520.gif') }) - test('renders static preview for big GIF files', async() => { + test('renders static preview for big GIF files', async () => { // bigger than max from capability propsData.size = 2048 @@ -345,7 +348,7 @@ describe('FilePreview.vue', () => { } }) - test('opens viewer when clicking if viewer available', async() => { + test('opens viewer when clicking if viewer available', async () => { OCA.Viewer = { open: jest.fn(), availableHandlers: [{ @@ -377,7 +380,7 @@ describe('FilePreview.vue', () => { expect(OCA.Files.Sidebar.state.file).toBe('/path/to/test.jpg') }) - test('does not open viewer when clicking if no mime handler available', async() => { + test('does not open viewer when clicking if no mime handler available', async () => { OCA.Viewer = { open: jest.fn(), availableHandlers: [{ @@ -398,7 +401,7 @@ describe('FilePreview.vue', () => { expect(OCA.Viewer.open).not.toHaveBeenCalled() }) - test('does not open viewer when clicking if viewer is not available', async() => { + test('does not open viewer when clicking if viewer is not available', async () => { delete OCA.Viewer const wrapper = shallowMount(FilePreview, { localVue, @@ -427,6 +430,9 @@ describe('FilePreview.vue', () => { } }) + /** + * @param visible + */ async function testPlayButtonVisible(visible) { const wrapper = shallowMount(FilePreview, { localVue, @@ -440,11 +446,11 @@ describe('FilePreview.vue', () => { expect(buttonEl.exists()).toBe(visible) } - test('renders play icon for video previews', async() => { + test('renders play icon for video previews', async () => { await testPlayButtonVisible(true) }) - test('does not render play icon for direct renders', async() => { + test('does not render play icon for direct renders', async () => { // gif is directly rendered propsData.mimetype = 'image/gif' propsData.name = 'test.gif' @@ -453,7 +459,7 @@ describe('FilePreview.vue', () => { await testPlayButtonVisible(false) }) - test('render play icon gif previews with big size', async() => { + test('render play icon gif previews with big size', async () => { // gif is directly rendered propsData.mimetype = 'image/gif' propsData.name = 'test.gif' @@ -463,12 +469,12 @@ describe('FilePreview.vue', () => { await testPlayButtonVisible(true) }) - test('does not render play icon for small previews', async() => { + test('does not render play icon for small previews', async () => { propsData.smallPreview = true await testPlayButtonVisible(false) }) - test('does not render play icon for failed videos', async() => { + test('does not render play icon for failed videos', async () => { const wrapper = shallowMount(FilePreview, { localVue, store, @@ -481,12 +487,12 @@ describe('FilePreview.vue', () => { expect(buttonEl.exists()).toBe(false) }) - test('does not render play icon if viewer not available', async() => { + test('does not render play icon if viewer not available', async () => { delete OCA.Viewer await testPlayButtonVisible(false) }) - test('does not render play icon for non-videos', async() => { + test('does not render play icon for non-videos', async () => { // viewer supported, but not a video propsData.mimetype = 'image/png' propsData.name = 'test.png' @@ -501,7 +507,7 @@ describe('FilePreview.vue', () => { beforeEach(() => { propsData.isUploadEditor = true }) - test('emits event when clicking remove button when inside upload editor', async() => { + test('emits event when clicking remove button when inside upload editor', async () => { const wrapper = shallowMount(FilePreview, { localVue, store, diff --git a/src/components/MessagesList/MessagesGroup/Message/MessagePart/Forwarder.vue b/src/components/MessagesList/MessagesGroup/Message/MessagePart/Forwarder.vue index ffd8daea6..e62a1539c 100644 --- a/src/components/MessagesList/MessagesGroup/Message/MessagePart/Forwarder.vue +++ b/src/components/MessagesList/MessagesGroup/Message/MessagePart/Forwarder.vue @@ -103,7 +103,8 @@ export default { /** * Object containing all the mentions in the message that will be forwarded - * @returns {Object} mentions. + * + * @return {object} mentions. */ mentions() { const mentions = {} diff --git a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue index 9c77b34e8..64492cdc8 100644 --- a/src/components/MessagesList/MessagesGroup/MessagesGroup.vue +++ b/src/components/MessagesList/MessagesGroup/MessagesGroup.vue @@ -112,28 +112,32 @@ export default { computed: { /** * The message actor type. - * @returns {string} + * + * @return {string} */ actorType() { return this.messages[0].actorType }, /** * The message actor id. - * @returns {string} + * + * @return {string} */ actorId() { return this.messages[0].actorId }, /** * The message date. - * @returns {string} + * + * @return {string} */ dateSeparator() { return this.messages[0].dateSeparator || '' }, /** * The message actor display name. - * @returns {string} + * + * @return {string} */ actorDisplayName() { const displayName = this.messages[0].actorDisplayName.trim() @@ -150,7 +154,8 @@ export default { }, /** * Whether the given message is a system message - * @returns {bool} + * + * @return {bool} */ isSystemMessage() { return this.messages[0].systemMessage.length !== 0 diff --git a/src/components/MessagesList/MessagesList.spec.js b/src/components/MessagesList/MessagesList.spec.js index d9f0f2fa5..22d6a3e53 100644 --- a/src/components/MessagesList/MessagesList.spec.js +++ b/src/components/MessagesList/MessagesList.spec.js @@ -286,6 +286,9 @@ describe('MessagesList.vue', () => { expect(messagesListMock).toHaveBeenCalledWith(TOKEN) }) + /** + * @param messages + */ function testNotGrouped(messages) { messagesListMock.mockReturnValue(messages) diff --git a/src/components/MessagesList/MessagesList.vue b/src/components/MessagesList/MessagesList.vue index cfafc4a07..62143728a 100644 --- a/src/components/MessagesList/MessagesList.vue +++ b/src/components/MessagesList/MessagesList.vue @@ -147,7 +147,7 @@ export default { /** * Finds the first visual unread message element * - * @returns {object} DOM element of the first unread message + * @return {object} DOM element of the first unread message */ unreadMessageElement() { let el = document.getElementById('message_' + this.visualLastReadMessageId) @@ -162,7 +162,7 @@ export default { * Gets the messages array. We need this because the DynamicScroller needs an array to * loop through. * - * @returns {array} + * @return {Array} */ messagesList() { return this.$store.getters.messagesList(this.token) @@ -172,7 +172,7 @@ export default { * corresponds to the id of the message, and makes it easy and efficient to access the * individual message object. * - * @returns {object} + * @return {object} */ messages() { // FIXME: remove if unused ? @@ -180,7 +180,8 @@ export default { }, /** * Creates an array of messages grouped in nested arrays by same autor. - * @returns {array} + * + * @return {Array} */ messagesGroupedByAuthor() { const groups = [] @@ -211,7 +212,8 @@ export default { * When isSticky is true, as new messages are appended to the list, the div .scroller * automatically scrolls down to the last message, if it's false, new messages are * appended but the scrolling position is not altered. - * @returns {boolean} + * + * @return {boolean} */ isSticky() { return this.isChatScrolledToBottom @@ -221,7 +223,7 @@ export default { * Returns whether the current participant is a participant of the * current conversation or not. * - * @returns {Boolean} true if it is already a participant, false + * @return {boolean} true if it is already a participant, false * otherwise. */ isParticipant() { @@ -314,7 +316,7 @@ export default { * @param {string} message2.actorDisplayName Actor display name of previous message * @param {string} message2.systemMessage System message content of the previous message * @param {int} message2.timestamp Timestamp of the second message - * @returns {boolean} Boolean if the messages should be grouped or not + * @return {boolean} Boolean if the messages should be grouped or not */ messagesShouldBeGrouped(message1, message2) { if (!message2) { @@ -354,7 +356,7 @@ export default { * @param {null|object} message2 The previous message * @param {string} message2.id The ID of the second message * @param {int} message2.timestamp Timestamp of the second message - * @returns {boolean} Boolean if the messages have the same date + * @return {boolean} Boolean if the messages have the same date */ messagesHaveDifferentDate(message1, message2) { return !message2 // There is no previous message @@ -367,7 +369,7 @@ export default { * @param {object} message The message object * @param {string} message.id The ID of the message * @param {int} message.timestamp Timestamp of the message - * @returns {string} Translated string of "<Today>, <November 11th, 2019>", "<3 days ago>, <November 8th, 2019>" + * @return {string} Translated string of "<Today>, <November 11th, 2019>", "<3 days ago>, <November 8th, 2019>" */ generateDateSeparator(message) { const date = this.getDateOfMessage(message) @@ -402,7 +404,7 @@ export default { * @param {object} message The message object * @param {string} message.id The ID of the message * @param {int} message.timestamp Timestamp of the message - * @returns {object} MomentJS object + * @return {object} MomentJS object */ getDateOfMessage(message) { if (message.id.toString().startsWith('temp-')) { @@ -512,6 +514,7 @@ export default { /** * Get messages history. + * * @param {boolean} includeLastKnown Include or exclude the last known message in the response */ async getOldMessages(includeLastKnown) { @@ -535,6 +538,7 @@ export default { /** * Creates a long polling request for a new message. + * * @param {boolean} scrollToBottom Whether we should try to automatically scroll to the bottom */ async getNewMessages(scrollToBottom = true) { @@ -634,7 +638,7 @@ export default { * the bottom of the viewport. * * @param {object} messageEl message element after which to start searching - * @returns {object} DOM element for the last visible message + * @return {object} DOM element for the last visible message */ findFirstVisibleMessage(messageEl) { let el = messageEl @@ -789,7 +793,7 @@ export default { * @param {string} messageId message id * @param {boolean} smooth true to smooth scroll, false to jump directly * @param {boolean} highlightAnimation true to highlight and set focus to the message - * @returns {bool} true if element was found, false otherwise + * @return {bool} true if element was found, false otherwise */ focusMessage(messageId, smooth = true, highlightAnimation = true) { const element = document.getElementById(`message_${messageId}`) @@ -799,7 +803,7 @@ export default { return false } - this.$nextTick(async() => { + this.$nextTick(async () => { // FIXME: this doesn't wait for the smooth scroll to end await element.scrollIntoView({ behavior: smooth ? 'smooth' : 'auto', @@ -821,7 +825,8 @@ export default { /** * gets the last known message id. - * @returns {string} The last known message id. + * + * @return {string} The last known message id. */ getLastKnownMessageId() { let i = this.messagesList.length - 1 @@ -836,7 +841,8 @@ export default { }, /** * gets the first message's id. - * @returns {string} + * + * @return {string} */ getFirstKnownMessageId() { return this.messagesList[0].id.toString() |