dill 0.5.2 → 0.6.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.
@@ -2,28 +2,16 @@ require 'chronic'
2
2
  require 'nokogiri'
3
3
  require 'capybara'
4
4
 
5
- require 'dill/checkpoint'
6
- require 'dill/widget_class'
7
- require 'dill/widget_checkpoint'
8
- require 'dill/widget_container'
9
5
  require 'dill/conversions'
10
6
  require 'dill/instance_conversions'
11
- require 'dill/node_text'
12
- require 'dill/widget_name'
13
- require 'dill/widget'
14
- require 'dill/list_item'
15
- require 'dill/list'
16
- require 'dill/base_table'
17
- require 'dill/auto_table'
18
- require 'dill/table'
19
- require 'dill/field_group'
20
- require 'dill/form'
21
- require 'dill/document'
7
+ require 'dill/checkpoint'
8
+ require 'dill/widgets'
22
9
  require 'dill/text_table'
23
10
  require 'dill/text_table/mapping'
24
11
  require 'dill/text_table/void_mapping'
25
12
  require 'dill/text_table/transformations'
26
13
  require 'dill/text_table/cell_text'
14
+ require 'dill/capybara'
27
15
  require 'dill/dsl'
28
16
 
29
17
  module Dill
@@ -0,0 +1,7 @@
1
+ Capybara.configure do |config|
2
+ config.match = :one
3
+ config.exact = true
4
+ config.exact_options = true
5
+ config.ignore_hidden_elements = true
6
+ config.visible_text_only = true
7
+ end
@@ -6,14 +6,54 @@ module Dill
6
6
  # which inspired this class.
7
7
  class Checkpoint
8
8
  class ConditionNotMet < StandardError; end
9
- class TimeFrozen < StandardError; end
10
9
 
11
- # @return the configured wait time, in seconds.
12
- attr_reader :wait_time
10
+ class Timer
11
+ class Frozen < StandardError; end
12
+
13
+ def initialize(duration)
14
+ @duration = duration
15
+ end
16
+
17
+ attr_reader :duration
18
+
19
+ def expired?
20
+ duration < elapsed
21
+ end
22
+
23
+ def elapsed
24
+ now - start_time
25
+ end
26
+
27
+ def start
28
+ @start_time = now
29
+ end
30
+
31
+ def tick
32
+ sleep tick_duration
33
+
34
+ raise Frozen, 'time appears to be frozen' if frozen?
35
+ end
36
+
37
+ protected
38
+
39
+ def now
40
+ Time.now
41
+ end
42
+
43
+ attr_reader :start_time
44
+
45
+ def frozen?
46
+ now == start_time
47
+ end
48
+
49
+ def tick_duration
50
+ 0.05
51
+ end
52
+ end
13
53
 
14
54
  # Shortcut for instance level wait_for.
15
55
  def self.wait_for(wait_time = Capybara.default_wait_time, &block)
16
- new(wait_time).wait_for(&block)
56
+ new(wait_time).call(&block)
17
57
  end
18
58
 
19
59
  # Initializes a new Checkpoint.
@@ -21,7 +61,7 @@ module Dill
21
61
  # @param wait_time how long this checkpoint will wait for its conditions to
22
62
  # be met, in seconds.
23
63
  def initialize(wait_time = Capybara.default_wait_time)
24
- @wait_time = wait_time
64
+ @timer = Timer.new(wait_time)
25
65
  end
26
66
 
27
67
  # Executes +block+ repeatedly until it returns a "truthy" value or
@@ -35,48 +75,26 @@ module Dill
35
75
  # raises a Dill::Checkpoint::ConditionNotMet error.
36
76
  #
37
77
  # Returns whatever value is returned by the block.
38
- def wait_for(&condition)
39
- start
78
+ def call(&condition)
79
+ timer.start
40
80
 
41
81
  begin
42
82
  yield or raise ConditionNotMet
43
83
  rescue *rescuable_errors
44
- raise if expired?
45
-
46
- wait
84
+ raise if timer.expired?
47
85
 
48
- raise TimeFrozen, 'time appears to be frozen' if time_frozen?
86
+ timer.tick
49
87
 
50
88
  retry
51
89
  end
52
90
  end
53
91
 
92
+ protected
93
+
54
94
  def rescuable_errors
55
95
  [StandardError]
56
96
  end
57
97
 
58
- private
59
-
60
- attr_reader :start_time
61
-
62
- def expired?
63
- remaining_time > wait_time
64
- end
65
-
66
- def remaining_time
67
- Time.now - start_time
68
- end
69
-
70
- def start
71
- @start_time = Time.now
72
- end
73
-
74
- def wait
75
- sleep 0.05
76
- end
77
-
78
- def time_frozen?
79
- Time.now == start_time
80
- end
98
+ attr_reader :timer
81
99
  end
82
100
  end
@@ -1,5 +1,7 @@
1
1
  module Dill
2
2
  module Conversions
3
+ extend self
4
+
3
5
  def Boolean(val)
4
6
  case val
5
7
  when 'yes', 'true', true
@@ -5,26 +5,36 @@ module Dill
5
5
  # @return [Document] the current document with the class of the
6
6
  # current object set as the widget lookup scope.
7
7
  def document
8
- Document.new(widget_lookup_scope: widget_lookup_scope)
8
+ Document.new(widget_lookup_scope)
9
9
  end
10
10
 
11
11
  # @return [Boolean] Whether one or more widgets exist in the current
12
12
  # document.
13
- def has_widget?(name)
14
- document.has_widget?(name)
13
+ def has_widget?(name, *args)
14
+ document.has_widget?(name, *args)
15
+ end
16
+
17
+ def value(name, *args)
18
+ widget(name, *args).value
15
19
  end
16
20
 
17
21
  # Returns a widget instance for the given name.
18
22
  #
19
23
  # @param name [String, Symbol]
20
- def widget(name)
21
- document.widget(name)
24
+ def widget(name, *args)
25
+ document.widget(name, *args)
22
26
  end
23
27
 
24
28
  def widget_lookup_scope
25
29
  @widget_lookup_scope ||= default_widget_lookup_scope
26
30
  end
27
31
 
32
+ # re-run one or more assertions until either they all pass,
33
+ # or Dill times out, which will result in a test failure.
34
+ def eventually(wait_time = Capybara.default_wait_time, &block)
35
+ Checkpoint.wait_for wait_time, &block
36
+ end
37
+
28
38
  private
29
39
 
30
40
  def default_widget_lookup_scope
@@ -1,3 +1,3 @@
1
1
  module Dill
2
- VERSION = "0.5.2"
2
+ VERSION = '0.6.0'
3
3
  end
@@ -0,0 +1,56 @@
1
+ # This file describes the organization of the major Widget API components.
2
+ #
3
+ # === Parts
4
+ #
5
+ # Widget parts encapsulate the set of behaviours that constitute a widget.
6
+ module Dill
7
+ module Constructors
8
+ def Widget(*selector, &block)
9
+ WidgetClass.new(selector.flatten, &block)
10
+ end
11
+
12
+ alias_method :String, :Widget
13
+
14
+ def Integer(*selector)
15
+ Widget(selector) do
16
+ def value
17
+ Integer(text)
18
+ end
19
+ end
20
+ end
21
+
22
+ require 'bigdecimal'
23
+
24
+ def Decimal(*selector)
25
+ Widget(selector) do
26
+ def value
27
+ # ensure we can convert to float first
28
+ Float(text) && BigDecimal.new(text)
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ extend Constructors
35
+ end
36
+
37
+ module Dill::WidgetParts; end
38
+
39
+ require 'dill/widgets/parts/struct'
40
+ require 'dill/widgets/parts/container'
41
+
42
+ require 'dill/widgets/widget_class'
43
+ require 'dill/widgets/widget_name'
44
+ require 'dill/widgets/widget'
45
+ require 'dill/widgets/list_item'
46
+ require 'dill/widgets/list'
47
+ require 'dill/widgets/base_table'
48
+ require 'dill/widgets/auto_table'
49
+ require 'dill/widgets/table'
50
+ require 'dill/widgets/field'
51
+ require 'dill/widgets/check_box'
52
+ require 'dill/widgets/select'
53
+ require 'dill/widgets/text_field'
54
+ require 'dill/widgets/field_group'
55
+ require 'dill/widgets/form'
56
+ require 'dill/widgets/document'
@@ -4,7 +4,7 @@ module Dill
4
4
  # don't include footer in to_table, because footer column configuration is very
5
5
  # often different from the headers & values.
6
6
  def footers
7
- @footers ||= root.all(footer_selector).map { |n| node_text(n) }
7
+ @footers ||= root.all(footer_selector).map { |n| Widget.new(n).text }
8
8
  end
9
9
 
10
10
  protected
@@ -37,7 +37,9 @@ module Dill
37
37
  end
38
38
 
39
39
  def headers
40
- @headers ||= root.all(header_selector).map { |n| node_text(n).downcase }
40
+ @headers ||= root.
41
+ all(header_selector).
42
+ map { |n| Widget.new(n).text.downcase }
41
43
  end
42
44
 
43
45
  def footer_selector
@@ -66,7 +68,7 @@ module Dill
66
68
  attr_accessor :cell_selector
67
69
 
68
70
  def node_text(node)
69
- NodeText.new(node)
71
+ node.text.strip
70
72
  end
71
73
  end
72
74
  end
@@ -0,0 +1,26 @@
1
+ module Dill
2
+ # A check box.
3
+ class CheckBox < Field
4
+ # @!method set(value)
5
+ # Checks or unchecks the current checkbox.
6
+ #
7
+ # @param value [Boolean] +true+ to check the checkbox, +false+
8
+ # otherwise.
9
+ def_delegator :root, :set
10
+
11
+ # @return [Boolean] +true+ if the checkbox is checked, +false+
12
+ # otherwise.
13
+ def get
14
+ !! root.checked?
15
+ end
16
+
17
+ def to_cell
18
+ to_s
19
+ end
20
+
21
+ # @return +"yes"+ if the checkbox is checked, +"no"+ otherwise.
22
+ def to_s
23
+ get ? 'yes' : 'no'
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,13 @@
1
+ module Dill
2
+ class Document
3
+ include WidgetParts::Container
4
+
5
+ def initialize(widget_lookup_scope)
6
+ self.widget_lookup_scope = widget_lookup_scope or raise 'No scope given'
7
+ end
8
+
9
+ def root
10
+ Capybara.current_session
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ module Dill
2
+ # A form field.
3
+ class Field < Widget
4
+ def self.find_in(parent)
5
+ new { parent.root.find_field(*selector) }
6
+ end
7
+
8
+ def self.present_in?(parent)
9
+ parent.root.has_field?(*selector)
10
+ end
11
+
12
+ # @return This field's value.
13
+ #
14
+ # Override this to get the actual value.
15
+ def get
16
+ raise NotImplementedError
17
+ end
18
+
19
+ # Sets the field value.
20
+ #
21
+ # Override this to set the value.
22
+ def set(value)
23
+ raise NotImplementedError
24
+ end
25
+ end
26
+ end
@@ -241,91 +241,5 @@ module Dill
241
241
 
242
242
  [headers, body]
243
243
  end
244
-
245
- # A form field.
246
- class Field < Widget
247
- def self.find_in(parent)
248
- new(parent.find_field(*selector))
249
- end
250
-
251
- def self.present_in?(parent)
252
- parent.has_field?(*selector)
253
- end
254
-
255
- # @return This field's value.
256
- #
257
- # Override this to get the actual value.
258
- def get
259
- raise NotImplementedError
260
- end
261
-
262
- # Sets the field value.
263
- #
264
- # Override this to set the value.
265
- def set(value)
266
- raise NotImplementedError
267
- end
268
- end
269
-
270
- # A check box.
271
- class CheckBox < Field
272
- # @!method set(value)
273
- # Checks or unchecks the current checkbox.
274
- #
275
- # @param value [Boolean] +true+ to check the checkbox, +false+
276
- # otherwise.
277
- def_delegator :root, :set
278
-
279
- # @return [Boolean] +true+ if the checkbox is checked, +false+
280
- # otherwise.
281
- def get
282
- !! root.checked?
283
- end
284
-
285
- # @return +"yes"+ if the checkbox is checked, +"no"+ otherwise.
286
- def to_s
287
- get ? 'yes' : 'no'
288
- end
289
- end
290
-
291
- # A select.
292
- class Select < Field
293
- # @return [String] The text of the selected option.
294
- def get
295
- option = root.find('[selected]') rescue nil
296
-
297
- option && option.text
298
- end
299
-
300
- # Selects the given option.
301
- #
302
- # @param option [String] The text of the option to select.
303
- def set(option)
304
- root.find('option', text: option).select_option
305
- end
306
-
307
- # @!method to_s
308
- # @return the text of the selected option, or the empty string if
309
- # no option is selected.
310
- def_delegator :get, :to_s
311
- end
312
-
313
- # A text field.
314
- class TextField < Field
315
- # @!method get
316
- # @return The text field value.
317
- def_delegator :root, :value, :get
318
-
319
- # @!method set(value)
320
- # Sets the text field value.
321
- #
322
- # @param value [String] the value to set.
323
- def_delegator :root, :set
324
-
325
- # @!method to_s
326
- # @return the text field value, or the empty string if the field is
327
- # empty.
328
- def_delegator :get, :to_s
329
- end
330
244
  end
331
245
  end