I use this code to submit a form using cucumber
When I fill in "Email" with "example#example.com"
And I fill in "Name" with "user name"
Now I want to fill value in a select box.How can I do that?
That's not code, those are cucumber feature statements. Cucumber will translate those into step definitions, which in turn can contain code that will let you test the thing being described.
You probably have something like web_steps.rb that provides a set of pre-built statements like this, but you should not use them. You should be describing the business behavior of the application you are building, not the low-level UI details. Instead you should write something like this
Given I am on the registration page
When I sign up
Then I should be logged in automatically
And I should see a message stating "Thank you for signing up!"
This gives you an example of what you want to happen when someone signs up (They are logged in automatically and they are thanked for signing up). They way you have it now, you will have to change your specification to match the UI whenever you want to change the name of a field, and the specification should never change unless you are changing your business needs.
So to answer your more technical question, the step definition would look something like this, based on webrat's documentation
fill_in 'email', :with => '123#example.com'
fill_in 'name', :with => 'username'
select 'free account'
click_button 'Signup'
Related
I have a function below
def fill_in_sources_details
click_button 'New Source'
assert_text 'Sources'
fill_in 'text', :with => #source.text
fill_in 'url', :with => #source.url
end
After New Source clicked, new fields added to the page. Sometimes the test fails because the test doesn't wait for new elements to be added so new fields cannot be found be Capybara. I tried to add assert_text 'Sources' which is obvious but it still fails sometimes. Any idea how to fix it?
A number of things could be going on here, some of which depend on which driver and driver version you're using.
You don't actually have a field that matches 'text' - That's not likely here since it works sometimes.
The initial click_button 'New Source' is missing the actual button. This could happen depending on which driver you're using if the button animates on to the page (slide in, zoom in, etc). You can tell if that's what's happening by putting a sleep 5 before the click_button. If that fixes the issue then you should look into disabling animation in test mode. It will speed up your tests and make them more reliable.
The click_button is happening but it takes too long for the fields to show on the page (slow ajax request, etc). Putting the sleep 5 after the click_button should have diagnosed that, however maybe it's taking longer than 5 seconds. The assert_text 'Sources' is a good attempt to diagnose that, as long as the text 'Sources' would only be on the page when the input is visible but that text seems too generic for that (it's probably on the current page already). You can always pass a wait option to fill_in, which will make it wait longer for the element to appear
fill_in 'text', :with => #source.text, wait: 20
You have an intermittent error in your app that's preventing the fields from showing. Diagnose that by catching the ElementNotFound, pausing the app and looking at the errors in your browser
begin
fill_in 'text', :with => #source.text, wait: 20
rescue Capybara::ElementNotFound
binding.pry # byebug, etc - whatever debugging you use
end
I'm trying to create a user during an integration test to use for some operations. I'm using devise with :confirmable. The code is the following:
user = User.create({username: "user1", password: "pass1234", password_confirmation: "pass1234", email: "test#email.com"})
user.confirm!
fill_in "Username", :with => user.username
fill_in "Password", :with => user.password
click_button "Sign in"
The problem is that the login fails every time I try it. There are no errors about the user creation, but for some reason the user doesn't seem to "be there" when I try to login. I just get 'Invalid username or password' when I try to sign in. This seems like something to do with the fact that maybe Capybara/Selenium webdriver isn't waiting properly for the database operation to take place before it tries to sign in. If that's the case, how could I test it or fix it?
Is it "wrong" to even be trying to insert into the database during an integration test?
I don't use devise myself so can't really comment on the specifics of the problem you're encountering, but this question caught my eye:
Is it "wrong" to even be trying to insert into the database during an integration test?
Yes, I would say it generally is.
Your integration tests should test your code from the point of view of the user:
Expectations should only depend on what the user can actually see.
Actions should correspond only to what the user can actually do.
Inserting something into the database goes beyond the range of actions that the user has at their disposal. It is something for a unit test perhaps, but not for an integration test.
That being said, you could argue that seeding database data is a bit of an exception to this rule, since you're setting up context for your test (see my comments below).
So, while I like Cucumber for its readability for integration testing and its ability to give us documentation we can share with the client easily, I also find it cumbersome from the development and testing speed standpoints.
I got to thinking today that if I could just print out messages to the RSpec documentation format that documented the "steps", then I could easily replicate the business features of Gherkin but in the simplicity of RSpec. But I can't figure out a way to do this.
What I want is to take something like this:
describe "Login and Authorization Tests" do
before (:each) do
docs "Given I have a user"
#user = FactoryGirl.create(:user)
end
it "A user can belong to one or more user roles" do
docs "And the user has no roles assigned"
#user.roles.length.should eq 0
docs "When I add two roles"
#user.roles << FactoryGirl.create(:role)
#user.roles << FactoryGirl.create(:role)
#user.reload
docs "Then the user should have two roles assigned"
#user.roles.length.should eq 2
end
end
and get this in the documentation
User
Login and Authorization Tests
A user can belong to one or more user roles
Given I have a user
And the user has no roles assigned"
When I add two roles
Then the user should have two roles assigned
Note that the message from "before" shows up in the docs too, and would show up with that line in every test below it.
I'm thinking of forking to see if I can add something like this in, but before I did that, does anyone know if something like this is possible already?
I also contacted the RSpec dev team and someone there posted this add-on called rspec-longrun that could be repurposed for this. I haven't had a chance to try it yet, but it looks very promising. And as a bonus, it includes timing information.
rspec-longrun: https://github.com/mdub/rspec-longrun
Thread on rspec-dev: https://github.com/rspec/rspec-dev/issues/34
You can try Steak, but the difference is not that big.
Or you can try Cucumber with RSpec matchers. In last case, you can fork RSpec and add a new formatter
When writing my scenerios, is it possible to not have to hard code text in the steps?
Like say I am insert a username in a textbox field, and a password in the password field.
If I need to do this in many places, it would be a pain to fix.
Example:
Given I am the registered member "myusername"
And I am on the login page
When I fill in "email" with "email#example.com"
And I fill in "password" with "123"
And I press "Login"
Then I should see "Account Activity"
I don't want my username, email, and password hard-coded.
Okay, you're still using the older version of the cucumber-rails gem which comes with the training wheels installed by default. Read this post by Aslak Hellesøy "The training wheels came off".
The gist of the post is that using web_steps.rb, although it having been the "standard" for years is now terribly wrong and that we should feel bad for doing that.
The purpose of Cucumber is to use it to make readable / understandable features for all people.
Writing a scenario like this is long and boring:
And I am on the login page
When I fill in "email" with "email#example.com"
And I fill in "password" with "123"
And I press "Login"
Then I should see "Account Activity"
What you want to actually be testing is that you should be able to login and after that see something to do with being logged in. Whatever that something is shouldn't be written in the scenario.
So ideally, your Scenario (in a more exciting fashion) would look like this:
When I login successfully
Then I should see that I am logged in
Then the task of doing the legwork goes to some new step definitions. Those two steps aren't defined automatically for you, like web_steps.rb does, but rather need to have them written in a file within feature/step_definitions. What you call the file is up to you, but it'll contain content similar to this:
When /I login successfully/ do
visit root_path
click_link "Login"
fill_in "Email", :with => "you#example.com"
fill_in "Password", :with => "password"
end
Then /^I should see I am logged in$/ do
page.should have_content("Account Activity")
end
No more excessive web_steps.rb file and cleaner step definitions. Exactly what Cucumber should be.
Create a step to encapsulate the logging in behavior as described here
If this works for you, I would then suggest tweaking the Given /I am logged in/ step to capybara calls to get a slight boost to performance. Also, in the future it is recommended that you avoid using web_steps for reasons described here.
Ryan's example is a change from imperative steps to declarative. This is generally a better idea. It means that the implementation has been moved into step definitions which makes the feature more readable and focuses on the behavior instead of the details.
But if you need to be specific with your steps (imperative), you could try something like
Given I am a registered member
And I am on the login page
When I fill in the login form
And I submit the login form
Then I should see I am logged in
You could also combine those steps to make it even simpler. But still, Ryan's idea is probably better in most cases.
Edit: Ryan has written a book. It's quite good. Hi Ryan!
You can create csv file in framework under data folder,add your private values to csv file, then call it in your feature file
I've created a custom cucumber step for checking the destination for a link, and I'm using Cucumber's new built in support in web_steps for scoping these lookups. So I have two cucumber steps involved:
# My step to verify the link
Then /^"([^\"]*)" should link to (.*)$/ do |link_text,page_name|
page.should have_link(link_text, :href => path_to(page_name))
end
# Cucumber's built in step to scope things
# Single-line step scoper
When /^(.*) within ([^:]+)$/ do |step, parent|
with_scope(parent) { When step }
end
I use this by having cucumber scripts that do things like
And "home" should link to the home page within the "Email Signature" section
My problem is that I'm getting ambiguous matches on the above between these two steps, because the 'within' clause can't be told apart from the "the home page", because the latter doesn't have any bounding quotes.
I've tried changing the link step to read like this, thinking it might resolve the ambiguity by not matching the 'within', but I think the 'within' gets swallowed by the preceeding group instead:
Then /^"([^\"]*)" should link to (.*)(?!within)$/ do |link_text,page_name|
page.should have_link(link_text, :href => path_to(page_name))
end
Any thoughts on how to resolve this?
Not directly an answer to the question I posed (for that see Qtax's answer), but here's what I've wound up doing. I think it's a nicer solution anyway, for what it's worth...
I've created a custom version of the scoping helper that looks like this:
Then /^within ([^,]*), (.+)$/ do |parent, step|
with_scope(parent) { When step }
end
This allows me to write steps like this:
And within the "Email Signature" section, "home" should link to the home page
Which I think (a) reads more naturally (it's clearer that we're talking about the link being in the e-mail signature section, not the home page), and (b) works around the problem I was having, because the unquoted 'within' selector is well out of the way of the unquoted page name.
Try something like:
/^"([^"]*)" should link to ((?:(?!within).)+)$/
Don't know anything about Cucumber, I'm just going by what you tried to do.