Skip to content

Using BDD and Robot Framework 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 robot files

Antonine updates her local repository to get the robot 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

Structure of the code base

Before implementing the first Robot Framework steps, Antonine creates some directories to organize her code. The resulting file hierarchy is:

  • .git/ → Git

  • resources/

    • browser_helpers / → technical HTML helpers

      • checkbox_radiobutton_helpers.resource
      • …
    • helpers / → technical data helpers

      • datatable_helpers.resource
      • quote_helpers.resource
      • …
    • step_definitions / → test step definitions

      • account_management.resource
      • cart_management.resource
      • navigation.resource
      • product_management.resource
      • …
    • page_objects / → page objects

      • account_creation_page.resource
      • cart_page.resource
      • header_page.resource
      • home_page.resource
      • identity_page.resource
      • login_page.resource
      • product_page.resource
      • …
    • setup_teardown.resource
  • tests/

    • bdd_squash / → contains robot files generated by Squash TM 🛑 Subdirectory hierarchy and robot files must not be modified!

      • Account_management /

        • squash_resources.resource created by Antonine 🛑 File name must not be modified!
        • 271_Standard_account_creation.robot
        • 294_Cannot_log_with_incorrect_password.robot
        • …
      • Cart_management /

        • squash_resources.resource created by Antonine 🛑 File name must not be modified!
        • 296_One_product.robot.robot
        • 297_Add_two_products_in_the_cart.robot
        • …
      • …

    • bdd_duplicates / → robot file duplicates in order to perform tests in Antonine's local environment

      • Account_management /
        • squash_resources.resource
        • 271_Standard_account_creation.robot
      • …
  • .gitignore

Some design notes

graph TD
    A[Step definitions] --> B[Page objects]
    A --> D[Helpers]
    B --> E[Browser helpers]
    B --> D
Antonine wants to clearly separate the concerns:

  • resources/page_objects contains the usual page objects.
    A page object is a file 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 doesn't need to know its HTML structure or its JavaScript behaviour.
  • resources/step_definitions contains the implementation of Robot Framework keywords (test steps). Each keyword interacts with one or several page objects, it has no knowledge about the HTML structure.

  • resources/helpers

    • contains the code which is not related to the tested application (data format, string transformation, conversion of list or dictionary…);
    • is a technical layer: it does not know about the business rules of the tested application.
  • resources/browser_helpers

    • contains the code used by page objects for common HTML interactions;
    • is also technical layer.

The tests/bdd_squash directory

🛑 The robot files of the tests/bdd_squash directory must not be modified, they are controlled by Squash TM.
Modifying some files in that directory, other than the squash_resources.resource files, could impede the transmission of new or updated test cases (i.e. robot files) in the future.
But, even if the transmission would work, all the modifications would be lost, overwritten by Squash TM.

.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 test reports and screenshots.
This file contains:

# browser → contains all files generated after executing Robot Framework tests with the Browser library
#     screenshot
#        failure_screen_1.png → full page screenshot embedded in Robot Framework report
#        …
#     traces → created by the Browser library to store temporary trace files
browser/

# output.xml → test execution results
output.xml

# playwright-log.txt → log generated by the Browser library
playwright-log.txt

# log.html → report file: details about executed tests
log.html

# report.html → report file: overview of test execution
report.html

Structure of a robot file generated by Squash TM

Antonine analyses a robot test generated by Squash TM:

# Automation priority: 42
# Test case importance: High
*** Settings ***
Resource    squash_resources.resource

*** Keywords ***
Test Setup
    ${__TEST_SETUP} Get Variable Value  ${TEST SETUP}
    ${__TEST_294_SETUP} Get Variable Value  ${TEST 294 SETUP}
    Run Keyword If  $__TEST_SETUP is not None   ${__TEST_SETUP}
    Run Keyword If  $__TEST_294_SETUP is not None   ${__TEST_294_SETUP}

Test Teardown
    ${__TEST_294_TEARDOWN}  Get Variable Value  ${TEST 294 TEARDOWN}
    ${__TEST_TEARDOWN}  Get Variable Value  ${TEST TEARDOWN}
    Run Keyword If  $__TEST_294_TEARDOWN is not None    ${__TEST_294_TEARDOWN}
    Run Keyword If  $__TEST_TEARDOWN is not None    ${__TEST_TEARDOWN}

*** Test Cases ***
Cannot log with incorrect password
    [Setup] Test Setup

    Given I am on the AccountCreation page
    When I fill AccountCreation fields with gender "F" firstName "Alice" lastName "Noel" password "police" email "alice@noel.com" birthDate "01/01/1970" acceptPartnerOffers "yes" acceptPrivacyPolicy "yes" acceptNewsletter "yes" acceptGpdr "yes" and submit
    And I sign out
    And I sign in with email "alice@noel.com" and password "poluce"
    Then The error message "Échec d'authentification" is displayed

    [Teardown]  Test Teardown

The file is organized in three main parts:

1 - Settings:

*** Settings ***
Resource    squash_resources.resource
The squash_resources.resource file will contain a list of all dependencies required by the scenario. Antonine must create this squash_resources.resource file in the test folder and list in it the relative paths of the dependencies.

For instance, if the test steps needed by the tests/bdd_squash/Account_management/271_Standard_account_creation.robot test are located in:

  • resources/setup_teardown.resource
  • resources/step_definitions/account_management.resource

she would fill the tests/bdd_squash/Account_management/squash_resources.resource file as:

*** Settings ***
Documentation    Resources for all account management tests
Resource    ../../../resources/setup_teardown.resource
Resource    ../../../resources/step_definitions/account_management.resource

squash_resources.resource

Antonine must create and implement the squash_resources.resource file in each folder containing BDD tests.
This file must contain the list of files defining the keywords used in the robot file generated by Squash TM (see below).

2 - Setup and Teardown:

*** Keywords ***
Test Setup
    ${__TEST_SETUP} Get Variable Value  ${TEST SETUP}
    ${__TEST_294_SETUP} Get Variable Value  ${TEST 294 SETUP}
    Run Keyword If  $__TEST_SETUP is not None   ${__TEST_SETUP}
    Run Keyword If  $__TEST_294_SETUP is not None   ${__TEST_294_SETUP}

Test Teardown
    ${__TEST_294_TEARDOWN}  Get Variable Value  ${TEST 294 TEARDOWN}
    ${__TEST_TEARDOWN}  Get Variable Value  ${TEST TEARDOWN}
    Run Keyword If  $__TEST_294_TEARDOWN is not None    ${__TEST_294_TEARDOWN}
    Run Keyword If  $__TEST_TEARDOWN is not None    ${__TEST_TEARDOWN}

Squash TM has created keywords to run as setup and teardown of the test. (The setup is used to prepare the test context. The teardown to clean it up.) For each test, Antonine has to choose to implement none, one, or several of those keywords:

  • ${TEST SETUP} and ${TEST TEARDOWN} are shared by all tests: used for basic non-specific setup and teardown (for instance: opening or closing a browser)

  • ${TEST 294 SETUP} and ${TEST 294 TEARDOWN} are specific setup and teardown for this specific 294 test case. If this test needs some specific steps in addition to the basic setup and teardown, Antonine can write the corresponding code in one of those keywords.

Setup and teardown keywords

  • If all tests require a common setup, Antonine must define the ${TEST SETUP} keyword; otherwise, she must keep this keyword undefined.
  • If all tests require a common teardown, Antonine must define the ${TEST TEARDOWN} keyword; otherwise, she must keep this keyword undefined.
  • If a given test requires a specific setup, Antonine must define the ${TEST <test_id> SETUP} keyword; otherwise, she must keep this keyword undefined.
  • If a given test a specific teardown, Antonine must define the ${TEST <test_id> TEARDOWN} keyword; otherwise, she must keep this keyword undefined.

The files implementing these keywords shall be referenced in the squash_resources.resource file.

(Some IDEs improperly report a warning when a Robot Framework keyword is undefined. This may be the case for these keywords. This warning should be ignored.)

3 - The test case as written in Squash TM:

Each keyword appearing in the test case will have to be implemented in the *** Keywords *** section of one of the resource files.

*** Test Cases ***
Cannot log with incorrect password
    [Setup] Test Setup

    Given I am on the AccountCreation page
    When I fill AccountCreation fields with gender "F" firstName "Alice" lastName "Noel" password "police" email "alice@noel.com" birthDate "01/01/1970" acceptPartnerOffers "yes" acceptPrivacyPolicy "yes" acceptNewsletter "yes" acceptGpdr "yes" and submit
    And I sign out
    And I sign in with email "alice@noel.com" and password "poluce"
    Then The error message "Échec d'authentification" is displayed

    [Teardown]  Test Teardown

Keyword implementation

Antonine has to implement all the keywords.

The files implementing these keywords shall be referenced in the squash_resources.resource file.

Implementing setup and teardown

Once the file hierarchy has been set up, Antonine writes some necessary basic building bricks, starting with the setup and teardown of the tests that she places in resources/setup_teardown.resource as Robot Framework keywords.

  • the definition of variables

    *** Variables ***
    ${TEST SETUP}    Open Application
    ${URL}    http://localhost:8080/
    

  • setup

    ***Keywords*** 
    Open Application
        [Documentation]    Test setup.
        Register Keyword To Run On Failure    Take Screenshot    failure_screen_{index}    fullPage=True
        New Browser    browser=firefox    headless=True
        New Page    url=${URL}
        Set Viewport Size    1900   1000
    
    This setup opens a new Page at the given ${URL} location, with the Firefox browser, and changes the size of the window to a basic laptop screen size. This setup also generates full-page screenshots in case of one or several step failures in the test. The screenshots are placed in the browser/screenshot folder and are also embedded in the test reports. This will be very helpful to analyse why a test failed:

Robotframework report

Writing browser helpers

resources/browser_helpers/ contains resources with keywords used in several page objects, for instance, the resources/browser_helpers/checkbox_radiobutton_helpers.resource contains keywords to:

  • verify which radiobutton is selected in a list of radiobuttons

    *** Settings ***
    Documentation    Helpers for checkboxes and radiobuttons
    Library    Browser
    
    
    *** Keywords ***
    Verify Selected Radiobutton
        [Arguments]    ${choice}    @{radiobuttons}
        [Documentation]    Checks if the specified radiobutton state matches the specified choice
        FOR    ${radiobutton}    IN    @{radiobuttons}
            IF    "${choice}" == "${radiobutton}[label]"
                Get Checkbox State    ${radiobutton}[rb]    ==    True
                BREAK
            END
        END
    

  • select a checkbox

    *** Keywords ***
    Select Checkbox Regarding Choice
        [Arguments]    ${choice}    ${cb}
        [Documentation]    Check checkbox regarding the specified choice.
        IF    "${choice}" == "yes"    Check Checkbox    ${cb}
    

  • select a radiobutton

    *** Keywords ***
    Select Radiobutton Regarding Choice
        [Arguments]    ${choice}    @{radiobuttons}
        [Documentation]    Select radiobutton in a list of radiobuttons regarding the specified choice.
        FOR    ${radiobutton}    IN    @{radiobuttons}
            IF    "${choice}" == "${radiobutton}[label]"
                Check Checkbox    ${radiobutton}[rb]
                BREAK
            END
        END
    

Manage different kinds of data

Parameters

Fabrice has written a first type of basic test, with embedded values of variables directly inside the test steps:

parameters and datasets

Squash TM has generated a Robot Framework test with embedded parameters between quotes:

*** Test Cases ***
Cannot log with incorrect password
    [Setup] Test Setup

    Given I am on the AccountCreation page
    When I fill AccountCreation fields with gender "F" firstName "Alice" lastName "Noel" password "police" email "alice@noel.com" birthDate "01/01/1970" acceptPartnerOffers "yes" acceptPrivacyPolicy "yes" acceptNewsletter "yes" acceptGpdr "yes" and submit
    And I sign out
    And I sign in with email "alice@noel.com" and password "poluce"
    Then The error message "Échec d'authentification" is displayed

    [Teardown]  Test Teardown

Datasets

Fabrice has also written a second type of test, using datasets and embedded variables:

parameters and datasets

For this test, values are defined using Squash TM's dataset section:

parameters and datasets

Squash TM has generated a Robot Framework test with embedded variables:

*** Test Cases ***
Standard account creation
    [Setup] Test Setup

    Given I am on the AccountCreation page
    When I fill AccountCreation fields with gender ${gender} firstName ${first} lastName ${last} password ${password} email ${mail} birthDate ${birth} acceptPartnerOffers ${offers} acceptPrivacyPolicy ${privacy} acceptNewsletter ${news} acceptGpdr ${gpdr} and submit
    And I sign out
    And I sign in with email ${mail} and password ${password}
    Then My personal informations are gender ${gender} firstName ${first} lastName ${last} email ${mail} birthDate ${birth}

    [Teardown]  Test Teardown

Managing quotes to avoid code duplication

Some test steps are shared by those two tests, for instance the I sign in with email "alice@noel.com" and password "poluce" and I sign in with email ${mail} and password ${password} are similar: the main difference between the two generated keywords are the quotes surrounding the variables in the first one.

Antonine wants to avoid code duplication, thus, she wants to implement only once the I sign in with email ${mail} and password ${password} keyword.

In order to achieve this, Antonine has to manage the quotes because if she would not remove the quotes from the variables values, the keyword would work perfectly for the embedded parameters test, but would fail on the basic one, because Robot Framework would consider the parameter value as "Alice" and would inject it in the tested application with the quotes. (This issue should be fixed in a future Squash TM release, as all robot keywords generated by Squash TM will have quotes.).

In the resources/step_definitions/account_management.robot file, Antonine implements the keyword I sign in with email ${mail} and password ${password}:

*** Keywords ***
I sign in with email ${mail} and password ${password}
    [Documentation]     Logs a user.
    ${mail} =    Remove Framing Quotes From Parameter  ${mail}
    ${password} =    Remove Framing Quotes From Parameter  ${password}

    Go To The SignIn Page
    Clear Login Fields
    Fill Login Fields  ${mail}  ${password}
    Submit Login

by using the resources/helpers/quotes.resource resource:

*** Settings ***
Documentation    helpers for quoted parameters coming from Squash TM.
Library    String
Library    Collections


*** Keywords ***
Remove Framing Quotes From Parameter
    [Arguments]    ${parameter}
    [Documentation]    If the parameter starts and ends with a quote,
    ...                this keyword removes them.
    ...                Examples:
    ...                "hello world!" -> hello world!
    ...                "hello world! -> "hello world!
    ...                hello world! -> hello world!
    ${parameter} =    Replace String Using Regexp    ${parameter}    \\".*\\"    ${parameter}[1:-1]
    RETURN    ${parameter}

Running Robot Framework test using datasets on local environment

For tests using datasets, it is possible to retrieve their values by using the squash-tf-services library (see that page):

*** Settings ***
Library     squash_tf.TFParamService

...

*** Test Cases ***
Standard account creation
    ${gender} = Get Test Param  DS_gender
    ${first} =  Get Test Param  DS_first
    ${last} =   Get Test Param  DS_last
    ${password} =   Get Test Param  DS_password
    ${mail} =   Get Test Param  DS_mail
    ${birth} =  Get Test Param  DS_birth
    ${offers} = Get Test Param  DS_offers
    ${privacy} =    Get Test Param  DS_privacy
    ${news} =   Get Test Param  DS_news
    ${gpdr} =   Get Test Param  DS_gpdr

    ...
In order to run those tests on her environment, Antonine has to to make a few changes. This, she first duplicates them in the tests\bdd_duplicates folder, in order to leave the .robot files used by Squash untouched. In the duplicated files, she then adds a *** Variables *** section and removes the ${data} = Get Test Param DS_data:

*** Settings ***

*** Variables ***
${gender}    F
${first}    Alice
${last}    Bob
${password}    Pass1234
${mail}    alice.bob@mail.fr
${birth}    10/08/1998
${offers}    yes
${privacy}    yes
${news}    yes
${gpdr}    yes

*** Test Cases ***
Standard account creation
    ...
For all the other kinds of tests, Antonine can directly run the .robot file generated by Squash TM.

Docstring

Fabrice can also use docstrings to add multilines or long strings to the tests:

test case 3

The docstring is managed by Squash TM by declaring a variable and assigning the text value to it:

*** Test Cases ***
Navigate to one product
    ${docstring_1} =    Set Variable    Le meilleur reste à venir ! Faites parler vos murs avec cette affiche encadrée chargée d'optimisme sera du plus bel effet dans un bureau ou un open-space. Cadre en bois peint avec passe-partout integré pour un effet de profondeur.

    ...

    When I navigate to category "art"
    And I navigate to product "Affiche encadrée The best is yet to come"
    Then The product description is "${docstring_1}"

    ...

In the case of a multiline docstring such as:

    Le meilleur reste Ă  venir !
    Faites parler vos murs avec cette affiche encadrée chargée d'optimisme sera du plus bel effet dans un bureau ou un open-space.
    Cadre en bois peint avec passe-partout integré pour un effet de profondeur.

Squash TM generates a robot file using \n:

*** Test Cases ***
Navigate to one product
    ${docstring_1} =    Set Variable    Le meilleur reste à venir !\nFaites parler vos murs avec cette affiche encadrée chargée d'optimisme sera du plus bel effet dans un bureau ou un open-space.\nCadre en bois peint avec passe-partout integré pour un effet de profondeur.

Antonine writes the The product description is "${docstring_1}" as documented in the parameters and datasets section above.

Datatables

Fabrice also used datatables to add data to the tests:

test case 2

The datatable has been extracted and converted in the Robot Framework syntax by Squash TM:

*** Settings ***
Resource    squash_resources.resource

...

*** Test Cases ***
Add two products in the cart
    ${row_1_1} =    Create List    Product    Number    Dimension
    ${row_1_2} =    Create List    Affiche encadrée The best is yet to come    1    40x60cm
    ${row_1_3} =    Create List    Illustration vectorielle Renard    1
    ${datatable_1} =    Create List    ${row_1_1}    ${row_1_2}    ${row_1_3}

    ...

    Then the cart contains "${datatable_1}"

    ...

Datatables are managed row by row: Squash TM generates a list of strings for each row, called ${row_1_*}. The ${datatable_1} list is a list of all the rows, in other words, a list of lists, the first row being a list of the header labels.

Antonine has several ways to manage this input, she chooses to convert it from a list of lists to a list of dictionaries. She adds the method in the resources/helpers/datatable_helper.resource file:

*** Keywords ***
Create ListOfDictionary From Datatable
    [Arguments]    ${datatable}
    [Documentation]    Convert a list of lists to a list of dictionaries.
    ...                Example of input from Squash TM's BDD datatable (list of lists):
    ...                ['['name', 'firstName', 'age']', '['Doe', 'Alice', '12']', '['Smith', 'John', '45']']
    ...                Output (list of dictionaries):
    ...                {'{'name': 'Doe', 'firstName': Alice, 'age': '12'}',
    ...                 '{'name': 'Smith', 'firstName': 'John', 'age': '45'}']

    ${datatable_size} =    Get Length    ${datatable}
    @{final_list} =    Create List
    FOR    ${i}    IN RANGE    1    ${datatable_size}    1
        ${nb_items} =    Get Length    ${datatable}[${i}]
        &{dict} =    Create Dictionary
        FOR    ${j}    IN RANGE    0    ${nb_items}    1
            Set To Dictionary    ${dict}    ${datatable}[0][${j}]=${datatable}[${i}][${j}]
        END
        Append To List    ${final_list}    ${dict}
    END
    RETURN    @{final_list}

Then, Antonine implements easily the Then the cart contains "${datatable_1}", using her structured data:

*** Keywords ***
The Cart contains "${datatable}"
    [Documentation]    Checks that specified products are found in the cart.
    @{products} =  Create ListOfDictionary From Datatable  ${datatable}
    Go To The Cart Page
    Products Should Be In Cart  @{products}

Writing page objects

Antonine creates a page object for each page used by the test steps, in the resources/page_objects folder. A page object contains a *** Variables *** section with the locators, and a *** Keywords *** section where keywords used in the test steps are implemented. For instance, the page object of the login page is:

*** Settings ***
Documentation    Login page object
Library    Browser


*** Variables ***
&{log_locators}    create_account_link=//a[contains(@href, "connexion?create_account=1")]
...                login_button=//*[@id="submit-login"]
...                email_field=//*[@id="field-email"]
...                password_field=//*[@id="field-password"]


*** Keywords ***
Clear Login Fields
    [Documentation]    Clear all login fields.
    Clear Text    ${log_locators}[email_field]
    Clear Text    ${log_locators}[password_field]

Fill Login Fields
    [Arguments]    ${email}    ${password}
    [Documentation]    Logs a user on the website using specified values.
    Type Text    ${log_locators}[email_field]    ${email}
    Type Text    ${log_locators}[password_field]    ${password}

Submit Login
    [Documentation]    Initiate login.
    Click    ${log_locators}[login_button]

Error Message Should Be Displayed
    [Arguments]    ${message}
    [Documentation]    Checks that the specified error message is displayed.
    Get Element    //li[text()="${message}"]

Go To The AccountCreation Page
    [Documentation]    Navigates to the AccountCreation page.
    Click    ${log_locators}[create_account_link]

Encapsulation in Robot Framework

One keyword can depend on several page objects. Thus, to avoid any ambiguity, Antonine choose to store all the locators variables in a dictionary with a clear page object identification name. In the login-page, this dictionary is called &{log_locators}.

Implementing Robot Framework keywords (steps)

The resources/step_definitions/* files contain the definitions of the Robot Framework test 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 to start in the AccountCreation page. This step is implemented by navigating to the AccountCreation page and checking that the navigation has succeeded (resources/step_definitions/account_management file):

*** Settings ***
Resource    ../page_objects/header_page.resource
Resource    ../page_objects/login_page.resource
Resource    ../page_objects/account_creation_page.resource


***Keywords*** 
I am on the AccountCreation page
    [Documentation]    Navigates to the AccountCreation page
    Go To The SignIn Page
    Go To The AccountCreation Page
    Page Should Be AccountCreation Page

The verification that navigation has succeeded is done by the Page Should Be AccountCreation Page keyword, implemented in resources/page_objects/account_creation_page.resource by checking both the page title and the tab title:

*** Variables ***
&{acc_locators}    page_title=//h1[contains(text(), "Créez votre compte")]
...                mister_rb=//*[@id="field-id_gender-1"]
...                miss_rb=//*[@id="field-id_gender-2"]
...                first_name_field=//*[@id="field-firstname"]
...                last_name_field=//*[@id="field-lastname"]
...                email_field=//*[@id="field-email"]
...                password_field=//*[@id="field-password"]
...                birth_date_field=//*[@id="field-birthday"]
...                privacy_cb=//*[@name="customer_privacy"]
...                gpdr_cb=//*[@name="psgdpr"]
...                news_cb=//*[@name="newsletter"]
...                offers_cb=//*[@name="optin"]
...                validate_button=//*[@id="customer-form"]/footer/button


***Keywords*** 
Page Should Be AccountCreation Page
    [Documentation]    Checks if we are on the AccountCreation page.
    Get Title    ==    Identifiant
    Get Element    ${acc_locators}[page_title]

When

A When step performs an action.

For example, the code implemented by the I sign in with email ${mail} and password ${password} keyword is:

*** Keywords ***
I sign in with email ${mail} and password ${password}
    [Documentation]    Logs a user.
    ${mail} =    Remove Framing Quotes From Parameter  ${mail}
    ${password} =    Remove Framing Quotes From Parameter  ${password}

    Go To The SignIn Page
    Clear Login Fields
    Fill Login Fields  ${mail}  ${password}
    Submit Login

Many When steps expect to be applied while a given page is displayed, so they assert that this is the case.
For instance, the implementation of I sign out is:

*** Keywords ***
I sign out
    [Documentation]    Logs out a user.
    Sign Out
    User Is Logged Out

The verification that the user is indeed logged out is done by the User Is Logged Out keyword, implemented in resources/page_objects/header_page.resource by checking that the login link is visible again.

*** Variables ***
&{h_locators}    login_link=//a[@title="Identifiez-vous"]
...              logout_link=//a[contains(@href, "?mylogout=") and @class="logout hidden-sm-down"]
...              welcome_message=//a[@title="Voir mon compte client"]/span
...              cart_link=//span[text()="Panier"]
...              home_link=//img[@alt="Prestashop-Robot"]


*** Keywords ***
User Is Logged In
    [Arguments]    ${first_name}    ${last_name}
    [Documentation]    Checks that the specified user is logged in.
    Get Text    ${h_locators}[logout_link]    *=    DĂ©connexion
    Get Text    ${h_locators}[welcome_message]    ==    ${first_name} ${last_name}

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 implementation of the Then My personal informations are gender ${gender} firstName ${first} lastName ${last} email ${mail} birthDate ${birth} keyword is achieved by displaying the personal data page, getting the field values, and checking that they have the expected values:

*** Keywords ***
My personal informations are gender ${gender} firstName ${first} lastName ${last} email ${mail} birthDate ${birth}
    [Documentation]    Checks if the specified values match the personal informations of a logged user.
    ${gender} =    Remove Framing Quotes From Parameter  ${gender}
    ${first} =    Remove Framing Quotes From Parameter  ${first}
    ${last} =    Remove Framing Quotes From Parameter  ${last}
    ${mail} =    Remove Framing Quotes From Parameter  ${mail}
    ${birth} =    Remove Framing Quotes From Parameter  ${birth}
    Go To The MyAccount Page
    Page Should Be MyAccount Page
    Go To The Identity Page
    Private Informations Should Be  ${gender}  ${first}  ${last}  ${mail}  ${birth}

The verification of the informations is done by the Private Informations Should Be keyword, implemented in resources/page_objects/identity_page.resource by checking the values of all specified parameters:

*** Variables ***
&{id_locators}    mister_rb=//*[@id="field-id_gender-1"]
...               miss_rb=//*[@id="field-id_gender-2"]
...               first_name_field=//*[@id="field-firstname"]
...               last_name_field=//*[@id="field-lastname"]
...               email_field=//*[@id="field-email"]
...               birth_date_field=//*[@id="field-birthday"]
...               submit_button=//*[@id="customer-form"]/footer/button
...               privacy_cb=//*[@name="customer_privacy"]
...               gpdr_cb=//*[@name="psgdpr"]
...               old_password_field=//*[@id="field-password"]
...               new_password_field=//*[@id="field-new_password"]


*** Keywords ***
Private Informations Should Be
    [Arguments]   ${gender}  ${first}  ${last}  ${mail}  ${birth}
    [Documentation]    Checks that the specified values match the personal informations of a logged user.

    &{gender_M} =     Create Dictionary    label=M    rb=${id_locators}[mister_rb]
    &{gender_F} =     Create Dictionary    label=F    rb=${id_locators}[miss_rb]
    @{genders} =    Create List    ${gender_M}    ${gender_F}

    Verify Selected Radiobutton    ${gender}     @{genders}

    Get Attribute    ${id_locators}[first_name_field]    value    ==    ${first}
    Get Attribute    ${id_locators}[last_name_field]    value    ==    ${last}
    Get Attribute    ${id_locators}[email_field]    value    ==    ${mail}
    Get Attribute    ${id_locators}[birth_date_field]    value    ==    ${birth}

Robocop linter

Antonine uses the Robocop linter (a linter is a static code analyzer) to ensure her code is clean:

Installation

Antonine installs Robocop as described in the Robocop documentation:

pip install robotframework-robocop

Usage

Then, to analyze the code in a file or a folder, Antonine runs:

robocop [path 1] [path 2] [path n]
with the paths of the files and/or folders she wants Robocop to analyze.

Robocop warnings

The Robot Framework code generated by Squash TM may trigger some robocop warnings, some of them should be corrected in future releases. Regarding the Robot Framework code written by Antonine, good coding practices should prevent warnings, except for ones resulting from the way Squash TM generates its robot files:

  • wrong-case-in-keyword-name: BDD test steps are not written in title case (i.e. using uppercase for the first letter of each word).
  • line-too-long: Squash TM allows to write test step up to 255 characters long whereas robocop recommends less than 120 characters.
  • too-long-test-case: Squash TM allows to write many step tests, whereas robocop recommends less than 20 steps.

Antonine can ignore those warnings, or she can configure her project to ignore some rules or some robot files as detailed in the Robocop documentation on including and excluding rules.

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

Antonine is now ready to run the test on her local environment:

robot <test.robot>
and checking the Robot Framework report (/report.html file):

Robotframework report

and the Robot Framework log (/log.html file):

Robotframework 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