Acceptance Testing XVI - Final Resource Protection Test

The finished version of our Resource Protection Test


In the previous article, we created a skeleton version of our test. That version created and removed the objects for the test, but performed no real tests. In this one we'll create the final version of our actual test. It will use the page and step objects we created earlier and will call Codeception's commands to navigate through the MODX Manager and perform the tests.


MODX logo

This article assumes that you've installed and configured Composer, Codeception, PhpUnit, MODX, Java, WebDriver, and ChromeDriver as described in earlier articles, and that you've created the acceptance test support files from those articles.


Creating the Resource Protection Test

In a normal project, we might just add the additional code we need to our T16_ResourceProtectionCest.php file. Since this is a learning experience, though, I thought it would be good to have a separate final file rather than messing with the working code of our skeleton version.

In the _build directory, enter this command:

codecept generate:cest acceptance T17_ResourceProtectionFinal

You should see the test file (T17_ResourceProtectionFinalCest.php) in the _build/tests/acceptance/ directory.

The initial tests in this article will only work in MODX 2. I created them using MODX 2.8.1, but they should work with any recent 2.x.x version. Later on, we'll look at running tests in MODX 3.


Test Review

In our test, we create three users: an admin super user (JoeTester2), a user who should see the protected pages (PrivateUser), and a user who should not (PublicUser). We also create corresponding user groups (PrivateUsers and PublicUsers, a role for those users (TestRole), a protected resource (PrivateResource) and an unprotected resource (PublicResource). We also create two corresponding resource groups (PrivateResources and PublicResources), and finally, an ACL entry to protect all resources in the "PrivateResources" resource group (in other words, the "Private" resource).

We use JoeTester2 for the username instead of JoeTester because we don't want to mess with the original admin super user we created earlier.

Once the objects all exist, we test the ACL process by logging in the admin user (JoeTester2) to create the ACL entry that protects the hidden resource, then log out the admin, and log in each of the non-admin users to see if the ACL entry works as it should.


The Code

Use this code for the file (also available at GitHub here.

<?php
use Codeception\Util\Fixtures;
use Page\Acceptance\LoginPage;
use Page\Acceptance\ResourceTestPage;

class T17_ResourceProtectionFinalCest
{

    /** @var _generated\modX $modx */
    public $modx;
    private const ROLES = array('TestUser');
    private const USER_GROUPS = array('PublicUsers',
        'PrivateUsers');
    private const RESOURCE_GROUPS =
        array('PublicResources', 'PrivateResources');

    public static function _before(\Step\Acceptance\Objects $I) {
        /* Load data files */
        $users = include codecept_data_dir() .
            '/user_data.php';

        $resources = include codecept_data_dir() .
            '/resource_data.php';

        $modx = Fixtures::get('modx');
        assertTrue($modx instanceof modX);
        $I->createRoles($modx, self::ROLES);
        $I->createUserGroups($modx, self::USER_GROUPS);
        $I->createUsers($modx, $users);
        $I->createResourceGroups($modx, self::RESOURCE_GROUPS);
        $I->createResources($modx, $resources);
    }

    public static function _after(\Step\Acceptance\Objects $I) {
     // return;  /* allows examination of objects and ACL */

        $users = include codecept_data_dir() .
            '/user_data.php';
        $resources = include codecept_data_dir() .
            '/resource_data.php';
        $modx = Fixtures::get('modx');
        assertTrue($modx instanceof modX);
        $I->removeRoles($modx, self::ROLES);
        $I->removeUserGroups($modx, self::USER_GROUPS);
        $I->removeUsers($modx, $users);
        $I->removeResourceGroups($modx, self::RESOURCE_GROUPS);
        $I->removeResources($modx, $resources);
    }

    public function ResourceProtectionTest(AcceptanceTester $I)
    {
        assertTrue(true);
        $testPage = new ResourceTestPage($I);
        $wait = 2;

        /* Login admin user JoeTester2 */
        $loginPage = new LoginPage($I);
        $loginPage->login('JoeTester2', 'TesterPassword');
        $I->see('Content');
        $I->see('Manage');
        $I->wait($wait);

        /* *** Create ACL entry *** */

        /* Go to ACL panel */
        $I->wait($wait + 1);
        $I->moveMouseOver($testPage::$systemMenu);
        $I->click($testPage::$systemMenu);
        $I->wait(1);
        $I->moveMouseOver($testPage::$acl_option);

        $I->click($testPage::$acl_option);
        $I->wait($wait);

        /* Update PrivateUser user group */
        $I->clickWithRightButton($testPage::$privateUsersGroup);
        $I->wait($wait+2);

        $I->click($testPage::$updateUserGroupOption);
        $I->wait($wait);

        /* Select Permissions top tab */
        $I->click($testPage::$permissionsTab);
        $I->wait($wait);

        /* Select Resource Group Access left tab */
        $I->click($testPage::$resourceGroupAccessTab);

        $I->wait($wait);

        /* Create actual ACL entry */
        $I->click($testPage::$addResourceGroupButton);

        $I->wait($wait);

        /* Set Resource Group */
        $I->click($testPage::$resourceGroupInput);
        $I->wait($wait);

        $I->click($testPage::$privateResourcesOption);

        /* Set Context */
        $I->click($testPage::$contextInput);
        $I->wait($wait);

        $I->click($testPage::$mgrOption);

        /* Set Role */
        $I->click($testPage::$authorityInput);

        $I->wait($wait+2);

        $I->click($testPage::$testUserOption);

        /* Set Policy */
        $I->click($testPage::$policyInput);
        $I->wait($wait);

        $I->click($testPage::$resourceOption);

        $I->wait($wait);

        /* Save ACL entry */
        $I->click($testPage::$addResourcePanelSaveButton);
        $I->wait($wait);
        $I->reloadPage();

        /* Make sure JoeTester2 can see PublicResource
           and can't see PrivateResource */
        $I->wait($wait+1);
        $I->see("PublicResource");
        $I->dontSee("PrivateResource");

        /* Logout JoeTester2 */
        $I->wait($wait);
        $loginPage->logout();
        $I->wait($wait);
        $I->see('Password');

        /* Login PrivateUser */
        $I->wait($wait);
        $loginPage->login('PrivateUser', 'somepassword');
        $I->see('Content');
        $I->see('Manage');
        $I->wait($wait);

        /* Make sure Private resource is visible */
        $I->wait($wait);
        $I->see("PublicResource");
        $I->see("PrivateResource");

        /* Logout PrivateUser */
        $I->wait($wait);
        $loginPage->logout();
        $I->wait($wait);
        $I->see('Password');

        /* Login PublicUser */
        $I->wait($wait);
        $loginPage->login('PublicUser', 'somepassword');
        $I->see('Content');
        $I->see('Manage');
        $I->wait($wait);

        /* Make sure Private resource is not visible */
        $I->see("PublicResource");
        $I->dontSee("PrivateResource");

        /* Logout PublicUser */
        $I->wait($wait);
        $loginPage->logout();
        $I->wait($wait);
        $I->see('Password');
    }
}


Code Review

The _before() and _after() methods are unchanged from our skeleton test, but we've filled in the code between the comments.

One of the nice things about Codeception is that the language is fairly obvious. There's no need to explain $I->click(), $I->fillField(), $I->see(), or $I->wait(), so you should be able to follow the code above.

If you want to slow things down to get a better view of what's happening as the test runs, you can change the value of the $wait variable to a larger number. It's expressed in seconds.

If you want the test to run faster, you can change the $wait value to 0, but be aware that this will often make tests fail, especially tests that check the visibility of some object that shows up after another action (like the dropdown option in the ACL entry). Sometimes, the test will run so fast, that it will check for the visibility before the object is on the screen and fail to see it.

Over time, you'll also find that if your wait times are too short, the tests will all pass sometimes but not others, since it depends on how busy the server is. It's a good practice to leave a little leeway in the wait times so that any failures will be real ones rather than timing issues.

You may have noticed a new Codeception command that appears in our test: $I->moveMouseOver(). Sometimes, this is useful if the click() command doesn't work when it should. It can also work when hovering works and a click isn't necessary. In fact, the click that follows the first instance of moveMouseOver() in our code, isn't necessary in MODX 2, it is in MODX 3, however, which will come into play in future articles.

Important: another command, which we haven't used is $I->scrollTo(#locator). This can be critical if you are trying to click on a locator that's below the bottom of the screen. Use it before you call $I->click(). I have a 24" monitor, so I seldom use it, but if you have a smaller screen, you might need it.


JoeTester2

You might wonder why we test to make sure JoeTester2 can't see the PrivateResource after creating the ACL entry. After all, Joe is an Admin Super User. Shouldn't he be able to see a private resource? The answer is no, because of the way MODX protection works.

If a resource group is connected to a user group with a Resource Group Access ACL entry like the one we created. Resources in that resource group will be hidden from anyone who is not a member of the user group (unless a separate ACL entry grants them access too). JoeTester2 is not a member of the PrivateUsers user group, so the resource is hidden from him. That's why, as admin, it's a good idea to add yourself to all user groups. Otherwise it's easy to end up hiding resources from yourself as JoeTester2 does in our acceptance test.


Remote Operation

Since Acceptance tests are all performed in a browser (or a simulated browser), you can test a remote site while running Codeception from your local machine. All you need is the correct URL to get started. This will only work, though, if you don't need to set anything up ahead of time (e.g., creating users, resources, or database records), or you're willing to write acceptance code that sets thing up by navigating the site.

For example, our current test would not work unless we removed the _before() and _after() methods and created and removed the objects either manually, or with code running on the remote site. That said, testing a live, production site is almost always a bad idea and should only be used if you're not modifying *anything* at the site.

You could, however, set up a duplicate of your production site on the same server and run remote tests to make sure some of your custom code is working as it should in the production environment.


$I->reloadPage()

Notice that we call $I->reloadPage(); after saving the ACL entry. This is sometimes necessary to make changes show up on the screen. If you remove it from the code here, the test will fail because JoeTester2 will still see the PrivateResource because the new ACL entry won't affect the display until a new request is made.

If you watch closely as the test executes, after the "Save" button is clicked to save the ACL entry, both resources are visible in the tree until the page reloads.

The $I->reloadPage(); call is also sometimes necessary in order to switch tabs on some of the Ext grid displays. Until the page is reloaded, Codeception sometimes can't click on tabs even though they're visible on the screen. I have no idea why.


Coming Up

In the next articles, we'll look at running our test in multiple browsers using Codeception environments.



For more information on how to use MODX to create a web site, see my web site Bob's Guides, or better yet, buy my book: MODX: The Official Guide.

Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)



Comments (0)


Please login to comment.

  (Login)