DEV Community

Patrick Baselier for Kabisa Software Artisans

Posted on • Originally published at kabisa.nl on

You're not stubbing, stupid!

Recently, in a Ruby on Rails project, I was writing a Cucumber scenario that was deleting a resource by having the user clicking a 'Destroy' button. Before the action was executed, the user had to confirm a message shown in a confirmation dialog. You may have seen this dozens of times when scaffolding a Rails application.

Oh and upon deleting, I also had to do a request to an external API (to be more precise: the use case was that of a user unsubscribing, so I had to send a DELETE request to a Mollie API).

So, "nothing new here", I thought. I knew about WebMock, since I wanted to stub the external API request and my test suite was set up to test JavaScript, so I knew I could use the accept_confirm method here that Capybara offers.

Stubbing the request was defined in a support file:

# features/support/webmock.rb

require 'webmock/cucumber'

WebMock.disable_net_connect!(allow_localhost: true)

Before do |_scenario|
  stub_request(
    :delete, 
    %r{https://api.mollie.com/v2/customers/\w+/subscriptions/\w+}
  )
    .to_return(body: {}.to_json)
end

Enter fullscreen mode Exit fullscreen mode

My step implementation looked like this:

# features/step_definitions/general_steps.rb

When('I delete the resource') do
  accept_confirm { click_on 'Destroy' }
end
Enter fullscreen mode Exit fullscreen mode

The test failed! It was telling me that I should stub the DELETE request.

  Real HTTP connections are disabled. Unregistered request: DELETE https://api.mollie.com/v2/customers/...

  You can stub this request with the following snippet:

  stub_request(:delete, "https://api.mollie.com/v2/customers/...").
    ...
    to_return(status: 200, body: "", headers: {})
Enter fullscreen mode Exit fullscreen mode

Wasn't I doing this?

After many (!!!) hours of trying rewriting the stub, rubber ducking with colleagues, writing alternative scenarios, I decided to get rid of the confirmation dialog that was shown to the user. This way I didn't need the accept_confirm and... tadaaa: it worked! My test was passing.

My theory was that accept_confirm executes in a different thread or something in which the stub is not defined (I know a theory can be proven wrong, but this one worked for me).

One way to work around this is, instead of using accept_confirm, is 'overriding' the JavaScript's confirm function:

# features/support/my_world.rb
module MyWorld
  def click_on_and_confirm(locator)
    link_or_button = find(:link_or_button, locator)
    page.evaluate_script('window.confirm = () => true')
    expect(link_or_button['data-confirm']).to be_a(String)
    link_or_button.click
  end
end

World(MyWorld)

# features/step_definitions/general_steps.rb

When('I delete the resource') do
  click_on_and_confirm 'Destroy'
end
Enter fullscreen mode Exit fullscreen mode

This way the DELETE request is being stubbed, you can still show a nice confirmation dialog and your test will pass.

Be aware that during the test, the confirmation dialog will not be shown anymore (due to the 'stubbed' confirm function in JavaScript. Therefor, I added an assertion to check indirectly if the confirmation dialog will be shown (by using the data-confirm attribute added and used by Rails) when clicking the 'Destroy' link or button.

AWS Q Developer image

Your AI Code Assistant

Automate your code reviews. Catch bugs before your coworkers. Fix security issues in your code. Built to handle large projects, Amazon Q Developer works alongside you from idea to production code.

Get started free in your IDE

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay