Mock HTTP using VCR with RSpec | Mock Authy | Rails

Well, slower test suite is a nightmare both in your local machine and in your CI server. If your gem provider has built some Mocking APIs then its cool. But, no mocking API and you are writing Unit Test for your models and controller then beware, do not leave your app making HTTP requests everytime.

What to do?

If you cannot mock your library then mock the damn Internet. Simple enough! you can get going in a couple of minutes. Continue reading

RSpect : need to be taken care of while writing UnitTesting

Ok let me show an example

let(:role) { create :role, name: 'parent' }
let(:user) { create(:user1, roles: [role]) }
let(:pact) { create :pact, parent_id: user.id, renews_at: 1.hour.ago }
let(:execution){ AutoRenewalPactAsync.new.perform}

it 'should renew pact and also schedule the drug test whose renews_at date is today' do
  expect{execution}.to change{pact.pact_years.count}.by(1)
  expect(pact.renews_at).to eq(pact.renews_at + Pact::RenewalYear)
end
------------------------------------------------------------------
Failure/Error: expect(pact.renews_at).to eq(1.year.from_now)
 
 expected: 2017-02-28 09:20:41.204897017 +0000
 got: 2016-02-28 08:20:40.980794147 +0000

Did you notice what went wrong?. Well what I was doing wrong was, I was expecting the value of stale object to be updated by the execution.

Correction:

it 'should renew pact and also schedule the drug test whose renews_at date is today' do
  expect{execution}.to change{pact.pact_years.count}.by(1)

  updated_pact = Pact.find(pact.id)
  expect(updated_pact.renews_at).to eq(pact.renews_at + Pact::RenewalYear)
end
------------------------------------------------------------------
Failure/Error: expect(updated_pact.renews_at).to eq(pact.renews_at + Pact::RenewalYear)
 
 expected: 2017-02-28 08:27:50.125348477 +0000
 got: 2017-02-28 08:27:50.125348000 +0000

This time the issue was: I was comparing the DateTime object and for them to be equal, even the milli/micro seconds have to be equal.

Correction:

updated_pact = Pact.find(pact.id)
expect(updated_pact.renews_at.to_date).to eq(pact.renews_at.to_date + Pact::RenewalYear)
should renew pact and also schedule the drug test whose renews_at date is today
Finished in 5.76 seconds (files took 5.35 seconds to load)
4 examples, 0 failures, 2 pending

 

How to mock Stripe::Charge.retrieve using Stripe Mock gem

I created customer, made a subscription on the behalf of the customer. Along with that I generated invoices and expected in the RSpec example like

 

it 'should make sure reward amount in transaction history is equal \
    to amount added by the supporter.' do
  invoice = customer.invoices.first
  invoice.pay
  charge = Stripe::Charge.create(customer: customer.id, amount: invoice.total, currency: 'usd').to_h
  charge[:id] = invoice.charge
  charge = RStruct.new(charge)
  allow(Stripe::Charge).to receive(:retrieve).and_return(charge) # A mock object would be more useful here.
  execution
  expect(TransactionHistory.first.added_rewards).to eq(invoice.total/100.0)
end

RSpec : Conditionals in before/after callbacks

Conditions

When you add a conditions hash to before(:example) or before(:context), RSpec will only apply that hook to groups or examples that match the conditions. e.g.

RSpec.configure do |config|
  config.before(:example, :authorized => true) do
     :authorized_user
  end
end

describe Something, :authorized => true do
  # The before hook will run in before each example in this group.
end

describe SomethingElse do
  it "does something", :authorized => true do
    # The before hook will run before this example.
  end

  it "does something else" do
    # The hook will not run before this example.
  end
end

 

Or

config.before(:each) do |ex|
  if ex.metadata[:admin] == true
    Rails.application.load_seed # loading seeds
  end
end

it "should auto fill the shipping date field to today's date", :admin => true  do
  expect(User.find_by_email('user@example.com')).not_to eq(nil)
end

Sources

http://www.rubydoc.info/github/rspec/rspec-core/RSpec/Core/Hooks#before-instance_method

Rails : Capybara::Webkit::ClickFailed, because of overlapping element

Capybara::Webkit::ClickFailed:
 Failed to click element /html/body/div[@id='wrapper']/div[@id='page-content-wrapper']/div/div/div/form[@id='signup']/div[@id='user_section']/div[7]/div[3]/div/button[@id='review_button'] because of overlapping element /html/body/div[8] at position 209, 718; 
 A screenshot of the page at the time of the failure has been written to /tmp/click_failed_S10458.png

 

The actual problem was; there was a link_tag (<a>) inside the <label> tag. So when I asked the capybara to click on the <label> it clicked on the  “Terms and Conditions” area and a popup appeared.

find('[for=agree_terms]').click

aaaaaaaaaaaaaa.png

 

To Solve this, I kept the link separate from the Label

 

Some useful links

http://stackoverflow.com/questions/34633269/wait-till-the-form-gets-submitted-in-capybara

https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara

Capybara : RSpec : filling and assertion tips

To use helper method you need to visit some web page like

visit '/signup'

For Text fields

fill 'user[email]', with: 'john@example.com'
fill_in 'user[name]', with: 'John Smith'
fill_in 'user[email]', with: 'john@example.com'

For Select box

select 'Annually', from: 'subscription_type'
# The `Annually` is the text not the value attribute
# 'subscription_type' is name attribute
select 'Monthly', from: 'subscription_type'

Continue reading