discourse-chat-integration/spec/lib/discourse_chat/provider/slack/slack_transcript_spec.rb

338 lines
12 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# frozen_string_literal: true
require 'rails_helper'
RSpec.describe DiscourseChat::Provider::SlackProvider::SlackTranscript do
let(:messages_fixture) {
[
{
"type": "message",
"user": "U6JSSESES",
"text": "Yeah, should make posting slack transcripts much easier",
"ts": "1501801665.062694"
},
{
"type": "message",
"user": "U5Z773QLZ",
"text": "Oooh a new discourse plugin <@U5Z773QLS> ???",
"ts": "1501801643.056375"
},
{
"type": "message",
"user": "U6E2W7R8C",
"text": "Which one?",
"ts": "1501801635.053761"
},
{
"type": "message",
"user": "U6JSSESES",
"text": "So, who's interested in the new <https://meta.discourse.org|discourse plugin>?",
"ts": "1501801629.052212"
},
{
"type": "message",
"user": "U820GH3LA",
"text": "I'm interested!!",
"ts": "1501801634.053761",
"thread_ts": "1501801629.052212"
},
{
"text": "Check this out!",
"username": "Test Community",
"bot_id": "B6C6JNUDN",
"attachments": [
{
"author_name": "@david",
"fallback": "Discourse can now be integrated with Mattermost! - @david",
"text": "Hey <http://localhost/groups/team|@team>, what do you think about this?",
"title": "Discourse can now be integrated with Mattermost! [Announcements] ",
"id": 1,
"title_link": "http://localhost:3000/t/discourse-can-now-be-integrated-with-mattermost/51/4",
"color": "283890",
"mrkdwn_in": [
"text"
]
}
],
"type": "message",
"subtype": "bot_message",
"ts": "1501615820.949638"
},
{
"type": "message",
"user": "U5Z773QLS",
"text": "Lets try some *bold text* <@U5Z773QLZ> <@someotheruser>",
"ts": "1501093331.439776"
},
]
}
let(:users_fixture) {
[
{
id: "U6JSSESES",
name: "threader",
profile: {
image_24: "https://example.com/avatar",
display_name: "Threader",
real_name: "A. Threader"
}
},
{
id: "U820GH3LA",
name: "responder",
profile: {
image_24: "https://example.com/avatar",
display_name: "Responder",
real_name: "A. Responder"
}
},
{
id: "U5Z773QLS",
name: "awesomeguyemail",
profile: {
image_24: "https://example.com/avatar",
display_name: "awesomeguy",
real_name: "actually just a guy"
}
},
{
id: "U5Z773QLZ",
name: "otherguyemail",
profile: {
image_24: "https://example.com/avatar",
display_name: "",
real_name: "another guy"
}
}
]
}
let(:transcript) { described_class.new(channel_name: "#general", channel_id: "G1234") }
before do
SiteSetting.chat_integration_slack_access_token = "abcde"
end
it "doesn't raise an error when there are no messages to guess" do
transcript.instance_variable_set(:@messages, [])
expect(transcript.guess_first_message(skip_messages: 1)).to eq(false)
end
describe 'loading users' do
it 'loads users correctly' do
stub_request(:post, "https://slack.com/api/users.list")
.with(body: { token: "abcde", "cursor": nil, "limit": "200" })
.to_return(status: 200, body: { ok: true, members: users_fixture, response_metadata: { next_cursor: "" } }.to_json)
expect(transcript.load_user_data).to be_truthy
end
it 'handles failed connection' do
stub_request(:post, "https://slack.com/api/users.list")
.to_return(status: 500, body: '')
expect(transcript.load_user_data).to be_falsey
end
it 'handles slack failure' do
stub_request(:post, "https://slack.com/api/users.list")
.to_return(status: 200, body: { ok: false }.to_json)
expect(transcript.load_user_data).to be_falsey
end
end
context 'with loaded users' do
before do
stub_request(:post, "https://slack.com/api/users.list")
.to_return(status: 200, body: { ok: true, members: users_fixture, response_metadata: { next_cursor: "" } }.to_json)
transcript.load_user_data
end
describe 'loading history' do
it 'loads messages correctly' do
stub_request(:post, "https://slack.com/api/conversations.history")
.with(body: hash_including(token: "abcde", channel: 'G1234'))
.to_return(status: 200, body: { ok: true, messages: messages_fixture }.to_json)
expect(transcript.load_chat_history).to be_truthy
end
it 'handles failed connection' do
stub_request(:post, "https://slack.com/api/conversations.history")
.to_return(status: 500, body: {}.to_json)
expect(transcript.load_chat_history).to be_falsey
end
it 'handles slack failure' do
stub_request(:post, "https://slack.com/api/conversations.history")
.to_return(status: 200, body: { ok: false }.to_json)
expect(transcript.load_chat_history).to be_falsey
end
end
context 'with thread_ts specified' do
let(:thread_transcript) { described_class.new(channel_name: "#general", channel_id: "G1234", requested_thread_ts: "1501801629.052212") }
before do
thread_transcript.load_user_data
stub_request(:post, "https://slack.com/api/conversations.replies")
.with(body: hash_including(token: "abcde", channel: 'G1234', ts: "1501801629.052212"))
.to_return(status: 200, body: { ok: true, messages: messages_fixture[3..4] }.to_json)
thread_transcript.load_chat_history
end
it 'includes messages in a thread' do
expect(thread_transcript.messages.length).to eq(2)
end
it 'loads in chronological order' do # replies API presents messages in actual chronological order
expect(thread_transcript.messages.first.ts).to eq('1501801629.052212')
end
it 'includes slack thread identifiers in body' do
text = thread_transcript.build_transcript
expect(text).to include("<!--SLACK_CHANNEL_ID=G1234;SLACK_TS=1501801629.052212-->")
end
end
context 'with loaded messages' do
before do
stub_request(:post, "https://slack.com/api/conversations.history")
.with(body: hash_including(token: "abcde", channel: 'G1234'))
.to_return(status: 200, body: { ok: true, messages: messages_fixture }.to_json)
transcript.load_chat_history
end
it 'ignores messages in a thread' do
expect(transcript.messages.length).to eq(6)
end
it 'loads in chronological order' do # API presents in reverse chronological
expect(transcript.messages.first.ts).to eq('1501093331.439776')
end
it 'handles bold text' do
expect(transcript.messages.first.text).to start_with("Lets try some **bold text** ")
end
it 'handles links' do
expect(transcript.messages[2].text).to eq("So, who's interested in the new [discourse plugin](https://meta.discourse.org)?")
end
it 'includes attachments' do
expect(transcript.messages[1].attachments.first).to eq("Discourse can now be integrated with Mattermost! - @david")
end
it 'can generate URL' do
expect(transcript.messages.first.url).to eq("https://slack.com/archives/G1234/p1501093331439776")
end
it 'includes attachments in raw text' do
transcript.set_first_message_by_ts('1501615820.949638')
expect(transcript.first_message.raw_text).to eq("Check this out!\n - Discourse can now be integrated with Mattermost! - @david\n")
end
it 'gives correct first and last messages' do
expect(transcript.first_message_number).to eq(0)
expect(transcript.last_message_number).to eq(transcript.messages.length - 1)
expect(transcript.first_message.ts).to eq('1501093331.439776')
expect(transcript.last_message.ts).to eq('1501801665.062694')
end
it 'can change first and last messages by index' do
expect(transcript.set_first_message_by_index(999)).to be_falsey
expect(transcript.set_first_message_by_index(1)).to be_truthy
expect(transcript.set_last_message_by_index(-2)).to be_truthy
expect(transcript.first_message.ts).to eq('1501615820.949638')
expect(transcript.last_message.ts).to eq('1501801643.056375')
end
it 'can change first and last messages by ts' do
expect(transcript.set_first_message_by_ts('blah')).to be_falsey
expect(transcript.set_first_message_by_ts('1501615820.949638')).to be_truthy
expect(transcript.set_last_message_by_ts('1501801629.052212')).to be_truthy
expect(transcript.first_message_number).to eq(1)
expect(transcript.last_message_number).to eq(2)
end
it 'can guess the first message' do
expect(transcript.guess_first_message(skip_messages: 1)).to eq(true)
expect(transcript.first_message.ts).to eq('1501801629.052212')
end
it 'handles usernames correctly' do
expect(transcript.first_message.username).to eq('awesomeguy') # Normal user
expect(transcript.messages[1].username).to eq('Test_Community') # Bot user
expect(transcript.messages[3].username).to eq(nil) # Unknown normal user
# Normal user, display_name not set (fall back to real_name)
expect(transcript.messages[4].username).to eq('another_guy')
end
it 'handles user mentions correctly' do
# User with display_name not set, unrecognized user
expect(transcript.first_message.text).to \
eq('Lets try some **bold text** @another_guy @someotheruser')
# Normal user
expect(transcript.messages[4].text).to \
eq('Oooh a new discourse plugin @awesomeguy ???')
end
it 'handles avatars correctly' do
expect(transcript.first_message.avatar).to eq("https://example.com/avatar") # Normal user
expect(transcript.messages[1].avatar).to eq(nil) # Bot user
end
it 'creates a transcript correctly' do
transcript.set_last_message_by_index(1)
text = transcript.build_transcript
expected = <<~END
[quote]
[**View in #general on Slack**](https://slack.com/archives/G1234/p1501093331439776)
![awesomeguy] **@awesomeguy:** Lets try some **bold text** @another_guy @someotheruser
**@Test_Community:** Check this out!
> Discourse can now be integrated with Mattermost! - @david
[/quote]
[awesomeguy]: https://example.com/avatar
END
expect(text).to eq(expected)
end
it 'creates the slack UI correctly' do
transcript.set_last_message_by_index(1)
ui = transcript.build_slack_ui
first_ui = ui[:attachments][0]
last_ui = ui[:attachments][1]
# The callback IDs are used to keep track of what the other option is
expect(first_ui[:callback_id]).to eq(transcript.last_message.ts)
expect(last_ui[:callback_id]).to eq(transcript.first_message.ts)
# The timestamps should match up to the actual messages
expect(first_ui[:ts]).to eq(transcript.first_message.ts)
expect(last_ui[:ts]).to eq(transcript.last_message.ts)
# Raw text should be used
expect(first_ui[:text]).to eq(transcript.first_message.raw_text)
end
end
end
end