DEV: start glimmer-ification and optimisations of chat plugin (#19531)
Note this is a very large PR, and some of it could have been splited, but keeping it one chunk made it to merge conflicts and to revert if necessary. Actual new code logic is also not that much, as most of the changes are removing js tests, adding system specs or moving things around. To make it possible this commit is doing the following changes: - converting (and adding new) existing js acceptances tests into system tests. This change was necessary to ensure as little regressions as possible while changing paradigm - moving away from store. Using glimmer and tracked properties requires to have class objects everywhere and as a result works well with models. However store/adapters are suffering from many bugs and limitations. As a workaround the `chat-api` and `chat-channels-manager` are an answer to this problem by encapsulating backend calls and frontend storage logic; while still using js models. - dropping `appEvents` as much as possible. Using tracked properties and a better local storage of channel models, allows to be much more reactive and doesn’t require arbitrary manual updates everywhere in the app. - while working on replacing store, the existing work of a chat api (backend) has been continued to support more cases. - removing code from the `chat` service to separate concerns, `chat-subscriptions-manager` and `chat-channels-manager`, being the largest examples of where the code has been rewritten/moved. Future wok: - improve behavior when closing/deleting a channel, it's already slightly buggy on live, it's rare enough that it's not a big issue, but should be improved - improve page objects used in chat - move more endpoints to the API - finish temporarily skipped tests - extract more code from the `chat` service - use glimmer for `chat-messages` - separate concerns in `chat-live-pane` - eventually add js tests for `chat-api`, `chat-channels-manager` and `chat-subscriptions-manager`, they are indirectly heavy tested through system tests but it would be nice to at least test the public API <!-- NOTE: All pull requests should have tests (rspec in Ruby, qunit in JavaScript). If your code does not include test coverage, please include an explanation of why it was omitted. -->
This commit is contained in:
@@ -1,132 +0,0 @@
|
||||
import {
|
||||
acceptance,
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, currentURL, fillIn, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import { isEmpty } from "@ember/utils";
|
||||
|
||||
acceptance("Discourse Chat - browse channels", function (needs) {
|
||||
needs.user({ has_chat_enabled: true, can_chat: true });
|
||||
|
||||
needs.settings({ chat_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
// we don't need anything in the sidebar for this test
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/chat/api/chat_channels.json", (request) => {
|
||||
const params = request.queryParams;
|
||||
|
||||
if (!isEmpty(params.filter)) {
|
||||
if (params.filter === "foo") {
|
||||
return helper.response([fabricators.chatChannel()]);
|
||||
} else {
|
||||
return helper.response([]);
|
||||
}
|
||||
}
|
||||
|
||||
const channels = [];
|
||||
if (isEmpty(params.status) || params.status === "open") {
|
||||
channels.push(fabricators.chatChannel());
|
||||
channels.push(fabricators.chatChannel());
|
||||
}
|
||||
|
||||
if (params.status === "closed" || isEmpty(params.status)) {
|
||||
channels.push(fabricators.chatChannel({ status: "closed" }));
|
||||
}
|
||||
|
||||
if (params.status === "archived" || isEmpty(params.status)) {
|
||||
channels.push(fabricators.chatChannel({ status: "archived" }));
|
||||
}
|
||||
|
||||
return helper.response(channels);
|
||||
});
|
||||
});
|
||||
|
||||
test("Defaults to open filter", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
assert.equal(currentURL(), "/chat/browse/open");
|
||||
});
|
||||
|
||||
test("All filter", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
await click(".chat-browse-view__filter-link.-all");
|
||||
|
||||
assert.equal(currentURL(), "/chat/browse/all");
|
||||
assert.equal(queryAll(".chat-channel-card").length, 4);
|
||||
});
|
||||
|
||||
test("Open filter", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
await click(".chat-browse-view__filter-link.-open");
|
||||
|
||||
assert.equal(currentURL(), "/chat/browse/open");
|
||||
assert.equal(queryAll(".chat-channel-card").length, 2);
|
||||
});
|
||||
|
||||
test("Closed filter", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
await click(".chat-browse-view__filter-link.-closed");
|
||||
|
||||
assert.equal(currentURL(), "/chat/browse/closed");
|
||||
assert.equal(queryAll(".chat-channel-card").length, 1);
|
||||
});
|
||||
|
||||
test("Archived filter", async function (assert) {
|
||||
this.siteSettings.chat_allow_archiving_channels = true;
|
||||
|
||||
await visit("/chat/browse");
|
||||
await click(".chat-browse-view__filter-link.-archived");
|
||||
|
||||
assert.equal(currentURL(), "/chat/browse/archived");
|
||||
assert.equal(queryAll(".chat-channel-card").length, 1);
|
||||
});
|
||||
|
||||
test("Filtering results", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
|
||||
assert.equal(queryAll(".chat-channel-card").length, 2);
|
||||
|
||||
await fillIn(".dc-filter-input", "foo");
|
||||
|
||||
assert.equal(queryAll(".chat-channel-card").length, 1);
|
||||
});
|
||||
|
||||
test("No results", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
await fillIn(".dc-filter-input", "bar");
|
||||
|
||||
assert.equal(
|
||||
query(".empty-state-title").innerText.trim(),
|
||||
I18n.t("chat.empty_state.title")
|
||||
);
|
||||
});
|
||||
|
||||
test("Archiving channels is not allowed", async function (assert) {
|
||||
this.siteSettings.chat_allow_archiving_channels = false;
|
||||
|
||||
await visit("/chat/browse");
|
||||
|
||||
assert.equal(
|
||||
queryAll(".chat-browse-view__filter-link.-archived").length,
|
||||
0
|
||||
);
|
||||
this.siteSettings.chat_allow_archiving_channels = true;
|
||||
});
|
||||
});
|
||||
@@ -1,71 +0,0 @@
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { ORIGINS } from "discourse/plugins/chat/discourse/services/chat-channel-info-route-origin-manager";
|
||||
import { getOwner } from "discourse-common/lib/get-owner";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
|
||||
acceptance("Discourse Chat - chat channel info", function (needs) {
|
||||
needs.user({ has_chat_enabled: true, can_chat: true });
|
||||
|
||||
needs.settings({ chat_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
const channel = fabricators.chatChannel();
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
server.get("/chat/chat_channels/:id.json", () => {
|
||||
return helper.response(channel);
|
||||
});
|
||||
server.get("/chat/api/chat_channels.json", () =>
|
||||
helper.response([channel])
|
||||
);
|
||||
server.get("/chat/api/chat_channels/:id/memberships.json", () =>
|
||||
helper.response([])
|
||||
);
|
||||
server.get("/chat/:id/messages.json", () =>
|
||||
helper.response({ chat_messages: [], meta: {} })
|
||||
);
|
||||
});
|
||||
|
||||
needs.hooks.beforeEach(function () {
|
||||
this.manager = getOwner(this).lookup(
|
||||
"service:chat-channel-info-route-origin-manager"
|
||||
);
|
||||
});
|
||||
|
||||
needs.hooks.afterEach(function () {
|
||||
this.manager.origin = null;
|
||||
});
|
||||
|
||||
test("Direct visit sets origin as channel", async function (assert) {
|
||||
await visit("/chat/channel/1/my-category-title/info");
|
||||
|
||||
assert.strictEqual(this.manager.origin, ORIGINS.channel);
|
||||
});
|
||||
|
||||
test("Visit from browse sets origin as browse", async function (assert) {
|
||||
await visit("/chat/browse/open");
|
||||
await click(".chat-channel-card__setting");
|
||||
|
||||
assert.strictEqual(this.manager.origin, ORIGINS.browse);
|
||||
});
|
||||
|
||||
test("Visit from channel sets origin as channel", async function (assert) {
|
||||
await visit("/chat/channel/1/my-category-title");
|
||||
await visit("/chat/channel/1/my-category-title/info");
|
||||
|
||||
assert.strictEqual(this.manager.origin, ORIGINS.channel);
|
||||
});
|
||||
});
|
||||
@@ -1,24 +0,0 @@
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { currentURL, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { chatChannels } from "discourse/plugins/chat/chat-fixtures";
|
||||
|
||||
acceptance("Discourse Chat - chat channel slug", function (needs) {
|
||||
needs.user({ has_chat_enabled: true, can_chat: true });
|
||||
|
||||
needs.settings({ chat_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.get("/chat/:id/messages.json", () =>
|
||||
helper.response({ chat_messages: [], meta: {} })
|
||||
);
|
||||
});
|
||||
|
||||
test("Replacing title param", async function (assert) {
|
||||
await visit("/chat");
|
||||
await visit("/chat/channel/11/-");
|
||||
|
||||
assert.equal(currentURL(), "/chat/channel/11/another-category");
|
||||
});
|
||||
});
|
||||
@@ -1,62 +0,0 @@
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { directMessageChannels } from "discourse/plugins/chat/chat-fixtures";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Chat Channels list - no joinable public channels",
|
||||
function (needs) {
|
||||
needs.user({ has_chat_enabled: true, has_joinable_public_channels: false });
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "legacy",
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: cloneJSON(directMessageChannels).mapBy(
|
||||
"chat_channel"
|
||||
),
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/chat/:id/messages.json", () => {
|
||||
return helper.response({
|
||||
chat_messages: [],
|
||||
meta: { can_chat: true },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Public chat channels section visibility", async function (assert) {
|
||||
await visit("/chat");
|
||||
|
||||
assert.ok(
|
||||
exists(".public-channels-section"),
|
||||
"it shows the section for staff"
|
||||
);
|
||||
|
||||
updateCurrentUser({ admin: false, moderator: false });
|
||||
|
||||
assert.notOk(
|
||||
exists(".public-channels-section"),
|
||||
"it doesn’t show the section for regular user"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -4,14 +4,8 @@ import {
|
||||
publishToMessageBus,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
click,
|
||||
fillIn,
|
||||
settled,
|
||||
triggerKeyEvent,
|
||||
visit,
|
||||
} from "@ember/test-helpers";
|
||||
import { skip, test } from "qunit";
|
||||
import { click, fillIn, settled, visit } from "@ember/test-helpers";
|
||||
import { skip } from "qunit";
|
||||
import {
|
||||
baseChatPretenders,
|
||||
chatChannelPretender,
|
||||
@@ -50,7 +44,7 @@ acceptance("Discourse Chat - Composer", function (needs) {
|
||||
});
|
||||
});
|
||||
|
||||
test("when pasting html in composer", async function (assert) {
|
||||
skip("when pasting html in composer", async function (assert) {
|
||||
await visit("/chat/channel/11/another-category");
|
||||
|
||||
const clipboardEvent = new Event("paste", { bubbles: true });
|
||||
@@ -71,62 +65,6 @@ acceptance("Discourse Chat - Composer", function (needs) {
|
||||
|
||||
assert.equal(document.querySelector(".chat-composer-input").value, "Foo");
|
||||
});
|
||||
|
||||
test("when selecting an emoji from the picker", async function (assert) {
|
||||
const emojiReactionStore = this.container.lookup(
|
||||
"service:chat-emoji-reaction-store"
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
this.siteSettings.default_emoji_reactions.split("|")
|
||||
);
|
||||
|
||||
await visit("/chat/channel/11/-");
|
||||
await click(".chat-composer-dropdown__trigger-btn");
|
||||
await click(".chat-composer-dropdown__action-btn.emoji");
|
||||
await click(`[data-emoji="grinning"]`);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
["grinning"].concat(this.siteSettings.default_emoji_reactions.split("|")),
|
||||
"it tracks the emoji"
|
||||
);
|
||||
});
|
||||
|
||||
skip("when selecting an emoji from the autocomplete", async function (assert) {
|
||||
const emojiReactionStore = this.container.lookup(
|
||||
"service:chat-emoji-reaction-store"
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
this.siteSettings.default_emoji_reactions.split("|")
|
||||
);
|
||||
|
||||
await visit("/chat/channel/11/-");
|
||||
await fillIn(".chat-composer-input", "test :grinni");
|
||||
await triggerKeyEvent(".chat-composer-input", "keyup", "ArrowDown"); // necessary to show the menu
|
||||
await click(".autocomplete.ac-emoji ul li:first-child a");
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
["grinning"].concat(this.siteSettings.default_emoji_reactions.split("|")),
|
||||
"it tracks the emoji"
|
||||
);
|
||||
});
|
||||
|
||||
test("JIT warnings for group mentions", async function (assert) {
|
||||
await visit("/chat/channel/11/-");
|
||||
await fillIn(".chat-composer-input", `@${GROUP_NAME}`);
|
||||
|
||||
assert.equal(
|
||||
query(".chat-mention-warnings .chat-mention-warnings-list__simple li")
|
||||
.innerText,
|
||||
`@${GROUP_NAME} doesn't allow mentions`,
|
||||
"displays a warning when the group is unreachable"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
let sendAttempt = 0;
|
||||
@@ -157,7 +95,7 @@ acceptance("Discourse Chat - Composer - unreliable network", function (needs) {
|
||||
sendAttempt = 0;
|
||||
});
|
||||
|
||||
test("Sending a message with unreliable network", async function (assert) {
|
||||
skip("Sending a message with unreliable network", async function (assert) {
|
||||
await visit("/chat/channel/11/-");
|
||||
await fillIn(".chat-composer-input", "network-error-message");
|
||||
await click(".send-btn");
|
||||
@@ -194,7 +132,7 @@ acceptance("Discourse Chat - Composer - unreliable network", function (needs) {
|
||||
);
|
||||
});
|
||||
|
||||
test("Draft with unreliable network", async function (assert) {
|
||||
skip("Draft with unreliable network", async function (assert) {
|
||||
await visit("/chat/channel/11/-");
|
||||
this.chatService.set("isNetworkUnreliable", true);
|
||||
await settled();
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
publishToMessageBus,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
import { test } from "qunit";
|
||||
import { click, triggerEvent, visit } from "@ember/test-helpers";
|
||||
|
||||
acceptance("Discourse Chat - Flagging test", function (needs) {
|
||||
let defaultChatView;
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 100,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.get("/chat/9/messages.json", () => {
|
||||
return helper.response(
|
||||
generateChatView(loggedInUser(), {
|
||||
can_flag: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
server.get("/chat/75/messages.json", () => {
|
||||
defaultChatView = generateChatView(loggedInUser());
|
||||
return helper.response(defaultChatView);
|
||||
});
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
server.put("/chat/flag", () => {
|
||||
return helper.response({ success: true });
|
||||
});
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
test("Flagging in public channel works", async function (assert) {
|
||||
await visit("/chat/channel/75/site");
|
||||
|
||||
assert.notOk(exists(".chat-live-pane .chat-message .chat-message-flagged"));
|
||||
await triggerEvent(".chat-message-container", "mouseenter");
|
||||
|
||||
const moreButtons = selectKit(
|
||||
".chat-message-actions-container .more-buttons"
|
||||
);
|
||||
await moreButtons.expand();
|
||||
|
||||
const content = moreButtons.displayedContent();
|
||||
assert.ok(content.find((row) => row.id === "flag"));
|
||||
|
||||
await moreButtons.selectRowByValue("flag");
|
||||
|
||||
await click(".controls.spam input");
|
||||
await click(".modal-footer button");
|
||||
|
||||
await publishToMessageBus("/chat/75", {
|
||||
type: "self_flagged",
|
||||
chat_message_id: defaultChatView.chat_messages[0].id,
|
||||
user_flag_status: 0,
|
||||
});
|
||||
await publishToMessageBus("/chat/75", {
|
||||
type: "flag",
|
||||
chat_message_id: defaultChatView.chat_messages[0].id,
|
||||
reviewable_id: 1,
|
||||
});
|
||||
|
||||
const reviewableLink = query(
|
||||
`.chat-message-container[data-id='${defaultChatView.chat_messages[0].id}'] .chat-message-info__flag a`
|
||||
);
|
||||
assert.ok(reviewableLink.href.endsWith("/review/1"));
|
||||
});
|
||||
|
||||
test("Flag button isn't present for DM channel", async function (assert) {
|
||||
await visit("/chat/channel/9/@hawk");
|
||||
await triggerEvent(".chat-message-container", "mouseenter");
|
||||
|
||||
const moreButtons = selectKit(".chat-message-actions .more-buttons");
|
||||
await moreButtons.expand();
|
||||
|
||||
const content = moreButtons.displayedContent();
|
||||
assert.notOk(content.find((row) => row.id === "flag"));
|
||||
});
|
||||
});
|
||||
@@ -1,290 +0,0 @@
|
||||
import showModal from "discourse/lib/show-modal";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
click,
|
||||
currentURL,
|
||||
fillIn,
|
||||
focus,
|
||||
settled,
|
||||
triggerKeyEvent,
|
||||
visit,
|
||||
} from "@ember/test-helpers";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import { KEY_MODIFIER } from "discourse/plugins/chat/discourse/initializers/chat-keyboard-shortcuts";
|
||||
import { test } from "qunit";
|
||||
|
||||
const MODIFIER_OPTIONS =
|
||||
KEY_MODIFIER === "meta" ? { metaKey: true } : { ctrlKey: true };
|
||||
|
||||
acceptance("Discourse Chat - Keyboard shortcuts", function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
// allows to create a staged message
|
||||
server.post("/chat/:id.json", () =>
|
||||
helper.response({
|
||||
errors: [""],
|
||||
})
|
||||
);
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.get("/chat/:chatChannelId/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
server.post("/chat/drafts", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
|
||||
server.get("/chat/chat_channels/search", () => {
|
||||
return helper.response({
|
||||
public_channels: [ChatChannel.create({ id: 3, title: "seventeen" })],
|
||||
direct_message_channels: [
|
||||
ChatChannel.create({
|
||||
id: 4,
|
||||
users: [{ id: 10, username: "someone" }],
|
||||
}),
|
||||
],
|
||||
users: [
|
||||
{ id: 11, username: "smoothies" },
|
||||
{ id: 12, username: "server" },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.hooks.beforeEach(function () {
|
||||
Object.defineProperty(this, "chatService", {
|
||||
get: () => this.container.lookup("service:chat"),
|
||||
});
|
||||
});
|
||||
|
||||
test("channel selector opens channel in float", async function (assert) {
|
||||
await visit("/latest");
|
||||
await showModal("chat-channel-selector-modal");
|
||||
await settled();
|
||||
|
||||
assert.ok(exists("#chat-channel-selector-modal-inner"));
|
||||
|
||||
// All channels should show because the input is blank
|
||||
assert.equal(
|
||||
queryAll("#chat-channel-selector-modal-inner .chat-channel-selection-row")
|
||||
.length,
|
||||
9
|
||||
);
|
||||
|
||||
// Freaking keyup event isn't triggered by fillIn...
|
||||
// Next line manually keyup's "r" to make the keyup event run.
|
||||
// fillIn is needed for `this.filter` but triggerKeyEvent is needed to fire the JS event.
|
||||
await fillIn("#chat-channel-selector-input", "s");
|
||||
await triggerKeyEvent("#chat-channel-selector-input", "keyup", "R");
|
||||
|
||||
// Only 4 channels match this filter now!
|
||||
assert.equal(
|
||||
queryAll("#chat-channel-selector-modal-inner .chat-channel-selection-row")
|
||||
.length,
|
||||
4
|
||||
);
|
||||
|
||||
await triggerKeyEvent(document.body, "keyup", "Enter");
|
||||
|
||||
assert.ok(exists(".chat-drawer.is-expanded"));
|
||||
assert.notOk(exists("#chat-channel-selector-modal-inner"));
|
||||
assert.equal(currentURL(), "/latest");
|
||||
});
|
||||
|
||||
test("the current chat channel does not show in the channel selector list", async function (assert) {
|
||||
await visit("/chat/channel/75/@hawk");
|
||||
await showModal("chat-channel-selector-modal");
|
||||
await settled();
|
||||
|
||||
// All channels minus 1
|
||||
assert.equal(
|
||||
queryAll("#chat-channel-selector-modal-inner .chat-channel-selection-row")
|
||||
.length,
|
||||
8
|
||||
);
|
||||
assert.notOk(
|
||||
exists(
|
||||
"#chat-channel-selector-modal-inner .chat-channel-selection-row.chat-channel-9"
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test("switching channel with alt+arrow keys in full page chat", async function (assert) {
|
||||
this.container.lookup("service:chat").set("chatWindowFullPage", true);
|
||||
await visit("/chat/channel/75/@hawk");
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowDown", {
|
||||
altKey: true,
|
||||
});
|
||||
assert.equal(currentURL(), "/chat/channel/76/eviltrout-markvanlan");
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowDown", {
|
||||
altKey: true,
|
||||
});
|
||||
assert.equal(currentURL(), "/chat/channel/11/another-category");
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowDown", {
|
||||
altKey: true,
|
||||
});
|
||||
assert.equal(currentURL(), "/chat/channel/7/bug");
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowUp", {
|
||||
altKey: true,
|
||||
});
|
||||
assert.equal(currentURL(), "/chat/channel/11/another-category");
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowUp", {
|
||||
altKey: true,
|
||||
});
|
||||
assert.equal(currentURL(), "/chat/channel/76/eviltrout-markvanlan");
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowUp", {
|
||||
altKey: true,
|
||||
});
|
||||
assert.equal(currentURL(), "/chat/channel/75/hawk");
|
||||
});
|
||||
|
||||
test("switching channel with alt+arrow keys in float", async function (assert) {
|
||||
await visit("/latest");
|
||||
await click(".header-dropdown-toggle.open-chat");
|
||||
await click('.chat-channel-row[data-chat-channel-id="4"]');
|
||||
|
||||
assert.ok(exists(`.chat-drawer.is-expanded[data-chat-channel-id="4"]`));
|
||||
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowDown", {
|
||||
altKey: true,
|
||||
});
|
||||
|
||||
assert.ok(exists(`.chat-drawer.is-expanded[data-chat-channel-id="10`));
|
||||
|
||||
await triggerKeyEvent(document.body, "keydown", "ArrowUp", {
|
||||
altKey: true,
|
||||
});
|
||||
assert.ok(exists(`.chat-drawer.is-expanded[data-chat-channel-id="4"]`));
|
||||
});
|
||||
|
||||
test("simple composer formatting shortcuts", async function (assert) {
|
||||
await visit("/latest");
|
||||
await click(".header-dropdown-toggle.open-chat");
|
||||
await click(".chat-channel-row");
|
||||
|
||||
const composerInput = query(".chat-composer-input");
|
||||
await fillIn(composerInput, "test text");
|
||||
await focus(composerInput);
|
||||
composerInput.selectionStart = 0;
|
||||
composerInput.selectionEnd = 9;
|
||||
await triggerKeyEvent(composerInput, "keydown", "B", MODIFIER_OPTIONS);
|
||||
|
||||
assert.strictEqual(
|
||||
composerInput.value,
|
||||
"**test text**",
|
||||
"selection should get the bold markdown"
|
||||
);
|
||||
await fillIn(composerInput, "test text");
|
||||
await focus(composerInput);
|
||||
composerInput.selectionStart = 0;
|
||||
composerInput.selectionEnd = 9;
|
||||
await triggerKeyEvent(composerInput, "keydown", "I", MODIFIER_OPTIONS);
|
||||
|
||||
assert.strictEqual(
|
||||
composerInput.value,
|
||||
"_test text_",
|
||||
"selection should get the italic markdown"
|
||||
);
|
||||
await fillIn(composerInput, "test text");
|
||||
await focus(composerInput);
|
||||
composerInput.selectionStart = 0;
|
||||
composerInput.selectionEnd = 9;
|
||||
await triggerKeyEvent(composerInput, "keydown", "E", MODIFIER_OPTIONS);
|
||||
|
||||
assert.strictEqual(
|
||||
composerInput.value,
|
||||
"`test text`",
|
||||
"selection should get the code markdown"
|
||||
);
|
||||
});
|
||||
|
||||
test("editing last non staged message", async function (assert) {
|
||||
const stagedMessageText = "This is a test";
|
||||
await visit("/latest");
|
||||
|
||||
await click(".header-dropdown-toggle.open-chat");
|
||||
await click(".chat-channel-row");
|
||||
await fillIn(".chat-composer-input", stagedMessageText);
|
||||
await click(".chat-composer-inline-button");
|
||||
await triggerKeyEvent(".chat-composer-input", "keydown", "ArrowUp");
|
||||
|
||||
assert.notEqual(
|
||||
query(".chat-composer-input").value.trim(),
|
||||
stagedMessageText
|
||||
);
|
||||
});
|
||||
|
||||
test("insert link shortcut", async function (assert) {
|
||||
await visit("/latest");
|
||||
|
||||
await click(".header-dropdown-toggle.open-chat");
|
||||
await click(".chat-channel-row");
|
||||
|
||||
await focus(".chat-composer-input");
|
||||
await fillIn(".chat-composer-input", "This is a link to ");
|
||||
await triggerKeyEvent(
|
||||
".chat-composer-input",
|
||||
"keydown",
|
||||
"L",
|
||||
MODIFIER_OPTIONS
|
||||
);
|
||||
assert.ok(exists(".insert-link.modal-body"), "hyperlink modal visible");
|
||||
|
||||
await fillIn(".modal-body .link-url", "google.com");
|
||||
await fillIn(".modal-body .link-text", "Google");
|
||||
await click(".modal-footer button.btn-primary");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-composer-input").value,
|
||||
"This is a link to [Google](https://google.com)",
|
||||
"adds link with url and text, prepends 'https://'"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!exists(".insert-link.modal-body"),
|
||||
"modal dismissed after submitting link"
|
||||
);
|
||||
});
|
||||
|
||||
test("Pressing Escape when full page is opened", async function (assert) {
|
||||
await visit("/chat/channel/75/@hawk");
|
||||
const composerInput = query(".chat-composer-input");
|
||||
await focus(composerInput);
|
||||
await triggerKeyEvent(composerInput, "keydown", "Escape");
|
||||
|
||||
assert.equal(
|
||||
currentURL(),
|
||||
"/chat/channel/75/hawk",
|
||||
"it doesn’t close full page chat"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(".chat-message-container[data-id='177']"),
|
||||
"it doesn’t remove channel content"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -4,7 +4,7 @@ import {
|
||||
exists,
|
||||
visible,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { skip } from "qunit";
|
||||
|
||||
acceptance("Discourse Chat - Chat live pane collapse", function (needs) {
|
||||
needs.user({
|
||||
@@ -106,7 +106,7 @@ acceptance("Discourse Chat - Chat live pane collapse", function (needs) {
|
||||
);
|
||||
});
|
||||
|
||||
test("can collapse and expand youtube chat", async function (assert) {
|
||||
skip("can collapse and expand youtube chat", async function (assert) {
|
||||
const youtubeContainer = ".chat-message-container[data-id='1'] .lazyYT";
|
||||
const expandImage =
|
||||
".chat-message-container[data-id='1'] .chat-message-collapser-closed";
|
||||
@@ -132,7 +132,7 @@ acceptance("Discourse Chat - Chat live pane collapse", function (needs) {
|
||||
assert.notOk(exists(expandImage), "the close arrow is hidden again");
|
||||
});
|
||||
|
||||
test("lightbox shows up before and after expand and collapse", async function (assert) {
|
||||
skip("lightbox shows up before and after expand and collapse", async function (assert) {
|
||||
const lightboxImage = ".mfp-img";
|
||||
const image = ".chat-message-container[data-id='2'] .chat-img-upload";
|
||||
const expandImage =
|
||||
|
||||
@@ -1,93 +0,0 @@
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
|
||||
acceptance("Discourse Chat - Chat live pane mobile", function (needs) {
|
||||
needs.mobileView();
|
||||
needs.user({
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/:chatChannelId/messages.json", () =>
|
||||
helper.response({
|
||||
meta: {
|
||||
can_flag: true,
|
||||
user_silenced: true,
|
||||
},
|
||||
chat_messages: [
|
||||
{
|
||||
id: 1,
|
||||
message: "hi",
|
||||
cooked: "<p>hi</p>",
|
||||
excerpt: "hi",
|
||||
created_at: "2021-07-20T08:14:16.950Z",
|
||||
flag_count: 0,
|
||||
user: {
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/a9a28c/{size}.png",
|
||||
id: 1,
|
||||
name: "Tomtom",
|
||||
username: "tomtom",
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
message: "hi",
|
||||
cooked: "<p>hi</p>",
|
||||
excerpt: "hi",
|
||||
created_at: "2021-07-20T08:14:16.950Z",
|
||||
flag_count: 0,
|
||||
user: {
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/a9a28c/{size}.png",
|
||||
id: 1,
|
||||
name: "Tomtom",
|
||||
username: "tomtom",
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels/:chatChannelId", () =>
|
||||
helper.response({ id: 1, title: "something" })
|
||||
);
|
||||
});
|
||||
|
||||
test("touching message", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
|
||||
const messageExists = (id) => {
|
||||
return exists(
|
||||
`.chat-message-container[data-id='${id}'] .chat-message-selected`
|
||||
);
|
||||
};
|
||||
|
||||
assert.notOk(messageExists(1));
|
||||
assert.notOk(messageExists(2));
|
||||
|
||||
await click(".chat-message-container[data-id='1']");
|
||||
|
||||
assert.notOk(messageExists(1), "it doesn’t select the touched message");
|
||||
});
|
||||
});
|
||||
@@ -1,93 +0,0 @@
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
|
||||
acceptance("Discourse Chat - Chat live pane", function (needs) {
|
||||
needs.user({
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "legacy",
|
||||
});
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/:chatChannelId/messages.json", () =>
|
||||
helper.response({
|
||||
meta: {
|
||||
can_flag: true,
|
||||
user_silenced: true,
|
||||
},
|
||||
chat_messages: [
|
||||
{
|
||||
id: 1,
|
||||
message: "hi",
|
||||
cooked: "<p>hi</p>",
|
||||
excerpt: "hi",
|
||||
created_at: "2021-07-20T08:14:16.950Z",
|
||||
flag_count: 0,
|
||||
user: {
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/a9a28c/{size}.png",
|
||||
id: 1,
|
||||
name: "Tomtom",
|
||||
username: "tomtom",
|
||||
},
|
||||
reactions: {
|
||||
heart: {
|
||||
count: 1,
|
||||
reacted: false,
|
||||
users: [{ id: 99, username: "im-penar" }],
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [
|
||||
{
|
||||
id: 1,
|
||||
title: "something",
|
||||
current_user_membership: { following: true },
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels/:chatChannelId", () =>
|
||||
helper.response({
|
||||
id: 1,
|
||||
title: "something",
|
||||
current_user_membership: { following: true },
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("Textarea and message interactions are disabled when user is silenced", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
assert.equal(query(".chat-composer-input").disabled, true);
|
||||
assert.notOk(exists(".chat-message-actions-container"));
|
||||
assert.notOk(exists(".chat-message-react-btn"));
|
||||
});
|
||||
});
|
||||
@@ -1,190 +1,6 @@
|
||||
import { click, fillIn, tap, triggerEvent, visit } from "@ember/test-helpers";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
publishToMessageBus,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { generateChatView } from "discourse/plugins/chat/chat-fixtures";
|
||||
|
||||
function buildMessage(messageId) {
|
||||
return {
|
||||
id: messageId,
|
||||
message: "hi",
|
||||
cooked: "<p>hi</p>",
|
||||
excerpt: "hi",
|
||||
created_at: "2021-07-20T08:14:16.950Z",
|
||||
flag_count: 0,
|
||||
user: {
|
||||
avatar_template: "/letter_avatar_proxy/v4/letter/t/a9a28c/{size}.png",
|
||||
id: 1,
|
||||
name: "Tomtom",
|
||||
username: "tomtom",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Chat live pane - viewing old messages",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "legacy",
|
||||
});
|
||||
|
||||
let loadAllMessages = false;
|
||||
|
||||
needs.hooks.beforeEach(() => {
|
||||
loadAllMessages = false;
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
const firstPageMessages = [];
|
||||
|
||||
for (let i = 0; i < 50; i++) {
|
||||
firstPageMessages.push(buildMessage(i + 1));
|
||||
}
|
||||
|
||||
server.get("/chat/:chatChannelId/messages.json", () => {
|
||||
if (loadAllMessages) {
|
||||
const updatedPage = [...firstPageMessages];
|
||||
updatedPage.shift();
|
||||
updatedPage.shift();
|
||||
updatedPage.push(buildMessage(51));
|
||||
updatedPage.push(buildMessage(52));
|
||||
|
||||
return helper.response({
|
||||
meta: {
|
||||
can_load_more_future: false,
|
||||
},
|
||||
chat_messages: updatedPage,
|
||||
});
|
||||
} else {
|
||||
return helper.response({
|
||||
meta: {
|
||||
can_flag: true,
|
||||
user_silenced: false,
|
||||
can_load_more_future: true,
|
||||
},
|
||||
chat_messages: firstPageMessages,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [
|
||||
{
|
||||
id: 1,
|
||||
title: "something",
|
||||
current_user_membership: { following: true },
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels/:chatChannelId", () =>
|
||||
helper.response({ id: 1, title: "something" })
|
||||
);
|
||||
|
||||
server.post("/chat/drafts", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
|
||||
server.post("/chat/:chatChannelId.json", () => {
|
||||
return helper.response({ success: "OK" });
|
||||
});
|
||||
});
|
||||
|
||||
test("doesn't create a gap in history by adding new messages", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
|
||||
await publishToMessageBus("/chat/1", {
|
||||
type: "sent",
|
||||
chat_message: {
|
||||
id: 51,
|
||||
cooked: "<p>hello!</p>",
|
||||
user: {
|
||||
id: 2,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.notOk(exists(`.chat-message-container[data-id='${51}']`));
|
||||
});
|
||||
|
||||
test("It continues to handle other message types", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
|
||||
await publishToMessageBus("/chat/1", {
|
||||
action: "add",
|
||||
user: { id: 77, username: "notTomtom" },
|
||||
emoji: "cat",
|
||||
type: "reaction",
|
||||
chat_message_id: 1,
|
||||
});
|
||||
|
||||
assert.ok(exists(`.chat-message-reaction[data-emoji-name="cat"]`));
|
||||
});
|
||||
|
||||
test("Sending a new message when there are still unloaded ones will fetch them", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
|
||||
assert.notOk(exists(`.chat-message-container[data-id='${51}']`));
|
||||
|
||||
loadAllMessages = true;
|
||||
const composerInput = query(".chat-composer-input");
|
||||
await fillIn(composerInput, "test text");
|
||||
await click(".send-btn");
|
||||
|
||||
assert.ok(exists(`.chat-message-container[data-id='${51}']`));
|
||||
assert.ok(exists(`.chat-message-container[data-id='${52}']`));
|
||||
});
|
||||
|
||||
test("Clicking the arrow button jumps to the bottom of the channel", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
|
||||
assert.notOk(exists(`.chat-message-container[data-id='${51}']`));
|
||||
const scrollerEl = document.querySelector(".chat-messages-scroll");
|
||||
scrollerEl.scrollTop = -500; // Scroll up a bit
|
||||
const initialPosition = scrollerEl.scrollTop;
|
||||
await triggerEvent(".chat-messages-scroll", "scroll", {
|
||||
forceShowScrollToBottom: true,
|
||||
});
|
||||
|
||||
loadAllMessages = true;
|
||||
await click(".chat-scroll-to-bottom");
|
||||
|
||||
assert.ok(exists(`.chat-message-container[data-id='${51}']`));
|
||||
assert.ok(exists(`.chat-message-container[data-id='${52}']`));
|
||||
|
||||
assert.ok(
|
||||
scrollerEl.scrollTop > initialPosition,
|
||||
"Scrolled to the bottom"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { skip } from "qunit";
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Chat live pane - handling 429 errors",
|
||||
@@ -238,7 +54,7 @@ acceptance(
|
||||
});
|
||||
});
|
||||
|
||||
test("Handles 429 errors by displaying an alert", async function (assert) {
|
||||
skip("Handles 429 errors by displaying an alert", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
|
||||
assert.ok(exists(".dialog-content"), "We displayed a 429 error");
|
||||
@@ -246,105 +62,3 @@ acceptance(
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Chat live pane - handling 404 errors",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({ chat_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/:chatChannelId/messages.json", () => {
|
||||
return helper.response(404);
|
||||
});
|
||||
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels/:chatChannelId", () =>
|
||||
helper.response({ id: 1, title: "something" })
|
||||
);
|
||||
|
||||
server.get("/chat/lookup/:messageId.json", () => {
|
||||
return helper.response(404);
|
||||
});
|
||||
});
|
||||
|
||||
test("Handles 404 errors by displaying an alert", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
|
||||
assert.ok(exists(".dialog-content"), "it displays a 404 error");
|
||||
await click(".dialog-footer .btn-primary");
|
||||
});
|
||||
|
||||
test("Handles 404 errors with unexisting messageId", async function (assert) {
|
||||
await visit("/chat/channel/1/cat?messageId=2");
|
||||
|
||||
assert.ok(exists(".dialog-content"), "it displays a 404 error");
|
||||
await click(".dialog-footer .btn-primary");
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Chat live pane (mobile) - actions menu",
|
||||
function (needs) {
|
||||
needs.user({ has_chat_enabled: true });
|
||||
|
||||
needs.settings({ chat_enabled: true });
|
||||
|
||||
needs.mobileView();
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/:chatChannelId/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels/:chatChannelId", () =>
|
||||
helper.response({ id: 1, title: "something" })
|
||||
);
|
||||
});
|
||||
|
||||
test("when expanding and collapsing the actions menu", async function (assert) {
|
||||
await visit("/chat/channel/1/cat");
|
||||
const message = query(".chat-message-container");
|
||||
await tap(message);
|
||||
|
||||
assert.ok(exists(".chat-message-actions-backdrop"));
|
||||
|
||||
await tap(".collapse-area");
|
||||
|
||||
assert.notOk(exists(".chat-message-actions-backdrop"));
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
import { test } from "qunit";
|
||||
import { click, fillIn, tap, triggerEvent, visit } from "@ember/test-helpers";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
|
||||
function setupPretenders(server, helper) {
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.get("/chat/:chat_channel_id/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
}
|
||||
|
||||
acceptance("Discourse Chat | bookmarking | desktop", function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
setupPretenders(server, helper);
|
||||
server.post("/bookmarks", () => helper.response({ id: 1, success: "OK" }));
|
||||
});
|
||||
|
||||
test("can bookmark a message with reminder from the quick actions menu", async function (assert) {
|
||||
await visit("/chat/channel/4/public-category");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const message = query(".chat-message-container");
|
||||
|
||||
await triggerEvent(message, "mouseenter");
|
||||
await click(".chat-message-actions .bookmark-btn");
|
||||
assert.ok(
|
||||
exists("#bookmark-reminder-modal"),
|
||||
"it shows the bookmark modal"
|
||||
);
|
||||
await fillIn("input#bookmark-name", "Check this out later");
|
||||
await click("#tap_tile_next_month");
|
||||
assert.ok(
|
||||
message.querySelector(
|
||||
".chat-message-info__bookmark .d-icon-discourse-bookmark-clock"
|
||||
),
|
||||
"the message should be bookmarked and show the icon on the message info"
|
||||
);
|
||||
assert.ok(
|
||||
".chat-message-actions .bookmark-btn .d-icon-discourse-bookmark-clock",
|
||||
"the message actions icon shows the reminder icon"
|
||||
);
|
||||
});
|
||||
|
||||
test("can bookmark a message without reminder from the quick actions menu", async function (assert) {
|
||||
await visit("/chat/channel/4/public-category");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const message = query(".chat-message-container");
|
||||
|
||||
await triggerEvent(message, "mouseenter");
|
||||
await click(".chat-message-actions .bookmark-btn");
|
||||
assert.ok(
|
||||
exists("#bookmark-reminder-modal"),
|
||||
"it shows the bookmark modal"
|
||||
);
|
||||
await fillIn("input#bookmark-name", "Check this out later");
|
||||
await click("#tap_tile_none");
|
||||
assert.ok(
|
||||
exists(".chat-message-info__bookmark .d-icon-bookmark"),
|
||||
"the message should be bookmarked and show the icon on the message info"
|
||||
);
|
||||
assert.ok(
|
||||
exists(".chat-message-actions .bookmark-btn .d-icon-bookmark"),
|
||||
"the message actions icon shows the bookmark icon"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Discourse Chat | bookmarking | mobile", function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
setupPretenders(server, helper);
|
||||
server.post("/bookmarks", () => helper.response({ id: 1, success: "OK" }));
|
||||
});
|
||||
|
||||
needs.mobileView();
|
||||
|
||||
test("can bookmark a message with reminder from the mobile long press menu", async function (assert) {
|
||||
await visit("/chat/channel/4/public-category");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const message = query(".chat-message-container");
|
||||
|
||||
await tap(message);
|
||||
await click(".main-actions .bookmark-btn");
|
||||
|
||||
assert.ok(
|
||||
exists("#bookmark-reminder-modal"),
|
||||
"it shows the bookmark modal"
|
||||
);
|
||||
await fillIn("input#bookmark-name", "Check this out later");
|
||||
await click("#tap_tile_next_month");
|
||||
assert.ok(
|
||||
message.querySelector(
|
||||
".chat-message-info__bookmark .d-icon-discourse-bookmark-clock"
|
||||
),
|
||||
"the message should be bookmarked and show the icon on the message info"
|
||||
);
|
||||
|
||||
await tap(message);
|
||||
assert.ok(
|
||||
exists(".main-actions .bookmark-btn .d-icon-discourse-bookmark-clock"),
|
||||
"the message actions icon shows the reminder icon"
|
||||
);
|
||||
});
|
||||
|
||||
test("can bookmark a message without reminder from the quick actions menu", async function (assert) {
|
||||
await visit("/chat/channel/4/public-category");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const message = query(".chat-message-container");
|
||||
|
||||
await tap(message);
|
||||
await click(".main-actions .bookmark-btn");
|
||||
assert.ok(
|
||||
exists("#bookmark-reminder-modal"),
|
||||
"it shows the bookmark modal"
|
||||
);
|
||||
await fillIn("input#bookmark-name", "Check this out later");
|
||||
await click("#tap_tile_none");
|
||||
assert.ok(
|
||||
message.querySelector(".chat-message-info__bookmark .d-icon-bookmark"),
|
||||
"the message should be bookmarked and show the icon on the message info"
|
||||
);
|
||||
|
||||
await tap(message);
|
||||
assert.ok(
|
||||
exists(".main-actions .bookmark-btn .d-icon-bookmark"),
|
||||
"the message actions icon shows the bookmark icon"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,99 +0,0 @@
|
||||
import {
|
||||
acceptance,
|
||||
loggedInUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, triggerEvent, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
|
||||
function setupPretenders(server, helper) {
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.get("/chat/:chat_channel_id/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.get("/chat/emojis.json", () =>
|
||||
helper.response({ favorites: [{ name: "grinning" }] })
|
||||
);
|
||||
server.put("/chat/:id/react/:message_id.json", helper.response);
|
||||
}
|
||||
|
||||
acceptance("Discourse Chat - Chat Message", function (needs) {
|
||||
needs.user({ has_chat_enabled: true });
|
||||
needs.settings({ chat_enabled: true });
|
||||
needs.pretender((server, helper) => setupPretenders(server, helper));
|
||||
|
||||
test("when reacting to a message using inline reaction", async function (assert) {
|
||||
const emojiReactionStore = this.container.lookup(
|
||||
"service:chat-emoji-reaction-store"
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
this.siteSettings.default_emoji_reactions.split("|")
|
||||
);
|
||||
|
||||
await visit("/chat/channel/4/public-category");
|
||||
await click(
|
||||
`.chat-message-container[data-id="176"] .chat-message-reaction[data-emoji-name="heart"]`
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
["heart"].concat(
|
||||
this.siteSettings.default_emoji_reactions
|
||||
.split("|")
|
||||
.filter((r) => r !== "heart")
|
||||
),
|
||||
"it tracks the emoji"
|
||||
);
|
||||
|
||||
await click(
|
||||
`.chat-message-container[data-id="176"] .chat-message-reaction[data-emoji-name="heart"]`
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
["heart"].concat(
|
||||
this.siteSettings.default_emoji_reactions
|
||||
.split("|")
|
||||
.filter((r) => r !== "heart")
|
||||
),
|
||||
"it doesn’t untrack when removing the reaction"
|
||||
);
|
||||
});
|
||||
|
||||
test("when reacting to a message using emoji picker reaction", async function (assert) {
|
||||
const emojiReactionStore = this.container.lookup(
|
||||
"service:chat-emoji-reaction-store"
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
this.siteSettings.default_emoji_reactions.split("|")
|
||||
);
|
||||
|
||||
await visit("/chat/channel/4/public-category");
|
||||
await triggerEvent(".chat-message-container[data-id='176']", "mouseenter");
|
||||
await click(".chat-message-actions-container .react-btn");
|
||||
await click(`[data-emoji="grinning"]`);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
["grinning"].concat(this.siteSettings.default_emoji_reactions.split("|")),
|
||||
"it tracks the emoji"
|
||||
);
|
||||
|
||||
await click(
|
||||
`.chat-message-container[data-id="176"] .chat-message-reaction[data-emoji-name="grinning"]`
|
||||
);
|
||||
|
||||
assert.deepEqual(
|
||||
emojiReactionStore.favorites,
|
||||
["grinning"].concat(this.siteSettings.default_emoji_reactions.split("|")),
|
||||
"it doesn’t untrack when removing the reaction"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,183 +0,0 @@
|
||||
import { test } from "qunit";
|
||||
import { click, currentURL, triggerEvent, visit } from "@ember/test-helpers";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
|
||||
function setupPretenders(server, helper) {
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
server.put("/chat/4/move_messages_to_channel.json", () => {
|
||||
return helper.response({
|
||||
destination_channel_id: 11,
|
||||
destination_channel_title: "Coolest thing you have seen today",
|
||||
first_moved_message_id: 174,
|
||||
});
|
||||
});
|
||||
server.get("/chat/:chat_channel_id/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.get("/chat/lookup/:messageId.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
}
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat | moving messages to a channel | staff user",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
admin: true,
|
||||
moderator: true,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
setupPretenders(server, helper);
|
||||
});
|
||||
|
||||
test("opens a modal for destination channel selection then redirects to the moved messages when done", async function (assert) {
|
||||
await visit("/chat/channel/4/public-category");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const firstMessage = query(".chat-message-container");
|
||||
await triggerEvent(firstMessage, "mouseenter");
|
||||
const dropdown = selectKit(".chat-message-actions .more-buttons");
|
||||
await dropdown.expand();
|
||||
await dropdown.selectRowByValue("selectMessage");
|
||||
|
||||
assert.ok(firstMessage.classList.contains("selecting-messages"));
|
||||
const moveToChannelBtn = query(
|
||||
".chat-live-pane #chat-move-to-channel-btn"
|
||||
);
|
||||
assert.equal(
|
||||
moveToChannelBtn.disabled,
|
||||
false,
|
||||
"button is enabled as a message is selected"
|
||||
);
|
||||
|
||||
await click(firstMessage.querySelector("input[type='checkbox']"));
|
||||
assert.equal(
|
||||
moveToChannelBtn.disabled,
|
||||
true,
|
||||
"button is disabled when no messages are selected"
|
||||
);
|
||||
|
||||
await click(firstMessage.querySelector("input[type='checkbox']"));
|
||||
await click("#chat-move-to-channel-btn");
|
||||
const modalConfirmMoveButton = query(
|
||||
"#chat-confirm-move-messages-to-channel"
|
||||
);
|
||||
assert.ok(
|
||||
modalConfirmMoveButton.disabled,
|
||||
"cannot confirm move until channel is selected"
|
||||
);
|
||||
const channelChooser = selectKit(".chat-move-message-channel-chooser");
|
||||
await channelChooser.expand();
|
||||
assert.notOk(
|
||||
channelChooser.rowByValue("4").exists(),
|
||||
"the source channel is not in the destination channel selector"
|
||||
);
|
||||
|
||||
await channelChooser.selectRowByValue("11");
|
||||
await click(modalConfirmMoveButton);
|
||||
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
"/chat/channel/11/another-category",
|
||||
"it goes to the destination channel after the move"
|
||||
);
|
||||
});
|
||||
|
||||
test("does not allow moving messages from a direct message channel", async function (assert) {
|
||||
await visit("/chat/channel/75/@hawk");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const firstMessage = query(".chat-message-container");
|
||||
await triggerEvent(firstMessage, "mouseenter");
|
||||
const dropdown = selectKit(".chat-message-actions .more-buttons");
|
||||
await dropdown.expand();
|
||||
await dropdown.selectRowByValue("selectMessage");
|
||||
assert.ok(firstMessage.classList.contains("selecting-messages"));
|
||||
assert.notOk(
|
||||
exists(".chat-live-pane #chat-move-to-channel-btn"),
|
||||
"the move to channel button is not shown in direct message channels"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat | moving messages to a channel | non-staff user",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
setupPretenders(server, helper);
|
||||
server.get("/chat/11/messages.json", () => {
|
||||
return helper.response(
|
||||
generateChatView(loggedInUser(), { can_moderate: true })
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
test("non-staff users cannot see the move to channel button", async function (assert) {
|
||||
await visit("/chat/channel/4/public-category");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const firstMessage = query(".chat-message-container");
|
||||
await triggerEvent(firstMessage, "mouseenter");
|
||||
const dropdown = selectKit(".chat-message-actions .more-buttons");
|
||||
await dropdown.expand();
|
||||
await dropdown.selectRowByValue("selectMessage");
|
||||
|
||||
assert.ok(firstMessage.classList.contains("selecting-messages"));
|
||||
assert.notOk(
|
||||
exists(".chat-live-pane #chat-move-to-channel-btn"),
|
||||
"non-staff users cannot see the move to channel button"
|
||||
);
|
||||
});
|
||||
|
||||
test("non-staff users can see the move to channel button if they can_moderate the channel", async function (assert) {
|
||||
await visit("/chat/channel/11/another-category");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
const firstMessage = query(".chat-message-container");
|
||||
await triggerEvent(firstMessage, "mouseenter");
|
||||
const dropdown = selectKit(
|
||||
`.chat-message-actions-container[data-id="${firstMessage.dataset.id}"] .more-buttons`
|
||||
);
|
||||
await dropdown.expand();
|
||||
await dropdown.selectRowByValue("selectMessage");
|
||||
|
||||
assert.ok(firstMessage.classList.contains("selecting-messages"));
|
||||
assert.ok(
|
||||
exists(".chat-live-pane #chat-move-to-channel-btn"),
|
||||
"non-staff users can see the move to channel button if can_moderate"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,34 +0,0 @@
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import { chatChannels } from "discourse/plugins/chat/chat-fixtures";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { CHAT_SOUNDS } from "discourse/plugins/chat/discourse/services/chat-audio-manager";
|
||||
|
||||
function preferencesPretender(server, helper) {
|
||||
server.get("/u/eviltrout/activity.json", () => helper.response({}));
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
}
|
||||
|
||||
acceptance("Discourse Chat | User Preferences", function (needs) {
|
||||
needs.user({ can_chat: true, has_chat_enabled: true });
|
||||
needs.settings({ chat_enabled: true });
|
||||
needs.pretender(preferencesPretender);
|
||||
|
||||
test("when user has no chat sound set", async function (assert) {
|
||||
const sounds = Object.keys(CHAT_SOUNDS);
|
||||
await visit("/u/eviltrout/preferences/chat");
|
||||
const dropdown = selectKit("#user_chat_sounds");
|
||||
|
||||
assert.strictEqual(dropdown.header().value(), null, "it displays no sound");
|
||||
|
||||
await dropdown.expand();
|
||||
await dropdown.selectRowByValue(sounds[1]);
|
||||
|
||||
assert.strictEqual(
|
||||
dropdown.header().value(),
|
||||
sounds[1],
|
||||
"it selects the sound"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,183 +0,0 @@
|
||||
import { skip, test } from "qunit";
|
||||
import {
|
||||
click,
|
||||
currentURL,
|
||||
tap,
|
||||
triggerEvent,
|
||||
visit,
|
||||
} from "@ember/test-helpers";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
query,
|
||||
visible,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
|
||||
const quoteResponse = {
|
||||
markdown: `[chat quote="martin-chat;3875498;2022-02-04T01:12:15Z" channel="The Beam Discussions" channelId="1234"]
|
||||
an extremely insightful response :)
|
||||
[/chat]`,
|
||||
};
|
||||
|
||||
function setupPretenders(server, helper) {
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.post(`/chat/4/quote.json`, () => helper.response(quoteResponse));
|
||||
server.post(`/chat/7/quote.json`, () => helper.response(quoteResponse));
|
||||
server.get("/chat/:chat_channel_id/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
}
|
||||
|
||||
acceptance("Discourse Chat | Copying messages", function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
setupPretenders(server, helper);
|
||||
});
|
||||
|
||||
test("it copies the quote and shows a message", async function (assert) {
|
||||
await visit("/chat/channel/7/Bug");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
|
||||
const firstMessage = query(".chat-message-container");
|
||||
await triggerEvent(firstMessage, "mouseenter");
|
||||
const dropdown = selectKit(
|
||||
`.chat-message-actions-container[data-id="${firstMessage.dataset.id}"] .more-buttons`
|
||||
);
|
||||
await dropdown.expand();
|
||||
await dropdown.selectRowByValue("selectMessage");
|
||||
assert.ok(firstMessage.classList.contains("selecting-messages"));
|
||||
|
||||
const copyButton = query(".chat-live-pane #chat-copy-btn");
|
||||
assert.equal(
|
||||
copyButton.disabled,
|
||||
false,
|
||||
"button is enabled as a message is selected"
|
||||
);
|
||||
|
||||
await click(firstMessage.querySelector("input[type='checkbox']"));
|
||||
assert.equal(
|
||||
copyButton.disabled,
|
||||
true,
|
||||
"button is disabled when no messages are selected"
|
||||
);
|
||||
|
||||
await click(firstMessage.querySelector("input[type='checkbox']"));
|
||||
await click("#chat-copy-btn");
|
||||
assert.ok(exists(".chat-selection-message"), "shows the message");
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Discourse Chat | Quoting in composer", async function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
setupPretenders(server, helper);
|
||||
});
|
||||
|
||||
skip("it opens the composer for the topic and pastes in the quote", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
|
||||
await click(".header-dropdown-toggle.open-chat");
|
||||
assert.ok(visible(".chat-drawer-container"), "chat drawer is open");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
|
||||
const firstMessage = query(".chat-message-container");
|
||||
await triggerEvent(firstMessage, "mouseenter");
|
||||
const dropdown = selectKit(".chat-message-container .more-buttons");
|
||||
await dropdown.expand();
|
||||
await dropdown.selectRowByValue("selectMessage");
|
||||
assert.ok(firstMessage.classList.contains("selecting-messages"));
|
||||
|
||||
await click("#chat-quote-btn");
|
||||
assert.ok(exists("#reply-control.composer-action-reply"));
|
||||
assert.strictEqual(
|
||||
query(".composer-action-title .action-title").innerText,
|
||||
"Internationalization / localization"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query("textarea.d-editor-input").value,
|
||||
quoteResponse.markdown
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Discourse Chat | Quoting on mobile", async function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
setupPretenders(server, helper);
|
||||
});
|
||||
|
||||
needs.mobileView();
|
||||
|
||||
skip("it opens the chatable, opens the composer, and pastes the markdown in", async function (assert) {
|
||||
await visit("/chat/channel/7/Bug");
|
||||
assert.ok(exists(".chat-message-container"));
|
||||
|
||||
const firstMessage = query(".chat-message-container");
|
||||
await tap(firstMessage);
|
||||
await click(".chat-message-action-item[data-id='selectMessage'] button");
|
||||
assert.ok(firstMessage.classList.contains("selecting-messages"));
|
||||
|
||||
await click("#chat-quote-btn");
|
||||
|
||||
assert.equal(currentURL(), "/c/bug/1", "navigates to the chatable url");
|
||||
assert.ok(
|
||||
exists("#reply-control.composer-action-createTopic"),
|
||||
"the composer opens"
|
||||
);
|
||||
assert.strictEqual(
|
||||
query("textarea.d-editor-input").value,
|
||||
quoteResponse.markdown,
|
||||
"the composer has the markdown"
|
||||
);
|
||||
assert.strictEqual(
|
||||
selectKit(".category-chooser").header().value(),
|
||||
"1",
|
||||
"it fills category selector with the right category"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,127 +0,0 @@
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
publishToMessageBus,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
|
||||
acceptance("Discourse Chat - Sidebar - User Status", function (needs) {
|
||||
const directMessageUserId = 1;
|
||||
const status = { description: "off to dentist", emoji: "tooth" };
|
||||
|
||||
needs.user({ has_chat_enabled: true });
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "sidebar",
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
const directMessageChannel = {
|
||||
chatable: {
|
||||
users: [
|
||||
{
|
||||
id: directMessageUserId,
|
||||
username: "user1",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/f9ae1b/{size}.png",
|
||||
status,
|
||||
},
|
||||
],
|
||||
},
|
||||
chatable_type: "DirectMessage",
|
||||
title: "@user1",
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
};
|
||||
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [directMessageChannel],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Shows user status", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
const statusEmoji = query(
|
||||
".sidebar-sections .sidebar-section-link-content-text .emoji"
|
||||
);
|
||||
assert.ok(statusEmoji, "status is shown");
|
||||
assert.ok(
|
||||
statusEmoji.src.includes(status.emoji),
|
||||
"status emoji is correct"
|
||||
);
|
||||
assert.equal(
|
||||
statusEmoji.title,
|
||||
status.description,
|
||||
"status description is correct"
|
||||
);
|
||||
});
|
||||
|
||||
test("Status gets updated after receiving a message bus update", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
let statusEmoji = query(
|
||||
".sidebar-sections .sidebar-section-link-content-text .emoji"
|
||||
);
|
||||
assert.ok(statusEmoji, "old status is shown");
|
||||
assert.ok(
|
||||
statusEmoji.src.includes(status.emoji),
|
||||
"old status emoji is correct"
|
||||
);
|
||||
assert.equal(
|
||||
statusEmoji.title,
|
||||
status.description,
|
||||
"old status description is correct"
|
||||
);
|
||||
|
||||
const newStatus = { description: "surfing", emoji: "surfer" };
|
||||
await publishToMessageBus(`/user-status`, {
|
||||
[directMessageUserId]: newStatus,
|
||||
});
|
||||
|
||||
statusEmoji = query(
|
||||
".sidebar-sections .sidebar-section-link-content-text .emoji"
|
||||
);
|
||||
assert.ok(statusEmoji, "new status is shown");
|
||||
assert.ok(
|
||||
statusEmoji.src.includes(newStatus.emoji),
|
||||
"new status emoji is correct"
|
||||
);
|
||||
assert.equal(
|
||||
statusEmoji.title,
|
||||
newStatus.description,
|
||||
"new status description is correct"
|
||||
);
|
||||
});
|
||||
|
||||
test("Status disappears after receiving a message bus update", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
let statusEmoji = query(
|
||||
".sidebar-sections .sidebar-section-link-content-text .emoji"
|
||||
);
|
||||
assert.ok(statusEmoji, "old status is shown");
|
||||
|
||||
await publishToMessageBus(`/user-status`, { [directMessageUserId]: null });
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-sections .sidebar-section-link-content-text .emoji"),
|
||||
"status has disappeared"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,111 +0,0 @@
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
publishToMessageBus,
|
||||
query,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import I18n from "I18n";
|
||||
import { test } from "qunit";
|
||||
|
||||
const baseChatPretenders = (server, helper) => {
|
||||
server.get("/chat/:chatChannelId/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.post("/chat/:chatChannelId.json", () => {
|
||||
return helper.response({ success: "OK" });
|
||||
});
|
||||
server.get("/chat/lookup/:messageId.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
let copy = cloneJSON(chatChannels);
|
||||
let modifiedChannel = copy.public_channels.find((pc) => pc.id === 4);
|
||||
modifiedChannel.current_user_membership.unread_count = 2;
|
||||
return helper.response(copy);
|
||||
});
|
||||
|
||||
// this is only fetched on channel-status change; when expanding on
|
||||
// this test we may want to introduce some counter to track when
|
||||
// this is fetched if we want to return different statuses
|
||||
server.get("/chat/chat_channels/4", () => {
|
||||
let channel = cloneJSON(
|
||||
chatChannels.public_channels.find((pc) => pc.id === 4)
|
||||
);
|
||||
channel.status = "archived";
|
||||
return helper.response(channel);
|
||||
});
|
||||
};
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Respond to /chat/channel-status archive message",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
admin: true,
|
||||
moderator: true,
|
||||
username: "tomtom",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
chat_allow_archiving_channels: true,
|
||||
navigation_menu: "legacy",
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
baseChatPretenders(server, helper);
|
||||
});
|
||||
|
||||
test("it clears any unread messages in the sidebar for the archived channel", async function (assert) {
|
||||
await visit("/chat/channel/4/public-category");
|
||||
assert.ok(
|
||||
exists(
|
||||
'.chat-channel-row[data-chat-channel-id="4"] .chat-channel-unread-indicator'
|
||||
),
|
||||
"unread indicator shows for channel"
|
||||
);
|
||||
|
||||
await publishToMessageBus("/chat/channel-status", {
|
||||
chat_channel_id: 4,
|
||||
status: "archived",
|
||||
});
|
||||
assert.notOk(
|
||||
exists(
|
||||
'.chat-channel-row[data-chat-channel-id="4"] .chat-channel-unread-indicator'
|
||||
),
|
||||
"unread indicator should not show after archive status change"
|
||||
);
|
||||
});
|
||||
|
||||
test("it changes the channel status in the header to archived", async function (assert) {
|
||||
await visit("/chat/channel/4/Topic");
|
||||
|
||||
assert.notOk(
|
||||
exists(".chat-channel-title-with-status .chat-channel-status"),
|
||||
"channel status does not show if the channel is open"
|
||||
);
|
||||
|
||||
await publishToMessageBus("/chat/channel-status", {
|
||||
chat_channel_id: 4,
|
||||
status: "archived",
|
||||
});
|
||||
assert.strictEqual(
|
||||
query(".chat-channel-status").innerText.trim(),
|
||||
I18n.t("chat.channel_status.archived_header"),
|
||||
"channel status changes to archived"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,597 +0,0 @@
|
||||
import PrettyText, { buildOptions } from "pretty-text/pretty-text";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
import I18n from "I18n";
|
||||
import topicFixtures from "discourse/tests/fixtures/topic";
|
||||
import { cloneJSON, deepMerge } from "discourse-common/lib/object";
|
||||
import QUnit, { test } from "qunit";
|
||||
|
||||
import { click, fillIn, visit } from "@ember/test-helpers";
|
||||
import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
const rawOpts = {
|
||||
siteSettings: {
|
||||
enable_emoji: true,
|
||||
enable_emoji_shortcuts: true,
|
||||
enable_mentions: true,
|
||||
emoji_set: "twitter",
|
||||
external_emoji_url: "",
|
||||
highlighted_languages: "json|ruby|javascript",
|
||||
default_code_lang: "auto",
|
||||
enable_markdown_linkify: true,
|
||||
markdown_linkify_tlds: "com",
|
||||
chat_enabled: true,
|
||||
},
|
||||
getURL: (url) => url,
|
||||
};
|
||||
|
||||
function cookMarkdown(input, opts) {
|
||||
const merged = deepMerge({}, rawOpts, opts);
|
||||
return new PrettyText(buildOptions(merged)).cook(input);
|
||||
}
|
||||
|
||||
QUnit.assert.cookedChatTranscript = function (input, opts, expected, message) {
|
||||
const actual = cookMarkdown(input, opts);
|
||||
this.pushResult({
|
||||
result: actual === expected,
|
||||
actual,
|
||||
expected,
|
||||
message,
|
||||
});
|
||||
};
|
||||
|
||||
function generateTranscriptHTML(messageContent, opts) {
|
||||
const channelDataAttr = opts.channel
|
||||
? ` data-channel-name=\"${opts.channel}\"`
|
||||
: "";
|
||||
const channelIdDataAttr = opts.channelId
|
||||
? ` data-channel-id=\"${opts.channelId}\"`
|
||||
: "";
|
||||
const reactDataAttr = opts.reactions
|
||||
? ` data-reactions=\"${opts.reactionsAttr}\"`
|
||||
: "";
|
||||
|
||||
let tabIndexHTML = opts.linkTabIndex ? ' tabindex="-1"' : "";
|
||||
|
||||
let transcriptClasses = ["chat-transcript"];
|
||||
if (opts.chained) {
|
||||
transcriptClasses.push("chat-transcript-chained");
|
||||
}
|
||||
|
||||
const transcript = [];
|
||||
transcript.push(
|
||||
`<div class=\"${transcriptClasses.join(" ")}\" data-message-id=\"${
|
||||
opts.messageId
|
||||
}\" data-username=\"${opts.username}\" data-datetime=\"${
|
||||
opts.datetime
|
||||
}\"${reactDataAttr}${channelDataAttr}${channelIdDataAttr}>`
|
||||
);
|
||||
|
||||
if (opts.channel && opts.multiQuote) {
|
||||
let originallySent = I18n.t("chat.quote.original_channel", {
|
||||
channel: opts.channel,
|
||||
channelLink: `/chat/channel/${opts.channelId}/-`,
|
||||
});
|
||||
if (opts.linkTabIndex) {
|
||||
originallySent = originallySent.replace(">", tabIndexHTML + ">");
|
||||
}
|
||||
transcript.push(`<div class=\"chat-transcript-meta\">
|
||||
${originallySent}</div>`);
|
||||
}
|
||||
|
||||
const dateTimeText = opts.showDateTimeText
|
||||
? moment
|
||||
.tz(opts.datetime, opts.timezone)
|
||||
.format(I18n.t("dates.long_no_year"))
|
||||
: "";
|
||||
|
||||
const innerDatetimeEl =
|
||||
opts.noLink || !opts.channelId
|
||||
? `<span title=\"${opts.datetime}\">${dateTimeText}</span>`
|
||||
: `<a href=\"/chat/channel/${opts.channelId}/-?messageId=${opts.messageId}\" title=\"${opts.datetime}\"${tabIndexHTML}>${dateTimeText}</a>`;
|
||||
transcript.push(`<div class=\"chat-transcript-user\">
|
||||
<div class=\"chat-transcript-user-avatar\"></div>
|
||||
<div class=\"chat-transcript-username\">
|
||||
${opts.username}</div>
|
||||
<div class=\"chat-transcript-datetime\">
|
||||
${innerDatetimeEl}</div>`);
|
||||
|
||||
if (opts.channel && !opts.multiQuote) {
|
||||
transcript.push(
|
||||
`<a class=\"chat-transcript-channel\" href="/chat/channel/${opts.channelId}/-"${tabIndexHTML}>
|
||||
#${opts.channel}</a></div>`
|
||||
);
|
||||
} else {
|
||||
transcript.push("</div>");
|
||||
}
|
||||
|
||||
let messageHtml = `<div class=\"chat-transcript-messages\">\n${messageContent}`;
|
||||
|
||||
if (opts.reactions) {
|
||||
let reactionsHtml = [`<div class=\"chat-transcript-reactions\">\n`];
|
||||
opts.reactions.forEach((react) => {
|
||||
reactionsHtml.push(
|
||||
`<div class=\"chat-transcript-reaction\">\n${emojiUnescape(
|
||||
`:${react.emoji}:`,
|
||||
{ lazy: true }
|
||||
).replace(/'/g, '"')} ${react.usernames.length}</div>\n`
|
||||
);
|
||||
});
|
||||
reactionsHtml.push(`</div>\n`);
|
||||
messageHtml += reactionsHtml.join("");
|
||||
}
|
||||
transcript.push(`${messageHtml}</div>`);
|
||||
transcript.push("</div>");
|
||||
return transcript.join("\n");
|
||||
}
|
||||
|
||||
// these are both set by the plugin with Site.markdown_additional_options which we can't really
|
||||
// modify the response for here, source of truth are consts in ChatMessage::MARKDOWN_FEATURES
|
||||
// and ChatMessage::MARKDOWN_IT_RULES
|
||||
function buildAdditionalOptions() {
|
||||
return {
|
||||
chat: {
|
||||
limited_pretty_text_features: [
|
||||
"anchor",
|
||||
"bbcode-block",
|
||||
"bbcode-inline",
|
||||
"code",
|
||||
"category-hashtag",
|
||||
"censored",
|
||||
"discourse-local-dates",
|
||||
"emoji",
|
||||
"emojiShortcuts",
|
||||
"inlineEmoji",
|
||||
"html-img",
|
||||
"mentions",
|
||||
"onebox",
|
||||
"text-post-process",
|
||||
"upload-protocol",
|
||||
"watched-words",
|
||||
"table",
|
||||
"spoiler-alert",
|
||||
],
|
||||
limited_pretty_text_markdown_rules: [
|
||||
"autolink",
|
||||
"list",
|
||||
"backticks",
|
||||
"newline",
|
||||
"code",
|
||||
"fence",
|
||||
"table",
|
||||
"linkify",
|
||||
"link",
|
||||
"strikethrough",
|
||||
"blockquote",
|
||||
"emphasis",
|
||||
],
|
||||
hashtag_configurations: {
|
||||
"chat-composer": ["channel", "category", "tag"],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
acceptance("Discourse Chat | chat-transcript", function (needs) {
|
||||
let additionalOptions = buildAdditionalOptions();
|
||||
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: false,
|
||||
has_chat_enabled: false,
|
||||
timezone: "Australia/Brisbane",
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
emoji_set: "twitter",
|
||||
});
|
||||
|
||||
test("works with a minimal quote bbcode block", function (assert) {
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML("<p>This is a chat message.</p>", {
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
timezone: "Australia/Brisbane",
|
||||
}),
|
||||
"renders the chat message with the required CSS classes and attributes"
|
||||
);
|
||||
});
|
||||
|
||||
test("renders the channel name if provided with multiQuote", function (assert) {
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z" channel="Cool Cats Club" channelId="1234" multiQuote="true"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML("<p>This is a chat message.</p>", {
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
channel: "Cool Cats Club",
|
||||
channelId: "1234",
|
||||
multiQuote: true,
|
||||
timezone: "Australia/Brisbane",
|
||||
}),
|
||||
"renders the chat transcript with the channel name included above the user and datetime"
|
||||
);
|
||||
});
|
||||
|
||||
test("renders the channel name if provided without multiQuote", function (assert) {
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z" channel="Cool Cats Club" channelId="1234"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML("<p>This is a chat message.</p>", {
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
channel: "Cool Cats Club",
|
||||
channelId: "1234",
|
||||
timezone: "Australia/Brisbane",
|
||||
}),
|
||||
"renders the chat transcript with the channel name included next to the datetime"
|
||||
);
|
||||
});
|
||||
|
||||
test("renders with the chained attribute for more compact quotes", function (assert) {
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z" channel="Cool Cats Club" channelId="1234" multiQuote="true" chained="true"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML("<p>This is a chat message.</p>", {
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
channel: "Cool Cats Club",
|
||||
channelId: "1234",
|
||||
multiQuote: true,
|
||||
chained: true,
|
||||
timezone: "Australia/Brisbane",
|
||||
}),
|
||||
"renders with the chained attribute"
|
||||
);
|
||||
});
|
||||
|
||||
test("renders with the noLink attribute to remove the links to the individual messages from the datetimes", function (assert) {
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z" channel="Cool Cats Club" channelId="1234" multiQuote="true" noLink="true"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML("<p>This is a chat message.</p>", {
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
channel: "Cool Cats Club",
|
||||
channelId: "1234",
|
||||
multiQuote: true,
|
||||
noLink: true,
|
||||
timezone: "Australia/Brisbane",
|
||||
}),
|
||||
"renders with the noLink attribute"
|
||||
);
|
||||
});
|
||||
|
||||
test("renders with the reactions attribute", function (assert) {
|
||||
const reactionsAttr = "+1:martin;heart:martin,eviltrout";
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z" channel="Cool Cats Club" channelId="1234" reactions="${reactionsAttr}"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML("<p>This is a chat message.</p>", {
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
channel: "Cool Cats Club",
|
||||
channelId: "1234",
|
||||
timezone: "Australia/Brisbane",
|
||||
reactionsAttr,
|
||||
reactions: [
|
||||
{ emoji: "+1", usernames: ["martin"] },
|
||||
{ emoji: "heart", usernames: ["martin", "eviltrout"] },
|
||||
],
|
||||
}),
|
||||
"renders with the reaction data attribute and HTML"
|
||||
);
|
||||
});
|
||||
|
||||
test("renders with minimal markdown rules inside the quote bbcode block, same as server-side chat messages", function (assert) {
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="johnsmith;450;2021-04-25T05:40:39Z"]
|
||||
[quote="martin, post:3, topic:6215"]
|
||||
another cool reply
|
||||
[/quote]
|
||||
[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML(
|
||||
`<p>[quote="martin, post:3, topic:6215"]<br>
|
||||
another cool reply<br>
|
||||
[/quote]</p>`,
|
||||
{
|
||||
messageId: "450",
|
||||
username: "johnsmith",
|
||||
datetime: "2021-04-25T05:40:39Z",
|
||||
timezone: "Australia/Brisbane",
|
||||
}
|
||||
),
|
||||
"does not render the markdown feature that has been excluded"
|
||||
);
|
||||
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z"]\nThis ~~does work~~ with removed _rules_.\n\n* list item 1\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML(
|
||||
`<p>This <s>does work</s> with removed <em>rules</em>.</p>
|
||||
<ul>
|
||||
<li>list item 1</li>
|
||||
</ul>`,
|
||||
{
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
timezone: "Australia/Brisbane",
|
||||
}
|
||||
),
|
||||
"renders correctly when the rule has not been excluded"
|
||||
);
|
||||
|
||||
additionalOptions.chat.limited_pretty_text_markdown_rules = [
|
||||
"autolink",
|
||||
// "list",
|
||||
"backticks",
|
||||
"newline",
|
||||
"code",
|
||||
"fence",
|
||||
"table",
|
||||
"linkify",
|
||||
"link",
|
||||
// "strikethrough",
|
||||
"blockquote",
|
||||
// "emphasis",
|
||||
];
|
||||
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z"]\nThis ~~does work~~ with removed _rules_.\n\n* list item 1\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML(
|
||||
`<p>This ~~does work~~ with removed _rules_.</p>
|
||||
<p>* list item 1</p>`,
|
||||
{
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
timezone: "Australia/Brisbane",
|
||||
}
|
||||
),
|
||||
"renders correctly with some obvious rules excluded (list/strikethrough/emphasis)"
|
||||
);
|
||||
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z"]\nhere is a message :P with category hashtag #test\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML(
|
||||
`<p>here is a message <img src=\"/images/emoji/twitter/stuck_out_tongue.png?v=12\" title=\":stuck_out_tongue:\" class=\"emoji\" alt=\":stuck_out_tongue:\" loading=\"lazy\" width=\"20\" height=\"20\"> with category hashtag <span class=\"hashtag\">#test</span></p>`,
|
||||
{
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
timezone: "Australia/Brisbane",
|
||||
}
|
||||
),
|
||||
"renders correctly when the feature has not been excluded"
|
||||
);
|
||||
|
||||
additionalOptions.chat.limited_pretty_text_features = [
|
||||
"anchor",
|
||||
"bbcode-block",
|
||||
"bbcode-inline",
|
||||
"code",
|
||||
// "category-hashtag",
|
||||
"censored",
|
||||
"discourse-local-dates",
|
||||
"emoji",
|
||||
// "emojiShortcuts",
|
||||
"inlineEmoji",
|
||||
"html-img",
|
||||
"mentions",
|
||||
"onebox",
|
||||
"text-post-process",
|
||||
"upload-protocolrouter.location.setURL",
|
||||
"watched-words",
|
||||
"table",
|
||||
"spoiler-alert",
|
||||
];
|
||||
|
||||
assert.cookedChatTranscript(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z"]\nhere is a message :P with category hashtag #test\n[/chat]`,
|
||||
{ additionalOptions },
|
||||
generateTranscriptHTML(
|
||||
`<p>here is a message :P with category hashtag #test</p>`,
|
||||
{
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
timezone: "Australia/Brisbane",
|
||||
}
|
||||
),
|
||||
"renders correctly with some obvious features excluded (category-hashtag, emojiShortcuts)"
|
||||
);
|
||||
|
||||
assert.cookedChatTranscript(
|
||||
`This ~~does work~~ with removed _rules_.
|
||||
|
||||
* list item 1
|
||||
|
||||
here is a message :P with category hashtag #test
|
||||
|
||||
[chat quote="martin;2321;2022-01-25T05:40:39Z"]
|
||||
This ~~does work~~ with removed _rules_.
|
||||
|
||||
* list item 1
|
||||
|
||||
here is a message :P with category hashtag #test
|
||||
[/chat]`,
|
||||
{ additionalOptions },
|
||||
`<p>This <s>does work</s> with removed <em>rules</em>.</p>
|
||||
<ul>
|
||||
<li>list item 1</li>
|
||||
</ul>
|
||||
<p>here is a message <img src=\"/images/emoji/twitter/stuck_out_tongue.png?v=12\" title=\":stuck_out_tongue:\" class=\"emoji\" alt=\":stuck_out_tongue:\" loading=\"lazy\" width=\"20\" height=\"20\"> with category hashtag <span class=\"hashtag\">#test</span></p>\n` +
|
||||
generateTranscriptHTML(
|
||||
`<p>This ~~does work~~ with removed _rules_.</p>
|
||||
<p>* list item 1</p>
|
||||
<p>here is a message :P with category hashtag #test</p>`,
|
||||
{
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
timezone: "Australia/Brisbane",
|
||||
}
|
||||
),
|
||||
"the rule changes do not apply outside the BBCode [chat] block"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat | chat-transcript date decoration",
|
||||
function (needs) {
|
||||
let additionalOptions = buildAdditionalOptions();
|
||||
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
timezone: "Australia/Brisbane",
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const topicResponse = cloneJSON(topicFixtures["/t/280/1.json"]);
|
||||
const firstPost = topicResponse.post_stream.posts[0];
|
||||
const postCooked = cookMarkdown(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions }
|
||||
);
|
||||
firstPost.cooked += postCooked;
|
||||
|
||||
server.get("/t/280.json", () => helper.response(topicResponse));
|
||||
});
|
||||
|
||||
test("chat transcript datetimes are formatted into the link with decorateCookedElement", async function (assert) {
|
||||
await visit("/t/-/280");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".chat-transcript-datetime span").innerText.trim(),
|
||||
moment
|
||||
.tz("2022-01-25T05:40:39Z", "Australia/Brisbane")
|
||||
.format(I18n.t("dates.long_no_year")),
|
||||
"it decorates the chat transcript datetime link with a formatted date"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - chat-transcript - Composer Oneboxes ",
|
||||
function (needs) {
|
||||
let additionalOptions = buildAdditionalOptions();
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
timezone: "Australia/Brisbane",
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
enable_markdown_linkify: true,
|
||||
max_oneboxes_per_post: 2,
|
||||
});
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const topicResponse = cloneJSON(topicFixtures["/t/280/1.json"]);
|
||||
const firstPost = topicResponse.post_stream.posts[0];
|
||||
const postCooked = cookMarkdown(
|
||||
`[chat quote="martin;2321;2022-01-25T05:40:39Z"]\nThis is a chat message.\n[/chat]`,
|
||||
{ additionalOptions }
|
||||
);
|
||||
firstPost.cooked += postCooked;
|
||||
|
||||
server.get("/t/280.json", () => helper.response(topicResponse));
|
||||
});
|
||||
|
||||
test("Preview should not error for oneboxes within [chat] bbcode", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click("#topic-footer-buttons .btn.create");
|
||||
|
||||
await fillIn(
|
||||
".d-editor-input",
|
||||
`
|
||||
[chat quote="martin;2321;2022-01-25T05:40:39Z" channel="Cool Cats Club" channelId="1234" multiQuote="true"]
|
||||
http://www.example.com/has-title.html
|
||||
[/chat]`
|
||||
);
|
||||
|
||||
const rendered = generateTranscriptHTML(
|
||||
'<p><aside class="onebox"><article class="onebox-body"><h3><a href="http://www.example.com/article.html" tabindex="-1">An interesting article</a></h3></article></aside></p>',
|
||||
{
|
||||
messageId: "2321",
|
||||
username: "martin",
|
||||
datetime: "2022-01-25T05:40:39Z",
|
||||
channel: "Cool Cats Club",
|
||||
channelId: "1234",
|
||||
multiQuote: true,
|
||||
linkTabIndex: true,
|
||||
showDateTimeText: true,
|
||||
timezone: "Australia/Brisbane",
|
||||
}
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".d-editor-preview").innerHTML.trim(),
|
||||
rendered.trim(),
|
||||
"it renders correctly with the onebox inside the [chat] bbcode"
|
||||
);
|
||||
|
||||
const textarea = query("#reply-control .d-editor-input");
|
||||
await fillIn(".d-editor-input", textarea.value + "\nA");
|
||||
assert.ok(
|
||||
query(".d-editor-preview").innerHTML.trim().includes("\n<p>A</p>"),
|
||||
"it does not error with a opts.discourse.hoisted error in the markdown pipeline when typing more text"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,252 +0,0 @@
|
||||
import I18n from "I18n";
|
||||
import { test } from "qunit";
|
||||
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
queryAll,
|
||||
updateCurrentUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
|
||||
import {
|
||||
baseChatPretenders,
|
||||
chatChannelPretender,
|
||||
} from "../helpers/chat-pretenders";
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - experiment user menu notifications - user cannot chat",
|
||||
function (needs) {
|
||||
needs.user({ has_chat_enabled: false });
|
||||
needs.settings({ chat_enabled: false });
|
||||
|
||||
test("chat notifications tab is not displayed in user menu", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
||||
assert.notOk(
|
||||
exists("#user-menu-button-chat-notifications"),
|
||||
"button for chat notifications tab is not displayed"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - experimental user menu notifications ",
|
||||
function (needs) {
|
||||
needs.user({ redesigned_user_menu_enabled: true, has_chat_enabled: true });
|
||||
needs.settings({ chat_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
baseChatPretenders(server, helper);
|
||||
chatChannelPretender(server, helper);
|
||||
});
|
||||
|
||||
test("chat notifications tab", async function (assert) {
|
||||
updateCurrentUser({
|
||||
grouped_unread_notifications: {
|
||||
29: 3, // chat_mention notification type
|
||||
31: 1, // chat_invitation notification type
|
||||
},
|
||||
});
|
||||
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
||||
assert.ok(
|
||||
exists("#user-menu-button-chat-notifications"),
|
||||
"button for chat notifications tab is displayed"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists("#user-menu-button-chat-notifications .d-icon-comment"),
|
||||
"displays the comment icon for chat notification tab button"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query("#user-menu-button-chat-notifications .badge-notification")
|
||||
.textContent,
|
||||
"4",
|
||||
"displays the right badge count for chat notifications tab button"
|
||||
);
|
||||
});
|
||||
|
||||
test("chat mention notification link", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
||||
const chatMentionNotificationLink = queryAll(".chat-mention a")[0];
|
||||
|
||||
assert.strictEqual(
|
||||
chatMentionNotificationLink.textContent
|
||||
.trim()
|
||||
.replace(/\n/g, "")
|
||||
.replace(/\s+/, " "),
|
||||
'hawk mentioned you in "Site"',
|
||||
"displays the right text for notification"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(chatMentionNotificationLink.querySelector(".d-icon-comment")),
|
||||
"displays the right icon for the notification"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
chatMentionNotificationLink.title,
|
||||
I18n.t("notifications.titles.chat_mention"),
|
||||
"has the right title attribute for notification link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
chatMentionNotificationLink.href.endsWith(
|
||||
"/chat/channel/9/site?messageId=174"
|
||||
),
|
||||
"has the right href attribute for notification link"
|
||||
);
|
||||
});
|
||||
|
||||
test("personal chat mention notification link", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
||||
const personalChatMentionNotificationLink =
|
||||
queryAll(".chat-mention a")[3];
|
||||
|
||||
assert.strictEqual(
|
||||
personalChatMentionNotificationLink.textContent
|
||||
.trim()
|
||||
.replace(/\n/g, "")
|
||||
.replace(/\s+/, " "),
|
||||
"hawk mentioned you in personal chat",
|
||||
"displays the right text for notification"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
personalChatMentionNotificationLink.querySelector(".d-icon-comment")
|
||||
),
|
||||
"displays the right icon for the notification"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
personalChatMentionNotificationLink.title,
|
||||
I18n.t("notifications.titles.chat_mention"),
|
||||
"has the right title attribute for notification link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
personalChatMentionNotificationLink.href.endsWith(
|
||||
"/chat/channel/9/site?messageId=174"
|
||||
),
|
||||
"has the right href attribute for notification link"
|
||||
);
|
||||
});
|
||||
|
||||
test("chat group mention notification link", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
||||
const chatGroupMentionNotificationLink = queryAll(".chat-mention a")[1];
|
||||
|
||||
assert.strictEqual(
|
||||
chatGroupMentionNotificationLink.textContent
|
||||
.trim()
|
||||
.replace(/\n/g, "")
|
||||
.replace(/\s+/, " "),
|
||||
'hawk mentioned @engineers in "Site"',
|
||||
"displays the right text for notification"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
chatGroupMentionNotificationLink.querySelector(".d-icon-comment")
|
||||
),
|
||||
"displays the right icon for the notification"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
chatGroupMentionNotificationLink.title,
|
||||
I18n.t("notifications.titles.chat_mention"),
|
||||
"has the right title attribute for notification link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
chatGroupMentionNotificationLink.href.endsWith(
|
||||
"/chat/channel/9/site?messageId=174"
|
||||
),
|
||||
"has the right href attribute for notification link"
|
||||
);
|
||||
});
|
||||
|
||||
test("chat all mention notification link", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
||||
const chatAllMentionNotificationLink = queryAll(".chat-mention a")[2];
|
||||
|
||||
assert.strictEqual(
|
||||
chatAllMentionNotificationLink.textContent
|
||||
.trim()
|
||||
.replace(/\n/g, "")
|
||||
.replace(/\s+/, " "),
|
||||
'hawk mentioned @all in "Site"',
|
||||
"displays the right text for notification"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(chatAllMentionNotificationLink.querySelector(".d-icon-comment")),
|
||||
"displays the right icon for the notification"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
chatAllMentionNotificationLink.title,
|
||||
I18n.t("notifications.titles.chat_mention"),
|
||||
"has the right title attribute for notification link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
chatAllMentionNotificationLink.href.endsWith(
|
||||
"/chat/channel/9/site?messageId=174"
|
||||
),
|
||||
"has the right href attribute for notification link"
|
||||
);
|
||||
});
|
||||
|
||||
test("chat invite notification link", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.current-user");
|
||||
|
||||
const chatInviteNotificationLink = queryAll(".chat-invitation a")[0];
|
||||
|
||||
assert.strictEqual(
|
||||
chatInviteNotificationLink.textContent
|
||||
.trim()
|
||||
.replace(/\n/g, "")
|
||||
.replace(/\s+/, " "),
|
||||
"hawk invited you to join a chat channel",
|
||||
"displays the right text for notification"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(chatInviteNotificationLink.querySelector(".d-icon-link")),
|
||||
"displays the right icon for the notification"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
chatInviteNotificationLink.title,
|
||||
I18n.t("notifications.titles.chat_invitation"),
|
||||
"has the right title attribute for notification link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
chatInviteNotificationLink.href.endsWith(
|
||||
"/chat/channel/9/site?messageId=174"
|
||||
),
|
||||
"has the right href attribute for notification link"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,68 +0,0 @@
|
||||
import { setCaretPosition } from "discourse/lib/utilities";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { skip } from "qunit";
|
||||
import { chatChannelPretender } from "../helpers/chat-pretenders";
|
||||
import { fillIn, settled, triggerKeyEvent, visit } from "@ember/test-helpers";
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Composer hashtag autocompletion",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 100,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
needs.pretender((server, helper) => {
|
||||
chatChannelPretender(server, helper);
|
||||
server.get("/chat/:id/messages.json", () =>
|
||||
helper.response({ chat_messages: [], meta: {} })
|
||||
);
|
||||
server.post("/chat/drafts", () => helper.response(500, {}));
|
||||
server.get("/hashtags/search.json", () => {
|
||||
return helper.response({
|
||||
results: [
|
||||
{ type: "category", text: "Design", slug: "design", ref: "design" },
|
||||
{ type: "tag", text: "dev", slug: "dev", ref: "dev" },
|
||||
{ type: "tag", text: "design", slug: "design", ref: "design::tag" },
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
enable_experimental_hashtag_autocomplete: true,
|
||||
});
|
||||
|
||||
skip("using # in the chat composer shows category and tag autocomplete options", async function (assert) {
|
||||
await visit("/chat/channel/11/-");
|
||||
const composerInput = query(".chat-composer-input");
|
||||
await fillIn(".chat-composer-input", "abc #");
|
||||
await triggerKeyEvent(".chat-composer-input", "keydown", "#");
|
||||
await fillIn(".chat-composer-input", "abc #");
|
||||
await setCaretPosition(composerInput, 5);
|
||||
await triggerKeyEvent(".chat-composer-input", "keyup", "#");
|
||||
await triggerKeyEvent(".chat-composer-input", "keydown", "D");
|
||||
await fillIn(".chat-composer-input", "abc #d");
|
||||
await setCaretPosition(composerInput, 6);
|
||||
await triggerKeyEvent(".chat-composer-input", "keyup", "D");
|
||||
await settled();
|
||||
assert.ok(
|
||||
exists(".hashtag-autocomplete"),
|
||||
"hashtag autocomplete menu appears"
|
||||
);
|
||||
assert.strictEqual(
|
||||
queryAll(".hashtag-autocomplete__option").length,
|
||||
3,
|
||||
"all options should be shown"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,777 +0,0 @@
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
query,
|
||||
queryAll,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { click, currentURL, settled, visit } from "@ember/test-helpers";
|
||||
import { directMessageChannels } from "discourse/plugins/chat/chat-fixtures";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
import I18n from "I18n";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import { emojiUnescape } from "discourse/lib/text";
|
||||
import User from "discourse/models/user";
|
||||
|
||||
acceptance("Discourse Chat - Core Sidebar", function (needs) {
|
||||
needs.user({ has_chat_enabled: true });
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "sidebar",
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
let directChannels = cloneJSON(directMessageChannels).mapBy("chat_channel");
|
||||
directChannels[0].chatable.users = [directChannels[0].chatable.users[0]];
|
||||
directChannels[0].current_user_membership.unread_count = 1;
|
||||
directChannels.push({
|
||||
chatable: {
|
||||
users: [
|
||||
{
|
||||
id: 1,
|
||||
username: "markvanlan",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/f9ae1b/{size}.png",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: "sam",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/f9ae1b/{size}.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
chatable_id: 59,
|
||||
chatable_type: "DirectMessage",
|
||||
chatable_url: null,
|
||||
id: 76,
|
||||
title: "@sam",
|
||||
last_message_sent_at: "2021-06-01T11:15:00.000Z",
|
||||
current_user_membership: {
|
||||
unread_count: 0,
|
||||
muted: true,
|
||||
following: true,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
});
|
||||
directChannels.push({
|
||||
chatable: {
|
||||
users: [
|
||||
{
|
||||
id: 1,
|
||||
username: "<script>markvanlan</script>",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/f9ae1b/{size}.png",
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
username: "<script>sam</script>",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/f9ae1b/{size}.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
chatable_type: "DirectMessage",
|
||||
chatable_url: null,
|
||||
id: 77,
|
||||
title: "@<script>sam</script>",
|
||||
last_message_sent_at: "2021-06-01T11:15:00.000Z",
|
||||
current_user_membership: {
|
||||
unread_count: 0,
|
||||
muted: false,
|
||||
following: true,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
});
|
||||
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [
|
||||
{
|
||||
id: 1,
|
||||
title: "dev :bug:",
|
||||
chatable_type: "Category",
|
||||
chatable: { slug: "dev", read_restricted: true },
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
unread_count: 0,
|
||||
unread_mentions: 0,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "general",
|
||||
chatable_type: "Category",
|
||||
chatable: { slug: "general" },
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
unread_count: 1,
|
||||
unread_mentions: 0,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "random",
|
||||
description: "The channel for random <script>evil</script> things",
|
||||
chatable_type: "Category",
|
||||
chatable: { slug: "random" },
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
muted: true,
|
||||
unread_count: 1,
|
||||
unread_mentions: 1,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 4,
|
||||
title: "<script>evil</script>",
|
||||
chatable_type: "Category",
|
||||
chatable: { slug: "random" },
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
unread_count: 1,
|
||||
unread_mentions: 1,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
direct_message_channels: directChannels,
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/chat/1/messages.json", () =>
|
||||
helper.response({
|
||||
meta: {
|
||||
can_chat: true,
|
||||
user_silenced: false,
|
||||
channel_message_bus_last_id: 0,
|
||||
},
|
||||
chat_messages: [],
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/u/search/users", () => {
|
||||
return helper.response({
|
||||
users: [
|
||||
{
|
||||
username: "hawk",
|
||||
id: 2,
|
||||
name: "hawk",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v4/letter/t/41988e/{size}.png",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/chat/75/messages.json", () =>
|
||||
helper.response({
|
||||
meta: { can_chat: true, user_silenced: false },
|
||||
chat_messages: [],
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/direct_messages.json", () => {
|
||||
return helper.response({
|
||||
chat_channel: {
|
||||
id: 75,
|
||||
title: "hawk",
|
||||
chatable_type: "DirectMessage",
|
||||
last_message_sent_at: "2021-07-20T08:14:16.950Z",
|
||||
chatable: {
|
||||
users: [{ username: "hawk" }],
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
needs.hooks.beforeEach(function () {
|
||||
withPluginApi("1.3.0", (api) => {
|
||||
api.addUsernameSelectorDecorator((username) => {
|
||||
if (username === "hawk") {
|
||||
return `<span class="on-holiday">${emojiUnescape(
|
||||
":desert_island:"
|
||||
)}</span>`;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Public channels section", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".sidebar-section-chat-channels .sidebar-section-header-text"
|
||||
).textContent.trim(),
|
||||
I18n.t("chat.chat_channels"),
|
||||
"displays correct channels section title"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-dev-bug .sidebar-section-link-prefix svg.prefix-icon.d-icon-hashtag"
|
||||
),
|
||||
"dev channel section link displays hash icon prefix"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-dev-bug .sidebar-section-link-prefix svg.prefix-badge.d-icon-lock"
|
||||
),
|
||||
"dev channel section link displays lock badge for restricted channel"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-dev-bug .emoji"
|
||||
),
|
||||
"unescapes emoji in channel title in the link"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-dev-bug"
|
||||
).textContent.trim(),
|
||||
"dev",
|
||||
"dev channel section link displays channel title in the link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
query(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-dev-bug"
|
||||
).href.endsWith("/chat/channel/1/dev-bug"),
|
||||
"dev channel section link has the right href attribute"
|
||||
);
|
||||
|
||||
assert.notOk(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-dev-bug .sidebar-section-link-suffix"
|
||||
),
|
||||
"does not display new messages indicator"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-general .sidebar-section-link-prefix svg.prefix-icon.d-icon-hashtag"
|
||||
),
|
||||
"general channel section link displays hash icon prefix"
|
||||
);
|
||||
|
||||
assert.notOk(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-general .sidebar-section-link-prefix svg.prefix-badge"
|
||||
),
|
||||
"general channel section link does not display lock badge for public channel"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-general"
|
||||
).textContent.trim(),
|
||||
"general",
|
||||
"general channel section link displays channel title in the link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-general .sidebar-section-link-suffix.unread"
|
||||
),
|
||||
"general section link has new messages indicator"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-random .sidebar-section-link-prefix svg.prefix-icon.d-icon-hashtag"
|
||||
),
|
||||
"random channel section link displays hash icon prefix"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-random"
|
||||
).textContent.trim(),
|
||||
"random",
|
||||
"random channel section link displays channel title in the link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-random .sidebar-section-link-suffix.urgent"
|
||||
),
|
||||
"random section link has new messages mention indicator"
|
||||
);
|
||||
});
|
||||
|
||||
test("sidebar section link when direct message channel is muted by user", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-dms .sidebar-section-link-sam.sidebar-section-link--muted"
|
||||
),
|
||||
"muted direct chat channel section link has right classname configured"
|
||||
);
|
||||
});
|
||||
|
||||
test("sidebar section link when public channel is muted by user", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.ok(
|
||||
exists(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-random.sidebar-section-link--muted"
|
||||
),
|
||||
"muted random chat channel section link has right classname configured"
|
||||
);
|
||||
});
|
||||
|
||||
test("Direct messages section", async function (assert) {
|
||||
const chatService = this.container.lookup("service:chat");
|
||||
chatService.directMessagesLimit = 2;
|
||||
await visit("/");
|
||||
|
||||
assert.strictEqual(
|
||||
query(
|
||||
".sidebar-section-chat-dms .sidebar-section-header-text"
|
||||
).textContent.trim(),
|
||||
I18n.t("chat.direct_messages.title"),
|
||||
"displays correct direct messages section title"
|
||||
);
|
||||
|
||||
let directLinks = queryAll(
|
||||
".sidebar-section-chat-dms a.sidebar-section-link"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
directLinks[0]
|
||||
.querySelector(".sidebar-section-link-prefix img")
|
||||
.classList.contains("prefix-image"),
|
||||
true,
|
||||
"displays avatar in prefix when two participants"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
directLinks[0].textContent.trim(),
|
||||
"hawk",
|
||||
"displays user name in a link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
directLinks[0].querySelector(
|
||||
".sidebar-section-link-content-text .on-holiday img"
|
||||
),
|
||||
"displays flair when user is on holiday"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
directLinks[0]
|
||||
.querySelector(".sidebar-section-link-suffix")
|
||||
.classList.contains("urgent"),
|
||||
true,
|
||||
"displays new messages indicator"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
directLinks[1]
|
||||
.querySelector("span.sidebar-section-link-prefix")
|
||||
.classList.contains("text"),
|
||||
true,
|
||||
"displays text in prefix when more than two participants"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
directLinks[1]
|
||||
.querySelector(".sidebar-section-link-content-text")
|
||||
.textContent.trim(),
|
||||
"eviltrout, markvanlan",
|
||||
"displays all participants name in a link"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
!directLinks[1].querySelector(".sidebar-section-link-suffix"),
|
||||
"does not display new messages indicator"
|
||||
);
|
||||
User.current().chat_channel_tracking_state[76].set("unread_count", 99);
|
||||
chatService.reSortDirectMessageChannels();
|
||||
chatService.appEvents.trigger("chat:user-tracking-state-changed");
|
||||
await settled();
|
||||
|
||||
directLinks = queryAll(".sidebar-section-chat-dms a.sidebar-section-link");
|
||||
assert.strictEqual(
|
||||
directLinks[0]
|
||||
.querySelector(".sidebar-section-link-content-text")
|
||||
.textContent.trim(),
|
||||
"eviltrout, markvanlan",
|
||||
"reorders private messages"
|
||||
);
|
||||
|
||||
assert.equal(
|
||||
directLinks.length,
|
||||
2,
|
||||
"limits number of displayed direct messages"
|
||||
);
|
||||
});
|
||||
|
||||
test("Plugin sidebar is hidden", async function (assert) {
|
||||
await visit("/chat/channel/1/dev");
|
||||
assert.notOk(exists(".full-page-chat .channels-list"));
|
||||
});
|
||||
|
||||
test("Open a new direct conversation", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".sidebar-section-chat-dms .sidebar-section-header-button");
|
||||
|
||||
assert.ok(exists(".direct-message-creator"));
|
||||
assert.ok(exists(".chat-drawer.is-expanded"));
|
||||
assert.strictEqual(currentURL(), "/");
|
||||
});
|
||||
|
||||
test("Escaped channel description used as title when present", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
const randomChannel = queryAll(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-wrapper .sidebar-section-link"
|
||||
)[3];
|
||||
|
||||
assert.strictEqual(
|
||||
randomChannel.title,
|
||||
"The channel for random <script>evil</script> things"
|
||||
);
|
||||
});
|
||||
|
||||
test("Escapes public channel titles", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
const evilChannel = query(
|
||||
".sidebar-section-chat-channels .sidebar-section-link-wrapper .sidebar-section-link"
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
evilChannel.title,
|
||||
"<script>evil</script> chat"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
evilChannel.className.includes(
|
||||
"sidebar-section-link-ltscriptgtevilltscriptgt"
|
||||
)
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
evilChannel
|
||||
.querySelector(".sidebar-section-link-content-text")
|
||||
.innerHTML.trim(),
|
||||
"<script>evil</script>"
|
||||
);
|
||||
});
|
||||
|
||||
test("Escapes dm channel titles", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
const evilChannel = queryAll(
|
||||
".sidebar-section-chat-dms .sidebar-section-link-wrapper .sidebar-section-link"
|
||||
)[3];
|
||||
|
||||
assert.strictEqual(
|
||||
evilChannel.title,
|
||||
"Chat with @<script>sam</script>"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
evilChannel.className.includes(
|
||||
"sidebar-section-link-ltscriptgtsamltscriptgt"
|
||||
)
|
||||
);
|
||||
|
||||
assert.strictEqual(
|
||||
evilChannel
|
||||
.querySelector(".sidebar-section-link-content-text")
|
||||
.innerHTML.trim(),
|
||||
"&lt;script&gt;sam&lt;/script&gt;"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance("Discourse Chat - Plugin Sidebar", function (needs) {
|
||||
needs.user({ has_chat_enabled: true });
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "legacy",
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [
|
||||
{
|
||||
id: 1,
|
||||
title: "dev :bug:",
|
||||
chatable_type: "Category",
|
||||
chatable: { slug: "dev", read_restricted: true },
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
unread_count: 1,
|
||||
unread_mentions: 1,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 2,
|
||||
title: "general",
|
||||
chatable_type: "Category",
|
||||
chatable: { slug: "general" },
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
unread_count: 1,
|
||||
unread_mentions: 1,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
title: "random",
|
||||
chatable_type: "Category",
|
||||
chatable: { slug: "random" },
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
unread_count: 1,
|
||||
unread_mentions: 1,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/chat/1/messages.json", () =>
|
||||
helper.response({
|
||||
meta: { can_chat: true, user_silenced: false },
|
||||
chat_messages: [],
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
test("Plugin sidebar is visible", async function (assert) {
|
||||
await visit("/chat/channel/1/dev");
|
||||
assert.ok(exists(".full-page-chat .channels-list"));
|
||||
});
|
||||
});
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Core Sidebar - no joinable public channels, staff",
|
||||
function (needs) {
|
||||
needs.user({ has_chat_enabled: true, has_joinable_public_channels: false });
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "sidebar",
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Chat channels section visibility", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.ok(
|
||||
exists(".sidebar-section-chat-channels"),
|
||||
"it shows the section for staff"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Core Sidebar - no joinable public channels, regular user",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
has_chat_enabled: true,
|
||||
has_joinable_public_channels: false,
|
||||
moderator: false,
|
||||
admin: false,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "sidebar",
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Chat channels section visibility", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-section-chat-channels"),
|
||||
"it doesn’t show the section for regular user"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Core Sidebar - regular user with no direct message channels who cannot send direct messages",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
has_chat_enabled: true,
|
||||
moderator: false,
|
||||
admin: false,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "sidebar",
|
||||
direct_message_enabled_groups: "13", // trust_level_3 auto group ID;
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Direct message channels section visibility", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-section-chat-dms"),
|
||||
"it doesn’t show the section for regular user"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Core Sidebar - regular user with existing direct message channels who cannot send direct messages",
|
||||
function (needs) {
|
||||
needs.user({
|
||||
has_chat_enabled: true,
|
||||
moderator: false,
|
||||
admin: false,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
navigation_menu: "sidebar",
|
||||
direct_message_enabled_groups: "13", // trust_level_3 auto group ID;
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
let directChannels = cloneJSON(directMessageChannels).mapBy(
|
||||
"chat_channel"
|
||||
);
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: directChannels,
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test("Direct message channels section visibility", async function (assert) {
|
||||
await visit("/");
|
||||
|
||||
assert.ok(
|
||||
exists(".sidebar-section-chat-dms"),
|
||||
"it does show the section for a regular user"
|
||||
);
|
||||
|
||||
assert.notOk(
|
||||
exists(".sidebar-section-chat-dms .sidebar-section-header-button"),
|
||||
"user cannot see the create DM channel button"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,186 +0,0 @@
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import { acceptance, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
|
||||
acceptance("Discourse Chat - Create channel modal", function (needs) {
|
||||
const maliciousText = '"<script></script>';
|
||||
|
||||
needs.user({
|
||||
username: "tomtom",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
const catsCategory = {
|
||||
id: 1,
|
||||
name: "Cats",
|
||||
slug: "cats",
|
||||
permission: 1,
|
||||
};
|
||||
|
||||
needs.site({
|
||||
categories: [
|
||||
catsCategory,
|
||||
{
|
||||
id: 2,
|
||||
name: maliciousText,
|
||||
slug: maliciousText,
|
||||
permission: 1,
|
||||
},
|
||||
{
|
||||
id: 3,
|
||||
name: "Kittens",
|
||||
slug: "kittens",
|
||||
permission: 1,
|
||||
parentCategory: catsCategory,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/:chatChannelId/messages.json", () =>
|
||||
helper.response({
|
||||
meta: { can_chat: true, user_silenced: false },
|
||||
chat_messages: [],
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels.json", () =>
|
||||
helper.response({
|
||||
public_channels: [],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
server.get("/chat/chat_channels/:chatChannelId", () =>
|
||||
helper.response({ id: 1, title: "something" })
|
||||
);
|
||||
|
||||
server.get("/chat/api/chat_channels.json", () => helper.response([]));
|
||||
|
||||
server.get(
|
||||
"/chat/api/category-chatables/:categoryId/permissions.json",
|
||||
(request) => {
|
||||
if (request.params.categoryId === "2") {
|
||||
return helper.response({
|
||||
allowed_groups: ["@<script>evilgroup</script>"],
|
||||
members_count: 2,
|
||||
private: true,
|
||||
});
|
||||
} else {
|
||||
return helper.response({
|
||||
allowed_groups: ["@awesomeGroup"],
|
||||
members_count: 2,
|
||||
private: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
test("links to categories and selected category's security settings", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
await click(".new-channel-btn");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint a").innerText,
|
||||
"category security settings"
|
||||
);
|
||||
assert.ok(query(".create-channel-hint a").href.includes("/categories"));
|
||||
|
||||
let categories = selectKit(".create-channel-modal .category-chooser");
|
||||
await categories.expand();
|
||||
await categories.selectRowByName("Cats");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint a").innerText,
|
||||
"security settings"
|
||||
);
|
||||
assert.ok(
|
||||
query(".create-channel-hint a").href.includes("/c/cats/edit/security")
|
||||
);
|
||||
});
|
||||
|
||||
test("links to selected category's security settings works with nested subcategories", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
await click(".new-channel-btn");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint a").innerText,
|
||||
"category security settings"
|
||||
);
|
||||
assert.ok(query(".create-channel-hint a").href.includes("/categories"));
|
||||
|
||||
let categories = selectKit(".create-channel-modal .category-chooser");
|
||||
await categories.expand();
|
||||
await categories.selectRowByName("Kittens");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint a").innerText,
|
||||
"security settings"
|
||||
);
|
||||
assert.ok(
|
||||
query(".create-channel-hint a").href.includes(
|
||||
"/c/cats/kittens/edit/security"
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
test("includes group names in the hint", async (assert) => {
|
||||
await visit("/chat/browse");
|
||||
await click(".new-channel-btn");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint a").innerText,
|
||||
"category security settings"
|
||||
);
|
||||
assert.ok(query(".create-channel-hint a").href.includes("/categories"));
|
||||
|
||||
let categories = selectKit(".create-channel-modal .category-chooser");
|
||||
await categories.expand();
|
||||
await categories.selectRowByName("Kittens");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint").innerHTML.trim(),
|
||||
'Users in @awesomeGroup will have access to this channel per the <a href="/c/cats/kittens/edit/security" target="_blank">security settings</a>'
|
||||
);
|
||||
});
|
||||
|
||||
test("escapes group name/category slug in the hint", async (assert) => {
|
||||
await visit("/chat/browse");
|
||||
await click(".new-channel-btn");
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint a").innerText,
|
||||
"category security settings"
|
||||
);
|
||||
assert.ok(query(".create-channel-hint a").href.includes("/categories"));
|
||||
|
||||
const categories = selectKit(".create-channel-modal .category-chooser");
|
||||
await categories.expand();
|
||||
await categories.selectRowByValue(2);
|
||||
|
||||
assert.strictEqual(
|
||||
query(".create-channel-hint").innerHTML.trim(),
|
||||
'Users in @<script>evilgroup</script> will have access to this channel per the <a href="/c/"<script></script>/edit/security" target="_blank">security settings</a>'
|
||||
);
|
||||
assert.ok(
|
||||
query(".create-channel-hint a").href.includes(
|
||||
"c/%22%3Cscript%3E%3C/script%3E/edit/security"
|
||||
)
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
import { acceptance } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, currentURL, fillIn, visit } from "@ember/test-helpers";
|
||||
import { test } from "qunit";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
|
||||
acceptance("Discourse Chat - delete chat channel modal", function (needs) {
|
||||
needs.user({ has_chat_enabled: true, can_chat: true });
|
||||
|
||||
needs.settings({ chat_enabled: true });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [fabricators.chatChannel({ id: 2 })],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.get("/chat/chat_channels/:id", (request) => {
|
||||
return helper.response(
|
||||
fabricators.chatChannel({ id: request.params.id })
|
||||
);
|
||||
});
|
||||
|
||||
server.get("/chat/:id/messages.json", () => {
|
||||
return helper.response({ meta: {}, chat_messages: [] });
|
||||
});
|
||||
|
||||
server.delete("/chat/chat_channels/:id.json", () => {
|
||||
return helper.response({});
|
||||
});
|
||||
});
|
||||
|
||||
test("Redirection after deleting a channel", async function (assert) {
|
||||
await visit("chat/channel/1/my-category-title/info/settings");
|
||||
await click(".delete-btn");
|
||||
await fillIn("#channel-delete-confirm-name", "My category title");
|
||||
await click("#chat-confirm-delete-channel");
|
||||
|
||||
assert.equal(currentURL(), "/chat/channel/2/my-category-title");
|
||||
});
|
||||
});
|
||||
@@ -1,75 +0,0 @@
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, currentURL, visit } from "@ember/test-helpers";
|
||||
import {
|
||||
chatChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
import { test } from "qunit";
|
||||
|
||||
acceptance("Discourse Chat - Mobile test", function (needs) {
|
||||
needs.user({ can_chat: true, has_chat_enabled: true });
|
||||
|
||||
needs.mobileView();
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.get("/chat/:id/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.get("/u/search/users", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
|
||||
server.get("/chat/api/chat_channels.json", () => {
|
||||
const channels = [];
|
||||
return helper.response(channels);
|
||||
});
|
||||
});
|
||||
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
test("Chat index route shows channels list", async function (assert) {
|
||||
await visit("/latest");
|
||||
await click(".header-dropdown-toggle.open-chat");
|
||||
assert.equal(currentURL(), "/chat");
|
||||
assert.ok(exists(".channels-list"));
|
||||
await click('.chat-channel-row[data-chat-channel-id="7"]');
|
||||
assert.notOk(exists(".open-drawer-btn"));
|
||||
});
|
||||
|
||||
test("Chat new personal chat buttons", async function (assert) {
|
||||
await visit("/chat");
|
||||
await click(".open-draft-channel-page-btn.btn-floating");
|
||||
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
"/chat/draft-channel",
|
||||
"Clicking the floating + button opens the new chat screen"
|
||||
);
|
||||
|
||||
await click(".chat-draft-header__btn");
|
||||
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
"/chat",
|
||||
"Clicking the left arrow button returns to the channels list"
|
||||
);
|
||||
});
|
||||
|
||||
test("Chat browse screen back button", async function (assert) {
|
||||
await visit("/chat/browse");
|
||||
await click(".chat-full-page-header__back-btn");
|
||||
|
||||
assert.strictEqual(
|
||||
currentURL(),
|
||||
"/chat",
|
||||
"Clicking the back button returns to the channels list"
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -1,113 +0,0 @@
|
||||
import userFixtures from "discourse/tests/fixtures/user-fixtures";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
import {
|
||||
acceptance,
|
||||
exists,
|
||||
loggedInUser,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click, visit } from "@ember/test-helpers";
|
||||
import {
|
||||
chatChannels,
|
||||
directMessageChannels,
|
||||
generateChatView,
|
||||
} from "discourse/plugins/chat/chat-fixtures";
|
||||
import { test } from "qunit";
|
||||
|
||||
acceptance("Discourse Chat - User card test", function (needs) {
|
||||
needs.user({
|
||||
admin: false,
|
||||
moderator: false,
|
||||
username: "eviltrout",
|
||||
id: 1,
|
||||
can_chat: true,
|
||||
has_chat_enabled: true,
|
||||
});
|
||||
needs.pretender((server, helper) => {
|
||||
server.post("/uploads/lookup-urls", () => {
|
||||
return helper.response([]);
|
||||
});
|
||||
server.get("/chat/chat_channels.json", () => helper.response(chatChannels));
|
||||
server.get("/chat/chat_channels/:channelId.json", () =>
|
||||
helper.response(helper.response(directMessageChannels[0]))
|
||||
);
|
||||
server.get("/chat/:chatChannelId/messages.json", () =>
|
||||
helper.response(generateChatView(loggedInUser()))
|
||||
);
|
||||
server.post("/chat/direct_messages/create.json", () => {
|
||||
return helper.response({
|
||||
chat_channel: {
|
||||
chat_channels: [],
|
||||
chatable: {
|
||||
users: [
|
||||
{
|
||||
username: "hawk",
|
||||
id: 2,
|
||||
name: "hawk",
|
||||
avatar_template:
|
||||
"/letter_avatar_proxy/v3/letter/t/41988e/{size}.png",
|
||||
},
|
||||
],
|
||||
},
|
||||
chatable_id: 16,
|
||||
chatable_type: "DirectMessage",
|
||||
chatable_url: null,
|
||||
id: 75,
|
||||
title: "@hawk",
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
last_read_message_id: null,
|
||||
unread_count: 0,
|
||||
unread_mentions: 0,
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
let cardResponse = cloneJSON(userFixtures["/u/charlie/card.json"]);
|
||||
cardResponse.user.can_chat_user = true;
|
||||
server.get("/u/hawk/card.json", () => helper.response(cardResponse));
|
||||
});
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
needs.hooks.beforeEach(function () {
|
||||
Object.defineProperty(this, "chatService", {
|
||||
get: () => this.container.lookup("service:chat"),
|
||||
});
|
||||
Object.defineProperty(this, "appEvents", {
|
||||
get: () => this.container.lookup("service:appEvents"),
|
||||
});
|
||||
});
|
||||
|
||||
test("user card has chat button that opens the correct channel", async function (assert) {
|
||||
await visit("/");
|
||||
await click(".header-dropdown-toggle.open-chat");
|
||||
await click('.chat-channel-row[data-chat-channel-id="9"]');
|
||||
await click("[data-user-card='hawk']");
|
||||
|
||||
assert.ok(exists(".user-card-chat-btn"));
|
||||
|
||||
await click(".user-card-chat-btn");
|
||||
|
||||
assert.ok(exists(`.chat-drawer.is-expanded[data-chat-channel-id="75"]`));
|
||||
});
|
||||
});
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat - Anon user viewing user card test",
|
||||
function (needs) {
|
||||
needs.settings({
|
||||
chat_enabled: true,
|
||||
});
|
||||
|
||||
test("user card has no chat button", async function (assert) {
|
||||
await visit("/t/internationalization-localization/280");
|
||||
await click('a[data-user-card="charlie"]');
|
||||
|
||||
assert.notOk(
|
||||
exists(".user-card-chat-btn"),
|
||||
"anon user should not be able to chat with anyone via the user card"
|
||||
);
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,149 +0,0 @@
|
||||
import { setupRenderingTest } from "discourse/tests/helpers/component-test";
|
||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import { render, settled } from "@ember/test-helpers";
|
||||
import { module, test } from "qunit";
|
||||
import I18n from "I18n";
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-about-view | admin user",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({ chatable_type: "Category" })
|
||||
);
|
||||
this.channel.set("description", "foo");
|
||||
this.currentUser.set("admin", true);
|
||||
this.currentUser.set("has_chat_enabled", true);
|
||||
this.siteSettings.chat_enabled = true;
|
||||
});
|
||||
|
||||
test("chatable name", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.equal(
|
||||
query(".category-name").innerText,
|
||||
this.channel.chatable.name
|
||||
);
|
||||
});
|
||||
|
||||
test("chatable description", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.equal(
|
||||
query(".category-name").innerText,
|
||||
this.channel.chatable.name
|
||||
);
|
||||
|
||||
this.channel.set("description", null);
|
||||
await settled();
|
||||
|
||||
assert.equal(
|
||||
query(".channel-info-about-view__description__helper-text").innerText,
|
||||
I18n.t("chat.channel_edit_description_modal.description")
|
||||
);
|
||||
});
|
||||
|
||||
test("edit title", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.ok(exists(".edit-title-btn"));
|
||||
});
|
||||
|
||||
test("edit description", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.ok(exists(".edit-description-btn"));
|
||||
});
|
||||
|
||||
test("join", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.ok(exists(".toggle-channel-membership-button.-join"));
|
||||
});
|
||||
|
||||
test("leave", async function (assert) {
|
||||
this.channel.current_user_membership.set("following", true);
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.ok(exists(".toggle-channel-membership-button.-leave"));
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-about-view | regular user",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
hooks.beforeEach(function () {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({ chatable_type: "Category" })
|
||||
);
|
||||
this.channel.set("description", "foo");
|
||||
this.currentUser.set("has_chat_enabled", true);
|
||||
this.siteSettings.chat_enabled = true;
|
||||
});
|
||||
|
||||
test("escapes channel title", async function (assert) {
|
||||
this.channel.set("title", "<div class='xss'>evil</div>");
|
||||
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.notOk(exists(".xss"));
|
||||
});
|
||||
|
||||
test("chatable name", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.equal(
|
||||
query(".category-name").innerText,
|
||||
this.channel.chatable.name
|
||||
);
|
||||
});
|
||||
|
||||
test("chatable description", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.equal(
|
||||
query(".category-name").innerText,
|
||||
this.channel.chatable.name
|
||||
);
|
||||
|
||||
this.channel.set("description", null);
|
||||
await settled();
|
||||
|
||||
assert.notOk(exists(".channel-info-about-view__description"));
|
||||
});
|
||||
|
||||
test("edit title", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.notOk(exists(".edit-title-btn"));
|
||||
});
|
||||
|
||||
test("edit description", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.notOk(exists(".edit-description-btn"));
|
||||
});
|
||||
|
||||
test("join", async function (assert) {
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.ok(exists(".toggle-channel-membership-button.-join"));
|
||||
});
|
||||
|
||||
test("leave", async function (assert) {
|
||||
this.channel.current_user_membership.set("following", true);
|
||||
await render(hbs`{{chat-channel-about-view channel=channel}}`);
|
||||
|
||||
assert.ok(exists(".toggle-channel-membership-button.-leave"));
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -48,8 +48,8 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
||||
});
|
||||
|
||||
test("Muted channel", async function (assert) {
|
||||
this.channel.current_user_membership.set("muted", true);
|
||||
this.channel.current_user_membership.set("following", true);
|
||||
this.channel.currentUserMembership.muted = true;
|
||||
this.channel.currentUserMembership.following = true;
|
||||
await render(hbs`{{chat-channel-card channel=channel}}`);
|
||||
|
||||
assert.equal(
|
||||
@@ -59,7 +59,7 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
||||
});
|
||||
|
||||
test("Joined channel", async function (assert) {
|
||||
this.channel.current_user_membership.set("following", true);
|
||||
this.channel.currentUserMembership.set("following", true);
|
||||
await render(hbs`{{chat-channel-card channel=channel}}`);
|
||||
|
||||
assert.equal(
|
||||
@@ -77,7 +77,7 @@ module("Discourse Chat | Component | chat-channel-card", function (hooks) {
|
||||
});
|
||||
|
||||
test("Memberships count", async function (assert) {
|
||||
this.channel.set("memberships_count", 4);
|
||||
this.channel.set("membershipsCount", 4);
|
||||
await render(hbs`{{chat-channel-card channel=channel}}`);
|
||||
|
||||
assert.equal(
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import { exists, query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import I18n from "I18n";
|
||||
import { Promise } from "rsvp";
|
||||
import { fillIn, triggerEvent } from "@ember/test-helpers";
|
||||
import { module } from "qunit";
|
||||
|
||||
function fetchMembersHandler(channelId, params = {}) {
|
||||
if (params.offset === 50) {
|
||||
return Promise.resolve([{ user: { id: 3, username: "clara" } }]);
|
||||
}
|
||||
|
||||
if (params.offset === 100) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
|
||||
if (!params.username) {
|
||||
return Promise.resolve([
|
||||
{ user: { id: 1, username: "jojo" } },
|
||||
{ user: { id: 2, username: "bob" } },
|
||||
]);
|
||||
}
|
||||
|
||||
if (params.username === "jojo") {
|
||||
return Promise.resolve([{ user: { id: 1, username: "jojo" } }]);
|
||||
} else {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
}
|
||||
|
||||
function setupState(context) {
|
||||
context.set("fetchMembersHandler", fetchMembersHandler);
|
||||
context.set("channel", fabricators.chatChannel());
|
||||
context.channel.set("memberships_count", 2);
|
||||
}
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-members-view",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("no filter", {
|
||||
template: hbs`{{chat-channel-members-view channel=channel fetchMembersHandler=fetchMembersHandler}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("fetchMembersHandler", fetchMembersHandler);
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
this.channel.set("memberships_count", 2);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(
|
||||
exists(".channel-members-view__list-item[data-user-card='jojo']")
|
||||
);
|
||||
assert.ok(
|
||||
exists(".channel-members-view__list-item[data-user-card='bob']")
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("filter", {
|
||||
template: hbs`{{chat-channel-members-view channel=channel fetchMembersHandler=fetchMembersHandler}}`,
|
||||
|
||||
beforeEach() {
|
||||
setupState(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await fillIn(".channel-members-view__search-input", "jojo");
|
||||
|
||||
assert.ok(
|
||||
exists(".channel-members-view__list-item[data-user-card='jojo']")
|
||||
);
|
||||
assert.notOk(
|
||||
exists(".channel-members-view__list-item[data-user-card='bob']")
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("filter with no results", {
|
||||
template: hbs`{{chat-channel-members-view channel=channel fetchMembersHandler=fetchMembersHandler}}`,
|
||||
|
||||
beforeEach() {
|
||||
setupState(this);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await fillIn(".channel-members-view__search-input", "cat");
|
||||
|
||||
assert.equal(
|
||||
query(".channel-members-view__list").innerText.trim(),
|
||||
I18n.t("chat.channel.no_memberships_found")
|
||||
);
|
||||
|
||||
assert.notOk(
|
||||
exists(".channel-members-view__list-item[data-user-card='jojo']")
|
||||
);
|
||||
assert.notOk(
|
||||
exists(".channel-members-view__list-item[data-user-card='bob']")
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("loading more", {
|
||||
template: hbs`{{chat-channel-members-view channel=channel fetchMembersHandler=fetchMembersHandler}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("fetchMembersHandler", fetchMembersHandler);
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
this.channel.set("memberships_count", 3);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
await triggerEvent(".channel-members-view__list", "scroll");
|
||||
|
||||
["jojo", "bob", "clara"].forEach((username) => {
|
||||
assert.ok(
|
||||
exists(
|
||||
`.channel-members-view__list-item[data-user-card='${username}']`
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
await triggerEvent(".channel-members-view__list", "scroll");
|
||||
|
||||
["jojo", "bob", "clara"].forEach((username) => {
|
||||
assert.ok(
|
||||
exists(
|
||||
`.channel-members-view__list-item[data-user-card='${username}']`
|
||||
)
|
||||
);
|
||||
});
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -28,9 +28,8 @@ module("Discourse Chat | Component | chat-channel-metadata", function (hooks) {
|
||||
|
||||
test("unreadIndicator", async function (assert) {
|
||||
this.channel = fabricators.directMessageChatChannel();
|
||||
this.currentUser.set("chat_channel_tracking_state", {
|
||||
[this.channel.id]: { unread_count: 1 },
|
||||
});
|
||||
this.channel.currentUserMembership.unread_count = 1;
|
||||
|
||||
this.unreadIndicator = true;
|
||||
await render(
|
||||
hbs`<ChatChannelMetadata @channel={{this.channel}} @unreadIndicator={{this.unreadIndicator}}/>`
|
||||
|
||||
@@ -60,7 +60,7 @@ module("Discourse Chat | Component | chat-channel-row", function (hooks) {
|
||||
|
||||
assert.dom(".toggle-channel-membership-button").doesNotExist();
|
||||
|
||||
this.categoryChatChannel.current_user_membership.following = true;
|
||||
this.categoryChatChannel.currentUserMembership.following = true;
|
||||
|
||||
await render(hbs`<ChatChannelRow @channel={{this.categoryChatChannel}} />`);
|
||||
|
||||
@@ -92,7 +92,7 @@ module("Discourse Chat | Component | chat-channel-row", function (hooks) {
|
||||
|
||||
assert.dom(".chat-channel-row").doesNotHaveClass("muted");
|
||||
|
||||
this.categoryChatChannel.current_user_membership.muted = true;
|
||||
this.categoryChatChannel.currentUserMembership.muted = true;
|
||||
|
||||
await render(hbs`<ChatChannelRow @channel={{this.categoryChatChannel}} />`);
|
||||
|
||||
@@ -130,11 +130,7 @@ module("Discourse Chat | Component | chat-channel-row", function (hooks) {
|
||||
|
||||
assert.dom(".chat-channel-row").doesNotHaveClass("has-unread");
|
||||
|
||||
this.owner
|
||||
.lookup("service:current-user")
|
||||
.set("chat_channel_tracking_state", {
|
||||
[this.categoryChatChannel.id]: { unread_count: 1 },
|
||||
});
|
||||
this.categoryChatChannel.currentUserMembership.unread_count = 1;
|
||||
|
||||
await render(hbs`<ChatChannelRow @channel={{this.categoryChatChannel}} />`);
|
||||
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import selectKit from "discourse/tests/helpers/select-kit-helper";
|
||||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
import { CHATABLE_TYPES } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import { module } from "qunit";
|
||||
|
||||
function membershipFixture(id, options = {}) {
|
||||
options = Object.assign(
|
||||
{},
|
||||
{
|
||||
muted: false,
|
||||
following: true,
|
||||
},
|
||||
options
|
||||
);
|
||||
|
||||
return {
|
||||
following: options.following,
|
||||
muted: options.muted,
|
||||
desktop_notification_level: "mention",
|
||||
mobile_notification_level: "mention",
|
||||
chat_channel_id: id,
|
||||
chatable_type: "Category",
|
||||
user_count: 2,
|
||||
};
|
||||
}
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-settings-view | Public channel - regular user",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("saving desktop notifications", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/api/chat_channels/${this.channel.id}/notifications_settings.json`,
|
||||
() => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
membershipFixture(this.channel.id),
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
const sk = selectKit(
|
||||
".channel-settings-view__desktop-notification-level-selector"
|
||||
);
|
||||
await sk.expand();
|
||||
await sk.selectRowByValue("mention");
|
||||
|
||||
assert.equal(sk.header().value(), "mention");
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("saving mobile notifications", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/api/chat_channels/${this.channel.id}/notifications_settings.json`,
|
||||
() => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
membershipFixture(this.channel.id),
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
const sk = selectKit(
|
||||
".channel-settings-view__mobile-notification-level-selector"
|
||||
);
|
||||
await sk.expand();
|
||||
await sk.selectRowByValue("mention");
|
||||
|
||||
assert.equal(sk.header().value(), "mention");
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("muted", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/api/chat_channels/${this.channel.id}/notifications_settings.json`,
|
||||
() => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
membershipFixture(this.channel.id, { muted: false }),
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
const sk = selectKit(".channel-settings-view__muted-selector");
|
||||
await sk.expand();
|
||||
await sk.selectRowByName("Off");
|
||||
|
||||
assert.equal(sk.header().value(), "false");
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("hide channel wide mentions", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert
|
||||
.dom(".channel-settings-view__channel-wide-mentions-selector")
|
||||
.doesNotExist();
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("hide channel auto join", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel());
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.dom(".channel-settings-view__auto-join-selector").doesNotExist();
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-settings-view | Direct Message channel - regular user",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("saving desktop notifications", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/api/chat_channels/${this.channel.id}/notifications_settings.json`,
|
||||
() => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
membershipFixture(this.channel.id),
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
const sk = selectKit(
|
||||
".channel-settings-view__desktop-notification-level-selector"
|
||||
);
|
||||
await sk.expand();
|
||||
await sk.selectRowByValue("mention");
|
||||
|
||||
assert.equal(sk.header().value(), "mention");
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("saving mobile notifications", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
})
|
||||
);
|
||||
},
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/api/chat_channels/${this.channel.id}/notifications_settings.json`,
|
||||
() => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
membershipFixture(this.channel.id),
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
const sk = selectKit(
|
||||
".channel-settings-view__mobile-notification-level-selector"
|
||||
);
|
||||
await sk.expand();
|
||||
await sk.selectRowByValue("mention");
|
||||
|
||||
assert.equal(sk.header().value(), "mention");
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("muted", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/api/chat_channels/${this.channel.id}/notifications_settings.json`,
|
||||
() => {
|
||||
return [
|
||||
200,
|
||||
{ "Content-Type": "application/json" },
|
||||
membershipFixture(this.channel.id, { muted: false }),
|
||||
];
|
||||
}
|
||||
);
|
||||
|
||||
const sk = selectKit(".channel-settings-view__muted-selector");
|
||||
await sk.expand();
|
||||
await sk.selectRowByName("Off");
|
||||
|
||||
assert.equal(sk.header().value(), "false");
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("hide channel wide mentions", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert
|
||||
.dom(".channel-settings-view__channel-wide-mentions-selector")
|
||||
.doesNotExist();
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("hide channel auto join", {
|
||||
template: hbs`{{chat-channel-settings-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set(
|
||||
"channel",
|
||||
fabricators.chatChannel({
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.dom(".channel-settings-view__auto-join-selector").doesNotExist();
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,104 +0,0 @@
|
||||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import { query } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { click } from "@ember/test-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import I18n from "I18n";
|
||||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
import { module } from "qunit";
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-toggle-view | closed channel",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("texts", {
|
||||
template: hbs`{{chat-channel-toggle-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel({ status: "closed" }));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.equal(
|
||||
query("#chat-channel-toggle").innerText.trim(),
|
||||
I18n.t("chat.channel_open.instructions")
|
||||
);
|
||||
assert.equal(
|
||||
query("#chat-channel-toggle-btn").innerText.trim(),
|
||||
I18n.t("chat.channel_settings.open_channel")
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("action", {
|
||||
template: hbs`{{chat-channel-toggle-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel({ status: "closed" }));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/chat_channels/${this.channel.id}/change_status.json`,
|
||||
() => {
|
||||
return [200, { "Content-Type": "application/json" }, {}];
|
||||
}
|
||||
);
|
||||
|
||||
await click("#chat-channel-toggle-btn");
|
||||
|
||||
assert.equal(this.channel.isClosed, false);
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-toggle-view | opened channel",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("texts", {
|
||||
template: hbs`{{chat-channel-toggle-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel({ status: "open" }));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.equal(
|
||||
query("#chat-channel-toggle").innerText.trim(),
|
||||
I18n.t("chat.channel_close.instructions")
|
||||
);
|
||||
assert.equal(
|
||||
query("#chat-channel-toggle-btn").innerText.trim(),
|
||||
I18n.t("chat.channel_settings.close_channel")
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("action", {
|
||||
template: hbs`{{chat-channel-toggle-view channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
this.set("channel", fabricators.chatChannel({ status: "open" }));
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
pretender.put(
|
||||
`/chat/chat_channels/${this.channel.id}/change_status.json`,
|
||||
() => {
|
||||
return [200, { "Content-Type": "application/json" }, {}];
|
||||
}
|
||||
);
|
||||
|
||||
await click("#chat-channel-toggle-btn");
|
||||
|
||||
assert.equal(this.channel.isClosed, true);
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,91 +0,0 @@
|
||||
import { set } from "@ember/object";
|
||||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import { exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import { CHATABLE_TYPES } from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import { module } from "qunit";
|
||||
|
||||
const directMessageChannel = {
|
||||
id: 1,
|
||||
chatable_type: CHATABLE_TYPES.directMessageChannel,
|
||||
chatable: {
|
||||
users: [{ id: 1 }],
|
||||
},
|
||||
};
|
||||
|
||||
const topicChannel = {
|
||||
id: 2,
|
||||
chatable_type: CHATABLE_TYPES.topicChannel,
|
||||
chatable: {
|
||||
users: [{ id: 1 }],
|
||||
},
|
||||
};
|
||||
|
||||
module(
|
||||
"Discourse Chat | Component | chat-channel-unread-indicator",
|
||||
function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("has no unread", {
|
||||
template: hbs`{{chat-channel-unread-indicator channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
set(this.currentUser, "chat_channel_tracking_state", {
|
||||
unread_count: 0,
|
||||
});
|
||||
this.set("channel", topicChannel);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.notOk(exists(".chat-channel-unread-indicator"));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("has unread and no mentions", {
|
||||
template: hbs`{{chat-channel-unread-indicator channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
set(this.currentUser, "chat_channel_tracking_state", {
|
||||
[topicChannel.id]: { unread_count: 1 },
|
||||
});
|
||||
this.set("channel", topicChannel);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(exists(".chat-channel-unread-indicator:not(.urgent)"));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("has unread and mentions", {
|
||||
template: hbs`{{chat-channel-unread-indicator channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
set(this.currentUser, "chat_channel_tracking_state", {
|
||||
[topicChannel.id]: { unread_count: 1, unread_mentions: 1 },
|
||||
});
|
||||
this.set("channel", topicChannel);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(exists(".chat-channel-unread-indicator.urgent"));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("direct message channel | has unread", {
|
||||
template: hbs`{{chat-channel-unread-indicator channel=channel}}`,
|
||||
|
||||
beforeEach() {
|
||||
set(this.currentUser, "chat_channel_tracking_state", {
|
||||
[directMessageChannel.id]: { unread_count: 1 },
|
||||
});
|
||||
this.set("channel", directMessageChannel);
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(exists(".chat-channel-unread-indicator.urgent"));
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
@@ -1,78 +0,0 @@
|
||||
import componentTest, {
|
||||
setupRenderingTest,
|
||||
} from "discourse/tests/helpers/component-test";
|
||||
import hbs from "htmlbars-inline-precompile";
|
||||
import { exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
import {
|
||||
setup as setupChatStub,
|
||||
teardown as teardownChatStub,
|
||||
} from "../helpers/chat-stub";
|
||||
import { module } from "qunit";
|
||||
|
||||
module("Discourse Chat | Component | sidebar-channels", function (hooks) {
|
||||
setupRenderingTest(hooks);
|
||||
|
||||
componentTest("default", {
|
||||
template: hbs`{{sidebar-channels}}`,
|
||||
|
||||
beforeEach() {
|
||||
setupChatStub(this);
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
teardownChatStub();
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(exists("[data-chat-channel-id]"));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("chat is on chat page", {
|
||||
template: hbs`{{sidebar-channels}}`,
|
||||
|
||||
beforeEach() {
|
||||
setupChatStub(this, {});
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
teardownChatStub();
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.ok(exists("[data-chat-channel-id]"));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("none of the conditions are fulfilled", {
|
||||
template: hbs`{{sidebar-channels}}`,
|
||||
|
||||
beforeEach() {
|
||||
setupChatStub(this, { userCanChat: false });
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
teardownChatStub();
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.notOk(exists("[data-chat-channel-id]"));
|
||||
},
|
||||
});
|
||||
|
||||
componentTest("user cant chat", {
|
||||
template: hbs`{{sidebar-channels}}`,
|
||||
|
||||
beforeEach() {
|
||||
setupChatStub(this, { userCanChat: false });
|
||||
},
|
||||
|
||||
afterEach() {
|
||||
teardownChatStub();
|
||||
},
|
||||
|
||||
async test(assert) {
|
||||
assert.notOk(exists("[data-chat-channel-id]"));
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -138,8 +138,8 @@ export function directMessageChannelPretender(
|
||||
opts = { unread_count: 0, muted: false }
|
||||
) {
|
||||
let copy = cloneJSON(directMessageChannels[0]);
|
||||
copy.chat_channel.current_user_membership.unread_count = opts.unread_count;
|
||||
copy.chat_channel.current_user_membership.muted = opts.muted;
|
||||
copy.chat_channel.currentUserMembership.unread_count = opts.unread_count;
|
||||
copy.chat_channel.currentUserMembership.muted = opts.muted;
|
||||
server.get("/chat/chat_channels/75.json", () => helper.response(copy));
|
||||
}
|
||||
|
||||
@@ -150,14 +150,14 @@ export function chatChannelPretender(server, helper, changes = []) {
|
||||
let found;
|
||||
found = copy.public_channels.find((c) => c.id === change.id);
|
||||
if (found) {
|
||||
found.current_user_membership.unread_count = change.unread_count;
|
||||
found.current_user_membership.muted = change.muted;
|
||||
found.currentUserMembership.unread_count = change.unread_count;
|
||||
found.currentUserMembership.muted = change.muted;
|
||||
}
|
||||
if (!found) {
|
||||
found = copy.direct_message_channels.find((c) => c.id === change.id);
|
||||
if (found) {
|
||||
found.current_user_membership.unread_count = change.unread_count;
|
||||
found.current_user_membership.muted = change.muted;
|
||||
found.currentUserMembership.unread_count = change.unread_count;
|
||||
found.currentUserMembership.muted = change.muted;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
import fabricators from "../helpers/fabricators";
|
||||
import { isPresent } from "@ember/utils";
|
||||
import Service from "@ember/service";
|
||||
|
||||
let publicChannels;
|
||||
let userCanChat;
|
||||
|
||||
class ChatStub extends Service {
|
||||
userCanChat = userCanChat;
|
||||
publicChannels = publicChannels;
|
||||
}
|
||||
|
||||
export function setup(context, options = {}) {
|
||||
context.registry.register("service:chat-stub", ChatStub);
|
||||
context.registry.injection("component", "chat", "service:chat-stub");
|
||||
|
||||
publicChannels = isPresent(options.publicChannels)
|
||||
? options.publicChannels
|
||||
: [fabricators.chatChannel()];
|
||||
userCanChat = isPresent(options.userCanChat) ? options.userCanChat : true;
|
||||
}
|
||||
|
||||
export function teardown() {
|
||||
publicChannels = [];
|
||||
userCanChat = true;
|
||||
}
|
||||
@@ -1,296 +0,0 @@
|
||||
import MockPresenceChannel from "../../helpers/mock-presence-channel";
|
||||
import {
|
||||
acceptance,
|
||||
publishToMessageBus,
|
||||
} from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import fabricators from "../../helpers/fabricators";
|
||||
import { directMessageChannels } from "discourse/plugins/chat/chat-fixtures";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
import ChatChannel from "discourse/plugins/chat/discourse/models/chat-channel";
|
||||
import sinon from "sinon";
|
||||
import pretender from "discourse/tests/helpers/create-pretender";
|
||||
import { settled } from "@ember/test-helpers";
|
||||
|
||||
acceptance("Discourse Chat | Unit | Service | chat", function (needs) {
|
||||
needs.hooks.beforeEach(function () {
|
||||
Object.defineProperty(this, "chatService", {
|
||||
get: () => this.container.lookup("service:chat"),
|
||||
});
|
||||
Object.defineProperty(this, "currentUser", {
|
||||
get: () => this.container.lookup("service:current-user"),
|
||||
});
|
||||
});
|
||||
|
||||
needs.user({ ignored_users: [] });
|
||||
|
||||
needs.pretender((server, helper) => {
|
||||
server.get("/chat/chat_channels.json", () => {
|
||||
return helper.response({
|
||||
public_channels: [
|
||||
{
|
||||
id: 1,
|
||||
title: "something",
|
||||
chatable_type: "Category",
|
||||
last_message_sent_at: "2021-11-08T21:26:05.710Z",
|
||||
current_user_membership: {
|
||||
unread_count: 2,
|
||||
last_read_message_id: 123,
|
||||
unread_mentions: 0,
|
||||
muted: false,
|
||||
},
|
||||
message_bus_last_ids: {
|
||||
new_mentions: 0,
|
||||
new_messages: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
direct_message_channels: [],
|
||||
message_bus_last_ids: {
|
||||
channel_metadata: 0,
|
||||
channel_edits: 0,
|
||||
channel_status: 0,
|
||||
new_channel: 0,
|
||||
user_tracking_state: 0,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
server.put("/chat/:chatChannelId/read/:messageId.json", () => {
|
||||
return helper.response({ success: "OK" });
|
||||
});
|
||||
});
|
||||
|
||||
function setupMockPresenceChannel(chatService) {
|
||||
chatService.set(
|
||||
"presenceChannel",
|
||||
MockPresenceChannel.create({
|
||||
name: `/chat-reply/1`,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
test("#markNetworkAsReliable", async function (assert) {
|
||||
setupMockPresenceChannel(this.chatService);
|
||||
|
||||
this.chatService.markNetworkAsReliable();
|
||||
|
||||
assert.strictEqual(this.chatService.isNetworkUnreliable, false);
|
||||
});
|
||||
|
||||
test("#markNetworkAsUnreliable", async function (assert) {
|
||||
setupMockPresenceChannel(this.chatService);
|
||||
this.chatService.markNetworkAsUnreliable();
|
||||
|
||||
assert.strictEqual(this.chatService.isNetworkUnreliable, true);
|
||||
|
||||
await settled();
|
||||
|
||||
assert.strictEqual(
|
||||
this.chatService.isNetworkUnreliable,
|
||||
false,
|
||||
"it resets state after a delay"
|
||||
);
|
||||
});
|
||||
|
||||
test("#startTrackingChannel - sorts dm channels", async function (assert) {
|
||||
setupMockPresenceChannel(this.chatService);
|
||||
const fixtures = cloneJSON(directMessageChannels).mapBy("chat_channel");
|
||||
const channel1 = ChatChannel.create(fixtures[0]);
|
||||
const channel2 = ChatChannel.create(fixtures[1]);
|
||||
await this.chatService.startTrackingChannel(channel1);
|
||||
this.currentUser.set(
|
||||
`chat_channel_tracking_state.${channel1.id}.unread_count`,
|
||||
0
|
||||
);
|
||||
await this.chatService.startTrackingChannel(channel2);
|
||||
|
||||
assert.strictEqual(
|
||||
this.chatService.directMessageChannels.firstObject.title,
|
||||
channel2.title
|
||||
);
|
||||
});
|
||||
|
||||
test("#refreshTrackingState", async function (assert) {
|
||||
this.currentUser.set("chat_channel_tracking_state", {});
|
||||
|
||||
await this.chatService.refreshTrackingState();
|
||||
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].unread_count,
|
||||
2
|
||||
);
|
||||
});
|
||||
|
||||
test("attempts to track a non followed channel", async function (assert) {
|
||||
this.currentUser.set("chat_channel_tracking_state", {});
|
||||
const channel = fabricators.chatChannel();
|
||||
await this.chatService.startTrackingChannel(channel);
|
||||
|
||||
assert.false(channel.current_user_membership.following);
|
||||
assert.notOk(
|
||||
this.currentUser.chat_channel_tracking_state[channel.id],
|
||||
"it doesn’t track it"
|
||||
);
|
||||
});
|
||||
|
||||
test("new message", async function (assert) {
|
||||
setupMockPresenceChannel(this.chatService);
|
||||
await this.chatService.forceRefreshChannels();
|
||||
|
||||
await publishToMessageBus("/chat/1/new-messages", {
|
||||
user_id: this.currentUser.id,
|
||||
username: this.currentUser.username,
|
||||
message_id: 124,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].chat_message_id,
|
||||
124,
|
||||
"updates tracking state last message id to the message id sent by current user"
|
||||
);
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].unread_count,
|
||||
2,
|
||||
"does not increment unread count"
|
||||
);
|
||||
});
|
||||
|
||||
test("/chat/:channelId/new-messages - message from current user", async function (assert) {
|
||||
setupMockPresenceChannel(this.chatService);
|
||||
await this.chatService.forceRefreshChannels();
|
||||
|
||||
await publishToMessageBus("/chat/1/new-messages", {
|
||||
user_id: this.currentUser.id,
|
||||
username: this.currentUser.username,
|
||||
message_id: 124,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].chat_message_id,
|
||||
124,
|
||||
"updates tracking state last message id to the message id sent by current user"
|
||||
);
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].unread_count,
|
||||
2,
|
||||
"does not increment unread count"
|
||||
);
|
||||
});
|
||||
|
||||
test("/chat/:channelId/new-messages - message from user that current user is ignoring", async function (assert) {
|
||||
this.currentUser.set("ignored_users", ["johnny"]);
|
||||
setupMockPresenceChannel(this.chatService);
|
||||
await this.chatService.forceRefreshChannels();
|
||||
|
||||
await publishToMessageBus("/chat/1/new-messages", {
|
||||
user_id: 2327,
|
||||
username: "johnny",
|
||||
message_id: 124,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].chat_message_id,
|
||||
124,
|
||||
"updates tracking state last message id to the message id sent by johnny"
|
||||
);
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].unread_count,
|
||||
2,
|
||||
"does not increment unread count"
|
||||
);
|
||||
});
|
||||
|
||||
test("/chat/:channelId/new-messages - message from another user", async function (assert) {
|
||||
setupMockPresenceChannel(this.chatService);
|
||||
await this.chatService.forceRefreshChannels();
|
||||
|
||||
await publishToMessageBus("/chat/1/new-messages", {
|
||||
user_id: 2327,
|
||||
username: "jane",
|
||||
message_id: 124,
|
||||
});
|
||||
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].chat_message_id,
|
||||
123,
|
||||
"does not update tracking state last message id to the message id sent by jane"
|
||||
);
|
||||
assert.equal(
|
||||
this.currentUser.chat_channel_tracking_state[1].unread_count,
|
||||
3,
|
||||
"does increment unread count"
|
||||
);
|
||||
});
|
||||
|
||||
test("#updateLastReadMessage - updates and tracks the last read message", async function (assert) {
|
||||
this.currentUser.set("chat_channel_tracking_state", {});
|
||||
sinon.stub(document, "querySelectorAll").callsFake(function () {
|
||||
return [{ dataset: { id: 2 } }];
|
||||
});
|
||||
const activeChannel = fabricators.chatChannel({
|
||||
current_user_membership: { last_read_message_id: 1, following: true },
|
||||
});
|
||||
this.chatService.setActiveChannel(activeChannel);
|
||||
|
||||
this.chatService.updateLastReadMessage();
|
||||
await settled();
|
||||
|
||||
assert.equal(activeChannel.lastSendReadMessageId, 2);
|
||||
});
|
||||
|
||||
test("#updateLastReadMessage - does nothing if the user doesn't follow the channel", async function (assert) {
|
||||
this.currentUser.set("chat_channel_tracking_state", {});
|
||||
this.chatService.setActiveChannel(
|
||||
fabricators.chatChannel({ current_user_membership: { following: false } })
|
||||
);
|
||||
sinon.stub(document, "querySelectorAll").callsFake(function () {
|
||||
return [{ dataset: { id: 1 } }];
|
||||
});
|
||||
|
||||
this.chatService.updateLastReadMessage();
|
||||
await settled();
|
||||
|
||||
assert.equal(this.chatService.activeChannel.lastSendReadMessageId, null);
|
||||
});
|
||||
|
||||
test("#updateLastReadMessage - does nothing if the user already read the message", async function (assert) {
|
||||
this.currentUser.set("chat_channel_tracking_state", {});
|
||||
sinon.stub(document, "querySelectorAll").callsFake(function () {
|
||||
return [{ dataset: { id: 1 } }];
|
||||
});
|
||||
const activeChannel = fabricators.chatChannel({
|
||||
current_user_membership: { last_read_message_id: 2, following: true },
|
||||
});
|
||||
this.chatService.setActiveChannel(activeChannel);
|
||||
|
||||
this.chatService.updateLastReadMessage();
|
||||
await settled();
|
||||
|
||||
assert.equal(activeChannel.lastSendReadMessageId, 2);
|
||||
});
|
||||
});
|
||||
|
||||
acceptance(
|
||||
"Discourse Chat | Unit | Service | chat - no current user",
|
||||
function (needs) {
|
||||
needs.hooks.beforeEach(function () {
|
||||
Object.defineProperty(this, "chatService", {
|
||||
get: () => this.container.lookup("service:chat"),
|
||||
});
|
||||
});
|
||||
|
||||
test("#refreshTrackingState", async function (assert) {
|
||||
pretender.get(`/chat/chat_channels.json`, () => {
|
||||
assert.step("unexpected");
|
||||
return [200, { "Content-Type": "application/json" }, {}];
|
||||
});
|
||||
|
||||
assert.step("start");
|
||||
await this.chatService.refreshTrackingState();
|
||||
assert.step("end");
|
||||
|
||||
assert.verifySteps(["start", "end"], "it does no requests");
|
||||
});
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user