DEV: Move chat transcript tests into system specs (#19434)
We are all in on system specs, so this commit moves all the chat quoting acceptance tests (some of which have been skipped for a while) into system specs.
This commit is contained in:
parent
641a1a6b44
commit
85b14a0359
|
@ -10,7 +10,7 @@
|
|||
<DButton @id="chat-move-to-channel-btn" @class="btn-secondary" @icon="sign-out-alt" @label="chat.selection.move_selection_to_channel" @title="chat.selection.move_selection_to_channel" @disabled={{not this.anyMessagesSelected}} @action={{action "openMoveMessageModal"}} />
|
||||
{{/if}}
|
||||
|
||||
<DButton @icon="times" @class="btn-secondary cancel-btn" @label="chat.selection.cancel" @title="chat.selection.cancel" @action={{this.cancelSelecting}} />
|
||||
<DButton @id="chat-cancel-selection-btn" @icon="times" @class="btn-secondary cancel-btn" @label="chat.selection.cancel" @title="chat.selection.cancel" @action={{this.cancelSelecting}} />
|
||||
</div>
|
||||
|
||||
{{#if this.showChatQuoteSuccess}}
|
||||
|
|
|
@ -83,6 +83,8 @@ export default {
|
|||
I18n.t("dates.long_no_year")
|
||||
);
|
||||
}
|
||||
|
||||
dateTimeEl.dataset.dateFormatted = true;
|
||||
});
|
||||
},
|
||||
{ id: "chat-transcript-datetime" }
|
||||
|
|
|
@ -23,6 +23,10 @@ module PageObjects
|
|||
has_no_css?(".chat-skeleton")
|
||||
end
|
||||
|
||||
def has_selection_management?
|
||||
has_css?(".chat-selection-management")
|
||||
end
|
||||
|
||||
def expand_message_actions(message)
|
||||
hover_message(message)
|
||||
click_more_buttons(message)
|
||||
|
|
|
@ -0,0 +1,245 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe "Quoting chat message transcripts", type: :system, js: true do
|
||||
fab!(:current_user) { Fabricate(:user) }
|
||||
fab!(:chat_channel_1) { Fabricate(:chat_channel) }
|
||||
|
||||
let(:chat_page) { PageObjects::Pages::Chat.new }
|
||||
let(:chat_channel_page) { PageObjects::Pages::ChatChannel.new }
|
||||
let(:topic_page) { PageObjects::Pages::Topic.new }
|
||||
|
||||
before do
|
||||
chat_system_bootstrap(Fabricate(:admin), [chat_channel_1])
|
||||
chat_channel_1.add(current_user)
|
||||
sign_in(current_user)
|
||||
end
|
||||
|
||||
def select_message_desktop(message)
|
||||
if page.has_css?(".chat-message-container.selecting-messages")
|
||||
chat_channel_page.message_by_id(message.id).find(".chat-message-selector").click
|
||||
else
|
||||
chat_channel_page.message_by_id(message.id).hover
|
||||
expect(page).to have_css(".chat-message-actions .more-buttons")
|
||||
find(".chat-message-actions .more-buttons").click
|
||||
find(".select-kit-row[data-value=\"selectMessage\"]").click
|
||||
end
|
||||
end
|
||||
|
||||
def select_message_mobile(message)
|
||||
if page.has_css?(".chat-message-container.selecting-messages")
|
||||
chat_channel_page.message_by_id(message.id).find(".chat-message-selector").click
|
||||
else
|
||||
chat_channel_page.message_by_id(message.id).click(delay: 0.5)
|
||||
find(".chat-message-action-item[data-id=\"selectMessage\"]").click
|
||||
end
|
||||
end
|
||||
|
||||
def cdp_allow_clipboard_access!
|
||||
cdp_params = {
|
||||
origin: page.server_url,
|
||||
permission: {
|
||||
name: "clipboard-read",
|
||||
},
|
||||
setting: "granted",
|
||||
}
|
||||
page.driver.browser.execute_cdp("Browser.setPermission", **cdp_params)
|
||||
|
||||
cdp_params = {
|
||||
origin: page.server_url,
|
||||
permission: {
|
||||
name: "clipboard-write",
|
||||
},
|
||||
setting: "granted",
|
||||
}
|
||||
page.driver.browser.execute_cdp("Browser.setPermission", **cdp_params)
|
||||
end
|
||||
|
||||
def read_clipboard
|
||||
page.evaluate_async_script("navigator.clipboard.readText().then(arguments[0])")
|
||||
end
|
||||
|
||||
def click_selection_button(button)
|
||||
selector =
|
||||
case button
|
||||
when "quote"
|
||||
"#chat-quote-btn"
|
||||
when "copy"
|
||||
"#chat-copy-btn"
|
||||
when "cancel"
|
||||
"#chat-cancel-selection-btn"
|
||||
when "move"
|
||||
"#chat-move-to-channel-btn"
|
||||
end
|
||||
within(".chat-selection-management-buttons") { find(selector).click }
|
||||
end
|
||||
|
||||
def copy_messages_to_clipboard(messages)
|
||||
messages = Array.wrap(messages)
|
||||
messages.each { |message| select_message_desktop(message) }
|
||||
expect(chat_channel_page).to have_selection_management
|
||||
click_selection_button("copy")
|
||||
expect(page).to have_content("Chat quote copied to clipboard")
|
||||
clip_text = read_clipboard
|
||||
expect(clip_text.chomp).to eq(generate_transcript(messages, current_user))
|
||||
clip_text
|
||||
end
|
||||
|
||||
def generate_transcript(messages, acting_user)
|
||||
messages = Array.wrap(messages)
|
||||
ChatTranscriptService
|
||||
.new(messages.first.chat_channel, acting_user, messages_or_ids: messages.map(&:id))
|
||||
.generate_markdown
|
||||
.chomp
|
||||
end
|
||||
|
||||
describe "copying quote transcripts with the clipboard" do
|
||||
before { cdp_allow_clipboard_access! }
|
||||
|
||||
context "when quoting a single message into a topic" do
|
||||
fab!(:post_1) { Fabricate(:post) }
|
||||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: chat_channel_1) }
|
||||
|
||||
it "quotes the message" do
|
||||
chat_page.visit_channel(chat_channel_1)
|
||||
|
||||
expect(chat_channel_page).to have_no_loading_skeleton
|
||||
|
||||
clip_text = copy_messages_to_clipboard(message_1)
|
||||
topic_page.visit_topic_and_open_composer(post_1.topic)
|
||||
topic_page.fill_in_composer("This is a new post!\n\n" + clip_text)
|
||||
|
||||
within(".d-editor-preview") { expect(page).to have_css(".chat-transcript") }
|
||||
|
||||
topic_page.send_reply
|
||||
selector = topic_page.post_by_number_selector(2)
|
||||
|
||||
expect(page).to have_css(selector)
|
||||
within(selector) { expect(page).to have_css(".chat-transcript") }
|
||||
end
|
||||
end
|
||||
|
||||
context "when quoting multiple messages into a topic" do
|
||||
fab!(:post_1) { Fabricate(:post) }
|
||||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: chat_channel_1) }
|
||||
fab!(:message_2) { Fabricate(:chat_message, chat_channel: chat_channel_1) }
|
||||
|
||||
it "quotes the messages" do
|
||||
chat_page.visit_channel(chat_channel_1)
|
||||
|
||||
expect(chat_channel_page).to have_no_loading_skeleton
|
||||
|
||||
clip_text = copy_messages_to_clipboard([message_1, message_2])
|
||||
topic_page.visit_topic_and_open_composer(post_1.topic)
|
||||
topic_page.fill_in_composer("This is a new post!\n\n" + clip_text)
|
||||
|
||||
within(".d-editor-preview") { expect(page).to have_css(".chat-transcript", count: 2) }
|
||||
expect(page).to have_content("Originally sent in #{chat_channel_1.name}")
|
||||
|
||||
topic_page.send_reply
|
||||
|
||||
selector = topic_page.post_by_number_selector(2)
|
||||
expect(page).to have_css(selector)
|
||||
within(selector) { expect(page).to have_css(".chat-transcript", count: 2) }
|
||||
end
|
||||
end
|
||||
|
||||
context "when quoting a message containing a onebox" do
|
||||
fab!(:post_1) { Fabricate(:post) }
|
||||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: chat_channel_1) }
|
||||
|
||||
before do
|
||||
Oneboxer.stubs(:preview).returns(
|
||||
"<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>",
|
||||
)
|
||||
message_1.update!(message: "http://www.example.com/has-title.html")
|
||||
message_1.rebake!
|
||||
end
|
||||
|
||||
it "works" do
|
||||
chat_page.visit_channel(chat_channel_1)
|
||||
|
||||
expect(chat_channel_page).to have_no_loading_skeleton
|
||||
|
||||
clip_text = copy_messages_to_clipboard(message_1)
|
||||
topic_page.visit_topic_and_open_composer(post_1.topic)
|
||||
topic_page.fill_in_composer(clip_text)
|
||||
|
||||
within(".chat-transcript-messages") do
|
||||
expect(page).to have_content("An interesting article")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when quoting a message in another message" do
|
||||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: chat_channel_1) }
|
||||
|
||||
it "quotes the message" do
|
||||
chat_page.visit_channel(chat_channel_1)
|
||||
|
||||
expect(chat_channel_page).to have_no_loading_skeleton
|
||||
|
||||
clip_text = copy_messages_to_clipboard(message_1)
|
||||
click_selection_button("cancel")
|
||||
chat_channel_page.fill_composer(clip_text)
|
||||
chat_channel_page.click_send_message
|
||||
|
||||
expect(page).to have_selector(".chat-message", count: 2)
|
||||
|
||||
message = ChatMessage.find_by(user: current_user, message: clip_text.chomp)
|
||||
|
||||
within(chat_channel_page.message_by_id(message.id)) do
|
||||
expect(page).to have_css(".chat-transcript")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when quoting into a topic directly" do
|
||||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: chat_channel_1) }
|
||||
let(:topic_title) { "Some topic title for testing" }
|
||||
|
||||
it "opens the topic composer with correct state" do
|
||||
chat_page.visit_channel(chat_channel_1)
|
||||
|
||||
expect(chat_channel_page).to have_no_loading_skeleton
|
||||
|
||||
select_message_desktop(message_1)
|
||||
click_selection_button("quote")
|
||||
|
||||
expect(topic_page).to have_expanded_composer
|
||||
expect(topic_page).to have_composer_content(generate_transcript(message_1, current_user))
|
||||
expect(page).to have_css(
|
||||
".category-input .select-kit-header[data-value='#{chat_channel_1.chatable.id}']",
|
||||
)
|
||||
expect(page).not_to have_current_path(chat_channel_1.chatable.url)
|
||||
|
||||
topic_page.fill_in_composer_title(topic_title)
|
||||
topic_page.send_reply
|
||||
|
||||
selector = topic_page.post_by_number_selector(1)
|
||||
expect(page).to have_css(selector)
|
||||
within(selector) { expect(page).to have_css(".chat-transcript") }
|
||||
|
||||
topic = Topic.find_by(user: current_user, title: topic_title)
|
||||
expect(page).to have_current_path(topic.url)
|
||||
end
|
||||
|
||||
context "when on mobile" 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)
|
||||
expect(chat_channel_page).to have_no_loading_skeleton
|
||||
|
||||
select_message_mobile(message_1)
|
||||
click_selection_button("quote")
|
||||
|
||||
expect(topic_page).to have_expanded_composer
|
||||
expect(topic_page).to have_composer_content(generate_transcript(message_1, current_user))
|
||||
expect(page).to have_current_path(chat_channel_1.chatable.url)
|
||||
expect(page).to have_css(
|
||||
".category-input .select-kit-header[data-value='#{chat_channel_1.chatable.id}']",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -245,6 +245,8 @@ RSpec.configure do |config|
|
|||
allow: [Webdrivers::Chromedriver.base_url]
|
||||
)
|
||||
|
||||
Capybara.disable_animation = true
|
||||
|
||||
Capybara.configure do |capybara_config|
|
||||
capybara_config.server_host = "localhost"
|
||||
capybara_config.server_port = 31337
|
||||
|
|
|
@ -25,6 +25,7 @@ module SystemHelpers
|
|||
SiteSetting.force_hostname = Capybara.server_host
|
||||
SiteSetting.port = Capybara.server_port
|
||||
SiteSetting.external_system_avatars_enabled = false
|
||||
SiteSetting.disable_avatar_education_message = true
|
||||
end
|
||||
|
||||
def try_until_success(timeout: 2, frequency: 0.01)
|
||||
|
|
|
@ -34,7 +34,11 @@ module PageObjects
|
|||
|
||||
def post_by_number(post_or_number)
|
||||
post_or_number = post_or_number.is_a?(Post) ? post_or_number.post_number : post_or_number
|
||||
find("#post_#{post_or_number}")
|
||||
find(".topic-post:not(.staged) #post_#{post_or_number}")
|
||||
end
|
||||
|
||||
def post_by_number_selector(post_number)
|
||||
".topic-post:not(.staged) #post_#{post_number}"
|
||||
end
|
||||
|
||||
def has_post_more_actions?(post)
|
||||
|
@ -74,24 +78,41 @@ module PageObjects
|
|||
|
||||
def click_reply_button
|
||||
find(".topic-footer-main-buttons > .create").click
|
||||
has_expanded_composer?
|
||||
end
|
||||
|
||||
def has_expanded_composer?
|
||||
has_css?("#reply-control.open")
|
||||
end
|
||||
|
||||
def find_composer
|
||||
find("#reply-control .d-editor .d-editor-input")
|
||||
end
|
||||
|
||||
def type_in_composer(input)
|
||||
find("#reply-control .d-editor .d-editor-input").send_keys(input)
|
||||
find_composer.send_keys(input)
|
||||
end
|
||||
|
||||
def fill_in_composer(input)
|
||||
find_composer.fill_in(with: input)
|
||||
end
|
||||
|
||||
def clear_composer
|
||||
find("#reply-control .d-editor .d-editor-input").set("")
|
||||
fill_in_composer("")
|
||||
end
|
||||
|
||||
def has_composer_content?(content)
|
||||
find_composer.value == content
|
||||
end
|
||||
|
||||
def send_reply
|
||||
find("#reply-control .save-or-cancel .create").click
|
||||
end
|
||||
|
||||
def fill_in_composer_title(title)
|
||||
find("#reply-title").fill_in(with: title)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def topic_footer_button_id(button)
|
||||
|
|
Loading…
Reference in New Issue