Ver código fonte

Added more docs

Emmanuel Peroumalnaik 11 anos atrás
pai
commit
9d6f5441b4

+ 12 - 0
lib/Selenium/Remote/Mock/Commands.pm

@@ -1,5 +1,7 @@
 package Selenium::Remote::Mock::Commands; 
+
 # ABSTRACT: utility class to mock Selenium::Remote::Commands 
+#
 use Moo; 
 extends 'Selenium::Remote::Commands';
 
@@ -33,3 +35,13 @@ sub get_method_name_from_parameters {
 }
 
 1;
+
+__END__
+
+=pod
+
+=head1 DESCRIPTION
+
+Utility class to be for testing purposes, with L<Selenium::Remote::Mock::RemoteConnection> only.
+
+=cut

+ 129 - 2
lib/Selenium/Remote/Mock/RemoteConnection.pm

@@ -96,7 +96,7 @@ sub dump_session_store {
     }
     my $json = JSON->new;
     $json->allow_blessed;
-    my $json_session = $json->allow_nonref->utf8->encode($dump);
+    my $json_session = $json->allow_nonref->utf8->pretty->encode($dump);
     print $fh $json_session; 
     close ($fh);
 }
@@ -193,6 +193,7 @@ __END__
 
 Selenium::Remote::Mock::RemoteConnection is a class to act as a short-circuit or a pass through to the connection to a Selenium Server. 
 Using this class in place of L<Selenium::Remote::RemoteConnection> allows to: 
+
 =over
 
 =item *
@@ -209,11 +210,137 @@ mock responses to specific functions
 =head1 SYNOPSIS
 
 =head2 Record interactions 
-
     
+    #!perl
+    use strict;
+    use warnings;
+    use Selenium::Remote::Driver;
+    use Selenium::Remote::Mock::RemoteConnection;
+
+    # create a new Mock object to record the interactions with Selenium
+    # Server
+    my $mock_connection = Selenium::Remote::Mock::RemoteConnection->new( record => 1 );
+
+    # the Mock object is passed to the driver in place of what would be
+    # a regular Selenium::Remote::RemoteConnection object
+    my $driver = Selenium::Remote::Driver->new( remote_conn => $mock_connection );
+
+    # always store the session id, as it will become undef once
+    # $driver->quit is called  
+    my $session_id = $driver->session_id;
+
+    # do all the selenium things and quit
+    $driver->get('http://www.google.com');
+    $driver->get('http://www.wikipedia.com');
+    $driver->quit;
+
+    # dump the session to a file
+    $mock_connection->dump_session_store( 'my_record.json', $session_id );
+
+
+This code, above doing some basic Selenium interactions, will end up generating a JSON file containing all the requests and their responses for your Selenium session. 
+The JSON file looks like this : 
+
+    { 
+        "HTTP_REQUEST URL {request_parameters}":[ARRAY_OF_RESPONSES]
+        ...
+    }
+
+The reason why we store array of responses is that the exact same request can be make more than once during a session, so we have to store every response to the same requests.
 
 =head2 Replay interactions
 
+    #!perl
+    use strict;
+    use warnings;
+    use Test::More;
+    use Test::Selenium::Remote::Driver;
+    use Selenium::Remote::Mock::RemoteConnection; 
+    my $mock_connection_2 =
+      Selenium::Remote::Mock::RemoteConnection->new( replay => 1,
+        replay_file => 'my_record.json' );
+    # javascript + version parameters added or else it will not work 
+    my $driver =
+      Test::Selenium::Remote::Driver->new( remote_conn => $mock_connection_2, javascript => 1, version => '' );
+    $driver->get_ok('http://www.google.com');
+    $driver->get_ok('http://www.wikipedia.com');
+    $driver->quit;
+    done_testing;
+
+Using the file generated with the recording snippet from the section before, we are able to mock the responses. 
+
+Note that there is one small limitation (that I hope to remove in future versions), is that a record generated with L<Selenium::Remote::Driver> is not directly useable with L<Test::Selenium::Remote::Driver>.
+This is mainly because the way the two instances are created are a bit different, which leads to different requests made, for creating a session for instance. 
+For now, what works for sure is recording and replaying from the same class.
+
 =head2 Mock responses
 
+    
+    #!perl
+    use Test::More;
+    use Test::Selenium::Remote::Driver;
+    use Selenium::Remote::WebElement;
+    use Selenium::Remote::Mock::Commands;
+    use Selenium::Remote::Mock::RemoteConnection;
+
+    my $spec = {
+        findElement => sub {
+            my (undef,$searched_item) = @_;
+            return { status => 'OK', return => { ELEMENT => '123456' } }
+              if ( $searched_item->{value} eq 'q' );
+            return { status => 'NOK', return => 0, error => 'element not found' };
+        },
+        getPageSource => sub { return 'this output matches regex'},
+    };
+    my $mock_commands = Selenium::Remote::Mock::Commands->new;
+
+    my $successful_driver =
+      Test::Selenium::Remote::Driver->new(
+        remote_conn => Selenium::Remote::Mock::RemoteConnection->new( spec => $spec, mock_cmds => $mock_commands ),
+        commands => $mock_commands,
+    );
+    $successful_driver->find_element_ok('q','find_element_ok works');
+    dies_ok { $successful_driver->find_element_ok('notq') } 'find_element_ok dies if element not found';
+    $successful_driver->find_no_element_ok('notq','find_no_element_ok works');
+    $successful_driver->content_like( qr/matches/, 'content_like works');
+    $successful_driver->content_unlike( qr/nomatch/, 'content_unlike works');
+
+    done_testing();
+
+Mocking responses by hand requires a more advanced knowledge of the underlying implementation of L<Selenium::Remote::Driver>. 
+What we mock here is the processed response that will be returned by L<Selenium::Remote::RemoteConnection> to '_execute_command' call.
+To accomplish this we need : 
+
+=over
+
+=item *
+a spec: a HASHREF which keys are the name of the methods we want to mock. Note that those keys should also be valid keys from the _cmds attribute in L<Selenium::Remote::Command>.
+The value of each key is a sub which will be given two parameters: 
+
+=over 
+
+=item * 
+$url_params : the values that should have been replaced in the URL 
+For instance, on the example above, it would have been:
+    { session_id => 'some_session_id'}
+
+=item * 
+$params : the original parameters of the request.
+On the example above it would have been: 
+    { value => 'q', using => 'xpath'}
+
+
+=back
+
+The sub used as a value in the spec is not expected to return anything, so you have to craft very carefully what you return so that it will produce the expected result.
+
+=item * 
+a mock_cmd: a L<Selenium::Remote::Mock::Commands> object. This is used mainly to hijack the normal commands so that placeholders do not get replaced in the URLs.
+
+=back
+
+=head1 BUGS 
+
+This code is really early alpha, so its API might change. Use with caution !
+
 =cut

+ 1 - 0
lib/Test/Selenium/Remote/Driver.pm

@@ -1,4 +1,5 @@
 package Test::Selenium::Remote::Driver;
+
 # ABSTRACT: Useful testing subclass for Selenium::Remote::Driver
 
 use Moo;