cucumber 0.5.1 → 0.5.2
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.
- data/History.txt +10 -0
- data/Rakefile +1 -0
- data/VERSION.yml +1 -1
- data/cucumber.gemspec +12 -3
- data/examples/watir/Rakefile +3 -1
- data/examples/watir/cucumber.yml +1 -0
- data/examples/watir/features/search.feature +1 -1
- data/features/step_definitions/wire_steps.rb +23 -5
- data/features/support/fake_wire_server.rb +16 -2
- data/features/wire_protocol_timeouts.feature +62 -0
- data/lib/cucumber/ast/table.rb +0 -5
- data/lib/cucumber/cli/options.rb +11 -0
- data/lib/cucumber/formatter/html.rb +16 -0
- data/lib/cucumber/languages.yml +200 -200
- data/lib/cucumber/wire_support/configuration.rb +18 -0
- data/lib/cucumber/wire_support/connection.rb +16 -12
- data/lib/cucumber/wire_support/request_handler.rb +14 -4
- data/lib/cucumber/wire_support/wire_language.rb +13 -17
- data/lib/cucumber/wire_support/wire_protocol.rb +15 -79
- data/lib/cucumber/wire_support/wire_protocol/requests.rb +113 -0
- data/spec/cucumber/formatter/html_spec.rb +14 -0
- data/spec/cucumber/wire_support/configuration_spec.rb +34 -0
- data/spec/cucumber/wire_support/wire_language_spec.rb +2 -2
- metadata +19 -3
@@ -0,0 +1,18 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module WireSupport
|
3
|
+
class Configuration
|
4
|
+
attr_reader :host, :port
|
5
|
+
|
6
|
+
def initialize(wire_file)
|
7
|
+
params = YAML.load_file(wire_file)
|
8
|
+
@host = params['host']
|
9
|
+
@port = params['port']
|
10
|
+
@timeouts = params['timeout'] || {}
|
11
|
+
end
|
12
|
+
|
13
|
+
def timeout(message = nil)
|
14
|
+
return @timeouts[message.to_s] || 3
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -4,33 +4,35 @@ require 'cucumber/wire_support/wire_protocol'
|
|
4
4
|
module Cucumber
|
5
5
|
module WireSupport
|
6
6
|
class Connection
|
7
|
+
class ConnectionError < StandardError; end
|
8
|
+
|
7
9
|
include WireProtocol
|
8
10
|
|
9
11
|
def initialize(config)
|
10
|
-
@
|
12
|
+
@config = config
|
11
13
|
end
|
12
14
|
|
13
|
-
def call_remote(
|
14
|
-
timeout = 3
|
15
|
+
def call_remote(request_handler, message, params)
|
15
16
|
packet = WirePacket.new(message, params)
|
16
17
|
|
17
18
|
begin
|
18
|
-
send_data_to_socket(packet.to_json
|
19
|
-
response = fetch_data_from_socket(timeout)
|
20
|
-
response.handle_with(
|
21
|
-
rescue Timeout::Error
|
22
|
-
|
19
|
+
send_data_to_socket(packet.to_json)
|
20
|
+
response = fetch_data_from_socket(@config.timeout(message))
|
21
|
+
response.handle_with(request_handler)
|
22
|
+
rescue Timeout::Error => e
|
23
|
+
backtrace = e.backtrace ; backtrace.shift # because Timeout puts some wierd stuff in there
|
24
|
+
raise Timeout::Error, "Timed out calling wire server with message '#{message}'", backtrace
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
26
28
|
def exception(params)
|
27
|
-
WireException.new(params, @host, @port)
|
29
|
+
WireException.new(params, @config.host, @config.port)
|
28
30
|
end
|
29
31
|
|
30
32
|
private
|
31
33
|
|
32
|
-
def send_data_to_socket(data
|
33
|
-
Timeout.timeout(timeout) { socket.puts(data) }
|
34
|
+
def send_data_to_socket(data)
|
35
|
+
Timeout.timeout(@config.timeout) { socket.puts(data) }
|
34
36
|
end
|
35
37
|
|
36
38
|
def fetch_data_from_socket(timeout)
|
@@ -39,7 +41,9 @@ module Cucumber
|
|
39
41
|
end
|
40
42
|
|
41
43
|
def socket
|
42
|
-
@socket ||= TCPSocket.new(@host, @port)
|
44
|
+
@socket ||= TCPSocket.new(@config.host, @config.port)
|
45
|
+
rescue Errno::ECONNREFUSED => exception
|
46
|
+
raise(ConnectionError, "Unable to contact the wire server at #{@config.host}:#{@config.port}. Is it up?")
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
@@ -1,19 +1,29 @@
|
|
1
1
|
module Cucumber
|
2
2
|
module WireSupport
|
3
3
|
class RequestHandler
|
4
|
-
def initialize(connection
|
4
|
+
def initialize(connection)
|
5
5
|
@connection = connection
|
6
|
-
@message =
|
7
|
-
instance_eval(&block) if block
|
6
|
+
@message = underscore(self.class.name.split('::').last)
|
8
7
|
end
|
9
8
|
|
10
|
-
def execute(request_params)
|
9
|
+
def execute(request_params = nil)
|
11
10
|
@connection.call_remote(self, @message, request_params)
|
12
11
|
end
|
13
12
|
|
14
13
|
def handle_fail(params)
|
15
14
|
raise @connection.exception(params)
|
16
15
|
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
# Props to Rails
|
20
|
+
def underscore(camel_cased_word)
|
21
|
+
camel_cased_word.to_s.gsub(/::/, '/').
|
22
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
23
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
24
|
+
tr("-", "_").
|
25
|
+
downcase
|
26
|
+
end
|
17
27
|
end
|
18
28
|
end
|
19
29
|
end
|
@@ -8,6 +8,7 @@ EOM
|
|
8
8
|
exit(1)
|
9
9
|
end
|
10
10
|
require 'cucumber/wire_support/connection'
|
11
|
+
require 'cucumber/wire_support/configuration'
|
11
12
|
require 'cucumber/wire_support/wire_packet'
|
12
13
|
require 'cucumber/wire_support/wire_exception'
|
13
14
|
require 'cucumber/wire_support/wire_step_definition'
|
@@ -15,19 +16,11 @@ require 'cucumber/wire_support/wire_step_definition'
|
|
15
16
|
module Cucumber
|
16
17
|
module WireSupport
|
17
18
|
|
18
|
-
# The wire-protocol (lanugage independent) implementation of the programming
|
19
|
+
# The wire-protocol (lanugage independent) implementation of the programming
|
20
|
+
# language API.
|
19
21
|
class WireLanguage
|
20
22
|
include LanguageSupport::LanguageMethods
|
21
|
-
|
22
|
-
def load_code_file(wire_file)
|
23
|
-
config = YAML.load_file(wire_file)
|
24
|
-
@connections << Connection.new(config)
|
25
|
-
end
|
26
|
-
|
27
|
-
def step_matches(step_name, formatted_step_name)
|
28
|
-
@connections.map{ |remote| remote.step_matches(step_name, formatted_step_name)}.flatten
|
29
|
-
end
|
30
|
-
|
23
|
+
|
31
24
|
def initialize(step_mother)
|
32
25
|
@connections = []
|
33
26
|
end
|
@@ -35,6 +28,11 @@ module Cucumber
|
|
35
28
|
def alias_adverbs(adverbs)
|
36
29
|
end
|
37
30
|
|
31
|
+
def load_code_file(wire_file)
|
32
|
+
config = Configuration.new(wire_file)
|
33
|
+
@connections << Connection.new(config)
|
34
|
+
end
|
35
|
+
|
38
36
|
def snippet_text(step_keyword, step_name, multiline_arg_class)
|
39
37
|
snippets = @connections.map do |remote|
|
40
38
|
remote.snippet_text(step_keyword, step_name, multiline_arg_class.to_s)
|
@@ -42,6 +40,10 @@ module Cucumber
|
|
42
40
|
snippets.flatten.join("\n")
|
43
41
|
end
|
44
42
|
|
43
|
+
def step_matches(step_name, formatted_step_name)
|
44
|
+
@connections.map{ |remote| remote.step_matches(step_name, formatted_step_name)}.flatten
|
45
|
+
end
|
46
|
+
|
45
47
|
protected
|
46
48
|
|
47
49
|
def begin_scenario(scenario)
|
@@ -51,12 +53,6 @@ module Cucumber
|
|
51
53
|
def end_scenario
|
52
54
|
@connections.each { |remote| remote.end_scenario }
|
53
55
|
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
def step_definitions
|
58
|
-
@step_definitions ||= {}
|
59
|
-
end
|
60
56
|
end
|
61
57
|
end
|
62
58
|
end
|
@@ -1,108 +1,44 @@
|
|
1
1
|
require 'cucumber/step_argument'
|
2
|
-
require 'cucumber/wire_support/
|
2
|
+
require 'cucumber/wire_support/wire_protocol/requests'
|
3
3
|
|
4
4
|
module Cucumber
|
5
5
|
module WireSupport
|
6
6
|
module WireProtocol
|
7
7
|
def step_matches(name_to_match, name_to_report)
|
8
|
-
|
9
|
-
|
10
|
-
def handle_step_matches(params)
|
11
|
-
params.map do |raw_step_match|
|
12
|
-
step_definition = WireStepDefinition.new(@connection, raw_step_match)
|
13
|
-
step_args = raw_step_match['args'].map do |raw_arg|
|
14
|
-
StepArgument.new(raw_arg['val'], raw_arg['pos'])
|
15
|
-
end
|
16
|
-
@connection.step_match(step_definition, step_args) # convoluted!
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
8
|
+
handler = Requests::StepMatches.new(self)
|
9
|
+
handler.execute(name_to_match, name_to_report)
|
20
10
|
end
|
21
11
|
|
22
|
-
def step_match(step_definition, step_args)
|
23
|
-
StepMatch.new(step_definition, @name_to_match, @name_to_report, step_args)
|
24
|
-
end
|
25
|
-
|
26
12
|
def snippet_text(step_keyword, step_name, multiline_arg_class_name)
|
27
|
-
|
28
|
-
|
29
|
-
make_request(:snippet_text, request_params) do
|
30
|
-
def handle_snippet_text(text)
|
31
|
-
text
|
32
|
-
end
|
33
|
-
end
|
13
|
+
handler = Requests::SnippetText.new(self)
|
14
|
+
handler.execute(step_keyword, step_name, multiline_arg_class_name)
|
34
15
|
end
|
35
16
|
|
36
17
|
def invoke(step_definition_id, args)
|
37
|
-
|
38
|
-
|
39
|
-
make_request(:invoke, request_params) do
|
40
|
-
def handle_success(params)
|
41
|
-
end
|
42
|
-
|
43
|
-
def handle_pending(message)
|
44
|
-
raise Pending, message || "TODO"
|
45
|
-
end
|
46
|
-
|
47
|
-
def handle_diff(tables)
|
48
|
-
table1 = Ast::Table.new(tables[0])
|
49
|
-
table2 = Ast::Table.new(tables[1])
|
50
|
-
begin
|
51
|
-
table1.diff!(table2)
|
52
|
-
rescue Cucumber::Ast::Table::Different
|
53
|
-
@connection.diff_failed
|
54
|
-
end
|
55
|
-
@connection.diff_ok
|
56
|
-
end
|
57
|
-
|
58
|
-
def handle_step_failed(params)
|
59
|
-
handle_fail(params)
|
60
|
-
end
|
61
|
-
end
|
18
|
+
handler = Requests::Invoke.new(self)
|
19
|
+
handler.execute(step_definition_id, args)
|
62
20
|
end
|
63
21
|
|
64
22
|
def diff_failed
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
def handle_step_failed(params)
|
70
|
-
handle_fail(params)
|
71
|
-
end
|
72
|
-
end
|
23
|
+
handler = Requests::DiffFailed.new(self)
|
24
|
+
handler.execute
|
73
25
|
end
|
74
26
|
|
75
27
|
def diff_ok
|
76
|
-
|
77
|
-
|
78
|
-
end
|
79
|
-
|
80
|
-
def handle_step_failed(params)
|
81
|
-
handle_fail(params)
|
82
|
-
end
|
83
|
-
end
|
28
|
+
handler = Requests::DiffOk.new(self)
|
29
|
+
handler.execute
|
84
30
|
end
|
85
31
|
|
86
32
|
def begin_scenario(scenario)
|
87
|
-
|
88
|
-
|
89
|
-
end
|
90
|
-
end
|
33
|
+
handler = Requests::BeginScenario.new(self)
|
34
|
+
handler.execute(scenario)
|
91
35
|
end
|
92
36
|
|
93
37
|
def end_scenario
|
94
|
-
|
95
|
-
|
96
|
-
end
|
97
|
-
end
|
38
|
+
handler = Requests::EndScenario.new(self)
|
39
|
+
handler.execute
|
98
40
|
end
|
99
41
|
|
100
|
-
private
|
101
|
-
|
102
|
-
def make_request(request_message, params = nil, &block)
|
103
|
-
handler = RequestHandler.new(self, request_message, &block)
|
104
|
-
handler.execute(params)
|
105
|
-
end
|
106
42
|
end
|
107
43
|
end
|
108
44
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'cucumber/wire_support/request_handler'
|
2
|
+
module Cucumber
|
3
|
+
module WireSupport
|
4
|
+
module WireProtocol
|
5
|
+
module Requests
|
6
|
+
class StepMatches < RequestHandler
|
7
|
+
def execute(name_to_match, name_to_report)
|
8
|
+
@name_to_match, @name_to_report = name_to_match, name_to_report
|
9
|
+
request_params = {
|
10
|
+
:name_to_match => name_to_match
|
11
|
+
}
|
12
|
+
super(request_params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def handle_step_matches(params)
|
16
|
+
params.map do |raw_step_match|
|
17
|
+
step_definition = WireStepDefinition.new(@connection, raw_step_match)
|
18
|
+
step_args = raw_step_match['args'].map do |raw_arg|
|
19
|
+
StepArgument.new(raw_arg['val'], raw_arg['pos'])
|
20
|
+
end
|
21
|
+
step_match(step_definition, step_args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def step_match(step_definition, step_args)
|
28
|
+
StepMatch.new(step_definition, @name_to_match, @name_to_report, step_args)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class SnippetText < RequestHandler
|
33
|
+
def execute(step_keyword, step_name, multiline_arg_class_name)
|
34
|
+
request_params = {
|
35
|
+
:step_keyword => step_keyword,
|
36
|
+
:step_name => step_name,
|
37
|
+
:multiline_arg_class => multiline_arg_class_name
|
38
|
+
}
|
39
|
+
super(request_params)
|
40
|
+
end
|
41
|
+
|
42
|
+
def handle_snippet_text(text)
|
43
|
+
text
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
class Invoke < RequestHandler
|
48
|
+
def execute(step_definition_id, args)
|
49
|
+
request_params = {
|
50
|
+
:id => step_definition_id,
|
51
|
+
:args => args
|
52
|
+
}
|
53
|
+
super(request_params)
|
54
|
+
end
|
55
|
+
|
56
|
+
def handle_success(params)
|
57
|
+
end
|
58
|
+
|
59
|
+
def handle_pending(message)
|
60
|
+
raise Pending, message || "TODO"
|
61
|
+
end
|
62
|
+
|
63
|
+
def handle_diff(tables)
|
64
|
+
table1 = Ast::Table.new(tables[0])
|
65
|
+
table2 = Ast::Table.new(tables[1])
|
66
|
+
begin
|
67
|
+
table1.diff!(table2)
|
68
|
+
rescue Cucumber::Ast::Table::Different
|
69
|
+
@connection.diff_failed
|
70
|
+
end
|
71
|
+
@connection.diff_ok
|
72
|
+
end
|
73
|
+
|
74
|
+
def handle_step_failed(params)
|
75
|
+
handle_fail(params)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class DiffFailed < RequestHandler
|
80
|
+
def handle_success(params)
|
81
|
+
end
|
82
|
+
|
83
|
+
def handle_step_failed(params)
|
84
|
+
handle_fail(params)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
class DiffOk < RequestHandler
|
89
|
+
def handle_success(params)
|
90
|
+
end
|
91
|
+
|
92
|
+
def handle_step_failed(params)
|
93
|
+
handle_fail(params)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class BeginScenario < RequestHandler
|
98
|
+
def execute(scenario)
|
99
|
+
super(nil) # not passing the scenario yet
|
100
|
+
end
|
101
|
+
|
102
|
+
def handle_success(params)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
class EndScenario < RequestHandler
|
107
|
+
def handle_success(params)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -21,6 +21,7 @@ module Cucumber
|
|
21
21
|
before(:each) do
|
22
22
|
@out = StringIO.new
|
23
23
|
@formatter = Html.new(step_mother, @out, {})
|
24
|
+
step_mother.visitor = @formatter
|
24
25
|
end
|
25
26
|
|
26
27
|
it "should not raise an error when visiting a blank feature name" do
|
@@ -205,6 +206,19 @@ module Cucumber
|
|
205
206
|
it { @doc.should_not have_css_node('.feature .scenario .step.failed', //) }
|
206
207
|
it { @doc.should have_css_node('.feature .scenario .step.undefined', /yay/) }
|
207
208
|
end
|
209
|
+
|
210
|
+
describe "with a step that embeds a snapshot" do
|
211
|
+
define_steps do
|
212
|
+
Given(/snap/) { embed('snapshot.jpeg', 'image/jpeg') }
|
213
|
+
end
|
214
|
+
|
215
|
+
define_feature(<<-FEATURE)
|
216
|
+
Scenario:
|
217
|
+
Given snap
|
218
|
+
FEATURE
|
219
|
+
|
220
|
+
it { @doc.css('.embed img').first.attributes['src'].to_s.should == "snapshot.jpeg" }
|
221
|
+
end
|
208
222
|
|
209
223
|
end
|
210
224
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
require 'cucumber/wire_support/wire_language'
|
3
|
+
require 'tempfile'
|
4
|
+
|
5
|
+
module Cucumber
|
6
|
+
module WireSupport
|
7
|
+
describe Configuration do
|
8
|
+
it "should read the hostname / port from the file" do
|
9
|
+
wire_file = Tempfile.new('wire')
|
10
|
+
wire_file << %q{
|
11
|
+
host: localhost
|
12
|
+
port: 54321
|
13
|
+
}
|
14
|
+
wire_file.close
|
15
|
+
config = Configuration.new(wire_file.path)
|
16
|
+
config.host.should == 'localhost'
|
17
|
+
config.port.should == 54321
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should read the timeout for a specific message" do
|
21
|
+
wire_file = Tempfile.new('wire')
|
22
|
+
wire_file << %q{
|
23
|
+
host: localhost
|
24
|
+
port: 54321
|
25
|
+
timeout:
|
26
|
+
invoke: 99
|
27
|
+
}
|
28
|
+
wire_file.close
|
29
|
+
config = Configuration.new(wire_file.path)
|
30
|
+
config.timeout(:invoke).should == 99
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|