cucumber-salad 0.2.2 → 0.3.0

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