Four Kitchens
Insights

Testing Drupal with CasperJS

5 Min. ReadDevelopment

In part three of our CasperJS series, we used CasperJS to rapidly test the user interface of a website. Now we will build on these skills and add a familiar element into the mix: Drupal. Like any framework, Drupal offers many predictable, standard behaviors which we can take advantage of. Using this predictability, we can easily test many behaviors including logged-in activity such as posting content.

Expected output from Casper

Just like our previous posts, we’ll provide some context for the code by looking at the desired result first, and working backward from there. Pictured here is the output of a successful execution of our drupal.js script:

Screenshot of Casper JS output

Console output displaying 8 successful Casper JS tests. The test is titled “Testing Drupal demo site”, and it proceeds to log in, verify successful authentication via HTTP header, check for the standard Drupal logged-in body class, click a link to open the Overlay, and verify that the Overlay changed page title and URL path. The script continues by loading the form to add a Page node, filling out the form with some fake content, and saving the form. Once the page redirects to the published node, the test looks for the sample title and body text that it entered on the previous page. The test concludes by reporting: PASS 8 tests executed in 1.723 seconds, 8 passed, 0 failed, 0 dubious, 0 skipped.

Commenting in CasperJS

In this Casper test’s output there are the comments beginning with a # symbol. These are log comments that are intended to help whoever is reading the test results. By announcing high-level user actions, it helps provide context to the test results. And if someone is actually watching the tests perform, a comment is especially helpful when the test executes an action that might result in a few seconds of delay. Our example has several instances of this: when it fills in the login and new content forms.

Side note: don’t worry if you see two squares in the code below. You’re probably using Chrome, which doesn’t display emoji properly. The emoji shows up pretty much everywhere else, including the terminal where this is designed to display. Refer to the image above to see what the intended effect is.

test.comment('⌚️  Logging in...');
test.comment('⌚️  Clicking the Content admin link...');
test.comment('⌚️  Adding Basic page...');
test.comment('⌚️  Saving new node...');

Detecting UI state changes

Using our knowledge of Drupal, we can verify that the state of our website is always in the predicted state, even when there is a more complex interface. Drupal’s Admin Overlay is one such interface, allowing users to edit content in a modal dialog without navigating away from the published version of the page. Since we know exactly how the Overlay behaves, we can verify that it is properly loading pages, changing the page title and so forth.

this.click('a[href="/admin/content"]');

// Test for the changes that we expect from the Overlay when
// clicking an administrative link. Instead of a new URL, we
// expect the <title> to change and a URL fragment to appear.
test.assertTitleMatch(/Content | Drupal Demo Install/, 'Overlay changed page title to contain the word "Content"');
test.assertUrlMatch(/node#overlay=admin/content/, 'Overlay updated the U​R​L to /node#overlay=admin/content');

Testing HTTP status codes

Another powerful tool within Casper is the ability to verify HTTP status codes. CasperJS allows us to test for any HTTP status code. Here are some common examples that come to mind:

  • Testing for HTTP 200, we can verify that a web page loaded properly. If you’re reading this page, our website served you a 200.
  • Testing for HTTP 301 or 302, we can verify a URL redirection strategy during a migration.
  • Testing for HTTP 403, we can make sure restricted sections of the site stay off-limits.
  • You could even test for a lack of 500 (server error) at a particularly problematic URL.
// Test for a normal page load
test.assertHttpStatus(200, 'Successfully opened node/add/page.');
// Test for a permanent redirect
test.assertHttpStatus(301, 'Permanent redirect found.');
// Test for a temporary redirect
test.assertHttpStatus(302, 'Temporary redirect found.');
// Tea time!
test.assertHttpStatus(418, 'You're a teapot.');

Filling forms and verifying submissions

This test also uses the casper.fill() function in order to create content within the CMS. We follow the form submission with a confirmation that our content was published on the page. Saving the contents of the form into pre-existing config helps us make sure that we test for the exact same value that we save into to Drupal. It would be annoying if we hardcoded an identical value in two places, and then forgot to change one of them, resulting in a false failure.

// Set up our test content. The keys of this object
// are values passed to a CSS selector `[name=K​E​Y]`
// that will only match inside the DOM tree specified
// in the first argument of casper.fill()
var nodeContent = {
  'title': 'Hello, World!',
  'body[und][0][value]': 'This content was added by CasperJS!'
};

// Fill and submit form. Third argument is a boolean
// controlling whether the form submits after being filled.
casper.fill('form#page-node-form', nodeContent, true);

// First test that the title matches the submission.
test.assertTitleMatch(new RegExp(nodeContent.title), 'Our custom title was found on the published page.');

// Now check that the text entered matches the non-HTML text
// that we submitted on the previous page. Drupal 7 ships with
// jQuery so it is 100% safe to assume it is available on a
// vanilla Drupal install.
test.assertEvalEquals(function () {
  return jQuery('.node-page .content p').text();
}, nodeContent['body[und][0][value]'], 'Our custom text was found on the published page.');

If you’d like more information about test.assertEvalEquals I covered it in depth in a previous article, Testing JS code with CasperJS.

Full code example

If you’d like to see a complete, thoroughly documented version of this script, please head to GitHub and check out the Gist. You are free to copy and modify this script to your heart’s content!

Gist of drupal.js

Video walkthrough

Here’s an excerpt of my recent DrupalCon Amsterdam presentation which walks through this very CasperJS test for Drupal. We will click around the site manually and observe what happens, to see what the test should look for. Then the script will perform the exact same actions described in this article, resulting in a published node and a beautiful green PASS after finding the fake content entered on the previous form.

Further reading

If you’d like to explore even more complex use-cases in Drupal read the next post in our CasperJS series. David Diers will explore more comprehensive test scenarios by combining both CasperJS and SimpleTest, a PHP-based testing tool which has deeper visibility into Drupal’s database and internal models.