.\" Automatically generated by Pod::Man 2.28 (Pod::Simple 3.28) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is turned on, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{ . if \nF \{ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" .\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). .\" Fear. Run. Save yourself. No user-serviceable parts. . \" fudge factors for nroff and troff .if n \{\ . ds #H 0 . ds #V .8m . ds #F .3m . ds #[ \f1 . ds #] \fP .\} .if t \{\ . ds #H ((1u-(\\\\n(.fu%2u))*.13m) . ds #V .6m . ds #F 0 . ds #[ \& . ds #] \& .\} . \" simple accents for nroff and troff .if n \{\ . ds ' \& . ds ` \& . ds ^ \& . ds , \& . ds ~ ~ . ds / .\} .if t \{\ . ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" . ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' . ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' . ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' . ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' . ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' .\} . \" troff and (daisy-wheel) nroff accents .ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' .ds 8 \h'\*(#H'\(*b\h'-\*(#H' .ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] .ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' .ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' .ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] .ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] .ds ae a\h'-(\w'a'u*4/10)'e .ds Ae A\h'-(\w'A'u*4/10)'E . \" corrections for vroff .if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' .if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' . \" for low resolution devices (crt and lpr) .if \n(.H>23 .if \n(.V>19 \ \{\ . ds : e . ds 8 ss . ds o a . ds d- d\h'-1'\(ga . ds D- D\h'-1'\(hy . ds th \o'bp' . ds Th \o'LP' . ds ae ae . ds Ae AE .\} .rm #[ #] #H #V #F C .\" ======================================================================== .\" .IX Title "Test::Mojo 3pm" .TH Test::Mojo 3pm "2014-10-22" "perl v5.20.1" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Test::Mojo \- Testing Mojo! .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 2 \& use Test::More; \& use Test::Mojo; \& \& my $t = Test::Mojo\->new(\*(AqMyApp\*(Aq); \& \& # HTML/XML \& $t\->get_ok(\*(Aq/welcome\*(Aq)\->status_is(200)\->text_is(\*(Aqdiv#message\*(Aq => \*(AqHello!\*(Aq); \& \& # JSON \& $t\->post_ok(\*(Aq/search.json\*(Aq => form => {q => \*(AqPerl\*(Aq}) \& \->status_is(200) \& \->header_is(\*(AqServer\*(Aq => \*(AqMojolicious (Perl)\*(Aq) \& \->header_isnt(\*(AqX\-Bender\*(Aq => \*(AqBite my shiny metal ass!\*(Aq) \& \->json_is(\*(Aq/results/4/title\*(Aq => \*(AqPerl rocks!\*(Aq) \& \->json_like(\*(Aq/results/7/title\*(Aq => qr/Perl/); \& \& # WebSocket \& $t\->websocket_ok(\*(Aq/echo\*(Aq) \& \->send_ok(\*(Aqhello\*(Aq) \& \->message_ok \& \->message_is(\*(Aqecho: hello\*(Aq) \& \->finish_ok; \& \& done_testing(); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" Test::Mojo is a collection of testing helpers for everyone developing Mojo and Mojolicious applications, it is usually used together with Test::More. .SH "ATTRIBUTES" .IX Header "ATTRIBUTES" Test::Mojo implements the following attributes. .SS "message" .IX Subsection "message" .Vb 2 \& my $msg = $t\->message; \& $t = $t\->message([text => $bytes]); .Ve .PP Current WebSocket message represented as an array reference containing the frame type and payload. .PP .Vb 5 \& # More specific tests \& use Mojo::JSON \*(Aqdecode_json\*(Aq; \& my $hash = decode_json $t\->message\->[1]; \& is ref $hash, \*(AqHASH\*(Aq, \*(Aqright reference\*(Aq; \& is $hash\->{foo}, \*(Aqbar\*(Aq, \*(Aqright value\*(Aq; \& \& # Test custom message \& $t\->message([binary => $bytes]) \& \->json_message_has(\*(Aq/foo/bar\*(Aq) \& \->json_message_hasnt(\*(Aq/bar\*(Aq) \& \->json_message_is(\*(Aq/foo/baz\*(Aq => {yada => [1, 2, 3]}); .Ve .SS "success" .IX Subsection "success" .Vb 2 \& my $bool = $t\->success; \& $t = $t\->success($bool); .Ve .PP True if the last test was successful. .PP .Vb 11 \& # Build custom tests \& my $location_is = sub { \& my ($t, $value, $desc) = @_; \& $desc ||= "Location: $value"; \& local $Test::Builder::Level = $Test::Builder::Level + 1; \& return $t\->success(is($t\->tx\->res\->headers\->location, $value, $desc)); \& }; \& $t\->get_ok(\*(Aq/\*(Aq) \& \->status_is(302) \& \->$location_is(\*(Aqhttp://mojolicio.us\*(Aq) \& \->or(sub { diag \*(AqMust have been Joel!\*(Aq }); .Ve .SS "tx" .IX Subsection "tx" .Vb 2 \& my $tx = $t\->tx; \& $t = $t\->tx(Mojo::Transaction::HTTP\->new); .Ve .PP Current transaction, usually a Mojo::Transaction::HTTP object. .PP .Vb 3 \& # More specific tests \& is $t\->tx\->res\->json\->{foo}, \*(Aqbar\*(Aq, \*(Aqright value\*(Aq; \& ok $t\->tx\->res\->content\->is_multipart, \*(Aqmultipart content\*(Aq; \& \& # Test custom transactions \& $t\->tx($t\->tx\->previous)\->status_is(302)\->header_like(Location => qr/foo/); .Ve .SS "ua" .IX Subsection "ua" .Vb 2 \& my $ua = $t\->ua; \& $t = $t\->ua(Mojo::UserAgent\->new); .Ve .PP User agent used for testing, defaults to a Mojo::UserAgent object. .PP .Vb 2 \& # Allow redirects \& $t\->ua\->max_redirects(10); \& \& # Use absolute URL for request with Basic authentication \& my $url = $t\->ua\->server\->url\->userinfo(\*(Aqsri:secr3t\*(Aq)\->path(\*(Aq/secrets.json\*(Aq); \& $t\->post_ok($url => json => {limit => 10}) \& \->status_is(200) \& \->json_is(\*(Aq/1/content\*(Aq, \*(AqMojo rocks!\*(Aq); \& \& # Customize all transactions (including followed redirects) \& $t\->ua\->on(start => sub { \& my ($ua, $tx) = @_; \& $tx\->req\->headers\->accept_language(\*(Aqen\-US\*(Aq); \& }); .Ve .SH "METHODS" .IX Header "METHODS" Test::Mojo inherits all methods from Mojo::Base and implements the following new ones. .SS "app" .IX Subsection "app" .Vb 2 \& my $app = $t\->app; \& $t = $t\->app(MyApp\->new); .Ve .PP Access application with \*(L"app\*(R" in Mojo::UserAgent::Server. .PP .Vb 2 \& # Change log level \& $t\->app\->log\->level(\*(Aqfatal\*(Aq); \& \& # Test application directly \& is $t\->app\->defaults\->{foo}, \*(Aqbar\*(Aq, \*(Aqright value\*(Aq; \& ok $t\->app\->routes\->find(\*(Aqecho\*(Aq)\->is_websocket, \*(AqWebSocket route\*(Aq; \& my $c = $t\->app\->build_controller; \& ok $c\->render(template => \*(Aqfoo\*(Aq), \*(Aqrendering was successful\*(Aq; \& is $c\->res\->status, 200, \*(Aqright status\*(Aq; \& is $c\->res\->body, \*(AqFoo!\*(Aq, \*(Aqright content\*(Aq; \& \& # Change application behavior \& $t\->app\->hook(before_dispatch => sub { \& my $c = shift; \& $c\->render(text => \*(AqThis request did not reach the router.\*(Aq) \& if $c\->req\->url\->path\->contains(\*(Aq/user\*(Aq); \& }); \& \& # Extract additional information \& my $stash; \& $t\->app\->hook(after_dispatch => sub { $stash = shift\->stash }); .Ve .SS "content_is" .IX Subsection "content_is" .Vb 2 \& $t = $t\->content_is(\*(Aqworking!\*(Aq); \& $t = $t\->content_is(\*(Aqworking!\*(Aq, \*(Aqright content\*(Aq); .Ve .PP Check response content for exact match after retrieving it from \&\*(L"text\*(R" in Mojo::Message. .SS "content_isnt" .IX Subsection "content_isnt" .Vb 2 \& $t = $t\->content_isnt(\*(Aqworking!\*(Aq); \& $t = $t\->content_isnt(\*(Aqworking!\*(Aq, \*(Aqdifferent content\*(Aq); .Ve .PP Opposite of \*(L"content_is\*(R". .SS "content_like" .IX Subsection "content_like" .Vb 2 \& $t = $t\->content_like(qr/working!/); \& $t = $t\->content_like(qr/working!/, \*(Aqright content\*(Aq); .Ve .PP Check response content for similar match after retrieving it from \&\*(L"text\*(R" in Mojo::Message. .SS "content_unlike" .IX Subsection "content_unlike" .Vb 2 \& $t = $t\->content_unlike(qr/working!/); \& $t = $t\->content_unlike(qr/working!/, \*(Aqdifferent content\*(Aq); .Ve .PP Opposite of \*(L"content_like\*(R". .SS "content_type_is" .IX Subsection "content_type_is" .Vb 2 \& $t = $t\->content_type_is(\*(Aqtext/html\*(Aq); \& $t = $t\->content_type_is(\*(Aqtext/html\*(Aq, \*(Aqright content type\*(Aq); .Ve .PP Check response \f(CW\*(C`Content\-Type\*(C'\fR header for exact match. .SS "content_type_isnt" .IX Subsection "content_type_isnt" .Vb 2 \& $t = $t\->content_type_isnt(\*(Aqtext/html\*(Aq); \& $t = $t\->content_type_isnt(\*(Aqtext/html\*(Aq, \*(Aqdifferent content type\*(Aq); .Ve .PP Opposite of \*(L"content_type_is\*(R". .SS "content_type_like" .IX Subsection "content_type_like" .Vb 2 \& $t = $t\->content_type_like(qr/text/); \& $t = $t\->content_type_like(qr/text/, \*(Aqright content type\*(Aq); .Ve .PP Check response \f(CW\*(C`Content\-Type\*(C'\fR header for similar match. .SS "content_type_unlike" .IX Subsection "content_type_unlike" .Vb 2 \& $t = $t\->content_type_unlike(qr/text/); \& $t = $t\->content_type_unlike(qr/text/, \*(Aqdifferent content type\*(Aq); .Ve .PP Opposite of \*(L"content_type_like\*(R". .SS "delete_ok" .IX Subsection "delete_ok" .Vb 4 \& $t = $t\->delete_ok(\*(Aq/foo\*(Aq); \& $t = $t\->delete_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => \*(AqHi!\*(Aq); \& $t = $t\->delete_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => form => {a => \*(Aqb\*(Aq}); \& $t = $t\->delete_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => json => {a => \*(Aqb\*(Aq}); .Ve .PP Perform a \f(CW\*(C`DELETE\*(C'\fR request and check for transport errors, takes the same arguments as \*(L"delete\*(R" in Mojo::UserAgent, except for the callback. .SS "element_exists" .IX Subsection "element_exists" .Vb 2 \& $t = $t\->element_exists(\*(Aqdiv.foo[x=y]\*(Aq); \& $t = $t\->element_exists(\*(Aqhtml head title\*(Aq, \*(Aqhas a title\*(Aq); .Ve .PP Checks for existence of the \s-1CSS\s0 selectors first matching \s-1HTML/XML\s0 element with \&\*(L"at\*(R" in Mojo::DOM. .SS "element_exists_not" .IX Subsection "element_exists_not" .Vb 2 \& $t = $t\->element_exists_not(\*(Aqdiv.foo[x=y]\*(Aq); \& $t = $t\->element_exists_not(\*(Aqhtml head title\*(Aq, \*(Aqhas no title\*(Aq); .Ve .PP Opposite of \*(L"element_exists\*(R". .SS "finish_ok" .IX Subsection "finish_ok" .Vb 3 \& $t = $t\->finish_ok; \& $t = $t\->finish_ok(1000); \& $t = $t\->finish_ok(1003 => \*(AqCannot accept data!\*(Aq); .Ve .PP Close WebSocket connection gracefully. .SS "finished_ok" .IX Subsection "finished_ok" .Vb 1 \& $t = $t\->finished_ok(1000); .Ve .PP Wait for WebSocket connection to be closed gracefully and check status. .SS "get_ok" .IX Subsection "get_ok" .Vb 4 \& $t = $t\->get_ok(\*(Aq/foo\*(Aq); \& $t = $t\->get_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => \*(AqHi!\*(Aq); \& $t = $t\->get_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => form => {a => \*(Aqb\*(Aq}); \& $t = $t\->get_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => json => {a => \*(Aqb\*(Aq}); .Ve .PP Perform a \f(CW\*(C`GET\*(C'\fR request and check for transport errors, takes the same arguments as \*(L"get\*(R" in Mojo::UserAgent, except for the callback. .PP .Vb 2 \& # Run tests against remote host \& $t\->get_ok(\*(Aqhttp://mojolicio.us/perldoc\*(Aq)\->status_is(200); \& \& # Run additional tests on the transaction \& $t\->get_ok(\*(Aq/foo\*(Aq)\->status_is(200); \& is $t\->tx\->res\->dom\->at(\*(Aqinput\*(Aq)\->val, \*(Aqwhatever\*(Aq, \*(Aqright value\*(Aq; .Ve .SS "head_ok" .IX Subsection "head_ok" .Vb 4 \& $t = $t\->head_ok(\*(Aq/foo\*(Aq); \& $t = $t\->head_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => \*(AqHi!\*(Aq); \& $t = $t\->head_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => form => {a => \*(Aqb\*(Aq}); \& $t = $t\->head_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => json => {a => \*(Aqb\*(Aq}); .Ve .PP Perform a \f(CW\*(C`HEAD\*(C'\fR request and check for transport errors, takes the same arguments as \*(L"head\*(R" in Mojo::UserAgent, except for the callback. .SS "header_is" .IX Subsection "header_is" .Vb 2 \& $t = $t\->header_is(ETag => \*(Aq"abc321"\*(Aq); \& $t = $t\->header_is(ETag => \*(Aq"abc321"\*(Aq, \*(Aqright header\*(Aq); .Ve .PP Check response header for exact match. .SS "header_isnt" .IX Subsection "header_isnt" .Vb 2 \& $t = $t\->header_isnt(Etag => \*(Aq"abc321"\*(Aq); \& $t = $t\->header_isnt(ETag => \*(Aq"abc321"\*(Aq, \*(Aqdifferent header\*(Aq); .Ve .PP Opposite of \*(L"header_is\*(R". .SS "header_like" .IX Subsection "header_like" .Vb 2 \& $t = $t\->header_like(ETag => qr/abc/); \& $t = $t\->header_like(ETag => qr/abc/, \*(Aqright header\*(Aq); .Ve .PP Check response header for similar match. .SS "header_unlike" .IX Subsection "header_unlike" .Vb 2 \& $t = $t\->header_unlike(ETag => qr/abc/); \& $t = $t\->header_unlike(ETag => qr/abc/, \*(Aqdifferent header\*(Aq); .Ve .PP Opposite of \*(L"header_like\*(R". .SS "json_has" .IX Subsection "json_has" .Vb 2 \& $t = $t\->json_has(\*(Aq/foo\*(Aq); \& $t = $t\->json_has(\*(Aq/minibar\*(Aq, \*(Aqhas a minibar\*(Aq); .Ve .PP Check if \s-1JSON\s0 response contains a value that can be identified using the given \&\s-1JSON\s0 Pointer with Mojo::JSON::Pointer. .SS "json_hasnt" .IX Subsection "json_hasnt" .Vb 2 \& $t = $t\->json_hasnt(\*(Aq/foo\*(Aq); \& $t = $t\->json_hasnt(\*(Aq/minibar\*(Aq, \*(Aqno minibar\*(Aq); .Ve .PP Opposite of \*(L"json_has\*(R". .SS "json_is" .IX Subsection "json_is" .Vb 3 \& $t = $t\->json_is({foo => [1, 2, 3]}); \& $t = $t\->json_is(\*(Aq/foo\*(Aq => [1, 2, 3]); \& $t = $t\->json_is(\*(Aq/foo/1\*(Aq => 2, \*(Aqright value\*(Aq); .Ve .PP Check the value extracted from \s-1JSON\s0 response using the given \s-1JSON\s0 Pointer with Mojo::JSON::Pointer, which defaults to the root value if it is omitted. .SS "json_like" .IX Subsection "json_like" .Vb 2 \& $t = $t\->json_like(\*(Aq/foo/1\*(Aq => qr/^\ed+$/); \& $t = $t\->json_like(\*(Aq/foo/1\*(Aq => qr/^\ed+$/, \*(Aqright value\*(Aq); .Ve .PP Check the value extracted from \s-1JSON\s0 response using the given \s-1JSON\s0 Pointer with Mojo::JSON::Pointer for similar match. .SS "json_message_has" .IX Subsection "json_message_has" .Vb 2 \& $t = $t\->json_message_has(\*(Aq/foo\*(Aq); \& $t = $t\->json_message_has(\*(Aq/minibar\*(Aq, \*(Aqhas a minibar\*(Aq); .Ve .PP Check if \s-1JSON\s0 WebSocket message contains a value that can be identified using the given \s-1JSON\s0 Pointer with Mojo::JSON::Pointer. .SS "json_message_hasnt" .IX Subsection "json_message_hasnt" .Vb 2 \& $t = $t\->json_message_hasnt(\*(Aq/foo\*(Aq); \& $t = $t\->json_message_hasnt(\*(Aq/minibar\*(Aq, \*(Aqno minibar\*(Aq); .Ve .PP Opposite of \*(L"json_message_has\*(R". .SS "json_message_is" .IX Subsection "json_message_is" .Vb 3 \& $t = $t\->json_message_is({foo => [1, 2, 3]}); \& $t = $t\->json_message_is(\*(Aq/foo\*(Aq => [1, 2, 3]); \& $t = $t\->json_message_is(\*(Aq/foo/1\*(Aq => 2, \*(Aqright value\*(Aq); .Ve .PP Check the value extracted from \s-1JSON\s0 WebSocket message using the given \s-1JSON\s0 Pointer with Mojo::JSON::Pointer, which defaults to the root value if it is omitted. .SS "json_message_like" .IX Subsection "json_message_like" .Vb 2 \& $t = $t\->json_message_like(\*(Aq/foo/1\*(Aq => qr/^\ed+$/); \& $t = $t\->json_message_like(\*(Aq/foo/1\*(Aq => qr/^\ed+$/, \*(Aqright value\*(Aq); .Ve .PP Check the value extracted from \s-1JSON\s0 WebSocket message using the given \s-1JSON\s0 Pointer with Mojo::JSON::Pointer for similar match. .SS "json_message_unlike" .IX Subsection "json_message_unlike" .Vb 2 \& $t = $t\->json_message_unlike(\*(Aq/foo/1\*(Aq => qr/^\ed+$/); \& $t = $t\->json_message_unlike(\*(Aq/foo/1\*(Aq => qr/^\ed+$/, \*(Aqdifferent value\*(Aq); .Ve .PP Opposite of \*(L"json_message_like\*(R". .SS "json_unlike" .IX Subsection "json_unlike" .Vb 2 \& $t = $t\->json_unlike(\*(Aq/foo/1\*(Aq => qr/^\ed+$/); \& $t = $t\->json_unlike(\*(Aq/foo/1\*(Aq => qr/^\ed+$/, \*(Aqdifferent value\*(Aq); .Ve .PP Opposite of \*(L"json_like\*(R". .SS "message_is" .IX Subsection "message_is" .Vb 4 \& $t = $t\->message_is({binary => $bytes}); \& $t = $t\->message_is({text => $bytes}); \& $t = $t\->message_is(\*(Aqworking!\*(Aq); \& $t = $t\->message_is(\*(Aqworking!\*(Aq, \*(Aqright message\*(Aq); .Ve .PP Check WebSocket message for exact match. .SS "message_isnt" .IX Subsection "message_isnt" .Vb 4 \& $t = $t\->message_isnt({binary => $bytes}); \& $t = $t\->message_isnt({text => $bytes}); \& $t = $t\->message_isnt(\*(Aqworking!\*(Aq); \& $t = $t\->message_isnt(\*(Aqworking!\*(Aq, \*(Aqdifferent message\*(Aq); .Ve .PP Opposite of \*(L"message_is\*(R". .SS "message_like" .IX Subsection "message_like" .Vb 4 \& $t = $t\->message_like({binary => qr/$bytes/}); \& $t = $t\->message_like({text => qr/$bytes/}); \& $t = $t\->message_like(qr/working!/); \& $t = $t\->message_like(qr/working!/, \*(Aqright message\*(Aq); .Ve .PP Check WebSocket message for similar match. .SS "message_ok" .IX Subsection "message_ok" .Vb 2 \& $t = $t\->message_ok; \& $t = $t\->message_ok(\*(Aqgot a message\*(Aq); .Ve .PP Wait for next WebSocket message to arrive. .PP .Vb 6 \& # Wait for message and perform multiple tests on it \& $t\->websocket_ok(\*(Aq/time\*(Aq) \& \->message_ok \& \->message_like(qr/\ed+/) \& \->message_unlike(qr/\ew+/) \& \->finish_ok; .Ve .SS "message_unlike" .IX Subsection "message_unlike" .Vb 4 \& $t = $t\->message_unlike({binary => qr/$bytes/}); \& $t = $t\->message_unlike({text => qr/$bytes/}); \& $t = $t\->message_unlike(qr/working!/); \& $t = $t\->message_unlike(qr/working!/, \*(Aqdifferent message\*(Aq); .Ve .PP Opposite of \*(L"message_like\*(R". .SS "new" .IX Subsection "new" .Vb 3 \& my $t = Test::Mojo\->new; \& my $t = Test::Mojo\->new(\*(AqMyApp\*(Aq); \& my $t = Test::Mojo\->new(MyApp\->new); .Ve .PP Construct a new Test::Mojo object. .SS "options_ok" .IX Subsection "options_ok" .Vb 4 \& $t = $t\->options_ok(\*(Aq/foo\*(Aq); \& $t = $t\->options_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => \*(AqHi!\*(Aq); \& $t = $t\->options_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => form => {a => \*(Aqb\*(Aq}); \& $t = $t\->options_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => json => {a => \*(Aqb\*(Aq}); .Ve .PP Perform a \f(CW\*(C`OPTIONS\*(C'\fR request and check for transport errors, takes the same arguments as \*(L"options\*(R" in Mojo::UserAgent, except for the callback. .SS "or" .IX Subsection "or" .Vb 1 \& $t = $t\->or(sub {...}); .Ve .PP Invoke callback if the value of \*(L"success\*(R" is false. .PP .Vb 3 \& # Diagnostics \& $t\->get_ok(\*(Aq/bad\*(Aq)\->or(sub { diag \*(AqMust have been Glen!\*(Aq }) \& \->status_is(200)\->or(sub { diag $t\->tx\->res\->dom\->at(\*(Aqtitle\*(Aq)\->text }); .Ve .SS "patch_ok" .IX Subsection "patch_ok" .Vb 4 \& $t = $t\->patch_ok(\*(Aq/foo\*(Aq); \& $t = $t\->patch_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => \*(AqHi!\*(Aq); \& $t = $t\->patch_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => form => {a => \*(Aqb\*(Aq}); \& $t = $t\->patch_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => json => {a => \*(Aqb\*(Aq}); .Ve .PP Perform a \f(CW\*(C`PATCH\*(C'\fR request and check for transport errors, takes the same arguments as \*(L"patch\*(R" in Mojo::UserAgent, except for the callback. .SS "post_ok" .IX Subsection "post_ok" .Vb 4 \& $t = $t\->post_ok(\*(Aq/foo\*(Aq); \& $t = $t\->post_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => \*(AqHi!\*(Aq); \& $t = $t\->post_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => form => {a => \*(Aqb\*(Aq}); \& $t = $t\->post_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => json => {a => \*(Aqb\*(Aq}); .Ve .PP Perform a \f(CW\*(C`POST\*(C'\fR request and check for transport errors, takes the same arguments as \*(L"post\*(R" in Mojo::UserAgent, except for the callback. .PP .Vb 3 \& # Test file upload \& $t\->post_ok(\*(Aq/upload\*(Aq => form => {foo => {content => \*(Aqbar\*(Aq}}) \& \->status_is(200); \& \& # Test JSON API \& $t\->post_ok(\*(Aq/hello.json\*(Aq => json => {hello => \*(Aqworld\*(Aq}) \& \->status_is(200) \& \->json_is({bye => \*(Aqworld\*(Aq}); .Ve .SS "put_ok" .IX Subsection "put_ok" .Vb 4 \& $t = $t\->put_ok(\*(Aq/foo\*(Aq); \& $t = $t\->put_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => \*(AqHi!\*(Aq); \& $t = $t\->put_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => form => {a => \*(Aqb\*(Aq}); \& $t = $t\->put_ok(\*(Aq/foo\*(Aq => {Accept => \*(Aq*/*\*(Aq} => json => {a => \*(Aqb\*(Aq}); .Ve .PP Perform a \f(CW\*(C`PUT\*(C'\fR request and check for transport errors, takes the same arguments as \*(L"put\*(R" in Mojo::UserAgent, except for the callback. .SS "request_ok" .IX Subsection "request_ok" .Vb 1 \& $t = $t\->request_ok(Mojo::Transaction::HTTP\->new); .Ve .PP Perform request and check for transport errors. .PP .Vb 3 \& # Request with custom method \& my $tx = $t\->ua\->build_tx(FOO => \*(Aq/test.json\*(Aq => json => {foo => 1}); \& $t\->request_ok($tx)\->status_is(200)\->json_is({success => 1}); \& \& # Custom WebSocket handshake \& my $tx = $t\->ua\->build_websocket_tx(\*(Aq/foo\*(Aq); \& $tx\->req\->headers\->remove(\*(AqUser\-Agent\*(Aq); \& $t\->request_ok($tx)\->message_ok\->message_is(\*(Aqbar\*(Aq)\->finish_ok; .Ve .SS "reset_session" .IX Subsection "reset_session" .Vb 1 \& $t = $t\->reset_session; .Ve .PP Reset user agent session. .SS "send_ok" .IX Subsection "send_ok" .Vb 6 \& $t = $t\->send_ok({binary => $bytes}); \& $t = $t\->send_ok({text => $bytes}); \& $t = $t\->send_ok({json => {test => [1, 2, 3]}}); \& $t = $t\->send_ok([$fin, $rsv1, $rsv2, $rsv3, $op, $payload]); \& $t = $t\->send_ok($chars); \& $t = $t\->send_ok($chars, \*(Aqsent successfully\*(Aq); .Ve .PP Send message or frame via WebSocket. .PP .Vb 6 \& # Send JSON object as "Text" message \& $t\->websocket_ok(\*(Aq/echo.json\*(Aq) \& \->send_ok({json => {test => \*(AqI X Mojolicious!\*(Aq}}) \& \->message_ok \& \->json_message_is(\*(Aq/test\*(Aq => \*(AqI X Mojolicious!\*(Aq) \& \->finish_ok; .Ve .SS "status_is" .IX Subsection "status_is" .Vb 2 \& $t = $t\->status_is(200); \& $t = $t\->status_is(200, \*(Aqright status\*(Aq); .Ve .PP Check response status for exact match. .SS "status_isnt" .IX Subsection "status_isnt" .Vb 2 \& $t = $t\->status_isnt(200); \& $t = $t\->status_isnt(200, \*(Aqdifferent status\*(Aq); .Ve .PP Opposite of \*(L"status_is\*(R". .SS "text_is" .IX Subsection "text_is" .Vb 2 \& $t = $t\->text_is(\*(Aqdiv.foo[x=y]\*(Aq => \*(AqHello!\*(Aq); \& $t = $t\->text_is(\*(Aqhtml head title\*(Aq => \*(AqHello!\*(Aq, \*(Aqright title\*(Aq); .Ve .PP Checks text content of the \s-1CSS\s0 selectors first matching \s-1HTML/XML\s0 element for exact match with \*(L"at\*(R" in Mojo::DOM. .SS "text_isnt" .IX Subsection "text_isnt" .Vb 2 \& $t = $t\->text_isnt(\*(Aqdiv.foo[x=y]\*(Aq => \*(AqHello!\*(Aq); \& $t = $t\->text_isnt(\*(Aqhtml head title\*(Aq => \*(AqHello!\*(Aq, \*(Aqdifferent title\*(Aq); .Ve .PP Opposite of \*(L"text_is\*(R". .SS "text_like" .IX Subsection "text_like" .Vb 2 \& $t = $t\->text_like(\*(Aqdiv.foo[x=y]\*(Aq => qr/Hello/); \& $t = $t\->text_like(\*(Aqhtml head title\*(Aq => qr/Hello/, \*(Aqright title\*(Aq); .Ve .PP Checks text content of the \s-1CSS\s0 selectors first matching \s-1HTML/XML\s0 element for similar match with \*(L"at\*(R" in Mojo::DOM. .SS "text_unlike" .IX Subsection "text_unlike" .Vb 2 \& $t = $t\->text_unlike(\*(Aqdiv.foo[x=y]\*(Aq => qr/Hello/); \& $t = $t\->text_unlike(\*(Aqhtml head title\*(Aq => qr/Hello/, \*(Aqdifferent title\*(Aq); .Ve .PP Opposite of \*(L"text_like\*(R". .SS "websocket_ok" .IX Subsection "websocket_ok" .Vb 2 \& $t = $t\->websocket_ok(\*(Aq/echo\*(Aq); \& $t = $t\->websocket_ok(\*(Aq/echo\*(Aq => {DNT => 1} => [\*(Aqv1.proto\*(Aq]); .Ve .PP Open a WebSocket connection with transparent handshake, takes the same arguments as \*(L"websocket\*(R" in Mojo::UserAgent, except for the callback. .PP .Vb 6 \& # WebSocket with permessage\-deflate compression \& $t\->websocket(\*(Aq/x\*(Aq => {\*(AqSec\-WebSocket\-Extensions\*(Aq => \*(Aqpermessage\-deflate\*(Aq}) \& \->send_ok(\*(Aqy\*(Aq x 50000) \& \->message_ok \& \->message_is(\*(Aqz\*(Aq x 50000) \& \->finish_ok; .Ve .SH "SEE ALSO" .IX Header "SEE ALSO" Mojolicious, Mojolicious::Guides, .