Week 10, Day 05
09 / 10 / 2015
What we covered today:
- Warmup
- Rspec
- Cucumber
- Capybara
- Interview Questions
- Homework and Readings
Rspec
So we are getting through all of this Rspec stuff but so far we have only done things like GET requests and checked existence of variables. Now we need to sort out validations such as Post requests and seeing how the page is actually rendered. It isn't overly difficult! This is a really basic version of it.
describe 'POST /fruits' do
describe "A fruit with valid information" do
before do
post :create, { fruit: { name: "Strawberry" } }
end
it "should redirect to the show action" do
# pending # Don't actually run this test!
expect( response ).to redirect_to( fruit_path( assigns(:fruit) ) )
end
it "should increase the number of fruits in the database"
# pending
expect( Fruit.count ).to eq( 1 )
end
end
describe "A fruit with invalid information" do
before do
post :create, { fruit: { name: "" } }
end
it "should give us a 200 success status" do
# pending
expect( response.status ).to eq( 200 )
end
it "should render the new template" do
# pending
expect( response ).to render_template( :new )
end
it "should not increase the number of fruits" do
pending
expect( Fruit.count ).to eq( 0 )
end
end
end
The rails scaffold generates some pretty great tests, so make sure you check that out.
Worth checking out betterspecs as well.
Cucumber
Cucumber is a higher level testing framework for Ruby. Similar approach but we write something that looks a lot more like English. Let's install the gem - gem install cucumber
.
Unlike Rspec, these tests belong in a features folder (in the root path of your project). To run these tests, run cucumber
.
This is what it looks like...
Feature: Calculator
As a young ambitious developer
I want to experiment with Cucumber
And add some numbers together
Scenario: Add two numbers together
Given I have a calculator
And I have the number 5
And I have the number 7
When I add them together
Then I should see the number 12 in the terminal
Now Ruby doesn't understand English so we need to do a bit more work. We need to create step definitions and teach it how to understand them. We do this in a step_definitions folder, lets call the file calculator_steps.rb. To get the code to copy into the file, run cucumber
and copy all of the yellowish code into it (and, of course, save).
Now most of this requires a calculator. So let's create a calculator.rb file in the root directory. This is where we create our class and put all of our methods.
We put all the requirements for our app in the features/support/setup.rb file. In here, for this example, let's make the file look like this. We need to make sure that we reference all necessary Ruby files and gems.
require_relative '../../calculator'
require 'minitest/autorun'
require 'test/unit'
World(Test::Unit::Assertions)
Make sure you run gem install cucumber
, gem install minitest
and gem install test-unit
before you try running cucumber
again.
- As Cucumber doesn't actually know English (which is a shame), we need to teach it what the tests actually mean - so let's have a look at the calculator_steps.rb file.
Given(/^I have a calculator$/) do @calculator = Calculator.new end
- It'll then say there is an uninitialized constant or a NameError. This means that we haven't defined the class Calculator in our calculator.rb file. Let's go ahead and do that.
class Calculator end
- That first one should now pass. So let's do the next step:
Given(/^I have the number (\d+)$/) do |num| @calculator << num end
It will say it doesn't know how to use << operator on @calculator, and that is because we haven't defined that method. So let's work on that! We have created the << method and that pushes a specified number in the input array. That should get us through!
class Calculator def initialize @input = [] end def <<(number) @input << number.to_i end end
- Now let's teach Cucumber how to add!
When(/^I add them together$/) do @result = @calculator.add end
- And then define the add method
def add # @input.inject { |sum, n| sum + n } @input.inject &:+ end
This is what this project looks like that so check this out.
Cucumber with Rails
Create a new Rails project ( railes new cucky -T
) and put a few things in your Gemfile.
group :test do
gem 'cucumber-rails', require: false
gem 'database_cleaner'
end
And then run rails generate cucumber:install
.
That will do all of the necessary steps. We can just add the features from there! To run the tests, we can run cucumber
or rake cucumber
.
It's a similar process for Cucumber with Rails compared to Cucumber with plain Ruby. Make your features - make them pass!
Capybara comes with Cucumber in Rails
Capybara is a way to interact with a browser. This is really handy for testing!
You can do things like the following:
visit "/users/sign_up"
fill_in 'Email', with: email
fill_in 'Password', with: 'chicken'
fill_in 'Password confirmation', with 'chicken'
click_button 'Sign in'
But also a whole heap of other things...
click_link('id-of-link')
click_link('Link Text')
click_button('Save')
click_on('Link Text') # clicks on either links or buttons
click_on('Button Value')
fill_in('First Name', :with => 'John')
fill_in('Password', :with => 'Seekrit')
fill_in('Description', :with => 'Really Long Text...')
choose('A Radio Button')
check('A Checkbox')
uncheck('A Checkbox')
attach_file('Image', '/path/to/image.jpg')
select('Option', :from => 'Select Box')
page.has_selector?('table tr')
page.has_selector?(:xpath, '//table/tr')
page.has_xpath?('//table/tr')
page.has_css?('table tr.foo')
page.has_content?('foo')
expect(page).to have_selector('table tr')
expect(page).to have_selector(:xpath, '//table/tr')
expect(page).to have_xpath('//table/tr')
expect(page).to have_css('table tr.foo')
expect(page).to have_content('foo')
find_field('First Name').value
find_link('Hello').visible?
find_button('Send').click
find(:xpath, "//table/tr").click
find("#overlay").find("h1").click
all('a').each { |a| a[:href] }
find('#navigation').click_link('Home')
expect(find('#navigation')).to have_button('Sign out')
within("li#employee") do
fill_in 'Name', :with => 'Jimmy'
end
within(:xpath, "//li[@id='employee']") do
fill_in 'Name', :with => 'Jimmy'
end
within_fieldset('Employee') do
fill_in 'Name', :with => 'Jimmy'
end
within_table('Employee') do
fill_in 'Name', :with => 'Jimmy'
end
facebook_window = window_opened_by do
click_button 'Like'
end
within_window facebook_window do
find('#login_email').set('[email protected]')
find('#login_password').set('qwerty')
click_button 'Submit'
end
page.execute_script("$('body').empty()")
result = page.evaluate_script('4 + 4');
accept_alert do
click_link('Show Alert')
end
dismiss_confirm do
click_link('Show Confirm')
end
accept_prompt(with: 'Linus Torvalds') do
click_link('Show Prompt About Linux')
end
save_and_open_page
print page.html
page.save_screenshot('screenshot.png')
save_and_open_screenshot
click_link("Password") # also matches "Password confirmation"
Capybara.exact = true
click_link("Password") # does not match "Password confirmation"
click_link("Password", exact: false) # can be overridden