mirror of
https://github.com/TracksApp/tracks.git
synced 2025-09-22 05:50:47 +02:00
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:
parent
85dc6f4898
commit
d47e863dfc
12 changed files with 257 additions and 74 deletions
|
@ -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" ) %> |
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
41
stories/notes/view_add_remove.story
Normal file
41
stories/notes/view_add_remove.story
Normal 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
|
||||
|
|
@ -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
94
stories/steps/notes.rb
Normal 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
30
stories/steps/users.rb
Normal 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
|
|
@ -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'
|
|
@ -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"
|
|
@ -1,5 +0,0 @@
|
|||
setup :fixtures => :all
|
||||
login :as => 'admin'
|
||||
open "/notes/"
|
||||
assert_element_present "note_1"
|
||||
assert_element_present "note_2"
|
|
@ -1,5 +0,0 @@
|
|||
setup :fixtures => :all
|
||||
login :as => 'admin'
|
||||
open "/notes"
|
||||
click "css=#toggle-notes-nav"
|
||||
wait_for_element_present "css=body.notes"
|
|
@ -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]
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue