Skip to content

Commit 57c24bb

Browse files
updating comments and read me
1 parent ec57b3f commit 57c24bb

File tree

9 files changed

+81
-12
lines changed

9 files changed

+81
-12
lines changed

Locators/amazon_home_page.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,17 @@
11
from selpy.locator import Locator
2+
# Importing the locator method from selpy
23

34

45
class AmazonHomePageLocator:
6+
# Use the following description for different locators
7+
# CSS - 'css selector'
8+
# XPATH - 'xpath'
9+
# ID - 'id'
10+
# NAME - 'name'
11+
# LINK TEXT - 'link text'
12+
# PARTIAL LINK TEXT - 'partial link text'
13+
# TAG NAME - 'tag name'
14+
# CLASS NAME - 'class name'
515
amazon_logo = Locator("css selector", "div#nav-logo a[aria-label='Amazon']")
616
amazon_search_categories = Locator("css selector", "div.nav-search-scope select.nav-search-dropdown")
717
amazon_search_categories_text = Locator("css selector", "div.nav-search-facade span")
@@ -11,6 +21,7 @@ class AmazonHomePageLocator:
1121
def __init__(self):
1222
print("Locators for Amazon home page")
1323

24+
# Dynamic locators can be declared as a method with variables.
1425
@staticmethod
1526
def amazon_search_category_list(string):
1627
amazon_search_category_list = Locator("xpath", "//select[contains(@class,'nav-search-dropdown')]//option[text("

Locators/amazon_product_page.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,28 @@
22

33

44
class AmazonProductPageLocator:
5+
# Use the following description for different locators
6+
# CSS - 'css selector'
7+
# XPATH - 'xpath'
8+
# ID - 'id'
9+
# NAME - 'name'
10+
# LINK TEXT - 'link text'
11+
# PARTIAL LINK TEXT - 'partial link text'
12+
# TAG NAME - 'tag name'
13+
# CLASS NAME - 'class name'
514
amazon_deliver_to_link = Locator("css selector", "div#contextualIngressPt")
615
amazon_deliver_to_pincode = Locator("css selector", "div.a-column input[aria-label='or enter a pincode']")
716
amazon_deliver_to_pincode_apply = Locator("css selector", "div.a-column input.a-button-input")
817
amazon_product_page_identifier = Locator("css selector", "div#dp")
918
# Product details locator
1019
amazon_product_title = Locator("css selector", "span#productTitle")
1120
amazon_product_byline_info = Locator("css selector", "div#bylineInfo")
21+
amazon_product_show_more_format = Locator("css selector", "span#showMoreFormatsPrompt")
1222
amazon_product_formats = Locator("css selector", "div#formats")
1323
amazon_product_detail_description_iframe = Locator("css selector", "iframe#bookDesc_iframe")
1424
amazon_product_detail_description = Locator("css selector", "div#iframeContent")
15-
amazon_product_offers = Locator("css selector", "div#sopp_feature_div")
1625
amazon_product_description = Locator("css selector", "div#productDescription_feature_div.a-row")
26+
amazon_product_offers = Locator("css selector", "div#sopp_feature_div")
1727
amazon_product_details = Locator("css selector", "div#detail_bullets_id")
1828

1929
def __init__(self):

Locators/amazon_search_result.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22

33

44
class AmazonSearchResultLocator:
5+
# Use the following description for different locators
6+
# CSS - 'css selector'
7+
# XPATH - 'xpath'
8+
# ID - 'id'
9+
# NAME - 'name'
10+
# LINK TEXT - 'link text'
11+
# PARTIAL LINK TEXT - 'partial link text'
12+
# TAG NAME - 'tag name'
13+
# CLASS NAME - 'class name'
514
amazon_search_result_top_header = Locator("css selector", "div.sg-col-inner div.a-section")
615
amazon_search_result_department_see_more = Locator("css selector", "div#departments span.a-expander-prompt")
716
amazon_search_sort_by = Locator("css selector", "span.a-dropdown-container")

Pages/amazon_home_page.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from Locators.amazon_home_page import AmazonHomePageLocator
22

33

4+
# Inherit the locator class inside page class for easier access of locators
45
class AmazonHomePage(AmazonHomePageLocator):
56

67
def __init__(self):

Pages/amazon_product_page.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from Locators.amazon_product_page import AmazonProductPageLocator
22

33

4+
# Inherit the locator class inside page class for easier access of locators
45
class AmazonProductPage(AmazonProductPageLocator):
56

67
def __init__(self):

Pages/amazon_search_result.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from Locators.amazon_search_result import AmazonSearchResultLocator
22

33

4+
# Inherit the locator class inside page class for easier access of locators
45
class AmazonSearchResultPage(AmazonSearchResultLocator):
56

67
def __init__(self):

README.md

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Selpy-Python is a Page Object Model (POM) framework for selenium automation with
44

55
This framework also uses [selpy](https://pypi.org/project/selpy/) custom built pypi module to implement snapshot feature (which is available in jest framework). If there are any change in UI we can directly change this in the test data file during the test run with ease. Manual maintenance of test data can be reduced drastically with this feature.
66

7+
More details of this module can be refered in [selpy](https://pypi.org/project/selpy/) or [repo](https://github.com/nareshnavinash/selpy)
8+
79

810
[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)
911
[![Made with Python](https://img.shields.io/badge/Made%20with-Python-yellow.svg)](https://www.python.org/)
@@ -129,7 +131,19 @@ class AmazonHomePageLocator:
129131
return Locator("xpath", "//select[contains(@class,'nav-search-dropdown')]//option[text()='%s']" % string)
130132
```
131133
132-
3. Ideally each web page should have a new file inside locators folder (with the same name as the web page) and all the locators inside a web page has to be declared inside a page class(Class name also should be same as the web page name).
134+
4. To use the Locator method we need to pass the type of locator and the actual locator element. Type of locator has to be mentioned in the following way to allow `selpy` to process the locator.
135+
```
136+
CSS - 'css selector'
137+
XPATH - 'xpath'
138+
ID - 'id'
139+
NAME - 'name'
140+
LINK TEXT - 'link text'
141+
PARTIAL LINK TEXT - 'partial link text'
142+
TAG NAME - 'tag name'
143+
CLASS NAME - 'class name'
144+
```
145+
146+
5. Ideally each web page should have a new file inside locators folder (with the same name as the web page) and all the locators inside a web page has to be declared inside a page class(Class name also should be same as the web page name).
133147
* If the web page name is `home page` then the locator file name should be `home_page.rb` inside `locators` folder and the class name should be `HomePageLocator` inside `Locators` module.
134148
135149
### Adding page methods to the project
@@ -154,7 +168,7 @@ class AmazonHomePage(AmazonHomePageLocator):
154168
return AmazonHomePageLocator.amazon_logo.is_displayed_with_wait()
155169
```
156170
157-
3. Ideally each web page should have a new page file inside `pages` folder with the class name same as the web page name.
171+
4. Ideally each web page should have a new page file inside `pages` folder with the class name same as the web page name.
158172
* If the web page name is `home page` then the pages file name should be `home_page.rb` inside `pages` folder and the class name should be `HomePage` inside `Pages` module.
159173
160174
### Creating a new test file in the project
@@ -194,7 +208,7 @@ Use `allure.step("step name")` to have a detailed reporting in allure.
194208
195209
3. Append the method name for the test as `test_` only then it will be taken as a test case. This has been configured in ```pytest.ini``` as,
196210
197-
```python
211+
```ini
198212
markers =
199213
sanity: sanity tests marker
200214
regression: regression tests marker
@@ -263,6 +277,14 @@ This ensures that this data has been set before pytest is being invoked only onc
263277
assert (AmazonHomePage.is_home_page_displayed() is True), "Amazon home page is not displayed"
264278
```
265279
280+
### Data sets:
281+
282+
In order to have distinguished set of data I have used three types of data.
283+
284+
**Global** - Global configuration for the whole project. Here mode of run, browsers to use, browser configurations etc., are specified.
285+
**Test Data** - This is to store the module level data. Ideally for each test file we need to have a test data file, but that depends on the requirement.
286+
**Dynamic Data** - This is to store the dynamic data. Files in this folder are supposed to change when we run with `snap=1 pytest`. This is separated from the other data files so that other static files are not disturbed during the run.
287+
266288
## Detailing snap Mode:
267289
268290
Snap mode is created to reduce the burden in maintaining the test data. While we test an application with data heavy validations, there is a high chance that the data in the application may change over the course of time.

Tests/amazon.py

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,28 +8,30 @@
88
from selpy.variable import Var
99

1010

11+
# Feature name and severity to have better reporting in the allure.
1112
@allure.feature("Amazon - Book search with text 'AI', department as 'Arts, Film & Photography', sub-department as "
1213
"'Cinema & Broadcast', maximum 'Avg Customer Review', sort result by 'Publication Date'"
1314
"filter as 1000 to 1500 rupees, the book available in paperback, Kindle ebooks, and Hardcover"
1415
"select the first result and verify")
1516
@allure.severity('Critical')
16-
@pytest.mark.regression
17-
@pytest.mark.ui
17+
@pytest.mark.regression # Custom pytest marker to run the test cases with ease on demand
18+
@pytest.mark.ui # Custom pytest marker to run the test cases with ease on demand
1819
def test_amazon_book_search_001():
1920
with allure.step("Initialize the UI dynamic data"):
2021
ui_dynamic_data = {}
2122
with allure.step("Set the test data file needed for this test run"):
22-
static_variable = Var("amazon.yml", "static")
23+
static_variable = Var("amazon.yml", "static") # static variables will change for each test case/ test module
24+
# Dynamic variable is to verify the dynamic data in UI, if needed we can store the UI values to this file
2325
dynamic_variable = Var("amazon_book_search_result_dynamic.yml", "dynamic")
2426

2527
with allure.step("Initialize the driver and navigate to the url"):
26-
driver = Driver()
28+
driver = Driver() # Initialize the driver. Driver configurations will be taken from the global_data.yml file
2729
driver.get(static_variable.static_value_for("url"))
2830
assert (AmazonHomePage.is_home_page_displayed() is True), "Amazon home page is not displayed"
2931

3032
with allure.step("Select the categories as books in the search dropdown"):
3133
AmazonHomePage.select_category_drop_down(static_variable.static_value_for("category"))
32-
assert (AmazonHomePage.get_selected_category() == static_variable.static_value_for("category")),\
34+
assert (AmazonHomePage.get_selected_category() == static_variable.static_value_for("category")), \
3335
"Category is not selected properly"
3436

3537
with allure.step("Search for the text which is needed in this"):
@@ -40,6 +42,7 @@ def test_amazon_book_search_001():
4042
"displayed in the result page"
4143

4244
with allure.step("Apply the filter categories in the search results page"):
45+
# applying and verifying the filters applied
4346
AmazonSearchResultPage.select_department(static_variable.static_value_for("search_department"))
4447
AmazonSearchResultPage.select_sub_department(static_variable.static_value_for("search_sub_department"))
4548
list_of_checkbox = static_variable.static_value_for("book_format")
@@ -76,6 +79,7 @@ def test_amazon_book_search_001():
7679

7780
with allure.step("Set the delivery pincode in the product page"):
7881
AmazonProductPage.set_delivery_pincode(static_variable.static_value_for("delivery_pincode"))
82+
# To handle the delay in the UI.
7983
for i in range(0, 10):
8084
time.sleep(1)
8185
res = AmazonProductPage.get_delivery_pincode().find(
@@ -86,22 +90,28 @@ def test_amazon_book_search_001():
8690
assert (res != -1), "Delivery Pin code is not set properly"
8791

8892
with allure.step("Store the UI details in the dynamic dictionary"):
93+
# Now fetch the data which you want to store in the snap way and save it in the ui_dynamic_data dictionary
94+
# with the name to it. After saving this to the dictionary/hash, you can compare with the stored data.
8995
AmazonProductPage.amazon_product_title.scroll_to_locator()
9096
ui_dynamic_data["amazon_product_title"] = AmazonProductPage.amazon_product_title.texts_as_string()
9197
AmazonProductPage.amazon_product_byline_info.scroll_to_locator()
9298
ui_dynamic_data["amazon_product_byline_info"] = AmazonProductPage.amazon_product_byline_info.texts_as_string()
99+
AmazonProductPage.amazon_product_show_more_format.click()
93100
AmazonProductPage.amazon_product_formats.scroll_to_locator()
94101
ui_dynamic_data["amazon_product_formats"] = AmazonProductPage.amazon_product_formats.texts_as_string()
95102
driver.switch_to_frame(AmazonProductPage.amazon_product_detail_description_iframe.get_element())
96-
ui_dynamic_data["amazon_product_detail_description"] = AmazonProductPage.\
103+
ui_dynamic_data["amazon_product_detail_description"] = AmazonProductPage. \
97104
amazon_product_detail_description.texts_as_string()
98105
driver.switch_to_default_content()
99-
AmazonProductPage.amazon_product_offers.scroll_to_locator()
100-
ui_dynamic_data["amazon_product_offers"] = AmazonProductPage.amazon_product_offers.texts_as_string()
101106
AmazonProductPage.amazon_product_description.scroll_to_locator()
102107
ui_dynamic_data["amazon_product_description"] = AmazonProductPage.amazon_product_description.texts_as_string()
108+
# Intentionally adding following two details which are vulnerable to change dynamically.
109+
# While running `snap=1 pytest` first time it will fail and next time it should pass
110+
AmazonProductPage.amazon_product_offers.scroll_to_locator()
111+
ui_dynamic_data["amazon_product_offers"] = AmazonProductPage.amazon_product_offers.texts_as_string()
103112
AmazonProductPage.amazon_product_details.scroll_to_locator()
104113
ui_dynamic_data["amazon_product_details"] = AmazonProductPage.amazon_product_details.texts_as_string()
105114

106115
with allure.step("Compare the dynamic value from UI with the stored file"):
116+
# Now compare the UI value with the stored value. This comparison is taken care in `selpy` module.
107117
dynamic_variable.compare(ui_dynamic_data)

Tests/conftest.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ def before_each():
1111
print('*-* Before each INITIALIZATION')
1212
try:
1313
yield
14+
# After each test case taking screen shots form the available drivers
1415
for driver in Store.drivers:
1516
root_dir = os.path.dirname(os.path.abspath(__file__)).replace("/Tests", "")
1617
name = 'img%s.png' % datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
@@ -26,6 +27,7 @@ def before_each():
2627
def before_module():
2728
print('*-* Before module INITIALIZATION')
2829
yield
30+
# after each module ensuring the browsers are closed
2931
for driver in Store.drivers:
3032
driver.quit()
3133
print('*-* After module END')
@@ -38,11 +40,13 @@ def pytest_configure(config):
3840
file after command line options have been parsed.
3941
"""
4042
print("*-* pytest_configure")
43+
# Configuring the selpy with data path location
4144
Store.global_data_path = os.path.dirname(
4245
os.path.abspath(__file__)).replace("/Tests", "") + '/Data/GlobalData/global_data.yml'
4346
Store.static_data_path = os.path.dirname(os.path.abspath(__file__)).replace("/Tests", "") + '/Data/TestData/'
4447
Store.dynamic_data_path = os.path.dirname(os.path.abspath(__file__)).replace("/Tests", "") + '/Data/DynamicData/'
4548
root_dir = os.path.dirname(os.path.abspath(__file__)).replace("/Tests", "")
49+
# Clearing the old screenshots from the location.
4650
config_path = root_dir + '/reports/screenshots/*.png'
4751
for CleanUp in glob.glob(config_path):
4852
print(CleanUp)

0 commit comments

Comments
 (0)