In the previous article, we set up the MODX login code, and the Login page object in preparation for our test of creating users in the MODX Manager. In this one, we'll create two more page objects, one for the Manager Dashboard, and another for the Create/Edit User panel.

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.
Reviewing the Planned Test
Ultimately, our automated test will perform the following tests in the MODX Manager:
- Log in
- Create users in the manager
- Verify that the user's data in the database
- Delete the users
- Confirm the deletion
In this article, we'll continue getting things ready for our test.
In an earlier article, we created a page object to hold locators and methods used on the Login page. In this one, we're going to create two more. One for the Manager in general, and one that will serve both the Manage Users panel and the Create/Edit User panel.
To create the two page objects, give these commands in the _build
directory:
codecept generate:pageobject acceptance Manager codecept generate:pageobject acceptance User
The Manager PageObject
In order to create users in an acceptance test that runs in the MODX Manager, we need to be able to trigger the Manage
dropdown menu in the Manager's top menu. Then we need to click on the "Users" option. We'll put the locators for these in our ManagerPage class. The file is ManagerPage.php
in the _build/tests/_support/Page/Acceptance
directory. Here's the code (also available at GitHub, here):
<?php namespace Page\Acceptance; class ManagerPage { /** * Declare UI map for this page here. CSS or XPath allowed. * */ // include url of current page public static $URL = 'manager/'; public static $manageMenu = '//*[@id="limenu-manage"]/a'; public static $manageUsersLink = '//*[@id="users"]/a'; /** * Basic route example for your current URL * You can append any additional parameter to URL * and use it in tests like: Page\Edit::route('/123-post'); */ public static function route($param) { return static::$URL.$param; } /** * @var \AcceptanceTester; */ protected $acceptanceTester; public function __construct(\AcceptanceTester $I) { $this->acceptanceTester = $I; } }
The only lines we're using from this file are the first three public static
lines, containing the URL and the two locators, and the constructor at the end. I've left in the rout()
method, placed there by Codeception, because you might want to use it for other tests.
It might seem like overkill to create this file just to store the two locators, but you may want to develop other functional or acceptance tests for the MODX Manager. You can continue to add locators for parts of the Manager in this file and use them in any test.
Let's look at the two locators:
public static $manageMenu = '//*[@id="limenu-manage"]/a'; public static $manageUsersLink = '//*[@id="users"]/a';
Both of these look from the root of the DOM for an element with that Id, and set the locator to its child a
tag. Clicking on the parent generally won't work. You need to click on the link in the a
tag itself. Rather than looking for the id
attribute, we could also have selected the link by the text in its href
attribute. We'll see an example of that in a bit.
The User PageObject
The locators in the code above will get us to the "Manage->Users" panel, but
to create users we'll need to do a lot of clicking on that page, and on the
"Create/Edit Users" panel. We'll put all the locators for that, as well as the data
for the two test users we'll be creating in the
UserPage.php
file found in the
_build/tests/_support/Page/Acceptance
directory. If you had many users, the user
data would typically go in the _data
directory,
but since there are only two of them, I put them in here.
Here's the code (also available at GitHub, here):
<?php namespace Page\Acceptance; class UserPage { /** * @var \AcceptanceTester; */ protected $acceptanceTester; public static $newUserButton = "//button[contains(text(), 'New User')]"; public static $userSaveButton = "//button[contains(text(), 'Save')]"; public static $userOkButton = "//button[contains(text(), 'OK')]"; public static $userCloseButton = "//button[contains(text(), 'Close')]"; public static $countryMenu = '//*[@id="modx-user-country"]/following-sibling::div'; public static $genderMenu = '//*[@id="modx-user-gender"]/following-sibling::div'; public static $photoInput = "//input[@type='text' and @name='photo']"; public static $passwordNotifyScreen = '#modx-user-passwordnotifymethod-s'; public static $passwordGenManual = '#modx-user-password-genmethod-s'; public static $passwordInput = '#modx-user-specifiedpassword'; public static $passwordConfirmInput = '#modx-user-confirmpassword'; public static $autoPasswordValue = '//span[starts-with(text(), "The User has been created")][1]'; /* In the associative arrays below, the keys are the locators for fields in the user form. The values are the values to use to fill those fields. */ public static $users = array( 'user1' => array( 'username' => 'User1', 'fullname' => 'user1 fullname', 'email' => 'user1@hotmail.com', 'phone' => '555-218-1234', 'mobilephone' => '555-218-5678', 'fax' => '555-612-1234', 'address' => '234 Walnut St.', 'city' => 'Milwaukee', 'state' => 'WI', 'country' => 'Albania', 'website' => 'http://bobsguides.com', 'photo' => 'assets/images/compass-vector.jpg', 'dob' => '03/22/1995', 'gender' => 'Male', 'comment' => 'Some Comment', 'password' => '', ), 'user2' => array( 'username' => 'User2', 'fullname' => 'user2 fullname', 'email' => 'user2@hotmail.com', 'phone' => '555-218-1234', 'mobilephone' => '555-218-5678', 'fax' => '555-612-1234', 'address' => '211 Elm St.', 'city' => 'Miami', 'state' => 'FL', 'country' => 'United States', 'website' => 'http://wordsmatter.softville.com', 'photo' => 'assets/images/flag1.jpg', 'dob' => '02/21/1997', 'gender' => 'Female', 'comment' => 'Some Other Comment', 'password' => 'SomePassword', ), ); public function __construct(\AcceptanceTester $I) { $this->acceptanceTester = $I; } }
Most of the locators in the code above are fairly straightforward. A number of them are simply Ids. Many of the locator keys here are not the actual locators (they would have #
in front of them if they were). The actual locators are prefixed with #modx-user-
, which we'll add to the default case in our test in the next article.
The two users are represented using associative arrays with the locator as a key and the value for that user as the value associated with that key. Note that the first user's password is empty. We'll use that "emptyness" in our test to indicate that the user's password should be generated by MODX rather than entered manually in the form.
These locators require a little explanation:
public static $countryMenu = '//*[@id="modx-user-country"]/following-sibling::div'; public static $genderMenu = '//*[@id="modx-user-gender"]/following-sibling::div'; public static $autoPasswordValue = '//span[starts-with(text(), "The User has been created")][1]';
The first two are the dropdown menus for the country
and gender
fields. In both cases, the label
tag has an Id, but clicking on it won't work. To trigger them, we need to click on the double arrow next to the input. Worse yet, if you do a "View Source" on the page, you won't see them because they are placed there by JavaScript.
If you inspect them in Dev. Tools (after clicking on the double arrow), you'll see that the actual selections are in a div
tag at the same level as the label
tag, so what we want is the label
tag's next sibling div
. We need to click on that div
.
The third locator above is for the message containing the user's password when it is autogenerated by MODX.
public static $autoPasswordValue = '//span[starts-with(text(), "The User has been created")][1]';
That message doesn't show up until you've clicked on the "Save" button. We need to grab that text and parse out the password, so we can check it later against the user's password hash stored in the database.
The message has no id and no near parent with one, so we need to identify it by the text of the message. We can't use the whole message because it contains the password, which we don't know yet, so we've used starts-with
in our XPath.
To complicate matters, the message appears in two places, in the "OK" button popup and in another popup that appears near the "Save" button. Because our locator appears twice, we've added [1]
at the end to select the first one. We could have used [2]
, but if one of the popups is removed at some point, the search would fail.
We'll see some more examples of XPath locators in a future article.
Coming Up
In the next article, we'll see the final Acceptance test that creates our two users and then checks the database to make sure they were created correctly.
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 Hosting.com (formerly A2 Hosting). (More information in the box below.)
Comments (0)
Please login to comment.