Started moving selenium on rails tests over to RSpec stories. See the updated README_DEVELOPERS for info on running the new tests.

This commit is contained in:
Luke Melia 2008-06-19 00:14:04 -04:00
parent 85dc6f4898
commit d47e863dfc
12 changed files with 257 additions and 74 deletions

View file

@ -10,12 +10,13 @@
:title =>"Delete this note",
:class=>"delete_item",
:id => "delete_note_"+note.id.to_s),
:update => dom_id(note),
{:update => dom_id(note),
:loading => visual_effect(:fade, dom_id(note, 'container')),
:complete => "Element.remove('#{dom_id(note, 'container')}');",
:url => note_path(note),
:method => :delete,
:confirm => "Are you sure that you want to delete the note \'#{note.id.to_s}\'?" ) + " " -%>
:confirm => "Are you sure that you want to delete the note \'#{note.id.to_s}\'?" },
{ :class => 'delete_note' }) -%> 
<%= link_to_function(image_tag( "blank.png", :title => "Edit item", :class=>"edit_item"),
"Element.toggle('#{dom_id(note)}'); Element.toggle('#{dom_id(note, 'edit')}'); Effect.Appear('#{dom_id(note, 'edit')}'); Form.focusFirstElement('#{dom_id(note, 'edit_form')}');" ) + " | " %>
<%= link_to("In: " + note.project.name, project_path(note.project), :class=>"footer_link" ) %>&nbsp;|&nbsp;

View file

@ -12,8 +12,10 @@ To avoid showing the migrations as tests are run, add the following to your data
If you want to run tests using another database, that's fine, too. Just change your database.yml accordingly.
3. SELENIUM TESTS
3. SELENIUM TESTS (Selenium on Rails)
This testing style is deprecated and are being moved over to Selenium via RSpec stories by lukemelia (See #4 below for the new style).
To run selenium tests, start Tracks in test mode using
script/server -e test
@ -24,4 +26,25 @@ Then open a browser to
and interact with the test runner.
For more information about Selenium on Rails, see vendor/plugins/selenium-on-rails/README
For more information about Selenium on Rails, see vendor/plugins/selenium-on-rails/README
4. RSPEC STORY RUNNER TESTS
To run the stories, which are browser tests using selenium, start Tracks in test mode using
rake db:test:prepare
script/server -e test
Then start Selenium by running
selenium
which is a script installed with the Selenium gem (sudo gem install Selenium)
Once the site and selenium server are running, then run all stories with
script/story
or a specific set with
script/story stories/login/*.story

View file

@ -7,6 +7,7 @@ require 'spec'
require 'spec/rails'
require 'spec/story'
require 'webrat/selenium'
require 'action_controller/test_process'
module Spec
module Story
@ -47,10 +48,30 @@ class SeleniumRailsStory < Test::Unit::TestCase
end
end
def should_not_see(text_or_regexp)
if text_or_regexp.is_a?(Regexp)
response.should_not have_tag("*", text_or_regexp)
else
response.should_not have_tag("*", /#{Regexp.escape(text_or_regexp)}/i)
end
end
def response
webrat_session.response_body
end
def logged_in_as(user)
visits("/selenium_helper/login?as=#{user.login}")
end
def selenium
SeleniumDriverManager.instance.running_selenium_driver
end
def badge_count_should_show(count)
response.should have_tag('#badge_count', count.to_s)
end
def method_missing(name, *args)
if webrat_session.respond_to?(name)
webrat_session.send(name, *args)
@ -70,6 +91,7 @@ end
class DatabaseResetListener
include Singleton
def scenario_started(*args)
if defined?(ActiveRecord::Base)
connection = ActiveRecord::Base.connection
@ -79,24 +101,23 @@ class DatabaseResetListener
end
end
def scenario_succeeded(*args)
def method_missing sym, *args, &block
# ignore all messages you don't care about
end
alias :scenario_pending :scenario_succeeded
alias :scenario_failed :scenario_succeeded
end
class CookieResetListener
include Singleton
def scenario_started(*args)
%w[tracks_login auth_token _session_id].each do |cookie_name|
SeleniumDriverManager.instance.running_selenium_driver.get_eval("window.document.cookie = '#{cookie_name}=;expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/';")
end
end
def scenario_succeeded(*args)
def method_missing sym, *args, &block
# ignore all messages you don't care about
end
alias :scenario_pending :scenario_succeeded
alias :scenario_failed :scenario_succeeded
end
class Spec::Story::Runner::ScenarioRunner

View file

@ -0,0 +1,41 @@
Story: View, add, remove notes
As a Tracks user
I want to view, add, and remove notes
So that I can keep important information easily accessible
Scenario: View and toggle notes
Given a logged in user Luis
And Luis has two projects with one note each
When Luis visits the notes page
Then two notes should be visible
And the badge should show 2
When Luis clicks Toggle Notes
Then the body of the notes should be shown
Scenario: Add a new note
Given a logged in user Luis
And Luis has one project Pass Final Exam with no notes
When Luis adds a note from the Pass Final Exam project page
Then Luis should see the note on the Pass Final Exam project page
And Luis should see the note on the notes page
And the badge on the notes page should show 1
Scenario: Delete note from notes page
Given a logged in user Luis
And Luis has one project Pass Final Exam with 2 notes
When Luis visits the notes page
And Luis deletes the first note
Then the first note should disappear
Then the badge should show 1
Scenario: Link to note
Given a logged in user Luis
And Luis has one project Pass Final Exam with 1 note
When Luis visits the Pass Final Exam project page
And clicks the icon next to the note
Then he should see the note text

View file

@ -1,19 +1,6 @@
steps_for :login do
Given "an admin user Reinier with the password abracadabra" do
@reinier = User.create!(:login => 'reinier', :password => 'abracadabra', :password_confirmation => 'abracadabra', :is_admin => true)
@reinier.create_preference
end
Given "Reinier is not logged in" do
end
Given "no users exist" do
User.delete_all
end
Given "a visitor named Reinier" do
end
steps_for :login do
include_steps_for :users
When "Reinier submits the login form with an incorrect password" do
fills_in 'Login', :with => 'reinier'
fills_in 'Password', :with => 'incorrectpass'

94
stories/steps/notes.rb Normal file
View file

@ -0,0 +1,94 @@
steps_for :notes do
include_steps_for :users
Given "Luis has two projects with one note each" do
project_a = @luis.projects.create!(:name => 'project A')
project_a.notes.create!(:user_id => @luis.id, :body => 'note for project A')
project_b = @luis.projects.create!(:name => 'project B')
project_b.notes.create!(:user_id => @luis.id, :body => 'note for project B')
end
Given "Luis has one project Pass Final Exam with no notes" do
@exam_project = @luis.projects.create!(:name => 'Pass Final Exam')
end
Given "Luis has one project Pass Final Exam with 1 note" do
Given "Luis has one project Pass Final Exam with no notes"
@exam_project.notes.create!(:user_id => @luis.id, :body => 'exam note 1')
end
Given "Luis has one project Pass Final Exam with 2 notes" do
Given "Luis has one project Pass Final Exam with 1 note"
@exam_project.notes.create!(:user_id => @luis.id, :body => 'exam note 2')
end
When "Luis visits the notes page" do
visits '/notes'
end
When "Luis adds a note from the Pass Final Exam project page" do
When "Luis visits the Pass Final Exam project page"
clicks_link 'Add a note', :wait => :ajax
fills_in 'new_note_body', :with => 'new exam note'
clicks_button 'Add note', :wait => :ajax
end
When "Luis visits the Pass Final Exam project page" do
visits "/projects/#{@exam_project.to_param}"
end
When "Luis deletes the first note" do
selenium.click "css=a.delete_note"
selenium.get_confirmation.should =~ /delete/
end
When "clicks the icon next to the note" do
selenium.click "css=a.link_to_notes"
wait_for_page_to_load
end
When "Luis clicks Toggle Notes" do
clicks_link 'Toggle notes', :wait => :effects
end
Then "the body of the notes should be shown" do
wait_for_effects
selenium.is_visible("css=body.notes").should be_true
end
Then "Luis should see the note on the Pass Final Exam project page" do
should_see "new exam note"
end
Then "Luis should see the note on the notes page" do
visits '/notes'
should_see "new exam note"
end
Then "the badge on the notes page should show 1" do
badge_count_should_show(1)
end
Then "the first note should disappear" do
wait_for_ajax_and_effects
should_not_see 'exam note 1'
end
Then "the badge should show 1" do
wait_for_ajax_and_effects
badge_count_should_show(1)
end
Then "the badge should show 2" do
badge_count_should_show(2)
end
Then "two notes should be visible" do
should_see 'note for project A'
should_see 'note for project B'
end
Then "he should see the note text" do
should_see 'exam note 1'
end
end

30
stories/steps/users.rb Normal file
View file

@ -0,0 +1,30 @@
steps_for :users do
Given "an admin user Reinier with the password abracadabra" do
@reinier = User.create!(:login => 'reinier', :password => 'abracadabra', :password_confirmation => 'abracadabra', :is_admin => true)
@reinier.create_preference
end
Given "an admin user Reinier" do
Given "an admin user Reinier with the password abracadabra"
end
Given "a logged in user Luis" do
@luis = User.create!(:login => 'luis', :password => 'sesame', :password_confirmation => 'sesame', :is_admin => false)
@luis.create_preference
logged_in_as @luis
end
Given "no users exist" do
User.delete_all
end
Given "Reinier is not logged in" do
#nothing to do
end
Given "a visitor named Reinier" do
#nothing to do
end
end

View file

@ -1,27 +0,0 @@
setup :fixtures => :all
login :as => 'admin'
open "/notes/"
assert_text 'badge_count', '2'
# add new note
open "/projects/1"
click "css=#add_note_href"
type "css=#new_note_body", "new note"
click "add-new-note"
# wait until new note is saved
wait_for_text_not_present "new note"
wait_for_text_present "new note"
# check badge count is one more
open "/notes/"
assert_text 'badge_count', '3'
# delete note
click "css=#delete_note_1"
assert_confirmation "Are you sure that you want to delete the note '1'?"
# check badge decreased
wait_for_visible "flash"
wait_for_element_not_present "container_note_1"
assert_text 'badge_count', '2'

View file

@ -1,5 +0,0 @@
setup :fixtures => :all
login :as => 'admin'
open "/projects/1"
click_and_wait "css=#note_1 .link_to_notes"
assert_element_present "note_1"

View file

@ -1,5 +0,0 @@
setup :fixtures => :all
login :as => 'admin'
open "/notes/"
assert_element_present "note_1"
assert_element_present "note_2"

View file

@ -1,5 +0,0 @@
setup :fixtures => :all
login :as => 'admin'
open "/notes"
click "css=#toggle-notes-nav"
wait_for_element_present "css=body.notes"

View file

@ -11,24 +11,52 @@ module Webrat
end
def fills_in(label_text, options)
@selenium.type("webrat=#{Regexp.escape(label_text)}", "#{options[:with]}")
@selenium.type("webrat=#{label_text}", "#{options[:with]}")
end
def response_body
@selenium.get_html_source
end
def clicks_button(button_text = nil)
def clicks_button(button_text = nil, options = {})
button_text, options = nil, button_text if button_text.is_a?(Hash) && options == {}
button_text ||= '*'
@selenium.click("button=#{button_text}")
@selenium.wait_for_page_to_load()
wait_for_result(options[:wait])
end
def clicks_link(link_text)
@selenium.click("webratlink=#{Regexp.escape(link_text)}")
@selenium.wait_for_page_to_load()
def clicks_link(link_text, options = {})
@selenium.click("webratlink=#{link_text}")
wait_for_result(options[:wait])
end
def wait_for_result(wait_type)
if wait_type == :ajax
wait_for_ajax
elsif wait_type == :effects
wait_for_effects
else
wait_for_page_to_load
end
end
def wait_for_page_to_load(timeout = 15000)
@selenium.wait_for_page_to_load(timeout)
end
def wait_for_ajax(timeout = 15000)
@selenium.wait_for_condition "window.Ajax.activeRequestCount == 0", timeout
end
def wait_for_effects(timeout = 15000)
@selenium.wait_for_condition "window.Effect.Queue.size() == 0", timeout
end
def wait_for_ajax_and_effects
wait_for_ajax
wait_for_effects
end
def selects(option_text, options = {})
id_or_name_or_label = options[:from]