Laravel-adminlte: more tests to increase the code coverage & raise the code quality

Created on 27 Apr 2020  路  14Comments  路  Source: jeroennoten/Laravel-AdminLTE

We need tests for the new functions getBodyClasses & getBodyData in src/AdminLte.php and for some other files to increase code coverage.

A code coverage over 90% would be great 馃槃 and improve the methods of the library to raise the code quality / the score from __scrutinizer__.

  • [x] src/AdminLte.php:getBodyClasses
  • [x] src/AdminLte.php:getBodyData
  • [x] src/Console/AdminLteInstallCommand.php __(Rating F)__
  • [x] src/Console/AdminLtePluginCommand.php
  • [x] src/Console/AdminLteStatusCommand.php __(Rating D)__
  • [x] src/Console/AdminLteUpdateCommand.php
  • [x] src/Menu/Filters/SearchFilter.php
  • [x] src/Http/Helpers/CommandHelper.php
  • [x] src/Http/ViewComposers/AdminLteComposer.php
scheduled

Most helpful comment

Ok, I found the solution again 馃槃.

I copied your testMenuNavbarLeftFilter and added the config-function below your todo notices to override the config variables.

<?php
    public function testMenuNavbarLeftFilter()
    {
        $adminLte = $this->makeAdminLte();

        $this->getDispatcher()->listen(
            BuildingMenu::class,
            function (BuildingMenu $event) {
                $event->menu->add(['header' => 'profile']);
                $event->menu->add(['text' => 'profile', 'url' => '/profile', 'label' => 'labels']);

                $event->menu->add(['text' => 'topnav1', 'url' => '/url1', 'topnav' => true]);
                $event->menu->add(['text' => 'topnav2', 'url' => '/url2', 'topnav' => false]);

                $event->menu->add(['text' => 'topnav_r1', 'url' => '/url_r1', 'topnav_right' => true]);
                $event->menu->add(['text' => 'topnav_r2', 'url' => '/url_r2', 'topnav_right' => false]);

                $event->menu->add(['text' => 'topnav_u1', 'url' => '/url_u1', 'topnav_user' => true]);
                $event->menu->add(['text' => 'topnav_u2', 'url' => '/url_u2', 'topnav_user' => false]);
            }
        );

        // TODO: Set config('adminlte.layout_topnav') to null.
        config(['adminlte.layout_topnav' => null]);

        $navbarLMenu = $adminLte->menu('navbar-left');
        $this->assertCount(1, $navbarLMenu);
        $this->assertArrayNotHasKey(0, $navbarLMenu);
        $this->assertArrayNotHasKey(1, $navbarLMenu);
        $this->assertArrayNotHasKey(3, $navbarLMenu);
        $this->assertArrayNotHasKey(4, $navbarLMenu);
        $this->assertArrayNotHasKey(5, $navbarLMenu);
        $this->assertArrayNotHasKey(6, $navbarLMenu);
        $this->assertArrayNotHasKey(7, $navbarLMenu);
        $this->assertEquals('topnav1', $navbarLMenu[2]['text']);

        // TODO: Now, set config('adminlte.layout_topnav') to true and
        // make another set of assertions.

        config(['adminlte.layout_topnav' => true]);
    }

Then you should get the error again, to resolve this error we need to install a extra package called orchestral/testbench.

  1. run this composer command composer require --dev "orchestra/testbench:>=4.0"
  2. replace use PHPUnit\Framework\TestCase as BaseTestCase; with this use Orchestra\Testbench\TestCase as BaseTestCase;

This should remove the errors 馃槃 after some researches I came to the decision that we need this package to achieve min 90% testing.

@lacodimizer I hope it's ok to add the dev-package into this project.

All 14 comments

@REJack @lacodimizer Hello, I was trying to learn the testing mechanism myself. I have already implemented some tests related to the new filters available for the AdminLte::menu() method. Examples of methods implemented on tests/AdminLteTest.php file are:

<?php

use JeroenNoten\LaravelAdminLte\Events\BuildingMenu;

class AdminLteTest extends TestCase
{
    public function testMenu()
    {
        $adminLte = $this->makeAdminLte();

        $this->getDispatcher()->listen(
            BuildingMenu::class,
            function (BuildingMenu $event) {
                $event->menu->add(['text' => 'Home']);
            }
        );

        $menu = $adminLte->menu();

        $this->assertEquals('Home', $menu[0]['text']);
    }

    public function testMenuSidebarFilter()
    {
        $adminLte = $this->makeAdminLte();

        $this->getDispatcher()->listen(
            BuildingMenu::class,
            function (BuildingMenu $event) {
                $event->menu->add(['header' => 'profile']);
                $event->menu->add(['text' => 'profile', 'url' => '/profile', 'label' => 'labels']);

                $event->menu->add(['text' => 'topnav1', 'url' => '/url1', 'topnav' => true]);
                $event->menu->add(['text' => 'topnav2', 'url' => '/url2', 'topnav' => false]);

                $event->menu->add(['text' => 'topnav_r1', 'url' => '/url_r1', 'topnav_right' => true]);
                $event->menu->add(['text' => 'topnav_r2', 'url' => '/url_r2', 'topnav_right' => false]);

                $event->menu->add(['text' => 'topnav_u1', 'url' => '/url_u1', 'topnav_user' => true]);
                $event->menu->add(['text' => 'topnav_u2', 'url' => '/url_u2', 'topnav_user' => false]);
            }
        );

        $sidebarMenu = $adminLte->menu('sidebar');
        $this->assertCount(5, $sidebarMenu);
        $this->assertArrayNotHasKey(2, $sidebarMenu);
        $this->assertArrayNotHasKey(4, $sidebarMenu);
        $this->assertArrayNotHasKey(6, $sidebarMenu);
        $this->assertEquals('profile', $sidebarMenu[0]['header']);
        $this->assertEquals('topnav2', $sidebarMenu[3]['text']);
        $this->assertEquals('topnav_u2', $sidebarMenu[7]['text']);
    }

    public function testMenuNavbarRightFilter()
    {
        $adminLte = $this->makeAdminLte();

        $this->getDispatcher()->listen(
            BuildingMenu::class,
            function (BuildingMenu $event) {
                $event->menu->add(['header' => 'profile']);
                $event->menu->add(['text' => 'profile', 'url' => '/profile', 'label' => 'labels']);

                $event->menu->add(['text' => 'topnav1', 'url' => '/url1', 'topnav' => true]);
                $event->menu->add(['text' => 'topnav2', 'url' => '/url2', 'topnav' => false]);

                $event->menu->add(['text' => 'topnav_r1', 'url' => '/url_r1', 'topnav_right' => true]);
                $event->menu->add(['text' => 'topnav_r2', 'url' => '/url_r2', 'topnav_right' => false]);

                $event->menu->add(['text' => 'topnav_u1', 'url' => '/url_u1', 'topnav_user' => true]);
                $event->menu->add(['text' => 'topnav_u2', 'url' => '/url_u2', 'topnav_user' => false]);
            }
        );

        $navbarRMenu = $adminLte->menu('navbar-right');
        $this->assertCount(1, $navbarRMenu);
        $this->assertArrayNotHasKey(0, $navbarRMenu);
        $this->assertArrayNotHasKey(1, $navbarRMenu);
        $this->assertArrayNotHasKey(2, $navbarRMenu);
        $this->assertArrayNotHasKey(3, $navbarRMenu);
        $this->assertArrayNotHasKey(5, $navbarRMenu);
        $this->assertArrayNotHasKey(6, $navbarRMenu);
        $this->assertArrayNotHasKey(7, $navbarRMenu);
        $this->assertEquals('topnav_r1', $navbarRMenu[4]['text']);
    }

    public function testMenuNavbarUserFilter()
    {
        $adminLte = $this->makeAdminLte();

        $this->getDispatcher()->listen(
            BuildingMenu::class,
            function (BuildingMenu $event) {
                $event->menu->add(['header' => 'profile']);
                $event->menu->add(['text' => 'profile', 'url' => '/profile', 'label' => 'labels']);

                $event->menu->add(['text' => 'topnav1', 'url' => '/url1', 'topnav' => true]);
                $event->menu->add(['text' => 'topnav2', 'url' => '/url2', 'topnav' => false]);

                $event->menu->add(['text' => 'topnav_r1', 'url' => '/url_r1', 'topnav_right' => true]);
                $event->menu->add(['text' => 'topnav_r2', 'url' => '/url_r2', 'topnav_right' => false]);

                $event->menu->add(['text' => 'topnav_u1', 'url' => '/url_u1', 'topnav_user' => true]);
                $event->menu->add(['text' => 'topnav_u2', 'url' => '/url_u2', 'topnav_user' => false]);
            }
        );

        $navbarUMenu = $adminLte->menu('navbar-user');
        $this->assertCount(1, $navbarUMenu);
        $this->assertArrayNotHasKey(0, $navbarUMenu);
        $this->assertArrayNotHasKey(1, $navbarUMenu);
        $this->assertArrayNotHasKey(2, $navbarUMenu);
        $this->assertArrayNotHasKey(3, $navbarUMenu);
        $this->assertArrayNotHasKey(4, $navbarUMenu);
        $this->assertArrayNotHasKey(5, $navbarUMenu);
        $this->assertArrayNotHasKey(7, $navbarUMenu);
        $this->assertEquals('topnav_u1', $navbarUMenu[6]['text']);
    }
}

Currently, testMenuSidebarFilter(), testMenuNavbarRightFilter() and testMenuNavbarUserFilter() works nicely when testing with command vendor/bin/phpunit --coverage-text. However, I'm facing a problem when trying to generate a test for a method that access configuration parameters. On the next example, the call to $adminLte->menu('navbar-left') will force an access to configuration:

<?php

public function testMenuNavbarLeftFilter()
{
    $adminLte = $this->makeAdminLte();

    $this->getDispatcher()->listen(
        BuildingMenu::class,
        function (BuildingMenu $event) {
            $event->menu->add(['header' => 'profile']);
            $event->menu->add(['text' => 'profile', 'url' => '/profile', 'label' => 'labels']);

            $event->menu->add(['text' => 'topnav1', 'url' => '/url1', 'topnav' => true]);
            $event->menu->add(['text' => 'topnav2', 'url' => '/url2', 'topnav' => false]);

            $event->menu->add(['text' => 'topnav_r1', 'url' => '/url_r1', 'topnav_right' => true]);
            $event->menu->add(['text' => 'topnav_r2', 'url' => '/url_r2', 'topnav_right' => false]);

            $event->menu->add(['text' => 'topnav_u1', 'url' => '/url_u1', 'topnav_user' => true]);
            $event->menu->add(['text' => 'topnav_u2', 'url' => '/url_u2', 'topnav_user' => false]);
        }
    );

    // TODO: Set config('adminlte.layout_topnav') to null.

    $navbarLMenu = $adminLte->menu('navbar-left');
    $this->assertCount(1, $navbarLMenu);
    $this->assertArrayNotHasKey(0, $navbarLMenu);
    $this->assertArrayNotHasKey(1, $navbarLMenu);
    $this->assertArrayNotHasKey(3, $navbarLMenu);
    $this->assertArrayNotHasKey(4, $navbarLMenu);
    $this->assertArrayNotHasKey(5, $navbarLMenu);
    $this->assertArrayNotHasKey(6, $navbarLMenu);
    $this->assertArrayNotHasKey(7, $navbarLMenu);
    $this->assertEquals('topnav1', $navbarLMenu[2]['text']);

    // TODO: Now, set config('adminlte.layout_topnav') to true and
    // make another set of assertions.
}

So, when trying to include the previous test (and execute with phpunit) I get the next error:

There was 1 error:

1) AdminLteTest::testMenuNavbarLeftFilter
Illuminate\Contracts\Container\BindingResolutionException: Target class [config] does not exist.

/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Container/Container.php:807
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Container/Container.php:687
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Container/Container.php:633
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:119
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:275
/home/diego/Projects/Github/Laravel-AdminLTE/src/AdminLte.php:227
/home/diego/Projects/Github/Laravel-AdminLTE/src/AdminLte.php:43
/home/diego/Projects/Github/Laravel-AdminLTE/tests/AdminLteTest.php:78

Caused by
ReflectionException: Class config does not exist

/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Container/Container.php:805
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Container/Container.php:687
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Container/Container.php:633
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:119
/home/diego/Projects/Github/Laravel-AdminLTE/vendor/laravel/framework/src/Illuminate/Foundation/helpers.php:275
/home/diego/Projects/Github/Laravel-AdminLTE/src/AdminLte.php:227
/home/diego/Projects/Github/Laravel-AdminLTE/src/AdminLte.php:43
/home/diego/Projects/Github/Laravel-AdminLTE/tests/AdminLteTest.php:78

ERRORS!
Tests: 61, Assertions: 146, Errors: 1.

Any suggestion on how to proceed on this? I already tried a few things that I have googled without success.

I'll check that out tomorrow. 馃槃 I had some similar problems with the tests in Laravel.

Ok, I found the solution again 馃槃.

I copied your testMenuNavbarLeftFilter and added the config-function below your todo notices to override the config variables.

<?php
    public function testMenuNavbarLeftFilter()
    {
        $adminLte = $this->makeAdminLte();

        $this->getDispatcher()->listen(
            BuildingMenu::class,
            function (BuildingMenu $event) {
                $event->menu->add(['header' => 'profile']);
                $event->menu->add(['text' => 'profile', 'url' => '/profile', 'label' => 'labels']);

                $event->menu->add(['text' => 'topnav1', 'url' => '/url1', 'topnav' => true]);
                $event->menu->add(['text' => 'topnav2', 'url' => '/url2', 'topnav' => false]);

                $event->menu->add(['text' => 'topnav_r1', 'url' => '/url_r1', 'topnav_right' => true]);
                $event->menu->add(['text' => 'topnav_r2', 'url' => '/url_r2', 'topnav_right' => false]);

                $event->menu->add(['text' => 'topnav_u1', 'url' => '/url_u1', 'topnav_user' => true]);
                $event->menu->add(['text' => 'topnav_u2', 'url' => '/url_u2', 'topnav_user' => false]);
            }
        );

        // TODO: Set config('adminlte.layout_topnav') to null.
        config(['adminlte.layout_topnav' => null]);

        $navbarLMenu = $adminLte->menu('navbar-left');
        $this->assertCount(1, $navbarLMenu);
        $this->assertArrayNotHasKey(0, $navbarLMenu);
        $this->assertArrayNotHasKey(1, $navbarLMenu);
        $this->assertArrayNotHasKey(3, $navbarLMenu);
        $this->assertArrayNotHasKey(4, $navbarLMenu);
        $this->assertArrayNotHasKey(5, $navbarLMenu);
        $this->assertArrayNotHasKey(6, $navbarLMenu);
        $this->assertArrayNotHasKey(7, $navbarLMenu);
        $this->assertEquals('topnav1', $navbarLMenu[2]['text']);

        // TODO: Now, set config('adminlte.layout_topnav') to true and
        // make another set of assertions.

        config(['adminlte.layout_topnav' => true]);
    }

Then you should get the error again, to resolve this error we need to install a extra package called orchestral/testbench.

  1. run this composer command composer require --dev "orchestra/testbench:>=4.0"
  2. replace use PHPUnit\Framework\TestCase as BaseTestCase; with this use Orchestra\Testbench\TestCase as BaseTestCase;

This should remove the errors 馃槃 after some researches I came to the decision that we need this package to achieve min 90% testing.

@lacodimizer I hope it's ok to add the dev-package into this project.

@REJack Nice, thanks you! I'm going to give it a try today.
Also, I have noted that the Spatie - Laravel Permission package uses this extra package too for the testing.
Maybe we should add this package to the composer.json and change the tests/TestCase.php file to use it, as you suggest.

UPDATE: I confirm those changes worked on my environment. I'm planing to submit a PR that will cover tests for the AdminLte.php file once we have permissions to include that dev-package to this project.

@REJack yes, you can add this dev-package into this project. :)

@REJack I have Added the PR #595 to include this dev-package, could you review it?

@Shidersz @REJack is merged

@lacodimizer Sweet 馃槃 I will start with artisan command tests soon.

@lacodimizer Nice! I just added tests for all the methods inside the AdminLte.php file (#598 ). @REJack I believe you can check as done the first two tasks.

@REJack The PR #636 covers the next items:

  • src/Menu/Filters/SearchFilter.php (82%)
  • src/Http/ViewComposers/AdminLteComposer.php (100%)

So, you can give a little update to this issue.

@REJack The PR #649 fully covers the CommandHelper class. My next step is to review the artisan commands...

@REJack @lacodimizer Finally we can close this one. The PR #679 was the last one needed to complete raise the quality and coverage.

Nice one @Shidersz you did a amazing job with the last PR 馃槃 99% is really great, I close this issue.

@REJack it should be 100% with the latest Laravel versions, but there are some tests that can't be executed with versions 6.x, however 99% is nice too! An example:

public function testInstallOnlyInteractive()
{
    // We can't do these test on old laravel versions.

    if (! class_exists('Illuminate\Testing\PendingCommand')) {
        $this->assertTrue(true);

        return;
    }

    // Test installation of the resources when using --interactive.

    foreach ($this->getResources() as $name => $res) {
        $confirmMsg = $res->getInstallMessage('install');

        // Ensure the required vendor assets exists, if needed.

        if ($name === 'assets') {
            $this->installVendorAssets();
        }

        // Ensure the target resource do not exists.

        $res->uninstall();

        // Test with --interactive option (response with no).

        $this->artisan("adminlte:install --only={$name} --interactive")
             ->expectsConfirmation($confirmMsg, 'no');

        $this->assertFalse($res->installed());

        // Test with --interactive option (response with yes).

        $this->artisan("adminlte:install --only={$name} --interactive")
             ->expectsConfirmation($confirmMsg, 'yes');

        $this->assertTrue($res->installed());

        // Clear the installed resource.

        $res->uninstall();
        $this->assertFalse($res->installed());
    }
}
Was this page helpful?
0 / 5 - 0 ratings