Test::...::PSGI(3pm)
π Test::WWW::Mechanize::PSGI π
okay bestie, listen β this is Test::...::PSGI(3pm) from the User Contributed Perl Documentation, and it's literally the moment your PSGI app gets a whole test suite without you ever needing to spin up a server. no cap. let's get into it π«Ά
β¨ NAME β¨
Test::WWW::Mechanize::PSGI β test your PSGI programs using WWW::Mechanize π
πΈ VERSION πΈ
version 0.39
π¦ SYNOPSIS π¦
so picture this: we're in a t/*.t test script, and we're about to be so iconic
# We're in a t/*.t test script...
use Test::WWW::Mechanize::PSGI;
my $mech = Test::WWW::Mechanize::PSGI->new(
app => sub {
my $env = shift;
return [
200,
[ 'Content-Type' => 'text/html' ],
[ '<html><head><title>Hi</title></head><body>Hello World</body></html>'
]
];
},
);
$mech->get_ok('/');
is( $mech->ct, 'text/html', 'Is text/html' );
$mech->title_is('Hi');
$mech->content_contains('Hello World');
# ... and all other Test::WWW::Mechanize methods
like. look at that. a whole app, tested, no server, no nothing. we ate π₯
π DESCRIPTION π
so PSGI is a specification whose whole thing is decoupling web server environments from web application framework code. slay. and Test::WWW::Mechanize is a subclass of WWW::Mechanize that incorporates features for web application testing. and Test::WWW::Mechanize::PSGI? it meshes the two so you can test PSGI applications like it's literally nothing. π§
here's the tea: testing web apps has always been a bit tricky β normally you gotta start an actual web server for your application and make real HTTP requests to it, which is giving major effort energy π. this module lets you test PSGI web applications but it does not require a server and it does not issue HTTP requests. instead, it passes the HTTP request object directly to PSGI. so you don't need a real hostname β http://localhost/ will do. but also that's optional, bestie. these next two lines of code do exactly the same thing:
$mech->get_ok('/action');
$mech->get_ok('http://localhost/action');
which makes testing fast and easy, periodt. and Test::WWW::Mechanize provides functions for all the common web testing scenarios, for example:
$mech->get_ok( $page );
$mech->title_is( "Invoice Status", "Make sure we're on the invoice page" );
$mech->content_contains( "Andy Lester", "My name somewhere" );
$mech->content_like( qr/(cpan|perl)\.org/, "Link to perl.org or CPAN" );
lowkey important: an alternative to this module is Plack::Test. just so you know your options π
π CONSTRUCTOR π
new
behaves like, and calls, WWW::Mechanize's new method π you should pass in your application:
my $mech = Test::WWW::Mechanize::PSGI->new(
app => sub {
my $env = shift;
return [ 200, [ 'Content-Type' => 'text/plain' ], ['Hello World'] ],;
},
env => { REMOTE_USER => 'Foo Bar' },
);
π METHODS: HTTP VERBS π
$mech->get_ok($url, [ %LWP_options ,] $desc)
a wrapper around WWW::Mechanize's get(), with similar options β except the second argument needs to be a hash reference, not a hash. like, that's the whole vibe check. and like all well-behaved *_ok() functions, it returns true if the test passed, or false if not.
A default description of GET $url is used if none if provided.
$mech->head_ok($url, [ %LWP_options ,] $desc)
a wrapper around WWW::Mechanize's head(), with similar options β except again, second argument = hash reference, not a hash. and like a well-behaved *_ok() function, it returns true if the test passed, or false if not.
A default description of HEAD $url is used if none if provided.
$mech->post_ok( $url, [ %LWP_options ,] $desc )
a wrapper around WWW::Mechanize's post(), with similar options β except the second argument needs to be a hash reference, not a hash. like well-behaved *_ok() functions, it returns true if the test passed, or false if not.
A default description of POST to $url is used if none if provided.
$mech->put_ok( $url, [ %LWP_options ,] $desc )
a wrapper around WWW::Mechanize's put(), with similar options β except the second argument needs to be a hash reference, not a hash. like well-behaved *_ok() functions, it returns true if the test passed, or false if not.
A default description of PUT to $url is used if none if provided.
$mech->submit_form_ok( %params [, $desc] )
this one makes a submit_form() call and executes tests on the results π
the form must be found, and then submitted successfully. otherwise? this test fails. sorry bestie π
%params is a hashref containing the params to pass to submit_form(). and here's the lil gotcha β the params to submit_form() are a hash, whereas the params to this function are a hashref. so you have to call this function like:
$agent->submit_form_ok({
form_number => 3,
fields => {
username => 'mungo',
password => 'lost-and-alone',
}
}, "looking for 3rd form" );
as with other test functions, $desc is optional. if it is supplied then it will display when running the test harness in verbose mode. π
returns a true value if the specified link was found and followed successfully. the HTTP::Response object returned by submit_form() is not available.
$mech->follow_link_ok( %params [, $desc] )
makes a follow_link() call and executes tests on the results β¨ the link must be found, and then followed successfully. otherwise, this test fails.
%params is a hashref containing the params to pass to follow_link(). note that the params to follow_link() are a hash whereas the params to this function are a hashref. you have to call this function like:
$mech->follow_link_ok( {n=>3}, "looking for 3rd link" );
as with other test functions, $desc is optional. if it is supplied then it will display when running the test harness in verbose mode.
returns a true value if the specified link was found and followed successfully. the HTTP::Response object returned by follow_link() is not available.
click_ok( $button[, $desc] )
clicks the button named by $button. an optional $desc can be given for the test. π±οΈβ¨
β¨ METHODS: CONTENT CHECKING β¨
okay bestie this is where it gets good β we're not just clicking around anymore, we're checking what's actually ON the page π
π $mech->html_lint_ok( [$desc] )
Checks the validity of the HTML on the current page. If the page is not HTML, then it fails. The URI is automatically appended to the $desc.
no cap: HTML::Lint must be installed for this to work. Otherwise, it will blow up. π like, actually explode. install the module.
πΈ $mech->title_is( $str [, $desc ] )
Tells if the title of the page is the given string.
$mech->title_is( "Invoice Summary" );
πΈ $mech->title_like( $regex [, $desc ] )
Tells if the title of the page matches the given regex.
$mech->title_like( qr/Invoices for (.+)/
πΈ $mech->title_unlike( $regex [, $desc ] )
Tells if the title of the page matches the given regex.
$mech->title_unlike( qr/Invoices for (.+)/
π¦ $mech->base_is( $str [, $desc ] )
Tells if the base of the page is the given string.
$mech->base_is( "http://example.com/" );
π¦ $mech->base_like( $regex [, $desc ] )
Tells if the base of the page matches the given regex.
$mech->base_like( qr{http://example.com/index.php?PHPSESSID=(.+)});
π¦ $mech->base_unlike( $regex [, $desc ] )
Tells if the base of the page matches the given regex.
$mech->base_unlike( qr{http://example.com/index.php?PHPSESSID=(.+)});
β $mech->content_is( $str [, $desc ] )
Tells if the content of the page matches the given string
β $mech->content_contains( $str [, $desc ] )
Tells if the content of the page contains $str.
β $mech->content_lacks( $str [, $desc ] )
Tells if the content of the page lacks $str.
β $mech->content_like( $regex [, $desc ] )
Tells if the content of the page matches $regex.
β $mech->content_unlike( $regex [, $desc ] )
Tells if the content of the page does NOT match $regex.
π $mech->has_tag( $tag, $text [, $desc ] )
Tells if the page has a $tag tag with the given content in its text.
π $mech->has_tag_like( $tag, $regex [, $desc ] )
Tells if the page has a $tag tag with the given content in its text.
π₯ $mech->followable_links()
Returns a list of links that WWW::Mechanize can follow. This is only http and https links.
π₯ $mech->page_links_ok( [ $desc ] )
Follow all links on the current page and test for HTTP status 200
$mech->page_links_ok('Check all links');
π₯ $mech->page_links_content_like( $regex [, $desc ] )
Follow all links on the current page and test their contents for $regex.
$mech->page_links_content_like( qr/foo/,
'Check all links contain "foo"' );
π $mech->links_ok( $links [, $desc ] )
Follow specified links on the current page and test for HTTP status 200. The links may be specified as a reference to an array containing WWW::Mechanize::Link objects, an array of URLs, or a scalar URL name.
my @links = $mech->find_all_links( url_regex => qr/cnn\.com$/ );
$mech->links_ok( \@links, 'Check all links for cnn.com' );
my @links = qw( index.html search.html about.html );
$mech->links_ok( \@links, 'Check main links' );
$mech->links_ok( 'index.html', 'Check link to index' );
π $mech->link_status_is( $links, $status [, $desc ] )
Follow specified links on the current page and test for HTTP status passed. The links may be specified as a reference to an array containing WWW::Mechanize::Link objects, an array of URLs, or a scalar URL name.
my @links = $mech->followable_links();
$mech->link_status_is( \@links, 403,
'Check all links are restricted' );
π $mech->link_status_isnt( $links, $status [, $desc ] )
Follow specified links on the current page and test for HTTP status passed. The links may be specified as a reference to an array containing WWW::Mechanize::Link objects, an array of URLs, or a scalar URL name.
my @links = $mech->followable_links();
$mech->link_status_isnt( \@links, 404,
'Check all links are not 404' );
π§ $mech->link_content_like( $links, $regex [, $desc ] )
Follow specified links on the current page and test the resulting content of each against $regex. The links may be specified as a reference to an array containing WWW::Mechanize::Link objects, an array of URLs, or a scalar URL name.
my @links = $mech->followable_links();
$mech->link_content_like( \@links, qr/Restricted/,
'Check all links are restricted' );
π§ $mech->link_content_unlike( $links, $regex [, $desc ] )
Follow specified links on the current page and test that the resulting content of each does not match $regex. The links may be specified as a reference to an array containing WWW::Mechanize::Link objects, an array of URLs, or a scalar URL name.
my @links = $mech->followable_links();
$mech->link_content_unlike( \@links, qr/Restricted/,
'No restricted links' );
π $mech->stuff_inputs( [\%options] )
okay this one is unhinged in the best way and I'm obsessed. π«Ά It finds all free-text input fields (text, textarea, and password) in the current form and fills them to their maximum length in hopes of finding application code that can't handle it. Fields with no maximum length and all textarea fields are set to 66000 bytes, which will often be enough to overflow the data's eventual receptacle. basically we're stress-testing your app by being that friend who fills the whole form with nonsense. iconic behaviour honestly.
There is no return value.
If there is no current form then nothing is done.
The hashref $options can contain the following keys:
ignoreβ hash value is arrayref of field names to not touch, e.g.:
$mech->stuff_inputs( {
ignore => [qw( specialfield1 specialfield2 )],
} );
fillβ hash value is default string to use when stuffing fields. Copies of the string are repeated up to the max length of each field. E.g.:
$mech->stuff_inputs( {
fill => '@' # stuff all fields with something easy to recognize
} );
specsβ hash value is arrayref of hashrefs with which you can pass detailed instructions about how to stuff a given field. E.g.:
$mech->stuff_inputs( {
specs=>{
# Some fields are datatype-constrained. It's most common to
# want the field stuffed with valid data.
widget_quantity => { fill=>'9' },
notes => { maxlength=>2000 },
}
} );
The specs allowed are fill (use this fill for the field rather than the default) and maxlength (use this as the field's maxlength instead of any maxlength specified in the HTML).
π AUTHOR
Leon Brocard <acme@astray.com>
π COPYRIGHT AND LICENSE
This software is copyright (c) 2009 by Leon Brocard.
This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself.
okay that's the whole page bestie, you made it to the end π this was Test::...::PSGI(3pm) from the Perl 5 documentation, generated for perl v5.36.0 and dated 2022-08-28 β so yes, your fave is a 2022 baby running on 5.36, and she ate. go forth and test all the things, no cap. π
β¨π
π¦ where this page comes from
- ubuntu noble: libtest-www-mechanize-psgi-perl 0.39-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu resolute: libtest-www-mechanize-psgi-perl 0.39-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libtest-www-mechanize-psgi-perl 0.39-2 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms