The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package Smolder::Mech;
use strict;
use warnings;
use base 'Test::WWW::Mechanize';
use Smolder::Conf;
use Smolder::TestData qw(base_url);
use JSON qw(from_json);
use Test::Builder;
use Test::More;

=head1 NAME 

Smolder::Mech

=head1 DESCRIPTION

L<Test::WWW::Mechanize> subclass with some Smolder specific
helper methods

    my $mech = Smolder::Mech->new();
    $mech->login($user);

=head1 METHODS

=head2 login

This routine will go to the login form, provide credentials
and login. It receives the following named args, all required:

=over

=item username

The text to use for the username field

=item password

The text to use for the password field. If none is given, it will use
'testing'.

=back

    $mech->login(
        username    => $username,
        password    => 's3cr3t',
    );

=cut

sub login {
    my $self = shift;
    my %args = @_;
    my $url  = base_url() . '/public_auth/login';
    $self->get($url);
    $self->form_name('login');
    $self->set_fields(
        username => $args{username},
        password => $args{password},
    );
    $self->submit();
}

=head2 logout

Logout the current user.

    $mech->logout();

=cut

sub logout {
    my $self = shift;
    my $url  = base_url() . '/public_auth/logout';
    $self->get($url);
}

=head1 get

Extends C<get()> from L<Test::WWW::Mechanize> to also disconnect
any open Database handles before making a request if we are using
SQLite to avoid locking the database

=cut

sub get {
    my $self = shift;
    Smolder::DB->disconnect();
    return $self->SUPER::get(@_);
}

=head1 submit

Extends C<submit()> from L<Test::WWW::Mechanize> to also disconnect
any open Database handles before making a request if we are using
SQLite to avoid locking the database

=cut

sub submit {
    my $self = shift;
    Smolder::DB->disconnect();
    return $self->SUPER::submit(@_);
}

=head1 request

Extends C<request()> from L<Test::WWW::Mechanize> to also disconnect
any open Database handles before making a request if we are using
SQLite to avoid locking the database

=cut

sub request {
    my $self = shift;
    Smolder::DB->disconnect();
    return $self->SUPER::request(@_);
}

=head1 contains_message

This method will look in the C<X-JSON> HTTP header
of the response, look through each message in the
C<messages> array and see if any of them match
the given message.

If given message is a scalar, the message must match
exactly, else if it's a regex, then it will be matched
against that.

=cut

sub contains_message {
    my ($self, $match) = @_;
    my $resp = $self->response();
    my $json = from_json($self->response->header('X-JSON') || '{}');
    my $msgs = $json->{messages} || [];
    my $diag = "contains message $match.";

    # so test diagnostics are right
    local $Test::Builder::Level = $Test::Builder::Level + 1;

    foreach my $msg (@$msgs) {
        if (ref $match eq 'Regexp') {
            if ($msg->{msg} =~ $match) {
                ok(1, $diag);
                return 1;
            }
        } else {
            if (index($msg->{msg}, $match) != -1) {
                ok(1, $diag);
                return 1;
            }
        }
    }

    $diag = qq(Could not find message "$match". Existing messages are:\n)
      . join("\n", map { $_->{msg} } @$msgs);
    ok(0, $diag);
    return 0;
}

1;