Creating a Page Model¶
We’ve been working on a test to open https:/www.google.com and to query for the word “example”. For the querying part, we need to identify the search input field and the button to submit the search form.
"query 'example'": actions: - set $".gLFyf.gsfi" to "example" - click $".FPdoLc.VlcLAe input[name=btnK]" assertions: - $page.title is "example - Google Search"
The test step works for now so that’s fine, right?
Well, those selectors are a bit messy and that’s not so fine. The selectors are hard to read (
doesn’t really shout “search input”) and may well need to be updated in many places when the page being tested changes.
Let’s create a page model to store all of these page properties. We can refer to the page model in our tests, making the tests clearer to read. And we can make sure that if something needs updating it only needs to be changed in one place.
Creating and Using a Page Model¶
A page model is a YAML object with
elements properties. The
url property holds the page URL. The
elements section maps convenience names to ways of identifying elements.
# examples/page/google.com.yml url: "https://www.google.com" elements: search_input: $".gLFyf.gsfi" search_button: $".FPdoLc.VlcLAe input[name=btnK]"
For the time being those selectors are a little hard on the eyes but at least we need to only update them in one place.
# examples/step/google-assert-open-literal.yml assertions: - $page.url is "https://www.google.com" - $page.title is "Google"
# examples/test/google-import-assert-open-with-page-model.yml config: browser: chrome url: google_com.url imports: steps: google_assert_open: "../step/google-assert-open-literal.yml" pages: google_com: "../page/google.com.yml" "verify Google is open": use: google_assert_open "query 'example'": actions: - set $google_com.elements.search_input to "example" - click $google_com.elements.search_button assertions: - $page.title is "example - Google Search"
We’ve added a
pages section to the
imports section to reference the page model we created. We’ve chosen an import
google_com) and provided an import path (
Within our assertions, we use the name of the page import to reference the elements that the page model defines.
click $google_com.elements.search_button is a lot easier on the brain than
click $".FPdoLc.VlcLAe input[name=btnK]"?
Scoping Elements Within a Page Model¶
Both the search input field and the search button are within a form. And both elements have some properties other than class names that are probably less prone to change.
We can make our page model more robust.
# examples/page/google.com-selector-scoped.yml url: "https://www.google.com" elements: # finds "[name=q]" within the context of "form[action='/search']" # using CSS syntax search_input: $"form[action='/search'] input[name=q]" # finds "[type=submit]" within the context of "form[action='/search']" # using CSS syntax search_button: $"form[action='/search'] input[type=submit]"
That makes my brain hurt just a little bit less. But we’re still repeating the
form[action='/search'] part of each
of the selectors. We can do better!
We have given the
$"form[action=/search]" identifier the name
search_form. We can reference this element via the
name we chose by prefixing the name with a dollar sign. Within our page model,
$search_form is the same as saying
Combine this with the
>> operator for a parent-child relationship and everything is much easier to read.
# examples/page/google.com-element-scoped-reference.yml url: "https://www.google.com" elements: search_form: $"form[action=/search]" # finds "[name=q]" within the context of search_form # using basil parent-child syntax search_input: $search_form >> $"[name=q]" # finds "[type=submit]" within the context of search_form # using basil parent-child syntax search_button: $search_form >> $"[type=submit]"