Kelp

 view release on metacpan or  search on metacpan

lib/Kelp/Test.pm  view on Meta::CPAN

    is $self->res->header($header), $value, $test_name
        || $self->diag_headers();
    return $self;
}

sub header_isnt
{
    my ($self, $header, $value, $test_name) = @_;
    local $Test::Builder::Level = $Test::Builder::Level + 1;

    $test_name ||= "Header '$header' is not '$value'";
    isnt $self->res->header($header), $value, $test_name
        || $self->diag_headers();
    return $self;
}

sub header_like
{
    my ($self, $header, $regexp, $test_name) = @_;
    local $Test::Builder::Level = $Test::Builder::Level + 1;

    $test_name ||= "Header '$header' =~ $regexp";
    like $self->res->header($header), $regexp, $test_name
        || $self->diag_headers();
    return $self;
}

sub header_unlike
{
    my ($self, $header, $regexp, $test_name) = @_;
    local $Test::Builder::Level = $Test::Builder::Level + 1;

    $test_name ||= "Header '$header' !~ $regexp";
    unlike $self->res->header($header), $regexp, $test_name
        || $self->diag_headers();
    return $self;
}

sub json_content
{
    my $self = shift;
    my $result;
    my $decoder = $self->app->get_encoder(json => 'internal');
    try {
        $result = $decoder->decode(
            $self->_decode($self->res->content)
        );
    }
    catch {
        fail("Poorly formatted JSON");
    };
    return $result;
}

sub json_cmp
{
    my ($self, $expected, $test_name) = @_;
    local $Test::Builder::Level = $Test::Builder::Level + 1;

    $test_name ||= "JSON structure matches";
    like $self->res->header('content-type'), qr/json/, 'Content-Type is JSON'
        or return $self;
    my $json = $self->json_content;
    cmp_deeply($json, $expected, $test_name) or diag explain $json;
    return $self;
}

sub note
{
    my $self = shift;
    Test::More::note @_;
    return $self;
}

sub diag_headers
{
    my $self = shift;
    diag $self->res->headers->as_string;
    return $self;
}

sub diag_content
{
    my $self = shift;
    diag $self->res->content;
    return $self;
}

1;

__END__

=pod

=head1 NAME

Kelp::Test - Automated tests for a Kelp web app

=head1 SYNOPSIS

    use MyApp;
    use Kelp::Test;
    use HTTP::Request::Common;

    my $app = MyApp->new;
    my $t = Kelp::Test->new( app => $app );

    $t->request( GET '/path' )
      ->code_is(200)
      ->content_is("It works");

    $t->request( POST '/api' )
      ->json_cmp({auth => 1});

    # automatically sets wide output for Test::More (disables Wide character warnings)
    use Kelp::Test -utf8;

=head1 DESCRIPTION

This module provides basic tools for testing a Kelp based web application. It
is object oriented, and all methods return C<$self>, so they can be chained

lib/Kelp/Test.pm  view on Meta::CPAN

    $t->request( POST '/api', [ user => 'jane' ] );

This method returns C<$self>, so other methods can be chained after it.

=head2 request_ok

C<request_ok( $http_request, $test_name )>

Runs C<request>, then tests if the response code is 200. Equivalent to the following
code:

    $t->request( GET '/path' )->code_is(200);
    $t->request_ok( GET '/path' );    # Same as the above

=head2 code_is, code_isnt

C<code_is( $code, $test_name )>, C<code_isnt( $code, $test_name )>

Tests if the last response returned a status code equal or not equal to C<$code>.
An optional name of the test can be added as a second parameter.

    $t->request( GET '/path' )->code_is(200);
    $t->request( GET '/path' )->code_isnt(500);

=head2 request_ok

Same as L</request>, but also runs C<code_is(200)>.

    $t->request_ok( GET '/home' );
    # Tests for code = 200

=head2 content_is, content_isnt

C<content_is( $value, $test_name )>, C<content_isnt( $value, $test_name )>

Tests if the last response returned content equal or not equal to C<$value>.
An optional name of the test can be added as a second parameter.

    $t->request( GET '/path' )->content_is("Ok.");
    $t->request( GET '/path' )->content_isnt("Fail.");

=head2 content_bytes_are

Same as C<content_is>, but the result is not decoded and the values are
compared byte by byte as hex-encoded string.

=head2 content_like, content_unlike

C<content_like( $regexp, $test_name )>, C<content_unlike( $regexp, $test_name )>

Tests if the last response returned content that matches or doesn't match C<$regexp>.
An optional name of the test can be added as a second parameter.

    $t->request( GET '/path' )->content_like(qr{Amsterdam});
    $t->request( GET '/path' )->content_unlike(qr{Rotterdam});

=head2 content_type_is, content_type_isnt

C<content_type_is( $value, $test_name )>, C<content_type_isnt( $value, $test_name )>

Tests if the last response's content-type header is equal or not equal to C<$value>.
An optional name of the test can be added as a second parameter.

    $t->request( GET '/path' )->content_type_is("text/plain");
    $t->request( GET '/path' )->content_type_isnt("text/html");

=head2 full_content_type_is

Like L</content_type_is>, but checks the full content type (with charset).

=head2 header_is, header_isnt

C<header_is( $header, $value, $test_name )>, C<header_isnt( $header, $value, $test_name )>

Tests if the last response returned a header C<$header> that is equal or not
equal to C<$value>. An optional name of the test can be added as a second parameter.

    $t->request( GET '/path' )->header_is( "Pragma", "no-cache" );
    $t->request( GET '/path' )->header_isnt( "X-Check", "yes" );

=head2 header_like, header_unlike

C<header_like( $header, $regexp, $test_name )>, C<header_unlike( $header, $regexp, $test_name )>

Tests if the last response returned a header C<$header> that matches or doesn't
match C<$regexp>. An optional name of the test can be added as a second parameter.

    $t->request( GET '/path' )->header_like( "Content-Type", qr/json/ );
    $t->request( GET '/path' )->header_unlike( "Content-Type", qr/image/ );

=head2 json_content

C<json_content()>

Returns the content decoded as JSON. Does not perform any checks, but may
C<fail()> and return C<undef> if the JSON decoding fails.

=head2 json_cmp

C<json_cmp( $expected, $test_name )>

This tests for two things: If the returned C<content-type> is
C<application-json>, and if the returned JSON structure matches the structure
specified in C<$expected>. To compare the two structures this method uses
C<cmp_deeply> from L<Test::Deep>, so you can use all the goodies from the
C<SPECIAL-COMPARISONS-PROVIDED> section of the Test::Deep module.

    $t->request( GET '/api' )->json_cmp(
        {
            auth      => 1,
            timestamp => ignore(),
            info      => subhashof( { name => 'Rick James' } )
        }
    );

An optional name of the test can be added as a second parameter.

=head2 note

C<note( $note )>

Print a note, using the L<Test::More> C<note> function.

    $t->request( GET '/path' )
      ->note("Checking headers now")
      ->header_is( "Content-Type", qr/json/ );

=head2 diag_headers

Prints all headers for debugging purposes.

    $t->request( GET '/path' )
      ->header_is( "Content-Type", qr/json/ )
      ->diag_headers();

=head2 diag_content

Prints the entire content for debugging purposes.

    $t->request( GET '/path' )
      ->content_is("Well")
      ->diag_content();

=cut



( run in 0.758 second using v1.01-cache-2.11-cpan-d7f47b0818f )