QA/Execution/Web Testing/Docs/Automation/StyleGuide: Difference between revisions

Jump to navigation Jump to search
no edit summary
No edit summary
Line 45: Line 45:
     Clicks the login link and then waits for the home page to load."""
     Clicks the login link and then waits for the home page to load."""
</pre>
</pre>
** Indenting should be a soft tab (4 spaces) as common with in Python. Do not mix tabs and spaces!
* Indenting should be a soft tab (4 spaces) as common with in Python. Do not mix tabs and spaces!
** There should be no whitespace at the end of the file (as per PEP8)
* There should be no whitespace at the end of the file (as per PEP8)
** Comments should be on the line above. Remember to update comments when changing code so that code matches the comments.
* Comments should be on the line above. Remember to update comments when changing code so that code matches the comments.
** Class names should be in Pascal style as this is Python idiomatic.
* Class names should be in Pascal style as this is Python idiomatic.
<pre class="brush:py;toolbar:false;">
<pre class="brush:py;toolbar:false;">
     # Good
     # Good
Line 68: Line 68:


== Locators ==
== Locators ==
** Locator variables should be prefixed with _ to show that it is "[http://docs.python.org/tutorial/classes.html#private-variables private]".
* Locator variables should be prefixed with _ 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.
* Variables should be descriptive of the area and not clash with any properties.
** Suffix of _locator.
* Suffix of _locator.
** Accessing Locators should be done through a property method as this keeps the locator as readonly.
* Accessing locators should be done through a property or method as this keeps the locator as readonly.
<pre class="brush:py;toolbar:false;">
<pre class="brush:py;toolbar:false;">
     @property
     @property
     def search_box(self):
     def search_term(self):
         return self.search_box_locator
         return self.selenium.find_element(*self._search_box_locator).value
</pre>
* This approach can also be used with get_* calls with Selenium making it more idiomatic for the call.
<pre class="brush:py;toolbar:false;">
    @property
    def page_title(self):
        return self.selenium.get_title()
</pre>
</pre>
* We should use locators in the following order of preference (there will be exceptions):
* We should use locators in the following order of preference (there will be exceptions):
** ID
** ID
** Name
** Name
** CSS
** Class name
** CSS selector
** XPath
** XPath
* Locators should include the strategy instead of using implied strategies.
* For Selenium RC, locators should include the strategy instead of using implied strategies.
<pre class="brush:py;toolbar:false;">
<pre class="brush:py;toolbar:false;">
     # Good
     # Good
Line 104: Line 99:
     _my_locator = "css=#content>p>a"
     _my_locator = "css=#content>p>a"
</pre>
</pre>
 
* With WebDriver, use a Python tuple to define locators:
* With Webdriver, use a Python tuple:
<pre class="brush:py;toolbar:false;">
<pre class="brush:py;toolbar:false;">
     # Good
     # Good
Line 120: Line 114:
     def report_length(length)
     def report_length(length)
</pre>
</pre>


== Advanced: Page Regions ==
== Advanced: Page Regions ==
In some circumstances, for example where a header/navigation is common across the website, we will use a page region. The page region is a child class of the base Page Object, which is inherited by all page objects. This means that the navigation can be reached from any page object and herein lies the DRY!
In some circumstances, for example where a header/navigation is common across the website, we will use a page region. The page region is a child class of the base Page object, which is inherited by all page objects. This means that the navigation can be reached from any page object and herein lies the DRY!


A brief example:
A brief example:
Line 141: Line 134:
</pre>
</pre>


Referring to this page region with a property makes it very readable and concise from within the test. Clicking home during a test would be performed like this:
Referring to this page region with a property makes it very readable and concise from within the test. Clicking login during a test would be performed like this:
<pre class="brush:py;toolbar:false;">
<pre class="brush:py;toolbar:false;">
     page_obj.header.click_login()
     my_page.header.click_login()
</pre>
</pre>


Line 150: Line 143:
= Tests =
= Tests =
* Module names should be called test_ and then behavioral areas.
* Module names should be called test_ and then behavioral areas.
     test_search_positive.py
     test_search.py
* Test method signature should include mozwebqa to use pytest-mozwebqa plugin.
* Test method signature should include mozwebqa to use pytest-mozwebqa plugin.
<pre class="brush:py;toolbar:false;">
<pre class="brush:py;toolbar:false;">
Line 166: Line 159:


= Size of patches =
= Size of patches =
To make sure that we can review your patch as quickly and efficiently as possibly we would like patches to have 1 test in them and the necessary changes to the Page Objects. This also limits the chances of merge conflicts later.
To make sure that we can review your patch as quickly and efficiently as possibly we would like patches to have a single test in them and the necessary changes to the page objects. This also limits the chances of merge conflicts later.


== Using new and old standards together ==
== Using new and old standards together ==
Confirmed users
2,197

edits

Navigation menu