cucumber-salad 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []