1
votes

I have an application that has a User model, and users have different roles. The roles are represented internally as integer indexes, but are presented to the user as strings. I also have a helper function access_level (in application_controller.rb - is that a sensible place for it?) that takes either the integer index or the string representation and returns a hash of loads of information about the role (including the string representation and the index, so this is a convenient way of converting between them). In case it matters, access_level depends in turn on role definitions defined in a file in config\initializers.

Because the interface presented to the user depends on the role, my tests have lots of things like Given I have the role of administrator and such like. I'm trying to create the user with FactoryGirl.create(:user, role: access_level(role).index) but I can't get Cucumber to see access_level.

Most of the advice I find by Googling this says "don't do that" because calling functions behind the scenes violates the principle of keeping Cucumber at the UI level, but I can't see a way of testing this user behaviour without Cucumber knowing how to map role names to indexes. I could duplicate access_level in one of my Cucumber support files, of course, but that violates DRY. So how should I structure this in such a way as to be able to test it cleanly in Cucumber?

2

2 Answers

1
votes

Cucumber drivers simulate a browser, so step definitions don't have an instance of a controller or access to controller instance methods.

The simplest possible way to make that controller method available to Cucumber step definitions would be to make it a class method and call it with ApplicationController.access_level. That would be icky, however, since it would make the step definitions depend on a class that they shouldn't know about.

Instead, put the code that you want to use in both your app and in Cucumber step definitions into a module and include that module in ApplicationController and in the Cucumber world.

In app/models/access_control.rb:

module AccessControl
  def access_level(role)
    # do whatever is necessary
  end
end

(I guessed that it should be in the models directory because it feels like a model-level concern to me, but that's not critical.)

In app/controllers/application_controller.rb:

class ApplicationController < ActionController::Base
  include AccessControl
  # ...
end

In features/support/env.rb:

World AccessControl
0
votes

I have been taught that Cucumber scenarios should replicate user behaviors. But that doesn't negate the fact that you need to create certain users with certain roles for testing. Having our automation separate from the site code doesn't give us the luxury/temptation of using existing controller methods. :) Have you considered creating a factory for roles that gets used by your user factory? I'm not sure how cumbersome this would be in your situation or how many roles you would need to create.