dill 0.5.2 → 0.6.0

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