File Coverage

blib/lib/Test/Selenium/Remote/Role/DoesTesting.pm
Criterion Covered Total %
statement 85 92 92.3
branch 25 28 89.2
condition 2 3 66.6
subroutine 16 18 88.8
pod n/a
total 128 141 90.7


line stmt bran cond sub pod time code
1             package Test::Selenium::Remote::Role::DoesTesting;
2             $Test::Selenium::Remote::Role::DoesTesting::VERSION = '1.49';
3             # ABSTRACT: Role to cope with everything that is related to testing (could
4             # be reused in both testing classes)
5              
6 7     7   40141 use Moo::Role;
  7         17  
  7         50  
7 7     7   3128 use Test::Builder;
  7         56918  
  7         202  
8 7     7   1553 use Try::Tiny;
  7         4128  
  7         425  
9 7     7   53 use Scalar::Util 'blessed';
  7         26  
  7         355  
10 7     7   46 use List::Util qw/any/;
  7         17  
  7         714  
11 7     7   2388 use namespace::clean;
  7         52469  
  7         52  
12              
13             requires qw(func_list has_args);
14              
15             has _builder => (
16             is => 'lazy',
17 18     18   624 builder => sub { return Test::Builder->new() },
18             handles => [qw/is_eq isnt_eq like unlike ok croak/],
19             );
20              
21             # get back the key value from an already coerced finder (default finder)
22              
23             sub _get_finder_key {
24 9     9   75 my $self = shift;
25 9         15 my $finder_value = shift;
26              
27 9         15 foreach my $k ( keys %{ $self->FINDERS } ) {
  9         42  
28 57 100       164 return $k if ( $self->FINDERS->{$k} eq $finder_value );
29             }
30              
31 0         0 return;
32             }
33              
34             # main method for non ok tests
35              
36             sub _check_method {
37 28     28   50 my $self = shift;
38 28         58 my $method = shift;
39 28         45 my $method_to_test = shift;
40 28         68 $method = "get_$method";
41 28         80 my @args = @_;
42 28         43 my $rv;
43             try {
44 28     28   1295 my $num_of_args = $self->has_args($method);
45 28         91 my @r_args = splice( @args, 0, $num_of_args );
46 28         193 $rv = $self->$method(@r_args);
47             }
48             catch {
49 0     0   0 $self->croak($_);
50 28         215 };
51              
52 28         916 return $self->$method_to_test( $rv, @args );
53             }
54              
55             # main method for _ok tests
56             # a bit hacked so that find_no_element_ok can also be processed
57              
58             sub _check_ok {
59 31     31   63 my $self = shift;
60 31         59 my $method = shift;
61              
62 31         97 my @args = @_;
63 31         53 my ( $rv, $num_of_args, @r_args );
64             try {
65 31     31   1538 $num_of_args = $self->has_args($method);
66 31         113 @r_args = splice( @args, 0, $num_of_args );
67 31 100       133 if ( $method =~ m/^find(_no|_child)?_element/ ) {
68              
69             # case find_element_ok was called with no arguments
70 10 50       28 if ( scalar(@r_args) - $num_of_args == 1 ) {
71 0         0 push @r_args, $self->_get_finder_key( $self->default_finder );
72             }
73             else {
74 10 100       23 if ( scalar(@r_args) == $num_of_args ) {
75              
76             # case find_element was called with no finder but
77             # a test description
78 8         18 my $finder = $r_args[ $num_of_args - 1 ];
79 8         10 my @FINDERS = keys( %{ $self->FINDERS } );
  8         43  
80 8 100       45 unless ( any { $finder eq $_ } @FINDERS ) {
  71         115  
81 4         96 $r_args[ $num_of_args - 1 ] =
82             $self->_get_finder_key( $self->default_finder );
83 4         13 push @args, $finder;
84             }
85             }
86             }
87             }
88              
89             # quick hack to fit 'find_no_element' into check_ok logic
90 31 100       132 if ( $method eq 'find_no_element' ) {
91             # If we use `find_element` and find nothing, the error
92             # handler is incorrectly invoked. Doing a `find_elements`
93             # and checking that it returns an empty array does not
94             # invoke the error_handler. See
95             # https://github.com/gempesaw/Selenium-Remote-Driver/issues/253
96 3         12 my $elements = $self->find_elements(@r_args);
97 1 50       3 if ( @{$elements} ) {
  1         4  
98 1         4 $rv = $elements->[0];
99             }
100             else {
101 0         0 $rv = 1; # empty list means success
102             }
103             }
104             else {
105 28         232 $rv = $self->$method(@r_args); # a true $rv means success
106             }
107             }
108             catch {
109 4 100   4   65 if ($method eq 'find_no_element') {
110 2         7 $rv = 1; # an exception from find_elements() means success
111             }
112             else {
113 2         48 $self->croak($_);
114             }
115 31         268 };
116              
117             # test description might have been explicitly passed
118 29         627 my $test_name = pop @args;
119              
120             # generic test description when no explicit test description was passed
121 29 100       94 if ( ! defined $test_name ) {
122             $test_name = $num_of_args > 0 ?
123 15 100       69 join( ' ', $method, map { q{'$_'} } @r_args )
  10         44  
124             :
125             $method;
126             }
127              
128             # case when find_no_element found an element, we should croak
129 29 100       100 if ( $method eq 'find_no_element' ) {
130 3 100 66     22 if ( blessed($rv) && $rv->isa('Selenium::Remote::WebElement') ) {
131 1         22 $self->croak($test_name);
132             }
133             }
134              
135 28         626 return $self->ok( $rv, $test_name );
136             }
137              
138             # build the subs with the correct arg set
139              
140             sub _build_sub {
141 381     381   667 my $self = shift;
142 381         576 my $meth_name = shift;
143              
144             # e.g. for $meth_name = 'find_no_element_ok':
145             # $meth_comp = 'ok'
146             # $meth_without_comp = 'find_no_element'
147 381         1035 my @meth_elements = split '_', $meth_name;
148 381         703 my $meth_comp = pop @meth_elements;
149 381         928 my $meth_without_comp = join '_', @meth_elements;
150              
151             # handle the ok testing methods
152 381 100       815 if ( $meth_comp eq 'ok' ) {
153             return sub {
154 31     31   10697 my $self = shift;
155              
156 31         113 local $Test::Builder::Level = $Test::Builder::Level + 2;
157              
158 31         115 return $self->_check_ok($meth_without_comp, @_);
159 135         659 };
160             }
161              
162             # find the Test::More comparator method
163 246         765 my %comparators = (
164             is => 'is_eq',
165             isnt => 'isnt_eq',
166             like => 'like',
167             unlike => 'unlike',
168             );
169              
170             # croak on unknown comparator methods
171 246 50       549 if ( ! exists $comparators{$meth_comp} ) {
172             return sub {
173 0     0   0 my $self = shift;
174              
175 0         0 return $self->croak("Sub $meth_name could not be defined");
176 0         0 };
177             }
178              
179             # handle check in _check_method()
180             return sub {
181 28     28   12454 my $self = shift;
182              
183 28         84 local $Test::Builder::Level = $Test::Builder::Level + 2;
184              
185 28         94 return $self->_check_method( $meth_without_comp, $comparators{$meth_comp}, @_ );
186 246         1122 };
187             }
188              
189             1;
190              
191             =head1 NAME
192              
193             Selenium::Remote::Role::DoesTesting - Role implementing the common logic used for testing
194              
195             =cut