Skip to content

Using BDD and Cucumber in Squash - Automating test cases

Getting the test cases

Annita
Squash TM administrator
Pravash
Product owner
Fabrice
Functional tester
Antonine
Automatician
Set up Squash TM
Write requirements
Write test cases
Transmit test cases
Get test cases
Automate test cases
Deliver automated test cases
Indicate automation is performed
Run automated tests

Picking up the test cases to automate in Squash TM

Antonine picks some tests to be automated in the "To Do" Tab of the Automation Workspace (see Squash TM documentation) by selecting them and clicking the "Assign to me" button.

test case pick up

Then, using "Assigned to me" Tab of the Automation Workspace (see Squash TM documentation), she indicates that the automation of these tests is started:

test case automation in progress

Getting the feature files

Antonine updates her local repository to get the feature files pushed by Squash TM in the remote Git repository.

git pull

Automating the test cases

Annita
Squash TM administrator
Pravash
Product owner
Fabrice
Functional tester
Antonine
Automatician
Set up Squash TM
Write requirements
Write test cases
Transmit test cases
Get test cases
Automate test cases
Deliver automated test cases
Indicate automation is performed
Run automated tests

Boiler plate setup

Before implementing the first Cucumber steps, Antonine needs to properly set up her Maven project.

.gitignore file

Antonine creates the usual .gitignore file. It defines the files that Git should not track and, hence, not consider for commits, see Git documentation. Here, she wants Git to ignore the files generated by Maven.
The file contains:

# ignore files created by Maven (compiled Java, test reports…)
target/

pom.xml file

She creates the following pom.xml file to use Cucumber, JUnit, and Selenium:
(The Maven documentation describes its syntax and working.)

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>prestashoptest</groupId>
    <artifactId>prestashoptest</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-java</artifactId>
            <version>7.2.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.platform</groupId>
            <artifactId>junit-platform-suite</artifactId>
            <version>1.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.junit.vintage</groupId>
            <artifactId>junit-vintage-engine</artifactId>
            <version>5.8.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>io.cucumber</groupId>
            <artifactId>cucumber-junit</artifactId>
            <version>7.2.3</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.seleniumhq.selenium</groupId>
            <artifactId>selenium-java</artifactId>
            <version>4.1.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <encoding>UTF-8</encoding>
                    <source>11</source>
                    <target>11</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M5</version>
            </plugin>
        </plugins>
    </build>
</project>

src/test/resources/cucumber.properties file

She also creates the src/test/resources/cucumber.properties file in order to avoid Cucumber messages about report publication.
The file contains:

cucumber.publish.quiet=true
cucumber.publish.enabled=false

Configuration of Cucumber in RunCucumberTest.java file

Antonine creates the src/test/java/prestashoptest/RunCucumberTest.java root test file:

package prestashoptest;

import org.junit.runner.RunWith;
import io.cucumber.junit.Cucumber;

@RunWith(Cucumber.class)
public class RunCucumberTest {
}

Structure of the code base

Antonine creates some directories in src/test/java/prestashoptest to organize her code. The resulting file hierarchy is:

  • .git/ → Git

  • src/

    • test /

      • java /

        • prestashoptest/

          • datatypes/ → data types required to model the business objects
          • helpers/ → technical helpers (StringHelper …)
          • pageobjects/ → page objects
            • AccountCreationPageObject.java
            • CartPageObject.java
            • CatalogPageObject.java
            • HomePageObject.java
            • IdentityPageObject.java
            • ProductPageObject.java
            • SignInPageObject.java
          • seleniumtools/ → Selenium tools (helpers for Selenium usage)
          • stepdefinitions/ → definition of the Cucumber steps
            • AccountStepDefinitions.java
            • CartStepDefinitions.java
            • CommonStepDefinitions.java
          • RunCucumberTest.java
          • SetupTeardown.java
      • resources/

        • prestashoptest/ → feature files generated by Squash TM 🛑 These files must not be modified!

          • account

            • 431_Create_an_account__then_check_login_and_personal_data.feature
            • 432_Create_an_account__then_try_to_login_with_incorrect_password.feature
            • …
          • cart

            • 240_Add_one_product_in_the_cart.feature
            • 303_Add_two_products_in_the_cart.feature
            • 304_Add_twice_a_product_to_the_cart.feature
            • …
        • cucumber.properties → configuration of Cucumber

  • .gitignore

  • pom.xml

Some design notes

graph TD
    A[Step definitions] --> B[Page objects]
    A --> C[Data types]
    A --> D[Helpers]
    B --> E[Selenium tools]
    B --> C
    B --> D
Antonine wants to clearly separate the concerns:

  • src/test/java/prestashoptest/seleniumtools
    • contains most of the code related to interface with WebDriver;
    • is a technical layer, it does not know about the business rules of the tested application.
  • src/test/java/prestashoptest/pageobjects contains the usual page objects.
    A page object is a Java class encapsulating the technical details of a tested page (IDs, names, XPaths… of the HTML elements).
    This design pattern has two main advantages:

    • It reduces the maintenance cost by centralizing the page details in one place: if a developer modifies a HTML element on the page and this change breaks the locator used by Antonine to find the element, she would have to update it in only one place.
    • It provides an API that has business semantics: code using the page object knows the features supported by the page (e.g. enter email and password, then try to login) but it does not need to know its HTML structure or its JavaScript behavior.

    The page objects are using WebDriver mostly via the seleniumtools classes (e.g. for all the basic operations such as setting a field value, getting a field value, clicking on an element…). In some few cases, when a page object needs to perform some operations which are too specific to be in a seleniumtools class, it calls WebDriver directly.

  • src/test/java/prestashoptest/stepdefinitions contains the implementation of the Cucumber steps.
    Each Cucumber step interacts with some page objects. It has no knowledge about WebDriver, HTML, JavaScript…

The src/test/resources/prestashoptest directory

🛑 The content of the src/test/resources/prestashoptest directory must not be modified, it is controlled by Squash TM.
Modifying some files in that directory could impede the transmission of new or updated test cases (i.e. feature files) in the future.
But, even if the transmission would work, all the modifications would be lost, overwritten by Squash TM.

Writing Selenium tools

Antonine uses inheritance to facilitate the Selenium calls: src/test/java/prestashoptest/seleniumtools/PageObjectBase.java is the base class for all page objects.
Antonine writes there some basic utility methods to

  • fill a field and get its value

    protected void fillFieldValue(final SelectBy by,
                                  final String fieldKey,
                                  final String value) {
        final WebElement element = by.findElement(getDriver(), fieldKey);
        element.clear();
        element.sendKeys(value);
    }
    protected String getFieldValue(final SelectBy by,
                                   final String fieldKey) {
        return by.findElement(getDriver(), fieldKey).getAttribute("value");
    }
    

  • click on an element

    protected void clickElement(final SelectBy by,
                                final String elementKey) {
        by.findElement(getDriver(), fieldKey).click();
    }
    

  • get the status of a checkbox

    protected boolean isCheckBoxSelected(final SelectBy by,
                                         final String checkBoxKey) {
        return by.findElement(getDriver(), checkBoxKey).isSelected();
    }
    

  • and so on…

It also contains some static methods to declare the host where the SUT is deployed, to select the browser to use for the test, to generate a screenshot, to quit the WebDriver session… (These methods are mostly used during the setup and teardown of the tests described below.)

    public static void setHost(final String host) {
        PageObjectBase.host = host;
    }
    public static void setBrowser(final Browser browser) {
        PageObjectBase.browser = browser;
    }
    public static void quit() {
        PageObjectBase.browser.quit();
    }
    public static byte[] getScreenshot() {
        return ((TakesScreenshot)getDriver()).getScreenshotAs(OutputType.BYTES);
    }

Writing setup and teardown

Antonine implements then the setup and teardown of the tests that she places in src/test/java/prestashoptest/SetupTeardown.java.

  • the test setup:

    @Before
    public void setup() {
        PageObjectBase.setBrowser(PageObjectBase.Browser.FIREFOX);
        PageObjectBase.setHost("http://localhost:8080/fr");
    }
    
    This setup initializes the Browser type and URL of the tested application.

  • the test teardown:

    @After
    public void closeBrowser(final Scenario scenario) {
        if (scenario.isFailed()) {
            final byte[] screenshot = PageObjectBase.getScreenshot();
            final String screenshotName = "screenshot " + scenario.getName() + " (line " + scenario.getLine() + ")";
            scenario.attach(screenshot,"image/png", screenshotName);
        }
        PageObjectBase.quit();
    }
    
    This teardown generates a screenshot and transmits it to Cucumber in case of a test failure. This will be very helpful to analyse why the failure occurred.
    The teardown also quits the WebDriver session.

Writing page objects

Once these foundation bricks are implemented, Antonine creates a page object for each page with which a Cucumber step will interact.

Most page objects are very simple and only use the PageObjectBase's methods.
For example, for the account creation page: Prestashop account creation the page object (src/test/java/prestashoptest/pageobjects/AccountCreationPageObject.java file) is:

package prestashoptest.pageobjects;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

import prestashoptest.datatypes.Gender;
import prestashoptest.seleniumtools.PageObjectBase;

/**
 * Account creation page
 */
public class AccountCreationPageObject extends PageObjectBase {

    public AccountCreationPageObject() {
        super("connexion?create_account=");
    }

    /**
     * Fill the form with the specified values (default values are used for the other fields)
     * and initiate the account creation.
     *
     * @param gender
     * @param firstName
     * @param lastName
     * @param password
     * @param email
     * @param birthDate
     * @param acceptPartnerOffers
     * @param acceptPrivacyPolicy
     * @param acceptNewsletter
     * @param acceptGdpr
     */
    public void fillNewAccountFields(final Gender gender,
                                     final String firstName,
                                     final String lastName,
                                     final String password,
                                     final String email,
                                     final LocalDate birthDate,
                                     final boolean acceptPartnerOffers,
                                     final boolean acceptPrivacyPolicy,
                                     final boolean acceptNewsletter,
                                     final boolean acceptGdpr) {
        fillGender(gender);
        fillFirstName(firstName);
        fillLastName(lastName);
        fillEmail(email);
        fillPassword(password);
        fillBirthDate(birthDate);
        if (acceptPartnerOffers) acceptPartnerOffers();
        if (acceptPrivacyPolicy) acceptPrivacyPolicy();
        if (acceptNewsletter) acceptNewsletter();
        if (acceptGdpr) acceptGdpr();
        submitNewAccountForm();
    }

    /**
     * Fill the gender field
     * If the gender is undefined, the field is untouched.
     * 
     * @param gender
     */
    public void fillGender(final Gender gender) {
        if (gender.equals(Gender.UNDEFINED)) {
            return;
        }
        final String id = (gender.equals(Gender.MALE)) ? "field-id_gender-1"
                                                       : "field-id_gender-2";
        clickElement(SelectBy.ID, id);
    }

    /**
     * Fill the first name field
     * 
     * @param firstName
     */
    public void fillFirstName(final String firstName) {
        fillFieldValue(SelectBy.ID, "field-firstname", firstName);
    }

    /**
     * Fill the last name field
     * 
     * @param lastName
     */
    public void fillLastName(final String lastName) {
        fillFieldValue(SelectBy.ID, "field-lastname", lastName);
    }

    /**
     * Fill the email field
     * 
     * @param email
     */
    public void fillEmail(final String email) {
        fillFieldValue(SelectBy.ID, "field-email", email);
    }

    /**
     * Fill the password field
     * 
     * @param password
     */
    public void fillPassword(final String password) {
        fillFieldValue(SelectBy.ID, "field-password", password);
    }

    /**
     * Fill the password field
     * 
     * @param birthDate
     */
    public void fillBirthDate(final LocalDate birthDate) {
        fillFieldValue(SelectBy.ID, "field-birthday", birthDate.format(DateTimeFormatter.ofPattern("dd/MM/yyyy")));
    }

    /**
     * Approve for partner offers
     */
    public void acceptPartnerOffers() {
        clickElement(SelectBy.NAME, "optin");
    }

    /**
     * Approve the customer privacy policy
     */
    public void acceptPrivacyPolicy() {
        clickElement(SelectBy.NAME, "customer_privacy");
    }

    /**
     * Sign up for the newsletter
     */
    public void acceptNewsletter() {
        clickElement(SelectBy.NAME, "newsletter");
    }

    /**
     * Approve the GDPR policy
     */
    public void acceptGdpr() {
        clickElement(SelectBy.NAME, "psgdpr");
    }

    /**
     * Initiate the account creation
     */
    private void submitNewAccountForm() {
        clickElement(SelectBy.XPATH, "//*[@id=\"customer-form\"]/footer/button");
    }
}

In a few cases, the HTML is more difficult to navigate, so the page object is more complex.
For example, to retrieve the content of the cart: Prestashop account creation the page object (src/test/java/prestashoptest/pageobjects/CartPageObject.java file) is:

package prestashoptest.pageobjects;

import java.util.ArrayList;
import java.util.List;

import org.openqa.selenium.By;
import org.openqa.selenium.WebElement;

import prestashoptest.datatypes.CartLine;
import prestashoptest.seleniumtools.PageObjectBase;

public class CartPageObject extends PageObjectBase {

    public CartPageObject() {
        super("panier?action=show");
    }

    public List<CartLine> getContent() {
        final List<WebElement> items = getElements(SelectBy.CLASS, "cart-item");
        final List<CartLine> list = new ArrayList<CartLine>(items.size());
        for (final WebElement item: items) {
            final WebElement productElem = item.findElement(By.className("label"));
            final String product = productElem.getText();
            final WebElement quantityElem = item.findElement(By.name("product-quantity-spin"));
            final int quantity = Integer.parseInt(quantityElem.getAttribute("value"));
            final List<WebElement> dimensionElem = item.findElements(By.className("dimension"));
            final String dimension = dimensionElem.isEmpty() ? null : dimensionElem.get(0).findElement(By.className("value")).getText();  
            final List<WebElement> sizeElem = item.findElements(By.className("taille"));
            final String size = sizeElem.isEmpty() ? null : sizeElem.get(0).findElement(By.className("value")).getText();  
            final List<WebElement> colorElem = item.findElements(By.className("couleur"));
            final String color = colorElem.isEmpty() ? null : colorElem.get(0).findElement(By.className("value")).getText();  
            list.add(new CartLine(product, quantity, dimension, size, color));
        }
        return list;
    }
}

Implementing Cucumber steps

The src/test/java/prestashoptest/stepdefinitions/*.java files contain the definitions of the Cucumber steps.
Antonine groups the steps related to a given feature domain in the same class. So she creates AccountStepDefinitions.java, CartStepDefinitions.java… At last, CommonStepDefinitions.java contains transverse steps.

There are three types of steps:

Given

A Given step is used to set up a test precondition.
It can navigate and interact with several pages in order to arrange the necessary data. It can even set up the data by bypassing the application user interface: calling the REST API provided by the application, injecting data in the application database…
A Given step does not need to be on a particular page to be called.

For example, some test cases need the (unspecified) user to be logged in. So they use the Given I am logged in step.
This step is implemented by using the account creation page and creating a one-time user (src/test/java/prestashoptest/stepdefinitions/AccountStepDefinitions.java file):

package prestashoptest.stepdefinitions;

…
import io.cucumber.java.en.Given;
…

public class AccountStepDefinitions {

    /**
     * Create a temporary user and keep him/her logged in
     */
    @Given("I am logged in")
    public void createTemporaryUser() {
        final String id = StringsHelper.generateRandomId();
        final AccountCreationPageObject newAccountPage = new AccountCreationPageObject();
        newAccountPage.goTo();
        newAccountPage.fillNewAccountFields(Gender.UNDEFINED,
                                            "first. " + id,
                                            "last. " + id,
                                            id,
                                            id + "@example.com",
                                            LocalDate.of(2000, 1, 1),
                                            true,
                                            true,
                                            true,
                                            true);
        final HomePageObject homePage = new HomePageObject();
        homePage.assertIsCurrent();
    }

   …
}
(In order to have robust steps, Antonine checks here that the account creation was successful by asserting that the user has been redirected to the home page.)

When

A When step performs an action.

For example, When I am on the AccountCreation page is implemented (in the same file) by:

    /**
     * Go to the Account Creation page
     */
    @When("I am on the AccountCreation page")
    public void displayNewAccountPage() {
        final AccountCreationPageObject newAccountPage = new AccountCreationPageObject();
        newAccountPage.goTo();
    }

Many When steps expect to be applied while a given page is displayed, so they assert that this is the case.
For example, the When("I fill AccountCreation fields with gender {string} firstName {string} lastName {string} password {string} email {string} birthDate {string} acceptPartnerOffers {string} acceptPrivacyPolicy {string} acceptNewsletter {string} acceptGdpr {string} and submit step is implemented by:

    /**
     * Fill the fields of the Account Creation page and submit the form
     *
     * The current page must be the Account Creation page
     */
    @When("I fill AccountCreation fields with gender {string} firstName {string} lastName {string} password {string} " +
          "email {string} birthDate {string} acceptPartnerOffers {string} acceptPrivacyPolicy {string} acceptNewsletter{string} acceptGdpr {string} and submit")
    public void fillAccountCreationFieldsAndSubmit(final String genderCode,
                                                   final String firstName,
                                                   final String lastName,
                                                   final String password,
                                                   final String email,
                                                   final String birthDate,
                                                   final String acceptPartnerOffers,
                                                   final String acceptPrivacyPolicy,
                                                   final String acceptNewsletter,
                                                   final String acceptGdpr) {
        final AccountCreationPageObject newAccountPage = new AccountCreationPageObject();
        newAccountPage.assertIsCurrent();
        newAccountPage.fillNewAccountFields(Gender.ofCode(genderCode),
                                            firstName,
                                            lastName,
                                            password,
                                            email,
                                            LocalDate.parse(birthDate),
                                            StringsHelper.convertYesNoIntoBoolean(acceptPartnerOffers),
                                            StringsHelper.convertYesNoIntoBoolean(acceptPrivacyPolicy),
                                            StringsHelper.convertYesNoIntoBoolean(acceptNewsletter),
                                            StringsHelper.convertYesNoIntoBoolean(acceptGdpr));
    }

Then

A Then step is used to verify that a test postcondition is fulfilled.
It can navigate and interact with several pages in order to arrange the necessary data. It can even set up the data by bypassing the application user interface: calling the REST API provided by the application, injecting data in the application database…
A Then step does not need to be on a particular page to be called.

For example, the Then My personal information is gender {string} firstName {string} lastName {string} email {string} birthDate {string} acceptPartnerOffers {string} acceptPrivacyPolicy {string} acceptNewsletter {string} acceptGdpr {string} step is implemented by displaying the personal data page, getting the field values, and checking that they have the expected values:

    /**
     * Verify that the personal data is equal to the given parameters
     */
    @Then("My personal information is gender {string} firstName {string} lastName {string} " +
          "email {string} birthDate {string} acceptPartnerOffers {string} acceptPrivacyPolicy {string} acceptNewsletter {string} acceptGdpr {string}")
    public void assertPersonalInformation(final String genderCode,
                                          final String firstName,
                                          final String lastName,
                                          final String email,
                                          final String birthDate,
                                          final String acceptPartnerOffers,
                                          final String acceptPrivacyPolicy,
                                          final String acceptNewsletter,
                                          final String acceptGdpr) {
        final IdentityPageObject identityPage = new IdentityPageObject();
        identityPage.goTo();
        Assertions.assertEquals(Gender.ofCode(genderCode),
                                identityPage.getGender(),
                                "The effective gender is not the expected one");
        Assertions.assertEquals(firstName,
                                identityPage.getFirstName(),
                                "The effective first name is not the expected one");
        Assertions.assertEquals(lastName,
                                identityPage.getLastName(),
                                "The effective last name is not the expected one");
        Assertions.assertEquals(email,
                                identityPage.getEmail(),
                                "The effective email is not the expected one");
        Assertions.assertEquals(LocalDate.parse(birthDate),
                                identityPage.getBirthDate(),
                                "The effective birth date is not the expected one");
        Assertions.assertEquals(StringsHelper.convertYesNoIntoBoolean(acceptPartnerOffers),
                                identityPage.doesAcceptPartnerOffers(),
                                "The effective acceptPartnerOffers is not the expected one");
        Assertions.assertEquals(StringsHelper.convertYesNoIntoBoolean(acceptPrivacyPolicy),
                                identityPage.doesAcceptPrivacyPolicy(),
                                "The effective acceptPrivacyPolicy is not the expected one");
        Assertions.assertEquals(StringsHelper.convertYesNoIntoBoolean(acceptNewsletter),
                                identityPage.doesAcceptNewsletter(),
                                "The effective acceptNewsletter is not the expected one");
        Assertions.assertEquals(StringsHelper.convertYesNoIntoBoolean(acceptGdpr),
                                identityPage.doesAcceptGdpr(),
                                "The effective acceptGdpr is not the expected one");
    }

Some implementation details

Regular expressions vs. Cucumber expressions

There are two ways to write the patterns matching the parameters of the Gherkin steps:

  • the usual Java regular expressions:

    public class CartStepDefinitions {
        @Then("I have (\\d+) products in my cart")
        public void assertNumberOfProductsInCart(final String argNbProducts) {
            int nbProducts = Integer.parseInt(argNbProducts);
            System.out.format("Products: %n\n", nbProducts);
        }
    }
    

  • the Cucumber expressions:

    public class CartStepDefinitions {
        @Then("I have {int} products in my cart")
        public void assertNumberOfProductsInCart(final int nbProducts) {
            System.out.format("Products: %n\n", nbProducts);
        }
    }
    
    They allow to quickly match common data types (string, word, int, float…) without having to write the boiler code for converting text into integers, floats… So Antonine uses these ones.

Lambdas vs. classic methods

There are two ways to implement Gherkin steps:

  • using classic methods:

    package prestashoptest.stepdefinitions;
    import io.cucumber.java.en.Then;
    
    public class CartStepDefinitions {
        @Then("I have {int} products in my cart")
        public void assertNumberOfProductsInCart(final int nbProducts) {
            System.out.format("Products: %n\n", nbProducts);
        }
    }
    
    For this, the following dependency must be added in the pom.xml file:
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-java</artifactId>
        <version>7.2.3</version>
        <scope>test</scope>
    </dependency>
    

  • using lambdas:

    package prestashoptest.stepdefinitions;
    import io.cucumber.java8.En;
    
    public class CartStepDefinitions implements En {
        public CartStepDefinitions() {
            Then("I have {int} products in my cart", (final Integer nbProducts) -> {
                System.out.format("Products: %n\n", nbProducts);
            });
        }
    }
    
    For this, the following dependency must be added in the pom.xml file:
    <dependency>
        <groupId>io.cucumber</groupId>
        <artifactId>cucumber-java8</artifactId>
        <version>7.2.3</version>
        <scope>test</scope>
    </dependency>
    

The second method requires less code, there is no need to define the useless assertNumberOfProductsInCart method name. But Cucumber supports lambdas only up to 9 parameters in a given Gherkin step.
Fabrice and Antonine agreed to have a single step to fill a given application form in order to keep the steps simple for Fabrice. But the account creation form has 10 parameters, so Antonine sticks with the classic methods.

Use Maven to generate the code skeleton

In order to save some time for implementing the Gherkin steps, Antonine uses Maven to generate the code skeleton.
She launches the test:

mvn clean test -Dcucumber.features=src/test/resources/prestashoptest/Account_management/431_Create_an_account__then_check_login_and_personal_data.feature
Maven will fail and report the unimplemented steps, each error message contains a code skeleton that Antonine can copy/paste to start implementing the step:
[ERROR]   The step 'I fill AccountCreation fields with gender "M" firstName "John" lastName "Doe" password "mypassword" email "jdoe@example.com" birthDate "1990-01-02" acceptPartnerOffers "no" acceptPrivacyPolicy "yes" acceptNewsletter "yes" acceptGdpr "yes" and submit' is undefined.
You can implement this step using the snippet(s) below:

@When("I fill AccountCreation fields with gender {string} firstName {string} lastName {string} password {string} email {string} birthDate {string} acceptPartnerOffers {string} acceptPrivacyPolicy {string} acceptNewsletter {string} acceptGdpr {string} and submit")
public void i_fill_account_creation_fields_with_gender_first_name_last_name_password_email_birth_date_accept_partner_offers_accept_privacy_policy_accept_newsletter_accept_gdpr_and_submit(String string, String string2, String string3, String string4, String string5, String string6, String string7, String string8, String string9, String string10) {
    // Write code here that turns the phrase above into concrete actions
    throw new io.cucumber.java.PendingException();
}
(If cucumber-java8 is used, the proposed skeletons use lambdas.)

Delivering the automated test cases

Annita
Squash TM administrator
Pravash
Product owner
Fabrice
Functional tester
Antonine
Automatician
Set up Squash TM
Write requirements
Write test cases
Transmit test cases
Get test cases
Automate test cases
Deliver automated test cases
Indicate automation is performed
Run automated tests

Once Antonine has implemented all the Cucumber steps used by the features files, she checks that the tests work properly by running them:

mvn test -Dcucumber.plugin="html:target/cucumber-reports/Cucumber_html.html"
and checking the Cucumber report (target/cucumber-reports/Cucumber_html.html file): Cucumber report

When she finds something suspicious while automating a test, she performs the test manually and, if there really is a bug, she reports it as described in the Squash TM documentation.

When the tests are running properly, she commits and pushes:

git add .
git commit -m "Implemented first account and cart steps"
git push

Indicating that the automation is performed

Annita
Squash TM administrator
Pravash
Product owner
Fabrice
Functional tester
Antonine
Automatician
Set up Squash TM
Write requirements
Write test cases
Transmit test cases
Get test cases
Automate test cases
Deliver automated test cases
Indicate automation is performed
Run automated tests

Then, using the "Assigned to me" Tab of the Automation Workspace (see Squash TM documentation), Antonine indicates that the tests have been automated:

test case automation done

She also sets the technology of the tests: test case automation done (This setting should be automatically done by Squash TM, this will be fixed in a future release.)