Specifing methods in a steps_for block

Hey list,

I’m refactoring some much-used functionality into a common_steps step
group. Methods like this are in there:

steps_for :common do
Given “a number of existing $types?” do |type|
@initial_item_count = type.singularize.classify.constantize.count
end

When “the user adds an invalid $type” do |type|
post “/#{type.pluralize}/create”, type.to_sym => {}
end

When “the user adds a valid $type” do |type|
post “/#{type.pluralize}/create”, type.to_sym => valid_attributes
end

Then “there should be $number more $type? in the system” do |
number, type|
type.classify.constantize.count.should == (@initial_item_count +
number.to_i)
end

Then “there should be an error message explaining what went wrong” do
response.should have_tag(‘div#errorExplanation’)
end

Then “the user should see the form again” do
response.should have_tag(‘form[method=post]’)
end
end

This more or less works for me. However, I’m interested in two
things. First, is this good practice? It’s DRY, but I’m coupling my
stories to these common steps in a way… And second, is it possible
to define a method in my specific stepgroup, that can be called from
my common stepgroup?
For instance, in the “user adds a valid type” step, I call a
valid_attributes method. I’d like to define that on the specific
stepgroup, but so far I haven’t been able to get it called…

thanks!
bartz

No replies? That doesn’t happen very often :).

regards,
bartz

On 13/03/2008, Bart Z. [email protected] wrote:

Hey list,

I’m refactoring some much-used functionality into a common_steps step
group. Methods like this are in there:

Hi Bart / list

This is not quite what you are thinking but I’ve noticed something
strange
about steps_for. Basically when the steps are define the Given, When,
Then
methods run in the context of a StepGroup, but when they run they have a
different context.

So to call a method in a step group you have to do something like this:

steps_for :login do
def sign_in(page, username, password)
# …
end

Given “a signed-in support user” do
# …
@page = browser.open_page("/signin")
steps_for(:login).sign_in(@page, “[email protected]”,
“support-password”)
end

end

(If you wonder about the code, I’m using Selenium not Rails Stories)

Two consequences of this scoping :

  • you have to use steps_for(:login) as the explicit receiver of the
    sign_in
    method
  • you have to pass in the instance variable because when the code runs,
    sign_in puts the instance variables in the StepGroup, not in whatever
    object
    the runner uses (didn’t bother to figure that out)

Really strange behaviour - I wonder if there’s a better way to do this.
Am
I going about it the wrong way by using methods in steps_for? Comments
welcome

Ashley

On Mon, Mar 17, 2008 at 7:05 AM, Ashley M.
[email protected] wrote:

This is not quite what you are thinking but I’ve noticed something strange

(If you wonder about the code, I’m using Selenium not Rails Stories)

Two consequences of this scoping :

  • you have to use steps_for(:login) as the explicit receiver of the sign_in
    method
  • you have to pass in the instance variable because when the code runs,
    sign_in puts the instance variables in the StepGroup, not in whatever object
    the runner uses (didn’t bother to figure that out)

I have mixed feelings about this. If you do build up a library of step
groups, having explicit scoping like this can be a great benefit.
Agreed it makes things less convenient otherwise.

I can see copying the helper methods to the scope in which the steps
are executed. WDYT?

David

I have mixed feelings about this. If you do build up a library of step
groups, having explicit scoping like this can be a great benefit.
Agreed it makes things less convenient otherwise.

Hi David

Not sure I follow. Do you mean explicit scoping as having to type
“steps_for(:login).”? If so, I guess that would be handy to call
methods
across step groups, but that would probably be bad style if they were in
different files. I see these helper methods as just a factoring out of
identical code.

I can see copying the helper methods to the scope in which the steps

are executed. WDYT?

Do you mean copy and paste? Or have the code track down the methods you
created in the StepGroup scope and copy them into the runner scope? If
so
that would be cool, it would be transparent then. Name clashes could
be an
issue though.

Syntax day-dreaming led me to think of something like this:
Given “a signed-in support user called ‘$name’” do |name|
@support_user = SupportUser.new
# log in, etc
end

Given “something that needs a support user” do
give_me “a signed-in support user called ‘Fred’”
@support_user.support_someone
end

or
When “user signs in with ‘$username’ and ‘$password’” do |username,
password|
# type form, click submit etc
end

Given “a signed-in support user called ‘$name’” do |name|
perform_step “user signs in with ‘support_user’ and ‘secret’”
end

or
Then “user should see text ‘$text’” do |text|
page.should =~ /text/
# type form, click submit etc
end

Then “user should see their details” do
include_requirement “user should see text ‘Adam’”
include_requirement “user should see text ‘Smith’”
include_requirement “user should see text ‘[email protected]’”
end

Is anything like this currently possible? If not, would it be (a) a
Good
Thing and (b) straightforward to implement?

Ashley

On 17/03/2008, Corey H. [email protected] wrote:

As an interim solution, we added this as helper file in the stories root.
The key was figuring out what to mixin to.

class ActionController::Integration::Session

end

-Corey

Pretty neat! Unfortunately I don’t think I can do something similar.
I’m
using the story runner raw to drive selenium, so only have access to the
RSpec library and nowhere to inject these helper methods.

As an interim solution, we added this as helper file in the stories
root.
The key was figuring out what to mixin to.

class ActionController::Integration::Session
def with_input(id)
with_tag(‘input[id=?]’,id)

end

def with_label(text)
    with_tag('label',text)
end

def show_login_form
    with_tag('h2','Log In')
    have_tag ('form[action=?]','/sessions') do
        with_input('username')
        with_input('password')
        with_tag('input[class=?]','image-submit')
    end
end

def show_invitation_form
    have_tag('form[action=?][method=?]',

membership_application_path(:show), ‘get’) do
with_label(‘Invitation Code:’)
with_input(‘code’)
end
end
end

-Corey

On Mon, Mar 17, 2008 at 9:11 AM, Ashley M.
[email protected]

I have been putting helper methods inside of my own modules and then
including them in RSpec::Story::World, which included in the context
that stories are defined and run in (David, feel free to correct me if
this is not 100% accurate).

module Spec::Story::World
def foo
# this is now available to all stories being run
end
end

Zach

On Mon, Mar 17, 2008 at 9:41 AM, Ashley M.

On 17-mrt-2008, at 14:51, Zach D. wrote:

I have been putting helper methods inside of my own modules and then
including them in RSpec::Story::World, which included in the context
that stories are defined and run in (David, feel free to correct me if
this is not 100% accurate).

Hmm, maybe I should clarify some more…

Imagine the following, untested, proof-of-idea code:

steps_for(:adding_posts) do
def valid_post
{ :title => ‘My First Post’ }
end
end

steps_for(:common) do
Given “a valid post” do
post “/posts/create”, post => valid_post
end
end

valid_post is not defined for steps_for(:common).

regards,
bartz

On 17/03/2008, Bart Z. [email protected] wrote:

common_steps stepgroup.

regards,
bartz

Bartz,

Without checking, I assume this could be done as

steps_for :common do
Given “something” do
steps_for(:login).sign_in(…)
end
end

Is that what you mean?

Ashley

Hmm, all of a sudden this thread is spiraling away from my original
question :). Which is good of course :).
I’ve made some inline comments.

On 17-mrt-2008, at 13:12, David C. wrote:

So to call a method in a step group you have to do something like
steps_for(:login).sign_in(@page, “[email protected]”,
“support-password”)
end

I can see how this would work for you, but I actually want something
more abstracted.
You’re specifing the sign_in method inside the same stepgroup, but I
want to reference it from another stepgroup. So, to follow your
example, I want to call sign_in(page, username, password) from my
common_steps stepgroup.

regards,
bartz

On 17-mrt-2008, at 15:01, Ashley M. wrote:

common_steps stepgroup.
Given “something” do
steps_for(:login).sign_in(…)
end
end

Is that what you mean?

Very close, but not quite :). In my common step group, I’d like to
call a (for instance) valid_attributes method, which is defined on
the stepgroup which is used in my story. Hope that makes sense…

regards,
bartz

On Mon, Mar 17, 2008 at 9:59 AM, Bart Z. [email protected]
wrote:

 post "/posts/create", post => valid_post

end
end

valid_post is not defined for steps_for(:common).

I’m sorry my last email should have said Spec::Story::World not
RSpec::Story::World. And your steps are executed in the context of
Spec::Story::World, so it doesn’t matter if the method is defined
inside of your steps for.

I understand what you want to do, but you can write better helpers
which don’t have this problem. For example I use the form_test_helper
to submit forms in Story’s, so I don’t have to call “post” directly. I
have a “submit_event_form” which submits a valid form by default.

ie:

def submit_event_form
submit_form “event-form” do |form|
form.event.name = “Foo”
end
end

Then in my step matcher I have something like:

When “they submit the event form with invalid information” do
submit_event_form do |form|
form.event.name = “”
end
end

If I have to reuse that in more then one place I pull it out into a
submit_event_form_with_invalid_information method.

Hello,

I’m having some trouble working out what the granularity of stories
should be.

I have a use-case ‘manage page’, for a blogging system (like wordpress)
I’m building.

The single use-case covers - add page,delete page,edit page,preview page
actions.

With the use-case we avoided getting too fine a level of granularity
(i.e. add page use-case, delete page use-case…), to keep the clients
and us sane.

I tried to maintain a convention of converting a use-case into a rspec
story. Mainly to make it easier for the client to engage in the
stories.

Example Story (High level):

Story: Web admin manages pages within the admin system
Scenario: Add page
Scenario: edit page.
Scenario: delete page.

I’m unsure if this granularity is productive for a rspec story. Whether
it will lead to a bloated story and if the scenarios become less
obviously link to the title/narrative. I have a nagging doubt that
perhaps it should be:

Example Story (Low level)

Story: Web admin adds a page
Scenario: without some special fields
Scenario: Setting publish dates

Have people experienced this issue before?
Does anyone have any comments or suggestions?

Thanks,
Joseph W.
http://www.joesniff.co.uk

On Mon, 2008-03-17 at 09:40 +0100, Bart Z. wrote:

group. Methods like this are in there:
When “the user adds a valid $type” do |type|
wrong" do
stories to these common steps in a way… And second, is it possible
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users


rspec-users mailing list
[email protected]
http://rubyforge.org/mailman/listinfo/rspec-users

Latest News:-

  • www.phaidon.com launch their new site on WORKSsitebuilder

  • www.pukkaherbs.com are experts in all things Ayurvedic. They have
    launched their new store on WORKSsitebuilder


This email was obviously intended for the people nnotremed in the
message. It may be confidential and/or legally privileged. If you have
received it by mistake, please take no action based on it, copy it, or
show it to anyone - just delete it and let us know about the error.
Also, we should point out that any opinions expressed are not
necessarily those of eShopworks.

Unfortunately email cannot be guaranteed to be secure or error-free and
thus this email should not be construed as a solicitation for, or offer
of contract. If verification is required please ask us for a hard-copy.

And finally, while we’ve scanned this email on 3/4/2008 to make sure it
is virus free to be on the safe side we recommend that you also scan it
with your own antivirus software.

On 03/04/2008, joseph [email protected] wrote:

Example Story (High level):

Story: Web admin manages pages within the admin system
Scenario: Add page
Scenario: edit page.
Scenario: delete page.

I’m unsure if this granularity is productive for a rspec story.

Hi Jospeh

This seems too coarse to me. The controller I’m working on now will end
up
with a corresponding story for each of your scenarios. My scenarios are
along the lines of “User edits page with valid details”, “User edits
page
with missing details”, “User edits page and clicks cancel”, “User with
insufficient priveleges tries to delete page” etc. I try to make a
scenario
for each common or complex thing that changes the state of the system -
they
would never fit in one story.

Ashley

On Thu, Apr 3, 2008 at 5:34 AM, Ashley M.
[email protected] wrote:

On 03/04/2008, joseph [email protected] wrote:

Example Story (High level):

Story: Web admin manages pages within the admin system
Scenario: Add page
Scenario: edit page.
Scenario: delete page.

This seems too coarse to me. The controller I’m working on now will end up
with a corresponding story for each of your scenarios. My scenarios are
along the lines of “User edits page with valid details”, “User edits page
with missing details”, “User edits page and clicks cancel”, “User with
insufficient priveleges tries to delete page” etc. I try to make a scenario
for each common or complex thing that changes the state of the system - they
would never fit in one story.

On the other hand. Keeping these finer grained scenarios within a
single story allows branching using GivenScenario which only works
with scenarios within the same story.

Story: Web admin manages pages within the admin system
Scenario: Add page

Scenario: edit page with valid details
GivenScenario: Add page

Scenario: edit page with missing details
GivenScenario: Add page

Scenario: user with sufficient privileges deletes page
GivenScenario: Add page

Scenario: user with insufficient privileges deletes page
GivenScenario: Add page

Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

On 3-apr-2008, at 14:12, Rick DeNatale wrote:

Scenario: delete page.
a scenario
for each common or complex thing that changes the state of the
system - they
would never fit in one story.

On the other hand. Keeping these finer grained scenarios within a
single story allows branching using GivenScenario which only works
with scenarios within the same story.

I am having the same struggles with the granularity. Is there a good
“sample” app out there on the interweb?
Or perhaps someone from the list wants to share their story? :slight_smile:

gr,
bartz

On Thu, Apr 3, 2008 at 8:25 AM, Bart Z. [email protected]
wrote:

Story: Web admin manages pages within the admin system
with missing details", “User edits page and clicks cancel”, "User

I am having the same struggles with the granularity. Is there a good
“sample” app out there on the interweb?
Or perhaps someone from the list wants to share their story? :slight_smile:

I addressed this in my talk at ETEC last week. Slides are here:
http://www.chariotsolutions.com/slides/pdfs/ete2008-IntegrationTestingWithRSpec.pdf

Cheers,
David

On 3-apr-2008, at 14:31, David C. wrote:

Example Story (High level):
along the lines of “User edits page with valid details”, "User
single story allows branching using GivenScenario which only works
with scenarios within the same story.

I am having the same struggles with the granularity. Is there a good
“sample” app out there on the interweb?
Or perhaps someone from the list wants to share their story? :slight_smile:

I addressed this in my talk at ETEC last week. Slides are here:
http://www.chariotsolutions.com/slides/pdfs/ete2008-
IntegrationTestingWithRSpec.pdf

Dang. Until The Book comes out, this is probably the best best-
practices source for plain text stories with rspec.
This should be on the wiki…

gr,
bartz

On Thu, Apr 3, 2008 at 10:59 AM, Ashley M.
[email protected] wrote:

available? Google only returns answers about JBehave.
The only documentation I’ve seen was the answer which Dave C. gave
here when I asked about nesting scenarios.

That and the source code of course.


Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs