denny/ShinyCMS

View on GitHub
t/admin-controllers/controller_Admin-Shop.t

Summary

Maintainability
Test Coverage
# ===================================================================
# File:        t/admin-controllers/controller_Admin-Shop.t
# Project:    ShinyCMS
# Purpose:    Tests for shop admin 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 Try::Tiny;

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


# Create some supporting data if it doesn't already exist
my $schema = get_schema();
my $postage = $schema->resultset( 'PostageOption' )->find_or_create({
    name  => 'Standard',
    price => '2.22',
});


# Log in as a Shop Admin
my $admin = create_test_admin(
    'shop_test_admin',
    'Shop Admin'
);
my $t = login_test_admin( $admin->username, $admin->username )
    or die 'Failed to log in as Shop Admin';
# Check login was successful
my $c = $t->ctx;
ok(
    $c->user->has_role( 'Shop Admin' ),
    'Logged in as Shop Admin'
);
# Check we get sent to correct admin area by default
$t->title_is(
    'List Shop Items - ShinyCMS',
    'Reached shop admin area'
);


# Add a category
$t->follow_link_ok(
    { text => 'Add category' },
    'Click on link to add new shop category'
);
$t->submit_form_ok({
    form_id => 'add_category',
    fields => {
        name => 'Test Category',
    }},
    'Submitted form to add new shop category'
);
$t->title_is(
    'Edit Category - ShinyCMS',
    'Redirected to category edit page'
);
my @category_inputs1 = $t->grep_inputs({ name => qr{^url_name$} });
ok(
    $category_inputs1[0]->value eq 'test-category',
    'Verified that new category was successfully created'
);

# Update category
$t->submit_form_ok({
    form_id => 'edit_category',
    fields => {
        name     => 'Updated Test Category',
        url_name => '',
    }},
    'Submitted form to update shop category'
);
my @category_inputs2 = $t->grep_inputs({ name => qr{^url_name$} });
ok(
    $category_inputs2[0]->value eq 'updated-test-category',
    'Verified that category was successfully updated'
);
$t->submit_form_ok({
    form_id => 'edit_category',
    fields => {
        url_name => 'updated-test-category-with-custom-url-name',
    }},
    'Submitted form to update shop category url_name a bit more'
);
$t->uri->path =~ m{/admin/shop/category/(\d+)/edit};
my $category1_id = $1;

# Create a second category
$t->follow_link_ok(
    { text => 'Add category' },
    'Click on link to add second new shop category'
);
$t->submit_form_ok({
    form_id => 'add_category',
    fields => {
        name     => 'Second Test Category',
        url_name => 'second-test-category',
        parent   => $category1_id,
    }},
    'Submitted form to add second new shop category'
);
$t->submit_form_ok({
    form_id => 'edit_category',
    fields => {
        parent => undef,
    }},
    'Submitted form to edit second new shop category (remove parent)'
);
$t->submit_form_ok({
    form_id => 'edit_category',
    fields => {
        parent => $category1_id,
    }},
    'Submitted form to edit second new shop category (re-add parent)'
);
$t->uri->path =~ m{/admin/shop/category/(\d+)/edit};
my $category2_id = $1;

# Try to edit a non-existent category
$t->get_ok(
    '/admin/shop/category/999/edit',
    'Try to edit non-existent category'
);
$t->title_is(
    'Shop Categories - ShinyCMS',
    'Got redirected to list of categories instead'
);
$t->text_contains(
    'Specified category not found - please select from the options below',
    'Got a helpful error message about the non-existent category'
);


# Log in as a Template Admin
my $template_admin = create_test_admin(
    'shop_test_template_admin',
    'Shop Admin',
    'CMS Template Admin'
);
$t = login_test_admin( $template_admin->username, $template_admin->username )
    or die 'Failed to log in as Shop Admin + CMS Template Admin';
$c = $t->ctx;
ok(
    $c->user->has_role( 'Shop Admin' ) && $c->user->has_role( 'CMS Template Admin' ),
    'Logged in as Shop Admin + CMS Template Admin'
);


# Add a product type
$t->follow_link_ok(
    { text => 'Add product type' },
    'Click on link to add a new product type to the shop'
);
$t->submit_form_ok({
    form_id => 'add_product_type',
    fields => {
        name => 'Test Type'
    }},
    'Submitted form to add new product type'
);
$t->title_is(
    'Edit Product Type - ShinyCMS',
    'Redirected to edit page for product type'
);
my @type_inputs1 = $t->grep_inputs({ name => qr{^name$} });
ok(
    $type_inputs1[0]->value eq 'Test Type',
    'Verified that new product type was successfully created'
);

# Update product type
$t->submit_form_ok({
    form_id => 'edit_product_type',
    fields => {
        name => 'Updated Test Type',
    }},
    'Submitted form to update product type'
);
my @type_inputs2 = $t->grep_inputs({ name => qr{^name$} });
ok(
    $type_inputs2[0]->value eq 'Updated Test Type',
    'Verified that product type was successfully updated'
);
# Save product type ID for use when deleting
$t->uri->path =~ m{/admin/shop/product-type/(\d+)/edit};
my $product_type1_id = $1;

# Add element to product type
$t->submit_form_ok({
    form_id => 'add_element',
    fields => {
        new_element => 'test_type_element',
        new_type    => 'Long Text'
    }},
    'Submitted form to add new element to product type'
);
$t->text_contains(
    'test_type_element',
    'Verified that new element was added'
);

# Add second product type
$t->follow_link_ok(
    { text => 'Add product type' },
    'Click on link to add a second new product type to the shop'
);
$t->submit_form_ok({
    form_id => 'add_product_type',
    fields => {
        name => 'Second Test Type'
    }},
    'Submitted form to add second new product type'
);
$t->uri->path =~ m{/admin/shop/product-type/(\d+)/edit};
my $product_type2_id = $1;

# Try to view a non-existent product type
$t->get_ok(
    '/admin/shop/product-type/999/edit',
    'Try to edit non-existent product type'
);
$t->title_is(
    'Product Types - ShinyCMS',
    'Got redirected to list of product types instead'
);
$t->text_contains(
    'Specified product type not found - please select from the options below',
    'Got a helpful error message about the non-existent product type'
);


# Log back in as a normal shop admin
$t = login_test_admin( $admin->username, $admin->username )
    or die 'Failed to log in as Shop Admin';
$c = $t->ctx;
ok(
    $c->user->has_role( 'Shop Admin' ),
    'Logged back in as Shop Admin'
);

# Add a shop item
$t->follow_link_ok(
    { text => 'Add shop item' },
    'Click on link to add a new item to the shop'
);
$t->submit_form_ok({
    form_id => 'add_item',
    fields => {
        name            => 'Test Item',
        code            => 'test-item',
        tags            => 'test, tests',
        price           => '0',
        stock           => '1',
        hidden          => 'on',
        allow_comments  => 'on',
        postage_options => $postage->id,
        restock_date    => DateTime->now->ymd,
        product_type    => $product_type1_id,
        categories      => $category1_id,
    }},
    'Submitted form to add new item'
);
$t->title_is(
    'Edit Item - ShinyCMS',
    'Redirected to edit page for item'
);
my @item_inputs1 = $t->grep_inputs({ name => qr{^code$} });
ok(
    $item_inputs1[0]->value eq 'test-item',
    'Verified that new item was successfully created'
);

# Update item
$t->submit_form_ok({
    form_id => 'edit_item',
    fields => {
        name            => 'Updated Test Item',
        code            => '',
        tags            => '',
        price           => '',
        stock           => '',
        hidden          => undef,
        allow_comments  => undef,
        postage_options => undef,
        restock_date    => undef,
    }},
    'Submitted form to update item name and wipe a bunch of other stuff'
);
$t->submit_form_ok({
    form_id => 'edit_item',
    fields => {
        tags           => 'test, tests, tags',
        price          => '0',
        stock          => '1',
        hidden         => 'on',
        allow_comments => 'on',
        postage_options => $postage->id,
        restock_date    => DateTime->now->ymd,
        categories     => [ $category1_id, 1 ],
        categories     => [ $category2_id, 2 ],
    }},
    'Submitted form again, re-adding stuff, and adding a second category'
);
my @item_inputs2 = $t->grep_inputs({ name => qr{^code$} });
ok(
    $item_inputs2[0]->value eq 'updated-test-item',
    'Verified that item was successfully updated'
);
# Save item ID so we can delete it later
$t->uri->path =~ m{/admin/shop/item/(\d+)/edit};
my $item1_id = $1;


# Log in as Template Admin
my $edit_form_path = $t->uri->path;
$t = login_test_admin( $template_admin->username, $template_admin->username )
    or die 'Failed to log in as Shop Admin + CMS Template Admin';
$c = $t->ctx;
ok(
    $c->user->has_role( 'Shop Admin' ) && $c->user->has_role( 'CMS Template Admin' ),
    'Logged in as Shop Admin + CMS Template Admin'
);
$t->get_ok(
    $edit_form_path,
    'Return to edit item page as Template Admin'
);

# Edit item again, as Template Admin, to go through product-type code
$t->submit_form_ok({
    form_id => 'edit_item',
    fields => {
        tags   => 'test, tags, sort order, tests, so much testing',
        hidden => 'on',
    }},
    'And submit shop edit form again, to change the tags once more'
);
$t->content_contains(
    'so much testing, sort order, tags, test, tests',
    'Tags are stored alphabetically'
);

# Add element to item
$t->submit_form_ok({
    form_id => 'add_element',
    fields => {
        new_element => 'test_item_element',
        new_type    => 'Long Text'
    }},
    'Submitted form to add new element to item'
);
$t->text_contains(
    'Element added',
    'Verified that new element was added'
);

# Add a second shop item
$t->follow_link_ok(
    { text => 'Add shop item' },
    'Click on link to add a second new item to the shop'
);
$t->submit_form_ok({
    form_id => 'add_item',
    fields => {
        name           => 'Second Test Item',
        code           => '',
        tags           => '',
        price          => '',
        hidden         => 'on',
        allow_comments => undef,
        product_type   => $product_type1_id,
        categories     => [ $category1_id, 1 ],
        categories     => [ $category2_id, 2 ],
    }},
    'Submitted form to add second new item'
);
my @item2_inputs1 = $t->grep_inputs({ name => qr{^code$} });
ok(
    $item2_inputs1[0]->value eq 'second-test-item',
    'Verified that second new item was successfully created'
);
$t->submit_form_ok({
    form_id => 'edit_item',
    fields => {
        tags           => 'more tags, more tests',
        hidden         => undef,
        price          => '1.00',
        allow_comments => 'on',
        product_type   => $product_type2_id,
    }},
    'Submitted edit item form to enable comments, and try to change product type'
);
$t->submit_form_ok({
    form_id => 'edit_item',
    fields => {
        tags           => '',
        hidden         => undef,
        allow_comments => 'on',
    }},
    'Submitted edit item form a final time to wipe tags'
);
$t->uri->path =~ m{/admin/shop/item/(\d+)/edit};
my $item2_id = $1;

# Try to edit non-existent item
$t->get_ok(
    '/admin/shop/item/999/edit',
    'Try to edit non-existent item'
);
$t->title_is(
    'List Shop Items - ShinyCMS',
    'Got redirected to the list of shop items instead'
);
$t->text_contains(
    'Item not found: 999',
    'Got a semi-helpful error message about the non-existent item'
);

# Preview
$t->post_ok(
    '/shop/item/green-ambi-widget/preview',
    {
        name => 'Test Item',
        code => 'test-item',
        categories => $category1_id,
        product_type => $product_type1_id,
        name_1       => 'test_element',
        content_1    => 'Test content',
    },
    'Preview a shop item'
);
$t->title_is(
    'Test Item - ShinySite',
    'Previewed a shop item with name overridden'
);


# Create an order, directly in db rather than using demo site
my $shopper = create_test_user( 'test_shopper' );
my $order = $shopper->orders->create({
    email            => $shopper->email,
    billing_address  => '1a Test Street',
    billing_town     => 'Test Town',
    billing_country  => 'Testland',
    billing_postcode => 'A1 1AA',
});
my $order_item = $order->order_items->create({
    item     => $item1_id,
    quantity => '1',
});
my $order_item_id = $order_item->id;

# View the list of orders
$t->get_ok(
    '/admin/shop',
    'Return to shop admin area'
);
$t->follow_link_ok(
    { text => 'List orders' },
    'Try to view the list of orders'
);
$t->title_is(
    'Shop Orders - ShinyCMS',
    'Loaded list of orders'
);

# Edit an order
$t->follow_link_ok(
    { text => 'Edit' },
    'Click link to edit an order'
);
$t->submit_form_ok({
    form_id => 'edit_order',
    fields => {
        status => 'Awaiting payment',
        "quantity_$order_item_id" => '42',
        "postage_$order_item_id"  => '1.23',
    }},
    'Submit form to edit order, changing order status and quantity of first item'
);
$t->content_contains(
    'selected="selected">Awaiting payment</option>',
    'Verified that order status was changed'
);
$t->content_contains(
    '<input name="quantity_'.$order_item_id.'" value="42"',
    'Verified that item quantity was changed'
);

# Delete an item
$t->submit_form_ok({
    form_id => 'edit_order',
    fields => {
        "quantity_$order_item_id" => '0',
        "postage_$order_item_id"  => undef,
    }},
    'Submit form to edit order, deleting first item'
);

# TODO

# Try to edit a non-existent order
$t->get_ok(
    '/admin/shop/order/999',
    'Try to edit a non-existent order'
);
$t->title_is(
    'Shop Orders - ShinyCMS',
    'Redirected to list of orders instead'
);
$t->text_contains(
    'Specified order not found - please select from the orders below',
    'Got helpful error message about non-existent order'
);

# Cancel an order (can't use submit_form_ok due to javascript confirmation)
$t->post_ok(
    '/admin/shop/order/'.$order->id.'/save',
    {
        cancel => 'Cancel Order'
    },
    'Submitted request to cancel order'
);
$t->title_is(
    'Shop Orders - ShinyCMS',
    'Redirected to list of shop orders'
);
$t->text_contains(
    'Cancelled',
    'Verified that order was cancelled'
);

# Delete order (via db as there's no way to delete orders via site)
$order->order_items->delete;
$order->delete;


# Delete shop items (can't use submit_form_ok due to javascript confirmation)
$t->post_ok(
    '/admin/shop/item/'.$item1_id.'/save',
    {
        delete => 'Delete'
    },
    'Submitted request to delete item'
);
$t->title_is(
    'List Shop Items - ShinyCMS',
    'Redirected to list of shop items'
);
$t->content_lacks(
    'Updated Test Item',
    'Verified that item was deleted'
);
$t->post_ok(
    '/admin/shop/item/'.$item2_id.'/save',
    {
        delete => 'Delete'
    },
    'Submitted request to delete second item'
);
$t->content_lacks(
    'Second Test Item',
    'Verified that second item was deleted'
);

# Delete element from product type
$t->get_ok(
    '/admin/shop/product-type/'.$product_type1_id.'/edit',
    'Loaded product type edit page'
);
$t->follow_link_ok(
    { text => 'Delete' },
    'Click button link to delete element from product type'
);

# Delete product types
$t->post_ok(
    '/admin/shop/product-type/'.$product_type1_id.'/save',
    {
        delete => 'Delete'
    },
    'Submitted request to delete product type'
);
$t->post_ok(
    '/admin/shop/product-type/'.$product_type2_id.'/save',
    {
        delete => 'Delete'
    },
    'Submitted request to delete product type'
);
$t->title_is(
    'Product Types - ShinyCMS',
    'Redirected to list of product types'
);
$t->content_lacks(
    'Updated Test Type',
    'Verified that product type was deleted'
);
$t->content_lacks(
    'Second Test Type',
    'Verified that second product type was deleted'
);

# Delete categories
$t->post_ok(
    '/admin/shop/category/'.$category2_id.'/save',
    {
        delete => 'Delete'
    },
    'Submitted request to delete second category (child)'
);
$t->post_ok(
    '/admin/shop/category/'.$category1_id.'/save',
    {
        delete => 'Delete'
    },
    'Submitted request to delete first category (parent)'
);
$t->title_is(
    'Shop Categories - ShinyCMS',
    'Redirected to list of categories'
);
$t->content_lacks(
    'Updated Test Category',
    'Verified that first category was deleted'
);
$t->content_lacks(
    'Second Test Category',
    'Verified that second category was deleted'
);

# Try to get template filenames when template directory is missing
my $template_dir = $c->path_to( 'root/shop/product-type-templates' );
system( "mv $template_dir $template_dir.test" );
try {
    ShinyCMS::Controller::Admin::Shop->get_template_filenames( $c );
}
catch {
    ok(
        m{Failed to open template directory},
        'Caught die() for get_template_filenames() when template directory is missing.'
    );
};
system( "mv $template_dir.test $template_dir" );


# Log out, then try to access admin area for shop again
$t->follow_link_ok(
    { text => 'Logout' },
    'Log out of shop admin account'
);
$t->get_ok(
    '/admin/shop',
    'Try to access admin area for shop after logging out'
);
$t->title_is(
    'Log In - ShinyCMS',
    'Redirected to admin login page instead'
);

# Log in as the wrong sort of admin, and make sure we're still blocked
my $poll_admin = create_test_admin( 'test_admin_shop_poll_admin', 'Poll Admin' );
$t = login_test_admin( $poll_admin->username, $poll_admin->username )
    or die 'Failed to log in as Poll Admin';
$c = $t->ctx;
ok(
    $c->user->has_role( 'Poll Admin' ),
    'Logged in as Poll Admin'
);
$t->get_ok(
    '/admin/shop',
    'Try to access shop admin area'
);
$t->title_unlike(
    qr{^.*Shop.* - ShinyCMS$},
    'Poll Admin cannot view shop admin area'
);


# Tidy up user accounts
remove_test_admin( $template_admin );
remove_test_admin( $admin          );
remove_test_user(  $shopper        );
remove_test_admin( $poll_admin     );

done_testing();