diff --git a/app/views/notes/_notes.rhtml b/app/views/notes/_notes.rhtml
index 3a020010..9391d108 100644
--- a/app/views/notes/_notes.rhtml
+++ b/app/views/notes/_notes.rhtml
@@ -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" ) %> |
diff --git a/doc/README_DEVELOPERS b/doc/README_DEVELOPERS
index e8f9bde0..5e48875a 100644
--- a/doc/README_DEVELOPERS
+++ b/doc/README_DEVELOPERS
@@ -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
\ No newline at end of file
+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
diff --git a/stories/helper.rb b/stories/helper.rb
index 8ad77009..db0c50ca 100644
--- a/stories/helper.rb
+++ b/stories/helper.rb
@@ -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
diff --git a/stories/notes/view_add_remove.story b/stories/notes/view_add_remove.story
new file mode 100644
index 00000000..34e519fe
--- /dev/null
+++ b/stories/notes/view_add_remove.story
@@ -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
+
\ No newline at end of file
diff --git a/stories/steps/login.rb b/stories/steps/login.rb
index 42599521..8729a5e8 100644
--- a/stories/steps/login.rb
+++ b/stories/steps/login.rb
@@ -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'
diff --git a/stories/steps/notes.rb b/stories/steps/notes.rb
new file mode 100644
index 00000000..aa17722a
--- /dev/null
+++ b/stories/steps/notes.rb
@@ -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
\ No newline at end of file
diff --git a/stories/steps/users.rb b/stories/steps/users.rb
new file mode 100644
index 00000000..834c41d0
--- /dev/null
+++ b/stories/steps/users.rb
@@ -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
\ No newline at end of file
diff --git a/test/selenium/notes/badge_count.rsel b/test/selenium/notes/badge_count.rsel
deleted file mode 100644
index ace3d85d..00000000
--- a/test/selenium/notes/badge_count.rsel
+++ /dev/null
@@ -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'
diff --git a/test/selenium/notes/link_to_note.rsel b/test/selenium/notes/link_to_note.rsel
deleted file mode 100644
index a9a3ae7e..00000000
--- a/test/selenium/notes/link_to_note.rsel
+++ /dev/null
@@ -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"
diff --git a/test/selenium/notes/see_all_notes.rsel b/test/selenium/notes/see_all_notes.rsel
deleted file mode 100644
index 83b9f52c..00000000
--- a/test/selenium/notes/see_all_notes.rsel
+++ /dev/null
@@ -1,5 +0,0 @@
-setup :fixtures => :all
-login :as => 'admin'
-open "/notes/"
-assert_element_present "note_1"
-assert_element_present "note_2"
diff --git a/test/selenium/notes/toggle_notes.rsel b/test/selenium/notes/toggle_notes.rsel
deleted file mode 100644
index c7551b32..00000000
--- a/test/selenium/notes/toggle_notes.rsel
+++ /dev/null
@@ -1,5 +0,0 @@
-setup :fixtures => :all
-login :as => 'admin'
-open "/notes"
-click "css=#toggle-notes-nav"
-wait_for_element_present "css=body.notes"
diff --git a/vendor/plugins/webrat/lib/webrat/selenium/selenium_session.rb b/vendor/plugins/webrat/lib/webrat/selenium/selenium_session.rb
index cbd0baea..b00735f3 100644
--- a/vendor/plugins/webrat/lib/webrat/selenium/selenium_session.rb
+++ b/vendor/plugins/webrat/lib/webrat/selenium/selenium_session.rb
@@ -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]