140 lines
4.8 KiB
Ruby
140 lines
4.8 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe 'TikTok Callbacks', type: :request do
|
|
let(:account) { create(:account) }
|
|
|
|
let(:client_secret) { 'tiktok-app-secret' }
|
|
let(:client_id) { 'tiktok-app-id' }
|
|
|
|
let(:token_endpoint) { 'https://business-api.tiktok.com/open_api/v1.3/tt_user/oauth2/token/' }
|
|
let(:business_endpoint) { 'https://business-api.tiktok.com/open_api/v1.3/business/get/' }
|
|
|
|
let(:tiktok_access_token) { 'access-token-1' }
|
|
let(:tiktok_refresh_token) { 'refresh-token-1' }
|
|
let(:tiktok_business_id) { 'biz-123' }
|
|
|
|
let(:token_response) do
|
|
{
|
|
code: 0,
|
|
message: 'ok',
|
|
data: {
|
|
open_id: tiktok_business_id,
|
|
scope: Tiktok::AuthClient::REQUIRED_SCOPES.join(','),
|
|
access_token: tiktok_access_token,
|
|
refresh_token: tiktok_refresh_token,
|
|
expires_in: 86_400,
|
|
refresh_token_expires_in: 2_592_000
|
|
}
|
|
}.to_json
|
|
end
|
|
|
|
let(:business_response) do
|
|
{
|
|
code: 0,
|
|
message: 'ok',
|
|
data: {
|
|
username: 'tiktok_user',
|
|
display_name: 'TikTok Display Name',
|
|
profile_image: 'https://www.example.com/avatar.png'
|
|
}
|
|
}.to_json
|
|
end
|
|
|
|
let(:state) do
|
|
JWT.encode({ sub: account.id, iat: Time.current.to_i }, client_secret, 'HS256')
|
|
end
|
|
|
|
before do
|
|
InstallationConfig.where(name: %w[TIKTOK_APP_ID TIKTOK_APP_SECRET]).delete_all
|
|
GlobalConfig.clear_cache
|
|
|
|
stub_request(:post, token_endpoint).to_return(status: 200, body: token_response, headers: { 'Content-Type' => 'application/json' })
|
|
stub_request(:get, business_endpoint)
|
|
.with(query: hash_including('business_id' => tiktok_business_id))
|
|
.to_return(status: 200, body: business_response, headers: { 'Content-Type' => 'application/json' })
|
|
end
|
|
|
|
it 'creates channel and inbox and redirects to agents step for new connections' do
|
|
expect(Avatar::AvatarFromUrlJob).to receive(:perform_later).with(instance_of(Inbox), 'https://www.example.com/avatar.png')
|
|
|
|
with_modified_env TIKTOK_APP_ID: client_id, TIKTOK_APP_SECRET: client_secret do
|
|
expect do
|
|
get '/tiktok/callback', params: { code: 'valid_code', state: state }
|
|
end.to change(Channel::Tiktok, :count).by(1).and change(Inbox, :count).by(1)
|
|
end
|
|
|
|
inbox = Inbox.last
|
|
channel = inbox.channel
|
|
|
|
expect(channel.business_id).to eq(tiktok_business_id)
|
|
expect(channel.access_token).to eq(tiktok_access_token)
|
|
expect(channel.refresh_token).to eq(tiktok_refresh_token)
|
|
|
|
expect(response).to redirect_to(app_tiktok_inbox_agents_url(account_id: account.id, inbox_id: inbox.id))
|
|
end
|
|
|
|
it 'updates an existing channel and redirects to settings' do
|
|
existing_channel = create(
|
|
:channel_tiktok,
|
|
account: account,
|
|
business_id: tiktok_business_id,
|
|
access_token: 'old-access-token',
|
|
refresh_token: 'old-refresh-token',
|
|
expires_at: 1.hour.ago,
|
|
refresh_token_expires_at: 1.day.from_now
|
|
)
|
|
existing_channel.inbox.update!(name: 'Old Name')
|
|
|
|
with_modified_env TIKTOK_APP_ID: client_id, TIKTOK_APP_SECRET: client_secret do
|
|
expect do
|
|
get '/tiktok/callback', params: { code: 'valid_code', state: state }
|
|
end.to not_change(Channel::Tiktok, :count).and not_change(Inbox, :count)
|
|
end
|
|
|
|
existing_channel.reload
|
|
inbox = existing_channel.inbox.reload
|
|
|
|
expect(existing_channel.access_token).to eq(tiktok_access_token)
|
|
expect(existing_channel.refresh_token).to eq(tiktok_refresh_token)
|
|
expect(inbox.name).to eq('TikTok Display Name')
|
|
|
|
expect(response).to redirect_to(app_tiktok_inbox_settings_url(account_id: account.id, inbox_id: inbox.id))
|
|
end
|
|
|
|
it 'redirects to error page when user denies authorization' do
|
|
with_modified_env TIKTOK_APP_ID: client_id, TIKTOK_APP_SECRET: client_secret do
|
|
get '/tiktok/callback', params: { error: 'access_denied', error_description: 'User cancelled', error_code: '400', state: state }
|
|
end
|
|
|
|
expect(response).to redirect_to(
|
|
app_new_tiktok_inbox_url(
|
|
account_id: account.id,
|
|
error_type: 'access_denied',
|
|
code: '400',
|
|
error_message: 'User cancelled'
|
|
)
|
|
)
|
|
end
|
|
|
|
it 'redirects to error page when required scopes are not granted' do
|
|
stub_request(:post, token_endpoint).to_return(
|
|
status: 200,
|
|
body: JSON.parse(token_response).deep_merge('data' => { 'scope' => 'user.info.basic' }).to_json,
|
|
headers: { 'Content-Type' => 'application/json' }
|
|
)
|
|
|
|
with_modified_env TIKTOK_APP_ID: client_id, TIKTOK_APP_SECRET: client_secret do
|
|
get '/tiktok/callback', params: { code: 'valid_code', state: state }
|
|
end
|
|
|
|
expect(response).to redirect_to(
|
|
app_new_tiktok_inbox_url(
|
|
account_id: account.id,
|
|
error_type: 'ungranted_scopes',
|
|
code: 400,
|
|
error_message: 'User did not grant all the required scopes'
|
|
)
|
|
)
|
|
end
|
|
end
|