Hi I am building a Rails/Rack middleware for the Mailgun api, and doing a simple test for connection, which is fine in Postman with exact same params.
It is showing an error in test, Failure/Error: @app.call(env)
NoMethodError:
undefined method `merge!' for #<Mailgun::Tracking::MailLogger:0x0000557e6bc8bb50>
on running RSpec, and no merge method is attempted at all, so dont know where its come from. The api_key and endpoint are initialized in config/initialisers folder as per the Mailgun Tracking gem (which is being used) guidelines.
Only two other files used and code below.
MailLogger class under Mailgun::Tracking module, registered as middleware in app.
require 'logger'
require 'mailgun/tracking'
require 'rack/contrib'
require 'rack'
require 'byebug'
module Mailgun::Tracking
class MailLogger
def initialize(app, options = {
"HTTP_X_MAILGUN_API_KEY" => ENV['MAILGUN_API_KEY'],
"HTTP_X_MAILGUN_ENDPOINT" => ENV['MAILGUN_ENDPOINT']
})
@app = app
@options = options
end
def call(env)
@app.call(env)
end
end
end
The RSpec test
require 'logger'
require "json"
require "rails_helper"
Bundler.require(*Rails.groups)
require_relative "../../lib/middleware/mailgun/mailgun_tracking.rb"
RSpec.describe Mailgun::Tracking::MailLogger, type: 'Mailgun Webhook' do
subject(:response) { app.call(env) }
# env to pass in middleware, url endpoint & key
let(:app) { described_class.new(Rails.application) }
let(:env) { described_class.new(app, options = {
"HTTP_X_MAILGUN_API_KEY" => ENV['MAILGUN_API_KEY'],
"HTTP_X_MAILGUN_ENDPOINT" => ENV['MAILGUN_ENDPOINT']
}) }
it "returns a 200 status code" do
expect(response).to eq([200, {}, ["OK"]])
end
end
Am just looking for a 200, OK on connection, as I already get in Postman with the same header (api_key) and endpoint (events)
but throws this mysterious missing "merge" method error
Not encountered before.
Anyone know why?
Thanks
CodePudding user response:
The actual code calling merge!
is hidden in rack implementation and as such is filtered out from the error message. Your problem is that env
you define in your test is not an instance of Rack::Environment
but rather instance of your middleware. You can generate mocked environment instance using, for example, Rack::MockRequest.env_for("/", method: :get)
That being said, your unit test is currently testing the whole of the rack stack, including the routes and other middlewares. You can isolate your test better by using a mock application:
let(:app) { described_class.new(->(env) [200, {}, 'success']) }