At Axelerant, we use various frameworks like Behat, PHPUnit and Drupal Test Traits (DTT) to write automated tests for Drupal applications.
We went ahead and tried out Cypress for primarily two reasons:
- The technology world is moving away from monolithic Drupal applications. What I mean is, we have a lot of clients that demand Drupal to be used in a certain way, mainly in the decoupled fashion. This, in turn, means that the frontend of the application is built using some frontend web development technology like React, Angular, Vue, Flutter, etc. and not through twig files (the way frontend is currently handled otherwise). I have been hearing and reading a lot about Cypress and its compatibility with these technologies. Hence, we decided to try Cypress on one of our actual projects to understand the real benefits rather than just drawing conclusions from others' experiences.
- As an organization, we strongly embrace external trends and Cypress tops our list for 2020-21.
To provide more context about the project into consideration, we chose Axelerant’s internal and a special project named “Knowledge sharing”. This application tracks all entries for the internal show-n-tell sessions and webinars presented within Axelerant every two weeks.
Refer to Cypress's official documentation.
End to end testing in Drupal
In this section, we will see some basic end-to-end tests in Drupal, like creating content types using certain user roles. So, let’s understand the typical user workflow for such scenarios:
- Login with a specific user role (admin, editor, etc.)
- Publish content
- Verify the content is visible to users
Sounds simple, isn’t it? It is indeed simple, and there’s no catch here. Let’s look at the implementation part now.
Login with a certain user role (Creating users and logging in)
To log in, we first had to create users in the backend and prefer creating users through non-UI ways as it is one of our good practices with Test Automation. As part of the setup activity, we created users using the Drush commands in Drupal. We then logged in by leveraging the “/user/login” API endpoint, totally skipping the UI here to further speed the tests. The createUser and login methods, both were added to commands.js. Here’s a quick sneak peek into the code.
GitHub gist for createUser and login methods:
Creating and publishing content
Next comes a certain user role that creates a certain content type (CT) and then publishes it to make the content visible to the system's appropriate users.
To address this use case, we considered the “Topic” CT to demonstrate our approaches to creating content faster.
Create data through UI
We created one sample topic through the user interface (UI) to verify the end-to-end user flow where the user can navigate through the UI and complete the process of creating a topic CT and that no JS errors are encountered creating the content.
This CT is used to store information regarding various internal sessions conducted within Axelerant and focused on sharing knowledge from actual learning and experiences.
This was a straightforward task wherein we just had to enter appropriate values in a few fields and validate the content got successfully created. It looks something like this in terms of the structure:
Here is the GitHub gist:
Here is the demo:
Seed data through JSON:API
Now that we had automated the verification of the creation of topics, the next scenario was to write an automated test for the topics listing page where these published topics were displayed. We needed to create different topics to verify the following scenarios:
- Verify that the topics are correctly displayed in the three tabs - Topics, Scheduled topics, and Unscheduled topics.
- Verify that pagination is displayed after the expected number of topics is reached on the first page.
- Verify that pagination works correctly for topics listing pages for each of the tabs.
The fact that all this data/content should not be created through UI for running your automated assertions is not new to us, and hence I am not going to be talking about why we shouldn’t be following this approach. Instead, we leveraged Drupal’s JSON API module and created data with the help of POST requests.
Here is the GitHub gist for JSON API:
Here is the demo:
Other approaches to try for data creation
- Default content module in Drupal:
The default content and default content deploy module can be used to create test automation data at great speed and then all you have to do is act and assert from the Arrange-Act-Assert (AAA) pattern.
- Containerized DB approach:
A similar benefit can be achieved if you use a dockerized database image for the arrange part and then focus only on the Act and Assert section. This strategy is especially useful if you have automated visual validation tests in the pipeline. One of the significant challenges of having dynamic content is eradicated and all you can focus is on getting accurate and faster feedback for your User Interface. However, this is a discussion to be parked for later.
Challenges faced and resolution
- The JSON API approach is not a straightforward one and might be time-consuming to implement in the case where there are complex content type structures involved. Hence, this is not a feasible solution.
- CKEditor had performance issues through sendKeys and hence, using jQuery was a better solution. We captured the data to be entered in a constant named “TOPIC_BODY” (Image 1 below) and entered it using a custom command “setValueByJQuery“ which looked like image2 shown below.
- Our approach ensured that we had fresh content every time our scripts acted upon them. The content was created through scripts without accessing the UI, thereby achieving faster feedback through faster execution and reducing flaky tests.
- We implemented the suite using the Page Object model for the various benefits this design pattern provides:
- Tests looked cleaner and more readable as all the data was stored in the fixtures directory.
- We created custom reusable commands, stored locators in variables, which helps us with better maintenance.
- A post hook (deleteUser method) destroyed the users and the corresponding data created as part of the pre-hook (createUser method), which made our automation test suite reusable without running into the risk of false positives.
These are just some of the tips and techniques we implemented for better execution and hope this helped you implement automated tests for your Drupal application using Cypress.
By the way, this is not the whole part and you will have more to this Cypress series in the next blogs, which will talk about running tests in the Continuous Integration pipeline, leveraging the Cypress Dashboard, etc.
And if you are looking to try all of this in a vanilla Drupal installation, enjoy our sample GitHub repository, which you need to clone and have these complete implementations on your machine for better understanding.
Shweta Sharma, Director of Quality Engineering Services
When Shweta isn't at work, she's either on a family road trip across the country or she's dancing with her kids—it's a great combination.