2023-05-24 20:55:20 +08:00
|
|
|
import {
|
|
|
|
acceptance,
|
|
|
|
emulateAutocomplete,
|
|
|
|
loggedInUser,
|
|
|
|
publishToMessageBus,
|
|
|
|
query,
|
|
|
|
} from "discourse/tests/helpers/qunit-helpers";
|
2023-07-04 05:42:47 +08:00
|
|
|
import { skip } from "qunit";
|
2023-06-08 22:28:42 +08:00
|
|
|
import { click, triggerEvent, visit, waitFor } from "@ember/test-helpers";
|
2023-07-07 02:39:23 +08:00
|
|
|
import pretender, { response } from "discourse/tests/helpers/create-pretender";
|
2023-05-24 20:55:20 +08:00
|
|
|
|
|
|
|
acceptance("Chat | User status on mentions", function (needs) {
|
|
|
|
const channelId = 1;
|
|
|
|
const messageId = 1;
|
|
|
|
const actingUser = {
|
|
|
|
id: 1,
|
|
|
|
username: "acting_user",
|
|
|
|
};
|
|
|
|
const mentionedUser1 = {
|
|
|
|
id: 1000,
|
|
|
|
username: "user1",
|
|
|
|
status: {
|
|
|
|
description: "surfing",
|
|
|
|
emoji: "surfing_man",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const mentionedUser2 = {
|
|
|
|
id: 2000,
|
|
|
|
username: "user2",
|
|
|
|
status: {
|
|
|
|
description: "vacation",
|
|
|
|
emoji: "desert_island",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const mentionedUser3 = {
|
|
|
|
id: 3000,
|
|
|
|
username: "user3",
|
|
|
|
status: {
|
|
|
|
description: "off to dentist",
|
|
|
|
emoji: "tooth",
|
|
|
|
},
|
|
|
|
};
|
|
|
|
const message = {
|
|
|
|
id: messageId,
|
|
|
|
message: `Hey @${mentionedUser1.username}`,
|
|
|
|
cooked: `<p>Hey <a class="mention" href="/u/${mentionedUser1.username}">@${mentionedUser1.username}</a></p>`,
|
|
|
|
mentioned_users: [mentionedUser1],
|
|
|
|
user: actingUser,
|
FIX: hide tooltips when scrolling on mobile (#23098)
This fixes the problem reported in
https://meta.discourse.org/t/custom-status-message-in-front-of-by-header-on-scroll/273320.
This problem can be reproduced with any tooltip created using the DTooltip
component or the createDTooltip function.
The problem happens because the trigger for tooltip on mobile is click, and for tooltip
to disappear the user has to click outside the tooltip. This is the default behavior
of tippy.js – the library we use under the hood.
Note that this PR fixes the problem in topics, but not in chat. I'm going to investigate and
address it in chat in a following PR.
To fix it for tooltips created with the createDTooltip function, I had to make a refactoring.
We had a somewhat not ideal solution there, we were leaking an implementation detail
by passing tippy instances to calling sides, so they could then destroy them. With this fix,
I would have to make it more complex, because now we need to also remove onScrool
handlers, and I would need to leak this implementation detail too. So, I firstly refactored
the current solution in 5a4af05 and then added onScroll handlers in fb4aabe.
When refactoring this, I was running locally some temporarily skipped flaky tests. Turned out
they got a bit outdated, so I fixed them. Note that I'm not unskipping them in this commit,
we'll address them separately later.
2023-08-23 19:39:58 +08:00
|
|
|
created_at: "2020-08-04T15:00:00.000Z",
|
2023-05-24 20:55:20 +08:00
|
|
|
};
|
|
|
|
const newStatus = {
|
|
|
|
description: "working remotely",
|
|
|
|
emoji: "house",
|
|
|
|
};
|
|
|
|
const channel = {
|
|
|
|
id: channelId,
|
|
|
|
chatable_id: 1,
|
|
|
|
chatable_type: "Category",
|
FIX: hide tooltips when scrolling on mobile (#23098)
This fixes the problem reported in
https://meta.discourse.org/t/custom-status-message-in-front-of-by-header-on-scroll/273320.
This problem can be reproduced with any tooltip created using the DTooltip
component or the createDTooltip function.
The problem happens because the trigger for tooltip on mobile is click, and for tooltip
to disappear the user has to click outside the tooltip. This is the default behavior
of tippy.js – the library we use under the hood.
Note that this PR fixes the problem in topics, but not in chat. I'm going to investigate and
address it in chat in a following PR.
To fix it for tooltips created with the createDTooltip function, I had to make a refactoring.
We had a somewhat not ideal solution there, we were leaking an implementation detail
by passing tippy instances to calling sides, so they could then destroy them. With this fix,
I would have to make it more complex, because now we need to also remove onScrool
handlers, and I would need to leak this implementation detail too. So, I firstly refactored
the current solution in 5a4af05 and then added onScroll handlers in fb4aabe.
When refactoring this, I was running locally some temporarily skipped flaky tests. Turned out
they got a bit outdated, so I fixed them. Note that I'm not unskipping them in this commit,
we'll address them separately later.
2023-08-23 19:39:58 +08:00
|
|
|
meta: { message_bus_last_ids: {}, can_delete_self: true },
|
2023-05-24 20:55:20 +08:00
|
|
|
current_user_membership: { following: true },
|
|
|
|
chatable: { id: 1 },
|
|
|
|
};
|
|
|
|
|
|
|
|
needs.settings({ chat_enabled: true });
|
|
|
|
|
|
|
|
needs.user({
|
|
|
|
...actingUser,
|
|
|
|
has_chat_enabled: true,
|
|
|
|
chat_channels: {
|
|
|
|
public_channels: [channel],
|
|
|
|
direct_message_channels: [],
|
|
|
|
meta: { message_bus_last_ids: {} },
|
|
|
|
tracking: {},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
|
|
|
needs.hooks.beforeEach(function () {
|
2023-07-07 02:39:23 +08:00
|
|
|
pretender.post(`/chat/1`, () => response({}));
|
|
|
|
pretender.put(`/chat/1/edit/${messageId}`, () => response({}));
|
|
|
|
pretender.post(`/chat/drafts`, () => response({}));
|
|
|
|
pretender.put(`/chat/api/channels/1/read/1`, () => response({}));
|
FIX: hide tooltips when scrolling on mobile (#23098)
This fixes the problem reported in
https://meta.discourse.org/t/custom-status-message-in-front-of-by-header-on-scroll/273320.
This problem can be reproduced with any tooltip created using the DTooltip
component or the createDTooltip function.
The problem happens because the trigger for tooltip on mobile is click, and for tooltip
to disappear the user has to click outside the tooltip. This is the default behavior
of tippy.js – the library we use under the hood.
Note that this PR fixes the problem in topics, but not in chat. I'm going to investigate and
address it in chat in a following PR.
To fix it for tooltips created with the createDTooltip function, I had to make a refactoring.
We had a somewhat not ideal solution there, we were leaking an implementation detail
by passing tippy instances to calling sides, so they could then destroy them. With this fix,
I would have to make it more complex, because now we need to also remove onScrool
handlers, and I would need to leak this implementation detail too. So, I firstly refactored
the current solution in 5a4af05 and then added onScroll handlers in fb4aabe.
When refactoring this, I was running locally some temporarily skipped flaky tests. Turned out
they got a bit outdated, so I fixed them. Note that I'm not unskipping them in this commit,
we'll address them separately later.
2023-08-23 19:39:58 +08:00
|
|
|
pretender.get(`/chat/api/channels/1/messages`, () =>
|
|
|
|
response({
|
|
|
|
messages: [message],
|
|
|
|
meta: {
|
|
|
|
can_load_more_future: false,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
);
|
2023-07-07 02:39:23 +08:00
|
|
|
pretender.delete(`/chat/api/channels/1/messages/${messageId}`, () =>
|
|
|
|
response({})
|
|
|
|
);
|
2023-05-24 20:55:20 +08:00
|
|
|
pretender.put(`/chat/api/channels/1/messages/${messageId}/restore`, () =>
|
2023-07-07 02:39:23 +08:00
|
|
|
response({})
|
2023-05-24 20:55:20 +08:00
|
|
|
);
|
|
|
|
|
2023-07-07 02:39:23 +08:00
|
|
|
pretender.get("/u/search/users", () =>
|
|
|
|
response({
|
|
|
|
users: [mentionedUser2, mentionedUser3],
|
|
|
|
})
|
|
|
|
);
|
|
|
|
|
|
|
|
pretender.get("/chat/api/mentions/groups.json", () =>
|
|
|
|
response({
|
|
|
|
unreachable: [],
|
|
|
|
over_members_limit: [],
|
|
|
|
invalid: ["and"],
|
|
|
|
})
|
|
|
|
);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-06-09 04:01:41 +08:00
|
|
|
skip("just posted messages | it shows status on mentions ", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
await typeWithAutocompleteAndSend(`mentioning @${mentionedUser2.username}`);
|
|
|
|
assertStatusIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser2.username),
|
|
|
|
mentionedUser2.status
|
|
|
|
);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser2.username),
|
|
|
|
mentionedUser2.status
|
|
|
|
);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-06-09 04:01:41 +08:00
|
|
|
skip("just posted messages | it updates status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
await typeWithAutocompleteAndSend(`mentioning @${mentionedUser2.username}`);
|
|
|
|
|
|
|
|
loggedInUser().appEvents.trigger("user-status:changed", {
|
|
|
|
[mentionedUser2.id]: newStatus,
|
|
|
|
});
|
|
|
|
|
|
|
|
const selector = statusSelector(mentionedUser2.username);
|
|
|
|
await waitFor(selector);
|
|
|
|
assertStatusIsRendered(assert, selector, newStatus);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(assert, selector, newStatus);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-06-09 04:01:41 +08:00
|
|
|
skip("just posted messages | it deletes status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await typeWithAutocompleteAndSend(`mentioning @${mentionedUser2.username}`);
|
|
|
|
|
|
|
|
loggedInUser().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");
|
|
|
|
});
|
|
|
|
|
2023-06-09 04:01:41 +08:00
|
|
|
skip("edited messages | it shows status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await editMessage(
|
|
|
|
".chat-message-content",
|
|
|
|
`mentioning @${mentionedUser3.username}`
|
|
|
|
);
|
|
|
|
|
|
|
|
assertStatusIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser3.username),
|
|
|
|
mentionedUser3.status
|
|
|
|
);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser3.username),
|
|
|
|
mentionedUser3.status
|
|
|
|
);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-06-09 04:01:41 +08:00
|
|
|
skip("edited messages | it updates status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
await editMessage(
|
|
|
|
".chat-message-content",
|
|
|
|
`mentioning @${mentionedUser3.username}`
|
|
|
|
);
|
|
|
|
|
|
|
|
loggedInUser().appEvents.trigger("user-status:changed", {
|
|
|
|
[mentionedUser3.id]: newStatus,
|
|
|
|
});
|
|
|
|
|
|
|
|
const selector = statusSelector(mentionedUser3.username);
|
|
|
|
await waitFor(selector);
|
|
|
|
assertStatusIsRendered(assert, selector, newStatus);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(assert, selector, newStatus);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-06-09 04:01:41 +08:00
|
|
|
skip("edited messages | it deletes status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await editMessage(
|
|
|
|
".chat-message-content",
|
|
|
|
`mentioning @${mentionedUser3.username}`
|
|
|
|
);
|
|
|
|
|
|
|
|
loggedInUser().appEvents.trigger("user-status:changed", {
|
|
|
|
[mentionedUser3.id]: null,
|
|
|
|
});
|
|
|
|
|
|
|
|
const selector = statusSelector(mentionedUser3.username);
|
|
|
|
await waitFor(selector, { count: 0 });
|
|
|
|
assert.dom(selector).doesNotExist("status is deleted");
|
|
|
|
});
|
|
|
|
|
2023-07-04 05:00:09 +08:00
|
|
|
skip("deleted messages | it shows status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await deleteMessage(".chat-message-content");
|
|
|
|
await click(".chat-message-expand");
|
|
|
|
|
|
|
|
assertStatusIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser1.username),
|
|
|
|
mentionedUser1.status
|
|
|
|
);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser1.username),
|
|
|
|
mentionedUser1.status
|
|
|
|
);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-07-04 05:42:47 +08:00
|
|
|
skip("deleted messages | it updates status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await deleteMessage(".chat-message-content");
|
|
|
|
await click(".chat-message-expand");
|
|
|
|
|
|
|
|
loggedInUser().appEvents.trigger("user-status:changed", {
|
|
|
|
[mentionedUser1.id]: newStatus,
|
|
|
|
});
|
|
|
|
|
|
|
|
const selector = statusSelector(mentionedUser1.username);
|
|
|
|
await waitFor(selector);
|
|
|
|
assertStatusIsRendered(assert, selector, newStatus);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(assert, selector, newStatus);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-07-04 05:20:19 +08:00
|
|
|
skip("deleted messages | it deletes status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await deleteMessage(".chat-message-content");
|
|
|
|
await click(".chat-message-expand");
|
|
|
|
|
|
|
|
loggedInUser().appEvents.trigger("user-status:changed", {
|
|
|
|
[mentionedUser1.id]: null,
|
|
|
|
});
|
|
|
|
|
|
|
|
const selector = statusSelector(mentionedUser1.username);
|
|
|
|
await waitFor(selector, { count: 0 });
|
|
|
|
assert.dom(selector).doesNotExist("status is deleted");
|
|
|
|
});
|
|
|
|
|
2023-07-04 05:42:47 +08:00
|
|
|
skip("restored messages | it shows status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await deleteMessage(".chat-message-content");
|
2023-06-19 15:50:54 +08:00
|
|
|
await restoreMessage(".chat-message-text.-deleted");
|
2023-05-24 20:55:20 +08:00
|
|
|
|
|
|
|
assertStatusIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser1.username),
|
|
|
|
mentionedUser1.status
|
|
|
|
);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(
|
|
|
|
assert,
|
|
|
|
statusSelector(mentionedUser1.username),
|
|
|
|
mentionedUser1.status
|
|
|
|
);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-07-04 04:54:03 +08:00
|
|
|
skip("restored messages | it updates status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await deleteMessage(".chat-message-content");
|
2023-06-19 15:50:54 +08:00
|
|
|
await restoreMessage(".chat-message-text.-deleted");
|
2023-05-24 20:55:20 +08:00
|
|
|
|
|
|
|
loggedInUser().appEvents.trigger("user-status:changed", {
|
|
|
|
[mentionedUser1.id]: newStatus,
|
|
|
|
});
|
|
|
|
|
|
|
|
const selector = statusSelector(mentionedUser1.username);
|
|
|
|
await waitFor(selector);
|
|
|
|
assertStatusIsRendered(assert, selector, newStatus);
|
2023-07-03 22:09:41 +08:00
|
|
|
await assertStatusTooltipIsRendered(assert, selector, newStatus);
|
2023-05-24 20:55:20 +08:00
|
|
|
});
|
|
|
|
|
2023-07-04 05:20:19 +08:00
|
|
|
skip("restored messages | it deletes status on mentions", async function (assert) {
|
2023-05-24 20:55:20 +08:00
|
|
|
await visit(`/chat/c/-/${channelId}`);
|
|
|
|
|
|
|
|
await deleteMessage(".chat-message-content");
|
2023-06-19 15:50:54 +08:00
|
|
|
await restoreMessage(".chat-message-text.-deleted");
|
2023-05-24 20:55:20 +08:00
|
|
|
|
|
|
|
loggedInUser().appEvents.trigger("user-status:changed", {
|
|
|
|
[mentionedUser1.id]: null,
|
|
|
|
});
|
|
|
|
|
|
|
|
const selector = statusSelector(mentionedUser1.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"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-07-03 22:09:41 +08:00
|
|
|
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");
|
|
|
|
}
|
|
|
|
|
2023-05-24 20:55:20 +08:00
|
|
|
async function deleteMessage(messageSelector) {
|
|
|
|
await triggerEvent(query(messageSelector), "mouseenter");
|
|
|
|
await click(".more-buttons .select-kit-header-wrapper");
|
|
|
|
await click(".select-kit-collection .select-kit-row[data-value='delete']");
|
|
|
|
await publishToMessageBus(`/chat/${channelId}`, {
|
|
|
|
type: "delete",
|
|
|
|
deleted_id: messageId,
|
|
|
|
deleted_at: "2022-01-01T08:00:00.000Z",
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function editMessage(messageSelector, text) {
|
|
|
|
await triggerEvent(query(messageSelector), "mouseenter");
|
|
|
|
await click(".more-buttons .select-kit-header-wrapper");
|
|
|
|
await click(".select-kit-collection .select-kit-row[data-value='edit']");
|
|
|
|
await typeWithAutocompleteAndSend(text);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function restoreMessage(messageSelector) {
|
|
|
|
await triggerEvent(query(messageSelector), "mouseenter");
|
|
|
|
await click(".more-buttons .select-kit-header-wrapper");
|
|
|
|
await click(".select-kit-collection .select-kit-row[data-value='restore']");
|
|
|
|
await publishToMessageBus(`/chat/${channelId}`, {
|
|
|
|
type: "restore",
|
|
|
|
chat_message: message,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function typeWithAutocompleteAndSend(text) {
|
|
|
|
await emulateAutocomplete(".chat-composer__input", text);
|
|
|
|
await click(".autocomplete.ac-user .selected");
|
2023-06-08 22:28:42 +08:00
|
|
|
await click(".chat-composer-button.-send");
|
2023-05-24 20:55:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
function statusSelector(username) {
|
2023-07-03 22:09:41 +08:00
|
|
|
return `.mention[href='/u/${username}'] .user-status-message img`;
|
2023-05-24 20:55:20 +08:00
|
|
|
}
|
|
|
|
});
|