cucumber-salad 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/cucumber/salad/conversions.rb +1 -1
- data/lib/cucumber/salad/instance_conversions.rb +21 -0
- data/lib/cucumber/salad/node_text.rb +11 -0
- data/lib/cucumber/salad/table/cell_text.rb +9 -0
- data/lib/cucumber/salad/table/mapping.rb +42 -0
- data/lib/cucumber/salad/table/transformations.rb +15 -0
- data/lib/cucumber/salad/table/void_mapping.rb +10 -0
- data/lib/cucumber/salad/table.rb +61 -25
- data/lib/cucumber/salad/version.rb +1 -1
- data/lib/cucumber/salad/widgets/action.rb +9 -0
- data/lib/cucumber/salad/widgets/{text.rb → atom.rb} +2 -2
- data/lib/cucumber/salad/widgets/auto_table.rb +66 -0
- data/lib/cucumber/salad/widgets/base_table.rb +13 -0
- data/lib/cucumber/salad/widgets/form.rb +22 -7
- data/lib/cucumber/salad/widgets/list.rb +3 -5
- data/lib/cucumber/salad/widgets/table.rb +43 -54
- data/lib/cucumber/salad/widgets/widget.rb +24 -15
- data/lib/cucumber/salad/widgets.rb +4 -1
- data/lib/cucumber/salad.rb +6 -0
- metadata +28 -3
@@ -0,0 +1,21 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Salad
|
3
|
+
module InstanceConversions
|
4
|
+
def self.included(base)
|
5
|
+
base.send :include, Cucumber::Salad::Conversions
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_boolean
|
9
|
+
Boolean(self)
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_a
|
13
|
+
List(self)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_time
|
17
|
+
Timeish(self)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Salad
|
3
|
+
class Table
|
4
|
+
class Mapping
|
5
|
+
def initialize(settings = {})
|
6
|
+
self.key = settings[:key]
|
7
|
+
self.value_transformer = transformer(settings[:value_transformer], :pass)
|
8
|
+
self.key_transformer = transformer(settings[:key_transformer], :keyword)
|
9
|
+
end
|
10
|
+
|
11
|
+
def set(instance, row, key, value)
|
12
|
+
row[transform_key(instance, key)] = transform_value(instance, value)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
attr_accessor :key, :value_transformer, :key_transformer
|
18
|
+
|
19
|
+
def transform_key(_, k)
|
20
|
+
key || key_transformer.(k)
|
21
|
+
end
|
22
|
+
|
23
|
+
def transform_value(instance, value)
|
24
|
+
instance.instance_exec(value, &value_transformer)
|
25
|
+
end
|
26
|
+
|
27
|
+
def transformer(set, fallback)
|
28
|
+
case set
|
29
|
+
when Symbol
|
30
|
+
Transformations.send(set)
|
31
|
+
when Proc
|
32
|
+
set
|
33
|
+
when nil
|
34
|
+
Transformations.send(fallback)
|
35
|
+
else
|
36
|
+
raise ArgumentError, "can't convert #{set.inspect} to transformer"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/cucumber/salad/table.rb
CHANGED
@@ -7,39 +7,70 @@ module Cucumber
|
|
7
7
|
include Conversions
|
8
8
|
|
9
9
|
class << self
|
10
|
-
def
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
def Array(table)
|
11
|
+
new(table).to_a
|
12
|
+
end
|
13
|
+
|
14
|
+
def Hash(table)
|
15
|
+
new(table).to_h
|
15
16
|
end
|
16
17
|
|
17
18
|
def map(name, options = {}, &block)
|
18
|
-
|
19
|
-
|
19
|
+
case name
|
20
|
+
when :*
|
21
|
+
set_default_mapping options, &block
|
22
|
+
else
|
23
|
+
set_mapping name, options, &block
|
24
|
+
end
|
20
25
|
end
|
21
26
|
|
22
|
-
def
|
23
|
-
@
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
+
def mappings
|
28
|
+
@mappings ||= Hash.
|
29
|
+
new { |h, k| h[k] = Mapping.new }.
|
30
|
+
merge(with_parent_mappings)
|
31
|
+
end
|
32
|
+
|
33
|
+
def skip(name)
|
34
|
+
case name
|
35
|
+
when :*
|
36
|
+
set_default_mapping VoidMapping
|
37
|
+
else
|
38
|
+
raise ArgumentError, "can't convert #{name.inspect} to name"
|
39
|
+
end
|
27
40
|
end
|
28
41
|
|
29
42
|
private
|
30
43
|
|
31
|
-
def
|
32
|
-
|
44
|
+
def set_default_mapping(options, &block)
|
45
|
+
case options
|
46
|
+
when Hash
|
47
|
+
@mappings = Hash.
|
48
|
+
new { |h, k|
|
49
|
+
h[k] = Mapping.new(key_transformer: options[:to],
|
50
|
+
value_transformer: block) }.
|
51
|
+
merge(mappings)
|
52
|
+
when Class
|
53
|
+
@mappings = Hash.new { |h, k| h[k] = options.new }.merge(mappings)
|
54
|
+
else
|
55
|
+
raise ArgumentError, "can't convert #{options.inspect} to mapping"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def set_mapping(name, options, &block)
|
60
|
+
mappings[name] = Mapping.
|
61
|
+
new(key: options[:to], value_transformer: block)
|
62
|
+
end
|
33
63
|
|
34
|
-
|
35
|
-
|
64
|
+
def with_parent_mappings
|
65
|
+
if superclass.respond_to?(:mappings)
|
66
|
+
superclass.send(:mappings).dup
|
36
67
|
else
|
37
|
-
|
68
|
+
{}
|
38
69
|
end
|
39
70
|
end
|
40
71
|
end
|
41
72
|
|
42
|
-
def_delegators 'self.class', :
|
73
|
+
def_delegators 'self.class', :mappings
|
43
74
|
|
44
75
|
def initialize(table)
|
45
76
|
self.table = table
|
@@ -53,20 +84,25 @@ module Cucumber
|
|
53
84
|
@rows ||= table.hashes.map { |h| new_row(h) }
|
54
85
|
end
|
55
86
|
|
87
|
+
def single_row
|
88
|
+
@single_row ||= new_row(table.rows_hash)
|
89
|
+
end
|
90
|
+
|
91
|
+
alias_method :to_a, :rows
|
92
|
+
alias_method :to_h, :single_row
|
93
|
+
|
56
94
|
private
|
57
95
|
|
58
96
|
attr_accessor :table
|
59
97
|
|
60
|
-
def key_for(header)
|
61
|
-
header_mappings[header]
|
62
|
-
end
|
63
|
-
|
64
98
|
def new_row(hash)
|
65
|
-
hash.each_with_object({}) { |(k, v), h|
|
99
|
+
hash.each_with_object({}) { |(k, v), h|
|
100
|
+
mapping_for(k).set(self, h, k, CellText.new(v))
|
101
|
+
}
|
66
102
|
end
|
67
103
|
|
68
|
-
def
|
69
|
-
|
104
|
+
def mapping_for(header)
|
105
|
+
mappings[header]
|
70
106
|
end
|
71
107
|
end
|
72
108
|
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module Cucumber
|
2
|
+
module Salad
|
3
|
+
module Widgets
|
4
|
+
class AutoTable < BaseTable
|
5
|
+
protected
|
6
|
+
|
7
|
+
def ensure_table_loaded
|
8
|
+
root.find(data_row_selector)
|
9
|
+
rescue Capybara::Ambiguous
|
10
|
+
end
|
11
|
+
|
12
|
+
private
|
13
|
+
|
14
|
+
def data_cell_selector
|
15
|
+
'td'
|
16
|
+
end
|
17
|
+
|
18
|
+
def data_row(node)
|
19
|
+
Row.new(root: node, cell_selector: data_cell_selector)
|
20
|
+
end
|
21
|
+
|
22
|
+
def data_row_selector
|
23
|
+
'tbody tr'
|
24
|
+
end
|
25
|
+
|
26
|
+
def data_rows
|
27
|
+
@data_rows ||= root.all(data_row_selector).map { |n| data_row(n) }
|
28
|
+
end
|
29
|
+
|
30
|
+
def header_selector
|
31
|
+
'thead th'
|
32
|
+
end
|
33
|
+
|
34
|
+
def headers
|
35
|
+
@headers ||= root.all(header_selector).map { |n| node_text(n).downcase }
|
36
|
+
end
|
37
|
+
|
38
|
+
def values
|
39
|
+
@values ||= data_rows.map(&:values)
|
40
|
+
end
|
41
|
+
|
42
|
+
class Row < Widget
|
43
|
+
def initialize(settings)
|
44
|
+
s = settings.dup
|
45
|
+
|
46
|
+
self.cell_selector = s.delete(:cell_selector)
|
47
|
+
|
48
|
+
super s
|
49
|
+
end
|
50
|
+
|
51
|
+
def values
|
52
|
+
root.all(cell_selector).map { |n| node_text(n) }
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
attr_accessor :cell_selector
|
58
|
+
|
59
|
+
def node_text(node)
|
60
|
+
NodeText.new(node)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -2,9 +2,15 @@ module Cucumber
|
|
2
2
|
module Salad
|
3
3
|
module Widgets
|
4
4
|
class Form < Widget
|
5
|
+
def self.default_locator(type = nil, &block)
|
6
|
+
alias_method :name_to_locator, type if type
|
7
|
+
|
8
|
+
define_method :name_to_locator, &block if block
|
9
|
+
end
|
10
|
+
|
5
11
|
def self.check_box(name, label = nil)
|
6
12
|
define_method "#{name}=" do |val|
|
7
|
-
l = label ||
|
13
|
+
l = label || name_to_locator(name)
|
8
14
|
|
9
15
|
if val
|
10
16
|
root.check l
|
@@ -19,7 +25,7 @@ module Cucumber
|
|
19
25
|
label, = args
|
20
26
|
|
21
27
|
define_method "#{name}=" do |val|
|
22
|
-
l = label ||
|
28
|
+
l = label || name_to_locator(name)
|
23
29
|
w = opts.fetch(:writer) { ->(v) { v } }
|
24
30
|
|
25
31
|
root.select w.(val).to_s, from: l
|
@@ -32,14 +38,19 @@ module Cucumber
|
|
32
38
|
|
33
39
|
def self.text(name, label = nil)
|
34
40
|
define_method "#{name}=" do |val|
|
35
|
-
l = label ||
|
41
|
+
l = label || name_to_locator(name)
|
36
42
|
|
37
43
|
root.fill_in l, with: val.to_s
|
38
44
|
end
|
39
45
|
end
|
40
46
|
|
41
|
-
def initialize(
|
42
|
-
|
47
|
+
def initialize(settings = {})
|
48
|
+
s = settings.dup
|
49
|
+
data = s.delete(:data) || {}
|
50
|
+
|
51
|
+
super s
|
52
|
+
|
53
|
+
fill_all data
|
43
54
|
|
44
55
|
if block_given?
|
45
56
|
yield self
|
@@ -57,16 +68,20 @@ module Cucumber
|
|
57
68
|
end
|
58
69
|
|
59
70
|
def submit
|
60
|
-
root.find('[
|
71
|
+
root.find('[type = "submit"]').click
|
61
72
|
|
62
73
|
self
|
63
74
|
end
|
64
75
|
|
65
76
|
private
|
66
77
|
|
67
|
-
def
|
78
|
+
def label(name)
|
68
79
|
name.to_s.humanize
|
69
80
|
end
|
81
|
+
|
82
|
+
def name_to_locator(name)
|
83
|
+
label(name)
|
84
|
+
end
|
70
85
|
end
|
71
86
|
end
|
72
87
|
end
|
@@ -2,13 +2,11 @@ module Cucumber
|
|
2
2
|
module Salad
|
3
3
|
module Widgets
|
4
4
|
class List < Widget
|
5
|
-
DEFAULT_TYPE =
|
6
|
-
|
7
|
-
extend Forwardable
|
5
|
+
DEFAULT_TYPE = Atom
|
8
6
|
|
9
7
|
include Enumerable
|
10
8
|
|
11
|
-
def_delegators :items, :size, :include?, :each, :empty
|
9
|
+
def_delegators :items, :size, :include?, :each, :empty?, :first
|
12
10
|
|
13
11
|
def self.item(selector, type = DEFAULT_TYPE, &item_for)
|
14
12
|
define_method :item_selector do
|
@@ -19,7 +17,7 @@ module Cucumber
|
|
19
17
|
define_method :item_for, &item_for
|
20
18
|
else
|
21
19
|
define_method :item_factory do
|
22
|
-
|
20
|
+
type
|
23
21
|
end
|
24
22
|
end
|
25
23
|
end
|
@@ -1,79 +1,68 @@
|
|
1
1
|
module Cucumber
|
2
2
|
module Salad
|
3
3
|
module Widgets
|
4
|
-
class Table <
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
class Table < BaseTable
|
5
|
+
class ColumnDefinition
|
6
|
+
attr_reader :header
|
7
|
+
|
8
|
+
def initialize(selector, header, transform)
|
9
|
+
self.selector = selector
|
10
|
+
self.header = header
|
11
|
+
self.transform = transform
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
+
def ensure_loaded(container)
|
15
|
+
container.find(selector)
|
16
|
+
rescue Capybara::Ambiguous
|
17
|
+
end
|
14
18
|
|
15
|
-
|
16
|
-
|
17
|
-
|
19
|
+
def values(container)
|
20
|
+
container.all(selector).map { |n| transform.(node_text(n)).to_s }
|
21
|
+
end
|
18
22
|
|
19
|
-
|
20
|
-
'thead th'
|
21
|
-
end
|
23
|
+
private
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
25
|
+
attr_accessor :selector
|
26
|
+
attr_writer :header, :transform
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
def node_text(node)
|
29
|
+
NodeText.new(node)
|
30
|
+
end
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
def transform
|
33
|
+
@transform ||= ->(v) { v }
|
34
|
+
end
|
33
35
|
end
|
34
36
|
|
35
|
-
|
36
|
-
|
37
|
+
class << self
|
38
|
+
attr_accessor :column_selector, :header_selector
|
37
39
|
end
|
38
40
|
|
39
|
-
def
|
40
|
-
|
41
|
+
def self.column(selector, header = nil, &transform)
|
42
|
+
column_definitions << ColumnDefinition.new(selector, header, transform)
|
41
43
|
end
|
42
44
|
|
43
|
-
def
|
44
|
-
|
45
|
+
def self.column_definitions
|
46
|
+
@column_definitions ||= []
|
45
47
|
end
|
46
48
|
|
47
|
-
|
48
|
-
def self.cell(name, selector, type = Text, &block)
|
49
|
-
widget name, selector, type, &block
|
49
|
+
protected
|
50
50
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
def self.cells
|
55
|
-
@cells ||= []
|
56
|
-
end
|
57
|
-
|
58
|
-
def to_a
|
59
|
-
declared_row || generated_row
|
60
|
-
end
|
61
|
-
|
62
|
-
protected
|
51
|
+
def ensure_table_loaded
|
52
|
+
column_definitions.first.ensure_loaded(self)
|
53
|
+
end
|
63
54
|
|
64
|
-
|
65
|
-
'td'
|
66
|
-
end
|
55
|
+
private
|
67
56
|
|
68
|
-
|
69
|
-
|
57
|
+
def_delegators 'self.class', :column_selector, :column_definitions,
|
58
|
+
:header_selector
|
70
59
|
|
71
|
-
|
72
|
-
|
60
|
+
def headers
|
61
|
+
@headers ||= column_definitions.map(&:header)
|
62
|
+
end
|
73
63
|
|
74
|
-
|
75
|
-
|
76
|
-
end
|
64
|
+
def values
|
65
|
+
@values ||= column_definitions.map { |d| d.values(root) }.transpose
|
77
66
|
end
|
78
67
|
end
|
79
68
|
end
|
@@ -2,8 +2,20 @@ module Cucumber
|
|
2
2
|
module Salad
|
3
3
|
module Widgets
|
4
4
|
class Widget
|
5
|
+
extend Forwardable
|
6
|
+
|
5
7
|
include Salad::Conversions
|
6
8
|
|
9
|
+
def self.action(name, selector, options = {})
|
10
|
+
wname = "#{name}_action"
|
11
|
+
|
12
|
+
widget wname, selector, type: options[:type] || Action
|
13
|
+
|
14
|
+
define_method name do
|
15
|
+
send(wname).click
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
7
19
|
def self.root(selector)
|
8
20
|
define_method :default_root_selector do
|
9
21
|
selector
|
@@ -12,14 +24,13 @@ module Cucumber
|
|
12
24
|
private :default_root_selector
|
13
25
|
end
|
14
26
|
|
15
|
-
def self.widget(name, selector,
|
16
|
-
|
17
|
-
|
18
|
-
else
|
19
|
-
->{ lookup(type).new(root: root.find(selector)) }
|
20
|
-
end
|
27
|
+
def self.widget(name, selector, options = {}, &block)
|
28
|
+
type = options.fetch(:type, Atom)
|
29
|
+
t = block_given? ? Class.new(type, &block) : type
|
21
30
|
|
22
|
-
define_method name
|
31
|
+
define_method name do
|
32
|
+
t.new(root: root.find(selector))
|
33
|
+
end
|
23
34
|
end
|
24
35
|
|
25
36
|
def initialize(settings = {})
|
@@ -33,6 +44,12 @@ module Cucumber
|
|
33
44
|
Nokogiri::XML(xml, &:noblanks).to_xhtml
|
34
45
|
end
|
35
46
|
|
47
|
+
protected
|
48
|
+
|
49
|
+
def node_text(node)
|
50
|
+
NodeText.new(node)
|
51
|
+
end
|
52
|
+
|
36
53
|
private
|
37
54
|
|
38
55
|
attr_writer :root_selector
|
@@ -42,14 +59,6 @@ module Cucumber
|
|
42
59
|
"#{self.class.name}: default root selector undefined"
|
43
60
|
end
|
44
61
|
|
45
|
-
def lookup(type)
|
46
|
-
if Class === type
|
47
|
-
type
|
48
|
-
else
|
49
|
-
self.class.const_get(type.to_s.classify)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
62
|
def page
|
54
63
|
Capybara.current_session
|
55
64
|
end
|
@@ -1,3 +1,6 @@
|
|
1
1
|
require 'cucumber/salad/widgets/widget'
|
2
|
-
require 'cucumber/salad/widgets/
|
2
|
+
require 'cucumber/salad/widgets/atom'
|
3
3
|
require 'cucumber/salad/widgets/list'
|
4
|
+
require 'cucumber/salad/widgets/base_table'
|
5
|
+
require 'cucumber/salad/widgets/auto_table'
|
6
|
+
require 'cucumber/salad/widgets/table'
|
data/lib/cucumber/salad.rb
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
require 'chronic'
|
2
2
|
|
3
3
|
require 'cucumber/salad/conversions'
|
4
|
+
require 'cucumber/salad/instance_conversions'
|
5
|
+
require 'cucumber/salad/node_text'
|
4
6
|
require 'cucumber/salad/widgets'
|
5
7
|
require 'cucumber/salad/table'
|
8
|
+
require 'cucumber/salad/table/mapping'
|
9
|
+
require 'cucumber/salad/table/void_mapping'
|
10
|
+
require 'cucumber/salad/table/transformations'
|
11
|
+
require 'cucumber/salad/table/cell_text'
|
metadata
CHANGED
@@ -2,14 +2,14 @@
|
|
2
2
|
name: cucumber-salad
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.2.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- David Leal
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-
|
12
|
+
date: 2013-05-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -43,6 +43,22 @@ dependencies:
|
|
43
43
|
- !ruby/object:Gem::Version
|
44
44
|
version: '0'
|
45
45
|
none: false
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ! '>='
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
version: '2.0'
|
52
|
+
none: false
|
53
|
+
name: capybara
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ! '>='
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.0'
|
61
|
+
none: false
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
63
|
version_requirements: !ruby/object:Gem::Requirement
|
48
64
|
requirements:
|
@@ -68,13 +84,22 @@ extra_rdoc_files: []
|
|
68
84
|
files:
|
69
85
|
- lib/cucumber/salad.rb
|
70
86
|
- lib/cucumber/salad/conversions.rb
|
87
|
+
- lib/cucumber/salad/instance_conversions.rb
|
88
|
+
- lib/cucumber/salad/node_text.rb
|
71
89
|
- lib/cucumber/salad/table.rb
|
90
|
+
- lib/cucumber/salad/table/cell_text.rb
|
91
|
+
- lib/cucumber/salad/table/mapping.rb
|
92
|
+
- lib/cucumber/salad/table/transformations.rb
|
93
|
+
- lib/cucumber/salad/table/void_mapping.rb
|
72
94
|
- lib/cucumber/salad/version.rb
|
73
95
|
- lib/cucumber/salad/widgets.rb
|
96
|
+
- lib/cucumber/salad/widgets/action.rb
|
97
|
+
- lib/cucumber/salad/widgets/atom.rb
|
98
|
+
- lib/cucumber/salad/widgets/auto_table.rb
|
99
|
+
- lib/cucumber/salad/widgets/base_table.rb
|
74
100
|
- lib/cucumber/salad/widgets/form.rb
|
75
101
|
- lib/cucumber/salad/widgets/list.rb
|
76
102
|
- lib/cucumber/salad/widgets/table.rb
|
77
|
-
- lib/cucumber/salad/widgets/text.rb
|
78
103
|
- lib/cucumber/salad/widgets/widget.rb
|
79
104
|
homepage: https://github.com/mojotech/cucumber-salad
|
80
105
|
licenses: []
|