WordPress E2E & UI Testing

As we continue to strive towards excellence in QA, we are looking to automate more of our QA process. WordPress presents some very specific challenges, and this article discussed some of the strategies we’ve used to automate testing for bespoke WordPress websites.

UI Testing

We have recently started using Happo for screenshot testing. The main reason I like Happo over the alternatives is the browser selection it offers – many UI bugs occur in the browsers we use least ourselves, like IE11 (unfortunately still required by a lot of our clients) and Edge. For us, it’s invaluable having a tool that forces us to review and accept the UI on these browsers, and that catches any subsequent regressions.

Happo solves the issues of setting up a snapshot comparison system and ironing out the inconsistencies you can get with these. However, this still leaves us with the tricky problem of how to ensure consistent snapshots when the content can be edited in the CMS. We solve it by adding a styleguide / component library to our WordPress themes – currently we use this implementation we built ourselves, but we are experimenting with Fractal, an open-source solution, for future projects (check out the impressive Cali Theme by our very own Francisco Giraldo).

We use the Happo wrapper for Cypress to run our tests, as we are using Cypress anyway for our functional testing. Cypress also gives us a way to interact with the UI before taking screenshots, eg if we want to test an element into a certain state.

For a typical project we want to cover a broad spectrum of browsers, devices and screen sizes. This includes Chrome and iOS Safari for mobile; and Chrome, IE11 (if required), Edge, Firefox and Safari on desktop. Only Chrome and Firefox allow for screen widths wider than 1,200px, so we use these to test the UI on wider screens. Our .happo.js file looks like the following for a typical project (with IE11 support required):

We then create a Cypress test (in the cypress/integrations folder) to visit the relevant pages of the styleguide and take a screenshot:

In our case, we had to take a shot of the whole page (by targeting the body tag) because of the way Tailwind CSS is setup to make its CSS more specific (and therefore higher priority for the browser) by targeting an id on the body tag before the actual class.

Once you’ve done the above you can test locally if you replace the process.env variables with the ones from your Happo account (but please be careful not to commit these to your repo, that’s not secure) or you could setup dotenv to inject them. In our case we haven’t done this, because we really only want Happo to run in our CI pipeline to keep costs down.

E2E Testing

For us, UI testing is the most important type of testing when it comes to WordPress. WordPress is a tool we mostly use for content-driven sites, like marketing or portfolio sites. For these there is not a lot of functionality in the UI, but we do want them to look as close to perfect as possible.

However, we also build some sites which have very customised back-ends or more advanced functionality, such as eCommerce built on the WooCommerce plugin. In these cases we do want to ensure that critical functionality does not break during a release and this is where Cypress comes in.

Of course we have the same problem with changing content, and this time it can’t be solved with a static styleguide. We have some up with 2 broad solutions:

Resilient Tests

Under this strategy we aim to write tests that work no matter what the content is. This works when we can target elements based on attributes which are fixed and/or the workflow cannot be changed via the CMS. A WooCommerce flow or browsing for a product and purchasing it is a classic example. Let’s look at another one too in more detail:

Nav Functional Test Example

We can work off the available data to build our tests, making some assumptions: there will always be a menu, there will always be a top-level menu item with no children and there will always be one with children.

First, we can target a menu item with no children using #main-menu li:not(.menu-item-has-children) and test that clicking it correctly redirects us to a new page. We can then assert that we are no longer on the homepage: cy.location('pathname').should('not.eq', '/').

Next, we can look for one with children, #main-menu li.menu-item-has-children and hover over it to make the sub-menu appear. We can then click the first item and run a similar test to the above.

The nice thing with the Cypress/Happo integration is that we could also choose to use intersperse our tests with a call to happoScreenshot(), allowing us to take a screenshot of the component / page in the state we choose.

Admin Automation

The other approach is a bit more involved, but has the benefits of greater flexibility and it also tests the admin experience is working as expected. This last point is often overlooked when it comes to testing, but in my experience it’s just as common to cause admin issues as it is to cause front-end issues when making a change or performing plugin updates.

The idea here is for Cypress to login to the WordPress admin, build a page using the page editor and then test it looks and functions as expected on the front-end. This way we have no dependencies on content, we just need a WordPress instance with the required plugins installed and configured.

Let’s take a look at an example of this:

The first thing we do is login to the WordPress dashboard using a custom command we created, cy.adminLogin(). We created a suite of such commands in the Cypress commands.js file, you can see them all here. The commands are sets of reusable steps we can use to perform repeated tasks, like adding a block to a page.

Next we delete any old test data from a previous run using cy.deletePost(), and then create and publish a new page to work on in this test run using cy.createPost() and cy.publishPost(). Note the Cypress.env('hash') suffix on the page slug: we use this to ensure we don’t create a page which clashes with an existing one on the site (as we’re generally working off a copy of the live, staging or dev database).

Now we get to the meat of the test: adding the blocks to the page. In this site we are using ACF to generate custom blocks, and we have of course created some useful commands to facilitate adding them to the page. The sequence is as follows:

  • Use cy.addBlock() to add the block at the end of the page (ie the new block is the last one).
  • Use cy.switchToEdit(last) to make the newly added block active.
  • Use cy.fillACFField() repeatedly to populate all the fields required for the block.

When we’re done editing the page, we use cy.updatePost() to save our changes. We can then run a standard set of Cypress tests on the front-end, such as my simple example of checking the button text is as expected and that clicking the button actually works.


I hope this article gave you some ideas on how you can automate your WordPress testing. A good next step from here is to include these tests in your continuous integration workflow – we use Bitbucket Pipelines combined with Pantheon hosting to automatically spin up new environments per feature.

Do let me know if you want to hear about this, or if you have any other ideas on automating WordPress tests.

Let’s launch something!