NAME

Test::TCM::Role::API - Role to test PSGI-based JSON API using Test::Class::Moose.

SYNOPSIS

package TestsFor::MyApp::Controller::API::v1::Some::Thing

use Test::Class::Moose;
with qw(
    Test::TCM::Role::API
);

sub _api_route_prefix { '/api/v1' }

sub test_some_route ($test, $) {

    # Calls "GET /api/v1/character"
    $test->api_ok(
        'List characters',
        [GET => '/character'],
        {
            status       => HTTP_OK,
            json_content => {
                superhashof(
                    {
                        attributes =>
                          { map { $_ => ignore() } qw(id name created) },
                    }
                )
            },
        }
    );

    my $result = $test->api_ok(
        'Create character',
        [
            POST => '/character' => {
                name    => 'Player 1',
                user_id => 12345,
            }
        ],
        {
            status       => HTTP_OK,
            json_content => {
                success => 1,
                character_id => ignore(),
            },
        }
    );
    is( $result->{id},
        $test->fetch_last_character()->id,
        'Result has a proper character ID'
    );
}

REQUIRED METHODS

psgi_app

PSGI application we're testing.

ATTRIBUTES

api_client

PSGI-compatible API client to use. Built automatically using psgi_app method.

PRIVATE METHODS THAT CAN BE OVERRIDDEN

_api_content_type

Returns content type for this API, default: application/vnd.api+json.

_api_headers

Returns a hash of headers to add to $test->mech, defaults to ( Accept => _api_content_type() )

_api_route_prefix

Common prefix for all API requests. Defaults to the empty string.

_before_request_hook($request)

Method that is called right before request is made. Gets a complete HTTP::Request object as the only argument. You can inspect / modify this request as needed - e.g. to add additional authorization headers to it.

METHODS

api_ok($title, \@request_args, \%expected)

In: $title - (sub)test title
    \@request_args - request data, 3-elements array of:
        $method - HTTP method
        $route - route to call
        \%params - URL query params (for GET) or JSON data (for other
        request types)
    \%expected - hash of expected parameters with the following fields
        status - HTTP status code; defaults to any successful code
        json_content - reference to a structure we expect, to be passed to
        C<Test::Deep::cmp_deeply> (so C<Test::Deep>'s functions can be used
        to skip / ignore some methods in it).
Out: $json_content - if result was a valid JSON, otherwise undef

Perform API $method request on the $route and test its output against %expected values.

If _api_route_prefix() is implemented in the consuming class, the value it returns gets prepended to the route before request is performed.

AUTHOR

Ilya Chesnokov chesnokov@cpan.org.

LICENSE

Under the same terms as Perl itself.

CREDITS

Many thanks to the following people and organizations:

Sam Kington cpan@illuminated.co.uk

For the idea and the initial implementation.

All Around the World SASU https://allaroundtheworld.fr

For sponsoring this rewrite and publication.