File Coverage

blib/lib/Test/Selenium/Remote/Driver.pm
Criterion Covered Total %
statement 183 224 81.7
branch 58 122 47.5
condition 32 69 46.3
subroutine 26 27 96.3
pod 16 19 84.2
total 315 461 68.3


line stmt bran cond sub pod time code
1             package Test::Selenium::Remote::Driver;
2             $Test::Selenium::Remote::Driver::VERSION = '1.48';
3             # ABSTRACT: Useful testing subclass for Selenium::Remote::Driver
4              
5 7     7   300627 use Moo;
  7         45612  
  7         41  
6 7     7   9865 use Test::Selenium::Remote::WebElement;
  7         27  
  7         339  
7 7     7   3753 use Test::LongString;
  7         16959  
  7         44  
8 7     7   3768 use IO::Socket;
  7         122675  
  7         42  
9 7     7   3463 use Sub::Install;
  7         18  
  7         137  
10 7     7   249 use Try::Tiny;
  7         70  
  7         19622  
11              
12             extends 'Selenium::Remote::Driver';
13              
14             # move_mouse_to_location_ok # TODO # move_to_ok # TODO
15             has func_list => (
16             is => 'lazy',
17             builder => sub {
18             return [
19 9     9   239 'alert_text_is', 'alert_text_isnt',
20             'alert_text_like', 'alert_text_unlike',
21             'current_window_handle_is', 'current_window_handle_isnt',
22             'current_window_handle_like', 'current_window_handle_unlike',
23             'window_handles_is', 'window_handles_isnt',
24             'window_handles_like', 'window_handles_unlike',
25             'window_size_is', 'window_size_isnt',
26             'window_size_like', 'window_size_unlike',
27             'window_position_is', 'window_position_isnt',
28             'window_position_like', 'window_position_unlike',
29             'current_url_is', 'current_url_isnt',
30             'current_url_like', 'current_url_unlike',
31             'title_is', 'title_isnt',
32             'title_like', 'title_unlike',
33             'active_element_is', 'active_element_isnt',
34             'active_element_like', 'active_element_unlike',
35             'send_keys_to_active_element_ok', 'send_keys_to_alert_ok',
36             'send_keys_to_prompt_ok', 'send_modifier_ok',
37             'accept_alert_ok', 'dismiss_alert_ok',
38             'get_ok', 'go_back_ok',
39             'go_forward_ok', 'add_cookie_ok',
40             'get_page_source_ok', 'find_element_ok',
41             'find_elements_ok', 'find_child_element_ok',
42             'find_child_elements_ok', 'find_no_element_ok',
43             'compare_elements_ok', 'click_ok',
44             'double_click_ok', 'body_like',
45             ];
46             },
47             );
48              
49             =for Pod::Coverage has_args
50              
51             =cut
52              
53             sub has_args {
54 27     27 0 58 my $self = shift;
55 27         65 my $fun_name = shift;
56 27         159 my $hash_fun_args = {
57             'find_element' => 2,
58             'find_no_element' => 2,
59             'find_child_element' => 3,
60             'find_child_elements' => 3,
61             'find_element' => 2,
62             'find_elements' => 2,
63             'compare_elements' => 2,
64             'get' => 1,
65             };
66 27   100     171 return ( $hash_fun_args->{$fun_name} // 0 );
67             }
68              
69             with 'Test::Selenium::Remote::Role::DoesTesting';
70              
71             =for Pod::Coverage BUILD
72              
73             =cut
74              
75             sub BUILD {
76 9     9 0 294 my $self = shift;
77 9         22 foreach my $method_name ( @{ $self->func_list } ) {
  9         256  
78 468 100       15910 unless ( defined( __PACKAGE__->can($method_name) ) ) {
79 312         975 my $sub = $self->_build_sub($method_name);
80 312         1150 Sub::Install::install_sub(
81             {
82             code => $sub,
83             into => __PACKAGE__,
84             as => $method_name
85             }
86             );
87             }
88             }
89             }
90              
91             =head1 NAME
92              
93             Test::Selenium::Remote::Driver - add testing methods to L
94              
95             =head1 DESCRIPTION
96              
97             A subclass of L which provides useful testing
98             methods.
99              
100             This is an I addition to the Selenium::Remote::Driver
101             distribution. Some interfaces may change.
102              
103             =head1 Methods
104              
105             =head2 new ( %opts )
106              
107             This will create a new Test::Selenium::Remote::Driver object, which subclasses
108             L. This subclass provides useful testing
109             functions. It is modeled on L.
110              
111             Environment vars can be used to specify options to pass to
112             L. ENV vars are prefixed with C.
113             ( After the old fork name, "Test::WebDriver" ). The explicity passed
114             options have precedence. ENV vars take only effect when they are
115             actually set. This important e.g. for the option C, which
116             is turned on per default in L.
117              
118             Set the Selenium server address with C<$TWD_HOST> and C<$TWD_PORT>.
119              
120             Pick which browser is used using the C<$TWD_BROWSER>, C<$TWD_VERSION>,
121             C<$TWD_PLATFORM>, C<$TWD_JAVASCRIPT>, C<$TWD_EXTRA_CAPABILITIES>.
122              
123             C<$TWD_BROWSER> is actually an alias for C<$TWD_BROWSER_NAME>.
124             C<$TWD_HOST> is actually an alias for C<$TWD_REMOTE_SERVER_ADDR>.
125             The aliases habe lower precedence than the original values.
126              
127             See L for the meanings of these options.
128              
129             =for Pod::Coverage BUILDARGS
130              
131             =cut
132              
133             sub BUILDARGS {
134 7     7 0 39171 my ( undef, %p ) = @_;
135              
136             OPT:
137 7         31 for my $opt (
138             qw/remote_server_addr port browser_name version platform
139             javascript auto_close extra_capabilities/
140             )
141             {
142 56         123 my $env_var_name = 'TWD_' . uc($opt);
143              
144 56 50       156 next OPT unless exists $ENV{$env_var_name};
145              
146 0   0     0 $p{$opt} //= $ENV{$env_var_name};
147             }
148 7 50 0     38 $p{browser_name} //= $ENV{TWD_BROWSER} if exists $ENV{TWD_BROWSER}; # ykwim
149 7 50 0     30 $p{remote_server_addr} //= $ENV{TWD_HOST} if exists $ENV{TWD_HOST}; # ykwim
150 7   50     46 $p{webelement_class} //= 'Test::Selenium::Remote::WebElement';
151 7         132 return \%p;
152             }
153              
154             =head2 verbose
155              
156             Enable/disable debugging output, or view the status of verbosity.
157              
158             =cut
159              
160             has verbose => ( is => 'rw', );
161              
162             =head2 server_is_running( $host, $port )
163              
164             Returns true if a Selenium server is running. The host and port
165             parameters are optional, and they default to C.
166              
167             The environment vars C and C can also be used to
168             determine which server should be checked.
169              
170             =cut
171              
172             sub server_is_running {
173 0   0 0 1 0 my $host = $ENV{TWD_HOST} || shift || 'localhost';
174 0   0     0 my $port = $ENV{TWD_PORT} || shift || 4444;
175              
176 0 0       0 return ( $host, $port )
177             if IO::Socket::INET->new(
178             PeerAddr => $host,
179             PeerPort => $port,
180             );
181 0         0 return;
182             }
183              
184             =head2 error_handler
185              
186             As for L, this class also supports adding an
187             optional C attribute during instantiation :
188              
189             my $test_driver = Test::Selenium::Remote::Driver->new(
190             error_handler => sub { print $_[1]; croak 'goodbye'; }
191             );
192              
193             Additionally, you can set and/or clear it at any time on an
194             already-instantiated driver:
195              
196             # later, change the error handler to something else
197             $driver->error_handler( sub { print $_[1]; croak 'hello'; } );
198              
199             # stop handling errors manually and use the default S:R:D behavior
200             # (we will croak about the exception)
201             $driver->clear_error_handler;
202              
203             Your error handler will receive two arguments,
204             The first argument is the C<$driver> object itself.
205             Due to some specificities of this class, the second argument passed to the
206             handler can be:
207              
208             =over
209              
210             =item the error message from the Webdriver
211              
212             This is the case when the error message is raised by a WebDriver failure
213              
214             =item "Failed to find ..."
215              
216             This message is raised when the Webdriver call is successful but the failure
217             occurs on the test performed aftwerwards. This is the case for functions like
218             C, C, C, C,
219             C, C, C, C.
220              
221             =back
222              
223             If you set your own handler, you should not rely that much on the message returned.
224             You should also remember that you are entirely responsible for handling exceptions,
225             which means that should the error handler be called, it means that the test you are
226             doing has failed, so you should croak.
227              
228             You should also call fail() in your handler, in case the function called raised a
229             webdriver error, because, as exceptions are not caught anymore when you specify a
230             handler, the function will not fail anymore, which translates to a 'ok' in your TAP
231             output if you do not handle it properly.
232              
233             =head1 Testing Methods
234              
235             The following testing methods are available.
236             For more documentation, see the related methods in L.
237             (And feel free to submit a patch to flesh out the documentation for these here).
238             Defaults for optional arguments B be the same as for their analogues in
239             L.
240              
241             alert_text_is
242             alert_text_isnt
243             alert_text_like
244             alert_text_unlike
245              
246             current_window_handle_is
247             current_window_handle_isnt
248             current_window_handle_like
249             current_window_handle_unlike
250              
251             window_handles_is
252             window_handles_isnt
253             window_handles_like
254             window_handles_unlike
255              
256             window_size_is
257             window_size_isnt
258             window_size_like
259             window_size_unlike
260              
261             window_position_is
262             window_position_isnt
263             window_position_like
264             window_position_unlike
265              
266             current_url_is
267             current_url_isnt
268             current_url_like
269             current_url_unlike
270              
271             title_is
272             title_isnt
273             title_like
274             title_unlike
275              
276              
277             active_element_is
278             active_element_isnt
279             active_element_like
280             active_element_unlike
281              
282             # Basically the same as 'content_like()', but content_like() supports multiple regex's.
283             page_source_is
284             page_source_isnt
285             page_source_like
286             page_source_unlike
287              
288             send_keys_to_active_element_ok
289             send_keys_to_alert_ok
290             send_keys_to_prompt_ok
291             send_modifier_ok
292              
293             accept_alert_ok
294             dismiss_alert_ok
295              
296             move_mouse_to_location_ok # TODO
297             move_to_ok # TODO
298              
299             get_ok
300             go_back_ok
301             go_forward_ok
302             add_cookie_ok
303             get_page_source_ok
304              
305             find_element_ok($search_target)
306             find_element_ok($search_target)
307              
308             find_elements_ok
309             find_child_element_ok
310             find_child_elements_ok
311              
312             compare_elements_ok
313              
314             click_ok
315             double_click_ok
316              
317             =cut
318              
319             # function composing a find_element with locator with a webelement test
320              
321             sub _find_element_with_action {
322 10     10   20 my $self = shift;
323 10         15 my $method = shift;
324 10         22 my ( $locator, $locator_strategy, $params, $desc ) = @_;
325 10   100     31 $locator_strategy //= 'xpath';
326              
327             # case 4 args
328 10 50       19 if ($desc) {
329             $self->croak('Invalid locator strategy')
330 0 0       0 unless ( $self->FINDERS->{$locator_strategy} );
331             }
332             else {
333 10 100       20 if ($params) {
334              
335             # means that we called it the 'old way' (no locator strategy)
336 6 100       41 if ( !defined( $self->FINDERS->{$locator_strategy} ) ) {
337 2         8 $desc = $params;
338 2         4 $params = $locator_strategy;
339 2         56 $locator_strategy =
340             $self->_get_finder_key( $self->default_finder );
341             }
342             }
343             else {
344             # means it was called with no locator strategy and no desc
345 4 50       20 if ($locator_strategy) {
346 4 100       35 if ( !defined( $self->FINDERS->{$locator_strategy} ) ) {
347 3         7 $params = $locator_strategy;
348 3         74 $locator_strategy =
349             $self->_get_finder_key( $self->default_finder );
350             }
351             }
352             else {
353 0         0 $self->croak('Not enough arguments');
354             }
355             }
356             }
357 10 100       24 unless ($desc) {
358 8         15 $desc = $method;
359 8   100     30 $desc .= "'" . join( " ", ( $params // '' ) ) . "'";
360             }
361 10         19 my $element;
362 10         15 eval { $element = $self->find_element( $locator, $locator_strategy ); };
  10         31  
363 10 50       26 if ($@) {
364 0         0 print "# Error: $@\n";
365 0         0 return 0;
366             }
367 10         33 return $element->$method( $params, $desc );
368             }
369              
370             =head2 $twd->type_element_ok($search_target [,$locator], $keys, [, $desc ]);
371              
372             $twd->type_element_ok( $search_target [,$locator], $keys [, $desc ] );
373              
374             Use L to resolve the C<$search_target>
375             to a web element and an optional locator, and then type C<$keys> into it, providing an optional test
376             label.
377              
378             =cut
379              
380             sub type_element_ok {
381 2     2 1 21 my $self = shift;
382 2         6 my $method = 'send_keys_ok';
383 2         8 return $self->_find_element_with_action( $method, @_ );
384             }
385              
386             =head2 $twd->element_text_is($search_target[,$finder],$expected_text [,$desc]);
387              
388             $twd->element_text_is($search_target[,$finder],$expected_text [,$desc]);
389              
390             =cut
391              
392             sub element_text_is {
393 2     2 1 951 my $self = shift;
394 2         5 my $method = 'text_is';
395 2         7 return $self->_find_element_with_action( $method, @_ );
396             }
397              
398             =head2 $twd->element_value_is($search_target[,$finder],$expected_value [,$desc]);
399              
400             $twd->element_value_is($search_target[,$finder],$expected_value [,$desc]);
401              
402             =cut
403              
404             sub element_value_is {
405 1     1 1 458 my $self = shift;
406 1         3 my $method = 'value_is';
407 1         4 return $self->_find_element_with_action( $method, @_ );
408             }
409              
410             =head2 $twd->click_element_ok($search_target [,$finder ,$desc]);
411              
412             $twd->click_element_ok($search_target [,$finder ,$desc]);
413              
414             Find an element and then click on it.
415              
416             =cut
417              
418             sub click_element_ok {
419 2     2 1 1004 my $self = shift;
420 2         5 my $method = 'click_ok';
421 2         6 return $self->_find_element_with_action( $method, @_ );
422             }
423              
424             =head2 $twd->clear_element_ok($search_target [,$finder ,$desc]);
425              
426             $twd->clear_element_ok($search_target [,$finder ,$desc]);
427              
428             Find an element and then clear on it.
429              
430             =cut
431              
432             sub clear_element_ok {
433 1     1 1 973 my $self = shift;
434 1         3 my $method = 'clear_ok';
435 1         5 return $self->_find_element_with_action( $method, @_ );
436             }
437              
438             =head2 $twd->is_element_displayed_ok($search_target [,$finder ,$desc]);
439              
440             $twd->is_element_displayed_ok($search_target [,$finder ,$desc]);
441              
442             Find an element and check to confirm that it is displayed. (visible)
443              
444             =cut
445              
446             sub is_element_displayed_ok {
447 1     1 1 439 my $self = shift;
448 1         3 my $method = 'is_displayed_ok';
449 1         6 return $self->_find_element_with_action( $method, @_ );
450             }
451              
452             =head2 $twd->is_element_enabled_ok($search_target [,$finder ,$desc]);
453              
454             $twd->is_element_enabled_ok($search_target [,$finder ,$desc]);
455              
456             Find an element and check to confirm that it is enabled.
457              
458             =cut
459              
460             sub is_element_enabled_ok {
461 1     1 1 440 my $self = shift;
462 1         4 my $method = 'is_enabled_ok';
463 1         7 return $self->_find_element_with_action( $method, @_ );
464             }
465              
466             =head2 $twd->find_element_ok($search_target [,$finder, $desc ]);
467              
468             $twd->find_element_ok( $search_target [,$finder, $desc ] );
469              
470             Returns true if C<$search_target> is successfully found on the page. C<$search_target>
471             is passed to L using a finder or the C
472             if none passed.
473             See there for more details on the format for C.
474              
475             =head2 $twd->find_no_element_ok($search_target [,$finder, $desc ]);
476              
477             $twd->find_no_element_ok( $search_target [,$finder, $desc ] );
478              
479             Returns true if C<$search_target> is I found on the page. C<$search_target>
480             is passed to L using a finder or the
481             C if none passed. See there for more details on the format for C.
482              
483             =head2 $twd->content_like( $regex [, $desc ] )
484              
485             $twd->content_like( $regex [, $desc ] )
486             $twd->content_like( [$regex_1, $regex_2] [, $desc ] )
487              
488             Tells if the content of the page matches I<$regex>. If an arrayref of regex's
489             are provided, one 'test' is run for each regex against the content of the
490             current page.
491              
492             A default description of 'Content is like "$regex"' will be provided if there
493             is no description.
494              
495             =cut
496              
497             sub content_like {
498 3     3 1 4779 my $self = shift;
499 3         6 my $regex = shift;
500 3         6 my $desc = shift;
501              
502 3         7 local $Test::Builder::Level = $Test::Builder::Level + 1;
503              
504 3         16 my $content = $self->get_page_source();
505 3         6 my $ret;
506              
507 3 50       11 if ( not ref $regex eq 'ARRAY' ) {
    0          
508 3 50       9 $desc = qq{Content is like "$regex"} if ( not defined $desc );
509 3         17 $ret = like_string( $content, $regex, $desc );
510 3 100 100     3249 if ( !$ret && $self->has_error_handler ) {
511 1         32 $self->error_handler->( $self, "Failed to find $regex" );
512             }
513 2         7 return $ret;
514             }
515             elsif ( ref $regex eq 'ARRAY' ) {
516 0         0 for my $re (@$regex) {
517 0 0       0 $desc = qq{Content is like "$re"} if ( not defined $desc );
518 0         0 $ret = like_string( $content, $re, $desc );
519 0 0 0     0 if ( !$ret && $self->has_error_handler ) {
520 0         0 $self->error_handler->( $self, "Failed to find $re" );
521             }
522             }
523             }
524             }
525              
526             =head2 $twd->content_unlike( $regex [, $desc ] )
527              
528             $twd->content_unlike( $regex [, $desc ] )
529             $twd->content_unlike( [$regex_1, $regex_2] [, $desc ] )
530              
531             Tells if the content of the page does NOT match I<$regex>. If an arrayref of regex's
532             are provided, one 'test' is run for each regex against the content of the
533             current page.
534              
535             A default description of 'Content is unlike "$regex"' will be provided if there
536             is no description.
537              
538             =cut
539              
540             sub content_unlike {
541 3     3 1 6836 my $self = shift;
542 3         6 my $regex = shift;
543 3         6 my $desc = shift;
544 3         8 local $Test::Builder::Level = $Test::Builder::Level + 1;
545              
546 3         9 my $content = $self->get_page_source();
547 3         17 my $ret;
548              
549 3 50       11 if ( not ref $regex eq 'ARRAY' ) {
    0          
550 3 50       9 $desc = qq{Content is unlike "$regex"} if ( not defined $desc );
551 3         18 $ret = unlike_string( $content, $regex, $desc );
552 3 100 100     3005 if ( !$ret && $self->has_error_handler ) {
553 1         25 $self->error_handler->( $self, "Failed to find $regex" );
554             }
555             }
556             elsif ( ref $regex eq 'ARRAY' ) {
557 0         0 for my $re (@$regex) {
558 0 0       0 $desc = qq{Content is unlike "$re"} if ( not defined $desc );
559 0         0 $ret = unlike_string( $content, $re, $desc );
560 0 0 0     0 if ( !$ret && $self->has_error_handler ) {
561 0         0 $self->error_handler->( $self, "Failed to find $re" );
562             }
563             }
564             }
565             }
566              
567             =head2 $twd->body_text_like( $regex [, $desc ] )
568              
569             $twd->body_text_like( $regex [, $desc ] )
570             $twd->body_text_like( [$regex_1, $regex_2] [, $desc ] )
571              
572             Tells if the text of the page (as returned by C<< get_body() >>) matches
573             I<$regex>. If an arrayref of regex's are provided, one 'test' is run for each
574             regex against the text of the current page.
575              
576             A default description of 'Text is like "$regex"' will be provided if there
577             is no description.
578              
579             To also match the HTML, see C<< content_unlike() >>.
580              
581             =cut
582              
583             sub body_text_like {
584 3     3 1 6147 my $self = shift;
585 3         5 my $regex = shift;
586 3         8 my $desc = shift;
587              
588 3         7 local $Test::Builder::Level = $Test::Builder::Level + 1;
589              
590 3         19 my $text = $self->get_body();
591 3         8 my $ret;
592              
593 3 50       11 if ( not ref $regex eq 'ARRAY' ) {
    0          
594 3 50       8 $desc = qq{Text is like "$regex"} if ( not defined $desc );
595 3         9 $ret = like_string( $text, $regex, $desc );
596 3 100 100     2997 if ( !$ret && $self->has_error_handler ) {
597 1         28 $self->error_handler->( $self, "Failed to find $regex" );
598             }
599 2         7 return $ret;
600             }
601             elsif ( ref $regex eq 'ARRAY' ) {
602 0         0 for my $re (@$regex) {
603 0 0       0 $desc = qq{Text is like "$re"} if ( not defined $desc );
604 0         0 $ret = like_string( $text, $re, $desc );
605 0 0 0     0 if ( !$ret && $self->has_error_handler ) {
606 0         0 $self->error_handler->( $self, "Failed to find $re" );
607             }
608             }
609             }
610             }
611              
612             =head2 $twd->body_text_unlike( $regex [, $desc ] )
613              
614             $twd->body_text_unlike( $regex [, $desc ] )
615             $twd->body_text_unlike( [$regex_1, $regex_2] [, $desc ] )
616              
617             Tells if the text of the page (as returned by C<< get_body() >>)
618             does NOT match I<$regex>. If an arrayref of regex's
619             are provided, one 'test' is run for each regex against the text of the
620             current page.
621              
622             A default description of 'Text is unlike "$regex"' will be provided if there
623             is no description.
624              
625             To also match the HTML, see C<< content_unlike() >>.
626              
627             =cut
628              
629             sub body_text_unlike {
630 3     3 1 6243 my $self = shift;
631 3         7 my $regex = shift;
632 3         8 my $desc = shift;
633              
634 3         7 local $Test::Builder::Level = $Test::Builder::Level + 1;
635              
636 3         10 my $text = $self->get_body();
637 3         7 my $ret;
638              
639 3 50       20 if ( not ref $regex eq 'ARRAY' ) {
    0          
640 3 50       10 $desc = qq{Text is unlike "$regex"} if ( not defined $desc );
641 3         10 $ret = unlike_string( $text, $regex, $desc );
642 3 100 100     3126 if ( !$ret && $self->has_error_handler ) {
643 1         26 $self->error_handler->( $self, "Failed to find $regex" );
644             }
645 2         6 return $ret;
646              
647             }
648             elsif ( ref $regex eq 'ARRAY' ) {
649 0         0 for my $re (@$regex) {
650 0 0       0 $desc = qq{Text is unlike "$re"} if ( not defined $desc );
651 0         0 $ret = unlike_string( $text, $re, $desc );
652 0 0 0     0 if ( !$ret && $self->has_error_handler ) {
653 0         0 $self->error_handler->( $self, "Failed to find $re" );
654             }
655             }
656             }
657             }
658              
659             #####
660              
661             =head2 $twd->content_contains( $str [, $desc ] )
662              
663             $twd->content_contains( $str [, $desc ] )
664             $twd->content_contains( [$str_1, $str_2] [, $desc ] )
665              
666             Tells if the content of the page contains I<$str>. If an arrayref of strings
667             are provided, one 'test' is run for each string against the content of the
668             current page.
669              
670             A default description of 'Content contains "$str"' will be provided if there
671             is no description.
672              
673             =cut
674              
675             sub content_contains {
676 3     3 1 6111 my $self = shift;
677 3         7 my $str = shift;
678 3         7 my $desc = shift;
679              
680 3         10 local $Test::Builder::Level = $Test::Builder::Level + 1;
681              
682 3         11 my $content = $self->get_page_source();
683 3         6 my $ret;
684              
685 3 50       14 if ( not ref $str eq 'ARRAY' ) {
    0          
686 3 50       10 $desc = qq{Content contains "$str"} if ( not defined $desc );
687 3         14 $ret = contains_string( $content, $str, $desc );
688 3 100 100     4496 if ( !$ret && $self->has_error_handler ) {
689 1         26 $self->error_handler->( $self, "Failed to find $str" );
690             }
691 2         8 return $ret;
692             }
693             elsif ( ref $str eq 'ARRAY' ) {
694 0         0 for my $s (@$str) {
695 0 0       0 $desc = qq{Content contains "$s"} if ( not defined $desc );
696 0         0 $ret = contains_string( $content, $s, $desc );
697              
698 0 0 0     0 if ( !$ret && $self->has_error_handler ) {
699 0         0 $self->error_handler->( $self, "Failed to find $s" );
700             }
701             }
702             }
703             }
704              
705             =head2 $twd->content_lacks( $str [, $desc ] )
706              
707             $twd->content_lacks( $str [, $desc ] )
708             $twd->content_lacks( [$str_1, $str_2] [, $desc ] )
709              
710             Tells if the content of the page does NOT contain I<$str>. If an arrayref of strings
711             are provided, one 'test' is run for each string against the content of the
712             current page.
713              
714             A default description of 'Content lacks "$str"' will be provided if there
715             is no description.
716              
717             =cut
718              
719             sub content_lacks {
720 3     3 1 6183 my $self = shift;
721 3         8 my $str = shift;
722 3         6 my $desc = shift;
723              
724 3         7 local $Test::Builder::Level = $Test::Builder::Level + 1;
725              
726 3         16 my $content = $self->get_page_source();
727 3         7 my $ret;
728              
729 3 50       9 if ( not ref $str eq 'ARRAY' ) {
    0          
730 3 50       10 $desc = qq{Content lacks "$str"} if ( not defined $desc );
731 3         10 $ret = lacks_string( $content, $str, $desc );
732 3 100 100     2960 if ( !$ret && $self->has_error_handler ) {
733 1         59 $self->error_handler->( $self, "Failed to find $str" );
734             }
735 2         8 return $ret;
736             }
737             elsif ( ref $str eq 'ARRAY' ) {
738 0         0 for my $s (@$str) {
739 0 0       0 $desc = qq{Content lacks "$s"} if ( not defined $desc );
740 0         0 $ret = lacks_string( $content, $s, $desc );
741 0 0 0     0 if ( !$ret && $self->has_error_handler ) {
742 0         0 $self->error_handler->( $self, "Failed to find $s" );
743             }
744             }
745             }
746             }
747              
748             =head2 $twd->body_text_contains( $str [, $desc ] )
749              
750             $twd->body_text_contains( $str [, $desc ] )
751             $twd->body_text_contains( [$str_1, $str_2] [, $desc ] )
752              
753             Tells if the text of the page (as returned by C<< get_body() >>) contains
754             I<$str>. If an arrayref of strings are provided, one 'test' is run for each
755             string against the text of the current page.
756              
757             A default description of 'Text contains "$str"' will be provided if there
758             is no description.
759              
760             To also match the HTML, see C<< content_lacks() >>.
761              
762             =cut
763              
764             sub body_text_contains {
765 3     3 1 6175 my $self = shift;
766 3         6 my $str = shift;
767 3         5 my $desc = shift;
768              
769 3         7 local $Test::Builder::Level = $Test::Builder::Level + 1;
770              
771 3         13 my $text = $self->get_body();
772 3         7 my $ret;
773              
774 3 100       15 if ( not ref $str eq 'ARRAY' ) {
    50          
775 2 100       9 $desc = qq{Text contains "$str"} if ( not defined $desc );
776 2         7 $ret = contains_string( $text, $str, $desc );
777 2 100 66     4302 if ( !$ret && $self->has_error_handler ) {
778 1         26 $self->error_handler->( $self, "Failed to find $str" );
779             }
780 1         5 return $ret;
781             }
782             elsif ( ref $str eq 'ARRAY' ) {
783 1         4 for my $s (@$str) {
784 2 50       7 $desc = qq{Text contains "$s"} if ( not defined $desc );
785 2         7 $ret = contains_string( $text, $s, $desc );
786 2 50 33     558 if ( !$ret && $self->has_error_handler ) {
787 0         0 $self->error_handler->( $self, "Failed to find $s" );
788             }
789             }
790             }
791             }
792              
793             =head2 $twd->body_text_lacks( $str [, $desc ] )
794              
795             $twd->body_text_lacks( $str [, $desc ] )
796             $twd->body_text_lacks( [$str_1, $str_2] [, $desc ] )
797              
798             Tells if the text of the page (as returned by C<< get_body() >>)
799             does NOT contain I<$str>. If an arrayref of strings
800             are provided, one 'test' is run for each string against the content of the
801             current page.
802              
803             A default description of 'Text lacks "$str"' will be provided if there
804             is no description.
805              
806             To also match the HTML, see C<< content_lacks() >>.
807              
808             =cut
809              
810             sub body_text_lacks {
811 3     3 1 6642 my $self = shift;
812 3         5 my $str = shift;
813 3         8 my $desc = shift;
814              
815 3         7 local $Test::Builder::Level = $Test::Builder::Level + 1;
816              
817 3         10 my $text = $self->get_body();
818 3         6 my $ret;
819              
820 3 100       20 if ( not ref $str eq 'ARRAY' ) {
    50          
821 1 50       3 $desc = qq{Text lacks "$str"} if ( not defined $desc );
822 1         5 $ret = lacks_string( $text, $str, $desc );
823 1 50 33     274 if ( !$ret && $self->has_error_handler ) {
824 0         0 $self->error_handler->( $self, "Failed to find $str" );
825             }
826 1         4 return $ret;
827             }
828             elsif ( ref $str eq 'ARRAY' ) {
829 2         5 for my $s (@$str) {
830 3 100       14 $desc = qq{Text lacks "$s"} if ( not defined $desc );
831 3         14 $ret = lacks_string( $text, $s, $desc );
832 3 100 100     3012 if ( !$ret && $self->has_error_handler ) {
833 1         27 $self->error_handler->( $self, "Failed to find $s" );
834             }
835             }
836             }
837             }
838              
839             1;
840              
841             __END__