Confirmed users
211
edits
(→Use testvars.json: testvars) |
(Moved away the external consumer parts and fixed nits) |
||
(26 intermediate revisions by 2 users not shown) | |||
Line 70: | Line 70: | ||
# Bad | # Bad | ||
class test_this_site: | class test_this_site: | ||
</source> | |||
== Locators == | |||
* Locator variables should be prefixed with <code>_</code> to show that it is [http://docs.python.org/tutorial/classes.html#private-variables private]. | |||
* Variables should be descriptive of the area and not clash with any properties. | |||
* Should have a suffix of <code>_locator</code>. | |||
* Accessing locators should be done through a property or method as this keeps the locator as read-only. | |||
<source lang="python"> | |||
@property | |||
def search_term(self): | |||
return self.marionette.find_element(*self._search_box_locator).value | |||
</source> | |||
* We should use locators in the following order of preference (there will be exceptions): | |||
** ID | |||
** Name | |||
** Class name | |||
** CSS selector | |||
** XPath | |||
* CSS locators should use whitespace for readability when using direct descendants. | |||
<source lang="python"> | |||
# Good | |||
_my_locator = "css=#content > p > a" | |||
# Bad | |||
_my_locator = "css=#content>p>a" | |||
</source> | |||
* Use Python tuples to define locators: | |||
<source lang="python"> | |||
# Good | |||
_my_locator = (By.ID, "content") | |||
</source> | </source> | ||
Line 85: | Line 119: | ||
* Actions should wait for the appropriate action to complete. This could be an implicit or explicit wait. For example, clicking a login button might explicitly wait for a username field to be visible. | * Actions should wait for the appropriate action to complete. This could be an implicit or explicit wait. For example, clicking a login button might explicitly wait for a username field to be visible. | ||
== | == Using High-Level Methods == | ||
* A test script should remain a short entry point which leads to more details (like the main() function of a program). Don't detail every single tap and wait, in the test. Use methods that reflect a user's intent rather than a sequence of small steps the user has to do. The details of how to fulfill that intent will be in the page classes. | |||
<source lang="python"> | <source lang="python"> | ||
# Good | |||
messages.send_an_sms_to_yourself() | |||
# Bad | |||
messages.open_sms_app() | |||
messages.create_new_sms(receiver) | |||
messages.type_content(content) | |||
messages.send() | |||
</source> | |||
== Variable Naming == | |||
* Name your variables with units. | |||
<source lang="python"> | |||
# Good | |||
timeout_in_seconds, width_in_pixels | |||
# Bad | |||
timeout, width | |||
</source> | </source> | ||
* Don't shorten variable names. | |||
<source lang="python"> | <source lang="python"> | ||
self. | # Good | ||
self.time_out_error_time = 1000 | |||
self. | |||
# Bad | |||
self.t_out_err_tim = 1000 | |||
</source> | </source> | ||
== | == Making Tests Locale Independent == | ||
It is recommended to make the test scripts (and especially the helper methods) locale independent, because this enables us to test devices in RTL locale. There are still some sections in gaiatest where it checks for the displayed English text, but unless one cannot avoid it, data-l10n-id attribute should be checked in place of any raw text comparison. | |||
= | <source lang="python"> | ||
= | # below method will not work in a non-English locale, | ||
# should only be used when there is no appropriate tag for the Open App button | |||
button = self.root_element.find_element(*self._install_button_locator) | |||
* | Wait(self.marionette).until(lambda m: button.text == 'Open app') | ||
button.tap() | |||
# below code will tap 'Send Mozilla Feedback' button in any locale | |||
_send_feedback_locator = (By.CSS_SELECTOR, '[data-l10n-id="sendMozillaFeedback"]') | |||
element = Wait(self.marionette).until( | |||
= | expected.element_present(*self._send_feedback_locator)) | ||
Wait(self.marionette).until(expected.element_displayed(element)) | |||
element.tap() | |||
</source> | |||
The rules of thumb are: | |||
* We can check for the raw text in order to verify the user input (i.e., a phone number entered in the dialer app) | |||
* | * We check the data-l10n-id for any string that comes from Gaia only (i.e., an error message) | ||
* | |||