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.
- checksums.yaml +4 -4
- data/History.md +74 -52
- data/examples/i18n/ht/Rakefile +6 -0
- data/examples/i18n/ht/features/adisyon.feature +17 -0
- data/examples/i18n/ht/features/divizyon.feature +10 -0
- data/examples/i18n/ht/features/step_definitions/kalkilatris_steps.rb +25 -0
- data/examples/i18n/ht/lib/kalkilatris.rb +14 -0
- data/features/docs/cli/dry_run.feature +43 -0
- data/features/docs/cli/strict_mode.feature +24 -1
- data/features/docs/defining_steps/nested_steps.feature +49 -0
- data/features/docs/exception_in_after_step_hook.feature +1 -1
- data/features/docs/exception_in_around_hook.feature +80 -0
- data/features/docs/formatters/json_formatter.feature +65 -1
- data/features/docs/formatters/junit_formatter.feature +40 -0
- data/features/docs/{wire_protocol_erb.feature → wire_protocol/erb_configuration.feature} +2 -2
- data/features/docs/wire_protocol/handle_unexpected_response.feature +30 -0
- data/features/docs/wire_protocol/invoke_message.feature +216 -0
- data/features/docs/wire_protocol/readme.md +26 -0
- data/features/docs/wire_protocol/snippets_message.feature +51 -0
- data/features/docs/wire_protocol/step_matches_message.feature +81 -0
- data/features/docs/{wire_protocol_table_diffing.feature → wire_protocol/table_diffing.feature} +1 -0
- data/features/docs/{wire_protocol_tags.feature → wire_protocol/tags.feature} +1 -0
- data/features/docs/{wire_protocol_timeouts.feature → wire_protocol/timeouts.feature} +1 -0
- data/features/docs/work_in_progress.feature +1 -1
- data/features/docs/writing_support_code/around_hooks.feature +31 -0
- data/features/docs/writing_support_code/before_hook.feature +7 -3
- data/features/docs/writing_support_code/tagged_hooks.feature +44 -6
- data/features/lib/step_definitions/wire_steps.rb +18 -1
- data/features/lib/support/fake_wire_server.rb +10 -7
- data/lib/cucumber.rb +1 -3
- data/lib/cucumber/cli/options.rb +7 -0
- data/lib/cucumber/encoding.rb +5 -0
- data/lib/cucumber/errors.rb +8 -0
- data/lib/cucumber/filters/prepare_world.rb +13 -5
- data/lib/cucumber/formatter/console.rb +1 -1
- data/lib/cucumber/formatter/gherkin_formatter_adapter.rb +9 -6
- data/lib/cucumber/formatter/junit.rb +95 -0
- data/lib/cucumber/formatter/legacy_api/adapter.rb +39 -3
- data/lib/cucumber/platform.rb +1 -1
- data/lib/cucumber/project_initializer.rb +43 -0
- data/lib/cucumber/rb_support/rb_step_definition.rb +11 -2
- data/lib/cucumber/rb_support/rb_world.rb +2 -2
- data/lib/cucumber/rb_support/snippet.rb +1 -1
- data/lib/cucumber/rspec/doubles.rb +1 -1
- data/lib/cucumber/running_test_case.rb +115 -0
- data/lib/cucumber/runtime.rb +5 -1
- data/lib/cucumber/runtime/for_programming_languages.rb +2 -2
- data/lib/cucumber/runtime/support_code.rb +18 -8
- data/spec/cucumber/formatter/junit_spec.rb +212 -156
- data/spec/cucumber/formatter/legacy_api/adapter_spec.rb +89 -1
- data/spec/cucumber/formatter/pretty_spec.rb +13 -0
- data/spec/cucumber/project_initializer_spec.rb +87 -0
- data/spec/cucumber/rb_support/rb_step_definition_spec.rb +21 -3
- data/spec/cucumber/rb_support/snippet_spec.rb +6 -6
- data/spec/cucumber/running_test_case_spec.rb +83 -0
- data/spec/spec_helper.rb +1 -4
- metadata +35 -18
- data/bin/cuke +0 -60
- data/features/docs/report_called_undefined_steps.feature +0 -57
- data/features/docs/wire_protocol.feature +0 -337
- 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
|
+
|
@@ -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 (
|
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
|
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
|
-
|
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
|
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
|
-
|
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:
|
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
|
-
@
|
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
|
-
|
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 => [] }
|
data/lib/cucumber.rb
CHANGED
@@ -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'
|
data/lib/cucumber/cli/options.rb
CHANGED
@@ -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",
|