File Coverage

blib/lib/Test/WebDriver.pm
Criterion Covered Total %
statement 35 116 30.1
branch 1 42 2.3
condition 2 34 5.8
subroutine 11 22 50.0
pod 6 8 75.0
total 55 222 24.7


line stmt bran cond sub pod time code
1 2     2   28883 use strict;
  2         5  
  2         266  
2 2     2   14 use warnings;
  2         4  
  2         90  
3             package Test::WebDriver;
4 2     2   11 use base 'Selenium::Remote::Driver';
  2         13  
  2         3600  
5             # ABSTRACT: Useful testing subclass for Selenium WebDriver!
6              
7 2     2   619813 use Test::More;
  2         5  
  2         29  
8 2     2   662 use Test::Builder;
  2         4  
  2         61  
9 2     2   2363 use IO::Socket;
  2         26843  
  2         11  
10              
11             our $AUTOLOAD;
12              
13             my $Test = Test::Builder->new;
14             $Test->exported_to(__PACKAGE__);
15              
16             my %comparator = (
17             is => 'is_eq',
18             isnt => 'isnt_eq',
19             like => 'like',
20             unlike => 'unlike',
21             );
22             my $comparator_keys = join '|', keys %comparator;
23              
24             # These commands don't require a locator
25             my %no_locator = map { $_ => 1 }
26             qw( alert_text current_window_handle current_url
27             title page_source body location path);
28            
29             sub no_locator {
30 0     0 0 0 my $self = shift;
31 0         0 my $method = shift;
32 0         0 return $no_locator{$method};
33             }
34              
35             sub AUTOLOAD {
36 0     0   0 my $name = $AUTOLOAD;
37 0         0 $name =~ s/.*:://;
38 0 0       0 return if $name eq 'DESTROY';
39 0         0 my $self = $_[0];
40              
41 0         0 my $sub;
42 0 0       0 if ($name =~ /(\w+)_($comparator_keys)$/i) {
    0          
43 0         0 my $getter = "get_$1";
44 0         0 my $comparator = $comparator{lc $2};
45              
46             # make a subroutine that will call Test::Builder's test methods
47             # with driver data from the getter
48 0 0       0 if ($self->no_locator($1)) {
49             $sub = sub {
50 0     0   0 my( $self, $str, $name ) = @_;
51 0 0       0 diag "Test::WebDriver running no_locator $getter (@_[1..$#_])"
52             if $self->{verbose};
53 0 0 0     0 $name = "$getter, '$str'"
54             if $self->{default_names} and !defined $name;
55 2     2   2102 no strict 'refs';
  2         6  
  2         471  
56 0         0 my $rc = $Test->$comparator( $self->$getter, $str, $name );
57 0 0 0     0 if (!$rc && $self->error_callback) {
58 0         0 &{$self->error_callback}($name);
  0         0  
59             }
60 0         0 return $rc;
61 0         0 };
62             }
63             else {
64             $sub = sub {
65 0     0   0 my( $self, $locator, $str, $name ) = @_;
66 0 0       0 diag "Test::WebDriver running with locator $getter (@_[1..$#_])"
67             if $self->{verbose};
68 0 0 0     0 $name = "$getter, $locator, '$str'"
69             if $self->{default_names} and !defined $name;
70 2     2   11 no strict 'refs';
  2         4  
  2         59  
71 2     2   11 no strict 'refs';
  2         3  
  2         896  
72 0         0 my $rc = $Test->$comparator( $self->$getter($locator), $str, $name );
73 0 0 0     0 if (!$rc && $self->error_callback) {
74 0         0 &{$self->error_callback}($name);
  0         0  
75             }
76 0         0 return $rc;
77 0         0 };
78             }
79             }
80             elsif ($name =~ /(\w+?)_?ok$/i) {
81 0         0 my $cmd = $1;
82              
83             # make a subroutine for ok() around the selenium command
84             $sub = sub {
85 0     0   0 my( $self, $arg1, $arg2, $name ) = @_;
86 0 0 0     0 if ($self->{default_names} and !defined $name) {
87 0         0 $name = $cmd;
88 0 0       0 $name .= ", $arg1" if defined $arg1;
89 0 0       0 $name .= ", $arg2" if defined $arg2;
90             }
91 0 0       0 diag "Test::WebDriver running _ok $cmd (@_[1..$#_])"
92             if $self->{verbose};
93              
94 0         0 local $Test::Builder::Level = $Test::Builder::Level + 1;
95 0         0 my $rc = '';
96 0         0 eval { $rc = $self->$cmd( $arg1, $arg2 ) };
  0         0  
97 0 0 0     0 die $@ if $@ and $@ =~ /Can't locate object method/;
98 0 0       0 diag($@) if $@;
99 0         0 $rc = ok( $rc, $name );
100 0 0 0     0 if (!$rc && $self->error_callback) {
101 0         0 &{$self->error_callback}($name);
  0         0  
102             }
103 0         0 return $rc;
104 0         0 };
105             }
106              
107             # jump directly to the new subroutine, avoiding an extra frame stack
108 0 0       0 if ($sub) {
109 2     2   28 no strict 'refs';
  2         4  
  2         1211  
110 0         0 *{$AUTOLOAD} = $sub;
  0         0  
111 0         0 goto &$AUTOLOAD;
112             }
113             else {
114             # try to pass through to Selenium::Remote::Driver
115 0         0 my $sel = 'Selenium::Remote::Driver';
116 0         0 my $sub = "${sel}::${name}";
117 0 0       0 goto &$sub if exists &$sub;
118 0         0 my ($package, $filename, $line) = caller;
119 0         0 die qq(Can't locate object method "$name" via package ")
120             . __PACKAGE__
121             . qq(" (also tried "$sel") at $filename line $line\n);
122             }
123             }
124              
125             sub error_callback {
126 0     0 0 0 my ($self, $cb) = @_;
127 0 0       0 if (defined($cb)) {
128 0         0 $self->{error_callback} = $cb;
129             }
130 0         0 return $self->{error_callback};
131             }
132              
133             =head2 new ( %opts )
134              
135             This will create a new Test::WebDriver object, which subclasses
136             L. This subclass provides useful testing
137             functions. It is modeled on L.
138              
139             Environment vars can be used to specify options to pass to
140             L. ENV vars are prefixed with C.
141              
142             Set the Selenium server address with C<$TWD_HOST> and C<$TWD_PORT>.
143              
144             Pick which browser is used using the C<$TWD_BROWSER>, C<$TWD_VERSION>,
145             C<$TWD_PLATFORM>, C<$TWD_JAVASCRIPT>, C<$TWD_EXTRA_CAPABILITIES>.
146              
147             See L for the meanings of these options.
148              
149             =cut
150              
151             sub new {
152 0     0 1 0 my ($class, %p) = @_;
153              
154 0         0 for my $opt (qw/remote_server_addr port browser_name version platform
155             javascript auto_close extra_capabilities/) {
156 0   0     0 $p{$opt} ||= $ENV{ 'TWD_' . uc($opt) };
157             }
158 0   0     0 $p{browser_name} ||= $ENV{TWD_BROWSER}; # ykwim
159 0   0     0 $p{remote_server_addr} ||= $ENV{TWD_HOST}; # ykwim
160              
161 0         0 my $self = $class->SUPER::new(%p);
162 0         0 $self->{verbose} = $p{verbose};
163 0         0 return $self;
164             }
165              
166             =head2 server_is_running( $host, $port )
167              
168             Returns true if a Selenium server is running. The host and port
169             parameters are optional, and default to C.
170              
171             Environment vars C and C can also be used to
172             determine the server to check.
173              
174             =cut
175              
176             sub server_is_running {
177 1     1 1 13 my $class_or_self = shift;
178 1   50     14 my $host = $ENV{TWD_HOST} || shift || 'localhost';
179 1   50     15 my $port = $ENV{TWD_PORT} || shift || 4444;
180              
181 1 50       15 return ($host, $port) if IO::Socket::INET->new(
182             PeerAddr => $host,
183             PeerPort => $port,
184             );
185 1         1433 return;
186              
187             }
188              
189              
190             =head2 Glue Code
191              
192             Below here are some methods that make things less easier or less wordy.
193              
194             =head3 get_text
195              
196             Get the text of a particular element. Wrapper around find_element()
197              
198             =cut
199              
200             sub get_text {
201 0     0 1   my $self = shift;
202 0           return $self->find_element(@_)->get_text();
203             }
204              
205             =head3 get_body
206              
207             Get the current text for the whole body.
208              
209             =cut
210              
211             sub get_body {
212 0     0 1   my $self = shift;
213 0           return $self->get_text('//body');
214             }
215              
216             =head3 get_location
217              
218             Get the current URL.
219              
220             =cut
221              
222             sub get_location {
223 0     0 1   return shift->get_current_url();
224             }
225              
226             =head3 get_location
227              
228             Get the path part of the current browser location.
229              
230             =cut
231              
232             sub get_path {
233 0     0 1   my $self = shift;
234 0           my $location = $self->get_location;
235 0           $location =~ s/\?.*//; # strip of query params
236 0           $location =~ s/#.*//; # strip of anchors
237 0           $location =~ s#^https?://[^/]+##; # strip off host
238 0           return $location;
239             }
240              
241             1;
242              
243             __END__