This website is rather simple and easy to use. That means that there isn't much to test, but having some sort of automated test coverage is giving me peace of mind that everything works as it should.
I'm primarily a Drupal developer, so it's kind of obvious that this website is built in Drupal 9. Behat is an open-source behavior-driven testing framework for PHP, and it has great integration with Drupal. Also, writing Behat tests is fun and easy, so no wonder I decided to use it to create automated tests.
I don't have any fancy features on the admin side, so all I need to test are user-facing features. That means making sure that my header, footer, menus, links and so on exist and are placed according to the design.
I have already written about setting up and running Behat tests, so if you want to find out more check out my Drupal 8 and Behat tests article. If you want to add Behat tests to your website, you should read the article because you will find out what you need to do to run the tests.
Tests for my website are executed automatically every Sunday at 4 AM. I'm using Gitlab for CI/CD, so I added a scheduled job to run the tests.
I added a job to the Gitlab CI config file that is executed only when the pipeline has been scheduled. The test job looks like this:
prod:behat:
stage: test
allow_failure: false
script:
- "cd /var/www/gorannikolovski.com; bin/behat"
only:
- schedules
As you can see the job is pretty simple -- all it does is changing to the correct directory and then executing bin/behat command that will run the tests.
Because of the nature of what I'm testing, the tests are executed on the production server. I could also run tests after each deployment, but I don't deploy that often so having scheduled testing is a better option.
And finally, here are the tests:
@api
Feature: Test website
Background:
Given I am not logged in
Scenario: Header region
Given I am on "/"
Then I should see the raw text matching "/themes/custom/gn2021/images/goran-nikolovski-signature.png" in the "header" region
And I should see "Home" in the "header" region
And I should see "Snippets" in the "header" region
And I should see "Search" in the "header" region
And I should see "Contact" in the "header" region
And I should see "About" in the "header" region
And I should see "Hi, I'm Goran Nikolovski. I'm a creator, speaker, open-source contributor, web developer specialized in Drupal and DevOps enthusiast. I'm based in Subotica, Serbia." in the "header" region
Scenario: Content region
Given I am on "/"
Then I should see the link "Read more"
And I should see "Next ›" in the "content" region
And I should see "Last »" in the "content" region
Scenario: Featured bottom region
Given I am on "/"
Then I should see "Get new posts delivered right to your inbox." in the "featured_bottom" region
And I should see the raw text matching "Your email address ..." in the "featured_bottom" region
And I should see the raw text matching "Subscribe" in the "featured_bottom" region
Scenario: Footer region
Given I am on "/"
Then I should see "Copyright © 2017-2020 by Goran Nikolovski. All rights reserved. Top of page." in the "footer" region
Scenario: Social bar region
Given I am on "/"
Then I should see the raw text matching "https://gorannikolovski.com/rss.xml" in the "social_bar" region
And I should see the raw text matching "https://github.com/gnikolovski" in the "social_bar" region
And I should see the raw text matching "https://www.drupal.org/u/gnikolovski" in the "social_bar" region
And I should see the raw text matching "https://www.linkedin.com/in/goran-nikolovski" in the "social_bar" region
And I should see the raw text matching "https://twitter.com/_gnikolovski" in the "social_bar" region
Scenario: Response status for pages
Given I am on "/"
Then the response status code should be 200
Given I am on "/snippets"
Then the response status code should be 200
Given I am on "/search"
Then the response status code should be 200
Given I am on "/contact"
Then the response status code should be 200
Given I am on "/about"
Then the response status code should be 200
Given I am on "/privacy-policy"
Then the response status code should be 200
Given I am on "/terms-of-service"
Then the response status code should be 200
Given I am on "/rss.xml"
Then the response status code should be 200
Scenario: Snippets page
Given I am on "/snippets"
Then I should see "Snippets"
And I should see "Next ›" in the "content" region
And I should see "Last »" in the "content" region
Scenario: Search page
Given I am on "/search"
Then I should see "Search"
And I should see "Displaying 0 - 0 of 0"
And I should see "No results match your search criteria."
And I should see the raw text matching "Search" in the "content" region
Scenario: Contact page
Given I am on "/contact"
Then I should see "Contact"
And I should see "Your Name"
And I should see "Your Email"
And I should see "Subject"
And I should see "Message"
And I should see the raw text matching "Send message" in the "content" region
Scenario: About page
Given I am on "/about"
Then I should see "About me"
And I should see "My Visits"
And I should see "Qualifications"
And I should see "Projects"
Scenario: Log in page
Given I am on "/account/login"
Then I should see "Log in"
And I should see the link "Log in"
And I should see the link "Reset your password"
And I should see "Username"
And I should see "Password"
And I should see the raw text matching "Log in" in the "content" region
Scenario: Response status for articles
Given I am on "/blog/couchbase-api-rate-limiter"
Then the response status code should be 200
Given I am on "/blog/hierarchical-taxonomy-menu"
Then the response status code should be 200
Given I am on "/blog/drupal-8-installing-composer"
Then the response status code should be 200
Given I am on "/blog/dix-database-import-export"
Then the response status code should be 200
Given I am on "/blog/react-js-and-drupal-8-building-decoupled-website-part-1"
Then the response status code should be 200
Given I am on "/blog/2017-recap"
Then the response status code should be 200
Given I am on "/blog/amazing-facts-about-drupal"
Then the response status code should be 200
Given I am on "/blog/drupal-camp-pannonia-2018"
Then the response status code should be 200
Given I am on "/blog/programmatically-create-menu-link-node"
Then the response status code should be 200
Given I am on "/blog/drupal-8-nginx-and-lets-encrypt"
Then the response status code should be 200
Given I am on "/blog/4-ways-delete-configuration-items-drupal-8"
Then the response status code should be 200
Given I am on "/blog/drupal-8-and-behat-tests"
Then the response status code should be 200
Given I am on "/blog/inline-twig-templates"
Then the response status code should be 200
Given I am on "/blog/2018-recap"
Then the response status code should be 200
Given I am on "/blog/alternative-menu-token-module"
Then the response status code should be 200
Given I am on "/blog/set-date-field-programmatically"
Then the response status code should be 200
Given I am on "/blog/how-loop-through-referenced-entities"
Then the response status code should be 200
Given I am on "/blog/out-stock-feature-drupal-commerce-2x"
Then the response status code should be 200
Given I am on "/blog/example-usage-twig-render-this"
Then the response status code should be 200
Given I am on "/blog/block-caching-examples"
Then the response status code should be 200
Given I am on "/blog/docker4drupal-and-functional-javascript-tests"
Then the response status code should be 200
Given I am on "/blog/easy-way-speed-your-website"
Then the response status code should be 200
Given I am on "/blog/taxonomy-post-update-make-taxonomy-term-revisionable-fails"
Then the response status code should be 200
Given I am on "/blog/add-computed-field-jsonapi-response"
Then the response status code should be 200
Given I am on "/blog/undefined-index-name-system-requirements"
Then the response status code should be 200
Given I am on "/blog/how-add-column-taxonomy-overview-page"
Then the response status code should be 200
Given I am on "/blog/menu-links-dynamic-values"
Then the response status code should be 200
Given I am on "/blog/drupalcamp-pannonia-2019"
Then the response status code should be 200
Given I am on "/blog/programmatically-update-search-api-index"
Then the response status code should be 200
Given I am on "/blog/batch-processing-and-update-hooks-drupal-8"
Then the response status code should be 200
Given I am on "/blog/how-alter-inline-entity-form-table-fields"
Then the response status code should be 200
Given I am on "/blog/query-level-filtering-custom-entities-drupal-8"
Then the response status code should be 200
Given I am on "/blog/svg-formatter-v110"
Then the response status code should be 200
Given I am on "/blog/drupal-9-readiness-checklist"
Then the response status code should be 200
Given I am on "/blog/making-my-modules-drupal-9-ready"
Then the response status code should be 200
Given I am on "/blog/drupal-9-and-drush-10"
Then the response status code should be 200
Given I am on "/blog/how-set-menu-link-attribute-programmatically"
Then the response status code should be 200
Given I am on "/blog/2019-recap"
Then the response status code should be 200
Given I am on "/blog/drupal-commerce-and-facebook-product-catalog"
Then the response status code should be 200
Given I am on "/blog/simplify-drupal-commerce-2x-checkout-removing-login-or-continue-guest-pane"
Then the response status code should be 200
Given I am on "/blog/browsersync-gulp-docker4drupal-and-my-new-theme"
Then the response status code should be 200
Given I am on "/blog/my-new-theme"
Then the response status code should be 200
Given I am on "/blog/how-convert-existing-image-fields-media-images"
Then the response status code should be 200
Given I am on "/blog/4-cool-new-php-8-features"
Then the response status code should be 200
Given I am on "/blog/how-im-using-behat-test-my-personal-website"
Then the response status code should be 200