cucumber 0.5.1 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|