cucumber-salad 0.2.2 → 0.3.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,9 @@
1
+ require 'cucumber/salad'
2
+
3
+ World(Cucumber::Salad::DSL)
4
+
5
+ module Salad
6
+ include Cucumber::Salad::Widgets
7
+
8
+ DSL = Cucumber::Salad::DSL
9
+ end
@@ -0,0 +1,36 @@
1
+ module Cucumber
2
+ module Salad
3
+ module DSL
4
+ attr_writer :widget_lookup_scope
5
+
6
+ # @return [Widgets::Document] the current document with the class of the
7
+ # current object set as the widget lookup scope.
8
+ def document
9
+ Widgets::Document.new(widget_lookup_scope: widget_lookup_scope)
10
+ end
11
+
12
+ # @return [Boolean] Whether one or more widgets exist in the current
13
+ # document.
14
+ def has_widget?(name)
15
+ document.has_widget?(name)
16
+ end
17
+
18
+ # Returns a widget instance for the given name.
19
+ #
20
+ # @param name [String, Symbol]
21
+ def widget(name, options = {})
22
+ document.widget(name, options)
23
+ end
24
+
25
+ def widget_lookup_scope
26
+ @widget_lookup_scope ||= default_widget_lookup_scope
27
+ end
28
+
29
+ private
30
+
31
+ def default_widget_lookup_scope
32
+ Module === self ? self : self.class
33
+ end
34
+ end
35
+ end
36
+ end
@@ -1,5 +1,5 @@
1
1
  module Cucumber
2
2
  module Salad
3
- VERSION = "0.2.2"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
@@ -0,0 +1,25 @@
1
+ module Cucumber
2
+ module Salad
3
+ module WidgetContainer
4
+ def has_widget?(name)
5
+ widget_class(name).has_instance?(root)
6
+ end
7
+
8
+ def widget(name, options = {})
9
+ widget_class(name).in_node(root, options)
10
+ end
11
+
12
+ private
13
+
14
+ attr_writer :widget_lookup_scope
15
+
16
+ def widget_class(name)
17
+ WidgetName.new(name).to_class(widget_lookup_scope)
18
+ end
19
+
20
+ def widget_lookup_scope
21
+ @widget_lookup_scope || self.class
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,59 @@
1
+ module Cucumber
2
+ module Salad
3
+ # The name of a widget in a format-independent representation.
4
+ class WidgetName < String
5
+ CAMEL_CASE_FORMAT = /\A([A-Z][a-z]*)+\Z/
6
+ SNAKE_CASE_FORMAT = /\A\w+\Z/
7
+
8
+ # Constructs the widget name.
9
+ #
10
+ # @param name [String, Symbol] the name of the widget in primitive form
11
+ def initialize(name)
12
+ @name = name
13
+ @canonical = canonical(@name)
14
+ end
15
+
16
+ # Returns the class for this widget name, in the given scope.
17
+ def to_class(scope = Object)
18
+ const = scope.const_get(@canonical)
19
+
20
+ raise TypeError, "`#{@canonical}' is not a widget in this scope" \
21
+ unless const < Widgets::Widget
22
+
23
+ const
24
+ rescue NameError
25
+ raise UnknownWidgetError,
26
+ "couldn't find `#{@name}' widget in this scope"
27
+ end
28
+
29
+ def to_sym
30
+ @canonical.to_sym
31
+ end
32
+
33
+ private
34
+
35
+ def canonical(name)
36
+ str = name.to_s
37
+
38
+ case str
39
+ when SNAKE_CASE_FORMAT
40
+ camel_case_from_snake_case(str)
41
+ when CAMEL_CASE_FORMAT
42
+ str
43
+ else
44
+ raise ArgumentError, "can't convert `#{str.inspect}' to canonical form"
45
+ end
46
+ end
47
+
48
+ def camel_case_from_snake_case(name)
49
+ capitalize_word = ->(word) { word[0].upcase + word[1..-1] }
50
+ word_separator = '_'
51
+
52
+ name
53
+ .split(word_separator)
54
+ .map(&capitalize_word)
55
+ .join
56
+ end
57
+ end
58
+ end
59
+ end
@@ -2,6 +2,13 @@ module Cucumber
2
2
  module Salad
3
3
  module Widgets
4
4
  class AutoTable < BaseTable
5
+
6
+ # don't include footer in to_table, because footer column configuration is very
7
+ # often different from the headers & values.
8
+ def footers
9
+ @footers ||= root.all(footer_selector).map { |n| node_text(n) }
10
+ end
11
+
5
12
  protected
6
13
 
7
14
  def ensure_table_loaded
@@ -35,6 +42,10 @@ module Cucumber
35
42
  @headers ||= root.all(header_selector).map { |n| node_text(n).downcase }
36
43
  end
37
44
 
45
+ def footer_selector
46
+ 'tfoot td'
47
+ end
48
+
38
49
  def values
39
50
  @values ||= data_rows.map(&:values)
40
51
  end
@@ -0,0 +1,18 @@
1
+ module Cucumber
2
+ module Salad
3
+ module Widgets
4
+ class Document
5
+ include WidgetContainer
6
+
7
+ def initialize(options)
8
+ self.widget_lookup_scope =
9
+ options.delete(:widget_lookup_scope) or raise "No scope given"
10
+ end
11
+
12
+ def root
13
+ Capybara.current_session
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -20,7 +20,7 @@ module Cucumber
20
20
  end
21
21
  end
22
22
 
23
- def self.select_box(name, *args)
23
+ def self.select(name, *args)
24
24
  opts = args.extract_options!
25
25
  label, = args
26
26
 
@@ -36,7 +36,7 @@ module Cucumber
36
36
  new.fill_all(attrs).submit
37
37
  end
38
38
 
39
- def self.text(name, label = nil)
39
+ def self.text_field(name, label = nil)
40
40
  define_method "#{name}=" do |val|
41
41
  l = label || name_to_locator(name)
42
42
 
@@ -73,6 +73,16 @@ module Cucumber
73
73
  self
74
74
  end
75
75
 
76
+ # Submit form with +attrs+.
77
+ #
78
+ # @param attrs [Hash] the form fields and their values
79
+ #
80
+ # @return self
81
+ def submit_with(attrs)
82
+ fill_all attrs
83
+ submit
84
+ end
85
+
76
86
  private
77
87
 
78
88
  def label(name)
@@ -2,11 +2,11 @@ module Cucumber
2
2
  module Salad
3
3
  module Widgets
4
4
  class List < Widget
5
- DEFAULT_TYPE = Atom
5
+ DEFAULT_TYPE = Widget
6
6
 
7
7
  include Enumerable
8
8
 
9
- def_delegators :items, :size, :include?, :each, :empty?, :first
9
+ def_delegators :items, :size, :include?, :each, :empty?, :first, :last
10
10
 
11
11
  def self.item(selector, type = DEFAULT_TYPE, &item_for)
12
12
  define_method :item_selector do
@@ -5,36 +5,46 @@ module Cucumber
5
5
  extend Forwardable
6
6
 
7
7
  include Salad::Conversions
8
+ include WidgetContainer
8
9
 
9
- def self.action(name, selector, options = {})
10
- wname = "#{name}_action"
11
-
12
- widget wname, selector, type: options[:type] || Action
10
+ def self.action(name, selector, parent = Widget)
11
+ widget name, selector, parent
13
12
 
14
13
  define_method name do
15
- send(wname).click
14
+ widget(name).click
16
15
  end
17
16
  end
18
17
 
18
+ def self.has_instance?(parent_node)
19
+ parent_node.has_selector?(selector)
20
+ end
21
+
22
+ def self.in_node(node, options = {})
23
+ new(options.merge(root: node.find(selector)))
24
+ end
25
+
19
26
  def self.root(selector)
20
- define_method :default_root_selector do
21
- selector
22
- end
27
+ @selector = selector
28
+ end
23
29
 
24
- private :default_root_selector
30
+ def self.selector
31
+ @selector
25
32
  end
26
33
 
27
- def self.widget(name, selector, options = {}, &block)
28
- type = options.fetch(:type, Atom)
29
- t = block_given? ? Class.new(type, &block) : type
34
+ def self.widget(name, selector, parent = Widget, &block)
35
+ type = Class.new(parent) {
36
+ root selector
30
37
 
31
- define_method name do
32
- t.new(root: root.find(selector))
33
- end
38
+ instance_eval(&block) if block
39
+ }
40
+
41
+ const_set(Salad::WidgetName.new(name).to_sym, type)
34
42
  end
35
43
 
44
+ def_delegators :root, :click
45
+
36
46
  def initialize(settings = {})
37
- self.root = settings[:root] if settings[:root]
47
+ self.root = settings.fetch(:root)
38
48
  end
39
49
 
40
50
  def inspect
@@ -44,6 +54,12 @@ module Cucumber
44
54
  Nokogiri::XML(xml, &:noblanks).to_xhtml
45
55
  end
46
56
 
57
+ def to_s
58
+ node_text(root)
59
+ end
60
+
61
+ alias_method :w, :widget
62
+
47
63
  protected
48
64
 
49
65
  def node_text(node)
@@ -52,37 +68,11 @@ module Cucumber
52
68
 
53
69
  private
54
70
 
55
- attr_writer :root_selector
56
-
57
- def default_root_selector
58
- raise NotImplementedError,
59
- "#{self.class.name}: default root selector undefined"
60
- end
71
+ attr_accessor :root
61
72
 
62
73
  def page
63
74
  Capybara.current_session
64
75
  end
65
-
66
- def root
67
- @root || page.find(root_selector)
68
- end
69
-
70
- def root=(selector_or_node)
71
- case selector_or_node
72
- when String
73
- self.root_selector = selector_or_node
74
- when Capybara::Node::Element, Capybara::Node::Simple
75
- @root = selector_or_node
76
- else
77
- msg = "can't convert #{selector_or_node.inspect} to root node"
78
-
79
- raise ArgumentError, msg
80
- end
81
- end
82
-
83
- def root_selector
84
- @root_selector || default_root_selector
85
- end
86
76
  end
87
77
  end
88
78
  end
@@ -1,6 +1,4 @@
1
1
  require 'cucumber/salad/widgets/widget'
2
- require 'cucumber/salad/widgets/atom'
3
- require 'cucumber/salad/widgets/action'
4
2
  require 'cucumber/salad/widgets/list'
5
3
  require 'cucumber/salad/widgets/base_table'
6
4
  require 'cucumber/salad/widgets/auto_table'
@@ -1,11 +1,17 @@
1
1
  require 'chronic'
2
2
 
3
+ require 'cucumber/salad/widget_container'
3
4
  require 'cucumber/salad/conversions'
4
5
  require 'cucumber/salad/instance_conversions'
5
6
  require 'cucumber/salad/node_text'
7
+ require 'cucumber/salad/widget_name'
6
8
  require 'cucumber/salad/widgets'
7
9
  require 'cucumber/salad/table'
8
10
  require 'cucumber/salad/table/mapping'
9
11
  require 'cucumber/salad/table/void_mapping'
10
12
  require 'cucumber/salad/table/transformations'
11
13
  require 'cucumber/salad/table/cell_text'
14
+ require 'cucumber/salad/widgets/document'
15
+ require 'cucumber/salad/dsl'
16
+
17
+ class UnknownWidgetError < StandardError; end
metadata CHANGED
@@ -2,14 +2,14 @@
2
2
  name: cucumber-salad
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.2
5
+ version: 0.3.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-05-27 00:00:00.000000000 Z
12
+ date: 2013-07-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  version_requirements: !ruby/object:Gem::Requirement
@@ -75,6 +75,22 @@ dependencies:
75
75
  - !ruby/object:Gem::Version
76
76
  version: 2.11.0
77
77
  none: false
78
+ - !ruby/object:Gem::Dependency
79
+ version_requirements: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ none: false
85
+ name: sinatra
86
+ type: :development
87
+ prerelease: false
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: '0'
93
+ none: false
78
94
  description: See https://github.com/mojotech/cucumber-salad/README.md
79
95
  email:
80
96
  - dleal@mojotech.com
@@ -83,7 +99,9 @@ extensions: []
83
99
  extra_rdoc_files: []
84
100
  files:
85
101
  - lib/cucumber/salad.rb
102
+ - lib/cucumber/salad/boot.rb
86
103
  - lib/cucumber/salad/conversions.rb
104
+ - lib/cucumber/salad/dsl.rb
87
105
  - lib/cucumber/salad/instance_conversions.rb
88
106
  - lib/cucumber/salad/node_text.rb
89
107
  - lib/cucumber/salad/table.rb
@@ -92,11 +110,13 @@ files:
92
110
  - lib/cucumber/salad/table/transformations.rb
93
111
  - lib/cucumber/salad/table/void_mapping.rb
94
112
  - lib/cucumber/salad/version.rb
113
+ - lib/cucumber/salad/widget_container.rb
114
+ - lib/cucumber/salad/widget_name.rb
95
115
  - lib/cucumber/salad/widgets.rb
96
- - lib/cucumber/salad/widgets/action.rb
97
116
  - lib/cucumber/salad/widgets/atom.rb
98
117
  - lib/cucumber/salad/widgets/auto_table.rb
99
118
  - lib/cucumber/salad/widgets/base_table.rb
119
+ - lib/cucumber/salad/widgets/document.rb
100
120
  - lib/cucumber/salad/widgets/form.rb
101
121
  - lib/cucumber/salad/widgets/list.rb
102
122
  - lib/cucumber/salad/widgets/table.rb
@@ -1,9 +0,0 @@
1
- module Cucumber
2
- module Salad
3
- module Widgets
4
- class Action < Atom
5
- def_delegators :root, :click
6
- end
7
- end
8
- end
9
- end