denny/ShinyCMS

View on GitHub
t/controllers/controller_Discussion.t

Summary

Maintainability
Test Coverage
# ===================================================================
# File:        t/controllers/controller-Discussion.t
# Project:    ShinyCMS
# Purpose:    Tests for ShinyCMS discussion features
#
# Author:    Denny de la Haye <2019@denny.me>
# Copyright (c) 2009-2019 Denny de la Haye
#
# ShinyCMS is free software; you can redistribute it and/or modify it
# under the terms of either the GPL 2.0 or the Artistic License 2.0
# ===================================================================

use strict;
use warnings;

use Test::More;
use Test::WWW::Mechanize::Catalyst::WithContext;

use lib 't/support';
require 'login_helpers.pl';  ## no critic

my $t = Test::WWW::Mechanize::Catalyst->new( catalyst_app => 'ShinyCMS' );

my $schema = get_schema();

my $blog_discussion_id = $schema->resultset( 'Discussion' )->search({
    resource_type => 'BlogPost',
})->first->id;

my $forum_discussion_id = $schema->resultset( 'Discussion' )->search({
    resource_type => 'ForumPost',
})->first->id;

# Check that hand-munged/malformed URLs do something sensible
$t->get_ok(
    '/discussion',
    'Try to fetch /discussion with no params'
);
$t->title_is(
    'Home - ShinySite',
    '/discussion (with no params) redirects to /'
);
$t->get_ok(
    '/discussion/9999',
    "Try to view a discussion that doesn't exist"
);
$t->text_contains(
    'Discussion not found.',
    'Got appropriate error message'
);
$t->get_ok(
    "/discussion/$blog_discussion_id",
    'Try to view a discussion without context'
);
$t->title_is(
    'w1n5t0n - ShinySite',
    "/discussion/$blog_discussion_id redirects to parent blog post"
);
# Post comment as pseudonymous user
$t->follow_link_ok(
    { text => 'Add a new comment' },
    "Click 'Add a new comment' link"
);
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_type  => 'Unverified',
        author_email => 'tester1@shinycms.org',
        author_link  => 'https://shinycms.org',
        title        => 'First Test Comment',
        body         => 'This is a test comment, posted by a pseudonymous user.',
    }},
    'Posting a pseudonymous comment'
);
$t->content_contains(
    'This is a test comment, posted by a pseudonymous user.',
    'Comment posted successfully (pseudonymous)'
);
# Post another comment as pseudonymous user
$t->follow_link_ok(
    { text => 'Add a new comment' },
    "Click 'Add a new comment' link"
);
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_type  => 'Unverified',
        author_name  => 'Test Suite',
        author_email => 'tester2@shinycms.org',
        title        => 'Another Test Comment',
        body         => 'This is another pseudonymous test comment.',
    }},
    'Posting a pseudonymous comment with different author details set'
);
# Post comment as anonymous user
$t->follow_link_ok(
    { text => 'Add a new comment' },
    "Click 'Add a new comment' link"
);
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_type => 'Anonymous',
        title       => 'Second Test Comment',
        body        => 'This is a test comment, posted by an anonymous user.',
    }},
    'Posting an anonymous comment'
);
$t->content_contains(
    'This is a test comment, posted by an anonymous user.',
    'Comment posted successfully (anonymous)'
);
# Attempt to comment as a logged-in user, without logging in
my @anons1 = $t->text =~ m{Posted by Anonymous at}g;
$t->follow_link_ok(
    { text => 'Add a new comment' },
    "Click 'Add a new comment' link"
);
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_type => 'Site User',
        title       => 'Not logged in yet...',
        body        => 'This should post anonymously',
    }},
    'Trying to comment as a logged-in user without being a logged in user'
);
$t->content_contains(
    'This should post anonymously',
    'Comment posted successfully'
);
my @anons2 = $t->text =~ m{Posted by Anonymous at}g;
ok(
    2 + scalar @anons1 == scalar @anons2,
    'But comment was posted anonymously, despite attempted form param manipulation'
);

# Log in
my $comment_tester = create_test_user( 'comment_tester' );
$t = login_test_user( 'comment_tester', 'comment_tester' )
    or die 'Failed to log in as comment tester';

$t->get_ok(
    "/discussion/$blog_discussion_id/add-comment",
    'Fetch the add-comment page again'
);
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_type => 'Site User',
        title       => 'Third Test Comment',
        body        => 'This is a test comment, posted by a logged-in user.',
    }},
    'Posting a logged-in comment'
);
$t->content_contains(
    'This is a test comment, posted by a logged-in user.',
    'Comment posted successfully (logged-in user)'
);
$t->follow_link_ok(
    { text => 'Reply' },
    'Follow link to reply to a comment'
);
$t->title_like(
    qr{^Reply to:},
    'Reached page for posting a reply'
);
my $reply_path = $t->uri->path;
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_name => 'Testing Testing',
        author_type => 'Unverified',
        title       => 'First Reply',
        body        => 'This is a reply from a pseudonymous user.',
    }},
    'Posting a pseudonymous reply'
);
$t->follow_link_ok(
    { text => 'Reply', n => 8 },
    'Follow link to reply again'
);
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_type => 'Site User',
        title       => 'Second Reply',
        body        => 'This is a test reply from a logged-in user.',
    }},
    'Posting a logged-in reply'
);

# 'Like' a comment while logged in
$t->follow_link_ok(
    { text => '0 likes' },
    "Click 'like' on first comment, before logging out"
);

# Log out, then go back to where we were
my $path = $t->uri->path;
$t->follow_link_ok(
    { text => 'logout' },
    'Log out'
);
$t->get( $path );
# 'Like' a comment while logged out
$t->follow_link_ok(
    { text => '1 like' },
    "Click 'like' on first comment, after logging out"
);

# Log in as another user and like another comment
my $comment_liker = create_test_user( 'comment_liker' );
$t = login_test_user( 'comment_liker', 'comment_liker' )
    or die 'Failed to log in as comment liker';
$t->get( $path );
$t->follow_link_ok(
    { text => '0 likes' },
    "Click 'like' on an unliked comment, logged in as a different user"
);

my $like_link = $t->find_link( text => '1 like' );
my $like_url  = $like_link->url;

# Remove the logged-in like
$t->get( $path );
$t->follow_link_ok(
    { text => '1 like' },
    "Remove the 'like' again"
);

# Try to hide a comment without appropriate admin privs
my $hide_url = $like_url;
$hide_url =~ s{like}{hide};
$t->get( $hide_url );
$t->text_contains(
    'You do not have the ability to hide a comment',
    'Failed to hide a comment without moderator privs'
);

# Try to delete a comment without appropriate admin privs
my $delete_url = $like_url;
$delete_url =~ s{like}{delete};
$t->get( $delete_url );
$t->text_contains(
    'You do not have the ability to delete a comment',
    'Failed to delete a comment without moderator privs'
);


# Discussion attached to a forum post
$t->get_ok(
    "/discussion/$forum_discussion_id",
    'Try to view a forum discussion without context'
);
$t->title_is(
    'Laptop Contest! - ShinySite',
    "/discussion/$forum_discussion_id redirects to parent post on forums"
);
# Post comment as pseudonymous user
$t->follow_link_ok(
    { text => 'Add a new comment' },
    "Click 'Add a new comment' link"
);
$t->submit_form_ok({
    form_id => 'add_comment',
    fields => {
        author_type => 'Unverified',
        author_name => 'Test Suite',
        title       => 'Test Comment In Forum',
        body        => 'This is a test comment in the forums.',
    }},
    'Posting a comment in the forums'
);
$t->content_contains(
    'This is a test comment in the forums.',
    'Forum comment posted successfully'
);


# Create and log in as a comment moderator
my $moderator = create_test_admin( 'test_comment_mod', 'Comment Moderator' );
$t = login_test_user( $moderator->username, $moderator->username )
    or die 'Failed to log in as Comment Moderator';
# Check login was successful
my $c = $t->ctx;
ok(
    $c->user->has_role( 'Comment Moderator' ),
    'Logged in as Comment Moderator'
);
$t->get( $path );

# Hide and un-hide a comment
$t->follow_link_ok(
    { url_regex => qr{$hide_url$} },
    'Clicking link to hide a comment'
);
$t->text_contains(
    'Comment hidden',
    'Verified that comment was hidden'
);
$t->follow_link_ok(
    { url_regex => qr{$hide_url$} },
    'Clicking link to unhide the comment'
);
$t->text_contains(
    'Comment un-hidden',
    'Verified that comment was un-hidden'
);

# Delete a comment
$t->follow_link_ok(
    { url_regex => qr{$delete_url$} },
    'Clicking link to delete a comment'
);
$t->text_contains(
    'Comment deleted',
    'Verified that comment was deleted'
);

# Try to freeze/unfreeze discussion when not logged in as Discussion Admin
$t->get( "/discussion/$blog_discussion_id/freeze" );
$t->text_contains(
    'You do not have the ability to freeze a discussion.',
    'Attempting to freeze discussion when not logged in as admin gets error'
);
$t->get( "/discussion/$blog_discussion_id/unfreeze" );
$t->text_contains(
    'You do not have the ability to unfreeze a discussion.',
    'Attempting to unfreeze discussion when not logged in as admin gets error'
);


# Login as Discussion Admin and freeze/unfreeze discussion
my $admin = create_test_admin(
    'test_discussion_admin', 'Comment Moderator', 'Discussion Admin'
);
$t = login_test_user( $admin->username, $admin->username )
    or die 'Failed to log in as Discussion Admin';
# Check login was successful
$c = $t->ctx;
ok(
    $c->user->has_role( 'Discussion Admin' ),
    'Logged in as Discussion Admin'
);
$t->get( $path );

$t->follow_link_ok(
    { text => 'Freeze discussion' },
    "Click 'Freeze discussion' link"
);
$t->text_contains(
    'Discussion frozen',
    'Got confirmation message that discussion has been frozen'
);
$t->follow_link_ok(
    { text => 'Add a new comment' },
    "Click 'Add a new comment' link"
);
$t->text_contains(
    'Discussion is frozen; no new comments allowed.',
    'Got error message warning user that discussion has been frozen'
);
$t->post_ok(
    "/discussion/$blog_discussion_id/save-comment",
    {
        author_type => 'Anonymous',
        title       => 'Sneak Around Freeze?',
        body        => 'This is a test comment, on a frozen discussion.',
    },
    'Attempt to POST new comment directly despite warning'
);
$t->text_contains(
    'Discussion is frozen; no new comments allowed.',
    'Got same error message again'
);
$t->get_ok(
    $reply_path,
    'Attempt to visit the reply-to-comment page'
);
$t->text_contains(
    'Discussion is frozen; no new comments allowed.',
    'And get the same error message again'
);

$t->get( $path );
$t->follow_link_ok(
    { text => 'Unfreeze discussion' },
    "Click 'Unfreeze discussion' link"
);
$t->text_contains(
    'Discussion unfrozen',
    'Got confirmation message that discussion is now unfrozen'
);

$t->follow_link_ok(
    { text => 'Mark as spam' },
    "Click 'mark as spam' link on a comment"
);
$t->text_contains(
    "Comment marked as 'spam'",
    'Got confirmation message that comment is now marked as spam'
);

$t->follow_link_ok(
    { text => 'Add a new comment' },
    "Click 'Add a new comment' link again"
);
$t->text_contains(
    'Add your comment:',
    'Got form for adding a new comment'
);


# Call search method without setting search param
$c = $t->ctx;
my $results = $c->controller( 'Discussion' )->search( $c );
my $returns_undef = defined $results ? 0 : 1;
my $no_results    = defined $c->stash->{ discussion_results } ? 0 : 1;
ok(
    $returns_undef && $no_results,
    "search() without param('search') set returns undef & stashes no results"
);


# Tidy up
$moderator->user_logins->delete;
remove_test_admin( $moderator );

remove_test_user( $comment_liker  );

my $tester_like = $comment_tester->comments_like->first;
$tester_like->update({ user => undef });
$tester_like->comment->comments_like->delete;
$comment_tester->comments->delete;
remove_test_user( $comment_tester );

$schema->resultset( 'Comment' )->search({
    author_type => { '!=' => 'Site User' },
})->delete;


done_testing();