Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions app/models/payment_providers/flutterwave_provider.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ class FlutterwaveProvider < BaseProvider
PROCESSING_STATUSES = %w[pending].freeze
SUCCESS_STATUSES = %w[successful].freeze
FAILED_STATUSES = %w[failed cancelled].freeze

validates :secret_key, presence: true
validates :success_redirect_url, url: true, allow_nil: true, length: {maximum: 1024}

secrets_accessors :secret_key
settings_accessors :webhook_secret
secrets_accessors :secret_key, :webhook_secret

before_create :generate_webhook_secret

Expand Down
5 changes: 2 additions & 3 deletions spec/factories/payment_providers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,12 @@
type { "PaymentProviders::FlutterwaveProvider" }
name { "Flutterwave" }
code { "flutterwave_#{SecureRandom.uuid}" }

secrets do
{secret_key:}.to_json
{secret_key:, webhook_secret:}.to_json
end

settings do
{success_redirect_url:, webhook_secret:}
{success_redirect_url:}
end

transient do
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,19 @@
after { ENV.delete("SIDEKIQ_PAYMENTS") }

it "uses the payments queue" do
expect(described_class.queue_name).to eq("payments")
expect {
described_class.perform_later(organization:, event: "test")
}.to have_enqueued_job.on_queue("payments")
end
end

context "when SIDEKIQ_PAYMENTS is false or not set" do
before { ENV.delete("SIDEKIQ_PAYMENTS") }

it "uses the providers queue" do
expect(described_class.queue_name).to eq("providers")
expect {
described_class.perform_later(organization:, event: "test")
}.to have_enqueued_job.on_queue("providers")
end
end
end
Expand Down
109 changes: 109 additions & 0 deletions spec/models/payment_providers/flutterwave_provider_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe PaymentProviders::FlutterwaveProvider, type: :model do
subject(:flutterwave_provider) { build(:flutterwave_provider) }

describe "validations" do
it { is_expected.to validate_presence_of(:secret_key) }
it { is_expected.to validate_presence_of(:name) }
it { is_expected.to allow_value(nil).for(:success_redirect_url) }
it { is_expected.to allow_value("https://example.com/success").for(:success_redirect_url) }
it { is_expected.not_to allow_value("invalid-url").for(:success_redirect_url) }
it { is_expected.not_to allow_value("a" * 1025).for(:success_redirect_url) }

it "validates uniqueness of the code" do
expect(flutterwave_provider).to validate_uniqueness_of(:code).scoped_to(:organization_id)
end
end

describe "constants" do
it "defines success redirect URL" do
expect(described_class::SUCCESS_REDIRECT_URL).to eq("https://www.flutterwave.com/ng")
end

it "defines API URL" do
expect(described_class::API_URL).to eq("https://api.flutterwave.com/v3")
end

it "defines processing statuses" do
expect(described_class::PROCESSING_STATUSES).to eq(%w[pending])
end

it "defines success statuses" do
expect(described_class::SUCCESS_STATUSES).to eq(%w[successful])
end

it "defines failed statuses" do
expect(described_class::FAILED_STATUSES).to eq(%w[failed cancelled])
end
end

describe "#payment_type" do
it "returns flutterwave" do
expect(flutterwave_provider.payment_type).to eq("flutterwave")
end
end

describe "#api_url" do
it "returns the API URL" do
expect(flutterwave_provider.api_url).to eq("https://api.flutterwave.com/v3")
end
end

describe "webhook_secret generation" do
context "when creating a new provider" do
it "generates a webhook secret" do
provider = create(:flutterwave_provider)
expect(provider.webhook_secret).to be_present
expect(provider.webhook_secret.length).to eq(64)
end

it "generates different secrets for different providers" do
provider1 = create(:flutterwave_provider)
provider2 = create(:flutterwave_provider)
expect(provider1.webhook_secret).not_to eq(provider2.webhook_secret)
end

it "does not override existing webhook secret" do
existing_secret = "existing_secret"
provider = described_class.new(
organization: create(:organization),
name: "Test Provider",
code: "test_provider",
secret_key: "test_key",
webhook_secret: existing_secret
)
provider.save!
expect(provider.reload.webhook_secret).to eq(existing_secret)
end
end
end

describe "FlutterwavePayment" do
it "defines a data structure for payments" do
payment = described_class::FlutterwavePayment.new(
id: "12345",
status: "successful",
metadata: {amount: 1000}
)

expect(payment.id).to eq("12345")
expect(payment.status).to eq("successful")
expect(payment.metadata).to eq({amount: 1000})
end
end

describe "secrets accessors" do
it "provides access to secret_key through secrets" do
provider = create(:flutterwave_provider, secret_key: "test_secret_key")
expect(provider.secret_key).to eq("test_secret_key")
end

it "provides access to webhook_secret through secrets" do
provider = create(:flutterwave_provider)
expect(provider.webhook_secret).to be_present
end
end
end
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,9 @@
let(:secret) { nil }

before do
flutterwave_provider.update!(settings: flutterwave_provider.settings.merge("webhook_secret" => nil))
secrets = JSON.parse(flutterwave_provider.secrets || "{}")
secrets.delete("webhook_secret")
flutterwave_provider.update!(secrets: secrets.to_json)
end

it "returns service failure" do
Expand Down
Loading