Module: Capybara::JsFinders

Extended by:
XPath
Defined in:
lib/capybara-js_finders.rb,
lib/capybara-js_finders/version.rb

Constant Summary collapse

LR =

Left range

"lr".freeze
RR =

Right range

"rr".freeze
TR =

Top range

"tr".freeze
BR =

Bottom range

"br".freeze
XpathTrue =
"(1=1)"
NEW_METHODS =
[:find_cell, :static_page].freeze
SCRIPT =

TODO: This script is only prototype compatible. Let it discover jquery or prototype and use proper methods.

If element left offset is 5 and element width is 10 then it cannot occupy pixels from 5 to 15 because that would give us 11px width. Element must occupy pixels from 6 to 15 or from 5 to 14 (including).

I assume that the former answer is correct. Element starts on 6th pixel and that's why offset is equal to 5. TODO: Make sure there is test for that!

"  xpathResult = document.evaluate( \"\#{descendant(:th, :td)}\", document, null, XPathResult.ANY_TYPE, null);\n  var ary = [];\n  var td;\n  while( td = xpathResult.iterateNext() ){\n    ary.push(td);\n  }\n  ary.each(function(ele){\n    try{\n      var dimensions = ele.getDimensions();\n      var offset = ele.cumulativeOffset();\n\n      ele.setAttribute('\#{LR}', offset.left + 1);\n      ele.setAttribute('\#{RR}', offset.left + dimensions.width);\n      ele.setAttribute('\#{TR}', offset.top  + 1);\n      ele.setAttribute('\#{BR}', offset.top  + dimensions.height);\n    } catch(err){\n      /* ele.getDimensions() sometimes raises an exception, just skip ele in such case, there is nothing we can do about it! */\n    }\n  });\n"
VERSION =
"0.4.3"

Class Method Summary collapse

Instance Method Summary collapse

Methods included from XPath

father

Class Method Details

.cell_condition(columns, rows) ⇒ Object

Condition for td to be under one of column and on the same level as one of the rows and cannot be the same cell as one of the row-header or column-header



89
90
91
92
# File 'lib/capybara-js_finders.rb', line 89

def self.cell_condition(columns, rows)
  xpath = "( #{overlaps_rows(rows)} ) and ( #{overlaps_columns(columns)} ) and (#{not_equal_to(columns + rows)})"
  return xpath
end

.not_equal_to(headers) ⇒ Object



81
82
83
84
85
# File 'lib/capybara-js_finders.rb', line 81

def self.not_equal_to(headers)
  headers.reject{|h| h == true}.map do |h|
    "( ./@#{TR} != #{h[TR]} or ./@#{BR} != #{h[BR]} or ./@#{LR} != #{h[LR]} or ./@#{RR} != #{h[RR]} )"
  end.join(" and ")
end

.overlaps_column(column) ⇒ Object



56
57
58
# File 'lib/capybara-js_finders.rb', line 56

def self.overlaps_column(column)
  overlaps_horizontal(column[LR], column[RR])
end

.overlaps_columns(columns) ⇒ Object



49
50
51
52
53
54
# File 'lib/capybara-js_finders.rb', line 49

def self.overlaps_columns(columns)
  return XpathTrue if columns.first == true
  columns_xpath = columns.map{|column| overlaps_column(column) }.join(" or ")
  columns_xpath = "( #{columns_xpath} )"
  return columns_xpath
end

.overlaps_horizontal(clr, crr) ⇒ Object

clr, crr - Column left and right range



61
62
63
# File 'lib/capybara-js_finders.rb', line 61

def self.overlaps_horizontal(clr, crr)
  "(./@#{RR} >= #{clr} and ./@#{LR} <= #{crr})"
end

.overlaps_row(row) ⇒ Object



72
73
74
# File 'lib/capybara-js_finders.rb', line 72

def self.overlaps_row(row)
  overlaps_vertical(row[TR], row[BR])
end

.overlaps_rows(rows) ⇒ Object



65
66
67
68
69
70
# File 'lib/capybara-js_finders.rb', line 65

def self.overlaps_rows(rows)
  return XpathTrue if rows.first == true
  rows_xpath = rows.map{|row| overlaps_row(row) }.join(" or ")
  rows_xpath = "( #{rows_xpath} )"
  return rows_xpath
end

.overlaps_vertical(rtr, rbr) ⇒ Object

rtr, rbr - row top and bottom range



77
78
79
# File 'lib/capybara-js_finders.rb', line 77

def self.overlaps_vertical(rtr, rbr)
  "(./@#{BR} >= #{rtr} and ./@#{TR} <= #{rbr})"
end

Instance Method Details

#find_cell(options = {}) ⇒ Object

:column - text which should appear in the table column, or td/th Capybara::Node::Element object [or Array of them] representing the columns which narrow the search area of the table. Nil is allowed.

:row - text which should appear in the row of the table, or td/th Capybara::Node::Element object [or Array of them] representing the columns which narrow the search area of the table. Nil is allowed. :text - text which should appear in the cell :multicolumn - set to true if finding column by test should return multiple results instead of just one :multirow - set to true if finding rows by test should return multiple results instead of just one

:visible :with



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/capybara-js_finders.rb', line 105

def find_cell(options = {})
  # TODO: Jak pierwszy arg to string to wywolaj cell zamiast tego

  columns = case options[:column]
  when String
    method = options[:multicolumn] ? :all : :find
    send(method, :xpath, XPath::HTML.cell(options[:column]) ) # TODO: jak all to musi byc conajmniej 1
  when Capybara::Node::Element
    options[:column]
  when Array
    options[:column].each{|x| raise ArgumentError unless x.is_a?(Capybara::Node::Element) }
  when NilClass
    true
  else
    raise ArgumentError
  end
  columns = Array.wrap(columns)

  rows = case options[:row]
  when String
    method = options[:multirow] ? :all : :find
    send(method, :xpath, XPath::HTML.cell(options[:row]) ) # TODO: jak all to musi byc conajmniej 1
  when Capybara::Node::Element
    options[:row]
  when Array
    options[:row].each{|x| raise ArgumentError unless x.is_a?(Capybara::Node::Element) }
  when NilClass
    true
  else
    raise ArgumentError
  end
  rows = Array.wrap(rows)

  if @static_page
    execute_script(SCRIPT) unless @executed
    @executed = true
  else
    execute_script(SCRIPT)
  end
  xpath = JsFinders.cell_condition(columns, rows)
  xpath = ".//td[ #{xpath} ]" # TODO: td or th ?
  # puts xpath
  find(:xpath, xpath, options)
end

#static_page(&block) ⇒ Object



150
151
152
153
154
155
156
# File 'lib/capybara-js_finders.rb', line 150

def static_page(&block)
  @static_page = true
  return block.call
ensure
  @executed = false
  @static_page = false
end