# Pull Request Template ## Description Fixes [CW-4620](https://linear.app/chatwoot/issue/CW-4620/rethinking-custom-domains-in-chatwoot) <img width="642" height="187" alt="Screenshot 2025-07-29 at 8 17 44 PM" src="https://github.com/user-attachments/assets/ad2f5dac-4b27-4dce-93ca-6cbba74443fb" /> ## Type of change - [x] New feature (non-breaking change which adds functionality) ## How Has This Been Tested? ## Checklist: - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have commented on my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] Any dependent changes have been merged and published in downstream modules --------- Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com> Co-authored-by: Pranav <pranavrajs@gmail.com> Co-authored-by: Pranav <pranav@chatwoot.com>
117 lines
4.4 KiB
Ruby
117 lines
4.4 KiB
Ruby
require 'rails_helper'
|
|
|
|
RSpec.describe Cloudflare::CreateCustomHostnameService do
|
|
let(:portal) { create(:portal, custom_domain: 'test.example.com') }
|
|
let(:installation_config_api_key) { create(:installation_config, name: 'CLOUDFLARE_API_KEY', value: 'test-api-key') }
|
|
let(:installation_config_zone_id) { create(:installation_config, name: 'CLOUDFLARE_ZONE_ID', value: 'test-zone-id') }
|
|
|
|
describe '#perform' do
|
|
context 'when API token or zone ID is not found' do
|
|
it 'returns error when API token is missing' do
|
|
installation_config_zone_id
|
|
service = described_class.new(portal: portal)
|
|
|
|
result = service.perform
|
|
|
|
expect(result).to eq(errors: ['Cloudflare API token or zone ID not found'])
|
|
end
|
|
|
|
it 'returns error when zone ID is missing' do
|
|
installation_config_api_key
|
|
service = described_class.new(portal: portal)
|
|
|
|
result = service.perform
|
|
|
|
expect(result).to eq(errors: ['Cloudflare API token or zone ID not found'])
|
|
end
|
|
end
|
|
|
|
context 'when no hostname is found' do
|
|
it 'returns error' do
|
|
installation_config_api_key
|
|
installation_config_zone_id
|
|
portal.update(custom_domain: nil)
|
|
service = described_class.new(portal: portal)
|
|
|
|
result = service.perform
|
|
|
|
expect(result).to eq(errors: ['No hostname found'])
|
|
end
|
|
end
|
|
|
|
context 'when API request is made' do
|
|
before do
|
|
installation_config_api_key
|
|
installation_config_zone_id
|
|
end
|
|
|
|
context 'when API request fails' do
|
|
it 'returns error response' do
|
|
service = described_class.new(portal: portal)
|
|
error_response = {
|
|
'errors' => [{ 'message' => 'API error' }]
|
|
}
|
|
|
|
stub_request(:post, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames')
|
|
.with(headers: { 'Authorization' => 'Bearer test-api-key', 'Content-Type' => 'application/json' },
|
|
body: { hostname: 'test.example.com', ssl: { method: 'http', type: 'dv' } }.to_json)
|
|
.to_return(status: 422, body: error_response.to_json, headers: { 'Content-Type' => 'application/json' })
|
|
|
|
result = service.perform
|
|
|
|
expect(result[:errors]).to eq(error_response['errors'])
|
|
end
|
|
end
|
|
|
|
context 'when API request succeeds but no data is returned' do
|
|
it 'returns hostname creation error' do
|
|
service = described_class.new(portal: portal)
|
|
success_response = {
|
|
'result' => nil
|
|
}
|
|
|
|
stub_request(:post, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames')
|
|
.with(headers: { 'Authorization' => 'Bearer test-api-key', 'Content-Type' => 'application/json' },
|
|
body: { hostname: 'test.example.com', ssl: { method: 'http', type: 'dv' } }.to_json)
|
|
.to_return(status: 200, body: success_response.to_json, headers: { 'Content-Type' => 'application/json' })
|
|
|
|
result = service.perform
|
|
|
|
expect(result).to eq(errors: ['Could not create hostname'])
|
|
end
|
|
end
|
|
|
|
context 'when API request succeeds and data is returned' do
|
|
it 'updates portal SSL settings and returns success' do
|
|
service = described_class.new(portal: portal)
|
|
success_response = {
|
|
'result' => {
|
|
'ownership_verification_http' => {
|
|
'http_url' => 'http://example.com/.well-known/cf-verification/verification-id',
|
|
'http_body' => 'verification-body'
|
|
}
|
|
}
|
|
}
|
|
expect(portal.ssl_settings).to eq({})
|
|
|
|
stub_request(:post, 'https://api.cloudflare.com/client/v4/zones/test-zone-id/custom_hostnames')
|
|
.with(headers: { 'Authorization' => 'Bearer test-api-key', 'Content-Type' => 'application/json' },
|
|
body: { hostname: 'test.example.com', ssl: { method: 'http', type: 'dv' } }.to_json)
|
|
.to_return(status: 200, body: success_response.to_json, headers: { 'Content-Type' => 'application/json' })
|
|
|
|
result = service.perform
|
|
expect(portal.ssl_settings).to eq(
|
|
{
|
|
'cf_verification_id' => 'verification-id',
|
|
'cf_verification_body' => 'verification-body',
|
|
'cf_status' => nil,
|
|
'cf_verification_errors' => ''
|
|
}
|
|
)
|
|
expect(result).to eq(data: success_response['result'])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|