Page Object Prototype Syntax

Overview

To simplify the process of creating new page objects, some page object prototype classes support YAML representations of the object. Prototype classes that support this will generate a .yml file in addition to a Python module when using the new page --prototype <prototype> command.

The following sections detail YAML syntax specifically for webdriver_test_tools as well as the non-YAML alternative syntax for each page object prototype. For a basic introduction to YAML syntax in general, see Ansible’s YAML documentation.

Supported Prototype Classes

The following prototype classes support YAML parsing:

When initialized, these classes check to see if the YAML_FILE attribute is set. If YAML_FILE is not None, the contents will be parsed and used to set the page object’s attributes.

Configure Defaults

Whether YAML files or Python-only files are generated by default when using the new page command is configured in <test_package>/config/projectfiles.py by setting the ENABLE_PAGE_OBJECT_YAML variable of the ProjectFilesConfig class.

Override Default Setting

The default setting can be overridden using command line arguments. If ENABLE_PAGE_OBJECT_YAML is True, the --no-yaml (or -Y) argument can be used to only generate .py files:

<test_package> new page <args> --no-yaml

If ENABLE_PAGE_OBJECT_YAML is False, the --yaml (or -y) argument can be used to generate .py and .yml files for supported prototypes:

<test_package> new page <args> --yaml

General Syntax

This section documents the syntax of general page object constructs.

Locator Dictionaries

Element locators are represented by YAML dictionaries with the following required keys:

  • by: Locator strategy to use when finding the element. Use variable names of attributes in selenium.webdriver.common.by.By:

    • CLASS_NAME
    • CSS_SELECTOR
    • ID
    • LINK_TEXT
    • NAME
    • PARTIAL_LINK_TEXT
    • TAG_NAME
    • XPATH
  • locator: Value used to locate element with the specified locator strategy

Note

For non-YAML page objects, any instances of a locator dictionary can be replaced with a Python locator tuple i.e. (By.<STRATEGY>, '<locator>')

Relative URL Dictionaries

URLs that are relative to attributes specified in a project’s SiteConfig are specified with dictionaries using the following keys:

  • path: The path to the page, relative to the SiteConfig attribute specified in relative_to
  • relative_to: A valid attribute declared in the project’s SiteConfig class to use as a base URL

Note

Internally, these URL dictionaries are parsed using SiteConfig.parse_relative_url_dict. If the attribute that relative_to specifies does not have a trailing ‘/’, this method adds one before building the full URL

FormObjects

FormObjects support YAML representations of the form element using the following syntax.

Syntax

Forms

Form objects have 3 required keys:

Inputs

The items in the form inputs list have the following keys:

  • name: (Required) The name attribute of the element. If the element doesn’t have a name attribute, set this to any unique identifier (i.e. not used as the name value for another input in the form)
  • input_locator: (Required if element has no name attribute) Locator dictionary for the element. If provided, this will be used instead of name to find the element
  • type: (Default: text ) The type attribute of the input
  • required: (Default: true ) Whether or not the input is required to submit the form
  • options: (Required if type is radio, select, or a checkbox group (i.e. multiple checkboxes with the same name)) List of value attributes of radio inputs, select options, or checkboxes. A dictionary mapping values to labels is also valid (though only the map keys will be used, so the labels can be set to anything)

Example

With YAML

form.py
import os

from selenium.webdriver.common.by import By
from webdriver_test_tools.pageobject import *
from webdriver_test_tools.webdriver import actions, locate


class ExampleForm(prototypes.FormObject):
    """YAML FormObject example"""

    # Path to YAML file representing the object
    YAML_FILE = os.path.join(os.path.dirname(__file__), 'form.yml')

    # (Optional) Page object of the modal/webpage/etc that should appear on
    # successful form submission. If set to a subclass of BasePage, the
    # click_submit() method will return an instance of the page object
    SUBMIT_SUCCESS_CLASS = None
form.yml
form:
  # Locator for the form
  form_locator:
    by: ID
    locator: example-form-id
  # Locator for the submit button
  submit_locator:
    by: CSS_SELECTOR
    locator: '#example-form-id button[type="submit"]'
  # List of inputs in the form
  inputs:
    # Basic syntax:
    - name: email
      type: email
    # 'type' defaults to 'text' if not specified:
    - name: text_input
    # Inputs are assumed to be required by default, use 'required' to specify
    # otherwise:
    - name: optional_input
      required: false
    # For input elements with no name attribute, the 'input_locator' key is
    # used to locate the element (though the 'name' key is still required for
    # identification):
    - name: unique_identifier
      input_locator:
        by: CLASS_NAME
        locator: input-with-no-name-attribute
      type: text
    # Selects and radios take a list of options:
    - name: select_example
      type: select
      options:
        - option1
        - option2
        - option3
        - option4
    # 'options' can bet a dictionary too. Only the keys are used, so the values
    # can be set to anything:
    - name: radio_example
      type: radio
      # NOTE: numeric options keys/list entries should be in quotes
      options:
        '001': Helpful label
        '002': Another helpful label
        '003': An even more helpful label
    # Supports select elements with the 'multiple' attribute:
    - name: multiple_select_example
      type: select
      multiple: true
      options:
        - option0
        - option1
        - option2
    # Checkbox groups can accept a list of options too:
    - name: checkboxes[]
      type: checkbox
      # NOTE: set 'multiple' to true when multiple checkboxes have the same
      # name and different values
      multiple: true
      options:
        - box0
        - box1
        - box2

Without YAML

form.py
from selenium.webdriver.common.by import By
from webdriver_test_tools.pageobject import *
from webdriver_test_tools.webdriver import actions, locate


class ExampleForm(prototypes.FormObject):
    """Non-YAML FormObject example"""

    # REQUIRED: Locator for the form element
    FORM_LOCATOR = (By.ID, 'example-form-id')
    # REQUIRED: Locator for the form submit button
    SUBMIT_LOCATOR = (By.CSS_SELECTOR, '#example-form-id button[type="submit"]')

    # Inputs are specified here:
    INPUT_DICTS = [
        # Basic syntax:
        {
            'name': 'email',
            'type': 'email'
        },
        # 'type' defaults to 'text' if not specified:
        {'name': 'text_input'},
        # Inputs are assumed to be required by default, use 'required' to
        # specify otherwise:
        {
            'name': 'optional_input',
            'required': False
        },
        # For input elements with no name attribute, the 'input_locator' key is
        # used to locate the element (though the 'name' key is still required
        # for identification):
        {
            'name': 'unique_identifier',
            'input_locator': (By.CLASS_NAME, 'input-with-no-name-attribute')
        },
        # Selects and radios take a list of options:
        {
            'name': 'select_example',
            'type': 'select',
            'options': [
                'option1',
                'option2',
                'option3',
                'option4',
            ]
        },
        # 'options' can bet a dictionary too. Only the keys are used, so the
        # values can be set to anything:
        {
            'name': 'radio_example',
            'type': 'radio',
            'options': {
                # NOTE: numeric options keys/list entries should be in quotes
                '001': 'Helpful label',
                '002': 'Another helpful label',
                '003': 'An even more helpful label',
            }
        },
        # Supports select elements with the 'multiple' attribute:
        {
            'name': 'multiple_select_example',
            'type': 'select',
            'multiple': True,
            'options': [
                'option1',
                'option2',
                'option3',
            ]
        },
        # Checkbox groups can accept a list of options too:
        {
            'name': 'checkboxes[]',
            'type': 'checkbox',
            # NOTE: set 'multiple' to True when multiple checkboxes have the
            # same name and different values
            'multiple': True,
            'options': [
                'box0',
                'box1',
                'box2',
            ]
        },
    ]

    # (Optional) Page object of the modal/webpage/etc that should appear on
    # successful form submission. If set to a subclass of BasePage, the
    # click_submit() method will return an instance of the page object
    SUBMIT_SUCCESS_CLASS = None

ModalObjects

ModalObjects support YAML representations of the modal using the following syntax.

Syntax

Modal objects have 2 required keys:

Example

With YAML

modal.py
import os

from selenium.webdriver.common.by import By
from webdriver_test_tools.pageobject import *
from webdriver_test_tools.webdriver import actions, locate


class ExampleModal(prototypes.ModalObject):
    """YAML ModalObject example"""

    # Path to YAML file representing the object
    YAML_FILE = os.path.join(os.path.dirname(__file__), 'modal.yml')

    # (Optional) Page object of the contents of the modal body. If set to a
    # subclass of BasePage, the get_modal_body() method will return an instance
    # of the page object
    MODAL_BODY_CLASS = None
modal.yml
modal:
  # Locator for the modal
  modal_locator:
    by: ID
    locator: test-modal
  # Locator for the close button
  close_locator:
    by: CSS_SELECTOR
    locator: "#test-modal button.close"

Without YAML

modal.py
from selenium.webdriver.common.by import By
from webdriver_test_tools.pageobject import *
from webdriver_test_tools.webdriver import actions, locate


class ExampleModal(prototypes.ModalObject):
    """Non-YAML ModalObject example"""

    # REQUIRED: Locator for the modal element
    MODAL_LOCATOR = (By.ID, 'test-modal')
    # REQUIRED: Locator for the modal's close button
    CLOSE_LOCATOR = (By.CSS_SELECTOR, '#test-modal button.close')
    # (Optional) Page object of the contents of the modal body. If set to a
    # subclass of BasePage, the get_modal_body() method will return an instance
    # of the page object
    MODAL_BODY_CLASS = None

WebPageObjects

WebPageObjects support YAML representations of the modal using the following syntax.

Syntax

Web page objects have one required key url, which can be set to either the full URL to the page or a relative URL dictionary

Note

If ‘url’ is set to just the full URL to the page, the attribute PAGE_FILENAME will not be set in the WebPageObject. If it is set to a dictionary, PAGE_FILENAME will be set to the value of ‘path’

Example

With YAML

web_page.py
import os

from selenium.webdriver.common.by import By
from webdriver_test_tools.pageobject import *
from webdriver_test_tools.webdriver import actions, locate

from yaml_example.config import SiteConfig


class FullURLExampleWebPage(prototypes.WebPageObject):
    """YAML WebPageObject example (full URL)"""

    # Path to YAML file representing the object
    YAML_FILE = os.path.join(os.path.dirname(__file__), 'web_page_full.yml')
    # Used for internal methods (do not modify)
    SITE_CONFIG = SiteConfig


class RelativeURLExampleWebPage(prototypes.WebPageObject):
    """YAML WebPageObject example (relative URL)"""

    # Path to YAML file representing the object
    YAML_FILE = os.path.join(os.path.dirname(__file__), 'web_page_relative.yml')
    # Used for internal methods (do not modify)
    SITE_CONFIG = SiteConfig
web_page_full.yml
# Example 1: Full URL to page
web_page:
  url: http://example.com/
web_page_relative.yml
# Example 2: Relative to a URL declared in SiteConfig
web_page:
  url:
    # Page path, relative to the SiteConfig attribute specified below
    path: path/to/page.html
    # A valid attribute in project SiteConfig to use as the base URL for page
    relative_to: BASE_URL

Without YAML

web_page.py
from selenium.webdriver.common.by import By
from webdriver_test_tools.pageobject import *
from webdriver_test_tools.webdriver import actions, locate

from no_yaml_example.config import SiteConfig


class FullURLExampleWebPage(prototypes.WebPageObject):
    """Non-YAML WebPageObject example (full URL)"""
    # Full URL of the page
    PAGE_URL = 'http://example.com/'


class RelativeURLExampleWebPage(prototypes.WebPageObject):
    """Non-YAML WebPageObject example (relative URL)"""
    # File name of the page relative to a base URL declared in SiteConfig
    PAGE_FILENAME = 'page.html'
    # Full URL of the page
    PAGE_URL = SiteConfig.BASE_URL + PAGE_FILENAME