1 package Test::WWW::Mechanize;
8 Test::WWW::Mechanize - Testing-specific WWW::Mechanize subclass
16 our $VERSION = '1.24';
20 Test::WWW::Mechanize is a subclass of L<WWW::Mechanize> that incorporates
21 features for web application testing. For example:
23 use Test::More tests => 5;
24 use Test::WWW::Mechanize;
26 my $mech = Test::WWW::Mechanize->new;
27 $mech->get_ok( $page );
28 $mech->base_is( 'http://petdance.com/', 'Proper <BASE HREF>' );
29 $mech->title_is( "Invoice Status", "Make sure we're on the invoice page" );
30 $mech->content_contains( "Andy Lester", "My name somewhere" );
31 $mech->content_like( qr/(cpan|perl)\.org/, "Link to perl.org or CPAN" );
33 This is equivalent to:
35 use Test::More tests => 5;
38 my $mech = WWW::Mechanize->new;
41 is( $mech->base, 'http://petdance.com', 'Proper <BASE HREF>' );
42 is( $mech->title, "Invoice Status", "Make sure we're on the invoice page" );
43 ok( index( $mech->content, "Andy Lester" ) >= 0, "My name somewhere" );
44 like( $mech->content, qr/(cpan|perl)\.org/, "Link to perl.org or CPAN" );
46 but has nicer diagnostics if they fail.
48 Default descriptions will be supplied for most methods if you omit them. e.g.
50 my $mech = Test::WWW::Mechanize->new;
51 $mech->get_ok( 'http://petdance.com/' );
52 $mech->base_is( 'http://petdance.com/' );
53 $mech->title_is( "Invoice Status" );
54 $mech->content_contains( "Andy Lester" );
55 $mech->content_like( qr/(cpan|perl)\.org/ );
59 ok - Got 'http://petdance.com/' ok
60 ok - Base is 'http://petdance.com/'
61 ok - Title is 'Invoice Status'
62 ok - Content contains 'Andy Lester'
63 ok - Content is like '(?-xism:(cpan|perl)\.org)'
67 use WWW::Mechanize ();
71 use Carp::Assert::More;
73 use base 'WWW::Mechanize';
75 my $Test = Test::Builder->new();
82 Behaves like, and calls, L<WWW::Mechanize>'s C<new> method. Any parms
83 passed in get passed to WWW::Mechanize's constructor.
85 You can pass in C<< autolint => 1 >> to make Test::WWW::Mechanize
86 automatically run HTML::Lint after any of the following methods are
95 and will eventually do the same after any of the following:
103 =item * submit_form_ok()
105 =item * follow_link_ok()
111 This means you no longerhave to do the following:
113 my $mech = Test::WWW::Mechanize->new();
114 $mech->get_ok( $url, 'Fetch the intro page' );
115 $mech->html_lint_ok( 'Intro page looks OK' );
119 my $mech = Test::WWW::Mechanize->new( autolint => 1 );
120 $mech->get_ok( $url, 'Fetch the intro page' );
122 The C<< $mech->get_ok() >> only counts as one test in the test count. Both the
123 main IO operation and the linting must pass for the entire test to pass.
131 agent => "Test-WWW-Mechanize/$VERSION",
135 my $autolint = delete $args{autolint};
137 my $self = $class->SUPER::new( %args );
139 $self->{autolint} = $autolint;
144 =head1 METHODS: HTTP VERBS
146 =head2 $mech->get_ok($url, [ \%LWP_options ,] $desc)
148 A wrapper around WWW::Mechanize's get(), with similar options, except
149 the second argument needs to be a hash reference, not a hash. Like
150 well-behaved C<*_ok()> functions, it returns true if the test passed,
153 A default description of "GET $url" is used if none if provided.
165 my $flex = shift; # The flexible argument
167 if ( !defined( $flex ) ) {
170 elsif ( ref $flex eq 'HASH' ) {
174 elsif ( ref $flex eq 'ARRAY' ) {
183 $self->get( $url, %opts );
184 my $ok = $self->success;
186 if ( not defined $desc ) {
187 $url = $url->url if ref($url) eq 'WWW::Mechanize::Link';
191 $ok = $self->_maybe_lint( $ok, $desc );
201 local $Test::Builder::Level = $Test::Builder::Level + 1;
204 if ( $self->is_html && $self->{autolint} ) {
205 $ok = $self->_lint_content_ok( $desc );
208 $Test->ok( $ok, $desc );
212 $Test->ok( $ok, $desc );
213 $Test->diag( $self->status );
214 $Test->diag( $self->response->message ) if $self->response;
220 =head2 $mech->head_ok($url, [ \%LWP_options ,] $desc)
222 A wrapper around WWW::Mechanize's head(), with similar options, except
223 the second argument needs to be a hash reference, not a hash. Like
224 well-behaved C<*_ok()> functions, it returns true if the test passed,
227 A default description of "HEAD $url" is used if none if provided.
239 my $flex = shift; # The flexible argument
241 if ( !defined( $flex ) ) {
244 elsif ( ref $flex eq 'HASH' ) {
248 elsif ( ref $flex eq 'ARRAY' ) {
257 $self->head( $url, %opts );
258 my $ok = $self->success;
260 if ( not defined $desc ) {
261 $url = $url->url if ref($url) eq 'WWW::Mechanize::Link';
264 $Test->ok( $ok, $desc );
266 $Test->diag( $self->status );
267 $Test->diag( $self->response->message ) if $self->response;
273 =head2 $mech->post_ok( $url, [ \%LWP_options ,] $desc )
275 A wrapper around WWW::Mechanize's post(), with similar options, except
276 the second argument needs to be a hash reference, not a hash. Like
277 well-behaved C<*_ok()> functions, it returns true if the test passed,
280 A default description of "POST to $url" is used if none if provided.
292 my $flex = shift; # The flexible argument
294 if ( !defined( $flex ) ) {
297 elsif ( ref $flex eq 'HASH' ) {
301 elsif ( ref $flex eq 'ARRAY' ) {
310 if ( not defined $desc ) {
311 $url = $url->url if ref($url) eq 'WWW::Mechanize::Link';
314 $self->post( $url, \%opts );
315 my $ok = $self->success;
316 $Test->ok( $ok, $desc );
318 $Test->diag( $self->status );
319 $Test->diag( $self->response->message ) if $self->response;
325 =head2 $mech->put_ok( $url, [ \%LWP_options ,] $desc )
327 A wrapper around WWW::Mechanize's put(), with similar options, except
328 the second argument needs to be a hash reference, not a hash. Like
329 well-behaved C<*_ok()> functions, it returns true if the test passed,
332 A default description of "PUT to $url" is used if none if provided.
344 my $flex = shift; # The flexible argument
346 if ( !defined( $flex ) ) {
349 elsif ( ref $flex eq 'HASH' ) {
353 elsif ( ref $flex eq 'ARRAY' ) {
362 if ( not defined $desc ) {
363 $url = $url->url if ref($url) eq 'WWW::Mechanize::Link';
366 $self->put( $url, \%opts );
367 my $ok = $self->success;
368 $Test->ok( $ok, $desc );
370 $Test->diag( $self->status );
371 $Test->diag( $self->response->message ) if $self->response;
377 =head2 $mech->submit_form_ok( \%parms [, $desc] )
379 Makes a C<submit_form()> call and executes tests on the results.
380 The form must be found, and then submitted successfully. Otherwise,
383 I<%parms> is a hashref containing the parms to pass to C<submit_form()>.
384 Note that the parms to C<submit_form()> are a hash whereas the parms to
385 this function are a hashref. You have to call this function like:
387 $agent->submit_form_ok( {n=>3}, "looking for 3rd link" );
389 As with other test functions, C<$desc> is optional. If it is supplied
390 then it will display when running the test harness in verbose mode.
392 Returns true value if the specified link was found and followed
393 successfully. The L<HTTP::Response> object returned by submit_form()
400 my $parms = shift || {};
403 if ( ref $parms ne 'HASH' ) {
404 Carp::croak 'FATAL: parameters must be given as a hashref';
407 # return from submit_form() is an HTTP::Response or undef
408 my $response = $self->submit_form( %{$parms} );
413 $error = 'No matching form found';
416 if ( $response->is_success ) {
420 $error = $response->as_string;
424 $Test->ok( $ok, $desc );
425 $Test->diag( $error ) if $error;
431 =head2 $mech->follow_link_ok( \%parms [, $desc] )
433 Makes a C<follow_link()> call and executes tests on the results.
434 The link must be found, and then followed successfully. Otherwise,
437 I<%parms> is a hashref containing the parms to pass to C<follow_link()>.
438 Note that the parms to C<follow_link()> are a hash whereas the parms to
439 this function are a hashref. You have to call this function like:
441 $mech->follow_link_ok( {n=>3}, "looking for 3rd link" );
443 As with other test functions, C<$desc> is optional. If it is supplied
444 then it will display when running the test harness in verbose mode.
446 Returns a true value if the specified link was found and followed
447 successfully. The L<HTTP::Response> object returned by follow_link()
454 my $parms = shift || {};
457 if (!defined($desc)) {
458 my $parms_str = join(', ', map { join('=', $_, $parms->{$_}) } keys(%{$parms}));
459 $desc = qq{Followed link with "$parms_str"} if !defined($desc);
462 if ( ref $parms ne 'HASH' ) {
463 Carp::croak 'FATAL: parameters must be given as a hashref';
466 # return from follow_link() is an HTTP::Response or undef
467 my $response = $self->follow_link( %{$parms} );
472 $error = 'No matching link found';
475 if ( $response->is_success ) {
479 $error = $response->as_string;
483 $Test->ok( $ok, $desc );
484 $Test->diag( $error ) if $error;
490 =head2 click_ok( $button[, $desc] )
492 Clicks the button named by C<$button>. An optional C<$desc> can
493 be given for the test.
502 my $response = $self->click( $button );
504 return $Test->ok( 0, $desc );
507 if ( !$response->is_success ) {
508 $Test->diag( "Failed test $desc:" );
509 $Test->diag( $response->as_string );
510 return $Test->ok( 0, $desc );
512 return $Test->ok( 1, $desc );
515 =head1 METHODS: CONTENT CHECKING
517 =head2 $mech->html_lint_ok( [$desc] )
519 Checks the validity of the HTML on the current page. If the page is not
520 HTML, then it fails. The URI is automatically appended to the I<$desc>.
522 Note that HTML::Lint must be installed for this to work. Otherwise,
531 my $uri = $self->uri;
532 $desc = $desc ? "$desc ($uri)" : $uri;
536 if ( $self->is_html ) {
537 $ok = $self->_lint_content_ok( $desc );
540 $ok = $Test->ok( 0, $desc );
541 $Test->diag( q{This page doesn't appear to be HTML, or didn't get the proper text/html content type returned.} );
547 sub _lint_content_ok {
551 local $Test::Builder::Level = $Test::Builder::Level + 1;
553 if ( not ( eval 'require HTML::Lint' ) ) {
554 die "Test::WWW::Mechanize can't do linting without HTML::Lint: $@";
557 # XXX Combine with the cut'n'paste version in get_ok()
558 my $lint = HTML::Lint->new;
559 $lint->parse( $self->content );
561 my @errors = $lint->errors;
562 my $nerrors = @errors;
565 $ok = $Test->ok( 0, $desc );
566 $Test->diag( 'HTML::Lint errors for ' . $self->uri );
567 $Test->diag( $_->as_string ) for @errors;
568 my $s = $nerrors == 1 ? '' : 's';
569 $Test->diag( "$nerrors error$s on the page" );
572 $ok = $Test->ok( 1, $desc );
578 =head2 $mech->title_is( $str [, $desc ] )
580 Tells if the title of the page is the given string.
582 $mech->title_is( "Invoice Summary" );
590 $desc = qq{Title is "$str"} if !defined($desc);
592 local $Test::Builder::Level = $Test::Builder::Level + 1;
593 return is_string( $self->title, $str, $desc );
596 =head2 $mech->title_like( $regex [, $desc ] )
598 Tells if the title of the page matches the given regex.
600 $mech->title_like( qr/Invoices for (.+)/
608 $desc = qq{Title is like "$regex"} if !defined($desc);
610 local $Test::Builder::Level = $Test::Builder::Level + 1;
611 return like_string( $self->title, $regex, $desc );
614 =head2 $mech->title_unlike( $regex [, $desc ] )
616 Tells if the title of the page matches the given regex.
618 $mech->title_unlike( qr/Invoices for (.+)/
626 $desc = qq{Title is unlike "$regex"} if !defined($desc);
628 local $Test::Builder::Level = $Test::Builder::Level + 1;
629 return unlike_string( $self->title, $regex, $desc );
632 =head2 $mech->base_is( $str [, $desc ] )
634 Tells if the base of the page is the given string.
636 $mech->base_is( "http://example.com/" );
644 $desc = qq{Base is "$str"} if !defined($desc);
646 local $Test::Builder::Level = $Test::Builder::Level + 1;
647 return is_string( $self->base, $str, $desc );
650 =head2 $mech->base_like( $regex [, $desc ] )
652 Tells if the base of the page matches the given regex.
654 $mech->base_like( qr{http://example.com/index.php?PHPSESSID=(.+)});
662 $desc = qq{Base is like "$regex"} if !defined($desc);
664 local $Test::Builder::Level = $Test::Builder::Level + 1;
665 return like_string( $self->base, $regex, $desc );
668 =head2 $mech->base_unlike( $regex [, $desc ] )
670 Tells if the base of the page matches the given regex.
672 $mech->base_unlike( qr{http://example.com/index.php?PHPSESSID=(.+)});
680 $desc = qq{Base is unlike "$regex"} if !defined($desc);
682 local $Test::Builder::Level = $Test::Builder::Level + 1;
683 return unlike_string( $self->base, $regex, $desc );
686 =head2 $mech->content_is( $str [, $desc ] )
688 Tells if the content of the page matches the given string
697 local $Test::Builder::Level = $Test::Builder::Level + 1;
698 $desc = qq{Content is "$str"} if !defined($desc);
700 return is_string( $self->content, $str, $desc );
703 =head2 $mech->content_contains( $str [, $desc ] )
705 Tells if the content of the page contains I<$str>.
709 sub content_contains {
714 local $Test::Builder::Level = $Test::Builder::Level + 1;
715 if ( ref($str) eq 'REGEX' ) {
716 diag( 'content_contains takes a string, not a regex' );
718 $desc = qq{Content contains "$str"} if !defined($desc);
720 return contains_string( $self->content, $str, $desc );
723 =head2 $mech->content_lacks( $str [, $desc ] )
725 Tells if the content of the page lacks I<$str>.
734 local $Test::Builder::Level = $Test::Builder::Level + 1;
735 if ( ref($str) eq 'REGEX' ) {
736 diag( 'content_lacks takes a string, not a regex' );
738 $desc = qq{Content lacks "$str"} if !defined($desc);
740 return lacks_string( $self->content, $str, $desc );
743 =head2 $mech->content_like( $regex [, $desc ] )
745 Tells if the content of the page matches I<$regex>.
753 $desc = qq{Content is like "$regex"} if !defined($desc);
755 local $Test::Builder::Level = $Test::Builder::Level + 1;
756 return like_string( $self->content, $regex, $desc );
759 =head2 $mech->content_unlike( $regex [, $desc ] )
761 Tells if the content of the page does NOT match I<$regex>.
769 $desc = qq{Content is like "$regex"} if !defined($desc);
771 local $Test::Builder::Level = $Test::Builder::Level + 1;
772 return unlike_string( $self->content, $regex, $desc );
775 =head2 $mech->has_tag( $tag, $text [, $desc ] )
777 Tells if the page has a C<$tag> tag with the given content in its text.
786 $desc = qq{Page has $tag tag with "$text"} if !defined($desc);
788 my $found = $self->_tag_walk( $tag, sub { $text eq $_[0] } );
790 return $Test->ok( $found, $desc );
794 =head2 $mech->has_tag_like( $tag, $regex [, $desc ] )
796 Tells if the page has a C<$tag> tag with the given content in its text.
805 $desc = qq{Page has $tag tag like "$regex"} if !defined($desc);
807 my $found = $self->_tag_walk( $tag, sub { $_[0] =~ $regex } );
809 return $Test->ok( $found, $desc );
818 my $p = HTML::TokeParser->new( \($self->content) );
820 while ( my $token = $p->get_tag( $tag ) ) {
821 my $tagtext = $p->get_trimmed_text( "/$tag" );
822 return 1 if $match->( $tagtext );
827 =head2 $mech->followable_links()
829 Returns a list of links that Mech can follow. This is only http and
834 sub followable_links {
837 return $self->find_all_links( url_abs_regex => qr{^https?://} );
840 =head2 $mech->page_links_ok( [ $desc ] )
842 Follow all links on the current page and test for HTTP status 200
844 $mech->page_links_ok('Check all links');
852 $desc = 'All links ok' unless defined $desc;
854 my @links = $self->followable_links();
855 my @urls = _format_links(\@links);
857 my @failures = $self->_check_links_status( \@urls );
858 my $ok = (@failures==0);
860 $Test->ok( $ok, $desc );
861 $Test->diag( $_ ) for @failures;
866 =head2 $mech->page_links_content_like( $regex [, $desc ] )
868 Follow all links on the current page and test their contents for I<$regex>.
870 $mech->page_links_content_like( qr/foo/,
871 'Check all links contain "foo"' );
875 sub page_links_content_like {
880 $desc = qq{All links are like "$regex"} unless defined $desc;
882 my $usable_regex=$Test->maybe_regex( $regex );
883 unless(defined( $usable_regex )) {
884 my $ok = $Test->ok( 0, 'page_links_content_like' );
885 $Test->diag(qq{ "$regex" doesn't look much like a regex to me.});
889 my @links = $self->followable_links();
890 my @urls = _format_links(\@links);
892 my @failures = $self->_check_links_content( \@urls, $regex );
893 my $ok = (@failures==0);
895 $Test->ok( $ok, $desc );
896 $Test->diag( $_ ) for @failures;
901 =head2 $mech->page_links_content_unlike( $regex [, $desc ] )
903 Follow all links on the current page and test their contents do not
904 contain the specified regex.
906 $mech->page_links_content_unlike(qr/Restricted/,
907 'Check all links do not contain Restricted');
911 sub page_links_content_unlike {
915 $desc = "All links are unlike '$regex'" if !defined($desc);
917 my $usable_regex=$Test->maybe_regex( $regex );
918 unless(defined( $usable_regex )) {
919 my $ok = $Test->ok( 0, 'page_links_content_unlike' );
920 $Test->diag(qq{ "$regex" doesn't look much like a regex to me.});
924 my @links = $self->followable_links();
925 my @urls = _format_links(\@links);
927 my @failures = $self->_check_links_content( \@urls, $regex, 'unlike' );
928 my $ok = (@failures==0);
930 $Test->ok( $ok, $desc );
931 $Test->diag( $_ ) for @failures;
936 =head2 $mech->links_ok( $links [, $desc ] )
938 Follow specified links on the current page and test for HTTP status
939 200. The links may be specified as a reference to an array containing
940 L<WWW::Mechanize::Link> objects, an array of URLs, or a scalar URL
943 my @links = $mech->find_all_links( url_regex => qr/cnn\.com$/ );
944 $mech->links_ok( \@links, 'Check all links for cnn.com' );
946 my @links = qw( index.html search.html about.html );
947 $mech->links_ok( \@links, 'Check main links' );
949 $mech->links_ok( 'index.html', 'Check link to index' );
958 my @urls = _format_links( $links );
959 $desc = _default_links_desc(\@urls, 'are ok') unless defined $desc;
960 my @failures = $self->_check_links_status( \@urls );
961 my $ok = (@failures == 0);
963 $Test->ok( $ok, $desc );
964 $Test->diag( $_ ) for @failures;
969 =head2 $mech->link_status_is( $links, $status [, $desc ] )
971 Follow specified links on the current page and test for HTTP status
972 passed. The links may be specified as a reference to an array
973 containing L<WWW::Mechanize::Link> objects, an array of URLs, or a
976 my @links = $mech->followable_links();
977 $mech->link_status_is( \@links, 403,
978 'Check all links are restricted' );
988 my @urls = _format_links( $links );
989 $desc = _default_links_desc(\@urls, "have status $status") if !defined($desc);
990 my @failures = $self->_check_links_status( \@urls, $status );
991 my $ok = (@failures == 0);
993 $Test->ok( $ok, $desc );
994 $Test->diag( $_ ) for @failures;
999 =head2 $mech->link_status_isnt( $links, $status [, $desc ] )
1001 Follow specified links on the current page and test for HTTP status
1002 passed. The links may be specified as a reference to an array
1003 containing L<WWW::Mechanize::Link> objects, an array of URLs, or a
1006 my @links = $mech->followable_links();
1007 $mech->link_status_isnt( \@links, 404,
1008 'Check all links are not 404' );
1012 sub link_status_isnt {
1018 my @urls = _format_links( $links );
1019 $desc = _default_links_desc(\@urls, "do not have status $status") if !defined($desc);
1020 my @failures = $self->_check_links_status( \@urls, $status, 'isnt' );
1021 my $ok = (@failures == 0);
1023 $Test->ok( $ok, $desc );
1024 $Test->diag( $_ ) for @failures;
1030 =head2 $mech->link_content_like( $links, $regex [, $desc ] )
1032 Follow specified links on the current page and test the resulting
1033 content of each against I<$regex>. The links may be specified as a
1034 reference to an array containing L<WWW::Mechanize::Link> objects, an
1035 array of URLs, or a scalar URL name.
1037 my @links = $mech->followable_links();
1038 $mech->link_content_like( \@links, qr/Restricted/,
1039 'Check all links are restricted' );
1043 sub link_content_like {
1049 my $usable_regex=$Test->maybe_regex( $regex );
1050 unless(defined( $usable_regex )) {
1051 my $ok = $Test->ok( 0, 'link_content_like' );
1052 $Test->diag(qq{ "$regex" doesn't look much like a regex to me.});
1056 my @urls = _format_links( $links );
1057 $desc = _default_links_desc(\@urls, "are like '$regex'") if !defined($desc);
1058 my @failures = $self->_check_links_content( \@urls, $regex );
1059 my $ok = (@failures == 0);
1061 $Test->ok( $ok, $desc );
1062 $Test->diag( $_ ) for @failures;
1067 =head2 $mech->link_content_unlike( $links, $regex [, $desc ] )
1069 Follow specified links on the current page and test that the resulting
1070 content of each does not match I<$regex>. The links may be specified as a
1071 reference to an array containing L<WWW::Mechanize::Link> objects, an array
1072 of URLs, or a scalar URL name.
1074 my @links = $mech->followable_links();
1075 $mech->link_content_unlike( \@links, qr/Restricted/,
1076 'No restricted links' );
1080 sub link_content_unlike {
1086 my $usable_regex=$Test->maybe_regex( $regex );
1087 unless(defined( $usable_regex )) {
1088 my $ok = $Test->ok( 0, 'link_content_unlike' );
1089 $Test->diag(qq{ "$regex" doesn't look much like a regex to me.});
1093 my @urls = _format_links( $links );
1094 $desc = _default_links_desc(\@urls, qq{are not like "$regex"}) if !defined($desc);
1095 my @failures = $self->_check_links_content( \@urls, $regex, 'unlike' );
1096 my $ok = (@failures == 0);
1098 $Test->ok( $ok, $desc );
1099 $Test->diag( $_ ) for @failures;
1104 # Create a default description for the link_* methods, including the link count.
1105 sub _default_links_desc {
1106 my ($urls, $desc_suffix) = @_;
1107 my $url_count = scalar(@{$urls});
1108 return sprintf( '%d link%s %s', $url_count, $url_count == 1 ? '' : 's', $desc_suffix );
1111 # This actually performs the status check of each url.
1112 sub _check_links_status {
1115 my $status = shift || 200;
1116 my $test = shift || 'is';
1118 # Create a clone of the $mech used during the test as to not disrupt
1120 my $mech = $self->clone();
1124 for my $url ( @{$urls} ) {
1125 if ( $mech->follow_link( url => $url ) ) {
1126 if ( $test eq 'is' ) {
1127 push( @failures, $url ) unless $mech->status() == $status;
1130 push( @failures, $url ) unless $mech->status() != $status;
1135 push( @failures, $url );
1142 # This actually performs the content check of each url.
1143 sub _check_links_content {
1146 my $regex = shift || qr/<html>/;
1147 my $test = shift || 'like';
1149 # Create a clone of the $mech used during the test as to not disrupt
1151 my $mech = $self->clone();
1154 for my $url ( @{$urls} ) {
1155 if ( $mech->follow_link( url => $url ) ) {
1156 my $content=$mech->content();
1157 if ( $test eq 'like' ) {
1158 push( @failures, $url ) unless $content=~/$regex/;
1161 push( @failures, $url ) unless $content!~/$regex/;
1166 push( @failures, $url );
1173 # Create an array of urls to match for mech to follow.
1178 if (ref($links) eq 'ARRAY') {
1179 if (defined($$links[0])) {
1180 if (ref($$links[0]) eq 'WWW::Mechanize::Link') {
1181 @urls = map { $_->url() } @{$links};
1194 =head2 $mech->stuff_inputs( [\%options] )
1196 Finds all free-text input fields (text, textarea, and password) in the
1197 current form and fills them to their maximum length in hopes of finding
1198 application code that can't handle it. Fields with no maximum length
1199 and all textarea fields are set to 66000 bytes, which will often be
1200 enough to overflow the data's eventual recepticle.
1202 There is no return value.
1204 If there is no current form then nothing is done.
1206 The hashref $options can contain the following keys:
1212 hash value is arrayref of field names to not touch, e.g.:
1214 $mech->stuff_inputs( {
1215 ignore => [qw( specialfield1 specialfield2 )],
1220 hash value is default string to use when stuffing fields. Copies
1221 of the string are repeated up to the max length of each field. E.g.:
1223 $mech->stuff_inputs( {
1224 fill => '@' # stuff all fields with something easy to recognize
1229 hash value is arrayref of hashrefs with which you can pass detailed
1230 instructions about how to stuff a given field. E.g.:
1232 $mech->stuff_inputs( {
1234 # Some fields are datatype-constrained. It's most common to
1235 # want the field stuffed with valid data.
1236 widget_quantity => { fill=>'9' },
1237 notes => { maxlength=>2000 },
1241 The specs allowed are I<fill> (use this fill for the field rather than
1242 the default) and I<maxlength> (use this as the field's maxlength instead
1243 of any maxlength specified in the HTML).
1252 my $options = shift || {};
1253 assert_isa( $options, 'HASH' );
1254 assert_in( $_, ['ignore', 'fill', 'specs'] ) foreach ( keys %{$options} );
1256 # set up the fill we'll use unless a field overrides it
1257 my $default_fill = '@';
1258 if ( exists $options->{fill} && defined $options->{fill} && length($options->{fill}) > 0 ) {
1259 $default_fill = $options->{fill};
1262 # fields in the form to not stuff
1264 if ( exists $options->{ignore} ) {
1265 assert_isa( $options->{ignore}, 'ARRAY' );
1266 $ignore = { map {($_, 1)} @{$options->{ignore}} };
1270 if ( exists $options->{specs} ) {
1271 assert_isa( $options->{specs}, 'HASH' );
1272 $specs = $options->{specs};
1273 foreach my $field_name ( keys %{$specs} ) {
1274 assert_isa( $specs->{$field_name}, 'HASH' );
1275 assert_in( $_, ['fill', 'maxlength'] ) foreach ( keys %{$specs->{$field_name}} );
1279 my @inputs = $self->find_all_inputs( type_regex => qr/^(text|textarea|password)$/ );
1281 foreach my $field ( @inputs ) {
1282 next if $field->readonly();
1283 next if $field->disabled(); # TODO: HTML::Form::TextInput allows setting disabled--allow it here?
1285 my $name = $field->name();
1287 # skip if it's one of the fields to ignore
1288 next if exists $ignore->{ $name };
1290 # fields with no maxlength will get this many characters
1291 my $maxlength = 66000;
1293 # maxlength from the HTML
1294 if ( $field->type ne 'textarea' ) {
1295 if ( exists $field->{maxlength} ) {
1296 $maxlength = $field->{maxlength};
1297 # TODO: what to do about maxlength==0 ? non-numeric? less than 0 ?
1301 my $fill = $default_fill;
1303 if ( exists $specs->{$name} ) {
1304 # process the per-field info
1306 if ( exists $specs->{$name}->{fill} && defined $specs->{$name}->{fill} && length($specs->{$name}->{fill}) > 0 ) {
1307 $fill = $specs->{$name}->{fill};
1310 # maxlength override from specs
1311 if ( exists $specs->{$name}->{maxlength} && defined $specs->{$name}->{maxlength} ) {
1312 $maxlength = $specs->{$name}->{maxlength};
1313 # TODO: what to do about maxlength==0 ? non-numeric? less than 0?
1318 if ( ($maxlength % length($fill)) == 0 ) {
1320 $field->value( $fill x ($maxlength/length($fill)) );
1323 # can be improved later
1324 $field->value( substr( $fill x int(($maxlength + length($fill) - 1)/length($fill)), 0, $maxlength ) );
1333 Add HTML::Tidy capabilities.
1335 Add a broken image check.
1339 Andy Lester, C<< <andy at petdance.com> >>
1343 Please report any bugs or feature requests to
1344 <http://code.google.com/p/www-mechanize/issues/list>. I will be
1345 notified, and then you'll automatically be notified of progress on
1346 your bug as I make changes.
1350 You can find documentation for this module with the perldoc command.
1352 perldoc Test::WWW::Mechanize
1354 You can also look for information at:
1358 =item * Google Code bug tracker
1360 L<http://code.google.com/p/www-mechanize/issues/list>
1362 Please B<do not use> the old queues for WWW::Mechanize and
1363 Test::WWW::Mechanize at
1364 L<http://rt.cpan.org/NoAuth/Bugs.html?Dist=Test-WWW-Mechanize>
1366 =item * AnnoCPAN: Annotated CPAN documentation
1368 L<http://annocpan.org/dist/Test-WWW-Mechanize>
1370 =item * CPAN Ratings
1372 L<http://cpanratings.perl.org/d/Test-WWW-Mechanize>
1376 L<http://search.cpan.org/dist/Test-WWW-Mechanize>
1380 =head1 ACKNOWLEDGEMENTS
1391 and Pete Krawczyk for patches.
1393 =head1 COPYRIGHT & LICENSE
1395 Copyright 2004-2008 Andy Lester, all rights reserved.
1397 This program is free software; you can redistribute it and/or modify it
1398 under the same terms as Perl itself.
1402 1; # End of Test::WWW::Mechanize