Jonah
Jonah

Reputation: 16242

Cucumber: Instance variable defined in support file not being passed to step definition

I have a file api_extensions.rb in features/support:

require 'rubygems'
require 'mechanize'
require 'json'

module ApiExtensions

    def initialize
        @agent = Mechanize.new
        @api_header = {'Accept' => 'application/json', 'Content-Type' => 'application/json'}
        @api_uris = {
            'the list of campuses' => 'http://example.com/servicehosts/campus.svc',
            'the list of settings' => 'http://example.com/servicehosts/setting.svc',
            'login' => 'http://example.com/servicehosts/Student.svc/login',
        }    
    end
end

World(ApiExtensions)

However, I am still getting the error undefined method '[]' for nil:NilClass (NoMethodError) on the second line of step definitions file when I run cucumber:

When /^I attempt to log in using a valid username and password$/ do 
    api_uri = @api_uris['login']
    request_body = {:username => "[email protected]", :password => "testsecret"}.to_json
    @page = @agent.post(api_uri, request_body, @api_header)
end

Why is the instance variable @api_uris not showing up even after I have added its module to World? Also, I have tested that the module is being executed by adding some instrumentation to that file, so @api_uris is being set, it's just not available to my step defintions.

Finally, if I explicitly include ApiExtensions as the first line of my step definitions file, it works fine. But I thought the call to World(ApiExtensions) was supposed to automatically include my module in all step definitions file.

Thanks!

Upvotes: 1

Views: 1217

Answers (1)

Justin Ko
Justin Ko

Reputation: 46846

The Problem: My understanding is that World(ApiExtensions) is extending the world object (see https://github.com/cucumber/cucumber/wiki/A-Whole-New-World). This extension will make the ApiExtensions methods (ie your initialize()) now be available to your steps. You would still need to actually call the initialize method before the instance variables get created and become available to all your steps. If you add initialize to the start of your step, your step should work.

Solution: If you want to initialize those instance variables when extending the World, you should change your module to:

module ApiExtensions
    def self.extended(obj)
        obj.instance_exec{
            @agent = Mechanize.new
            @api_header = {'Accept' => 'application/json', 'Content-Type' => 'application/json'}
            @api_uris = {
                'the list of campuses' => 'http://example.com/servicehosts/campus.svc',
                'the list of settings' => 'http://example.com/servicehosts/setting.svc',
                'login' => 'http://example.com/servicehosts/Student.svc/login',
            }  
        }
    end
end

When the world object is extending with your module, the self.extended(obj) method will immediately run and initialize all the variables, making them available to all your steps.

Upvotes: 3

Related Questions