User perspective
testing using Ruby
Michał Czyż@cs3b
User perspective
testing using Ruby
https://twitter.com/#!/moonmaster9000/status/169540724474384384
https://twitter.com/#!/athoshun/statuses/165138347432488962
https://twitter.com/#!/defkode/status/124066265642967040http://www.jackkinsella.ie/2011/09/26/why-bother-with-cucumber-testing.html
http://blog.jonasbandi.net/2010/09/acceptance-vs-integration-tests.html
http://www.funnypictures24.com/funny2/funnyphotoshopped166.jpg
KAMELEON
click
click 'Administrations', 'Products', click :and_dismiss => 'Delete' click :and_accept => 'Delete' click :image => 'OK' click :element => "#some_div"
fill_in
fill_in 'www.selleo.com' => 'Link' fill_in 'www.selleo.com' => 'Link'
'Selleo' => 'Company','Poland' => 'Country'
fill_in :check => 'Remember me' fill_in :check => [ 'Red',
'Green','Grey' ]
fill_in :uncheck => 'Remember me' fill_in :uncheck => [ 'Red',
'Green','Grey' ]
fill_in :choose => 'Female' fill_in :choose => [ 'Europe',
'Poland' ]
fill_in :select => { 'Poland' => 'Countries' }
fill_in :select => { 'Poland' =>
'Countries',
'Silesia' => 'Provinces' }
fill_in :unselect => { 'Poland' => 'Countries' }
fill_in :unselect => { 'Poland' =>
'Countries',
'Silesia' => 'Provinces' }
fill_in :attach => { 'me.png' => 'Avatar'}
fill_in :attach => { 'me.png' =>
'Avatar', 'selleo.png' =>
'Company Logo' }
# spec_helper.rbKameleon.configure do |c| c.assets_dir = '(...)/fixtures/assets'end
see
see 'www.selleo.com',
see 'one','another piece of text','and another one'
see :link => 'Wrocloverb' see :link => { 'Wrocloverb' => 'http://wrocloverb.com' } see :links => { 'Wrocloverb' => 'http://wrocloverb.com', 'Selleo' => 'http://www.selleo.com' }
see :image => 'OK' see :image => 'icon_ok.png' see :images => [ 'completed',
'approved' ]
see 'Ruby' => 'First Name' see 'Wisła' => 'City',
'Silesia' => 'Province'
see :field => 'Email' see :fields => ['Email',
'City','Street' ]
see :empty => 'Last Name' see :empty => [ 'Last Name',
'City' ]
see :checked => 'Remember me' see :checked => [ 'Newsletter',
'Remember me' ]
see :unchecked => 'Remember me' see :unchecked => [ 'Newsletter',
'Remember me' ]
see :selected => { 'Poland' => 'Countries' }
see :selected => { 'Poland' =>
'Countries',
'Silesia' => 'Provinces' }
see :selected => { [ 'Red','Green','Orange' ] =>
'Colors' }
see :unselected => { 'Poland' => 'Countries' }
see :unselected => { 'Poland' =>
'Countries',
'Silesia' => 'Provinces' }
see :unselected => { [ 'Red','Green','Orange' ] =>
'Colors' }
see :ordered => [ 'Bart', 'Tom',
'Anette' ]
see 5 => ".element" see 3 => :menu_item see 5 => [:xpath, '//div[@class="element"]' ]
not_see
not_see 'php'
not_see 'java','c#','.net'
not_see :field => 'Email' not_see :fields => [ 'Email',
'City','Street' ]
not_see :link => 'Wrocloverb' not_see :link => { 'Wrocloverb' =>
'http://wrocloverb.com' }
not_see :links => [ 'Wrocloverb', 'Selleo' ]
not_see :image => 'OK' not_see :image => 'ok.png' not_see :images => [ 'OK',
'rails.png' ]
act_as
visit('/') act_as(:default) do
click 'Products'end
visit('/') create_session(:user)visit('/login') act_as(:default) do
not_see :field => 'Email'end act_as(:user)see :fields => [ 'Email', 'Password' ]
http://s1.desktopia.net/wp-content/uploads/walls/thumbs/Funny-Chameleon-575x359.jpg
click_link "Products"within('table.index tr:nth-child(2)') {
page.should have_content("apache baseball cap") }
within('table.index tr:nth-child(3)') { page.should have_content("zomg shirt") }
click_link "admin_products_listing_name_title"within('table.index tr:nth-child(2)') {
page.should have_content("zomg shirt") }within('table.index tr:nth-child(3)') {
page.should have_content("apache baseball cap") }
https://github.com/spree/spree/blob/master/core/spec/requests/admin/products/products_spec.rb#L22
click "Products"within('table.index) do
see :ordered => [ "apache baseball cap","zomg shirt" ]
end click "admin_products_listing_name_title"within('table.index') do
see :ordered => [ "zomg shirt","apache baseball cap"]
end
click_link "Products"click_link "admin_new_product" fill_in "product_name", :with => "Baseball Cap"fill_in "product_sku", :with => "B100"fill_in "product_price", :with => "100"fill_in "product_available_on", :with =>
"2012/01/24"select "Size", :from => "Prototype"check "Large"click_button "Create"page.should have_content("successfully created!")
https://github.com/spree/spree/blob/master/core/spec/requests/admin/products/products_spec.rb#L77
click "Products","admin_new_product"
fill_in "Baseball Cap" => "product_name",
"B100" => "product_sku","100" => "product_price","2012/01/24" => "product_available_on",:select => {
"Size" => "Prototype" },
:check => "Large"click "Create"see "successfully created!"
within(:css, 'table.index tr:nth-child(2)') { click_link "Edit" }
fill_in "adjustment_amount", :with => "99"fill_in "adjustment_label", :with => "rebate 99"click_button "Continue"page.should have_content("successfully
updated!")page.should have_content("rebate 99")page.should have_content("$99.00")
https://github.com/spree/spree/blob/master/core/spec/requests/admin/orders/adjustments_spec.rb#L48
within(:row => 2) { click "Edit" } fill_in 99 => "adjustment_amount",
"rebate 99" => "adjustment_label"click "Continue"see "successfully updated!",
"rebate 99","$99.00"
click_link "Orders"within('table#listing_orders tbody tr:nth-child(1)') { click_link "R100" } click_link "Payments"within('#payment_status') { page.should have_content("Payment: balance due") } find('table.index tbody tr:nth-child(2)
td:nth-child(2)').text.should == "$39.98"find('table.index tbody tr:nth-child(2)
td:nth-child(3)').text.should == "Credit Card"find('table.index tbody tr:nth-child(2)
td:nth-child(4)').text.should == "pending" https://github.com/spree/spree/blob/master/core/spec/requests/admin/orders/payments_spec.rb#L32
click "Orders"within('table#listing_orders', :row => 1) do
click_link "R100"end click "Payments"within('#payment_status') do
see("Payment: balance due")end within(:cell =>[2,2]) { see "$39.98" }within(:cell =>[2,3]) { see "Credit Card" }within(:cell =>[2,4]) { see "pending" }
DEMOinspired by a case takenfrom a production system
create_session(:user)sign_in_as(:user)
create_session(:admin)sign_in_as(:admin)
act_as(:user) do not_see 'IS OPEN', 'IS CLOSED' within(:right_column) do
not_see 'Submit a proposal', 'Submit' endend
act_as(:admin) do within(:menu) { click 'Set Contest' } fill_in 'S vs C' => 'Name', '2012-01-19 08:00:00' => 'starts at', '2012-01-20 08:00:00' => 'ends at' click 'Create Contest' see 'Contest was successfully created'end
Timecop.travel(2012, 1, 19, 8, 59, 55) do act_as(:user) do
refresh_pagesee 'IS CLOSED'sleep 10not_see 'IS CLOSED'see 'IS OPEN'
endend
Timecop.travel(2012, 1, 19, 9, 1, 1) do act_as(:user) do
refresh_page%w(ruby ... haml).each do |content|
fill_in content => 'proposal_content' click 'Submit'
end end
act_as(:admin) do click 'Sticker proposals', 'Load more' %w(ruby ... html).each do |c|
within(:proposal_with_content => c) do click 'favorite'
end endend
act_as(:user) do refresh_page %w(...).each_with_index do |c, r|
within(:proposal_with_content => c) do click "Rate #{r+1} out of 5"
end endend
act_as(:user) do %w(ruby coffescript).each do |c|
within(:proposal_with_content => c) do click 'Comment' fill_in "sample text #{c}" => 'body' click 'Create comment'
end endend
Timecop.travel(2012, 1, 20, 11, 10, 10) do act_as(:admin) do
refresh_pageclick 'Load more'%w(html python).each do |c|
within(:proposal_with_content => c) do click 'choose' end
end end
act_as(:user) do refresh_page click 'Gallery' within(:ordered_list) do
see *(%w(html python))not_see *(%w(ruby ... coffescript))
endend
act_as(:admin) do click 'Gallery', 'Add new production picture' fill_in 'Sample title for picture' => 'Title', :attach => {'pict.jpg' => 'Image'} click 'Create Gallery image'end
act_as(:user) do click 'Gallery' fill_in :select => {'S vs C' => 'contest_id'} within(:gallery_list) do
see :image => 'Thumb_pict' endend
act_as(:admin) do click 'Add new contest sticker' fill_in 'Sample title for picture' => 'Title', :attach => {'pict2.jpg' => 'Image'} click 'Create Gallery image'end
act_as(:user) do click 'Gallery' fill_in :select => {'S vs C' => 'contest_id'} within(:gallery_list) do
see :image => 'Thumb_pict2' endend
http://2.bp.blogspot.com/_bVtGlUaW-tA/TMOUvmYXzHI/AAAAAAAAP90/SR5yHHWydN4/s1600/Mech_chameleon_by_tommaso_sanguigni.jpg
# gemfilegem 'kameleon', '>= 0.2.0.alpha.2'gem 'headless' # spec_helper.rbrequire 'kameleon'require 'kameleon/ext/rspec/all'
# orrequire 'kameleon/ext/rspec/dsl' # optional# .../rspec/garbage_collector'# .../rspec/headless'
SHARED DB CONNECTION
example: lib/kameleon/ext/active_record/
● shared_single_connection.rb
● shared_single_connection_with_spork.rb
RSpec.configure do |config| config.before(:suite) do
@headless = Headless.new(:display => '100')@headless.start
end config.after(:suite) do
@headless.stop if defined?(@headless) endend
HEADLESS
require 'kameleon/ext/rspec/headless'
config.after(:each) doif exception = example.instance_variable_get(:@exception)
Ripl.start :binding => binding
end end
RIPL
example: lib/kameleon/utils/debug_console.rb
LINKS
RSPEC● http://pragprog.com/book/achbd/the-rspec-book● https://www.relishapp.com/rspec
CAPYBARA● https://github.com/jnicklas/capybara
XPATH● http://www.w3.org/TR/xpath/● https://addons.mozilla.org/en-US/firefox/addon/firepath/
SELENIUM● http://seleniumhq.org/docs/
WEBKIT● https://github.com/thoughtbot/capybara-webkit
KAMELEON
● https://github.com/cs3b/kameleon
THANKS :-)
http://selleo.com/people/michal-czyz
http://cs3b.com
questions ?