瀏覽代碼

Close #69 : new() now accepts a webelement_class option

This is used to set an alternate WebElement class. Test::WebDriver is a
particular use-case that is in mind, since it will now have a clean way
to add testing methods to web elements.

Tested manually with and without passing the option.
Mark Stosberg 12 年之前
父節點
當前提交
d38a367a9f
共有 2 個文件被更改,包括 30 次插入19 次删除
  1. 4 1
      Changes
  2. 26 18
      lib/Selenium/Remote/Driver.pm

+ 4 - 1
Changes

@@ -12,11 +12,14 @@ Revision history for Selenium-Remote-Driver
         - Added a pause() function, that sleeps for the given number of milliseconds, just like
           Test::WWW::Selenium.  https://github.com/aivaturi/Selenium-Remote-Driver/issues/60
 
-        - new() now accepts a 'default_finder' option to allow to you change the default finder, which
+        - new() now accepts a 'default_finder' option to allow you to change the default finder, which
           is currently 'xpath'. This will be of interest to those who prefer CSS-style selectors,
           such as jQuery uses.
            https://github.com/aivaturi/Selenium-Remote-Driver/pull/49
 
+        - new() now accepts a 'webelement_class' option to allow you to specify an alternate WebElement class.
+          This could be used to add testing methods or functionality for WebElements.  
+
         [DOCUMENTATION]
         - Updated ChangeLog to reflect that debug_on() and debug_off() methods were added in 0.16.
 

+ 26 - 18
lib/Selenium/Remote/Driver.pm

@@ -12,7 +12,7 @@ our @CARP_NOT;
 
 use MIME::Base64;
 use IO::Compress::Zip qw(zip $ZipError) ;
-
+use Scalar::Util;
 use Selenium::Remote::RemoteConnection;
 use Selenium::Remote::Commands;
 use Selenium::Remote::WebElement;
@@ -82,7 +82,7 @@ nothing was returned by the method.
 =head2 WebElement
 
 Selenium Webdriver represents all the HTML elements as WebElement, which is
-in turn represented by Selenium::Remote::WebElement module. So any method that
+in turn represented by L<Selenium::Remote::WebElement> module. So any method that
 deals with WebElements will return and/or expect WebElement object. The POD for
 that module describes all the methods that perform various actions on the
 WebElements like click, submit etc.
@@ -94,6 +94,13 @@ your further actions will fail for that element. Finally, just remember that you
 don't have to instantiate WebElement objects at all - they will be automatically
 created when you use the find_* methods.
 
+A sub-class of Selenium::Remote::WebElement may be used instead of Selenium::Remote::WebElement,
+by providing that class name as an option the constructor:
+
+   my $driver = Selenium::Remote::Driver->new( webelement_class => ... );
+
+For example, a testing-subclass may extend the web-element object with testing methods.
+
 =cut
 
 =head1 FUNCTIONS
@@ -118,6 +125,7 @@ created when you use the find_* methods.
         'auto_close'           - <boolean>  - whether driver should end session on remote server on close.
         'default_finder'       - <string>   - choose default finder used for find_element* {class|class_name|css|id|link|link_text|name|partial_link_text|tag_name|xpath}
         'extra_capabilities'   - HASH of extra capabilities
+        'webelement_class'     - <string>   - sub-class of Selenium::Remote::WebElement if you wish to use an alternate WebElement class. 
         'proxy'                - HASH       - Proxy configuration with the following keys:
             'proxyType' - <string> - REQUIRED, Possible values are:
                 direct     - A direct connection                                                                    - no proxy in use,
@@ -178,6 +186,7 @@ sub new {
         platform           => delete $args{platform}                  || 'ANY',
         port               => delete $args{port}                      || '4444',
         version            => delete $args{version}                   || '',
+        webelement_class   => delete $args{webelement_class}          || "Selenium::Remote::WebElement",
         default_finder     => FINDERS->{delete $args{default_finder}  || 'xpath'},
         session_id         => undef,
         remote_conn        => undef,
@@ -992,7 +1001,7 @@ sub execute_async_script {
         # Check the args array if the elem obj is provided & replace it with
         # JSON representation
         for (my $i=0; $i<@args; $i++) {
-            if (ref $args[$i] eq 'Selenium::Remote::WebElement') {
+            if (Scalar::Util::blessed($args[$i]) and $args[$i]->isa('Selenium::Remote::WebElement')) {
                 $args[$i] = {'ELEMENT' => ($args[$i])->{id}};
             }
         }
@@ -1002,9 +1011,7 @@ sub execute_async_script {
 
         # replace any ELEMENTS with WebElement
         if (ref($ret) and (ref($ret) eq 'HASH') and exists $ret->{'ELEMENT'}) {
-            $ret =
-                new Selenium::Remote::WebElement(
-                                        $ret->{ELEMENT}, $self);
+            $ret = $self->{webelement_class}->new($ret->{ELEMENT}, $self);
         }
         return $ret;
     }
@@ -1052,7 +1059,7 @@ sub execute_script {
         # Check the args array if the elem obj is provided & replace it with
         # JSON representation
         for (my $i=0; $i<@args; $i++) {
-            if (ref $args[$i] eq 'Selenium::Remote::WebElement') {
+            if (Scalar::Util::blessed($args[$i]) and $args[$i]->isa('Selenium::Remote::WebElement')) {
                 $args[$i] = {'ELEMENT' => ($args[$i])->{id}};
             }
         }
@@ -1077,7 +1084,7 @@ sub _convert_to_webelement {
     if (ref($ret) and (ref($ret) eq 'HASH')) {
         if((keys %$ret==1) and exists $ret->{'ELEMENT'}) {
             # replace an ELEMENT with WebElement
-            return new Selenium::Remote::WebElement($ret->{ELEMENT}, $self);
+            return $self->{webelement_class}->new($ret->{ELEMENT}, $self);
         }
 
         my %hash;
@@ -1167,7 +1174,7 @@ sub switch_to_frame {
     $id = ( defined $id ) ? $id : $json_null;
 
     my $res    = { 'command' => 'switchToFrame' };
-    if (ref $id eq 'Selenium::Remote::WebElement') {
+    if (ref $id eq $self->{webelement_class}) {
         $params = { 'id' => {'ELEMENT' => $id->{'id'}}};
     } else {
         $params = { 'id'      => $id };
@@ -1470,6 +1477,7 @@ sub get_page_source {
 
  Output:
     Selenium::Remote::WebElement - WebElement Object
+        (This could be a subclass of L<Selenium::Remote::WebElement> if C<webelement_class> was set.
 
  Usage:
     $driver->find_element("//input[\@name='q']");
@@ -1497,7 +1505,7 @@ sub find_element {
             die $@;
           }
         }
-        return new Selenium::Remote::WebElement($ret_data->{ELEMENT}, $self);
+        return $self->{webelement_class}->new($ret_data->{ELEMENT}, $self);
     }
     else {
         croak "Bad method, expected - class, class_name, css, id, link,
@@ -1521,7 +1529,7 @@ sub find_element {
                  Defaults to 'xpath' if not configured global during instantiation.
 
  Output:
-    ARRAY of Selenium::Remote::WebElement - Array of WebElement Objects
+    ARRAY of WebElement Objects
 
  Usage:
     $driver->find_elements("//input");
@@ -1553,7 +1561,7 @@ sub find_elements {
         }
         my @elem_obj_arr = ();
         foreach (@$ret_data) {
-          push(@elem_obj_arr, new Selenium::Remote::WebElement($_->{ELEMENT}, $self));
+          push(@elem_obj_arr, $self->{webelement_class}->new($_->{ELEMENT}, $self));
         }
         return @elem_obj_arr;
     }
@@ -1585,7 +1593,7 @@ sub find_elements {
                  Defaults to 'xpath' if not configured global during instantiation.
 
  Output:
-    Selenium::Remote::WebElement - WebElement Object
+    WebElement Object
 
  Usage:
     my $elem1 = $driver->find_element("//select[\@name='ned']");
@@ -1615,7 +1623,7 @@ sub find_child_element {
             die $@;
           }
         }
-        return new Selenium::Remote::WebElement($ret_data->{ELEMENT}, $self);
+        return $self->{webelement_class}->new($ret_data->{ELEMENT}, $self);
     }
     else {
         croak "Bad method, expected - class, class_name, css, id, link,
@@ -1642,7 +1650,7 @@ sub find_child_element {
                  Defaults to 'xpath' if not configured global during instantiation.
 
  Output:
-    ARRAY of Selenium::Remote::WebElement - Array of WebElement Objects.
+    ARRAY of WebElement Objects.
 
  Usage:
     my $elem1 = $driver->find_element("//select[\@name='ned']");
@@ -1674,7 +1682,7 @@ sub find_child_elements {
         my $elem_obj_arr;
         my $i = 0;
         foreach (@$ret_data) {
-            $elem_obj_arr->[$i] = new Selenium::Remote::WebElement($_->{ELEMENT}, $self);
+            $elem_obj_arr->[$i] = $self->{webelement_class}->new($_->{ELEMENT}, $self);
             $i++;
         }
         return wantarray?@{$elem_obj_arr}:$elem_obj_arr;
@@ -1692,7 +1700,7 @@ sub find_child_elements {
     will be returned as a WebElement object.
 
  Output:
-    Selenium::Remote::WebElement - WebElement Object
+    WebElement Object
 
  Usage:
     $driver->get_active_element();
@@ -1706,7 +1714,7 @@ sub get_active_element {
     if ($@) {
         croak $@;
     } else {
-        return new Selenium::Remote::WebElement($ret_data->{ELEMENT}, $self);
+        return $self->{webelement_class}->new($ret_data->{ELEMENT}, $self);
     }
 }