• +43 660 1453541
  • contact@germaniumhq.com

Getting Started with Germanium II


Getting Started with Germanium II

The 2nd part of our 3 part series in which we’ll explore how to get started in using germanium. We’ll assume the only thing you have is python and a browser, and we’ll go from writing the first test, to integrating the test suite in a CI/CD system, in our case Jenkins.

This series is broken down into:

  1. Installation and the first test

  2. Test structure with behave (this article)

  3. Integration in CI/CD

Test structure with behave

Now that we got the first test running, we will need to create quite a few of them. As the system would grow, the test complexities might follow if you’re not paying attention.

Separate selectors in their own selectors.py file.

This is why the recommendation is to break down the UI components into their own file. We’ll call that file selectors.py. In this file we will define the UI components with which the test is interacting. For this we will create functions that will return the selectors defining a vocabulary for our application.

In it we would have things such as ModalDialog, LoginButton, CustomPanel, etc. depending on what components are in the application.

Let’s go forward with the google sample. We would create a selector for the input:

from germanium.static import *

def GoogleInput():
    return InputText("q")

This decoupling allows us to be resilient to changes in the future. If the upstream developers decide to change the input selector, we still can use the awesome positional finding capabilities:

def GoogleInput():
    return Element("input").below(Text("Search for:"))

All the description of the GoogleInput, and how we find it are nicely packaged into the GoogleInput() function.

This also means we can relate various UI components together, including in finding. For example we could have a component such as:

def DialogCloseButton():
    return Button().inside(ModalDialogHeader)

While Button comes from Germanium, ModalDialogHeader is just another function that will return a new selector.

Use the Germanium interaction APIs

Now we can interact with it, leveraging the Germanium’s input API, using its component’s custom name:

type_keys(GoogleInput, "germaniumhq.com<enter>")

In the ever changing APIs from Selenium, Germanium is built with backwards compatibility in mind. You can click, right_click, hover, double_click, drag_and_drop, type_keys including using keyboard shortcuts, in a simple, sane API.

The format is also made so you can just stream your keys from your behave test directly into the API, without having action builders and other nonsense:

Scenario: Test cleaning the input works correctly.
    Given I have a value in the custom input spinner that is not '11'
    When I type in the custom input spinner '<ctrl-a><del>11<enter>'
    Then the value in the custom input spinner is '11'

The step implementation can then be just:

@when(u"I type in the custom input spinner '(.+)'")
def type_in_custom_spinner(context, keys):
    type_keys(CustomSpinner, keys)

Conclusions

In this article we learned that we should:

  1. Have all the UI components selectors into a single file, using functions to fetch them.

  2. Use the Germanium interaction APIs in the step implementations.