Restructure omni services and add Chatwoot research snapshot

This commit is contained in:
Ruslan Bakiev
2026-02-21 11:11:27 +07:00
parent edea7a0034
commit b73babbbf6
7732 changed files with 978203 additions and 32 deletions

View File

@@ -0,0 +1,138 @@
require 'rails_helper'
RSpec.describe InstagramConcern do
let(:dummy_class) { Class.new { include InstagramConcern } }
let(:dummy_instance) { dummy_class.new }
let(:client_id) { 'test_client_id' }
let(:client_secret) { 'test_client_secret' }
let(:short_lived_token) { 'short_lived_token' }
let(:long_lived_token) { 'long_lived_token' }
let(:access_token) { 'access_token' }
before do
allow(GlobalConfigService).to receive(:load).with('INSTAGRAM_APP_ID', nil).and_return(client_id)
allow(GlobalConfigService).to receive(:load).with('INSTAGRAM_APP_SECRET', nil).and_return(client_secret)
allow(Rails.logger).to receive(:error)
end
describe '#instagram_client' do
it 'creates an OAuth2 client with correct configuration', :aggregate_failures do
client = dummy_instance.instagram_client
expect(client).to be_a(OAuth2::Client)
expect(client.id).to eq(client_id)
expect(client.secret).to eq(client_secret)
expect(client.site).to eq('https://api.instagram.com')
expect(client.options[:authorize_url]).to eq('https://api.instagram.com/oauth/authorize')
expect(client.options[:token_url]).to eq('https://api.instagram.com/oauth/access_token')
expect(client.options[:auth_scheme]).to eq(:request_body)
expect(client.options[:token_method]).to eq(:post)
end
end
describe '#exchange_for_long_lived_token' do
let(:response_body) { { 'access_token' => long_lived_token, 'expires_in' => 5_184_000 }.to_json }
let(:mock_response) { instance_double(HTTParty::Response, body: response_body, success?: true) }
before do
allow(HTTParty).to receive(:get).and_return(mock_response)
allow(mock_response).to receive(:inspect).and_return(response_body)
end
it 'exchanges short lived token for long lived token' do
result = dummy_instance.send(:exchange_for_long_lived_token, short_lived_token)
expect(HTTParty).to have_received(:get).with(
'https://graph.instagram.com/access_token',
{
query: {
grant_type: 'ig_exchange_token',
client_secret: client_secret,
access_token: short_lived_token,
client_id: client_id
},
headers: { 'Accept' => 'application/json' }
}
)
expect(result).to eq({ 'access_token' => long_lived_token, 'expires_in' => 5_184_000 })
end
context 'when the request fails' do
let(:mock_response) { instance_double(HTTParty::Response, body: 'Error', success?: false, code: 400) }
it 'raises an error' do
expect do
dummy_instance.send(:exchange_for_long_lived_token, short_lived_token)
end.to raise_error(RuntimeError, 'Failed to exchange token: Error')
end
end
context 'when the response is not valid JSON' do
let(:mock_response) { instance_double(HTTParty::Response, body: 'Not JSON', success?: true) }
it 'raises a JSON parse error' do
allow(JSON).to receive(:parse).and_raise(JSON::ParserError.new('Invalid JSON'))
expect { dummy_instance.send(:exchange_for_long_lived_token, short_lived_token) }.to raise_error(JSON::ParserError)
end
end
end
describe '#fetch_instagram_user_details' do
let(:user_details) do
{
'id' => '12345',
'username' => 'test_user',
'user_id' => '12345',
'name' => 'Test User',
'profile_picture_url' => 'https://example.com/profile.jpg',
'account_type' => 'BUSINESS'
}
end
let(:response_body) { user_details.to_json }
let(:mock_response) { instance_double(HTTParty::Response, body: response_body, success?: true) }
before do
allow(HTTParty).to receive(:get).and_return(mock_response)
allow(mock_response).to receive(:inspect).and_return(response_body)
end
it 'fetches Instagram user details' do
result = dummy_instance.send(:fetch_instagram_user_details, access_token)
expect(HTTParty).to have_received(:get).with(
'https://graph.instagram.com/v22.0/me',
{
query: {
fields: 'id,username,user_id,name,profile_picture_url,account_type',
access_token: access_token
},
headers: { 'Accept' => 'application/json' }
}
)
expect(result).to eq(user_details)
end
context 'when the request fails' do
let(:mock_response) { instance_double(HTTParty::Response, body: 'Error', success?: false, code: 400) }
it 'raises an error' do
expect do
dummy_instance.send(:fetch_instagram_user_details, access_token)
end.to raise_error(RuntimeError, 'Failed to fetch Instagram user details: Error')
end
end
context 'when the response is not valid JSON' do
let(:mock_response) { instance_double(HTTParty::Response, body: 'Not JSON', success?: true) }
it 'raises a JSON parse error' do
allow(JSON).to receive(:parse).and_raise(JSON::ParserError.new('Invalid JSON'))
expect { dummy_instance.send(:fetch_instagram_user_details, access_token) }.to raise_error(JSON::ParserError)
end
end
end
end

View File

@@ -0,0 +1,56 @@
require 'rails_helper'
RSpec.describe NotionConcern, type: :concern do
let(:controller_class) do
Class.new do
include NotionConcern
end
end
let(:controller) { controller_class.new }
describe '#notion_client' do
let(:client_id) { 'test_notion_client_id' }
let(:client_secret) { 'test_notion_client_secret' }
before do
allow(GlobalConfigService).to receive(:load).with('NOTION_CLIENT_ID', nil).and_return(client_id)
allow(GlobalConfigService).to receive(:load).with('NOTION_CLIENT_SECRET', nil).and_return(client_secret)
end
it 'creates OAuth2 client with correct configuration' do
expect(OAuth2::Client).to receive(:new).with(
client_id,
client_secret,
{
site: 'https://api.notion.com',
authorize_url: 'https://api.notion.com/v1/oauth/authorize',
token_url: 'https://api.notion.com/v1/oauth/token',
auth_scheme: :basic_auth
}
)
controller.notion_client
end
it 'loads client credentials from GlobalConfigService' do
expect(GlobalConfigService).to receive(:load).with('NOTION_CLIENT_ID', nil)
expect(GlobalConfigService).to receive(:load).with('NOTION_CLIENT_SECRET', nil)
controller.notion_client
end
it 'returns OAuth2::Client instance' do
client = controller.notion_client
expect(client).to be_an_instance_of(OAuth2::Client)
end
it 'configures client with Notion-specific endpoints' do
client = controller.notion_client
expect(client.site).to eq('https://api.notion.com')
expect(client.options[:authorize_url]).to eq('https://api.notion.com/v1/oauth/authorize')
expect(client.options[:token_url]).to eq('https://api.notion.com/v1/oauth/token')
expect(client.options[:auth_scheme]).to eq(:basic_auth)
end
end
end