spectie 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/LICENSE +21 -0
  2. data/README.rdoc +85 -0
  3. data/Rakefile +8 -0
  4. data/VERSION.yml +4 -0
  5. data/initialize.rb +6 -0
  6. data/lib/spectie.rb +3 -0
  7. data/lib/spectie/configuration.rb +10 -0
  8. data/lib/spectie/main.rb +26 -0
  9. data/lib/spectie/rails.rb +2 -0
  10. data/lib/spectie/rails_story_example_group.rb +55 -0
  11. data/lib/spectie/selenium.rb +3 -0
  12. data/lib/spectie/selenium/configuration.rb +27 -0
  13. data/lib/spectie/selenium/story_example_group.rb +51 -0
  14. data/lib/spectie/story_example_group_methods.rb +40 -0
  15. data/rake_tasks/package.rake +51 -0
  16. data/rake_tasks/publish.rake +40 -0
  17. data/rake_tasks/spec.rake +42 -0
  18. data/rake_tasks/utility.rake +11 -0
  19. data/rdoc/classes/Spectie.html +135 -0
  20. data/rdoc/classes/Spectie/Configuration.html +175 -0
  21. data/rdoc/classes/Spectie/Configuration/ForScenarios.html +111 -0
  22. data/rdoc/classes/Spectie/Configuration/Selenium.html +220 -0
  23. data/rdoc/classes/Spectie/Main.html +161 -0
  24. data/rdoc/classes/Spectie/RailsStoryExampleGroup.html +118 -0
  25. data/rdoc/classes/Spectie/SeleniumStoryExampleGroup.html +119 -0
  26. data/rdoc/classes/Spectie/StoryExampleGroupMethods.html +254 -0
  27. data/rdoc/created.rid +1 -0
  28. data/rdoc/files/README_rdoc.html +266 -0
  29. data/rdoc/files/lib/spectie/configuration_rb.html +101 -0
  30. data/rdoc/files/lib/spectie/main_rb.html +108 -0
  31. data/rdoc/files/lib/spectie/rails_rb.html +109 -0
  32. data/rdoc/files/lib/spectie/rails_story_example_group_rb.html +182 -0
  33. data/rdoc/files/lib/spectie/selenium/configuration_rb.html +101 -0
  34. data/rdoc/files/lib/spectie/selenium/story_example_group_rb.html +101 -0
  35. data/rdoc/files/lib/spectie/selenium_rb.html +110 -0
  36. data/rdoc/files/lib/spectie/story_example_group_methods_rb.html +101 -0
  37. data/rdoc/files/lib/spectie_rb.html +110 -0
  38. data/rdoc/fr_class_index.html +34 -0
  39. data/rdoc/fr_file_index.html +36 -0
  40. data/rdoc/fr_method_index.html +38 -0
  41. data/rdoc/index.html +24 -0
  42. data/rdoc/rdoc-style.css +208 -0
  43. data/script/selenium_webapp +45 -0
  44. data/script/spec +10 -0
  45. data/spec/example_run_state_tracking.rb +65 -0
  46. data/spec/selenium_config.rb +11 -0
  47. data/spec/spec_helper.rb +10 -0
  48. data/spec/spectie/rails_helper.rb +29 -0
  49. data/spec/spectie/rails_story_example_group_spec.rb +59 -0
  50. data/spec/spectie/selenium/configuration_spec.rb +91 -0
  51. data/spec/spectie/selenium/spec_helper.rb +16 -0
  52. data/spec/spectie/selenium/story_example_group_spec.rb +132 -0
  53. data/spec/spectie/spec_helper.rb +1 -0
  54. data/spec/spectie/story_example_group_methods_spec.rb +217 -0
  55. data/spec/spectie_spec.rb +46 -0
  56. data/spec/support/rails_app/controllers/application_controller.rb +2 -0
  57. data/tags +19899 -0
  58. metadata +125 -0
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2009 Ryan Kinderman
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.rdoc ADDED
@@ -0,0 +1,85 @@
1
+ = Spectie
2
+
3
+ Spectie (rhymes with "necktie") is a pure Ruby BDD integration testing framework for RSpec.
4
+
5
+ Spectie was written with the following beliefs:
6
+
7
+ * Business stakeholders or analysts are often not writing comprehensive (or any) acceptance criteria.
8
+ * Business stakeholders or analysts are usually unwilling or unable to follow a strict format for writing the acceptance criteria that they _are_ writing.
9
+ * On many projects, the communication with the business stakeholders or analysts are accessible enough that written acceptance criteria is not necessary, but discussed requirements still need to be implemented, and therefore need to be tested.
10
+ * Good developers recognize the benefits of top-down, BDD-style integration testing in helping to ensure that the code that is written to implement a feature directly satisfies business requirements, and doesn't get over-engineered or over-complicated.
11
+ * Good developers love Ruby.
12
+
13
+ Spectie tries to strike the proper balance between writing readable tests, and just getting your work done in the most efficient way possible. It does this by providing a consistent structure for writing your integration test code in a BDD fashion, with the breakdown of features, scenarios, and their given/when/then statements. However, a little bit of syntactic sugar goes a long way to aid in the understanding of code, while too much can add unnecessary complexity and actually decrease maintainability. So, Spectie keeps things pretty close to the underlying technology at all times, since most of the time, it's a developer that's *really* writing the tests.
14
+
15
+ With these ideas in mind, what Spectie provides is:
16
+
17
+ * A small number of methods on top of RSpec for making your integration tests readable. This isn't much more than "Given/When/Then".
18
+ * A configuration and mapping layer for different integration testing code, such as what's provided by ActionController's integration.rb, or the Ruby client for Selenium.
19
+ * Common functionality for supported integration testing solutions, such as the option to restart the Selenium browser between tests, or simply clear the cookies.
20
+
21
+ Advantages of having your integration tests written with Spectie:
22
+
23
+ * It's Ruby.
24
+ * If you're familiar with RSpec already, all the same functionality is available.
25
+ * All new syntax beyond RSpec is kept to a minimum, and exists solely to facilitate developer-driven BDD.
26
+ * Use familiar methods for code navigation and reuse.
27
+
28
+ == Example
29
+ === Rails
30
+ Feature "Compelling Feature" do
31
+ Scenario "As a user, I would like to use a compelling feature" do
32
+ Given :i_have_an_account
33
+ And :i_have_logged_in
34
+
35
+ When :i_access_a_compelling_feature
36
+
37
+ Then :i_am_presented_with_stunning_results
38
+ end
39
+
40
+ def i_have_an_account
41
+ @user = create_user
42
+ end
43
+
44
+ def i_have_logged_in
45
+ log_in_as @user
46
+ end
47
+
48
+ def i_access_a_compelling_feature
49
+ get compelling_feature_path
50
+ response.should be_success
51
+ end
52
+
53
+ def i_am_presented_with_stunning_results
54
+ response.should have_text("Simply stunning!")
55
+ end
56
+ end
57
+
58
+ == Installation
59
+
60
+ === Gem
61
+ sudo gem install spectie
62
+
63
+ === Rails plugin
64
+ script/plugin install git://github.com/ryankinderman/spectie.git
65
+
66
+ === Git
67
+ git clone git://github.com/ryankinderman/spectie.git
68
+
69
+ == Configuration
70
+ === Ruby on Rails
71
+ In <em>spec/spec_helper.rb</em>, after <tt>require 'spec/rails'</tt>, add:
72
+ require 'spectie/rails'
73
+
74
+ That's it. Spectie registers itself with RSpec, so you can run your integration tests with the usual <tt>rake spec:integration</tt> command. Also, all of the usual methods in a {Rails integration testing session}[http://api.rubyonrails.org/classes/ActionController/Integration/Session.html] are available for you to use as well.
75
+
76
+ === Selenium
77
+ TODO
78
+
79
+ == Author
80
+
81
+ Ryan Kinderman (ryan@kinderman.net)
82
+
83
+ == Copyright
84
+
85
+ Copyright (c) 2009 Ryan Kinderman. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require File.expand_path(File.dirname(__FILE__) + "/initialize")
4
+
5
+ Dir[File.expand_path(File.dirname(__FILE__) + "/rake_tasks/*.rake")].each do |file|
6
+ load file
7
+ end
8
+
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 0
3
+ :patch: 3
4
+ :major: 0
data/initialize.rb ADDED
@@ -0,0 +1,6 @@
1
+ require 'rubygems'
2
+
3
+ Dir[File.dirname(__FILE__) + "/vendor/*/lib"].each do |lib|
4
+ lib_path = File.expand_path(lib)
5
+ $:.unshift lib_path unless $:.include?(lib_path)
6
+ end
data/lib/spectie.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "spectie/story_example_group_methods"
2
+ require "spectie/configuration"
3
+ require "spectie/main.rb"
@@ -0,0 +1,10 @@
1
+ module Spectie
2
+ module Configuration
3
+ class ForScenarios
4
+ end
5
+ def scenarios
6
+ ForScenarios.new
7
+ end
8
+ end
9
+ ::Spec::Runner::Configuration.send :include, Configuration
10
+ end
@@ -0,0 +1,26 @@
1
+ module Spectie
2
+ module Main
3
+ # Creates an example group for the feature.
4
+ # Feature "User Authentication" do
5
+ # Scenario "As a user without an account, I want to create one so that I can log in" do
6
+ # Given :i_do_not_have_an_account
7
+ # And :i_want_to_log_in
8
+ #
9
+ # When :i_create_an_account
10
+ #
11
+ # Then :i_can_log_in
12
+ # end
13
+ #
14
+ # def i_do_not_have_an_account
15
+ # # ... codey code ...
16
+ # end
17
+ #
18
+ # # ... remaining scenario statements ...
19
+ # end
20
+ def Feature(*args, &block)
21
+ describe(*args, &block)
22
+ end
23
+ end
24
+ end
25
+
26
+ include Spectie::Main
@@ -0,0 +1,2 @@
1
+ require "spectie"
2
+ require "spectie/rails_story_example_group"
@@ -0,0 +1,55 @@
1
+ ###################################################################################
2
+ # Preserve method_missing from rspec, which supports the general
3
+ # be_ and have_ predicate matchers. This method gets overridden for
4
+ # Rails integration tests by ActionController::IntegrationTest for
5
+ # session delegation.
6
+ require "spec/interop/test/unit/testcase"
7
+ Test::Unit::TestCase.class_eval do
8
+ alias_method :method_missing_from_rspec, :method_missing
9
+ end
10
+
11
+ require "action_controller/integration"
12
+ ActionController::IntegrationTest.class_eval do
13
+ alias_method :method_missing_from_rails, :method_missing
14
+ def method_missing(*args, &block)
15
+ method_missing_from_rspec(*args, &block)
16
+ rescue NameError
17
+ method_missing_from_rails(*args, &block)
18
+ end
19
+ end
20
+ ###################################################################################
21
+ begin
22
+ spec_rails_path = "spec/rails"
23
+ require spec_rails_path
24
+ rescue LoadError => e
25
+ if e.message =~ /#{Regexp.escape(spec_rails_path)}$/
26
+ raise "RSpec-Rails not available. Install it with sudo gem install rspec-rails"
27
+ else
28
+ raise e
29
+ end
30
+ end
31
+
32
+ ActionController::IntegrationTest.class_eval do
33
+ alias_method :orig_initialize, :initialize
34
+ def initialize(*args)
35
+ super
36
+ end
37
+ end
38
+
39
+ module Spectie
40
+
41
+ class RailsStoryExampleGroup < ActionController::IntegrationTest
42
+ include StoryExampleGroupMethods
43
+
44
+ # The following line ensures that RailsStoryExampleGroup is, by
45
+ # default, the lowest point in the example group hierarchy that
46
+ # helper modules will be included.
47
+ #
48
+ # If that doesn't make sense, just comment this line
49
+ # out and observe the failing test.
50
+ Spec::Example::ExampleGroupFactory.default(self)
51
+ Spec::Example::ExampleGroupFactory.register(:integration, self)
52
+ end
53
+
54
+ end
55
+
@@ -0,0 +1,3 @@
1
+ require "spectie"
2
+ require "spectie/selenium/configuration"
3
+ require "spectie/selenium/story_example_group"
@@ -0,0 +1,27 @@
1
+ module Spectie
2
+ module Configuration
3
+ class Selenium
4
+ attr_writer :driver_options
5
+ attr_accessor :start_browser_once, :controlled
6
+
7
+ def initialize
8
+ self.start_browser_once = true
9
+ self.controlled = true
10
+ end
11
+
12
+ def driver_options
13
+ @driver_options || raise("No Selenium driver options specified")
14
+ end
15
+
16
+ def controlled?
17
+ self.controlled == true
18
+ end
19
+
20
+ end
21
+
22
+ def selenium
23
+ @selenium ||= Selenium.new
24
+ end
25
+ end
26
+ ::Spec::Runner.send :include, Configuration
27
+ end
@@ -0,0 +1,51 @@
1
+ begin
2
+ selenium_client_path = "selenium/client"
3
+ require selenium_client_path
4
+ rescue LoadError => e
5
+ if e.message =~ /#{Regexp.escape(selenium_client_path)}$/
6
+ raise "selenium-client not available. Install it with sudo gem install selenium-client"
7
+ else
8
+ raise e
9
+ end
10
+ end
11
+
12
+ module Spectie
13
+ class SeleniumStoryExampleGroup
14
+ include StoryExampleGroupMethods
15
+ include Selenium::Client::SeleniumHelper
16
+
17
+ selenium = nil
18
+ selenium_config = Spec::Runner.configuration.selenium
19
+
20
+ before :suite do
21
+ if selenium_config.controlled? and selenium_config.start_browser_once
22
+ selenium = Selenium::Client::Driver.new(selenium_config.driver_options)
23
+ selenium.start
24
+ end
25
+ end
26
+
27
+ after :suite do
28
+ if selenium_config.controlled? and selenium_config.start_browser_once
29
+ selenium.stop
30
+ end
31
+ end
32
+
33
+ before :each do
34
+ if selenium_config.controlled? and !selenium_config.start_browser_once
35
+ selenium = Selenium::Client::Driver.new(selenium_config.driver_options)
36
+ selenium.start
37
+ end
38
+ @selenium = selenium
39
+ end
40
+
41
+ after :each do
42
+ if selenium_config.controlled?
43
+ if selenium_config.start_browser_once
44
+ selenium.delete_all_visible_cookies
45
+ else
46
+ selenium.stop
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,40 @@
1
+ module Spectie
2
+
3
+ module StoryExampleGroupMethods
4
+ def self.included(mod)
5
+ mod.class_eval do
6
+ extend Spec::Example::ExampleGroupMethods
7
+ include Spec::Example::ExampleMethods
8
+
9
+ class << self
10
+
11
+ def scenario_methods; [:Given, :When, :Then, :And] end
12
+
13
+ # Creates a scenario example within a feature (see Spectie::Main#Feature).
14
+ def Scenario(description, options={}, backtrace=nil, &implementation)
15
+ example(description, options, backtrace) do
16
+ instance_eval &implementation
17
+ end
18
+ end
19
+
20
+ # Disables a scenario.
21
+ def xScenario(description, options={}, &implementation)
22
+ xexample description, options, &implementation
23
+ end
24
+
25
+ end
26
+
27
+ scenario_methods.each do |scenario_method|
28
+ method = <<-METHOD
29
+ def #{scenario_method}(statement, *args, &block)
30
+ send statement, *args, &block
31
+ end
32
+ METHOD
33
+
34
+ class_eval method, __FILE__, __LINE__
35
+ end
36
+
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,51 @@
1
+ namespace :package do
2
+ begin
3
+ require 'jeweler'
4
+ Jeweler::Tasks.new do |gem|
5
+ gem.name = %q{spectie}
6
+ gem.summary = %q{A Ruby integration testing framework written on top of RSpec.}
7
+ gem.description = <<-EOF
8
+ Spectie (rhymes with "necktie") is a pure Ruby acceptance testing framework for RSpec.
9
+ The philosophy of Spectie is that, since the business stakeholders on most projects
10
+ don't care about exactly how you test, you're free to write the acceptance tests on
11
+ a project how *you*, the developer, need to in order to ensure that the implementation
12
+ is correct, easily understood, and maintainable. Furthermore, since you're a developer,
13
+ the easiest, most straight-forward and maintainable way for you to write your tests is
14
+ by using the highly expressive language that you're already coding in for the project;
15
+ that's Ruby, baby!
16
+ EOF
17
+ gem.platform = Gem::Platform::RUBY
18
+ gem.required_ruby_version = '>= 1.8.6'
19
+ gem.add_dependency('rspec', '>= 1.2.7')
20
+
21
+ gem.authors = ["Ryan Kinderman"]
22
+ gem.date = Time.now.strftime("%Y-%m-%d")
23
+ gem.email = %q{ryan@kinderman.net}
24
+ gem.homepage = %q{http://github.com/ryankinderman/spectie}
25
+ gem.rubyforge_project = %q{kinderman}
26
+
27
+ gem.has_rdoc = true
28
+ gem.rdoc_options = ["--charset=UTF-8"]
29
+ gem.extra_rdoc_files = [
30
+ "LICENSE",
31
+ "README.rdoc"
32
+ ]
33
+
34
+ gem.require_paths = ["lib"]
35
+ gem.files = Dir["**/*"]
36
+ gem.files.reject! { |f| !f.match(/^(vendor|pkg)(\/|$)/).nil? }
37
+ gem.test_files = Dir["spec/**/*_spec.rb"]
38
+
39
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
40
+ end
41
+
42
+ Jeweler::RubyforgeTasks.new do |rubyforge|
43
+ rubyforge.doc_task = "rdoc"
44
+ end
45
+ rescue LoadError
46
+ puts "Jeweler not available. It's only needed if you're going to build the gem for this library. Install it with something like: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
47
+ end
48
+
49
+ desc "Cleans the project package artifacts, generates all files needed to build the gem, and builds it"
50
+ task :full => ["clean", "rdoc", "gemspec", "build"]
51
+ end
@@ -0,0 +1,40 @@
1
+ require 'rake/rdoctask'
2
+ Rake::RDocTask.new do |rdoc|
3
+ if File.exist?('VERSION.yml')
4
+ config = YAML.load(File.read('VERSION.yml'))
5
+ version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
6
+ else
7
+ version = ""
8
+ end
9
+
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = "spectie #{version}"
12
+ rdoc.rdoc_files.include('README*')
13
+ rdoc.rdoc_files.include('lib/**/*.rb')
14
+ end
15
+
16
+ begin
17
+ require 'rake/contrib/sshpublisher'
18
+ namespace :rubyforge do
19
+
20
+ desc "Release gem and RDoc documentation to RubyForge"
21
+ task :release => ["rubyforge:release:gem", "rubyforge:release:docs"]
22
+
23
+ namespace :release do
24
+ desc "Publish RDoc to RubyForge."
25
+ task :docs => [:rdoc] do
26
+ config = YAML.load(
27
+ File.read(File.expand_path('~/.rubyforge/user-config.yml'))
28
+ )
29
+
30
+ host = "#{config['username']}@rubyforge.org"
31
+ remote_dir = "/var/www/gforge-projects/spectie/"
32
+ local_dir = 'rdoc'
33
+
34
+ Rake::SshDirPublisher.new(host, remote_dir, local_dir).upload
35
+ end
36
+ end
37
+ end
38
+ rescue LoadError
39
+ puts "Rake SshDirPublisher is unavailable or your rubyforge environment is not configured."
40
+ end