import { setupRenderingTest } from "discourse/tests/helpers/component-test"; import hbs from "htmlbars-inline-precompile"; import fabricators from "discourse/plugins/chat/discourse/lib/fabricators"; import { render, triggerEvent, waitFor } from "@ember/test-helpers"; import { module, test } from "qunit"; import pretender, { response } from "discourse/tests/helpers/create-pretender"; import { publishToMessageBus } from "discourse/tests/helpers/qunit-helpers"; module( "Discourse Chat | Component | chat-channel | status on mentions", function (hooks) { setupRenderingTest(hooks); const channelId = 1; const channel = { id: channelId, chatable_id: 1, chatable_type: "Category", meta: { message_bus_last_ids: {} }, current_user_membership: { following: true }, chatable: { id: 1 }, }; const actingUser = { id: 1, username: "acting_user", }; const mentionedUser = { id: 1000, username: "user1", status: { description: "surfing", emoji: "surfing_man", }, }; const mentionedUser2 = { id: 2000, username: "user2", status: { description: "vacation", emoji: "desert_island", }, }; const message = { id: 1891, message: `Hey @${mentionedUser.username}`, cooked: `

Hey @${mentionedUser.username}

`, mentioned_users: [mentionedUser], user: { id: 1, username: "jesse", }, }; hooks.beforeEach(function () { pretender.get(`/chat/api/channels/1`, () => response({ channel, chat_messages: [message], meta: { can_delete_self: true }, }) ); this.channel = fabricators.channel({ id: channelId, currentUserMembership: { following: true }, meta: { can_join_chat_channel: false }, }); this.appEvents = this.container.lookup("service:appEvents"); }); test("it shows status on mentions", async function (assert) { await render(hbs``); assertStatusIsRendered( assert, statusSelector(mentionedUser.username), mentionedUser.status ); await assertStatusTooltipIsRendered( assert, statusSelector(mentionedUser.username), mentionedUser.status ); }); test("it updates status on mentions", async function (assert) { await render(hbs``); const newStatus = { description: "off to dentist", emoji: "tooth", }; this.appEvents.trigger("user-status:changed", { [mentionedUser.id]: newStatus, }); const selector = statusSelector(mentionedUser.username); await waitFor(selector); assertStatusIsRendered( assert, statusSelector(mentionedUser.username), newStatus ); await assertStatusTooltipIsRendered( assert, statusSelector(mentionedUser.username), newStatus ); }); test("it deletes status on mentions", async function (assert) { await render(hbs``); this.appEvents.trigger("user-status:changed", { [mentionedUser.id]: null, }); const selector = statusSelector(mentionedUser.username); await waitFor(selector, { count: 0 }); assert.dom(selector).doesNotExist("status is deleted"); }); test("it shows status on mentions on messages that came from Message Bus", async function (assert) { await render(hbs``); await receiveChatMessageViaMessageBus(); assertStatusIsRendered( assert, statusSelector(mentionedUser2.username), mentionedUser2.status ); await assertStatusTooltipIsRendered( assert, statusSelector(mentionedUser2.username), mentionedUser2.status ); }); test("it updates status on mentions on messages that came from Message Bus", async function (assert) { await render(hbs``); await receiveChatMessageViaMessageBus(); const newStatus = { description: "off to meeting", emoji: "calendar", }; this.appEvents.trigger("user-status:changed", { [mentionedUser2.id]: newStatus, }); const selector = statusSelector(mentionedUser2.username); await waitFor(selector); assertStatusIsRendered( assert, statusSelector(mentionedUser2.username), newStatus ); await assertStatusTooltipIsRendered( assert, statusSelector(mentionedUser2.username), newStatus ); }); test("it deletes status on mentions on messages that came from Message Bus", async function (assert) { await render(hbs``); await receiveChatMessageViaMessageBus(); this.appEvents.trigger("user-status:changed", { [mentionedUser2.id]: null, }); const selector = statusSelector(mentionedUser2.username); await waitFor(selector, { count: 0 }); assert.dom(selector).doesNotExist("status is deleted"); }); function assertStatusIsRendered(assert, selector, status) { assert .dom(selector) .exists("status is rendered") .hasAttribute( "src", new RegExp(`${status.emoji}.png`), "status emoji is updated" ); } async function assertStatusTooltipIsRendered(assert, selector, status) { await triggerEvent(selector, "mouseenter"); assert.equal( document .querySelector(".user-status-tooltip-description") .textContent.trim(), status.description, "status description is correct" ); assert.ok( document.querySelector( `.user-status-message-tooltip img[alt='${status.emoji}']` ), "status emoji is correct" ); await triggerEvent(selector, "mouseleave"); } async function receiveChatMessageViaMessageBus() { await publishToMessageBus(`/chat/${channelId}`, { chat_message: { id: 2138, message: `Hey @${mentionedUser2.username}`, cooked: `

Hey @${mentionedUser2.username}

`, created_at: "2023-05-18T16:07:59.588Z", excerpt: `Hey @${mentionedUser2.username}`, available_flags: [], chat_channel_id: 7, mentioned_users: [mentionedUser2], user: actingUser, chat_webhook_event: null, uploads: [], }, type: "sent", }); } function statusSelector(username) { return `.mention[href='/u/${username}'] .user-status-message img`; } } );