cucumber 2.0.0.rc.4 → 2.0.0.rc.5

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 (61) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +74 -52
  3. data/examples/i18n/ht/Rakefile +6 -0
  4. data/examples/i18n/ht/features/adisyon.feature +17 -0
  5. data/examples/i18n/ht/features/divizyon.feature +10 -0
  6. data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +25 -0
  7. data/examples/i18n/ht/lib/kalkilatris.rb +14 -0
  8. data/features/docs/cli/dry_run.feature +43 -0
  9. data/features/docs/cli/strict_mode.feature +24 -1
  10. data/features/docs/defining_steps/nested_steps.feature +49 -0
  11. data/features/docs/exception_in_after_step_hook.feature +1 -1
  12. data/features/docs/exception_in_around_hook.feature +80 -0
  13. data/features/docs/formatters/json_formatter.feature +65 -1
  14. data/features/docs/formatters/junit_formatter.feature +40 -0
  15. data/features/docs/{wire_protocol_erb.feature → wire_protocol/erb_configuration.feature} +2 -2
  16. data/features/docs/wire_protocol/handle_unexpected_response.feature +30 -0
  17. data/features/docs/wire_protocol/invoke_message.feature +216 -0
  18. data/features/docs/wire_protocol/readme.md +26 -0
  19. data/features/docs/wire_protocol/snippets_message.feature +51 -0
  20. data/features/docs/wire_protocol/step_matches_message.feature +81 -0
  21. data/features/docs/{wire_protocol_table_diffing.feature → wire_protocol/table_diffing.feature} +1 -0
  22. data/features/docs/{wire_protocol_tags.feature → wire_protocol/tags.feature} +1 -0
  23. data/features/docs/{wire_protocol_timeouts.feature → wire_protocol/timeouts.feature} +1 -0
  24. data/features/docs/work_in_progress.feature +1 -1
  25. data/features/docs/writing_support_code/around_hooks.feature +31 -0
  26. data/features/docs/writing_support_code/before_hook.feature +7 -3
  27. data/features/docs/writing_support_code/tagged_hooks.feature +44 -6
  28. data/features/lib/step_definitions/wire_steps.rb +18 -1
  29. data/features/lib/support/fake_wire_server.rb +10 -7
  30. data/lib/cucumber.rb +1 -3
  31. data/lib/cucumber/cli/options.rb +7 -0
  32. data/lib/cucumber/encoding.rb +5 -0
  33. data/lib/cucumber/errors.rb +8 -0
  34. data/lib/cucumber/filters/prepare_world.rb +13 -5
  35. data/lib/cucumber/formatter/console.rb +1 -1
  36. data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +9 -6
  37. data/lib/cucumber/formatter/junit.rb +95 -0
  38. data/lib/cucumber/formatter/legacy_api/adapter.rb +39 -3
  39. data/lib/cucumber/platform.rb +1 -1
  40. data/lib/cucumber/project_initializer.rb +43 -0
  41. data/lib/cucumber/rb_support/rb_step_definition.rb +11 -2
  42. data/lib/cucumber/rb_support/rb_world.rb +2 -2
  43. data/lib/cucumber/rb_support/snippet.rb +1 -1
  44. data/lib/cucumber/rspec/doubles.rb +1 -1
  45. data/lib/cucumber/running_test_case.rb +115 -0
  46. data/lib/cucumber/runtime.rb +5 -1
  47. data/lib/cucumber/runtime/for_programming_languages.rb +2 -2
  48. data/lib/cucumber/runtime/support_code.rb +18 -8
  49. data/spec/cucumber/formatter/junit_spec.rb +212 -156
  50. data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +89 -1
  51. data/spec/cucumber/formatter/pretty_spec.rb +13 -0
  52. data/spec/cucumber/project_initializer_spec.rb +87 -0
  53. data/spec/cucumber/rb_support/rb_step_definition_spec.rb +21 -3
  54. data/spec/cucumber/rb_support/snippet_spec.rb +6 -6
  55. data/spec/cucumber/running_test_case_spec.rb +83 -0
  56. data/spec/spec_helper.rb +1 -4
  57. metadata +35 -18
  58. data/bin/cuke +0 -60
  59. data/features/docs/report_called_undefined_steps.feature +0 -57
  60. data/features/docs/wire_protocol.feature +0 -337
  61. data/lib/cucumber/ast/facade.rb +0 -117
@@ -0,0 +1,26 @@
1
+ Cucumber's wire protocol allows step definitions to be
2
+ implemented and invoked on any platform.
3
+
4
+ Communication is over a TCP socket, which Cucumber connects to when it finds
5
+ a definition file with the .wire extension in the step_definitions folder
6
+ (or other load path). Note that these files are rendered with ERB when loaded.
7
+
8
+ A WirePacket flowing in either direction is formatted as a JSON-encoded
9
+ string, with a newline character signaling the end of a packet. See the
10
+ specs for Cucumber::WireSupport::WirePacket for more details.
11
+
12
+ Cucumber sends the following request messages out over the wire:
13
+
14
+ * `step_matches` - Find out whether the wire server has a definition for a step
15
+ * `invoke` - Ask for a step definition to be invoked
16
+ * `begin_scenario` - signals that cucumber is about to execute a scenario
17
+ * `end_scenario` - signals that cucumber has finished executing a scenario
18
+ * `snippet_text` - requests a snippet for an undefined step
19
+
20
+ Every message supports two standard responses:
21
+
22
+ * `success` - expects different arguments (sometimes none at all) depending
23
+ on the request that was sent.
24
+ * `fail` - causes a Cucumber::WireSupport::WireException to be raised.
25
+
26
+ Some messages support more responses - see individual scenarios for details.
@@ -0,0 +1,51 @@
1
+ @wire
2
+ Feature: Snippets message
3
+
4
+ If a step doesn't match, Cucumber will ask the wire server to return a snippet of code for a
5
+ step definition.
6
+
7
+ Background:
8
+ Given a file named "features/wired.feature" with:
9
+ """
10
+ Feature: High strung
11
+ Scenario: Wired
12
+ Given we're all wired
13
+
14
+ """
15
+ And a file named "features/step_definitions/some_remote_place.wire" with:
16
+ """
17
+ host: localhost
18
+ port: 54321
19
+
20
+ """
21
+
22
+ @spawn
23
+ Scenario: Wire server returns snippets for a step that didn't match
24
+ Given there is a wire server running on port 54321 which understands the following protocol:
25
+ | request | response |
26
+ | ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
27
+ | ["snippet_text",{"step_keyword":"Given","multiline_arg_class":"","step_name":"we're all wired"}] | ["success","foo()\n bar;\nbaz"] |
28
+ | ["begin_scenario"] | ["success"] |
29
+ | ["end_scenario"] | ["success"] |
30
+ When I run `cucumber -f pretty`
31
+ Then the stderr should not contain anything
32
+ And it should pass with:
33
+ """
34
+ Feature: High strung
35
+
36
+ Scenario: Wired # features/wired.feature:2
37
+ Given we're all wired # features/wired.feature:3
38
+
39
+ 1 scenario (1 undefined)
40
+ 1 step (1 undefined)
41
+ """
42
+ And the output should contain:
43
+ """
44
+
45
+ You can implement step definitions for undefined steps with these snippets:
46
+
47
+ foo()
48
+ bar;
49
+ baz
50
+
51
+ """
@@ -0,0 +1,81 @@
1
+ @wire
2
+ Feature: Step matches message
3
+
4
+ When the features have been parsed, Cucumber will send a `step_matches`
5
+ message to ask the wire server if it can match a step name. This happens for
6
+ each of the steps in each of the features.
7
+
8
+ The wire server replies with an array of StepMatch objects.
9
+
10
+ When each StepMatch is returned, it contains the following data:
11
+
12
+ * `id` - identifier for the step definition to be used later when if it
13
+ needs to be invoked. The identifier can be any string value and
14
+ is simply used for the wire server's own reference.
15
+ * `args` - any argument values as captured by the wire end's own regular
16
+ expression (or other argument matching) process.
17
+
18
+ Background:
19
+ Given a file named "features/wired.feature" with:
20
+ """
21
+ Feature: High strung
22
+ Scenario: Wired
23
+ Given we're all wired
24
+
25
+ """
26
+ And a file named "features/step_definitions/some_remote_place.wire" with:
27
+ """
28
+ host: localhost
29
+ port: 54321
30
+
31
+ """
32
+
33
+ Scenario: Dry run finds no step match
34
+ Given there is a wire server running on port 54321 which understands the following protocol:
35
+ | request | response |
36
+ | ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[]] |
37
+ When I run `cucumber --dry-run --no-snippets -f progress`
38
+ And it should pass with:
39
+ """
40
+ U
41
+
42
+ 1 scenario (1 undefined)
43
+ 1 step (1 undefined)
44
+
45
+ """
46
+
47
+ Scenario: Dry run finds a step match
48
+ Given there is a wire server running on port 54321 which understands the following protocol:
49
+ | request | response |
50
+ | ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[]}]] |
51
+ When I run `cucumber --dry-run -f progress`
52
+ And it should pass with:
53
+ """
54
+ -
55
+
56
+ 1 scenario (1 skipped)
57
+ 1 step (1 skipped)
58
+
59
+ """
60
+
61
+ Scenario: Step matches returns details about the remote step definition
62
+
63
+ Optionally, the StepMatch can also contain a source reference, and a native
64
+ regexp string which will be used by some formatters.
65
+
66
+ Given there is a wire server running on port 54321 which understands the following protocol:
67
+ | request | response |
68
+ | ["step_matches",{"name_to_match":"we're all wired"}] | ["success",[{"id":"1", "args":[], "source":"MyApp.MyClass:123", "regexp":"we.*"}]] |
69
+ When I run `cucumber -f stepdefs --dry-run`
70
+ Then it should pass with:
71
+ """
72
+ -
73
+
74
+ we.* # MyApp.MyClass:123
75
+
76
+ 1 scenario (1 skipped)
77
+ 1 step (1 skipped)
78
+
79
+ """
80
+ And the stderr should not contain anything
81
+
@@ -1,5 +1,6 @@
1
1
  @wire
2
2
  Feature: Wire protocol table diffing
3
+
3
4
  In order to use the amazing functionality in the Cucumber table object
4
5
  As a wire server
5
6
  I want to be able to ask for a table diff during a step definition invocation
@@ -1,5 +1,6 @@
1
1
  @wire
2
2
  Feature: Wire protocol tags
3
+
3
4
  In order to use Before and After hooks in a wire server, we send tags with the
4
5
  scenario in the begin_scenario and end_scenario messages
5
6
 
@@ -1,5 +1,6 @@
1
1
  @wire
2
2
  Feature: Wire protocol timeouts
3
+
3
4
  We don't want Cucumber to hang forever on a wire server that's not even there,
4
5
  but equally we need to give the user the flexibility to allow step definitions
5
6
  to take a while to execute, if that's what they need.
@@ -148,7 +148,7 @@ Feature: Cucumber --work-in-progress switch
148
148
  The --wip switch was used, so I didn't expect anything to pass. These scenarios passed:
149
149
  (::) passed scenarios (::)
150
150
 
151
- features/passing_outline.feature:7:in `Scenario Outline: Passing, Examples (row 1)'
151
+ features/passing_outline.feature:7:in `Scenario Outline: Passing, Examples (#1)'
152
152
 
153
153
 
154
154
  """
@@ -227,3 +227,34 @@ Feature: Around hooks
227
227
  2 steps (2 passed)
228
228
 
229
229
  """
230
+
231
+ Scenario: Around Hooks and the Custom World
232
+ Given a file named "features/step_definitions/steps.rb" with:
233
+ """
234
+ Then /^the world should be available in the hook$/ do
235
+ $previous_world = self
236
+ expect($hook_world).to eq(self)
237
+ end
238
+
239
+ Then /^what$/ do
240
+ expect($hook_world).not_to eq($previous_world)
241
+ end
242
+ """
243
+ And a file named "features/support/hooks.rb" with:
244
+ """
245
+ Around do |scenario, block|
246
+ $hook_world = self
247
+ block.call
248
+ end
249
+ """
250
+ And a file named "features/f.feature" with:
251
+ """
252
+ Feature: Around hooks
253
+ Scenario: using hook
254
+ Then the world should be available in the hook
255
+
256
+ Scenario: using the same hook
257
+ Then what
258
+ """
259
+ When I run `cucumber features/f.feature`
260
+ Then it should pass
@@ -25,7 +25,8 @@ Feature: Before Hook
25
25
  """
26
26
  NAMES:
27
27
  Feature name
28
- Scenario: Scenario name
28
+ Scenario name
29
+
29
30
  """
30
31
 
31
32
  Scenario: Examine names of scenario outline and feature
@@ -46,7 +47,8 @@ Feature: Before Hook
46
47
  Before do |scenario|
47
48
  names << scenario.scenario_outline.feature.name.split("\n").first
48
49
  names << scenario.scenario_outline.name.split("\n").first
49
- if(names.size == 2)
50
+ names << scenario.name.split("\n").first
51
+ if(names.size == 3)
50
52
  raise "NAMES:\n" + names.join("\n") + "\n"
51
53
  end
52
54
  end
@@ -56,6 +58,8 @@ Feature: Before Hook
56
58
  """
57
59
  NAMES:
58
60
  Feature name
59
- Scenario Outline: Scenario Outline name
61
+ Scenario Outline name, Examples Table name (#1)
62
+ Scenario Outline name, Examples Table name (#1)
63
+
60
64
  """
61
65
 
@@ -4,7 +4,7 @@ Feature: Tagged hooks
4
4
  Given the standard step definitions
5
5
  And a file named "features/support/hooks.rb" with:
6
6
  """
7
- Before('~@no-boom') do
7
+ Before('~@no-boom') do
8
8
  raise 'boom'
9
9
  end
10
10
  """
@@ -17,12 +17,23 @@ Feature: Tagged hooks
17
17
  @no-boom
18
18
  Scenario: omitting hook
19
19
  Given this step passes
20
+
21
+ Scenario Outline: omitting hook on specified examples
22
+ Given this step passes
23
+
24
+ Examples:
25
+ | Value |
26
+ | Irrelevant |
27
+
28
+ @no-boom
29
+ Examples:
30
+ | Value |
31
+ | Also Irrelevant |
20
32
  """
21
33
 
22
- @spawn
23
- Scenario: Invoke tagged hook
34
+ Scenario: omit tagged hook
24
35
  When I run `cucumber features/f.feature:2`
25
- Then it should fail with:
36
+ Then it should fail with exactly:
26
37
  """
27
38
  Feature: With and without hooks
28
39
 
@@ -36,12 +47,13 @@ Feature: Tagged hooks
36
47
 
37
48
  1 scenario (1 failed)
38
49
  1 step (1 skipped)
50
+ 0m0.012s
39
51
 
40
52
  """
41
53
 
42
- Scenario: Omit tagged hook
54
+ Scenario: omit tagged hook
43
55
  When I run `cucumber features/f.feature:6`
44
- Then it should pass with:
56
+ Then it should pass with exactly:
45
57
  """
46
58
  Feature: With and without hooks
47
59
 
@@ -51,7 +63,33 @@ Feature: Tagged hooks
51
63
 
52
64
  1 scenario (1 passed)
53
65
  1 step (1 passed)
66
+ 0m0.012s
54
67
 
55
68
  """
69
+ Scenario: Omit example hook
70
+ When I run `cucumber features/f.feature:12`
71
+ Then it should fail with exactly:
72
+ """
73
+ Feature: With and without hooks
74
+
75
+ Scenario Outline: omitting hook on specified examples # features/f.feature:9
76
+ Given this step passes # features/f.feature:10
77
+
78
+ Examples:
79
+ | Value |
80
+ boom (RuntimeError)
81
+ ./features/support/hooks.rb:2:in `Before'
82
+ | Irrelevant |
56
83
 
84
+ Failing Scenarios:
85
+ cucumber features/f.feature:14 # Scenario Outline: omitting hook on specified examples, Examples (#1)
86
+
87
+ 1 scenario (1 failed)
88
+ 1 step (1 skipped)
89
+ 0m0.012s
90
+
91
+ """
92
+ Scenario:
93
+ When I run `cucumber features/f.feature:17`
94
+ Then it should pass
57
95
 
@@ -17,9 +17,26 @@ Given /^I have environment variable (\w+) set to "([^"]*)"$/ do |variable, value
17
17
  set_env(variable, value)
18
18
  end
19
19
 
20
+ Then(/^the wire server should have received the following messages:$/) do |expected_messages|
21
+ expect(messages_received).to eq expected_messages.raw.flatten
22
+ end
23
+
20
24
  module WireHelper
25
+ attr_reader :messages_received
26
+
21
27
  def start_wire_server
22
- @wire_pid = fork { @server.run }
28
+ @messages_received = []
29
+ reader, writer = IO.pipe
30
+ @wire_pid = fork {
31
+ reader.close
32
+ @server.run(writer)
33
+ }
34
+ writer.close
35
+ Thread.new do
36
+ while message = reader.gets
37
+ @messages_received << message.strip
38
+ end
39
+ end
23
40
  at_exit { stop_wire_server }
24
41
  end
25
42
 
@@ -7,9 +7,9 @@ class FakeWireServer
7
7
  @delays = {}
8
8
  end
9
9
 
10
- def run
10
+ def run(io)
11
11
  @server = TCPServer.open(@port)
12
- loop { handle_connections }
12
+ loop { handle_connections(io) }
13
13
  end
14
14
 
15
15
  def delay_response(message, delay)
@@ -18,13 +18,14 @@ class FakeWireServer
18
18
 
19
19
  private
20
20
 
21
- def handle_connections
22
- Thread.start(@server.accept) { |socket| open_session_on socket }
21
+ def handle_connections(io)
22
+ Thread.start(@server.accept) { |socket| open_session_on socket, io }
23
23
  end
24
24
 
25
- def open_session_on(socket)
25
+ def open_session_on(socket, io)
26
26
  begin
27
- SocketSession.new(socket, @protocol_table, @delays).start
27
+ on_message = lambda { |message| io.puts message }
28
+ SocketSession.new(socket, @protocol_table, @delays, on_message).start
28
29
  rescue Exception => e
29
30
  raise e
30
31
  ensure
@@ -33,10 +34,11 @@ class FakeWireServer
33
34
  end
34
35
 
35
36
  class SocketSession
36
- def initialize(socket, protocol, delays)
37
+ def initialize(socket, protocol, delays, on_message)
37
38
  @socket = socket
38
39
  @protocol = protocol
39
40
  @delays = delays
41
+ @on_message = on_message
40
42
  end
41
43
 
42
44
  def start
@@ -50,6 +52,7 @@ class FakeWireServer
50
52
  def handle(data)
51
53
  if protocol_entry = response_to(data.strip)
52
54
  sleep delay(data)
55
+ @on_message.call(MultiJson.load(protocol_entry['request'])[0])
53
56
  send_response(protocol_entry['response'])
54
57
  else
55
58
  serialized_exception = { :message => "Not understood: #{data}", :backtrace => [] }
@@ -1,7 +1,5 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
-
4
1
  require 'yaml'
2
+ require 'cucumber/encoding'
5
3
  require 'cucumber/platform'
6
4
  require 'cucumber/runtime'
7
5
  require 'cucumber/cli/main'
@@ -1,6 +1,7 @@
1
1
  require 'cucumber/cli/profile_loader'
2
2
  require 'cucumber/formatter/ansicolor'
3
3
  require 'cucumber/rb_support/rb_language'
4
+ require 'cucumber/project_initializer'
4
5
 
5
6
  module Cucumber
6
7
  module Cli
@@ -126,6 +127,12 @@ module Cucumber
126
127
  *FORMAT_HELP) do |v|
127
128
  @options[:formats] << [v, @out_stream]
128
129
  end
130
+ opts.on('--init',
131
+ 'Initializes folder structure and generates conventional files for',
132
+ 'a Cucumber project.') do |v|
133
+ ProjectInitializer.new.run
134
+ Kernel.exit(0)
135
+ end
129
136
  opts.on("-o", "--out [FILE|DIR]",
130
137
  "Write output to a file/directory instead of STDOUT. This option",
131
138
  "applies to the previously specified --format, or the",