cucumber-salad 0.1.0

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.
@@ -0,0 +1,31 @@
1
+ module Cucumber
2
+ module Salad
3
+ module Conversions
4
+ def Boolean(val)
5
+ case val
6
+ when 'yes', 'true', true
7
+ true
8
+ when 'no', 'false', false, nil
9
+ false
10
+ else
11
+ raise ArgumentError, "can't convert #{val.inspect} to boolean"
12
+ end
13
+ end
14
+
15
+ def List(valstr, &block)
16
+ vs = valstr.strip.split(/\s*,\s*/)
17
+
18
+ block ? vs.map(&block) : vs
19
+ end
20
+
21
+ def Timeish(val)
22
+ raise ArgumentError, "can't convert nil to Timeish" if val.nil?
23
+
24
+ return val if Date === val || Time === val || DateTime === val
25
+
26
+ Chronic.parse(val) or
27
+ raise ArgumentError, "can't parse #{val.inspect} to Timeish"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,73 @@
1
+ module Cucumber
2
+ module Salad
3
+ class Table
4
+ extend Forwardable
5
+
6
+ include Enumerable
7
+ include Conversions
8
+
9
+ class << self
10
+ def header_mappings
11
+ @header_mappings ||=
12
+ with_parent_mappings(:header) { |h, k|
13
+ h[k] = k.squeeze(' ').strip.gsub(' ', '_').to_sym
14
+ }
15
+ end
16
+
17
+ def map(name, options = {}, &block)
18
+ header_mappings[name.to_s] = options[:to].to_sym if options[:to]
19
+ value_mappings[name.to_s] = block if block_given?
20
+ end
21
+
22
+ def value_mappings
23
+ @value_mappings ||=
24
+ with_parent_mappings(:value) { |h, k|
25
+ h[k] = ->(value) { value }
26
+ }
27
+ end
28
+
29
+ private
30
+
31
+ def with_parent_mappings(name, &init)
32
+ m = "#{name}_mappings"
33
+
34
+ if superclass.respond_to?(m)
35
+ superclass.send(m).dup
36
+ else
37
+ Hash.new(&init)
38
+ end
39
+ end
40
+ end
41
+
42
+ def_delegators 'self.class', :header_mappings, :value_mappings
43
+
44
+ def initialize(table)
45
+ self.table = table
46
+ end
47
+
48
+ def each(&block)
49
+ rows.each(&block)
50
+ end
51
+
52
+ def rows
53
+ @rows ||= table.hashes.map { |h| new_row(h) }
54
+ end
55
+
56
+ private
57
+
58
+ attr_accessor :table
59
+
60
+ def key_for(header)
61
+ header_mappings[header]
62
+ end
63
+
64
+ def new_row(hash)
65
+ hash.each_with_object({}) { |(k, v), h| h[key_for(k)] = value_for(k, v) }
66
+ end
67
+
68
+ def value_for(key, value)
69
+ instance_exec(value, &value_mappings[key])
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,5 @@
1
+ module Cucumber
2
+ module Salad
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
@@ -0,0 +1,73 @@
1
+ module Cucumber
2
+ module Salad
3
+ module Widgets
4
+ class Form < Widget
5
+ def self.check_box(name, label = nil)
6
+ define_method "#{name}=" do |val|
7
+ l = label || name_to_label(name)
8
+
9
+ if val
10
+ root.check l
11
+ else
12
+ root.uncheck l
13
+ end
14
+ end
15
+ end
16
+
17
+ def self.select_box(name, *args)
18
+ opts = args.extract_options!
19
+ label, = args
20
+
21
+ define_method "#{name}=" do |val|
22
+ l = label || name_to_label(name)
23
+ w = opts.fetch(:writer) { ->(v) { v } }
24
+
25
+ root.select w.(val).to_s, from: l
26
+ end
27
+ end
28
+
29
+ def self.submit(attrs)
30
+ new.fill_all(attrs).submit
31
+ end
32
+
33
+ def self.text(name, label = nil)
34
+ define_method "#{name}=" do |val|
35
+ l = label || name_to_label(name)
36
+
37
+ root.fill_in l, with: val.to_s
38
+ end
39
+ end
40
+
41
+ def initialize(*super_args)
42
+ super(*super_args)
43
+
44
+ if block_given?
45
+ yield self
46
+
47
+ submit
48
+ end
49
+ end
50
+
51
+ def fill_all(attrs)
52
+ attrs.each do |k, v|
53
+ send "#{k}=", v
54
+ end
55
+
56
+ self
57
+ end
58
+
59
+ def submit
60
+ root.find('[name = "commit"]').click
61
+
62
+ self
63
+ end
64
+
65
+ private
66
+
67
+ def name_to_label(name)
68
+ name.to_s.humanize
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,53 @@
1
+ module Cucumber
2
+ module Salad
3
+ module Widgets
4
+ class List < Widget
5
+ DEFAULT_TYPE = Text
6
+
7
+ extend Forwardable
8
+
9
+ include Enumerable
10
+
11
+ def_delegators :items, :size, :include?, :each, :empty?
12
+
13
+ def self.item(selector, type = DEFAULT_TYPE, &item_for)
14
+ define_method :item_selector do
15
+ @item_selector ||= selector
16
+ end
17
+
18
+ if block_given?
19
+ define_method :item_for, &item_for
20
+ else
21
+ define_method :item_factory do
22
+ lookup(type)
23
+ end
24
+ end
25
+ end
26
+
27
+ def to_table
28
+ items.map { |e| Array(e) }
29
+ end
30
+
31
+ protected
32
+
33
+ attr_writer :item_selector
34
+
35
+ def item_factory
36
+ DEFAULT_TYPE
37
+ end
38
+
39
+ def item_for(node)
40
+ item_factory.new(root: node)
41
+ end
42
+
43
+ def item_selector
44
+ 'li'
45
+ end
46
+
47
+ def items
48
+ root.all(item_selector).map { |node| item_for(node) }
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,81 @@
1
+ module Cucumber
2
+ module Salad
3
+ module Widgets
4
+ class Table < Widget
5
+ def self.row_class
6
+ Row
7
+ end
8
+
9
+ def to_table
10
+ [headers, *rows.map { |r| Array(r) }]
11
+ end
12
+
13
+ private
14
+
15
+ def header_for(node)
16
+ node.text.strip.downcase
17
+ end
18
+
19
+ def header_selector
20
+ 'thead th'
21
+ end
22
+
23
+ def headers
24
+ items(header_selector, :header_for)
25
+ end
26
+
27
+ def items(selector, builder)
28
+ root.all(selector).map { |e| send(builder, e) }
29
+ end
30
+
31
+ def row_factory
32
+ self.class.row_class
33
+ end
34
+
35
+ def row_for(node)
36
+ row_factory.new(root: node)
37
+ end
38
+
39
+ def row_selector
40
+ 'tbody tr'
41
+ end
42
+
43
+ def rows
44
+ items(row_selector, :row_for)
45
+ end
46
+
47
+ class Row < Widget
48
+ def self.cell(name, selector, type = Text, &block)
49
+ widget name, selector, type, &block
50
+
51
+ cells << name
52
+ end
53
+
54
+ def self.cells
55
+ @cells ||= []
56
+ end
57
+
58
+ def to_a
59
+ declared_row || generated_row
60
+ end
61
+
62
+ protected
63
+
64
+ def cell_selector
65
+ 'td'
66
+ end
67
+
68
+ def declared_row
69
+ cells = self.class.cells
70
+
71
+ cells.map { |c| send(c).to_s } if cells.present?
72
+ end
73
+
74
+ def generated_row
75
+ root.all(cell_selector).map { |c| c.text.strip }
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
81
+ end
@@ -0,0 +1,19 @@
1
+ module Cucumber
2
+ module Salad
3
+ module Widgets
4
+ class Text < Widget
5
+ def to_a
6
+ [to_s]
7
+ end
8
+
9
+ def ==(other)
10
+ to_s.downcase == other.to_s.downcase
11
+ end
12
+
13
+ def to_s
14
+ root.text.strip
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,80 @@
1
+ module Cucumber
2
+ module Salad
3
+ module Widgets
4
+ class Widget
5
+ include Salad::Conversions
6
+
7
+ def self.root(selector)
8
+ define_method :default_root_selector do
9
+ selector
10
+ end
11
+
12
+ private :default_root_selector
13
+ end
14
+
15
+ def self.widget(name, selector, type = Text, &block)
16
+ body = if block_given?
17
+ ->{ block.(find(selector)) }
18
+ else
19
+ ->{ lookup(type).new(root: root.find(selector)) }
20
+ end
21
+
22
+ define_method name, &body
23
+ end
24
+
25
+ def initialize(settings = {})
26
+ self.root = settings[:root] if settings[:root]
27
+ end
28
+
29
+ def inspect
30
+ xml = Nokogiri::HTML(page.body).at(root.path).to_xml
31
+
32
+ "<!-- #{self.class.name}: -->\n" <<
33
+ Nokogiri::XML(xml, &:noblanks).to_xhtml
34
+ end
35
+
36
+ private
37
+
38
+ attr_writer :root_selector
39
+
40
+ def default_root_selector
41
+ raise NotImplementedError,
42
+ "#{self.class.name}: default root selector undefined"
43
+ end
44
+
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
+ def page
54
+ Capybara.current_session
55
+ end
56
+
57
+ def root
58
+ @root || page.find(root_selector)
59
+ end
60
+
61
+ def root=(selector_or_node)
62
+ case selector_or_node
63
+ when String
64
+ self.root_selector = selector_or_node
65
+ when Capybara::Node::Element, Capybara::Node::Simple
66
+ @root = selector_or_node
67
+ else
68
+ msg = "can't convert #{selector_or_node.inspect} to root node"
69
+
70
+ raise ArgumentError, msg
71
+ end
72
+ end
73
+
74
+ def root_selector
75
+ @root_selector || default_root_selector
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,3 @@
1
+ require 'cucumber/salad/widgets/widget'
2
+ require 'cucumber/salad/widgets/text'
3
+ require 'cucumber/salad/widgets/list'
@@ -0,0 +1,5 @@
1
+ require 'chronic'
2
+
3
+ require 'cucumber/salad/conversions'
4
+ require 'cucumber/salad/widgets'
5
+ require 'cucumber/salad/table'
metadata ADDED
@@ -0,0 +1,103 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cucumber-salad
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.1.0
6
+ platform: ruby
7
+ authors:
8
+ - David Leal
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-04-20 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ version_requirements: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ none: false
21
+ name: cucumber
22
+ type: :runtime
23
+ prerelease: false
24
+ requirement: !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ! '>='
27
+ - !ruby/object:Gem::Version
28
+ version: '0'
29
+ none: false
30
+ - !ruby/object:Gem::Dependency
31
+ version_requirements: !ruby/object:Gem::Requirement
32
+ requirements:
33
+ - - ! '>='
34
+ - !ruby/object:Gem::Version
35
+ version: '0'
36
+ none: false
37
+ name: chronic
38
+ type: :runtime
39
+ prerelease: false
40
+ requirement: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: '0'
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.11.0
52
+ none: false
53
+ name: rspec
54
+ type: :development
55
+ prerelease: false
56
+ requirement: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ! '>='
59
+ - !ruby/object:Gem::Version
60
+ version: 2.11.0
61
+ none: false
62
+ description: See https://github.com/mojotech/cucumber-salad/README.md
63
+ email:
64
+ - dleal@mojotech.com
65
+ executables: []
66
+ extensions: []
67
+ extra_rdoc_files: []
68
+ files:
69
+ - lib/cucumber/salad.rb
70
+ - lib/cucumber/salad/conversions.rb
71
+ - lib/cucumber/salad/table.rb
72
+ - lib/cucumber/salad/version.rb
73
+ - lib/cucumber/salad/widgets.rb
74
+ - lib/cucumber/salad/widgets/form.rb
75
+ - lib/cucumber/salad/widgets/list.rb
76
+ - lib/cucumber/salad/widgets/table.rb
77
+ - lib/cucumber/salad/widgets/text.rb
78
+ - lib/cucumber/salad/widgets/widget.rb
79
+ homepage: https://github.com/mojotech/cucumber-salad
80
+ licenses: []
81
+ post_install_message:
82
+ rdoc_options: []
83
+ require_paths:
84
+ - lib
85
+ required_ruby_version: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ! '>='
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ none: false
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ none: false
97
+ requirements: []
98
+ rubyforge_project: ! '[none]'
99
+ rubygems_version: 1.8.23
100
+ signing_key:
101
+ specification_version: 3
102
+ summary: A set of helpers to ease writing cucumber features
103
+ test_files: []