Restructure omni services and add Chatwoot research snapshot
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::Copilot::GetArticleService do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:service) { described_class.new(assistant, user: user) }
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('get_article')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the service description' do
|
||||
expect(service.description).to eq('Get details of an article including its content and metadata')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'defines article_id parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:article_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when user is an admin' do
|
||||
let(:user) { create(:user, :administrator, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role with knowledge_base_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['knowledge_base_manage']) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role without knowledge_base_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: []) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when article_id is blank' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute(article_id: nil)).to eq('Article not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when article is not found' do
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(article_id: 999)).to eq('Article not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when article exists' do
|
||||
let(:portal) { create(:portal, account: account) }
|
||||
let(:article) { create(:article, account: account, portal: portal, author: user, title: 'Test Article', content: 'Content') }
|
||||
|
||||
it 'returns the article in llm text format' do
|
||||
result = service.execute(article_id: article.id)
|
||||
expect(result).to eq(article.to_llm_text)
|
||||
end
|
||||
|
||||
context 'when article belongs to different account' do
|
||||
let(:other_account) { create(:account) }
|
||||
let(:other_portal) { create(:portal, account: other_account) }
|
||||
let(:other_article) { create(:article, account: other_account, portal: other_portal, author: user, title: 'Other Article') }
|
||||
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(article_id: other_article.id)).to eq('Article not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,99 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::Copilot::GetContactService do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:service) { described_class.new(assistant, user: user) }
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('get_contact')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the service description' do
|
||||
expect(service.description).to eq('Get details of a contact including their profile information')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'defines contact_id parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:contact_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when user is an admin' do
|
||||
let(:user) { create(:user, :administrator, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role with contact_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['contact_manage']) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role without contact_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: []) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when contact_id is blank' do
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(contact_id: nil)).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when contact is not found' do
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(contact_id: 999)).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when contact exists' do
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
|
||||
it 'returns the contact in llm text format' do
|
||||
result = service.execute(contact_id: contact.id)
|
||||
expect(result).to eq(contact.to_llm_text)
|
||||
end
|
||||
|
||||
context 'when contact belongs to different account' do
|
||||
let(:other_account) { create(:account) }
|
||||
let(:other_contact) { create(:contact, account: other_account) }
|
||||
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(contact_id: other_contact.id)).to eq('Contact not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,148 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::Copilot::GetConversationService do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:service) { described_class.new(assistant, user: user) }
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('get_conversation')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the service description' do
|
||||
expect(service.description).to eq('Get details of a conversation including messages and contact information')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'defines conversation_id parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:conversation_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when user is an admin' do
|
||||
let(:user) { create(:user, :administrator, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role with conversation_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['conversation_manage']) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role with conversation_unassigned_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['conversation_unassigned_manage']) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role with conversation_participating_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['conversation_participating_manage']) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role without any conversation permissions' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: []) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when conversation is not found' do
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(conversation_id: 999)).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when conversation exists' do
|
||||
let(:inbox) { create(:inbox, account: account) }
|
||||
let(:conversation) { create(:conversation, account: account, inbox: inbox) }
|
||||
|
||||
it 'returns the conversation in llm text format' do
|
||||
result = service.execute(conversation_id: conversation.display_id)
|
||||
expect(result).to eq(conversation.to_llm_text)
|
||||
end
|
||||
|
||||
it 'includes private messages in the llm text format' do
|
||||
# Create a regular message
|
||||
create(:message,
|
||||
conversation: conversation,
|
||||
message_type: 'outgoing',
|
||||
content: 'Regular message',
|
||||
private: false)
|
||||
|
||||
# Create a private message
|
||||
create(:message,
|
||||
conversation: conversation,
|
||||
message_type: 'outgoing',
|
||||
content: 'Private note content',
|
||||
private: true)
|
||||
|
||||
result = service.execute(conversation_id: conversation.display_id)
|
||||
|
||||
# Verify that the result includes both regular and private messages
|
||||
expect(result).to include('Regular message')
|
||||
expect(result).to include('Private note content')
|
||||
expect(result).to include('[Private Note]')
|
||||
end
|
||||
|
||||
context 'when conversation belongs to different account' do
|
||||
let(:other_account) { create(:account) }
|
||||
let(:other_inbox) { create(:inbox, account: other_account) }
|
||||
let(:other_conversation) { create(:conversation, account: other_account, inbox: other_inbox) }
|
||||
|
||||
it 'returns not found message' do
|
||||
expect(service.execute(conversation_id: other_conversation.display_id)).to eq('Conversation not found')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,115 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::Copilot::SearchArticlesService do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:service) { described_class.new(assistant, user: user) }
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('search_articles')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the service description' do
|
||||
expect(service.description).to eq('Search articles based on parameters')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when user is an admin' do
|
||||
let(:user) { create(:user, :administrator, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is an agent' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role with knowledge_base_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['knowledge_base_manage']) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has custom role without knowledge_base_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: []) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when no articles are found' do
|
||||
it 'returns no articles found message' do
|
||||
expect(service.execute(query: 'test', category_id: nil, status: nil)).to eq('No articles found')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when articles are found' do
|
||||
let(:portal) { create(:portal, account: account) }
|
||||
let!(:article1) { create(:article, account: account, portal: portal, author: user, title: 'Test Article 1', content: 'Content 1') }
|
||||
let!(:article2) { create(:article, account: account, portal: portal, author: user, title: 'Test Article 2', content: 'Content 2') }
|
||||
|
||||
it 'returns formatted articles with count' do
|
||||
result = service.execute(query: 'Test', category_id: nil, status: nil)
|
||||
expect(result).to include('Total number of articles: 2')
|
||||
expect(result).to include(article1.to_llm_text)
|
||||
expect(result).to include(article2.to_llm_text)
|
||||
end
|
||||
|
||||
context 'when filtered by category' do
|
||||
let(:category) { create(:category, slug: 'test-category', portal: portal, account: account) }
|
||||
let!(:article3) { create(:article, account: account, portal: portal, author: user, category: category, title: 'Test Article 3') }
|
||||
|
||||
it 'returns only articles from the specified category' do
|
||||
result = service.execute(query: 'Test', category_id: category.id, status: nil)
|
||||
expect(result).to include('Total number of articles: 1')
|
||||
expect(result).to include(article3.to_llm_text)
|
||||
expect(result).not_to include(article1.to_llm_text)
|
||||
expect(result).not_to include(article2.to_llm_text)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when filtered by status' do
|
||||
let!(:article3) { create(:article, account: account, portal: portal, author: user, title: 'Test Article 3', status: 'published') }
|
||||
let!(:article4) { create(:article, account: account, portal: portal, author: user, title: 'Test Article 4', status: 'draft') }
|
||||
|
||||
it 'returns only articles with the specified status' do
|
||||
result = service.execute(query: 'Test', category_id: nil, status: 'published')
|
||||
expect(result).to include(article3.to_llm_text)
|
||||
expect(result).not_to include(article4.to_llm_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,94 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::Copilot::SearchContactsService do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:service) { described_class.new(assistant, user: user) }
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('search_contacts')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the service description' do
|
||||
expect(service.description).to eq('Search contacts based on query parameters')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'defines email, phone_number, and name parameters' do
|
||||
expect(service.parameters.keys).to contain_exactly(:email, :phone_number, :name)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when user has contact_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['contact_manage']) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user does not have contact_manage permission' do
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: []) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when contacts are found' do
|
||||
let(:contact1) { create(:contact, account: account, email: 'test1@example.com', name: 'Test Contact 1', phone_number: '+1234567890') }
|
||||
let(:contact2) { create(:contact, account: account, email: 'test2@example.com', name: 'Test Contact 2', phone_number: '+1234567891') }
|
||||
|
||||
before do
|
||||
contact1
|
||||
contact2
|
||||
end
|
||||
|
||||
it 'returns contacts when filtered by email' do
|
||||
result = service.execute(email: 'test1@example.com')
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).not_to include(contact2.to_llm_text)
|
||||
end
|
||||
|
||||
it 'returns contacts when filtered by phone number' do
|
||||
result = service.execute(phone_number: '+1234567890')
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).not_to include(contact2.to_llm_text)
|
||||
end
|
||||
|
||||
it 'returns contacts when filtered by name' do
|
||||
result = service.execute(name: 'Contact 1')
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).not_to include(contact2.to_llm_text)
|
||||
end
|
||||
|
||||
it 'returns all matching contacts when no filters are provided' do
|
||||
result = service.execute
|
||||
expect(result).to include(contact1.to_llm_text)
|
||||
expect(result).to include(contact2.to_llm_text)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,160 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::Copilot::SearchConversationsService do
|
||||
let(:account) { create(:account) }
|
||||
let(:user) { create(:user, role: 'administrator', account: account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:service) { described_class.new(assistant, user: user) }
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('search_conversation')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the service description' do
|
||||
expect(service.description).to eq('Search conversations based on parameters')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'defines the expected parameters' do
|
||||
expect(service.parameters.keys).to contain_exactly(:status, :contact_id, :priority, :labels)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when user has conversation_manage permission' do
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['conversation_manage']) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has conversation_unassigned_manage permission' do
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['conversation_unassigned_manage']) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has conversation_participating_manage permission' do
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: ['conversation_participating_manage']) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has no relevant conversation permissions' do
|
||||
let(:custom_role) { create(:custom_role, account: account, permissions: []) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
|
||||
before do
|
||||
account_user = AccountUser.find_by(user: user, account: account)
|
||||
account_user.update(role: :agent, custom_role: custom_role)
|
||||
end
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
let(:contact) { create(:contact, account: account) }
|
||||
let!(:open_conversation) { create(:conversation, account: account, contact: contact, status: 'open', priority: 'high') }
|
||||
let!(:resolved_conversation) { create(:conversation, account: account, status: 'resolved', priority: 'low') }
|
||||
|
||||
it 'returns all conversations when no filters are applied' do
|
||||
result = service.execute
|
||||
expect(result).to include('Total number of conversations: 2')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'filters conversations by status' do
|
||||
result = service.execute(status: 'open')
|
||||
expect(result).to include('Total number of conversations: 1')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).not_to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'filters conversations by contact_id' do
|
||||
result = service.execute(contact_id: contact.id)
|
||||
expect(result).to include('Total number of conversations: 1')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).not_to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'filters conversations by priority' do
|
||||
result = service.execute(priority: 'high')
|
||||
expect(result).to include('Total number of conversations: 1')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).not_to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'returns appropriate message when no conversations are found' do
|
||||
result = service.execute(status: 'snoozed')
|
||||
expect(result).to eq('No conversations found')
|
||||
end
|
||||
|
||||
context 'when invalid status is provided' do
|
||||
it 'ignores invalid status and returns all conversations' do
|
||||
result = service.execute(status: 'all')
|
||||
expect(result).to include('Total number of conversations: 2')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'ignores random invalid status values' do
|
||||
result = service.execute(status: 'invalid_status')
|
||||
expect(result).to include('Total number of conversations: 2')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when invalid priority is provided' do
|
||||
it 'ignores invalid priority and returns all conversations' do
|
||||
result = service.execute(priority: 'all')
|
||||
expect(result).to include('Total number of conversations: 2')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
|
||||
it 'ignores random invalid priority values' do
|
||||
result = service.execute(priority: 'invalid_priority')
|
||||
expect(result).to include('Total number of conversations: 2')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when combining valid and invalid parameters' do
|
||||
it 'applies valid filters and ignores invalid ones' do
|
||||
result = service.execute(status: 'all', contact_id: contact.id)
|
||||
expect(result).to include('Total number of conversations: 1')
|
||||
expect(result).to include(open_conversation.to_llm_text(include_contact_details: true))
|
||||
expect(result).not_to include(resolved_conversation.to_llm_text(include_contact_details: true))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,139 @@
|
||||
require 'rails_helper'
|
||||
|
||||
RSpec.describe Captain::Tools::Copilot::SearchLinearIssuesService do
|
||||
let(:account) { create(:account) }
|
||||
let(:assistant) { create(:captain_assistant, account: account) }
|
||||
let(:user) { create(:user, account: account) }
|
||||
let(:service) { described_class.new(assistant, user: user) }
|
||||
|
||||
describe '#name' do
|
||||
it 'returns the correct service name' do
|
||||
expect(service.name).to eq('search_linear_issues')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#description' do
|
||||
it 'returns the service description' do
|
||||
expect(service.description).to eq('Search Linear issues based on a search term')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parameters' do
|
||||
it 'defines term parameter' do
|
||||
expect(service.parameters.keys).to contain_exactly(:term)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#active?' do
|
||||
context 'when Linear integration is enabled' do
|
||||
before do
|
||||
create(:integrations_hook, :linear, account: account)
|
||||
end
|
||||
|
||||
context 'when user is present' do
|
||||
it 'returns true' do
|
||||
expect(service.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not present' do
|
||||
let(:service) { described_class.new(assistant) }
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Linear integration is not enabled' do
|
||||
context 'when user is present' do
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user is not present' do
|
||||
let(:service) { described_class.new(assistant) }
|
||||
|
||||
it 'returns false' do
|
||||
expect(service.active?).to be false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
context 'when Linear integration is not enabled' do
|
||||
it 'returns error message' do
|
||||
expect(service.execute(term: 'test')).to eq('Linear integration is not enabled')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when Linear integration is enabled' do
|
||||
let(:linear_service) { instance_double(Integrations::Linear::ProcessorService) }
|
||||
|
||||
before do
|
||||
create(:integrations_hook, :linear, account: account)
|
||||
allow(Integrations::Linear::ProcessorService).to receive(:new).and_return(linear_service)
|
||||
end
|
||||
|
||||
context 'when term is blank' do
|
||||
before do
|
||||
allow(linear_service).to receive(:search_issue).with('').and_return({ data: [] })
|
||||
end
|
||||
|
||||
it 'returns no issues found message' do
|
||||
expect(service.execute(term: '')).to eq('No issues found, I should try another similar search term')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when search returns error' do
|
||||
before do
|
||||
allow(linear_service).to receive(:search_issue).and_return({ error: 'API Error' })
|
||||
end
|
||||
|
||||
it 'returns the error message' do
|
||||
expect(service.execute(term: 'test')).to eq('API Error')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when search returns no issues' do
|
||||
before do
|
||||
allow(linear_service).to receive(:search_issue).and_return({ data: [] })
|
||||
end
|
||||
|
||||
it 'returns no issues found message' do
|
||||
expect(service.execute(term: 'test')).to eq('No issues found, I should try another similar search term')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when search returns issues' do
|
||||
let(:issues) do
|
||||
[{
|
||||
'title' => 'Test Issue',
|
||||
'id' => 'TEST-123',
|
||||
'state' => { 'name' => 'In Progress' },
|
||||
'priority' => 4,
|
||||
'assignee' => { 'name' => 'John Doe' },
|
||||
'description' => 'Test description'
|
||||
}]
|
||||
end
|
||||
|
||||
before do
|
||||
allow(linear_service).to receive(:search_issue).and_return({ data: issues })
|
||||
end
|
||||
|
||||
it 'returns formatted issues' do
|
||||
result = service.execute(term: 'test')
|
||||
expect(result).to include('Total number of issues: 1')
|
||||
expect(result).to include('Title: Test Issue')
|
||||
expect(result).to include('ID: TEST-123')
|
||||
expect(result).to include('State: In Progress')
|
||||
expect(result).to include('Priority: Low')
|
||||
expect(result).to include('Assignee: John Doe')
|
||||
expect(result).to include('Description: Test description')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user