dchelimsky-rspec-stories 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. data/History.txt +5 -0
  2. data/License.txt +22 -0
  3. data/Manifest.txt +78 -0
  4. data/README.txt +23 -0
  5. data/Rakefile +87 -0
  6. data/init.rb +4 -0
  7. data/lib/spec/runner/formatter/story/html_formatter.rb +174 -0
  8. data/lib/spec/runner/formatter/story/plain_text_formatter.rb +194 -0
  9. data/lib/spec/runner/formatter/story/progress_bar_formatter.rb +42 -0
  10. data/lib/spec/runner/options_extensions.rb +25 -0
  11. data/lib/spec/stories.rb +11 -0
  12. data/lib/spec/story/extensions.rb +3 -0
  13. data/lib/spec/story/extensions/main.rb +86 -0
  14. data/lib/spec/story/extensions/regexp.rb +9 -0
  15. data/lib/spec/story/extensions/string.rb +9 -0
  16. data/lib/spec/story/given_scenario.rb +14 -0
  17. data/lib/spec/story/runner.rb +57 -0
  18. data/lib/spec/story/runner/plain_text_story_runner.rb +48 -0
  19. data/lib/spec/story/runner/scenario_collector.rb +18 -0
  20. data/lib/spec/story/runner/scenario_runner.rb +54 -0
  21. data/lib/spec/story/runner/story_mediator.rb +137 -0
  22. data/lib/spec/story/runner/story_parser.rb +247 -0
  23. data/lib/spec/story/runner/story_runner.rb +74 -0
  24. data/lib/spec/story/scenario.rb +14 -0
  25. data/lib/spec/story/step.rb +70 -0
  26. data/lib/spec/story/step_group.rb +89 -0
  27. data/lib/spec/story/step_mother.rb +38 -0
  28. data/lib/spec/story/story.rb +39 -0
  29. data/lib/spec/story/version.rb +15 -0
  30. data/lib/spec/story/world.rb +124 -0
  31. data/resources/rake/verify_rcov.rake +7 -0
  32. data/rspec-stories.gemspec +35 -0
  33. data/spec/spec.opts +6 -0
  34. data/spec/spec/runner/formatter/story/html_formatter_spec.rb +135 -0
  35. data/spec/spec/runner/formatter/story/plain_text_formatter_spec.rb +600 -0
  36. data/spec/spec/runner/formatter/story/progress_bar_formatter_spec.rb +82 -0
  37. data/spec/spec/runner/most_recent_spec.rb +0 -0
  38. data/spec/spec/runner/options_extensions_spec.rb +31 -0
  39. data/spec/spec/runner/resources/a_bar.rb +0 -0
  40. data/spec/spec/runner/resources/a_foo.rb +0 -0
  41. data/spec/spec/runner/resources/a_spec.rb +1 -0
  42. data/spec/spec/runner/resources/custom_example_group_runner.rb +14 -0
  43. data/spec/spec/runner/resources/utf8_encoded.rb +7 -0
  44. data/spec/spec/runner_spec.rb +11 -0
  45. data/spec/spec/spec_classes.rb +133 -0
  46. data/spec/spec/story/builders.rb +46 -0
  47. data/spec/spec/story/extensions/main_spec.rb +161 -0
  48. data/spec/spec/story/extensions_spec.rb +14 -0
  49. data/spec/spec/story/given_scenario_spec.rb +27 -0
  50. data/spec/spec/story/runner/plain_text_story_runner_spec.rb +90 -0
  51. data/spec/spec/story/runner/scenario_collector_spec.rb +27 -0
  52. data/spec/spec/story/runner/scenario_runner_spec.rb +214 -0
  53. data/spec/spec/story/runner/story_mediator_spec.rb +143 -0
  54. data/spec/spec/story/runner/story_parser_spec.rb +401 -0
  55. data/spec/spec/story/runner/story_runner_spec.rb +294 -0
  56. data/spec/spec/story/runner_spec.rb +93 -0
  57. data/spec/spec/story/scenario_spec.rb +18 -0
  58. data/spec/spec/story/step_group_spec.rb +157 -0
  59. data/spec/spec/story/step_mother_spec.rb +84 -0
  60. data/spec/spec/story/step_spec.rb +272 -0
  61. data/spec/spec/story/story_helper.rb +2 -0
  62. data/spec/spec/story/story_spec.rb +84 -0
  63. data/spec/spec/story/world_spec.rb +423 -0
  64. data/spec/spec_helper.rb +84 -0
  65. data/story_server/prototype/javascripts/builder.js +136 -0
  66. data/story_server/prototype/javascripts/controls.js +972 -0
  67. data/story_server/prototype/javascripts/dragdrop.js +976 -0
  68. data/story_server/prototype/javascripts/effects.js +1117 -0
  69. data/story_server/prototype/javascripts/prototype.js +4140 -0
  70. data/story_server/prototype/javascripts/rspec.js +149 -0
  71. data/story_server/prototype/javascripts/scriptaculous.js +58 -0
  72. data/story_server/prototype/javascripts/slider.js +276 -0
  73. data/story_server/prototype/javascripts/sound.js +55 -0
  74. data/story_server/prototype/javascripts/unittest.js +568 -0
  75. data/story_server/prototype/lib/server.rb +24 -0
  76. data/story_server/prototype/stories.html +176 -0
  77. data/story_server/prototype/stylesheets/rspec.css +136 -0
  78. data/story_server/prototype/stylesheets/test.css +90 -0
  79. metadata +154 -0
@@ -0,0 +1,38 @@
1
+ module Spec
2
+ module Story
3
+ class StepMother
4
+ def initialize
5
+ @steps = StepGroup.new
6
+ end
7
+
8
+ def use(new_step_group)
9
+ @steps << new_step_group
10
+ end
11
+
12
+ def store(type, step)
13
+ @steps.add(type, step)
14
+ end
15
+
16
+ def find(type, unstripped_name)
17
+ name = unstripped_name.strip
18
+ if @steps.find(type, name).nil?
19
+ @steps.add(type,
20
+ Step.new(name) do
21
+ raise Spec::Example::ExamplePendingError.new("Unimplemented step: #{name}")
22
+ end
23
+ )
24
+ end
25
+ @steps.find(type, name)
26
+ end
27
+
28
+ def clear
29
+ @steps.clear
30
+ end
31
+
32
+ def empty?
33
+ @steps.empty?
34
+ end
35
+
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,39 @@
1
+ module Spec
2
+ module Story
3
+ class Story
4
+ attr_reader :title, :narrative
5
+
6
+ def initialize(title, narrative, params = {}, &body)
7
+ @body = body
8
+ @title = title
9
+ @narrative = narrative
10
+ @params = params
11
+ end
12
+
13
+ def [](key)
14
+ @params[key]
15
+ end
16
+
17
+ def run_in(obj)
18
+ obj.instance_eval(&@body)
19
+ end
20
+
21
+ def assign_steps_to(assignee)
22
+ if steps=@params[:steps_for]
23
+ steps = [steps] unless steps.is_a?(Array)
24
+ steps.each do |step|
25
+ if step.is_a?(StepGroup)
26
+ assignee.use(step)
27
+ else
28
+ assignee.use(steps_for(step))
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def steps_for(key)
35
+ $rspec_story_steps[key]
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,15 @@
1
+ module Spec
2
+ module Story
3
+ module VERSION
4
+ unless defined? MAJOR
5
+ MAJOR = 1
6
+ MINOR = 0
7
+ TINY = 0
8
+
9
+ STRING = [MAJOR, MINOR, TINY].compact.join('.')
10
+
11
+ SUMMARY = "rspec-stories #{STRING}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,124 @@
1
+ require 'spec/expectations'
2
+ require 'spec/matchers'
3
+ require 'spec/example/pending'
4
+
5
+ module Spec
6
+ module Story
7
+ =begin
8
+ A World represents the actual instance a scenario will run in.
9
+
10
+ The runner ensures any instance variables and methods defined anywhere
11
+ in a story block are available to all the scenarios. This includes
12
+ variables that are created or referenced inside Given, When and Then
13
+ blocks.
14
+ =end
15
+ module World
16
+ include ::Spec::Example::Pending
17
+ include ::Spec::Matchers
18
+
19
+ def self.create(cls = Object, *args)
20
+ cls.new(*args).extend(World)
21
+ end
22
+
23
+ def self.listeners
24
+ @listeners ||= []
25
+ end
26
+
27
+ def self.add_listener(listener)
28
+ listeners() << listener
29
+ end
30
+
31
+ def self.step_mother
32
+ @step_mother ||= StepMother.new
33
+ end
34
+
35
+ def self.use(steps)
36
+ step_mother.use(steps)
37
+ end
38
+
39
+ def self.step_names
40
+ @step_names ||= []
41
+ end
42
+
43
+ def self.run_given_scenario_with_suspended_listeners(world, type, name, scenario)
44
+ current_listeners = Array.new(listeners)
45
+ begin
46
+ listeners.each { |l| l.found_scenario(type, name) }
47
+ @listeners.clear
48
+ scenario.perform(world, name) unless dry_run
49
+ ensure
50
+ @listeners.replace(current_listeners)
51
+ end
52
+ end
53
+
54
+ def self.store_and_call(world, type, name, *args, &block)
55
+ if block_given?
56
+ step_mother.store(type, Step.new(name, &block))
57
+ end
58
+ step = step_mother.find(type, name)
59
+
60
+ step_name = step.name
61
+ step_names << step_name
62
+
63
+ # It's important to have access to the parsed args here, so
64
+ # we can give them to the listeners. The HTML reporter needs
65
+ # the args so it can style them. See the generated output in
66
+ # story_server/prototype/rspec_stories.html (generated by rake stories)
67
+ args = step.parse_args(name) if args.empty?
68
+ begin
69
+ listeners.each { |l| l.step_upcoming(type, step_name, *args) }
70
+ step.perform(world, *args) unless dry_run
71
+ listeners.each { |l| l.step_succeeded(type, step_name, *args) }
72
+ rescue Exception => e
73
+ case e
74
+ when Spec::Example::ExamplePendingError
75
+ @listeners.each { |l| l.step_pending(type, step_name, *args) }
76
+ else
77
+ @listeners.each { |l| l.step_failed(type, step_name, *args) }
78
+ end
79
+ errors << e
80
+ end
81
+ end
82
+
83
+ def self.errors
84
+ @errors ||= []
85
+ end
86
+
87
+ def self.dry_run
88
+ ::Spec::Story::Runner.dry_run
89
+ end
90
+
91
+ def start_collecting_errors
92
+ errors.clear
93
+ end
94
+
95
+ def errors
96
+ World.errors
97
+ end
98
+
99
+ def GivenScenario(name)
100
+ World.run_given_scenario_with_suspended_listeners(self, :'given scenario', name, GivenScenario.new(name))
101
+ @__previous_step = :given
102
+ end
103
+
104
+ def Given(name, *args, &block)
105
+ World.store_and_call self, :given, name, *args, &block
106
+ @__previous_step = :given
107
+ end
108
+
109
+ def When(name, *args, &block)
110
+ World.store_and_call self, :when, name, *args, &block
111
+ @__previous_step = :when
112
+ end
113
+
114
+ def Then(name, *args, &block)
115
+ World.store_and_call self, :then, name, *args, &block
116
+ @__previous_step = :then
117
+ end
118
+
119
+ def And(name, *args, &block)
120
+ World.store_and_call self, @__previous_step, name, *args, &block
121
+ end
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,7 @@
1
+ require 'rake'
2
+ require 'spec/rake/verify_rcov'
3
+
4
+ RCov::VerifyTask.new(:verify_rcov => :spec) do |t|
5
+ t.threshold = 100.0
6
+ t.index_html = 'coverage/index.html'
7
+ end
@@ -0,0 +1,35 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{rspec-stories}
5
+ s.version = "1.0.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["RSpec Development Team"]
9
+ s.date = %q{2009-01-12}
10
+ s.description = %q{Behaviour Driven Development for Ruby.}
11
+ s.email = ["rspec-devel@rubyforge.org"]
12
+ s.extra_rdoc_files = ["History.txt", "License.txt", "Manifest.txt", "README.txt"]
13
+ s.files = ["History.txt", "License.txt", "Manifest.txt", "README.txt", "Rakefile", "init.rb", "lib/spec/runner/formatter/story/html_formatter.rb", "lib/spec/runner/formatter/story/plain_text_formatter.rb", "lib/spec/runner/formatter/story/progress_bar_formatter.rb", "lib/spec/runner/options_extensions.rb", "lib/spec/stories.rb", "lib/spec/story/extensions.rb", "lib/spec/story/extensions/main.rb", "lib/spec/story/extensions/regexp.rb", "lib/spec/story/extensions/string.rb", "lib/spec/story/given_scenario.rb", "lib/spec/story/runner.rb", "lib/spec/story/runner/plain_text_story_runner.rb", "lib/spec/story/runner/scenario_collector.rb", "lib/spec/story/runner/scenario_runner.rb", "lib/spec/story/runner/story_mediator.rb", "lib/spec/story/runner/story_parser.rb", "lib/spec/story/runner/story_runner.rb", "lib/spec/story/scenario.rb", "lib/spec/story/step.rb", "lib/spec/story/step_group.rb", "lib/spec/story/step_mother.rb", "lib/spec/story/story.rb", "lib/spec/story/version.rb", "lib/spec/story/world.rb", "resources/rake/verify_rcov.rake", "rspec-stories.gemspec", "spec/spec.opts", "spec/spec/runner/formatter/story/html_formatter_spec.rb", "spec/spec/runner/formatter/story/plain_text_formatter_spec.rb", "spec/spec/runner/formatter/story/progress_bar_formatter_spec.rb", "spec/spec/runner/most_recent_spec.rb", "spec/spec/runner/options_extensions_spec.rb", "spec/spec/runner/resources/a_bar.rb", "spec/spec/runner/resources/a_foo.rb", "spec/spec/runner/resources/a_spec.rb", "spec/spec/runner/resources/custom_example_group_runner.rb", "spec/spec/runner/resources/utf8_encoded.rb", "spec/spec/runner_spec.rb", "spec/spec/spec_classes.rb", "spec/spec/story/builders.rb", "spec/spec/story/extensions/main_spec.rb", "spec/spec/story/extensions_spec.rb", "spec/spec/story/given_scenario_spec.rb", "spec/spec/story/runner/plain_text_story_runner_spec.rb", "spec/spec/story/runner/scenario_collector_spec.rb", "spec/spec/story/runner/scenario_runner_spec.rb", "spec/spec/story/runner/story_mediator_spec.rb", "spec/spec/story/runner/story_parser_spec.rb", "spec/spec/story/runner/story_runner_spec.rb", "spec/spec/story/runner_spec.rb", "spec/spec/story/scenario_spec.rb", "spec/spec/story/step_group_spec.rb", "spec/spec/story/step_mother_spec.rb", "spec/spec/story/step_spec.rb", "spec/spec/story/story_helper.rb", "spec/spec/story/story_spec.rb", "spec/spec/story/world_spec.rb", "spec/spec_helper.rb", "story_server/prototype/javascripts/builder.js", "story_server/prototype/javascripts/controls.js", "story_server/prototype/javascripts/dragdrop.js", "story_server/prototype/javascripts/effects.js", "story_server/prototype/javascripts/prototype.js", "story_server/prototype/javascripts/rspec.js", "story_server/prototype/javascripts/scriptaculous.js", "story_server/prototype/javascripts/slider.js", "story_server/prototype/javascripts/sound.js", "story_server/prototype/javascripts/unittest.js", "story_server/prototype/lib/server.rb", "story_server/prototype/stories.html", "story_server/prototype/stylesheets/rspec.css", "story_server/prototype/stylesheets/test.css"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://rspec.info/}
16
+ s.rdoc_options = ["--main", "README.txt"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{rspec-stories}
19
+ s.rubygems_version = %q{1.3.1}
20
+ s.summary = %q{rspec-stories 1.0.0}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<rspec>, [">= 1.1.11"])
28
+ s.add_development_dependency(%q<hoe>, [">= 1.8.2"])
29
+ else
30
+ s.add_dependency(%q<rspec>, [">= 1.1.11"])
31
+ end
32
+ else
33
+ s.add_dependency(%q<rspec>, [">= 1.1.11"])
34
+ end
35
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,6 @@
1
+ --colour
2
+ --format
3
+ profile
4
+ --timeout
5
+ 20
6
+ --diff
@@ -0,0 +1,135 @@
1
+ require File.dirname(__FILE__) + '/../../../../spec_helper.rb'
2
+ require 'spec/runner/formatter/story/html_formatter'
3
+
4
+ module Spec
5
+ module Runner
6
+ module Formatter
7
+ module Story
8
+ describe HtmlFormatter do
9
+ before :each do
10
+ @out = StringIO.new
11
+ @options = mock('options')
12
+ @reporter = HtmlFormatter.new(@options, @out)
13
+ end
14
+
15
+ it "should just be poked at" do
16
+ @reporter.run_started(1)
17
+ @reporter.story_started('story_title', 'narrative')
18
+
19
+ @reporter.scenario_started('story_title', 'succeeded_scenario_name')
20
+ @reporter.step_succeeded('given', 'succeded_step', 'one', 'two')
21
+ @reporter.scenario_succeeded('story_title', 'succeeded_scenario_name')
22
+
23
+ @reporter.scenario_started('story_title', 'pending_scenario_name')
24
+ @reporter.step_pending('when', 'pending_step', 'un', 'deux')
25
+ @reporter.scenario_pending('story_title', 'pending_scenario_name', 'not done')
26
+
27
+ @reporter.scenario_started('story_title', 'failed_scenario_name')
28
+ @reporter.step_failed('then', 'failed_step', 'en', 'to')
29
+ @reporter.scenario_failed('story_title', 'failed_scenario_name', NameError.new('sup'))
30
+
31
+ @reporter.scenario_started('story_title', 'scenario_with_given_scenario_name')
32
+ @reporter.found_scenario('given scenario', 'succeeded_scenario_name')
33
+
34
+ @reporter.story_ended('story_title', 'narrative')
35
+ @reporter.run_ended
36
+ end
37
+
38
+ it "should create spans for params" do
39
+ @reporter.step_succeeded('given', 'a $coloured $animal', 'brown', 'dog')
40
+ @reporter.scenario_ended
41
+ @reporter.story_ended('story_title', 'narrative')
42
+
43
+ @out.string.should include(" <li class=\"passed\">Given a <span class=\"param\">brown</span> <span class=\"param\">dog</span></li>\n")
44
+ end
45
+
46
+ it 'should create spanes for params in regexp steps' do
47
+ @reporter.step_succeeded :given, /a (pink|blue) (.*)/, 'brown', 'dog'
48
+ @reporter.scenario_ended
49
+ @reporter.story_ended('story_title', 'narrative')
50
+
51
+ @out.string.should include(" <li class=\"passed\">Given a <span class=\"param\">brown</span> <span class=\"param\">dog</span></li>\n")
52
+ end
53
+
54
+ it "should create a ul for collected_steps" do
55
+ @reporter.collected_steps(['Given a $coloured $animal', 'Given a $n legged eel'])
56
+ @out.string.should == (<<-EOF)
57
+ <ul id="stock_steps" style="display: none;">
58
+ <li>Given a $coloured $animal</li>
59
+ <li>Given a $n legged eel</li>
60
+ </ul>
61
+ EOF
62
+ end
63
+
64
+ it 'should document additional givens using And' do
65
+ # when
66
+ @reporter.step_succeeded :given, 'step 1'
67
+ @reporter.step_succeeded :given, 'step 2'
68
+ @reporter.scenario_ended
69
+ @reporter.story_ended '', ''
70
+
71
+ # then
72
+ @out.string.should include("Given step 1")
73
+ @out.string.should include("And step 2")
74
+ end
75
+
76
+ it 'should document additional events using And' do
77
+ # when
78
+ @reporter.step_succeeded :when, 'step 1'
79
+ @reporter.step_succeeded :when, 'step 2'
80
+ @reporter.scenario_ended
81
+ @reporter.story_ended '', ''
82
+
83
+ # then
84
+ @out.string.should include("When step 1")
85
+ @out.string.should include("And step 2")
86
+ end
87
+
88
+ it 'should document additional outcomes using And' do
89
+ # when
90
+ @reporter.step_succeeded :then, 'step 1'
91
+ @reporter.step_succeeded :then, 'step 2'
92
+ @reporter.scenario_ended
93
+ @reporter.story_ended '', ''
94
+
95
+ # then
96
+ @out.string.should include("Then step 1")
97
+ @out.string.should include("And step 2")
98
+ end
99
+
100
+ it 'should document a GivenScenario followed by a Given using And' do
101
+ # when
102
+ @reporter.step_succeeded :'given scenario', 'a scenario'
103
+ @reporter.step_succeeded :given, 'a context'
104
+ @reporter.scenario_ended
105
+ @reporter.story_ended '', ''
106
+
107
+ # then
108
+ @out.string.should include("Given scenario a scenario")
109
+ @out.string.should include("And a context")
110
+ end
111
+
112
+ it "should create a failed story if one of its scenarios fails" do
113
+ @reporter.story_started('story_title', 'narrative')
114
+ @reporter.scenario_started('story_title', 'succeeded_scenario_name')
115
+ @reporter.step_failed('then', 'failed_step', 'en', 'to')
116
+ @reporter.scenario_failed('story_title', 'failed_scenario_name', NameError.new('sup'))
117
+ @reporter.story_ended('story_title', 'narrative')
118
+
119
+ @out.string.should include("<dl class=\"story failed\">\n <dt>Story: story_title</dt>\n")
120
+ end
121
+
122
+ it "should create a failed scenario if one of its steps fails" do
123
+ @reporter.scenario_started('story_title', 'failed_scenario_name')
124
+ @reporter.step_failed('then', 'failed_step', 'en', 'to')
125
+ @reporter.scenario_failed('story_title', 'failed_scenario_name', NameError.new('sup'))
126
+ @reporter.story_ended('story_title', 'narrative')
127
+
128
+ @out.string.should include("<dl class=\"failed\">\n <dt>Scenario: failed_scenario_name</dt>\n")
129
+ end
130
+
131
+ end
132
+ end
133
+ end
134
+ end
135
+ end
@@ -0,0 +1,600 @@
1
+ require File.dirname(__FILE__) + '/../../../../spec_helper.rb'
2
+ require 'spec/runner/formatter/story/plain_text_formatter'
3
+
4
+ module Spec
5
+ module Runner
6
+ module Formatter
7
+ module Story
8
+ describe PlainTextFormatter do
9
+ before :each do
10
+ # given
11
+ @out = StringIO.new
12
+ @tweaker = mock('tweaker')
13
+ @tweaker.stub!(:tweak_backtrace)
14
+ @options = mock('options')
15
+ @options.stub!(:colour).and_return(false)
16
+ @options.stub!(:backtrace_tweaker).and_return(@tweaker)
17
+ @formatter = PlainTextFormatter.new(@options, @out)
18
+ end
19
+
20
+ it 'should summarize the number of scenarios when the run ends' do
21
+ # when
22
+ @formatter.run_started(3)
23
+ @formatter.scenario_started(nil, nil)
24
+ @formatter.scenario_succeeded('story', 'scenario1')
25
+ @formatter.scenario_started(nil, nil)
26
+ @formatter.scenario_succeeded('story', 'scenario2')
27
+ @formatter.scenario_started(nil, nil)
28
+ @formatter.scenario_succeeded('story', 'scenario3')
29
+ @formatter.run_ended
30
+
31
+ # then
32
+ @out.string.should include('3 scenarios')
33
+ end
34
+
35
+ it 'should summarize the number of successful scenarios when the run ends' do
36
+ # when
37
+ @formatter.run_started(3)
38
+ @formatter.scenario_started(nil, nil)
39
+ @formatter.scenario_succeeded('story', 'scenario1')
40
+ @formatter.scenario_started(nil, nil)
41
+ @formatter.scenario_succeeded('story', 'scenario2')
42
+ @formatter.scenario_started(nil, nil)
43
+ @formatter.scenario_succeeded('story', 'scenario3')
44
+ @formatter.run_ended
45
+
46
+ # then
47
+ @out.string.should include('3 scenarios: 3 succeeded')
48
+ end
49
+
50
+ it 'should summarize the number of failed scenarios when the run ends' do
51
+ # when
52
+ @formatter.run_started(3)
53
+ @formatter.scenario_started(nil, nil)
54
+ @formatter.scenario_succeeded('story', 'scenario1')
55
+ @formatter.scenario_started(nil, nil)
56
+ @formatter.scenario_failed('story', 'scenario2', exception_from { raise RuntimeError, 'oops' })
57
+ @formatter.scenario_started(nil, nil)
58
+ @formatter.scenario_failed('story', 'scenario3', exception_from { raise RuntimeError, 'oops' })
59
+ @formatter.run_ended
60
+
61
+ # then
62
+ @out.string.should include("3 scenarios: 1 succeeded, 2 failed")
63
+ end
64
+
65
+ it 'should end cleanly (no characters on the last line) with successes' do
66
+ # when
67
+ @formatter.run_started(1)
68
+ @formatter.scenario_started(nil, nil)
69
+ @formatter.scenario_succeeded('story', 'scenario')
70
+ @formatter.run_ended
71
+
72
+ # then
73
+ @out.string.should =~ /\n\z/
74
+ end
75
+
76
+ it 'should end cleanly (no characters on the last line) with failures' do
77
+ # when
78
+ @formatter.run_started(1)
79
+ @formatter.scenario_started(nil, nil)
80
+ @formatter.scenario_failed('story', 'scenario', exception_from { raise RuntimeError, 'oops' })
81
+ @formatter.run_ended
82
+
83
+ # then
84
+ @out.string.should =~ /\n\z/
85
+ end
86
+
87
+ it 'should end cleanly (no characters on the last line) with pending steps' do
88
+ # when
89
+ @formatter.run_started(1)
90
+ @formatter.scenario_started(nil, nil)
91
+ @formatter.step_pending(:then, 'do pend')
92
+ @formatter.scenario_pending('story', 'scenario', exception_from { raise RuntimeError, 'oops' })
93
+ @formatter.run_ended
94
+
95
+ # then
96
+ @out.string.should =~ /\n\z/
97
+ end
98
+
99
+ it 'should summarize the number of pending scenarios when the run ends' do
100
+ # when
101
+ @formatter.run_started(3)
102
+ @formatter.scenario_started(nil, nil)
103
+ @formatter.scenario_succeeded('story', 'scenario1')
104
+ @formatter.scenario_started(nil, nil)
105
+ @formatter.scenario_pending('story', 'scenario2', 'message')
106
+ @formatter.scenario_started(nil, nil)
107
+ @formatter.scenario_pending('story', 'scenario3', 'message')
108
+ @formatter.run_ended
109
+
110
+ # then
111
+ @out.string.should include("3 scenarios: 1 succeeded, 0 failed, 2 pending")
112
+ end
113
+
114
+ it "should only count the first failure in one scenario" do
115
+ # when
116
+ @formatter.run_started(3)
117
+ @formatter.scenario_started(nil, nil)
118
+ @formatter.scenario_succeeded('story', 'scenario1')
119
+ @formatter.scenario_started(nil, nil)
120
+ @formatter.scenario_failed('story', 'scenario2', exception_from { raise RuntimeError, 'oops' })
121
+ @formatter.scenario_failed('story', 'scenario2', exception_from { raise RuntimeError, 'oops again' })
122
+ @formatter.scenario_started(nil, nil)
123
+ @formatter.scenario_failed('story', 'scenario3', exception_from { raise RuntimeError, 'oops' })
124
+ @formatter.run_ended
125
+
126
+ # then
127
+ @out.string.should include("3 scenarios: 1 succeeded, 2 failed")
128
+ end
129
+
130
+ it "should only count the first pending in one scenario" do
131
+ # when
132
+ @formatter.run_started(3)
133
+ @formatter.scenario_started(nil, nil)
134
+ @formatter.scenario_succeeded('story', 'scenario1')
135
+ @formatter.scenario_started(nil, nil)
136
+ @formatter.scenario_pending('story', 'scenario2', 'because ...')
137
+ @formatter.scenario_pending('story', 'scenario2', 'because ...')
138
+ @formatter.scenario_started(nil, nil)
139
+ @formatter.scenario_pending('story', 'scenario3', 'because ...')
140
+ @formatter.run_ended
141
+
142
+ # then
143
+ @out.string.should include("3 scenarios: 1 succeeded, 0 failed, 2 pending")
144
+ end
145
+
146
+ it "should only count a failure before the first pending in one scenario" do
147
+ # when
148
+ @formatter.run_started(3)
149
+ @formatter.scenario_started(nil, nil)
150
+ @formatter.scenario_succeeded('story', 'scenario1')
151
+ @formatter.scenario_started(nil, nil)
152
+ @formatter.scenario_pending('story', 'scenario2', exception_from { raise RuntimeError, 'oops' })
153
+ @formatter.scenario_failed('story', 'scenario2', exception_from { raise RuntimeError, 'oops again' })
154
+ @formatter.scenario_started(nil, nil)
155
+ @formatter.scenario_failed('story', 'scenario3', exception_from { raise RuntimeError, 'oops' })
156
+ @formatter.run_ended
157
+
158
+ # then
159
+ @out.string.should include("3 scenarios: 1 succeeded, 1 failed, 1 pending")
160
+ end
161
+
162
+ it 'should show test summary in red if there were failed scenarios' do
163
+ # when
164
+ @out.stub!(:tty?).and_return(true)
165
+ @options.stub!(:colour).and_return(true)
166
+
167
+ @formatter.scenario_started(nil, nil)
168
+ @formatter.scenario_failed('story', 'scenario', exception_from { raise RuntimeError, 'oops' })
169
+ @formatter.run_ended
170
+
171
+ # then
172
+ @out.string.should include("\e[31m scenarios: 0 succeeded, 1 failed, 0 pending\e[0m")
173
+ end
174
+
175
+ it 'should show test summary in yellow if there are pending scenarios' do
176
+ # when
177
+ @out.stub!(:tty?).and_return(true)
178
+ @options.stub!(:colour).and_return(true)
179
+
180
+ @formatter.scenario_started(nil, nil)
181
+ @formatter.scenario_pending('story', 'scenario', '')
182
+ @formatter.run_ended
183
+
184
+ # then
185
+ @out.string.should include("\e[32m scenarios: 0 succeeded, 0 failed, 1 pending\e[0m")
186
+ end
187
+
188
+ it 'should show test summary in green if all scenarios pass' do
189
+ # when
190
+ @out.stub!(:tty?).and_return(true)
191
+ @options.stub!(:colour).and_return(true)
192
+
193
+ @formatter.scenario_started(nil, nil)
194
+ @formatter.scenario_succeeded('story', 'scenario')
195
+ @formatter.run_ended
196
+
197
+ # then
198
+ @out.string.should include("\e[32m scenarios: 1 succeeded, 0 failed, 0 pending\e[0m")
199
+ end
200
+
201
+ it 'should produce details of the first failure each failed scenario when the run ends' do
202
+ # when
203
+ @formatter.run_started(3)
204
+ @formatter.scenario_started(nil, nil)
205
+ @formatter.scenario_succeeded('story', 'scenario1')
206
+ @formatter.scenario_started(nil, nil)
207
+ @formatter.scenario_failed('story', 'scenario2', exception_from { raise RuntimeError, 'oops2' })
208
+ @formatter.scenario_failed('story', 'scenario2', exception_from { raise RuntimeError, 'oops2 - this one should not appear' })
209
+ @formatter.scenario_started(nil, nil)
210
+ @formatter.scenario_failed('story', 'scenario3', exception_from { raise RuntimeError, 'oops3' })
211
+ @formatter.run_ended
212
+
213
+ # then
214
+ @out.string.should include("FAILURES:\n")
215
+ @out.string.should include("1) story (scenario2) FAILED")
216
+ @out.string.should include("RuntimeError: oops2")
217
+ @out.string.should_not include("RuntimeError: oops2 - this one should not appear")
218
+ @out.string.should include("2) story (scenario3) FAILED")
219
+ @out.string.should include("RuntimeError: oops3")
220
+ end
221
+
222
+ it 'should produce details of the failures in red when the run ends' do
223
+ # when
224
+ @out.stub!(:tty?).and_return(true)
225
+ @options.stub!(:colour).and_return(true)
226
+ @formatter.scenario_started(nil, nil)
227
+ @formatter.scenario_failed('story', 'scenario1', exception_from { raise RuntimeError, 'oops1' })
228
+ @formatter.run_ended
229
+
230
+ # then
231
+ @out.string.should =~ /\e\[31m[\n\s]*story \(scenario1\) FAILED\e\[0m/m
232
+ @out.string.should =~ /\e\[31m[\n\s]*RuntimeError: oops1\e\[0m/m
233
+ end
234
+
235
+ it 'should produce details of each pending step when the run ends' do
236
+ # when
237
+ @formatter.run_started(2)
238
+ @formatter.story_started('story 1', 'narrative')
239
+ @formatter.scenario_started('story 1', 'scenario 1')
240
+ @formatter.step_pending(:given, 'todo 1', [])
241
+ @formatter.story_started('story 2', 'narrative')
242
+ @formatter.scenario_started('story 2', 'scenario 2')
243
+ @formatter.step_pending(:given, 'todo 2', [])
244
+ @formatter.run_ended
245
+
246
+ # then
247
+ @out.string.should include("Pending Steps:\n")
248
+ @out.string.should include("1) story 1 (scenario 1): todo 1")
249
+ @out.string.should include("2) story 2 (scenario 2): todo 2")
250
+ end
251
+
252
+ it 'should document a story title and narrative' do
253
+ # when
254
+ @formatter.story_started 'story', 'narrative'
255
+ @formatter.story_ended 'story', 'narrative'
256
+
257
+ # then
258
+ @out.string.should include("Story: story\n\n narrative")
259
+ end
260
+
261
+ it 'should document a scenario name' do
262
+ # when
263
+ @formatter.scenario_started 'story', 'scenario'
264
+ @formatter.scenario_ended
265
+ @formatter.story_ended '', ''
266
+
267
+ # then
268
+ @out.string.should include("\n\n Scenario: scenario")
269
+ end
270
+
271
+ it 'should document a step by sentence-casing its name' do
272
+ # when
273
+ @formatter.step_succeeded :given, 'a context'
274
+ @formatter.step_succeeded :when, 'an event'
275
+ @formatter.step_succeeded :then, 'an outcome'
276
+ @formatter.scenario_ended
277
+ @formatter.story_ended '', ''
278
+
279
+ # then
280
+ @out.string.should include("\n\n Given a context\n\n When an event\n\n Then an outcome")
281
+ end
282
+
283
+ it 'should document additional givens using And' do
284
+ # when
285
+ @formatter.step_succeeded :given, 'step 1'
286
+ @formatter.step_succeeded :given, 'step 2'
287
+ @formatter.step_succeeded :given, 'step 3'
288
+ @formatter.scenario_ended
289
+ @formatter.story_ended '', ''
290
+
291
+ # then
292
+ @out.string.should include(" Given step 1\n And step 2\n And step 3")
293
+ end
294
+
295
+ it 'should document additional events using And' do
296
+ # when
297
+ @formatter.step_succeeded :when, 'step 1'
298
+ @formatter.step_succeeded :when, 'step 2'
299
+ @formatter.step_succeeded :when, 'step 3'
300
+ @formatter.scenario_ended
301
+ @formatter.story_ended '', ''
302
+
303
+ # then
304
+ @out.string.should include(" When step 1\n And step 2\n And step 3")
305
+ end
306
+
307
+ it 'should document additional outcomes using And' do
308
+ # when
309
+ @formatter.step_succeeded :then, 'step 1'
310
+ @formatter.step_succeeded :then, 'step 2'
311
+ @formatter.step_succeeded :then, 'step 3'
312
+ @formatter.scenario_ended
313
+ @formatter.story_ended '', ''
314
+
315
+ # then
316
+ @out.string.should include(" Then step 1\n And step 2\n And step 3")
317
+ end
318
+
319
+ it 'should document a GivenScenario followed by a Given using And' do
320
+ # when
321
+ @formatter.step_succeeded :'given scenario', 'a scenario'
322
+ @formatter.step_succeeded :given, 'a context'
323
+ @formatter.scenario_ended
324
+ @formatter.story_ended '', ''
325
+
326
+ # then
327
+ @out.string.should include(" Given scenario a scenario\n And a context")
328
+ end
329
+
330
+ it 'should document steps with replaced params' do
331
+ @formatter.step_succeeded :given, 'a $coloured dog with $n legs', 'pink', 21
332
+ @formatter.scenario_ended
333
+ @formatter.story_ended '', ''
334
+ @out.string.should include(" Given a pink dog with 21 legs")
335
+ end
336
+
337
+ it 'should document steps that include dollar signs ($)' do
338
+ @formatter.step_succeeded :given, 'kicks that cost $$amount', 50
339
+ @formatter.scenario_ended
340
+ @formatter.story_ended '', ''
341
+ @out.string.should include("Given kicks that cost $50")
342
+ end
343
+
344
+ it 'should document regexp steps with replaced params' do
345
+ @formatter.step_succeeded :given, /a (pink|blue) dog with (.*) legs/, 'pink', 21
346
+ @formatter.scenario_ended
347
+ @formatter.story_ended '', ''
348
+ @out.string.should include(" Given a pink dog with 21 legs")
349
+ end
350
+
351
+ it 'should document regex steps that include dollar signs ($)' do
352
+ @formatter.step_succeeded :given, /kicks that cost \$(\d+)/, 50
353
+ @formatter.scenario_ended
354
+ @formatter.story_ended '', ''
355
+ @out.string.should include("Given kicks that cost $50")
356
+ end
357
+
358
+ it "should append PENDING for the first pending step" do
359
+ @formatter.scenario_started('','')
360
+ @formatter.scenario_ended
361
+ @formatter.story_ended '', ''
362
+ @formatter.step_pending(:given, 'a context')
363
+ @formatter.scenario_ended
364
+ @formatter.story_ended '', ''
365
+
366
+ @out.string.should include('Given a context (PENDING)')
367
+ end
368
+
369
+ it "should append PENDING for pending after already pending" do
370
+ @formatter.scenario_started('','')
371
+ @formatter.step_pending(:given, 'a context')
372
+ @formatter.step_pending(:when, 'I say hey')
373
+ @formatter.scenario_ended
374
+ @formatter.story_ended '', ''
375
+
376
+ @out.string.should include('When I say hey (PENDING)')
377
+ end
378
+
379
+ it "should append FAILED for the first failiure" do
380
+ @formatter.scenario_started('','')
381
+ @formatter.step_failed(:given, 'a context')
382
+ @formatter.scenario_ended
383
+ @formatter.story_ended '', ''
384
+
385
+ @out.string.should include('Given a context (FAILED)')
386
+ end
387
+
388
+ it "should append SKIPPED for the second failiure" do
389
+ @formatter.scenario_started('','')
390
+ @formatter.step_failed(:given, 'a context')
391
+ @formatter.step_failed(:when, 'I say hey')
392
+ @formatter.scenario_ended
393
+ @formatter.story_ended '', ''
394
+
395
+ @out.string.should include('When I say hey (SKIPPED)')
396
+ end
397
+
398
+ it "should append SKIPPED for a failure after PENDING" do
399
+ @formatter.scenario_started('','')
400
+ @formatter.step_pending(:given, 'a context')
401
+ @formatter.step_failed(:when, 'I say hey')
402
+ @formatter.scenario_ended
403
+ @formatter.story_ended '', ''
404
+
405
+ @out.string.should include('When I say hey (SKIPPED)')
406
+ end
407
+
408
+ it "should print steps which succeeded in green" do
409
+ @out.stub!(:tty?).and_return(true)
410
+ @options.stub!(:colour).and_return(true)
411
+
412
+ @formatter.scenario_started('','')
413
+ @formatter.step_succeeded(:given, 'a context')
414
+ @formatter.scenario_ended
415
+ @formatter.story_ended '', ''
416
+
417
+ @out.string.should =~ /\e\[32m[\n\s]+Given a context\e\[0m/m
418
+ end
419
+
420
+ it "should print failed steps in red" do
421
+ @out.stub!(:tty?).and_return(true)
422
+ @options.stub!(:colour).and_return(true)
423
+
424
+ @formatter.scenario_started('','')
425
+ @formatter.step_failed(:given, 'a context')
426
+ @formatter.scenario_ended
427
+ @formatter.story_ended '', ''
428
+
429
+ @out.string.should =~ /\e\[31m[\n\s]+Given a context\e\[0m/m
430
+ end
431
+
432
+ it "should print ' (FAILED)' in red" do
433
+ @out.stub!(:tty?).and_return(true)
434
+ @options.stub!(:colour).and_return(true)
435
+
436
+ @formatter.scenario_started('','')
437
+ @formatter.step_failed(:given, 'a context')
438
+ @formatter.scenario_ended
439
+ @formatter.story_ended '', ''
440
+
441
+ @out.string.should =~ /\e\[31m \(FAILED\)\e\[0m/
442
+ end
443
+
444
+ it "should print pending steps in yellow" do
445
+ @out.stub!(:tty?).and_return(true)
446
+ @options.stub!(:colour).and_return(true)
447
+
448
+ @formatter.scenario_started('','')
449
+ @formatter.step_pending(:given, 'a context')
450
+ @formatter.scenario_ended
451
+ @formatter.story_ended '', ''
452
+
453
+ @out.string.should =~ /\e\[33m[\n\s]+Given a context\e\[0m/m
454
+ end
455
+
456
+ it "should print ' (PENDING)' in yellow" do
457
+ @out.stub!(:tty?).and_return(true)
458
+ @options.stub!(:colour).and_return(true)
459
+
460
+ @formatter.scenario_started('','')
461
+ @formatter.step_pending(:given, 'a context')
462
+ @formatter.scenario_ended
463
+ @formatter.story_ended '', ''
464
+
465
+ @out.string.should =~ /\e\[33m \(PENDING\)\e\[0m/
466
+ end
467
+
468
+ it "should print a scenario in red if any of its steps fail" do
469
+ @out.stub!(:tty?).and_return(true)
470
+ @options.stub!(:colour).and_return(true)
471
+
472
+ @formatter.scenario_started('title','narrative')
473
+ @formatter.step_failed(:given, 'a context')
474
+ @formatter.scenario_failed('story', 'scenario1', exception_from { raise RuntimeError, 'oops1' })
475
+ @formatter.story_ended('title','narrative')
476
+ @out.string.should include("\e[31m\n\n Scenario: narrative\e[0m")
477
+ end
478
+
479
+ it "should print a scenario in yellow if its steps are pending" do
480
+ @out.stub!(:tty?).and_return(true)
481
+ @options.stub!(:colour).and_return(true)
482
+
483
+ @formatter.scenario_started('title','narrative')
484
+ @formatter.step_pending(:given, 'a context')
485
+ @formatter.scenario_ended
486
+ @formatter.story_ended('','')
487
+ @out.string.should include("\e[33m\n\n Scenario: narrative\e[0m")
488
+ end
489
+
490
+ it "should print a story in red if any of its scenarios fail" do
491
+ @out.stub!(:tty?).and_return(true)
492
+ @options.stub!(:colour).and_return(true)
493
+
494
+ @formatter.story_started('story', 'narrative')
495
+ @formatter.scenario_started('','')
496
+ @formatter.step_failed(:given, 'a context')
497
+ @formatter.scenario_failed('story', 'scenario1', exception_from { raise RuntimeError, 'oops1' })
498
+ @formatter.story_ended('story', 'narrative')
499
+ @out.string.should include("\e[31mStory: story\n\n narrative\e[0m")
500
+ end
501
+
502
+ it "should print a story in green if all its scenarios succeed" do
503
+ @out.stub!(:tty?).and_return(true)
504
+ @options.stub!(:colour).and_return(true)
505
+
506
+ @formatter.story_started('story', 'narrative')
507
+ @formatter.scenario_started('','')
508
+ @formatter.step_succeeded(:given, 'a context')
509
+ @formatter.scenario_succeeded('story', 'scenario1')
510
+ @formatter.story_ended('story', 'narrative')
511
+ @out.string.should include("\e[32mStory: story\n\n narrative\e[0m")
512
+ end
513
+
514
+ it "should print a story in yellow if all its scenarios are pending" do
515
+ @out.stub!(:tty?).and_return(true)
516
+ @options.stub!(:colour).and_return(true)
517
+
518
+ @formatter.story_started('story', 'narrative')
519
+ @formatter.scenario_started('','')
520
+ @formatter.step_pending(:given, 'a context')
521
+ @formatter.scenario_pending('story', 'scenario1','pending')
522
+ @formatter.story_ended('story', 'narrative')
523
+ @out.string.should include("\e[33mStory: story\n\n narrative\e[0m")
524
+ end
525
+
526
+ it "should print skipped steps in yellow if the scenario is already pending" do
527
+ @out.stub!(:tty?).and_return(true)
528
+ @options.stub!(:colour).and_return(true)
529
+
530
+ @formatter.scenario_started('','')
531
+ @formatter.step_pending(:given, 'a context')
532
+ @formatter.step_failed(:when, 'I say hey')
533
+ @formatter.scenario_ended
534
+ @formatter.story_ended '', ''
535
+
536
+ @out.string.should =~ /\e\[33m[\n\s]+When I say hey\e\[0m/m
537
+ end
538
+
539
+ it "should print ' (SKIPPED)' in yellow if the scenario is already pending" do
540
+ @out.stub!(:tty?).and_return(true)
541
+ @options.stub!(:colour).and_return(true)
542
+
543
+ @formatter.scenario_started('','')
544
+ @formatter.step_pending(:given, 'a context')
545
+ @formatter.step_failed(:when, 'I say hey')
546
+ @formatter.scenario_ended
547
+ @formatter.story_ended '', ''
548
+
549
+ @out.string.should =~ /\e\[33m \(SKIPPED\)\e\[0m/
550
+ end
551
+
552
+ it "should print skipped steps in red if the scenario has already failed" do
553
+ @out.stub!(:tty?).and_return(true)
554
+ @options.stub!(:colour).and_return(true)
555
+
556
+ @formatter.scenario_started('','')
557
+ @formatter.step_failed(:given, 'a context')
558
+ @formatter.step_failed(:when, 'I say hey')
559
+ @formatter.scenario_ended
560
+ @formatter.story_ended '', ''
561
+
562
+ @out.string.should =~ /\e\[31m[\n\s]+When I say hey\e\[0m/m
563
+ end
564
+
565
+ it "should print ' (SKIPPED)' in red if the scenario has already failed" do
566
+ @out.stub!(:tty?).and_return(true)
567
+ @options.stub!(:colour).and_return(true)
568
+
569
+ @formatter.scenario_started('','')
570
+ @formatter.step_failed(:given, 'a context')
571
+ @formatter.step_failed(:when, 'I say hey')
572
+ @formatter.scenario_failed('story', 'scenario1', exception_from { raise RuntimeError, 'oops1' })
573
+ @formatter.story_ended('','')
574
+
575
+ @out.string.should =~ /\e\[31m \(SKIPPED\)\e\[0m/m
576
+ end
577
+
578
+ it 'should print some white space after each story' do
579
+ # when
580
+ @formatter.story_ended 'title', 'narrative'
581
+
582
+ # then
583
+ @out.string.should include("\n\n")
584
+ end
585
+
586
+ it "should print nothing for collected_steps" do
587
+ @formatter.collected_steps(['Given a $coloured $animal', 'Given a $n legged eel'])
588
+ @out.string.should == ("")
589
+ end
590
+
591
+ it "should ignore messages it doesn't care about" do
592
+ lambda {
593
+ @formatter.this_method_does_not_exist
594
+ }.should_not raise_error
595
+ end
596
+ end
597
+ end
598
+ end
599
+ end
600
+ end