pincers 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9be2262d6757498e82ec195e8e8e5109226df675
4
- data.tar.gz: 73e0e4943ec46e3dcbd35a043dda468bbb1e75f2
3
+ metadata.gz: feda6bb5061f196c604a1dc79dfd32ec4bec842c
4
+ data.tar.gz: 54b99547bdb963def619ef399e39b166de4c6720
5
5
  SHA512:
6
- metadata.gz: a7fcc330eb821333f73e1d9f4989084e5d7a0d161703542725ab606a244ac10305f69430bb3522e1c7cc5d8a1746a8bb974f4d9585170aa27b59822980c9afd5
7
- data.tar.gz: 917e6139161b82a3a817b9fb6deb3d31295e60658e138d9004efcb8712f27f41e691c963fedc200c8de22d12c4d398ef5a0e4f2f1176c9523a68b0605b21ab53
6
+ metadata.gz: acc759a2464e7ec81ad88d75b44824e1f3d7dddeaa68511ce851a7e5bd4d06b5dc2c3410a1f92a362a4789a2d1e1950bf4a7889b15d063a1d12b51204b832da8
7
+ data.tar.gz: 084a161f77fe5e52eec66d84188a98b55dc70d945acdb8b3a5bce34f2ed70e57fba73be3f3768b90abf41fc0fedca87987e76fae05fd8a4177df26fd1cda0b98
@@ -20,10 +20,6 @@ module Pincers::Backend
20
20
  ensure_implementation :document_title
21
21
  end
22
22
 
23
- def document_source
24
- ensure_implementation :document_source
25
- end
26
-
27
23
  def fetch_cookies
28
24
  ensure_implementation :fetch_cookies
29
25
  end
@@ -52,6 +48,10 @@ module Pincers::Backend
52
48
  ensure_implementation :search_by_xpath
53
49
  end
54
50
 
51
+ def extract_element_tag(_element)
52
+ ensure_implementation :extract_element_tag
53
+ end
54
+
55
55
  def extract_element_text(_element)
56
56
  ensure_implementation :extract_element_text
57
57
  end
@@ -68,18 +68,30 @@ module Pincers::Backend
68
68
  ensure_implementation :clear_input
69
69
  end
70
70
 
71
- def fill_input(_element, _value)
72
- ensure_implementation :fill_input
71
+ def set_element_text(_element, _value)
72
+ ensure_implementation :set_element_text
73
+ end
74
+
75
+ def click_on_element(_element)
76
+ ensure_implementation :click_on_element
77
+ end
78
+
79
+ def switch_to_frame(_element)
80
+ ensure_implementation :switch_to_frame
81
+ end
82
+
83
+ def switch_to_top_frame
84
+ ensure_implementation :switch_to_top_frame
73
85
  end
74
86
 
75
- def load_frame_element(_element)
76
- ensure_implementation :load_frame_element
87
+ def switch_to_parent_frame
88
+ ensure_implementation :switch_to_parent_frame
77
89
  end
78
90
 
79
91
  private
80
92
 
81
93
  def ensure_implementation(_name)
82
- raise MissingFeatureError.new _name
94
+ raise Pincers::MissingFeatureError.new _name
83
95
  end
84
96
 
85
97
  end
@@ -4,6 +4,14 @@ module Pincers::Backend
4
4
 
5
5
  class Nokogiri < Base
6
6
 
7
+ def document_root
8
+ [document]
9
+ end
10
+
11
+ def document_title
12
+ document.title
13
+ end
14
+
7
15
  def search_by_css(_element, _selector)
8
16
  _element.css _selector
9
17
  end
@@ -12,16 +20,32 @@ module Pincers::Backend
12
20
  _element.xpath _selector
13
21
  end
14
22
 
23
+ def extract_element_tag(_element)
24
+ _element.name
25
+ end
26
+
15
27
  def extract_element_text(_element)
16
- # _element.text
28
+ _element.content
17
29
  end
18
30
 
19
31
  def extract_element_html(_element)
20
- # _element['outerHTML']
32
+ _element.to_html
21
33
  end
22
34
 
23
35
  def extract_element_attribute(_element, _name)
24
- # _element[_name]
36
+ _name = _name.to_sym
37
+
38
+ value = _element[_name]
39
+ value = checkbox_value_fix _element, value if _name == :value
40
+ value
41
+ end
42
+
43
+ private
44
+
45
+ def checkbox_value_fix(_element, _value)
46
+ if _value.nil? and _element.name.downcase == 'input' and ['checkbox', 'radio'].include? _element[:type].downcase
47
+ 'on'
48
+ else _value end
25
49
  end
26
50
 
27
51
  end
@@ -23,10 +23,6 @@ module Pincers::Backend
23
23
  @driver.title
24
24
  end
25
25
 
26
- def document_source
27
- @driver.page_source
28
- end
29
-
30
26
  def fetch_cookies
31
27
  @driver.manage.all_cookies
32
28
  end
@@ -55,30 +51,43 @@ module Pincers::Backend
55
51
  _element.find_elements xpath: _selector
56
52
  end
57
53
 
58
- def extract_element_text(_element)
54
+ def extract_element_tag(_element)
55
+ _element = ensure_element _element
56
+ _element.tag_name
57
+ end
59
58
 
59
+ def extract_element_text(_element)
60
+ _element = ensure_element _element
60
61
  _element.text
61
62
  end
62
63
 
63
64
  def extract_element_html(_element)
64
- if _element == @driver then @driver.page_source else _element.attribute('outerHTML') end
65
+ return @driver.page_source if _element == @driver
66
+ _element.attribute 'outerHTML'
65
67
  end
66
68
 
67
69
  def extract_element_attribute(_element, _name)
70
+ _element = ensure_element _element
68
71
  _element[_name]
69
72
  end
70
73
 
71
- def clear_input(_element)
74
+ def set_element_text(_element, _value)
75
+ _element = ensure_element _element
72
76
  _element.clear
77
+ _element.send_keys _value
73
78
  end
74
79
 
75
- def fill_input(_element, _value)
76
- _element.send_keys _value
80
+ def click_on_element(_element)
81
+ _element = ensure_element _element
82
+ _element.click
83
+ end
84
+
85
+ def switch_to_frame(_element)
86
+ @driver.switch_to.frame _element
77
87
  end
78
88
 
79
- def load_frame_element(_element)
80
- driver.switch_to.frame _element
81
- self
89
+ def switch_to_top_frame
90
+ @driver.switch_to.default_content
82
91
  end
83
92
 
84
93
  # wait contitions
@@ -103,6 +112,13 @@ module Pincers::Backend
103
112
  not _elements.any? { |e| e.displayed? }
104
113
  end
105
114
 
115
+ private
116
+
117
+ def ensure_element(_element)
118
+ return @driver.find_element tag_name: 'html' if _element == @driver
119
+ _element
120
+ end
121
+
106
122
  end
107
123
 
108
124
  end
@@ -32,16 +32,24 @@ module Pincers::Core
32
32
  wrap_errors { backend.document_title }
33
33
  end
34
34
 
35
- def source
36
- wrap_errors { backend.document_source }
37
- end
38
-
39
35
  def cookies
40
36
  @cookies ||= CookieJar.new backend
41
37
  end
42
38
 
43
- def goto(_url)
44
- wrap_errors { backend.navigate_to _url }
39
+ def goto(_urlOrOptions)
40
+ wrap_errors do
41
+ if _urlOrOptions.is_a? String
42
+ _urlOrOptions = { url: _urlOrOptions }
43
+ end
44
+
45
+ if _urlOrOptions.key? :frame
46
+ goto_frame _urlOrOptions[:frame]
47
+ elsif _urlOrOptions.key? :url
48
+ backend.navigate_to _urlOrOptions[:url]
49
+ else
50
+ raise ArgumentError.new "Must provide a valid target when calling 'goto'"
51
+ end
52
+ end
45
53
  self
46
54
  end
47
55
 
@@ -68,5 +76,22 @@ module Pincers::Core
68
76
  @config[:wait_interval]
69
77
  end
70
78
 
79
+ private
80
+
81
+ def goto_frame(_frame)
82
+ case _frame
83
+ when :top
84
+ backend.switch_to_top_frame
85
+ when :parent
86
+ backend.switch_to_parent_frame
87
+ when String
88
+ backend.switch_to_frame css(_frame).element!
89
+ when SearchContext
90
+ backend.switch_to_frame _frame.element!
91
+ else
92
+ raise ArgumentError.new "Invalid :frame option #{_frame.inspect}"
93
+ end
94
+ end
95
+
71
96
  end
72
97
  end
@@ -1,7 +1,12 @@
1
+ require 'pincers/extension/queries'
2
+ require 'pincers/extension/actions'
3
+
1
4
  module Pincers::Core
2
5
  class SearchContext
3
6
  include Enumerable
4
7
  extend Forwardable
8
+ include Pincers::Extension::Queries
9
+ include Pincers::Extension::Actions
5
10
 
6
11
  attr_accessor :parent, :elements
7
12
 
@@ -51,6 +56,10 @@ module Pincers::Core
51
56
  if elements.first.nil? then nil else wrap_elements [elements.first] end
52
57
  end
53
58
 
59
+ def first!
60
+ first or raise Pincers::EmptySetError.new(self)
61
+ end
62
+
54
63
  def last
55
64
  if elements.last.nil? then nil else wrap_elements [elements.last] end
56
65
  end
@@ -67,16 +76,15 @@ module Pincers::Core
67
76
  end
68
77
  end
69
78
 
70
- def text
79
+ def tag
71
80
  wrap_errors do
72
- backend.extract_element_text element!
81
+ backend.extract_element_tag(element!).downcase
73
82
  end
74
83
  end
75
84
 
76
- def classes
85
+ def text
77
86
  wrap_errors do
78
- class_attr = backend.extract_element_attribute element!, 'class'
79
- (class_attr || '').split(' ')
87
+ backend.extract_element_text element!
80
88
  end
81
89
  end
82
90
 
@@ -88,49 +96,22 @@ module Pincers::Core
88
96
 
89
97
  # Input related
90
98
 
91
- def set(_value)
99
+ def set_text(_value)
92
100
  wrap_errors do
93
- backend.clear_input element!
94
- backend.fill_input element!
101
+ backend.set_element_text element!, _value
95
102
  end
96
103
  end
97
104
 
98
- def select(_value)
99
- # TODO.
100
- end
101
-
102
- # context related
103
-
104
- def enter
105
+ def click
105
106
  wrap_errors do
106
- RootContext.new backend.load_frame_element(element!), root.config
107
+ backend.click_on_element element!
107
108
  end
108
109
  end
109
110
 
110
- # Any methods missing are forwarded to the main element (first)
111
-
112
- def method_missing(_method, *_args, &_block)
113
- wrap_errors do
114
- m = /^(.*)_all$/.match _method.to_s
115
- if m then
116
- return [] if empty?
117
- elements.map { |e| e.send(m[1], *_args, &_block) }
118
- else
119
- element!.send(_method, *_args, &_block)
120
- end
121
- end
122
- end
111
+ # context related
123
112
 
124
- def respond_to?(_method, _include_all=false)
125
- return true if super
126
- m = /^.*_all$/.match _method.to_s
127
- if m then
128
- return true if empty?
129
- elements.first.respond_to? m[1], _include_all
130
- else
131
- return true if empty?
132
- elements.first.respond_to? _method, _include_all
133
- end
113
+ def goto
114
+ root.goto frame: self
134
115
  end
135
116
 
136
117
  private
@@ -0,0 +1,56 @@
1
+ module Pincers::Extension
2
+ module Actions
3
+
4
+ def set(_value=true, _options={})
5
+
6
+ if _value.is_a? Hash
7
+ _options = _value
8
+ _value = true
9
+ end
10
+
11
+ case input_mode
12
+ when :text
13
+ set_text _value.to_s
14
+ when :select
15
+ return set_selected _value, _options
16
+ when :checkbox, :radio
17
+ return set_checked _value
18
+ when :button
19
+ click if _value
20
+ else
21
+ return false
22
+ end
23
+ true
24
+ end
25
+
26
+ private
27
+
28
+ def set_selected(_value, _options)
29
+ click
30
+ option = if _options.key? :by_value then
31
+ find_option_by_value _options.delete(:by_value), _options
32
+ else
33
+ find_option_by_label _value, _options
34
+ end
35
+
36
+ return false if option.nil? or option.selected?
37
+ option.click
38
+ true
39
+ end
40
+
41
+ def set_checked(_value)
42
+ return false if _value == checked?
43
+ click
44
+ true
45
+ end
46
+
47
+ def find_option_by_label(_label, _options)
48
+ css("option", _options).find { |o| o.text == _label }
49
+ end
50
+
51
+ def find_option_by_value(_value, _options)
52
+ css("option", _options).find { |o| o[:value] == _value.to_s }
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,45 @@
1
+ module Pincers::Extension
2
+ module Queries
3
+
4
+ TEXT_INPUTS = ['text', 'email', 'number', 'email', 'color', 'password', 'search', 'tel', 'url']
5
+
6
+ def value
7
+ case input_mode
8
+ when :checkbox, :radio
9
+ if checked? then self[:value] else nil end
10
+ else
11
+ self[:value]
12
+ end
13
+ end
14
+
15
+ [:selected, :checked, :disabled, :required].each do |attr_name|
16
+ define_method "#{attr_name}?" do
17
+ not self[attr_name].nil?
18
+ end
19
+ end
20
+
21
+ def classes
22
+ (self[:class] || '').split(' ')
23
+ end
24
+
25
+ def selected(_options={})
26
+ first!.css('option', _options).select { |opt| opt.selected? }
27
+ end
28
+
29
+ def checked(_options={})
30
+ first!.css('input', _options).select { |opt| opt.checked? }
31
+ end
32
+
33
+ def input_mode
34
+ return :select if tag == 'select'
35
+ return :button if tag == 'button' # TODO: button types
36
+ return :text if tag == 'textarea'
37
+ return nil if tag != 'input'
38
+
39
+ type = (self[:type] || 'text').downcase
40
+ return :text if TEXT_INPUTS.include? type
41
+ type.to_sym
42
+ end
43
+
44
+ end
45
+ end
@@ -1,3 +1,3 @@
1
1
  module Pincers
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pincers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ignacio Baixas
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-11 00:00:00.000000000 Z
11
+ date: 2015-08-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: selenium-webdriver
@@ -178,6 +178,34 @@ dependencies:
178
178
  - - '>='
179
179
  - !ruby/object:Gem::Version
180
180
  version: '0'
181
+ - !ruby/object:Gem::Dependency
182
+ name: rack
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - '>='
186
+ - !ruby/object:Gem::Version
187
+ version: '0'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - '>='
193
+ - !ruby/object:Gem::Version
194
+ version: '0'
195
+ - !ruby/object:Gem::Dependency
196
+ name: thin
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - '>='
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ type: :development
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - '>='
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
181
209
  description:
182
210
  email:
183
211
  - ignacio@platan.us
@@ -191,6 +219,8 @@ files:
191
219
  - lib/pincers/core/root_context.rb
192
220
  - lib/pincers/core/search_context.rb
193
221
  - lib/pincers/errors.rb
222
+ - lib/pincers/extension/actions.rb
223
+ - lib/pincers/extension/queries.rb
194
224
  - lib/pincers/factory.rb
195
225
  - lib/pincers/support/configuration.rb
196
226
  - lib/pincers/support/cookie_jar.rb