Skip to content

Instantly share code, notes, and snippets.

@mikker
Created September 9, 2019 06:55
Show Gist options
  • Save mikker/f7fc5efa3245190343187896ad99d58a to your computer and use it in GitHub Desktop.
Save mikker/f7fc5efa3245190343187896ad99d58a to your computer and use it in GitHub Desktop.
Receive and expect Stripe webhook events in your Rails system tests
require 'system_helper'
RSpec.describe 'Something', type: :system do
it 'receives an event', :with_stripe_events do
make_request_at_stripe
wait_for_stripe_event { |e| e.type == 'charge.succeeded' }
expect(...)
end
end
require 'stripe'
require 'stripe_event' # https://github.com/integrallis/stripe_event
require 'json'
require 'open3'
# Expects bin/stripe-{platform} to be relevant version of stripe-cli
# https://github.com/stripe/stripe-cli
class StripeCli
class << self
def debug?
@debug ||= false
end
attr_writer :debug
end
def initialize(callback = nil, &block)
@callback = callback || block
end
def self.boot!(&block)
return if @instance
@instance = new(&block).boot!
end
def self.kill!
return unless @instance
@instance.kill!
@instance = nil
end
def boot!
@cli_thread = Thread.new do
puts "Booting Stripe CLI with #{cmd}" if debug?
meth = debug? ? :popen2 : :popen2e
Open3.send(meth, cmd) do |_in, out, _status|
out.each do |line|
case line
when /^{/
start_buffering(line)
when /^}/
json = flush_buffer(line)
puts json if debug?
begin
event = Stripe::Event.construct_from(json, symbolize_names: true)
@callback.call(event)
rescue => e
puts e.inspect
puts e.backtrace if debug?
end
else
write_to_buffer(line) if buffering?
end
end
rescue => e
puts e.inspect
puts e.backtrace if debug?
end
end
sleep 1 # wait for the cli to be mostly ready
self
end
def kill!
puts 'Killing Stripe CLI' if debug?
@cli_thread.kill
end
private
def debug?
self.class.debug?
end
def cmd
@cmd ||=
begin
cli = "bin/stripe-#{Gem::Platform.local.os}"
"#{cli} listen -p --config spec/stripe.toml"
end
end
def start_buffering(line)
@object_buffer = '' + line
end
def write_to_buffer(line)
@object_buffer += line
end
def flush_buffer(line)
@object_buffer += line
json = JSON.parse(@object_buffer)
@object_buffer = nil
json
end
def buffering?
!!@object_buffer
end
end
module WithStripeEventsHelpers
def register_stripe_event(event)
stripe_events.push(event)
end
def stripe_events
@stripe_events ||= []
end
def wait_for_stripe_event
Timeout.timeout(15) do
loop do
break if stripe_events.find { |event| yield(event) }
sleep 0.1
end
rescue Timeout::Error
puts 'Died waiting for Stripe event'
raise
end
end
end
RSpec.configure do |config|
config.include WithStripeEventsHelpers, with_stripe_events: true
config.before(:each, with_stripe_events: true) do
StripeCli.boot! do |event|
register_stripe_event event
StripeEvent.instrument(event)
end
end
config.after(:each, with_stripe_events: true) do
StripeCli.kill!
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment