Generic Component structures¶
Let’s say you have a common structure for your form control elements in all your forms where each field has an <input> element and a <label> bundled inside its own <div>. It would look something like this:
<div class='form-field'>
<label for='first-name'>First Name:</label>
<input id='first-name' name='first-name' />
</div>
<div class='form-field'>
<label for='last-name'>Last Name:</label>
<input id='last-name' name='last-name' />
</div>
This would be tedious to have to define a label and input component for every field in your site. But you could create a generic structure like this that you could reuse:
class Label(PC):
_find_from_parent = True
_locator = (By.TAG_NAME, "label")
class Input(PC):
_find_from_parent = True
_locator = (By.TAG_NAME, "input")
class FormField(PC):
label = Label()
input = Input()
def __set__(self, instance, value):
self._parent = instance
self.driver = self._parent.driver
self.input = value
With that, you could just inherit from FormField to make a new class for each field, and it would even let you assign a value to the input by setting the field component itself (i.e. page.form.my_field = “something”). You could even get a little fancy with the locator to make sure you always find the right field <div>:
class FirstNameField(FormField):
_locator = (
By.XPATH,
(
"//div[contains(concat(' ', @class, ' '), ' form-field ')]"
"[input[@id='first-name']]"
),
)
class LastNameField(FormField):
_locator = (
By.XPATH,
(
"//div[contains(concat(' ', @class, ' '), ' form-field ')]"
"[input[@id='last-name']]"
),
)
That XPATH would locate a <div> that both has a single class of form-field and also contains an <input> with the desired id. It won’t find the <input> itself; it just finds the right <div> that contains it. But that’s intended. This way we know we found the element that contains only that <input> and its <label>, and we can let the FormField class hold all the common logic.