module RSpec::Rails::Matchers
@api public Container module for Rails
specific matchers.
Public Instance Methods
@api public Passes if actual is an instance of ‘model_class` and returns `true` for `new_record?`. Typically used to specify instance variables assigned to views by controller actions
Use the ‘with` method to specify the specific attributes to match on the new record.
@example
get :new assigns(:thing).should be_a_new(Thing) post :create, :thing => { :name => "Illegal Value" } assigns(:thing).should be_a_new(Thing).with(:name => nil)
# File lib/rspec/rails/matchers/be_a_new.rb, line 78 def be_a_new(model_class) BeANew.new(model_class) end
@api public Passes if actual returns ‘true` for `new_record?`.
@example
get :new expect(assigns(:thing)).to be_new_record
# File lib/rspec/rails/matchers/be_new_record.rb, line 25 def be_new_record BeANewRecord.new end
@api public Passes if the given model instance’s ‘valid?` method is true, meaning all of the `ActiveModel::Validations` passed and no errors exist. If a message is not given, a default message is shown listing each error.
@example
thing = Thing.new expect(thing).to be_valid
# File lib/rspec/rails/matchers/be_valid.rb, line 44 def be_valid(*args) BeValid.new(*args) end
@api public Passes if a job has been enqueued. May chain at_least, at_most or exactly to specify a number of times.
@example
before { ActiveJob::Base.queue_adapter.enqueued_jobs.clear } HeavyLiftingJob.perform_later expect(HeavyLiftingJob).to have_been_enqueued HelloJob.perform_later HeavyLiftingJob.perform_later expect(HeavyLiftingJob).to have_been_enqueued.exactly(:once) 3.times { HelloJob.perform_later } expect(HelloJob).to have_been_enqueued.at_least(2).times HelloJob.perform_later expect(HelloJob).to enqueue_job(HelloJob).at_most(:twice) HelloJob.perform_later HeavyLiftingJob.perform_later expect(HelloJob).to have_been_enqueued expect(HeavyLiftingJob).to have_been_enqueued HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42) expect(HelloJob).to have_been_enqueued.with(42).on_queue("low").at(Date.tomorrow.noon) HelloJob.set(queue: "low").perform_later(42) expect(HelloJob).to have_been_enqueued.with(42).on_queue("low").at(:no_wait)
# File lib/rspec/rails/matchers/active_job.rb, line 436 def have_been_enqueued check_active_job_adapter ActiveJob::HaveBeenEnqueued.new end
@api public Passes if a job has been performed. May chain at_least, at_most or exactly to specify a number of times.
@example
before do ActiveJob::Base.queue_adapter.performed_jobs.clear ActiveJob::Base.queue_adapter.perform_enqueued_jobs = true ActiveJob::Base.queue_adapter.perform_enqueued_at_jobs = true end HeavyLiftingJob.perform_later expect(HeavyLiftingJob).to have_been_performed HelloJob.perform_later HeavyLiftingJob.perform_later expect(HeavyLiftingJob).to have_been_performed.exactly(:once) 3.times { HelloJob.perform_later } expect(HelloJob).to have_been_performed.at_least(2).times HelloJob.perform_later HeavyLiftingJob.perform_later expect(HelloJob).to have_been_performed expect(HeavyLiftingJob).to have_been_performed HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42) expect(HelloJob).to have_been_performed.with(42).on_queue("low").at(Date.tomorrow.noon)
# File lib/rspec/rails/matchers/active_job.rb, line 509 def have_been_performed check_active_job_adapter ActiveJob::HaveBeenPerformed.new end
@api public Passes if a message has been sent to a stream/object inside a block. May chain ‘at_least`, `at_most` or `exactly` to specify a number of times. To specify channel from which message has been broadcasted to object use `from_channel`.
@example
expect { ActionCable.server.broadcast "messages", text: 'Hi!' }.to have_broadcasted_to("messages") expect { SomeChannel.broadcast_to(user) }.to have_broadcasted_to(user).from_channel(SomeChannel) # Using alias expect { ActionCable.server.broadcast "messages", text: 'Hi!' }.to broadcast_to("messages") expect { ActionCable.server.broadcast "messages", text: 'Hi!' ActionCable.server.broadcast "all", text: 'Hi!' }.to have_broadcasted_to("messages").exactly(:once) expect { 3.times { ActionCable.server.broadcast "messages", text: 'Hi!' } }.to have_broadcasted_to("messages").at_least(2).times expect { ActionCable.server.broadcast "messages", text: 'Hi!' }.to have_broadcasted_to("messages").at_most(:twice) expect { ActionCable.server.broadcast "messages", text: 'Hi!' }.to have_broadcasted_to("messages").with(text: 'Hi!')
# File lib/rspec/rails/matchers/action_cable.rb, line 50 def have_broadcasted_to(target = nil) check_action_cable_adapter ActionCable::HaveBroadcastedTo.new(target, channel: described_class) end
@api public Passes if a job has been enqueued inside block. May chain at_least, at_most or exactly to specify a number of times.
@example
expect { HeavyLiftingJob.perform_later }.to have_enqueued_job # Using alias expect { HeavyLiftingJob.perform_later }.to enqueue_job expect { HelloJob.perform_later HeavyLiftingJob.perform_later }.to have_enqueued_job(HelloJob).exactly(:once) expect { 3.times { HelloJob.perform_later } }.to have_enqueued_job(HelloJob).at_least(2).times expect { HelloJob.perform_later }.to have_enqueued_job(HelloJob).at_most(:twice) expect { HelloJob.perform_later HeavyLiftingJob.perform_later }.to have_enqueued_job(HelloJob).and have_enqueued_job(HeavyLiftingJob) expect { HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42) }.to have_enqueued_job.with(42).on_queue("low").at(Date.tomorrow.noon) expect { HelloJob.set(queue: "low").perform_later(42) }.to have_enqueued_job.with(42).on_queue("low").at(:no_wait) expect { HelloJob.perform_later('rspec_rails', 'rails', 42) }.to have_enqueued_job.with { |from, to, times| # Perform more complex argument matching using dynamic arguments expect(from).to include "_#{to}" }
# File lib/rspec/rails/matchers/active_job.rb, line 401 def have_enqueued_job(job = nil) check_active_job_adapter ActiveJob::HaveEnqueuedJob.new(job) end
@api public Passes if an email has been enqueued inside block. May chain with to specify expected arguments. May chain at_least, at_most or exactly to specify a number of times. May chain at to specify a send time. May chain on_queue to specify a queue.
@example
expect { MyMailer.welcome(user).deliver_later }.to have_enqueued_mail expect { MyMailer.welcome(user).deliver_later }.to have_enqueued_mail(MyMailer) expect { MyMailer.welcome(user).deliver_later }.to have_enqueued_mail(MyMailer, :welcome) # Using alias expect { MyMailer.welcome(user).deliver_later }.to enqueue_mail(MyMailer, :welcome) expect { MyMailer.welcome(user).deliver_later }.to have_enqueued_mail(MyMailer, :welcome).with(user) expect { MyMailer.welcome(user).deliver_later MyMailer.welcome(user).deliver_later }.to have_enqueued_mail(MyMailer, :welcome).at_least(:once) expect { MyMailer.welcome(user).deliver_later }.to have_enqueued_mail(MyMailer, :welcome).at_most(:twice) expect { MyMailer.welcome(user).deliver_later(wait_until: Date.tomorrow.noon) }.to have_enqueued_mail(MyMailer, :welcome).at(Date.tomorrow.noon) expect { MyMailer.welcome(user).deliver_later(queue: :urgent_mail) }.to have_enqueued_mail(MyMailer, :welcome).on_queue(:urgent_mail)
# File lib/rspec/rails/matchers/have_enqueued_mail.rb, line 250 def have_enqueued_mail(mailer_class = nil, mail_method_name = nil) HaveEnqueuedMail.new(mailer_class, mail_method_name) end
@api public Passes if ‘response` has a matching HTTP status code.
The following symbolic status codes are allowed:
-
‘Rack::Utils::SYMBOL_TO_STATUS_CODE`
-
One of the defined ‘ActionDispatch::TestResponse` aliases:
-
‘:error`
-
‘:missing`
-
‘:redirect`
-
‘:success`
-
@example Accepts numeric and symbol statuses
expect(response).to have_http_status(404) expect(response).to have_http_status(:created) expect(response).to have_http_status(:success) expect(response).to have_http_status(:error) expect(response).to have_http_status(:missing) expect(response).to have_http_status(:redirect)
@example Works with standard ‘response` objects and Capybara’s ‘page`
expect(response).to have_http_status(404) expect(page).to have_http_status(:created)
@see github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/testing/test_response.rb ‘ActionDispatch::TestResponse` @see github.com/rack/rack/blob/master/lib/rack/utils.rb `Rack::Utils::SYMBOL_TO_STATUS_CODE`
# File lib/rspec/rails/matchers/have_http_status.rb, line 374 def have_http_status(target) raise ArgumentError, "Invalid HTTP status: nil" unless target HaveHttpStatus.matcher_for_status(target) end
@api public Passes if a job has been performed inside block. May chain at_least, at_most or exactly to specify a number of times.
@example
expect { perform_enqueued_jobs { HeavyLiftingJob.perform_later } }.to have_performed_job expect { perform_enqueued_jobs { HelloJob.perform_later HeavyLiftingJob.perform_later } }.to have_performed_job(HelloJob).exactly(:once) expect { perform_enqueued_jobs { 3.times { HelloJob.perform_later } } }.to have_performed_job(HelloJob).at_least(2).times expect { perform_enqueued_jobs { HelloJob.perform_later } }.to have_performed_job(HelloJob).at_most(:twice) expect { perform_enqueued_jobs { HelloJob.perform_later HeavyLiftingJob.perform_later } }.to have_performed_job(HelloJob).and have_performed_job(HeavyLiftingJob) expect { perform_enqueued_jobs { HelloJob.set(wait_until: Date.tomorrow.noon, queue: "low").perform_later(42) } }.to have_performed_job.with(42).on_queue("low").at(Date.tomorrow.noon)
# File lib/rspec/rails/matchers/active_job.rb, line 476 def have_performed_job(job = nil) check_active_job_adapter ActiveJob::HavePerformedJob.new(job) end
@api public Passes if the given inbound email would be routed to the subject inbox.
@param message [Hash, Mail::Message] a mail message or hash of
attributes used to build one
# File lib/rspec/rails/matchers/action_mailbox.rb, line 68 def receive_inbound_email(message) ActionMailbox::ReceiveInboundEmail.new(message) end
@api public Check email sending with specific parameters.
@example Positive expectation
expect { action }.to send_email
@example Negative expectations
expect { action }.not_to send_email
@example More precise expectation with attributes to match
expect { action }.to send_email(to: 'test@example.com', subject: 'Confirm email')
# File lib/rspec/rails/matchers/send_email.rb, line 117 def send_email(criteria = {}) SendEmail.new(criteria) end
Private Instance Methods
@private
# File lib/rspec/rails/matchers/action_cable.rb, line 63 def check_action_cable_adapter return if ::ActionCable::SubscriptionAdapter::Test === ::ActionCable.server.pubsub raise StandardError, "To use ActionCable matchers set `adapter: test` in your cable.yml" end
@private
# File lib/rspec/rails/matchers/active_job.rb, line 517 def check_active_job_adapter return if ::ActiveJob::QueueAdapters::TestAdapter === ::ActiveJob::Base.queue_adapter raise StandardError, "To use ActiveJob matchers set `ActiveJob::Base.queue_adapter = :test`" end