vapir-firefox 1.9.0 → 1.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/vapir-firefox/browser.rb +73 -25
- data/lib/vapir-firefox/element.rb +5 -5
- data/lib/vapir-firefox/firefox_socket/base.rb +8 -7
- data/lib/vapir-firefox/javascript_object.rb +26 -3
- data/lib/vapir-firefox/modal_dialog.rb +5 -4
- data/lib/vapir-firefox/page_container.rb +16 -5
- data/lib/vapir-firefox/version.rb +1 -1
- data/lib/vapir-firefox/window.rb +1 -1
- metadata +6 -15
@@ -187,7 +187,7 @@ module Vapir
|
|
187
187
|
# socket may be dead, and you want a new one. a warning will be printed if this occurs.
|
188
188
|
def self.firefox_socket(options={}) # :nodoc:
|
189
189
|
if options[:reset] || !(class_variable_defined?('@@firefox_socket') && @@firefox_socket)
|
190
|
-
initialize_firefox_socket(options[:socket_class], options[:socket_options])
|
190
|
+
initialize_firefox_socket(options[:socket_class] || firefox_socket_class, options[:socket_options] || firefox_socket_class_options)
|
191
191
|
end
|
192
192
|
if options[:reset_if_dead]
|
193
193
|
begin
|
@@ -268,7 +268,7 @@ module Vapir
|
|
268
268
|
|
269
269
|
@pid = begin
|
270
270
|
self.pid
|
271
|
-
rescue
|
271
|
+
rescue CannotHandlePid
|
272
272
|
nil
|
273
273
|
end
|
274
274
|
|
@@ -282,7 +282,6 @@ module Vapir
|
|
282
282
|
find_window(how, what)
|
283
283
|
end
|
284
284
|
end
|
285
|
-
set_browser_document
|
286
285
|
else
|
287
286
|
open_window
|
288
287
|
end
|
@@ -294,8 +293,8 @@ module Vapir
|
|
294
293
|
wait if options[:wait]
|
295
294
|
end
|
296
295
|
|
297
|
-
def
|
298
|
-
'MozillaUIWindowClass'
|
296
|
+
def mozilla_window_class_names
|
297
|
+
['MozillaUIWindowClass', 'MozillaWindowClass']
|
299
298
|
end
|
300
299
|
|
301
300
|
def browser
|
@@ -413,7 +412,6 @@ module Vapir
|
|
413
412
|
@document_object=browser_object.contentDocument
|
414
413
|
@content_window_object=browser_object.contentWindow
|
415
414
|
# note that browser_window_object.content is the same thing, but simpler to refer to stuff on browser_object since that is updated by the nsIWebProgressListener below
|
416
|
-
@body_object=document_object.body
|
417
415
|
@browser_objects[:requests_in_progress]=[]
|
418
416
|
@requests_in_progress=@browser_objects[:requests_in_progress].to_array
|
419
417
|
@browser_objects[:unmatched_stopped_requests_count]=0
|
@@ -481,7 +479,9 @@ module Vapir
|
|
481
479
|
attr_reader :content_window_object
|
482
480
|
attr_reader :browser_object
|
483
481
|
attr_reader :document_object
|
484
|
-
|
482
|
+
def body_object
|
483
|
+
document_object.body
|
484
|
+
end
|
485
485
|
|
486
486
|
def updated_at
|
487
487
|
Time.at(@updated_at_epoch_ms.val/1000.0)+@updated_at_offset
|
@@ -517,7 +517,7 @@ module Vapir
|
|
517
517
|
end
|
518
518
|
end
|
519
519
|
|
520
|
-
@browser_window_object=@browser_object=@document_object=@content_window_object
|
520
|
+
@browser_window_object=@browser_object=@document_object=@content_window_object=nil
|
521
521
|
if @self_launched_browser && firefox_socket && !self.class.window_objects.any?{ true }
|
522
522
|
quit_browser(:force => false)
|
523
523
|
end
|
@@ -540,7 +540,7 @@ module Vapir
|
|
540
540
|
|
541
541
|
pid = @pid || begin
|
542
542
|
self.pid
|
543
|
-
rescue
|
543
|
+
rescue CannotHandlePid
|
544
544
|
nil
|
545
545
|
end
|
546
546
|
|
@@ -557,20 +557,24 @@ module Vapir
|
|
557
557
|
|
558
558
|
wait_for_process_exit(pid)
|
559
559
|
|
560
|
-
@browser_window_object=@browser_object=@document_object=@content_window_object
|
560
|
+
@browser_window_object=@browser_object=@document_object=@content_window_object=nil
|
561
561
|
nil
|
562
562
|
end
|
563
563
|
|
564
|
+
# class representing an inability to either retrieve or check the status of firefox's pid
|
565
|
+
class CannotHandlePid < StandardError; end
|
566
|
+
|
564
567
|
# returns the pid of the currently-attached Firefox process.
|
565
568
|
#
|
566
569
|
# This only works on Firefox >= 3.6, on platforms supported (see #current_os), and raises
|
567
|
-
#
|
570
|
+
# CannotHandlePid if it can't get the pid.
|
568
571
|
def pid
|
569
572
|
begin
|
573
|
+
raise CannotHandlePid unless firefox_socket.host == 'localhost'
|
570
574
|
begin
|
571
575
|
ctypes = firefox_socket.Components.utils.import("resource://gre/modules/ctypes.jsm").ctypes
|
572
576
|
rescue FirefoxSocketJavascriptError
|
573
|
-
raise
|
577
|
+
raise CannotHandlePid, "Firefox 3.6 or greater is required for this method.\n\nOriginal error from firefox: #{$!.class}: #{$!.message}", $!.backtrace
|
574
578
|
end
|
575
579
|
lib, pidfunction, abi = *case current_os
|
576
580
|
when :macosx
|
@@ -588,7 +592,7 @@ module Vapir
|
|
588
592
|
# see https://bugzilla.mozilla.org/show_bug.cgi?id=585175
|
589
593
|
['kernel32', 'GetCurrentProcessId', ctypes['winapi_abi'] || ctypes['stdcall_abi']]
|
590
594
|
else
|
591
|
-
raise
|
595
|
+
raise CannotHandlePid, "don't know how to get pid for #{current_os}"
|
592
596
|
end
|
593
597
|
lib = ctypes.open(lib)
|
594
598
|
begin
|
@@ -600,9 +604,16 @@ module Vapir
|
|
600
604
|
end
|
601
605
|
end
|
602
606
|
|
607
|
+
# returns the host which will be configured for a socket. same as firefox_socket.host,
|
608
|
+
# if that exist, but this is correct even if firefox_socket isn't initialized.
|
609
|
+
def firefox_socket_host
|
610
|
+
firefox_socket_class_options['host'] || firefox_socket_class.config.host
|
611
|
+
end
|
612
|
+
|
603
613
|
# attempts to determine whether the given process is still running. will raise
|
604
|
-
#
|
614
|
+
# CannotHandlePid if it can't determine this.
|
605
615
|
def process_running?(pid)
|
616
|
+
raise CannotHandlePid unless firefox_socket_host == 'localhost'
|
606
617
|
case current_os
|
607
618
|
when :windows
|
608
619
|
kernel32 = Vapir::Firefox.instance_eval do # define this on the class for reuse
|
@@ -630,7 +641,7 @@ module Vapir
|
|
630
641
|
`ps -p #{pid}`
|
631
642
|
$? == 0
|
632
643
|
else
|
633
|
-
raise
|
644
|
+
raise CannotHandlePid
|
634
645
|
end
|
635
646
|
end
|
636
647
|
|
@@ -800,12 +811,36 @@ module Vapir
|
|
800
811
|
|
801
812
|
# the HTTP response status code for the currently loaded document
|
802
813
|
def response_status_code
|
814
|
+
current_document_channel_object.responseStatus
|
815
|
+
end
|
816
|
+
# a hash of the response headers returned for the currently loaded document
|
817
|
+
def response_headers
|
818
|
+
firefox_socket.call_function(:channel => current_document_channel_object) do %Q{
|
819
|
+
var headers={};
|
820
|
+
channel.visitResponseHeaders({visitHeader: function(header, value){ headers[header]=value; }});
|
821
|
+
return headers;
|
822
|
+
}
|
823
|
+
end.val.freeze
|
824
|
+
end
|
825
|
+
# a hash of the request headers the browser sent for the currently loaded document
|
826
|
+
def request_headers
|
827
|
+
firefox_socket.call_function(:channel => current_document_channel_object) do %Q{
|
828
|
+
var headers={};
|
829
|
+
channel.visitRequestHeaders({visitHeader: function(header, value){ headers[header]=value; }});
|
830
|
+
return headers;
|
831
|
+
}
|
832
|
+
end.val.freeze
|
833
|
+
end
|
834
|
+
# a nsIHttpChannel for the currently loaded document - the browser's docShell.currentDocumentChannel
|
835
|
+
#
|
836
|
+
# see https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIHttpChannel
|
837
|
+
def current_document_channel_object
|
803
838
|
channel = nil
|
804
839
|
::Waiter.try_for(8, :exception => nil) do
|
805
840
|
channel=browser.browser_object.docShell.currentDocumentChannel
|
806
841
|
channel.is_a?(JavascriptObject) && channel.instanceof(browser.firefox_socket.Components.interfaces.nsIHttpChannel) && channel.respond_to?(:responseStatus)
|
807
842
|
end || raise(RuntimeError, "expected currentDocumentChannel to exist and be a nsIHttpChannel but it wasn't; was #{channel.is_a?(JavascriptObject) ? channel.toString : channel.inspect}")
|
808
|
-
|
843
|
+
channel
|
809
844
|
end
|
810
845
|
|
811
846
|
# Maximize the current browser window.
|
@@ -820,6 +855,7 @@ module Vapir
|
|
820
855
|
|
821
856
|
# Waits for the page to get loaded.
|
822
857
|
def wait(options={})
|
858
|
+
return unless config.wait
|
823
859
|
return unless exists?
|
824
860
|
unless options.is_a?(Hash)
|
825
861
|
raise ArgumentError, "given options should be a Hash, not #{options.inspect} (#{options.class})\nold conflicting arguments of no_sleep or last_url are gone"
|
@@ -833,9 +869,9 @@ module Vapir
|
|
833
869
|
# If the redirect is to a download attachment that does not reload this page, this
|
834
870
|
# method will loop forever. Therefore, we need to ensure that if this method is called
|
835
871
|
# twice with the same URL, we simply accept that we're done.
|
836
|
-
url= document_object
|
872
|
+
url= document_object['URL']
|
837
873
|
|
838
|
-
if(url != options[:last_url])
|
874
|
+
if(url && url != options[:last_url])
|
839
875
|
# check for meta redirects, except for redirects back to the same page (infinite
|
840
876
|
# loop redirects).
|
841
877
|
metas=document_object.getElementsByTagName 'meta'
|
@@ -876,7 +912,11 @@ module Vapir
|
|
876
912
|
# - :format => a valid format. if :dc is :window, the default is 'png' ('jpeg' is also supported); if :dc is anything else, 'bmp' is both the
|
877
913
|
# default and the only supported format.
|
878
914
|
def screen_capture(filename, options = {})
|
879
|
-
|
915
|
+
if filename =~ /\.(\w+)\z/
|
916
|
+
extension = $1
|
917
|
+
file_format = %w(jpeg png).inject({'jpg' => 'jpeg'}){|h,f| h.merge(f => f) }[extension]
|
918
|
+
end
|
919
|
+
options = handle_options(options, :format => file_format, :dc => :page)
|
880
920
|
|
881
921
|
if options[:dc] == :page
|
882
922
|
options[:format] ||= 'png'
|
@@ -929,9 +969,8 @@ module Vapir
|
|
929
969
|
fileOutputStream.init(nsFile, writeFlag | createFlag | truncateFlag, 0664, null);
|
930
970
|
fileOutputStream.write(bytes, numBytes);
|
931
971
|
fileOutputStream.close();
|
932
|
-
document_element.removeChild(canvas);
|
933
972
|
}
|
934
|
-
|
973
|
+
finally
|
935
974
|
{ document_element.removeChild(canvas);
|
936
975
|
}
|
937
976
|
)
|
@@ -984,10 +1023,19 @@ module Vapir
|
|
984
1023
|
raise NotImplementedError, "(need to know how to access windows registry on JRuby)" if RUBY_PLATFORM =~ /java/
|
985
1024
|
require 'win32/registry'
|
986
1025
|
lm = ::Win32::Registry::HKEY_LOCAL_MACHINE
|
987
|
-
lm.open('SOFTWARE\Mozilla\Mozilla Firefox') do |
|
988
|
-
|
989
|
-
|
990
|
-
|
1026
|
+
lm.open('SOFTWARE\Mozilla\Mozilla Firefox') do |firefox_reg|
|
1027
|
+
firefox_reg.keys.map do |firefox_version_key|
|
1028
|
+
firefox_reg.open(firefox_version_key) do |firefox_version_reg|
|
1029
|
+
if firefox_version_reg.keys.include?('Main')
|
1030
|
+
firefox_version_reg.open('Main') do |firefox_version_main_reg|
|
1031
|
+
firefox_version_main_reg.map do |key, type, data|
|
1032
|
+
if key=='PathToExe'
|
1033
|
+
return data
|
1034
|
+
end
|
1035
|
+
end
|
1036
|
+
end
|
1037
|
+
end
|
1038
|
+
end
|
991
1039
|
end
|
992
1040
|
end
|
993
1041
|
end
|
@@ -60,7 +60,7 @@ module Vapir
|
|
60
60
|
# TODO: Provide ability to specify event parameters like keycode for key events, and click screen
|
61
61
|
# coordinates for mouse events.
|
62
62
|
def fire_event(event_type, options={})
|
63
|
-
options={:wait =>
|
63
|
+
options={:wait => config.wait, :highlight => true}.merge(options)
|
64
64
|
with_highlight(options) do
|
65
65
|
event=create_event_object(event_type, options)
|
66
66
|
if !options[:wait]
|
@@ -159,10 +159,10 @@ module Vapir
|
|
159
159
|
# Options:
|
160
160
|
# - :wait => true or false. If true, waits for the javascript call to return, and calls the #wait method.
|
161
161
|
# If false, does not wait for the javascript to return and does not call #wait.
|
162
|
-
# Default is true.
|
162
|
+
# Default is the current config.wait value (which is by default true).
|
163
163
|
# - :highlight => true or false. Highlights the element while clicking if true. Default is true.
|
164
164
|
def click(options={})
|
165
|
-
options={:wait =>
|
165
|
+
options={:wait => config.wait, :highlight => true}.merge(options)
|
166
166
|
result=nil
|
167
167
|
with_highlight(options) do
|
168
168
|
assert_enabled if respond_to?(:assert_enabled)
|
@@ -196,12 +196,12 @@ module Vapir
|
|
196
196
|
# Takes options:
|
197
197
|
# - :highlight => true or false. Highlights the element while clicking if true. Default is true.
|
198
198
|
def click_no_wait(options={})
|
199
|
-
|
199
|
+
with_config(:wait => false) { click(options) }
|
200
200
|
end
|
201
201
|
|
202
202
|
# Waits for the browser to finish loading, if it is loading. See Firefox#wait.
|
203
203
|
def wait(options={})
|
204
|
-
@container.wait(options)
|
204
|
+
@container.wait(options) if config.wait
|
205
205
|
end
|
206
206
|
|
207
207
|
# Checks this element and its parents for display: none or visibility: hidden, these are
|
@@ -240,7 +240,7 @@ class FirefoxSocket
|
|
240
240
|
# immediately.
|
241
241
|
def read_value(options={})
|
242
242
|
options=options_from_config(options, {:timeout => :default_timeout, :read_size => :read_size}, [:length_before_value])
|
243
|
-
received_data = []
|
243
|
+
# received_data = []
|
244
244
|
value_string = ""
|
245
245
|
size_to_read=options[:read_size]
|
246
246
|
timeout=options[:timeout]
|
@@ -249,7 +249,13 @@ class FirefoxSocket
|
|
249
249
|
# logger.add(-1) { "RECV_SOCKET is starting. timeout=#{timeout}" }
|
250
250
|
while size_to_read > 0 && ensuring_extra_handled { @socket.ready_to_recv?(timeout) }
|
251
251
|
data = ensuring_extra_handled { @socket.recv(size_to_read) }
|
252
|
-
|
252
|
+
|
253
|
+
# if the peer has performed an orderly shutdown, recv returns a 0-length string.
|
254
|
+
if data.size==0
|
255
|
+
raise FirefoxSocketConnectionError, "The connection to Firefox has been closed."
|
256
|
+
end
|
257
|
+
|
258
|
+
# received_data << data
|
253
259
|
value_string << data
|
254
260
|
if @prompt && @expecting_prompt && utf8_length_safe(value_string) > @prompt.length
|
255
261
|
if value_string =~ /\A#{Regexp.escape(@prompt)}/
|
@@ -280,11 +286,6 @@ class FirefoxSocket
|
|
280
286
|
timeout=config.short_timeout
|
281
287
|
end
|
282
288
|
end
|
283
|
-
|
284
|
-
# Kernel.select seems to indicate that a dead socket is ready to read, and returns endless blank strings to recv. rather irritating.
|
285
|
-
if received_data.length >= 3 && received_data[-3..-1].all?{|rd| rd==''}
|
286
|
-
raise FirefoxSocketConnectionError, "Socket seems to no longer be connected"
|
287
|
-
end
|
288
289
|
# logger.add(-1) { "RECV_SOCKET is continuing. timeout=#{timeout}; data=#{data.inspect}" }
|
289
290
|
end
|
290
291
|
# logger.debug { "RECV_SOCKET is done. received_data=#{received_data.inspect}; value_string=#{value_string.inspect}" }
|
@@ -143,7 +143,7 @@ class JavascriptObject
|
|
143
143
|
def val_or_object(options={})
|
144
144
|
options={:error_on_undefined=>true, :define_methods => self.class.always_define_methods}.merge(options)
|
145
145
|
if function_result # calling functions multiple times is bad, so store in temp before figuring out what to do with it
|
146
|
-
|
146
|
+
store_rand_temp.val_or_object(options.merge(:error_on_undefined => false))
|
147
147
|
else
|
148
148
|
# if we don't know our type, stick everything into one call to avoid multiple socket calls
|
149
149
|
types_to_convert = ['boolean', 'number', 'string', 'null']
|
@@ -192,7 +192,7 @@ class JavascriptObject
|
|
192
192
|
end
|
193
193
|
end
|
194
194
|
# does the work of #method_missing to determine whether to call a function what to return based
|
195
|
-
# on the defined behavior of the given suffix. see #method_missing for more
|
195
|
+
# on the defined behavior of the given suffix. see #method_missing for more information.
|
196
196
|
def assign_or_call_or_val_or_object_by_suffix(suffix, *args)
|
197
197
|
if suffix=='='
|
198
198
|
assign(*args)
|
@@ -472,7 +472,9 @@ class JavascriptObject
|
|
472
472
|
# in irb, mostly.
|
473
473
|
def define_methods! # :nodoc:
|
474
474
|
metaclass=(class << self; self; end)
|
475
|
-
|
475
|
+
# the following needs the try/catch because sometimes it raises NS_ERROR_NOT_AVAILABLE: Component is not available
|
476
|
+
# bug: https://bugzilla.mozilla.org/show_bug.cgi?id=683978
|
477
|
+
keys=firefox_socket.object("function(obj) { var keys=[]; try { for(var key in obj) { keys.push(key); } } catch(e) {} return keys; }").pass(self).val
|
476
478
|
|
477
479
|
keys.grep(/\A[a-z_][a-z0-9_]*\z/i).reject{|k| self.class.method_defined?(k)}.each do |key|
|
478
480
|
metaclass.send(:define_method, key) do |*args|
|
@@ -545,6 +547,9 @@ class JavascriptObject
|
|
545
547
|
def to_function
|
546
548
|
JavascriptFunction.new(self.ref, self.firefox_socket, :debug_name => debug_name)
|
547
549
|
end
|
550
|
+
def to_simple_enumerator
|
551
|
+
JavascriptSimpleEnumerator.new(self.ref, self.firefox_socket, :debug_name => debug_name)
|
552
|
+
end
|
548
553
|
|
549
554
|
# returns a ruby Hash. each key/value pair of this object
|
550
555
|
# is represented in the returned hash.
|
@@ -649,6 +654,7 @@ class JavascriptDOMNode < JavascriptObject
|
|
649
654
|
# call #dump(:recurse => n) to recurse down only n levels. default is to recurse all the way down the dom tree.
|
650
655
|
def dump(options={})
|
651
656
|
options={:recurse => nil, :level => 0}.merge(options)
|
657
|
+
options[:document] ||= self.ownerDocument
|
652
658
|
next_options=options.merge(:recurse => options[:recurse] && (options[:recurse]-1), :level => options[:level]+1)
|
653
659
|
result=(" "*options[:level]*2)+self.inspect+"\n"
|
654
660
|
if options[:recurse]==0
|
@@ -657,6 +663,13 @@ class JavascriptDOMNode < JavascriptObject
|
|
657
663
|
self.childNodes.to_array.each do |child|
|
658
664
|
result+=child.to_dom.dump(next_options)
|
659
665
|
end
|
666
|
+
anons = self.nodeType == 1 && options[:document].getAnonymousNodes(self)
|
667
|
+
if anons
|
668
|
+
result+=(" "*next_options[:level]*2)+"ANONYMOUS:\n"
|
669
|
+
anons.to_array.each do |child|
|
670
|
+
result+=child.to_dom.dump(next_options)
|
671
|
+
end
|
672
|
+
end
|
660
673
|
end
|
661
674
|
result
|
662
675
|
end
|
@@ -734,3 +747,13 @@ class JavascriptFunction < JavascriptObject
|
|
734
747
|
end
|
735
748
|
end
|
736
749
|
end
|
750
|
+
|
751
|
+
class JavascriptSimpleEnumerator < JavascriptObject
|
752
|
+
def each
|
753
|
+
stored = store_rand_temp
|
754
|
+
while stored.hasMoreElements
|
755
|
+
yield stored.getNext
|
756
|
+
end
|
757
|
+
end
|
758
|
+
include Enumerable
|
759
|
+
end
|
@@ -51,7 +51,7 @@ module Vapir
|
|
51
51
|
# raise if no anonymous nodes are found (this is where the buttons are)
|
52
52
|
anonymous_dialog_nodes=@modal_window.document.getAnonymousNodes(@modal_window.document.documentElement) || raise("Could not find anonymous nodes on which to look for buttons")
|
53
53
|
xul_buttons=[]
|
54
|
-
anonymous_dialog_nodes.to_array.each do |node|
|
54
|
+
anonymous_dialog_nodes.to_array.select{|node| node.nodeType == 1 }.each do |node|
|
55
55
|
xul_buttons+=node.getElementsByTagName('xul:button').to_array.select do |button|
|
56
56
|
Vapir::fuzzy_match(button.label, button_text)
|
57
57
|
end
|
@@ -74,8 +74,8 @@ module Vapir
|
|
74
74
|
assert_exists
|
75
75
|
modal_window
|
76
76
|
end
|
77
|
-
def
|
78
|
-
'MozillaDialogClass'
|
77
|
+
def mozilla_window_class_names
|
78
|
+
['MozillaDialogClass']
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -134,7 +134,8 @@ module Vapir
|
|
134
134
|
end
|
135
135
|
|
136
136
|
def wait(options=nil)
|
137
|
-
|
137
|
+
return unless config.wait
|
138
|
+
::Waiter.try_for(config.wait_timeout) do
|
138
139
|
!browser_object.webProgress.isLoadingDocument
|
139
140
|
end
|
140
141
|
end
|
@@ -11,10 +11,12 @@ module Vapir
|
|
11
11
|
end
|
12
12
|
|
13
13
|
# evaluates a given javascript string in the context of the browser's content window. anything
|
14
|
-
# that is a top-level variable on the window will be seen as a
|
15
|
-
# evaluated script.
|
14
|
+
# that is a top-level variable on the window (such as document or alert) will be seen as a
|
15
|
+
# top-level variable in the evaluated script.
|
16
16
|
#
|
17
|
-
# returns the last evaluated expression.
|
17
|
+
# returns the last evaluated expression. WARNING! DO NOT RUN #execute_script AGAINST UNTRUSTED
|
18
|
+
# PAGES! the resulting value has no security wrappers and could execute malicious code in a
|
19
|
+
# privileged context.
|
18
20
|
#
|
19
21
|
# raises an error if the given javascript errors.
|
20
22
|
#
|
@@ -43,8 +45,17 @@ module Vapir
|
|
43
45
|
# >> browser.execute_script('element.PercentLoaded()', :element => browser.element(:tag_name => 'embed').element_object)
|
44
46
|
# => 100
|
45
47
|
def execute_script(javascript, other_variables={})
|
46
|
-
|
47
|
-
|
48
|
+
# TODO: add tests for cross-context expando properties
|
49
|
+
xpcNativeWrapper = firefox_socket.root['XPCNativeWrapper']
|
50
|
+
unwrapped_window = if xpcNativeWrapper.respond_to?('unwrap')
|
51
|
+
xpcNativeWrapper.unwrap(content_window_object)
|
52
|
+
elsif content_window_object.respond_to?('wrappedJSObject')
|
53
|
+
content_window_object.wrappedJSObject
|
54
|
+
else
|
55
|
+
content_window_object.window
|
56
|
+
end
|
57
|
+
sandbox=firefox_socket.Components.utils.Sandbox(unwrapped_window, :wantXrays => false)
|
58
|
+
sandbox.window = unwrapped_window
|
48
59
|
other_variables.each do |name, var|
|
49
60
|
sandbox[name]=var
|
50
61
|
end
|
data/lib/vapir-firefox/window.rb
CHANGED
@@ -18,7 +18,7 @@ module Vapir
|
|
18
18
|
begin
|
19
19
|
candidates=::Waiter.try_for(2, :condition => proc{|ret| ret.size > 0}, :exception => nil) do
|
20
20
|
WinWindow::All.select do |win|
|
21
|
-
|
21
|
+
mozilla_window_class_names.include?(win.class_name) && win.text==browser_window_object.document.title
|
22
22
|
end
|
23
23
|
end
|
24
24
|
unless candidates.size==1
|
metadata
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vapir-firefox
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash: 51
|
5
4
|
prerelease: false
|
6
5
|
segments:
|
7
6
|
- 1
|
8
|
-
-
|
7
|
+
- 10
|
9
8
|
- 0
|
10
|
-
version: 1.
|
9
|
+
version: 1.10.0
|
11
10
|
platform: ruby
|
12
11
|
authors:
|
13
12
|
- Ethan
|
@@ -15,34 +14,30 @@ autorequire:
|
|
15
14
|
bindir: bin
|
16
15
|
cert_chain: []
|
17
16
|
|
18
|
-
date: 2011-
|
17
|
+
date: 2011-09-28 00:00:00 -04:00
|
19
18
|
default_executable:
|
20
19
|
dependencies:
|
21
20
|
- !ruby/object:Gem::Dependency
|
22
21
|
name: vapir-common
|
23
22
|
prerelease: false
|
24
23
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
24
|
requirements:
|
27
25
|
- - "="
|
28
26
|
- !ruby/object:Gem::Version
|
29
|
-
hash: 51
|
30
27
|
segments:
|
31
28
|
- 1
|
32
|
-
-
|
29
|
+
- 10
|
33
30
|
- 0
|
34
|
-
version: 1.
|
31
|
+
version: 1.10.0
|
35
32
|
type: :runtime
|
36
33
|
version_requirements: *id001
|
37
34
|
- !ruby/object:Gem::Dependency
|
38
35
|
name: json
|
39
36
|
prerelease: false
|
40
37
|
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
38
|
requirements:
|
43
39
|
- - ">="
|
44
40
|
- !ruby/object:Gem::Version
|
45
|
-
hash: 3
|
46
41
|
segments:
|
47
42
|
- 0
|
48
43
|
version: "0"
|
@@ -109,27 +104,23 @@ rdoc_options:
|
|
109
104
|
require_paths:
|
110
105
|
- lib
|
111
106
|
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
-
none: false
|
113
107
|
requirements:
|
114
108
|
- - ">="
|
115
109
|
- !ruby/object:Gem::Version
|
116
|
-
hash: 3
|
117
110
|
segments:
|
118
111
|
- 0
|
119
112
|
version: "0"
|
120
113
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
114
|
requirements:
|
123
115
|
- - ">="
|
124
116
|
- !ruby/object:Gem::Version
|
125
|
-
hash: 3
|
126
117
|
segments:
|
127
118
|
- 0
|
128
119
|
version: "0"
|
129
120
|
requirements:
|
130
121
|
- Firefox browser with MozRepl or JSSH extension installed
|
131
122
|
rubyforge_project:
|
132
|
-
rubygems_version: 1.3.
|
123
|
+
rubygems_version: 1.3.6
|
133
124
|
signing_key:
|
134
125
|
specification_version: 3
|
135
126
|
summary: Library for automating the Firefox browser in Ruby
|