Functional tests with puppeteer and gherkin scenarios

June 3, 2019

For my custom needs, I was looking for puppeteer functional testing suite. As a php developer, I ordinary use behat to write and play my functional tests. But the project I want to test is python written, and I don’t want to install and configure PHP just to run tests. And what about puppeteer and chrome headless engine? Hey, I had an idea: implement the cool gherkin syntax with puppeteer in pyhton.

About Gherkin

Gherkin is a syntax which looks like:

Feature: Use the rest test suite  
  
	Scenario: We can fetch data from an api  
		Given I add these headers:  
			| accept | application/json |  
		Given I prepare a "GET" request to "/todos/1"  
		When I send the request  
		Then print the last json response  
		And the json node "anythng" should not exist  
		And the json node "userId" should exist  
		And the json node "id" should be equal to "1"  

It’s readable by human, (I mean, by non-developer human :)) and it’s really easy to write.

About Puppeteer

Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the DevTools Protocol, and allows to execute actions in a headless (without visible UI) version of chrome.
In nodejs, these tests look like:

const puppeteer = require('puppeteer');  
(async() => {  
  const browser = await puppeteer.launch();  
  const page = await browser.newPage();  
  await page.setRequestInterception(true);  
  page.on('request', request => {  
    if (request.resourceType() === 'image')  
      request.abort();  
    else  
      request.continue();  
  });  
  await page.goto('https://news.google.com/news/');  
  await page.screenshot({path: 'news.png', fullPage: true});  
  
  await browser.close();  
})();  

Understandable by developers, but a bit ugly (and boring to write)…
However, using a real browser as chrome to play functional tests has a lot of advantages:

  • javascript testing
  • speed
  • easy to use

Let’s play with pyppettheater

Pyppettheater is one of my amaziiing idea (and it’s what this article is about).
In python, the puppether engine can be used thanks to Pyppeteer. And to parse the gherkin features files, we’ll use gherkin-parser.

Install pyppetheater

First, you have to install the chrome headless engine (under ubuntu):

$ wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -  
$ sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google-chrome.list'  
$ apt-get -y update  
$ apt-get install -yqq unzip sudo python3-pip mysql-client google-chrome-stable  
$ wget -O /tmp/chromedriver.zip http://chromedriver.storage.googleapis.com/`curl -sS chromedriver.storage.googleapis.com/LATEST_RELEASE`/chromedriver_linux64.zip  
$ unzip /tmp/chromedriver.zip chromedriver -d /usr/local/bin/  
$ pyppeteer-install  

And install pyppettheater:

$ pip3 install Pyppetheater  

You can now run the pyppet_theater binary:

$ pyppet_theater /path/to/your/yml/or/feature/file  

Some example of test

Each test suite is a yml file which contains some parameters (if needed):

parameters:  
    rest:  
        base_endpoint: https://jsonplaceholder.typicode.com  
  
scenarios:  
    0: rest/rest-suite.feature  

For a REST API:

For example in the rest/rest-suite.feature:

Feature: Use the rest test suite  
  
	Scenario: We can fetch data from an api  
		Given I add these headers:  
			| accept | application/json |  
		Given I prepare a "GET" request to "/todos/1"  
		When I send the request  
		Then print the last json response  
		And the json node "anythng" should not exist  
		And the json node "userId" should exist  
		And the json node "id" should be equal to "1"  
$ pyppet_theater rest.yml  

For a frontend test:

For example, in a game/registration.feature file:

Feature: Create an account on a website  
  
	Scenario: As a visitor, I register on the website  
		Given I go on "http://my-website.com"  
		And I click on "\#signup-link"  
		And I type "player6" in field "\#id_username"  
		And I type "somepassword" in field "\#id_password1"  
		And I type "somepassword" in field "\#id_password2"  
		When I click on "\#register"  
		Then I should be on "http://my-website.com"  

And run it:

$ pyppet_theater game/registration.feature  

For mysql tests:

With a mysql.yml file

parameters:  
    mysql:  
        db_host: 127.0.0.1  
        db_user: root  
        db_password: root  
        db_name: test  
  
scenarios:  
    0: "mysql/mysql-suite.feature"  
  

And, in a mysql/mysql-suite.feature:

Feature: Use the mysql test suite  
  
	Scenario: We can select, update and check existence  
		Given the row with "id" equal to "1" in table "some_table" should exist  
		And the row with "id" equal to "1" in table "some_table" has "some_key" equal to "some_value"  
		Then the row with "id" equal to "1" in table "some_table" should have "some_key" equal to "some_value"  
		And the row with "some_key" equal to "some_value" in table "some_table" should exist  
  
	Scenario: We can delete and check existence  
		Given the row with "id" equal to "1" in table "some_table" does not exist  
		Then the row with "id" equal to "1" in table "some_table" should not exist  
  

And run it:

$ pyppet_theater mysql.yml  

You can also use the docker image.

To know more about Pyppettheater, go to the repo!

Let's twitt about it!

When you click on links to various merchants on this site and make a purchase, this can result in this site earning a commission.
Affiliate programs and affiliations include, but are not limited to, the eBay Partner Network and Amazon.