= 500) {
+ event.preventDefault();
+ }
+
cancel(this._isPressingHandler);
}
diff --git a/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs b/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs
index e2a1bf669fd..e67e20a5953 100644
--- a/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs
+++ b/plugins/chat/assets/javascripts/discourse/components/chat-thread.hbs
@@ -22,7 +22,7 @@
{{on "scroll" this.computeScrollState passive=true}}
>
{{#each this.thread.messages key="id" as |message|}}
diff --git a/plugins/chat/assets/javascripts/discourse/components/chat/composer/channel.js b/plugins/chat/assets/javascripts/discourse/components/chat/composer/channel.js
index 49a67daa4b7..5ad1bde3616 100644
--- a/plugins/chat/assets/javascripts/discourse/components/chat/composer/channel.js
+++ b/plugins/chat/assets/javascripts/discourse/components/chat/composer/channel.js
@@ -40,6 +40,14 @@ export default class ChatComposerChannel extends ChatComposer {
this.chatApi.saveDraft(channelId, jsonDraft);
}
+ get lastMessage() {
+ return this.args.channel.lastMessage;
+ }
+
+ lastUserMessage(user) {
+ return this.args.channel.lastUserMessage(user);
+ }
+
get placeholder() {
if (!this.args.channel.canModifyMessages(this.currentUser)) {
return I18n.t(
diff --git a/plugins/chat/assets/javascripts/discourse/components/chat/composer/thread.js b/plugins/chat/assets/javascripts/discourse/components/chat/composer/thread.js
index fdb94e77b03..ff1ff442b41 100644
--- a/plugins/chat/assets/javascripts/discourse/components/chat/composer/thread.js
+++ b/plugins/chat/assets/javascripts/discourse/components/chat/composer/thread.js
@@ -21,6 +21,14 @@ export default class ChatComposerThread extends ChatComposer {
return I18n.t("chat.placeholder_thread");
}
+ get lastMessage() {
+ return this.args.thread.lastMessage;
+ }
+
+ lastUserMessage(user) {
+ return this.args.thread.lastUserMessage(user);
+ }
+
@action
onKeyDown(event) {
if (event.key === "Escape") {
diff --git a/plugins/chat/assets/javascripts/discourse/lib/chat-messages-manager.js b/plugins/chat/assets/javascripts/discourse/lib/chat-messages-manager.js
index 5ccaf95ec93..67a237394cd 100644
--- a/plugins/chat/assets/javascripts/discourse/lib/chat-messages-manager.js
+++ b/plugins/chat/assets/javascripts/discourse/lib/chat-messages-manager.js
@@ -48,4 +48,14 @@ export default class ChatMessagesManager {
findIndexOfMessage(id) {
return this.messages.findIndex((m) => m.id === id);
}
+
+ findLastMessage() {
+ return this.messages.findLast((message) => !message.deletedAt);
+ }
+
+ findLastUserMessage(user) {
+ return this.messages.findLast(
+ (message) => message.user.id === user.id && !message.deletedAt
+ );
+ }
}
diff --git a/plugins/chat/assets/javascripts/discourse/models/chat-channel.js b/plugins/chat/assets/javascripts/discourse/models/chat-channel.js
index ed8eadfbf50..ef2af33eb38 100644
--- a/plugins/chat/assets/javascripts/discourse/models/chat-channel.js
+++ b/plugins/chat/assets/javascripts/discourse/models/chat-channel.js
@@ -169,6 +169,14 @@ export default class ChatChannel {
this.messagesManager.removeMessage(message);
}
+ get lastMessage() {
+ return this.messagesManager.findLastMessage();
+ }
+
+ lastUserMessage(user) {
+ return this.messagesManager.findLastUserMessage(user);
+ }
+
get messages() {
return this.messagesManager.messages;
}
diff --git a/plugins/chat/assets/javascripts/discourse/models/chat-message.js b/plugins/chat/assets/javascripts/discourse/models/chat-message.js
index 5f88728d716..d16e7623c98 100644
--- a/plugins/chat/assets/javascripts/discourse/models/chat-message.js
+++ b/plugins/chat/assets/javascripts/discourse/models/chat-message.js
@@ -124,6 +124,14 @@ export default class ChatMessage {
return message;
}
+ get replyable() {
+ return !this.staged && !this.error;
+ }
+
+ get editable() {
+ return !this.staged && !this.error;
+ }
+
get cooked() {
return this._cooked;
}
diff --git a/plugins/chat/assets/javascripts/discourse/models/chat-thread.js b/plugins/chat/assets/javascripts/discourse/models/chat-thread.js
index 5f9ea26f3c1..0ec29be80d8 100644
--- a/plugins/chat/assets/javascripts/discourse/models/chat-thread.js
+++ b/plugins/chat/assets/javascripts/discourse/models/chat-thread.js
@@ -73,6 +73,14 @@ export default class ChatThread {
this.messagesManager.addMessages([message]);
}
+ get lastMessage() {
+ return this.messagesManager.findLastMessage();
+ }
+
+ lastUserMessage(user) {
+ return this.messagesManager.findLastUserMessage(user);
+ }
+
get routeModels() {
return [...this.channel.routeModels, this.id];
}
diff --git a/plugins/chat/assets/javascripts/discourse/services/chat-channel-pane.js b/plugins/chat/assets/javascripts/discourse/services/chat-channel-pane.js
index 5ed5bee8d1f..f07f3ad8eda 100644
--- a/plugins/chat/assets/javascripts/discourse/services/chat-channel-pane.js
+++ b/plugins/chat/assets/javascripts/discourse/services/chat-channel-pane.js
@@ -40,22 +40,6 @@ export default class ChatChannelPane extends Service {
this.selectingMessages = true;
}
- get lastCurrentUserMessage() {
- const lastCurrentUserMessage = this.chat.activeChannel.messages.findLast(
- (message) => message.user.id === this.currentUser.id
- );
-
- if (!lastCurrentUserMessage) {
- return;
- }
-
- if (lastCurrentUserMessage.staged || lastCurrentUserMessage.error) {
- return;
- }
-
- return lastCurrentUserMessage;
- }
-
get lastMessage() {
return this.chat.activeChannel.messages.lastObject;
}
diff --git a/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-composer.js b/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-composer.js
index d9b08e6e885..5c68f83d416 100644
--- a/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-composer.js
+++ b/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-composer.js
@@ -10,4 +10,9 @@ export default class ChatChannelThreadComposer extends ChatComposer {
thread,
});
}
+
+ @action
+ replyTo() {
+ this.chat.activeMessage = null;
+ }
}
diff --git a/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-pane.js b/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-pane.js
index 2e03a27da6c..58922a2e5fd 100644
--- a/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-pane.js
+++ b/plugins/chat/assets/javascripts/discourse/services/chat-channel-thread-pane.js
@@ -24,21 +24,4 @@ export default class ChatChannelThreadPane extends ChatChannelPane {
get composerService() {
return this.chatChannelThreadComposer;
}
-
- get lastCurrentUserMessage() {
- const lastCurrentUserMessage =
- this.chat.activeChannel.activeThread.messages.findLast(
- (message) => message.user.id === this.currentUser.id
- );
-
- if (!lastCurrentUserMessage) {
- return;
- }
-
- if (lastCurrentUserMessage.staged || lastCurrentUserMessage.error) {
- return;
- }
-
- return lastCurrentUserMessage;
- }
}
diff --git a/plugins/chat/spec/system/bookmark_message_spec.rb b/plugins/chat/spec/system/bookmark_message_spec.rb
index 1f62d0ebf66..ab115b0eb47 100644
--- a/plugins/chat/spec/system/bookmark_message_spec.rb
+++ b/plugins/chat/spec/system/bookmark_message_spec.rb
@@ -3,8 +3,8 @@
RSpec.describe "Bookmark message", type: :system, js: true do
fab!(:current_user) { Fabricate(:user) }
- let(:chat) { PageObjects::Pages::Chat.new }
- let(:channel) { PageObjects::Pages::ChatChannel.new }
+ let(:chat_page) { PageObjects::Pages::Chat.new }
+ let(:channel_page) { PageObjects::Pages::ChatChannel.new }
let(:bookmark_modal) { PageObjects::Modals::Bookmark.new }
fab!(:category_channel_1) { Fabricate(:category_channel) }
@@ -18,13 +18,13 @@ RSpec.describe "Bookmark message", type: :system, js: true do
context "when desktop" do
it "allows to bookmark a message" do
- chat.visit_channel(category_channel_1)
- channel.bookmark_message(message_1)
+ chat_page.visit_channel(category_channel_1)
+ channel_page.bookmark_message(message_1)
bookmark_modal.fill_name("Check this out later")
bookmark_modal.select_preset_reminder(:next_month)
- expect(channel).to have_bookmarked_message(message_1)
+ expect(channel_page).to have_bookmarked_message(message_1)
end
context "when the user has a bookmark auto_delete_preference" do
@@ -35,11 +35,11 @@ RSpec.describe "Bookmark message", type: :system, js: true do
end
it "is respected when the user creates a new bookmark" do
- chat.visit_channel(category_channel_1)
- channel.bookmark_message(message_1)
+ chat_page.visit_channel(category_channel_1)
+ channel_page.bookmark_message(message_1)
bookmark_modal.save
- expect(channel).to have_bookmarked_message(message_1)
+ expect(channel_page).to have_bookmarked_message(message_1)
bookmark = Bookmark.find_by(bookmarkable: message_1, user: current_user)
expect(bookmark.auto_delete_preference).to eq(
@@ -51,20 +51,13 @@ RSpec.describe "Bookmark message", type: :system, js: true do
context "when mobile", mobile: true do
it "allows to bookmark a message" do
- chat.visit_channel(category_channel_1)
-
- i = 0.5
- try_until_success(timeout: 20) do
- channel.message_by_id(message_1.id).click(delay: i)
- first(".bookmark-btn")
- i += 0.1
- end
- find(".bookmark-btn").click
+ chat_page.visit_channel(category_channel_1)
+ channel_page.bookmark_message(message_1)
bookmark_modal.fill_name("Check this out later")
bookmark_modal.select_preset_reminder(:next_month)
- expect(channel).to have_bookmarked_message(message_1)
+ expect(channel_page).to have_bookmarked_message(message_1)
end
end
end
diff --git a/plugins/chat/spec/system/chat/composer/shortcuts/channel_spec.rb b/plugins/chat/spec/system/chat/composer/shortcuts/channel_spec.rb
new file mode 100644
index 00000000000..2d62ca13bbc
--- /dev/null
+++ b/plugins/chat/spec/system/chat/composer/shortcuts/channel_spec.rb
@@ -0,0 +1,128 @@
+# frozen_string_literal: true
+
+RSpec.describe "Chat | composer | shortcuts | channel", type: :system, js: true do
+ fab!(:channel_1) { Fabricate(:chat_channel) }
+ fab!(:current_user) { Fabricate(:admin) }
+
+ let(:chat) { PageObjects::Pages::Chat.new }
+ let(:channel_page) { PageObjects::Pages::ChatChannel.new }
+ let(:thread_page) { PageObjects::Pages::ChatThread.new }
+ let(:key_modifier) { RUBY_PLATFORM =~ /darwin/i ? :meta : :control }
+
+ before do
+ chat_system_bootstrap
+ channel_1.add(current_user)
+ sign_in(current_user)
+ end
+
+ context "when using meta + b" do
+ it "adds bold text" do
+ chat.visit_channel(channel_1)
+
+ channel_page.composer.bold_text_shortcut
+
+ expect(channel_page.composer.value).to eq("**strong text**")
+ end
+ end
+
+ context "when using meta + i" do
+ it "adds italic text" do
+ chat.visit_channel(channel_1)
+
+ channel_page.composer.emphasized_text_shortcut
+
+ expect(channel_page.composer.value).to eq("_emphasized text_")
+ end
+ end
+
+ context "when using meta + e" do
+ it "adds preformatted text" do
+ chat.visit_channel(channel_1)
+
+ channel_page.composer.indented_text_shortcut
+
+ expect(channel_page.composer.value).to eq("`indent preformatted text by 4 spaces`")
+ end
+ end
+
+ context "when the thread panel is also open" do
+ fab!(:user_2) { Fabricate(:user) }
+ fab!(:thread) do
+ chat_thread_chain_bootstrap(
+ channel: channel_1,
+ users: [current_user, user_2],
+ messages_count: 2,
+ )
+ end
+
+ before do
+ SiteSetting.enable_experimental_chat_threaded_discussions = true
+ channel_1.update!(threading_enabled: true)
+ end
+
+ it "directs the shortcut to the focused composer" do
+ chat.visit_channel(channel_1)
+ channel_page.message_thread_indicator(thread.original_message).click
+ channel_page.composer.emphasized_text_shortcut
+
+ expect(channel_page.composer.value).to eq("_emphasized text_")
+ expect(thread_page.composer.value).to eq("")
+
+ channel_page.composer.fill_in(with: "")
+ thread_page.composer.fill_in(with: "")
+
+ thread_page.composer.emphasized_text_shortcut
+
+ expect(channel_page.composer.value).to eq("")
+ expect(thread_page.composer.value).to eq("_emphasized text_")
+ end
+ end
+
+ context "when using ArrowUp" do
+ fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1, user: current_user) }
+ fab!(:message_2) { Fabricate(:chat_message, chat_channel: channel_1) }
+
+ it "edits last editable message" do
+ chat.visit_channel(channel_1)
+
+ channel_page.composer.edit_last_message_shortcut
+
+ expect(channel_page.composer.message_details).to be_editing(message_1)
+ end
+
+ context "when last message is staged" do
+ it "does not edit a message" do
+ chat.visit_channel(channel_1)
+ page.driver.browser.network_conditions = { offline: true }
+ channel_page.send_message
+ channel_page.composer.edit_last_message_shortcut
+
+ expect(channel_page.composer.message_details).to have_no_message
+ ensure
+ page.driver.browser.network_conditions = { offline: false }
+ end
+ end
+
+ context "when last message is deleted" do
+ before { message_1.trash! }
+
+ it "does not edit a message" do
+ chat.visit_channel(channel_1)
+
+ channel_page.composer.edit_last_message_shortcut
+
+ expect(channel_page.composer.message_details).to have_no_message
+ end
+ end
+
+ context "with shift" do
+ it "starts replying to the last message" do
+ chat.visit_channel(channel_1)
+
+ channel_page.composer.reply_to_last_message_shortcut
+
+ expect(channel_page.composer.message_details).to be_replying_to(message_2)
+ end
+ end
+ end
+end
diff --git a/plugins/chat/spec/system/chat/composer/shortcuts/thread_spec.rb b/plugins/chat/spec/system/chat/composer/shortcuts/thread_spec.rb
index 33ac3299341..f416e7e4b20 100644
--- a/plugins/chat/spec/system/chat/composer/shortcuts/thread_spec.rb
+++ b/plugins/chat/spec/system/chat/composer/shortcuts/thread_spec.rb
@@ -2,8 +2,9 @@
RSpec.describe "Chat | composer | shortcuts | thread", type: :system, js: true do
fab!(:channel_1) { Fabricate(:chat_channel, threading_enabled: true) }
- fab!(:current_user) { Fabricate(:user) }
+ fab!(:current_user) { Fabricate(:admin) }
fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1) }
+
let(:chat_page) { PageObjects::Pages::Chat.new }
let(:thread_page) { PageObjects::Pages::ChatThread.new }
@@ -15,36 +16,44 @@ RSpec.describe "Chat | composer | shortcuts | thread", type: :system, js: true d
end
describe "ArrowUp" do
- let(:thread_1) { message_1.reload.thread }
+ fab!(:thread_1) { Fabricate(:chat_message, user: current_user, in_reply_to: message_1).thread }
+ let(:last_thread_message) { thread_1.replies.last }
context "when there are editable messages" do
- let(:last_thread_message) { thread_1.replies.last }
-
- before do
- thread_message_1 = Fabricate(:chat_message, user: current_user, in_reply_to: message_1)
- Fabricate(:chat_message, user: current_user, thread: thread_message_1.reload.thread)
- end
+ before { Fabricate(:chat_message, user: current_user, thread: thread_1) }
it "starts editing the last editable message" do
chat_page.visit_thread(thread_1)
thread_page.composer.edit_last_message_shortcut
- expect(thread_page.composer_message_details).to have_message(last_thread_message)
+ expect(thread_page.composer_message_details).to have_message(id: last_thread_message.id)
expect(thread_page.composer.value).to eq(last_thread_message.message)
end
end
- context "when there are no editable messages" do
- before { Fabricate(:chat_message, in_reply_to: message_1) }
+ context "when last message is staged" do
+ it "does not edit a message" do
+ chat_page.visit_thread(thread_1)
+ page.driver.browser.network_conditions = { offline: true }
+ thread_page.send_message
+ thread_page.composer.edit_last_message_shortcut
- it "does nothing" do
+ expect(thread_page.composer.message_details).to have_no_message
+ ensure
+ page.driver.browser.network_conditions = { offline: false }
+ end
+ end
+
+ context "when last message is deleted" do
+ before { last_thread_message.trash! }
+
+ it "does not edit a message" do
chat_page.visit_thread(thread_1)
thread_page.composer.edit_last_message_shortcut
- expect(thread_page.composer_message_details).to have_no_message
- expect(thread_page.composer.value).to be_blank
+ expect(thread_page.composer.message_details).to have_no_message
end
end
end
diff --git a/plugins/chat/spec/system/chat_channel_spec.rb b/plugins/chat/spec/system/chat_channel_spec.rb
index 26d2354f328..ad0633cfb24 100644
--- a/plugins/chat/spec/system/chat_channel_spec.rb
+++ b/plugins/chat/spec/system/chat_channel_spec.rb
@@ -36,8 +36,7 @@ RSpec.describe "Chat channel", type: :system, js: true do
)
sidebar_page.open_channel(channel_1)
- expect(channel_page).to have_no_loading_skeleton
- expect(channel_page.messages).to have_x_messages(51)
+ expect(channel_page.messages).to have_message(id: message_1.id)
end
end
diff --git a/plugins/chat/spec/system/chat_composer_spec.rb b/plugins/chat/spec/system/chat_composer_spec.rb
index 1495913c85d..2264a564877 100644
--- a/plugins/chat/spec/system/chat_composer_spec.rb
+++ b/plugins/chat/spec/system/chat_composer_spec.rb
@@ -3,19 +3,18 @@
RSpec.describe "Chat composer", type: :system, js: true do
fab!(:current_user) { Fabricate(:user) }
fab!(:channel_1) { Fabricate(:chat_channel) }
- fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1) }
+ fab!(:message_1) { Fabricate(:chat_message, user: current_user, chat_channel: channel_1) }
let(:chat_page) { PageObjects::Pages::Chat.new }
let(:channel_page) { PageObjects::Pages::ChatChannel.new }
- before { chat_system_bootstrap }
+ before do
+ chat_system_bootstrap
+ channel_1.add(current_user)
+ sign_in(current_user)
+ end
context "when replying to a message" do
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
it "adds the reply indicator to the composer" do
chat_page.visit_channel(channel_1)
channel_page.reply_to(message_1)
@@ -43,11 +42,6 @@ RSpec.describe "Chat composer", type: :system, js: true do
context "when editing a message" do
fab!(:message_2) { Fabricate(:chat_message, chat_channel: channel_1, user: current_user) }
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
it "adds the edit indicator" do
chat_page.visit_channel(channel_1)
channel_page.edit_message(message_2)
@@ -95,11 +89,6 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
context "when adding an emoji through the picker" do
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
xit "adds the emoji to the composer" do
chat_page.visit_channel(channel_1)
channel_page.open_action_menu
@@ -121,11 +110,6 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
context "when adding an emoji through the autocomplete" do
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
it "adds the emoji to the composer" do
chat_page.visit_channel(channel_1)
find(".chat-composer__input").fill_in(with: ":gri")
@@ -147,11 +131,6 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
context "when opening emoji picker through more button of the autocomplete" do
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
xit "prefills the emoji picker filter input" do
chat_page.visit_channel(channel_1)
find(".chat-composer__input").fill_in(with: ":gri")
@@ -173,11 +152,6 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
context "when typing on keyboard" do
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
it "propagates keys to composer" do
chat_page.visit_channel(channel_1)
@@ -196,11 +170,6 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
context "when pasting link over selected text" do
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
it "outputs a markdown link" do
modifier = /darwin/i =~ RbConfig::CONFIG["host_os"] ? :command : :control
select_text = <<-JS
@@ -226,12 +195,19 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
end
- context "when posting a message with length equal to minimum length" do
- before do
- SiteSetting.chat_minimum_message_length = 1
- channel_1.add(current_user)
- sign_in(current_user)
+ context "when editing a message with no length" do
+ it "deletes the message" do
+ chat_page.visit_channel(channel_1)
+ channel_page.composer.edit_last_message_shortcut
+ channel_page.composer.fill_in(with: "")
+ channel_page.click_send_message
+
+ expect(channel_page.messages).to have_message(deleted: 1)
end
+ end
+
+ context "when posting a message with length equal to minimum length" do
+ before { SiteSetting.chat_minimum_message_length = 1 }
it "works" do
chat_page.visit_channel(channel_1)
@@ -243,11 +219,7 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
context "when posting a message with length superior to minimum length" do
- before do
- SiteSetting.chat_minimum_message_length = 2
- channel_1.add(current_user)
- sign_in(current_user)
- end
+ before { SiteSetting.chat_minimum_message_length = 2 }
it "doesn’t allow to send" do
chat_page.visit_channel(channel_1)
@@ -258,11 +230,6 @@ RSpec.describe "Chat composer", type: :system, js: true do
end
context "when upload is in progress" do
- before do
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
it "doesn’t allow to send" do
chat_page.visit_channel(channel_1)
diff --git a/plugins/chat/spec/system/hashtag_autocomplete_spec.rb b/plugins/chat/spec/system/hashtag_autocomplete_spec.rb
index f3dfa9ba18a..2973832dd67 100644
--- a/plugins/chat/spec/system/hashtag_autocomplete_spec.rb
+++ b/plugins/chat/spec/system/hashtag_autocomplete_spec.rb
@@ -25,7 +25,7 @@ describe "Using #hashtag autocompletion to search for and lookup channels",
it "searches for channels, categories, and tags with # and prioritises channels in the results" do
chat_page.visit_channel(channel1)
- chat_channel_page.type_in_composer("this is #ra")
+ chat_channel_page.composer.fill_in(with: "this is #ra")
expect(page).to have_css(
".hashtag-autocomplete .hashtag-autocomplete__option .hashtag-autocomplete__link",
count: 3,
diff --git a/plugins/chat/spec/system/page_objects/chat/chat_channel.rb b/plugins/chat/spec/system/page_objects/chat/chat_channel.rb
index df94ad88058..e0d12307fc3 100644
--- a/plugins/chat/spec/system/page_objects/chat/chat_channel.rb
+++ b/plugins/chat/spec/system/page_objects/chat/chat_channel.rb
@@ -59,8 +59,7 @@ module PageObjects
end
def click_message_action_mobile(message, message_action)
- expand_message_actions_mobile(message, delay: 0.5)
- wait_for_animation(find(".chat-message-actions"), timeout: 5)
+ expand_message_actions_mobile(message, delay: 0.6)
find(".chat-message-actions [data-id=\"#{message_action}\"]").click
end
@@ -69,8 +68,22 @@ module PageObjects
end
def bookmark_message(message)
- hover_message(message)
- find(".bookmark-btn").click
+ if page.has_css?("html.mobile-view", wait: 0)
+ click_message_action_mobile(message, "bookmark")
+ else
+ hover_message(message)
+ find(".bookmark-btn").click
+ end
+ end
+
+ def select_message(message)
+ if page.has_css?("html.mobile-view", wait: 0)
+ click_message_action_mobile(message, "select")
+ else
+ hover_message(message)
+ click_more_button
+ find("[data-value='select']").click
+ end
end
def click_more_button
@@ -95,12 +108,6 @@ module PageObjects
find("[data-value='flag']").click
end
- def select_message(message)
- hover_message(message)
- click_more_button
- find("[data-value='select']").click
- end
-
def delete_message(message)
hover_message(message)
click_more_button
@@ -125,6 +132,7 @@ module PageObjects
click_send_message
click_composer
has_no_loading_skeleton?
+ text
end
def reply_to(message)
diff --git a/plugins/chat/spec/system/page_objects/chat/chat_thread.rb b/plugins/chat/spec/system/page_objects/chat/chat_thread.rb
index ab7f396e10e..794d1b2982f 100644
--- a/plugins/chat/spec/system/page_objects/chat/chat_thread.rb
+++ b/plugins/chat/spec/system/page_objects/chat/chat_thread.rb
@@ -63,6 +63,7 @@ module PageObjects
fill_composer(text)
click_send_message
click_composer
+ text
end
def click_send_message
diff --git a/plugins/chat/spec/system/page_objects/chat/components/composer.rb b/plugins/chat/spec/system/page_objects/chat/components/composer.rb
index 3c3306893fa..5386c905ef4 100644
--- a/plugins/chat/spec/system/page_objects/chat/components/composer.rb
+++ b/plugins/chat/spec/system/page_objects/chat/components/composer.rb
@@ -8,6 +8,8 @@ module PageObjects
SELECTOR = ".chat-composer__wrapper"
+ MODIFIER = RUBY_PLATFORM =~ /darwin/i ? :meta : :control
+
def initialize(context)
@context = context
end
@@ -20,6 +22,10 @@ module PageObjects
find(context).find(SELECTOR).find(".chat-composer__input")
end
+ def fill_in(**args)
+ input.fill_in(**args)
+ end
+
def value
input.value
end
@@ -32,12 +38,24 @@ module PageObjects
input.send_keys(%i[arrow_up])
end
+ def emphasized_text_shortcut
+ input.send_keys([MODIFIER, "i"])
+ end
+
+ def indented_text_shortcut
+ input.send_keys([MODIFIER, "e"])
+ end
+
+ def bold_text_shortcut
+ input.send_keys([MODIFIER, "b"])
+ end
+
def open_emoji_picker
find(context).find(SELECTOR).find(".chat-composer-button__btn.emoji").click
end
def editing_message?(message)
- value == message.message && message_details.editing_message?(message)
+ value == message.message && message_details.editing?(message)
end
end
end
diff --git a/plugins/chat/spec/system/page_objects/chat/components/composer_message_details.rb b/plugins/chat/spec/system/page_objects/chat/components/composer_message_details.rb
index 694f1012401..c619ae4e0f4 100644
--- a/plugins/chat/spec/system/page_objects/chat/components/composer_message_details.rb
+++ b/plugins/chat/spec/system/page_objects/chat/components/composer_message_details.rb
@@ -12,18 +12,29 @@ module PageObjects
@context = context
end
- def has_message?(message, action: nil)
- data_attributes = "[data-id=\"#{message.id}\"]"
- data_attributes << "[data-action=\"#{action}\"]" if action
- find(context).find(SELECTOR + data_attributes)
+ def component
+ find(context)
end
- def has_no_message?
- find(context).has_no_css?(SELECTOR)
+ def has_message?(**args)
+ selectors = SELECTOR
+ selectors += "[data-id=\"#{args[:id]}\"]" if args[:id]
+ selectors += "[data-action=\"#{args[:action]}\"]" if args[:action]
+ selector_method = args[:does_not_exist] ? :has_no_selector? : :has_selector?
+
+ component.send(selector_method, selectors)
end
- def editing_message?(message)
- has_message?(message, action: :edit)
+ def has_no_message?(**args)
+ has_message?(**args, does_not_exist: true)
+ end
+
+ def editing?(message)
+ has_message?(id: message.id, action: :edit)
+ end
+
+ def replying_to?(message)
+ has_message?(id: message.id, action: :reply)
end
end
end
diff --git a/plugins/chat/spec/system/page_objects/chat/components/message.rb b/plugins/chat/spec/system/page_objects/chat/components/message.rb
index 4b656e68bf4..7bb9c0c8e78 100644
--- a/plugins/chat/spec/system/page_objects/chat/components/message.rb
+++ b/plugins/chat/spec/system/page_objects/chat/components/message.rb
@@ -17,18 +17,22 @@ module PageObjects
end
def exists?(**args)
+ text = args[:text]
+
selectors = SELECTOR
selectors += "[data-id=\"#{args[:id]}\"]" if args[:id]
selectors += ".is-persisted" if args[:persisted]
selectors += ".is-staged" if args[:staged]
+
+ if args[:deleted]
+ selectors += ".is-deleted"
+ text = I18n.t("js.chat.deleted", count: args[:deleted])
+ end
+
selector_method = args[:does_not_exist] ? :has_no_selector? : :has_selector?
- if args[:text]
- find(context).send(
- selector_method,
- selectors + " " + ".chat-message-text",
- text: args[:text],
- )
+ if text
+ find(context).send(selector_method, selectors + " " + ".chat-message-text", text: text)
else
find(context).send(selector_method, selectors)
end
diff --git a/plugins/chat/spec/system/page_objects/chat/components/messages.rb b/plugins/chat/spec/system/page_objects/chat/components/messages.rb
index 42046ce01dd..a496369a5db 100644
--- a/plugins/chat/spec/system/page_objects/chat/components/messages.rb
+++ b/plugins/chat/spec/system/page_objects/chat/components/messages.rb
@@ -6,7 +6,7 @@ module PageObjects
class Messages < PageObjects::Components::Base
attr_reader :context
- SELECTOR = ".chat-message-container"
+ SELECTOR = ".chat-messages-scroll"
def initialize(context)
@context = context
@@ -16,16 +16,16 @@ module PageObjects
find(context)
end
+ def message
+ PageObjects::Components::Chat::Message.new(context + " " + SELECTOR)
+ end
+
def has_message?(**args)
- PageObjects::Components::Chat::Message.new(".chat-channel").exists?(**args)
+ message.exists?(**args)
end
def has_no_message?(**args)
- PageObjects::Components::Chat::Message.new(".chat-channel").does_not_exist?(**args)
- end
-
- def has_x_messages?(count)
- find(context).has_css?(SELECTOR, count: count, visible: :all)
+ message.does_not_exist?(**args)
end
end
end
diff --git a/plugins/chat/spec/system/reply_to_message/mobile_spec.rb b/plugins/chat/spec/system/reply_to_message/mobile_spec.rb
index e5c188753fe..3cc2fd9bebf 100644
--- a/plugins/chat/spec/system/reply_to_message/mobile_spec.rb
+++ b/plugins/chat/spec/system/reply_to_message/mobile_spec.rb
@@ -27,10 +27,9 @@ RSpec.describe "Reply to message - channel - mobile", type: :system, js: true, m
expect(side_panel_page).to have_open_thread
- thread_page.fill_composer("reply to message")
- thread_page.click_send_message
+ text = thread_page.send_message
- expect(thread_page).to have_message(text: "reply to message")
+ expect(thread_page.messages).to have_message(text: text, persisted: true)
thread_page.close
diff --git a/plugins/chat/spec/system/shortcuts/chat_composer_spec.rb b/plugins/chat/spec/system/shortcuts/chat_composer_spec.rb
deleted file mode 100644
index 624851f28da..00000000000
--- a/plugins/chat/spec/system/shortcuts/chat_composer_spec.rb
+++ /dev/null
@@ -1,129 +0,0 @@
-# frozen_string_literal: true
-
-RSpec.describe "Shortcuts | chat composer", type: :system, js: true do
- fab!(:channel_1) { Fabricate(:chat_channel) }
- fab!(:current_user) { Fabricate(:user) }
-
- let(:chat) { PageObjects::Pages::Chat.new }
- let(:channel_page) { PageObjects::Pages::ChatChannel.new }
- let(:key_modifier) { RUBY_PLATFORM =~ /darwin/i ? :meta : :control }
-
- before do
- chat_system_bootstrap
- channel_1.add(current_user)
- sign_in(current_user)
- end
-
- context "when using meta + l" do
- xit "handles insert link shortcut" do
- end
- end
-
- context "when using meta + b" do
- it "adds bold text" do
- chat.visit_channel(channel_1)
-
- composer = find(".chat-composer__input")
- composer.send_keys([key_modifier, "b"])
-
- expect(composer.value).to eq("**strong text**")
- end
- end
-
- context "when using meta + i" do
- it "adds italic text" do
- chat.visit_channel(channel_1)
-
- composer = find(".chat-composer__input")
- composer.send_keys([key_modifier, "i"])
-
- expect(composer.value).to eq("_emphasized text_")
- end
- end
-
- context "when using meta + e" do
- it "adds preformatted text" do
- chat.visit_channel(channel_1)
-
- composer = find(".chat-composer__input")
- composer.send_keys([key_modifier, "e"])
-
- expect(composer.value).to eq("`indent preformatted text by 4 spaces`")
- end
- end
-
- context "when the thread panel is also open" do
- fab!(:user_2) { Fabricate(:user) }
- fab!(:thread) do
- chat_thread_chain_bootstrap(
- channel: channel_1,
- users: [current_user, user_2],
- messages_count: 2,
- )
- end
-
- before do
- SiteSetting.enable_experimental_chat_threaded_discussions = true
- channel_1.update!(threading_enabled: true)
- end
-
- it "directs the shortcut to the focused composer" do
- chat.visit_channel(channel_1)
- channel_page.message_thread_indicator(thread.original_message).click
-
- composer = find(".chat-channel .chat-composer__input")
- thread_composer = find(".chat-thread .chat-composer__input")
- composer.send_keys([key_modifier, "i"])
-
- expect(composer.value).to eq("_emphasized text_")
- expect(thread_composer.value).to eq("")
-
- composer.fill_in(with: "")
- thread_composer.fill_in(with: "")
-
- thread_composer.send_keys([key_modifier, "i"])
-
- expect(composer.value).to eq("")
- expect(thread_composer.value).to eq("_emphasized text_")
- end
- end
-
- context "when using ArrowUp" do
- fab!(:message_1) do
- Fabricate(:chat_message, message: "message 1", chat_channel: channel_1, user: current_user)
- end
- fab!(:message_2) { Fabricate(:chat_message, message: "message 2", chat_channel: channel_1) }
-
- it "edits last editable message" do
- chat.visit_channel(channel_1)
-
- find(".chat-composer__input").send_keys(:arrow_up)
-
- expect(page.find(".chat-composer-message-details")).to have_content(message_1.message)
- end
-
- context "when last message is not editable" do
- it "does not edit a message" do
- chat.visit_channel(channel_1)
- page.driver.browser.network_conditions = { offline: true }
- channel_page.send_message("Hello world")
-
- find(".chat-composer__input").send_keys(:arrow_up)
-
- expect(page).to have_no_css(".chat-composer-message-details")
-
- page.driver.browser.network_conditions = { offline: false }
- end
- end
-
- context "with shift" do
- it "starts replying to the last message" do
- chat.visit_channel(channel_1)
-
- find(".chat-composer__input").send_keys(%i[shift arrow_up])
-
- expect(channel_page).to be_replying_to(message_2)
- end
- end
- end
-end
diff --git a/plugins/chat/spec/system/single_thread_spec.rb b/plugins/chat/spec/system/single_thread_spec.rb
index 7cd8eafceea..d109ce69fb8 100644
--- a/plugins/chat/spec/system/single_thread_spec.rb
+++ b/plugins/chat/spec/system/single_thread_spec.rb
@@ -183,6 +183,7 @@ describe "Single thread in side panel", type: :system, js: true do
it "opens the side panel for a single thread using the indicator", mobile: true do
chat_page.visit_channel(channel)
channel_page.message_thread_indicator(thread.original_message).click
+
expect(side_panel).to have_open_thread(thread)
end
end
diff --git a/plugins/chat/spec/system/transcript_spec.rb b/plugins/chat/spec/system/transcript_spec.rb
index e0ff76d3f7d..aa4fafbd041 100644
--- a/plugins/chat/spec/system/transcript_spec.rb
+++ b/plugins/chat/spec/system/transcript_spec.rb
@@ -181,8 +181,7 @@ RSpec.describe "Quoting chat message transcripts", type: :system, js: true do
it "first navigates to the channel's category before opening the topic composer with the quote prefilled",
mobile: true do
chat_page.visit_channel(chat_channel_1)
-
- chat_channel_page.click_message_action_mobile(message_1, "select")
+ chat_channel_page.select_message(message_1)
click_selection_button("quote")
expect(topic_page).to have_expanded_composer