Automation

Testing Authenticated REST Calls with Behat and Drupal

Prerequisites: Drupal, Behat, Composer, REST

There are plenty of posts out there describing how to make REST calls from a Behat test apparatus. What if, however, you need to take things a step further and make these calls as an authenticated user instead of just an anonymous user? As it turns out, this is both more involved and easier than you might think.

The back end for this project is a composer-based Drupal 8 site, hosted on Pantheon and initially setup with Pantheon’s Build Tools plugin for their Terminus utility. The site exposes a set of endpoints intended for use by a private app and so most of the functionality is restricted to authenticated users. The site also uses cookie-based authentication and requires a JSON request format for incoming calls.

In order to write tests for this scenario, we have to overcome two main obstacles:

  1. We need to be able to specify the payload, method and endpoint for the outgoing REST call and also inspect the responses.
  2. We need to be able to make calls as a user with a particular Drupal role.

As you may already know, Behat (plus Mink) combined with the Behat Drupal Extension has some very nice conveniences, including Behat Steps like

[Given|*] I am logged in as a/an :role

This step creates a user with the given role, then deletes the user when the test is over. All steps in between are executed as the newly created user.

If you search the internet for “Behat REST plugin”, you’ll find a number of solutions, some of which directly use Guzzle to make HTTP calls and some of which extend MinkContext. Choosing one that extends MinkContext is key in this scenario because we want to leverage the benefits given to us by the “…logged in as…” step. We went with the nifty Behatch extension. As you can see from the Behatch instructions, installation of the this extension is pretty simple, requiring only a composer command and some minor edits to your behat.yml file.

So far, so good. We can now make REST calls using steps like

Then I send a "GET" request to "my/cool/rest/api"

or even make a POST request, specifying the raw body with a PyString. We can also inspect the responses.

There are a couple of complications, however. First, our calls need to add a Content-Type header equal to application/json. Luckily, Behatch includes the step

[Then|*] I add :name header equal to :value

The second issue is that we need to maintain the CSRF token required by Drupal web services. Luckily, Drupal 8 has a default way to get the token, so all you have to do is write some custom steps in your Behat context to get it and add it to your outgoing calls. Your custom context might contain something like this:

  /**
   * @Given I get the CSRF Token
   */
  public function getCSRF() {
    $this->getSession()->visit('/session/token');
    $this->csrf = $this->getSession()->getPage()->getContent();
  }

  /**
   * @Then I add CSRF Token to request
   */
  public function addCSRF() {
    $this->request->setHttpHeader('X-CSRF-TOKEN', $this->csrf);
  }

Finally, a feature might contain something like this:

  Given I am logged in as an "authenticated"
  Given I get the CSRF Token

  Then I add CSRF Token to request
  Then I add "Content-Type" header equal to "application/json"
  When I send a "GET" request to "/my/cool/api?_format=json"
  Then I should get a "200" HTTP response

  Then I add CSRF Token to request
  Then I add "Content-Type" header equal to "application/json"
  When I send a "POST" request to "/my/cool/api?_format=json" with body:
    """
    {
      "name": [{
        "value": "mitsuha"
      }],
      "title": [{
        "value": "Your Name"
      }]
    }
    """
  Then I should get a "201" HTTP response

  Then I add CSRF Token to request
  Then I add "Content-Type" header equal to "application/json"
  When I send a "DELETE" request to "/my/cool/api?_format=json"
  Then I should get a "204" HTTP response

And so, with just some minor custom coding, we are now able to write Behat automated tests for our REST endpoints that require authentication in Drupal.

Making Marketing Automation Work for SMB and Non-Profits

Marketing Automation!  You are probably starting to hear that phrase more and more.  What is it you ask?  Software and technologies that help marketers more effectively market on multiple channels (websites, email, social media) and automate certain tasks (sending welcome emails, tweeting, lead nurturing) as well as analytics and marketing intelligence  (tracking site visitors, search terms, A/B testing, buyer behavior).  Even some older ideas such as auto-responders are now being called marketing automation - like at MailChimp:

Mailchimp Marketing Automation intro diagram

The underlying principle of marketing automation is to take a process that is effective in bringing you customers and automate it.  

The first part is the most important - if you automate a process that doesn't work, then you will just become much more efficient at failing to get new business.  So first you must understand and identify your successful process, or you must develop an effective one.  There are so many moving parts in today's digital marketing - a small business owner or director of a non-profit just doesn't have hours in the day to perform everything manually.  Research shows it often takes five "touches" before converting a prospect to a client.  That's a lot of work, done over and over.

Marketing Automation is still in an early phase, and most of the solutions available are intended (and priced) for large enterprises and big brands.  A Hubspot or Eloqua implementation can cost $2,000 a month plus five-figures and dozens of hours of training to get it going. But here at FireRoad Digital, we provide solutions for small businesses and non-profits.  So we are going to help you get going with a marketing automation process you can understand and afford.

This is start of a series of blog posts that will cover all aspects of SMB and non-profit digital marketing automation, with of course, a slant toward use with Drupal websites.  We will cover :

  • creating a strong marketing message and effective marketing process
  • understanding the Reach, Engage, Convert funnel process that turns anonymous Internet users into clients
  • learning which marketing channels your business should be in, and the tools used to market to those channels
  • understanding how your prospects are finding you, and what is important to them 
  • automating your email marketing messages, social media postings, client touches
  • creating eBooks and premium offers to start the lead nurturing process with prospects

Since we are not FireRoad Analog, we won't cover offline activities such as mass snail mail, phone calls, and other non-Internet activities that may be important to your business.  But digital stuff - we got that!

I've been a triathlete and multi-sport athlete for many years, and my coach once told me - "if your training consist of lots of slow runs, bikes and swims, then you will get really good at running, biking and swimming slowly."  So let's not get good at performing a bad process over and over - let's put together a killer process for generating growth, then let the robots take it over.

Stay tuned..