locatine 0.01084 → 0.01100

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: 38885391980f7e8d2b0cef65643f998edf5074cf
4
- data.tar.gz: f321d064c113b65f024d8d22bd52bfd0ab6a56d8
3
+ metadata.gz: 8ca422d8fbe87acacb5b19639d98c509fbdb04a2
4
+ data.tar.gz: b81058cdc3aa26f76a5521312de44f11f5b299bd
5
5
  SHA512:
6
- metadata.gz: 110afe53c901b20d93cdc7c34c2846e82c5b361d96068e368a42ad907278bb124eed0fdc53bc993a77f87afae72b744a03bd41e7e7156679a62604a6a76a115b
7
- data.tar.gz: 02105771e43ba72453ebbb238be198408037c11fd90e2169f0e79f44d96efc49a1c4bed2c08dcf8e5068e34c08c2725bb015343475074b9a48707e9a52937764
6
+ metadata.gz: f3435a0ae9f55f95e2419d47f37e066c9af65c4cc630b222229a5057aec35060a4a3d24504a5bb1eed21bee6c2c59611b692eb14dec12a945648da1f75bb8fd0
7
+ data.tar.gz: 96236870dffc079e8fa474b8fab27d5276c57ddbb1655ff0b8edf598a7eea1e45476e8cfb41b27e6feb16fc992c0f66bca6f80a84afdfe45df623ae75f9b9cc2
@@ -3,7 +3,7 @@ chrome.browserAction.onClicked.addListener(
3
3
  console.log("WAS here");
4
4
  chrome.windows.create( {'url': 'popup.html',
5
5
  'type': 'popup',
6
- 'width': 800,
7
- 'height': 600});
6
+ 'width': 640,
7
+ 'height': 480});
8
8
 
9
9
  });
@@ -29,6 +29,10 @@ async function refreshData(){
29
29
  await set_value('magic_div', true);
30
30
  magicDiv.setAttribute("locatinestyle", "true");
31
31
  };
32
+ if (magicDiv.getAttribute("locatinestyle") === "set_false") {
33
+ await set_value('magic_div', false);
34
+ magicDiv.setAttribute("locatinestyle", "false");
35
+ };
32
36
  if (magicDiv.getAttribute("locatinetitle") != "ok") {
33
37
  await set_value('locatine_title', magicDiv.getAttribute("locatinetitle"));
34
38
  await set_value('locatine_hint', magicDiv.getAttribute("locatinehint"));
@@ -43,7 +47,6 @@ async function refreshData(){
43
47
  magicDiv.removeAttribute("tag");
44
48
  magicDiv.removeAttribute("index");
45
49
  await set_value("locatine_confirm", false);
46
- await set_value('magic_div', false);
47
50
  }
48
51
  const confirmed = await get_value('locatine_confirm');
49
52
  magicDiv.setAttribute("locatineconfirmed", confirmed);
@@ -52,21 +55,27 @@ async function refreshData(){
52
55
  magic_cover.onclick = function(e) {locatine_magic_click(e)};
53
56
  };
54
57
 
55
- function getSelected(value){
58
+ async function getSelected(value){
59
+ const magic_div = document.getElementById("locatine_magic_div");
56
60
  const tagName = value.tagName;
57
61
  const array = Array.prototype.slice.call( document.getElementsByTagName(tagName) );
58
62
  const index = array.indexOf(value);
59
- document.getElementById("locatine_magic_div").setAttribute("tag", tagName);
60
- document.getElementById("locatine_magic_div").setAttribute("index", index);
63
+ if (document.locatine_selected != value) {
64
+ document.locatine_selected = value;
65
+ await set_value("locatine_confirm", "selected");
66
+ magic_div.setAttribute("tag", tagName);
67
+ magic_div.setAttribute("index", index);
68
+ }
61
69
  };
62
70
 
63
- function locatine_magic_click(e) {
71
+ async function locatine_magic_click(e) {
64
72
  document.getElementById("locatine_magic_div").setAttribute("locatinestyle", "blocked");
65
73
  const value = document.elementFromPoint(e.clientX, e.clientY);
66
74
  document.getElementById("locatine_magic_div").setAttribute("locatinestyle", "true");
67
75
  const tagName = value.tagName;
68
76
  const array = Array.prototype.slice.call( document.getElementsByTagName(tagName) );
69
77
  const index = array.indexOf(value);
78
+ await set_value("locatine_confirm", "selected");
70
79
  document.getElementById("locatine_magic_div").setAttribute("TAG", tagName);
71
80
  document.getElementById("locatine_magic_div").setAttribute("INDEX", index);
72
81
  };
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "Locatine app",
3
- "version": "0.01084",
3
+ "version": "0.01100",
4
4
  "description": "Messaging from browser to main app",
5
5
  "devtools_page": "devtools.html",
6
6
  "permissions": ["activeTab", "storage", "contextMenus", "tabs"],
@@ -0,0 +1,91 @@
1
+ module Locatine
2
+ ##
3
+ # Generating locatine json info from element itself
4
+ module DataGenerate
5
+ private
6
+
7
+ def get_dynamic_attributes(element, vars)
8
+ attrs = []
9
+ get_attributes(element).each do |hash|
10
+ if vars[hash['name'].to_sym]
11
+ hash['value'].gsub!(vars[hash['name'].to_sym], "\#{#{hash['name']}}")
12
+ end
13
+ attrs.push hash
14
+ end
15
+ attrs
16
+ end
17
+
18
+ def get_dynamic_tag(element, vars)
19
+ tag = element.tag_name
20
+ tag = "\#{tag}" if vars[:tag] == tag
21
+ { 'name' => 'tag', 'value' => tag, 'type' => 'tag' }
22
+ end
23
+
24
+ def real_text_of(element)
25
+ element.text == element.inner_html ? element.text : ''
26
+ end
27
+
28
+ def get_dynamic_text(element, vars)
29
+ attrs = []
30
+ real_text_of(element).split(' ').each do |word|
31
+ final_word = if !vars[:text].to_s.strip.empty?
32
+ word.gsub(vars[:text].to_s, "\#{text}")
33
+ else
34
+ word
35
+ end
36
+ attrs.push('name' => 'text', 'value' => final_word, 'type' => 'text')
37
+ end
38
+ attrs
39
+ end
40
+
41
+ ##
42
+ # Generating array of hashes representing data of the element
43
+ def get_element_info(element, vars)
44
+ attrs = get_dynamic_attributes(element, vars)
45
+ attrs.push get_dynamic_tag(element, vars)
46
+ attrs += get_dynamic_text(element, vars)
47
+ attrs
48
+ end
49
+
50
+ ##
51
+ # Generating data for group of elements
52
+ def generate_data(result, vars)
53
+ family = {}
54
+ result.each do |item|
55
+ family = get_commons(get_family_info(item, vars), family)
56
+ end
57
+ family
58
+ end
59
+
60
+ ##
61
+ # Getting element\\parents information
62
+ def get_family_info(element, vars)
63
+ current_depth = 0
64
+ attributes = {}
65
+ while current_depth != @depth
66
+ attributes[current_depth.to_s] = get_element_info(element, vars)
67
+ current_depth += 1
68
+ element = element.parent
69
+ # Sometimes watir is not returning a valid parent that's why:
70
+ current_depth = @depth unless element.parent.exists?
71
+ end
72
+ attributes
73
+ end
74
+
75
+ ##
76
+ # Collecting attributes of the element
77
+ def get_attributes(element)
78
+ attributes = element.attributes
79
+ array = []
80
+ attributes.each_pair do |name, value|
81
+ next if name.to_s == 'locatineclass'
82
+
83
+ value.split(' ').uniq.each do |part|
84
+ array.push('name' => name.to_s, 'type' => 'attribute',
85
+ 'value' => part)
86
+ end
87
+ end
88
+ array
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,71 @@
1
+ module Locatine
2
+ ##
3
+ # Simple actions about communicating with chrome extension (and user)
4
+ module DialogActions
5
+ private
6
+
7
+ ##
8
+ # Setting attribute of locatine div (way to communicate)
9
+ def send_to_app(what, value, bro = engine)
10
+ fix_iframe
11
+ bro.wd.execute_script(
12
+ %[if (document.getElementById('locatine_magic_div')){
13
+ const magic_div = document.getElementById('locatine_magic_div');
14
+ return magic_div.setAttribute("#{what}", "#{value}")}]
15
+ )
16
+ fix_iframe
17
+ end
18
+
19
+ ##
20
+ # Getting attribute of locatine div (way to communicate)
21
+ def get_from_app(what)
22
+ fix_iframe
23
+ result = engine.wd.execute_script(
24
+ %[if (document.getElementById('locatine_magic_div')) {
25
+ const magic_div = document.getElementById('locatine_magic_div');
26
+ return magic_div.getAttribute("#{what}")}]
27
+ )
28
+ fix_iframe
29
+ result
30
+ end
31
+
32
+ def fix_iframe
33
+ @iframe = @browser.iframe(@iframe.selector) if @iframe
34
+ end
35
+
36
+ def push_title(text)
37
+ puts text
38
+ send_to_app('locatinetitle', text)
39
+ end
40
+
41
+ ##
42
+ # Sending request to locatine app
43
+ def start_listening(_scope, _name)
44
+ send_to_app('locatinestyle', 'blocked', @browser) if @iframe
45
+ send_to_app('locatinehint', 'Toggle single//collection mode button if '\
46
+ 'you need. If you want to do some actions on the page toggle Locatine'\
47
+ ' waiting button. You also can select element on devtools -> Elements.'\
48
+ ' Do not forget to confirm your selection.')
49
+ send_to_app('locatinestyle', 'set_true')
50
+ sleep 0.5
51
+ end
52
+
53
+ def tag_index
54
+ tag = get_from_app('tag')
55
+ tag = tag.downcase unless tag.nil?
56
+ index = get_from_app('index').to_i
57
+ return tag, index
58
+ end
59
+
60
+ def response_action(element)
61
+ send_to_app('locatineconfirmed', 'ok')
62
+ send_to_app('locatinetitle', 'Right now you are defining nothing. '\
63
+ 'So no button will work')
64
+ send_to_app('locatinehint', 'Place for a smart hint here')
65
+ mass_highlight_turn(element, false)
66
+ send_to_app('locatinestyle', 'set_false')
67
+ send_to_app('locatinestyle', 'ok', @browser) if @iframe
68
+ sleep 0.5
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,94 @@
1
+ module Locatine
2
+ ##
3
+ # Logic of recieving element selected by user
4
+ module DialogLogic
5
+ private
6
+
7
+ def suggest_element(element, vars, name, scope)
8
+ attributes = {}
9
+ if !element.nil?
10
+ attributes = generate_data(element, vars)
11
+ push_title("#{element.length} elements found as #{name} in #{scope}.")
12
+ elsif name.length >= 5
13
+ push_title("Locatine is trying to guess what is #{name} in #{scope}.")
14
+ element, attributes = find_by_guess(scope, name, vars)
15
+ end
16
+ mass_highlight_turn(element) if element
17
+ return element, attributes
18
+ end
19
+
20
+ def add_selected_attributes(new_attributes, attributes)
21
+ if get_from_app('locatinecollection') == 'true'
22
+ get_commons(new_attributes, attributes.to_h)
23
+ else
24
+ new_attributes
25
+ end
26
+ end
27
+
28
+ def selected_element_attributes(tag, index, vars)
29
+ generate_data([engine.elements(tag_name: tag)[index]], vars).to_h
30
+ end
31
+
32
+ def selected_element(tag, index, vars, attributes)
33
+ new_attributes = selected_element_attributes(tag, index, vars)
34
+ new_attributes = add_selected_attributes(new_attributes, attributes)
35
+ element = find_by_data(new_attributes, vars)
36
+ return element, new_attributes
37
+ end
38
+
39
+ def working_on_selected(tag, index, vars, attributes)
40
+ push_title "You've selected //#{tag}[#{index}]. Wait while Locatine works"
41
+ element, new_attributes = selected_element(tag, index, vars, attributes)
42
+ warn 'Cannot proceed with selected. Dropping it.' unless element
43
+
44
+ warn "Maybe #{tag} can't be found as a #{@type}?" if @type && !element
45
+
46
+ return find_by_data(attributes, vars).to_a, attributes.to_h unless element
47
+
48
+ return element, new_attributes
49
+ end
50
+
51
+ def what_was_selected(element, attributes, vars, name, scope)
52
+ send_to_app('locatineconfirmed', 'ok')
53
+ tag, index = tag_index
54
+ mass_highlight_turn(element, false) if element
55
+ element, attributes = working_on_selected(tag, index, vars, attributes)
56
+ mass_highlight_turn(element) if element
57
+ push_title "#{element.length} elements were selected as #{name} in "\
58
+ "#{scope}. If it is correct - confirm the selection."
59
+ return element, attributes
60
+ end
61
+
62
+ def decline(element, name, scope)
63
+ mass_highlight_turn(element, false) if element
64
+ send_to_app('locatineconfirmed', 'ok')
65
+ push_title "Nothing is selected as #{name} in #{scope}"
66
+ return nil, {}
67
+ end
68
+
69
+ def listening(els, attrs, vars, name, scope)
70
+ until get_from_app('locatineconfirmed') == 'true'
71
+ sleep(0.1)
72
+ case get_from_app('locatineconfirmed')
73
+ when 'selected'
74
+ els, attrs = what_was_selected(els, attrs, vars, name, scope)
75
+ when 'declined'
76
+ els, attrs = decline(els, name, scope)
77
+ end
78
+ end
79
+ return els, attrs
80
+ end
81
+
82
+ ##
83
+ # request send and waiting for an answer
84
+ def ask(scope, name, element, vars)
85
+ start_listening(scope, name)
86
+ element, attributes = suggest_element(element, vars, name, scope)
87
+ @cold_time = 0
88
+ element, attributes = listening(element, attributes, vars, name, scope)
89
+ @cold_time = nil
90
+ response_action(element)
91
+ return element, attributes
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,54 @@
1
+ module Locatine
2
+ ##
3
+ # Methods about creating, reading and writing files
4
+ module FileWork
5
+ private
6
+
7
+ ##
8
+ # Reading data from provided file which is set on init of the class instance
9
+ #
10
+ # If there is no dir or\and file they will be created
11
+ def read_create
12
+ FileUtils.mkdir_p(@folder) unless File.directory?(@folder)
13
+ hash = Hash.new { |h, k| h[k] = Hash.new { |hi, ki| hi[ki] = {} } }
14
+ create_json_file unless File.exist?(@json)
15
+ hash.merge(JSON.parse(File.read(@json))['data'])
16
+ end
17
+
18
+ def create_json_file
19
+ f = File.new(@json, 'w')
20
+ f.puts '{"data" : {}}'
21
+ f.close
22
+ end
23
+
24
+ ##
25
+ # Setting stability
26
+ def set_stability(first, second)
27
+ second = first if second.to_h == {}
28
+ final = Hash.new { |hash, key| hash[key] = [] }
29
+ first.each_pair do |depth, array|
30
+ final[depth] = same_entries(array, second, depth, true).uniq
31
+ end
32
+ final
33
+ end
34
+
35
+ def stability_bump(to_add, hash)
36
+ if to_add.empty? # new ones
37
+ hash['stability'] = '1'
38
+ elsif to_add[0]['stability'].to_i < @stability_limit # old ones
39
+ to_add[0]['stability'] = (to_add[0]['stability'].to_i + 1).to_s
40
+ end
41
+ to_add.empty? ? [hash] : to_add
42
+ end
43
+
44
+ ##
45
+ # Saving json
46
+ def store(attributes, scope, name)
47
+ @data[scope][name] = set_stability(attributes, @data[scope][name])
48
+ to_write = { 'data' => @data }
49
+ File.open(@json, 'w') do |f|
50
+ f.write(JSON.pretty_generate(to_write))
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,62 @@
1
+ module Locatine
2
+ ##
3
+ # If html code is good and name is related to the code, Locatine can guess it
4
+ #
5
+ # Methods for finding element by name only
6
+ module FindByGuess
7
+ private
8
+
9
+ def main_guess(name)
10
+ all = []
11
+ name.split(' ').each do |part|
12
+ all += guess_by_part(part)
13
+ end
14
+ all
15
+ end
16
+
17
+ def guess_by_part(part)
18
+ all = []
19
+ tag_xpath = "//#{part}#{not_magic_div}"
20
+ text_xpath = "//*[contains(text(),'#{part}')]#{not_magic_div}"
21
+ attr_xpath = "//*[@*[contains(., '#{part}')]]#{not_magic_div}"
22
+ all += find_by_locator(xpath: tag_xpath).to_a
23
+ all += find_by_locator(xpath: text_xpath).to_a
24
+ all += find_by_locator(xpath: attr_xpath).to_a
25
+ all
26
+ end
27
+
28
+ def full_guess(all, vars, name)
29
+ max = all.count(all.max_by { |i| all.count(i) })
30
+ if max >= name.split(' ').length
31
+ guess = (all.select { |i| all.count(i) == max }).uniq
32
+ guess_data = generate_data(guess, vars)
33
+ found_by_data = find_by_data(guess_data, vars)
34
+ end
35
+ return found_by_data, guess_data.to_h
36
+ end
37
+
38
+ def check_guess(all, vars, name, scope)
39
+ guess, guess_data = full_guess(all, vars, name)
40
+ if guess.nil? || (engine.elements.length / guess.length <= 4)
41
+ push_title "Locatine has no good guess for #{name} in #{scope}."
42
+ guess = nil
43
+ guess_data = {}
44
+ else
45
+ push_title "#{guess.length} elements guessed as #{name} in #{scope}."
46
+ end
47
+ return guess, guess_data
48
+ end
49
+
50
+ def find_by_guess(scope, name, vars)
51
+ @cold_time = 0
52
+ all = main_guess(name)
53
+ if !all.empty?
54
+ guess, guess_data = check_guess(all, vars, name, scope)
55
+ else
56
+ push_title "Locatine has no guess for #{name} in #{scope}."
57
+ end
58
+ @cold_time = nil
59
+ return guess, guess_data.to_h
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,98 @@
1
+ module Locatine
2
+ ##
3
+ # Methods related to the most simple search by ready locator.
4
+ module FindByLocator
5
+ private
6
+
7
+ def collection?(the_class)
8
+ case the_class.superclass.to_s
9
+ when 'Object'
10
+ nil
11
+ when 'Watir::Element'
12
+ false
13
+ when 'Watir::ElementCollection'
14
+ true
15
+ else
16
+ collection?(the_class.superclass)
17
+ end
18
+ end
19
+
20
+ ##
21
+ # Getting all the elements matching a locator
22
+ def find_by_locator(locator)
23
+ method = @type.nil? ? :elements : @type
24
+ results = engine.send(method, locator)
25
+ case collection?(results.class)
26
+ when nil
27
+ wrong_method_detected(method)
28
+ when true
29
+ return correct_method_detected(results)
30
+ when false
31
+ return acceptable_method_detected(results, method)
32
+ end
33
+ end
34
+
35
+ def wrong_method_detected(method)
36
+ @type = nil
37
+ raise ArgumentError, "#{method} is not good for :look_in property. Use"\
38
+ ' a method of Watir::Browser that returns a collection (like :divs,'\
39
+ ' :links, etc.)'
40
+ end
41
+
42
+ def correct_method_detected(results)
43
+ all = []
44
+ begin
45
+ results[0].wait_until(timeout: @cold_time, &:present?)
46
+ rescue StandardError
47
+ nil
48
+ end
49
+ results.each { |item| all.push item if item.present? }
50
+ return all unless all.empty?
51
+ return nil if all.empty?
52
+ end
53
+
54
+ def acceptable_method_detected(results, method, locator)
55
+ warn "#{method} works for :look_in. But it is better to use a method of"\
56
+ ' Watir::Browser that returns a collection (like :divs, :links, etc.)'
57
+ the_class = results.class
58
+ results = engine.elements(locator)
59
+ .to_a.select { |item| item.to_subtype.class == the_class }
60
+ correct_method_detected(results)
61
+ end
62
+
63
+ ##
64
+ # Getting elements by tag
65
+ def find_by_tag(hash, vars, depth = 0)
66
+ correction = '/*' * depth.to_i
67
+ xpath = "//*[self::#{process_string(hash['value'], vars)}]"
68
+ find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
69
+ end
70
+
71
+ ##
72
+ # Getting elements by text
73
+ def find_by_text(hash, vars, depth = 0)
74
+ correction = '/*' * depth.to_i
75
+ xpath = "//*[contains(text(), '#{process_string(hash['value'], vars)}')]"
76
+ find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
77
+ end
78
+
79
+ ##
80
+ # Getting elements by attribute
81
+ def find_by_attribute(hash, vars, depth = 0)
82
+ correction = '/*' * depth.to_i
83
+ full_part = '//*[@*'
84
+ hash['name'].split('_').each do |part|
85
+ full_part += "[contains(name(), '#{part}')]"
86
+ end
87
+ value = process_string(hash['value'], vars)
88
+ xpath = full_part + "[contains(., '#{value}')]]"
89
+ find_by_locator(xpath: "#{xpath}#{correction}#{not_magic_div}")
90
+ end
91
+
92
+ ##
93
+ # Getting all the elements via stored information
94
+ def find_by_data(data, vars)
95
+ find_by_locator(xpath: generate_xpath(data, vars))
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,43 @@
1
+ module Locatine
2
+ ##
3
+ # Logic for finding lost element
4
+ module FindByMagic
5
+ private
6
+
7
+ ##
8
+ # Getting all the elements via black magic
9
+ def find_by_magic(name, scope, data, vars)
10
+ warn "#{name} in #{scope} is lost. Looking for it."
11
+ @cold_time = 0
12
+ all = all_options(data, vars)
13
+ @cold_time = nil
14
+ raise "Unable to find element #{name} in #{scope}" if all.empty?
15
+
16
+ max = all.count(all.max_by { |i| all.count(i) })
17
+ suggestion = (all.select { |i| all.count(i) == max }).uniq
18
+ attributes = generate_data(suggestion, vars)
19
+ return suggestion, attributes
20
+ end
21
+
22
+ def all_options(data, vars)
23
+ all = []
24
+ data.each_pair do |depth, array|
25
+ get_trusted(array).each do |hash|
26
+ all += one_option_array(hash, vars, depth)
27
+ end
28
+ end
29
+ all
30
+ end
31
+
32
+ def one_option_array(hash, vars, depth)
33
+ case hash['type']
34
+ when 'tag'
35
+ find_by_tag(hash, vars, depth).to_a
36
+ when 'text'
37
+ find_by_text(hash, vars, depth).to_a
38
+ when 'attribute'
39
+ find_by_attribute(hash, vars, depth).to_a
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,61 @@
1
+ module Locatine
2
+ ##
3
+ # Methods explaining find logic
4
+ module FindLogic
5
+ private
6
+
7
+ def set_name(simple_name, name)
8
+ name ||= simple_name
9
+ raise ArgumentError, ':name should be provided' unless name
10
+
11
+ name
12
+ end
13
+
14
+ def core_search(result, name, scope, vars, exact)
15
+ if @data[scope][name].to_h != {}
16
+ result = find_by_data(@data[scope][name], vars)
17
+ attributes = generate_data(result, vars) if result
18
+ if !result && !exact
19
+ result, attributes = find_by_magic(name, scope,
20
+ @data[scope][name], vars)
21
+ end
22
+ end
23
+ return result, attributes
24
+ end
25
+
26
+ def full_search(name, scope, vars, locator, exact)
27
+ result, attributes = locator_search(locator, vars)
28
+ unless result
29
+ result, attributes = core_search(result, name, scope,
30
+ vars, exact)
31
+ end
32
+ result, attributes = ask(scope, name, result, vars) if @learn
33
+ raise "Nothing was found for #{scope} #{name}" if !result && !exact
34
+
35
+ store(attributes, scope, name) if result
36
+ return result, attributes
37
+ end
38
+
39
+ def locator_search(locator, vars)
40
+ result = find_by_locator(locator) if locator != {}
41
+ attributes = generate_data(result, vars) if result
42
+ return result, attributes
43
+ end
44
+
45
+ ##
46
+ # Returning subtype of the only element of collection OR collection
47
+ #
48
+ # Params:
49
+ # +result+ must be Watir::HTMLElementCollection or Array
50
+ #
51
+ # +collection+ nil, true or false
52
+ def to_subtype(result, collection)
53
+ case collection
54
+ when true
55
+ result
56
+ when false
57
+ result.first.to_subtype
58
+ end
59
+ end
60
+ end
61
+ end