rhunal
rhunal

Reputation: 415

How to call same methods inside and outside 'context' and 'it' block

Below is a simple rspec example:

describe 'Emails' do    
  email_ids.each do |email_id|    
    it "should display #{email_id}" do
    end    
  end    
end

def email_ids
  [
    '[email protected]',
    '[email protected]',
    '[email protected]'
  ]
end

The above does not work, as methods are not accessible outside the it block.

Please advise how to make the method email_ids accessible outside the it block.

Upvotes: 3

Views: 1766

Answers (6)

rodeezy
rodeezy

Reputation: 1

short version of @stefan's answer: needs to be

def self.email_ids
 # stuff
end

(def self.method for context/describe/etc; def method for it/etc)

Upvotes: 0

Prabs
Prabs

Reputation: 46

Rather than using proc or scopes, Simply use local variables outside describe block.

email_ids = [ 
  '[email protected]',
  '[email protected]',
  '[email protected]'
]
describe 'Emails' do
end

Upvotes: 2

rhunal
rhunal

Reputation: 415

I have better solution for this, than above.

1.using 'procs' or just local variable as below:

email_ids = ->{ %w[[email protected] [email protected] [email protected]] }

email_ids = { %w[[email protected] [email protected] [email protected]] }

Scope of proc & local variable will be same, but if you want to pass an argument then 'procs' are useful.

2.Define 'email_ids' method in module and include that module in spec, so that method will be accessible inside and outside the 'it' block

module EmailFactoryHelper

  def email_ids
    %w[[email protected] [email protected] [email protected]]
  end

end

include in specs as below:

require 'factories_helper/email_factory_helper'

include EmailFactoryHelper

describe 'Emails' do
  email_ids.call.each do |email_id|
    it "should display #{email_id}" do
      page.should have_content "#{email_id}"
    end
  end
end

Output:

Emails
  should display [email protected]
  should display [email protected]
  should display [email protected]

Finished in 41.56 seconds
3 examples, 0 failures

I have preferred step-2

Upvotes: 3

George Koehler
George Koehler

Reputation: 1703

The method wasn't accessible because you called the method before you defined the method. This simpler script has the same problem:

p email_ids

def email_ids
  [
    '[email protected]',
    '[email protected]',
    '[email protected]'
  ]
end

"undefined local variable or method `email_ids' for main:Object (NameError)"

You must define your methods before you call them. You can solve this problem by moving the def email_ids above the describe 'Emails'.

Upvotes: 0

Stefan
Stefan

Reputation: 114188

describe creates a (nested) class and evaluates the given block within that class:

describe 'Foo' do     
  p self            #=> RSpec::ExampleGroups::Foo
  describe '' do
    p self          #=> RSpec::ExampleGroups::Foo::Bar
  end
end

it blocks on the other hand are evaluated in the corresponding class' instance:

describe 'Foo' do    
  it 'foo' do 
    p self          #=> #<RSpec::ExampleGroups::Foo ...>
  end
end

If you define a method via def email_ids, it becomes an instance method and is therefore only available within the instance, i.e. within it.

In order to make a method available within describe, you have to define it as a class method, i.e via def self.email_ids:

describe 'Emails' do
  def self.email_ids
    %w[[email protected] [email protected] [email protected]]
  end

  email_ids.each do |email_id|
    it "should display #{email_id}" do
    end
  end
end

Output:

Emails
  should display [email protected]
  should display [email protected]
  should display [email protected]

You can also reuse the helper method across multiple tests by putting it in a module and using extend. See Define helper methods in a module for more examples.

Upvotes: 8

David
David

Reputation: 3610

The solution is to simply define your structure within scope, instead of returning it from a method call:

EMAILS = [
   '[email protected]',
   '[email protected]',
   '[email protected]'
]

EMAILS.each do |email|
  it "should display #{email}" do
  end
end

Upvotes: 1

Related Questions