├── .gitignore ├── README.md ├── core ├── __init__.py ├── common │ ├── __init__.py │ ├── constants.py │ └── init.py ├── conf │ ├── __init__.py │ └── environments │ │ ├── __init__.py │ │ ├── base.py │ │ ├── config.py │ │ └── default.py └── utils │ ├── __init__.py │ ├── fileutils.py │ └── utils.py ├── entrypoint.sh ├── pages ├── __init__.py ├── base_page.py ├── locators.py ├── login_page.py └── my_account_page.py ├── project.py ├── requirements.txt ├── resources ├── chromedriver_linux └── chromedriver_mac ├── run.sh ├── screenshots └── .gitkeep ├── scripts ├── send_message_to_slack.py └── test_ping.py └── tests ├── LoginTests.py └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | MANIFEST 27 | 28 | # PyInstaller 29 | # Usually these files are written by a python script from a template 30 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 31 | *.manifest 32 | *.spec 33 | 34 | # Installer logs 35 | pip-log.txt 36 | pip-delete-this-directory.txt 37 | 38 | # Unit test / coverage reports 39 | htmlcov/ 40 | .tox/ 41 | .coverage 42 | .coverage.* 43 | .cache 44 | nosetests.xml 45 | coverage.xml 46 | *.cover 47 | .hypothesis/ 48 | .pytest_cache/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | db.sqlite3 58 | 59 | # Flask stuff: 60 | instance/ 61 | .webassets-cache 62 | 63 | # Scrapy stuff: 64 | .scrapy 65 | 66 | # Sphinx documentation 67 | docs/_build/ 68 | 69 | # PyBuilder 70 | target/ 71 | 72 | # Jupyter Notebook 73 | .ipynb_checkpoints 74 | 75 | # pyenv 76 | .python-version 77 | 78 | # celery beat schedule file 79 | celerybeat-schedule 80 | 81 | # SageMath parsed files 82 | *.sage.py 83 | 84 | # Environments 85 | .env 86 | .venv 87 | env/ 88 | selenium-pom-python-venv/ 89 | ENV/ 90 | env.bak/ 91 | venv.bak/ 92 | 93 | # Spyder project settings 94 | .spyderproject 95 | .spyproject 96 | 97 | # Rope project settings 98 | .ropeproject 99 | 100 | # mkdocs documentation 101 | /site 102 | 103 | # mypy 104 | .mypy_cache/ 105 | 106 | # custom entries 107 | /.idea/* 108 | /docker-report/* 109 | *.pyc 110 | *.png 111 | *.txt 112 | /report/* 113 | /reports/* 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # selenium-python-page-object-model 2 | This repository provides some working boilerplate code for building automated test suites on top of the lemoncheesecake test framework for UI-based testing with Selenium. 3 | 4 | ### Below are some of the features of this test framework: 5 | - Uses [lemoncheesecake](http://lemoncheesecake.io/) as a core functional test framework 6 | - Provides awesome and highly readable HTML reports with custom log messages and screenshot hyperlinks 7 | - Provides pre-configured Slack reporting which posts the report link(s) at suite level to a specific Slack channel; requires only `SLACK_AUTH_TOKEN` and channel name 8 | - Provides a way to define different base URL based test environment configurations 9 | - Provides a way to run one or more of your test suites in a single run serially 10 | 11 | ### Below is the explanation of the key packages/files/directories/modules in the code: 12 | - The `core` package contains various other directories like `common`, `conf`, `utils`, etc. 13 | -- The `common` package contains files like `constants.py` (used to define various constants), `init.py` (used to initialise all the base URLs under test using a `Config` object), etc. 14 | -- The `conf` package contains an `environment` package, which lets you define various test environments (base URLs for the most part). Note that the `config.py` uses Python's `importlib` module to define a `config` object using the `TEST_ENV` environment variable set while running the tests. 15 | -- The `utilities` package defines and lets you define various utility functions. 16 | - As per the page object model, the `pages` package defines various page classes with element locator definitions and functions defining operations on these elements. 17 | - The `scripts` directory contains various ad-hoc scripts, e.g. `test_ping.py` (used to check if one or more URLs pertaining to the application under test are up). 18 | - The `tests` package contains the actual UI-based tests, which use the page class objects for instantiating the webdriver and running tests. 19 | - The `entrypoint.sh` script does reporting related tasks and uses another `run.sh` script which is run per test suite. You must edit various variables like `SLACK_AUTH_TOKEN`, `SLACK_CHANNEL`, `ALL_TEST_SUITES` as per your needs. 20 | - In the `run.sh` script, your must edit various variables like `SERVER_URL`, `WWW_REPORTS_DIR`, `VENV_NAME` as per your needs. 21 | 22 | ### Getting a Slack API access token 23 | You can obtain a Slack API access token for your workspace by following the steps below: 24 | 1. In your Slack Workspace, click the Apps section. 25 | 2. In the Apps page, click Manage apps. 26 | 3. The App Directory page shows up, in this page, make a search using the keyword “bots” in the top text box Search App Directory. 27 | 4. Click Bots app > Add configuration. 28 | 5. Set Username and click Add bot integration. 29 | 6. You’ll get the API access token in Integration Settings. 30 | 31 | ### Examples 32 | This repository contains below examples to run some simple UI-based tests from http://automationpractice.com in the test suite file `tests/LoginTests.py`. The required URLs can be found in the `core/conf/environments/default.py` file. 33 | 1. `verify_login_failure` - Launches the sign-in page of the website, enters the incorrect username and password and checks whether the login fails and an error message is shown subsequently. 34 | 2. `verify_login_success` - Enters the correct username and password and checks whether the login succeeds and the user is taken to the 'My Account' landing page. 35 | 36 | ### Setting up and running tests 37 | 1. Once you have cloned this repository, you should create a virtual environment using the `virtualenv` tool in the root directory of the project. Note that the name of this virtual environment should be the same as that in the `run.sh` and `.gitignore` files. 38 | `$ virtualenv venv_name` 39 | 2. Activate the virtual environment with `$ source venv_name/bin/activate` 40 | 3. Install all the project dependencies with `$ pip install -r requirements.txt` 41 | 4. Set `PYTHONPATH` to the project's root directory. 42 | 5. Set `TEST_ENV` to a suitable configuration defined in any of the configuration modules in the `environment` package. Not setting this will make the test framework use the `default` configuration defined in the `environment` package since we have defined this under `config.py`. 43 | 6. Run tests with `entrypoint.sh`. Providing no arguments to this script will run all the test suites defined in the `ALL_TEST_SUITES` shell variable in the given order. In order to run one or more test suites in a custom order, you can use `entrypoint.sh my_test_suite_1 my_test_suite_2` (note no `.py` extension in the test suite names). 44 | 7. If the `SLACK_AUTH_TOKEN` and `SLACK_CHANNEL` provided in `entrypoint.sh` are valid, you should see a message in your Slack channel with test suite name, number of passed/failed tests and report link. 45 | 46 | That's all folks. Happy testing! 47 | -------------------------------------------------------------------------------- /core/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/core/__init__.py -------------------------------------------------------------------------------- /core/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/core/common/__init__.py -------------------------------------------------------------------------------- /core/common/constants.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | 4 | 5 | class Global(object): 6 | PROJECT_ROOT_DIR = os.path.dirname(os.path.dirname(os.path.dirname(__file__))) 7 | CHROME_DRIVER_MAC_DIR = os.path.join(PROJECT_ROOT_DIR, os.path.join("resources", "chromedriver_mac")) 8 | CHROME_DRIVER_LINUX_DIR = os.path.join(PROJECT_ROOT_DIR, os.path.join("resources", "chromedriver_linux")) 9 | PLATFORM_NAME = platform.system() 10 | CHROME_DRIVER = CHROME_DRIVER_MAC_DIR if PLATFORM_NAME == "Darwin" else CHROME_DRIVER_LINUX_DIR 11 | SCREENSHOTS_DIR = os.path.join(PROJECT_ROOT_DIR, os.path.join("screenshots")) 12 | -------------------------------------------------------------------------------- /core/common/init.py: -------------------------------------------------------------------------------- 1 | from core.conf.environments.config import get_config_object 2 | 3 | 4 | class Base: 5 | ENVIRONMENT = None 6 | USER_BASE_URL = None 7 | 8 | 9 | def init_session(): 10 | config = get_config_object() 11 | print "Test environment: {}".format(config.ENVIRONMENT) 12 | print "URL under test: {}".format(config.AUTOMATION_PRACTICE_URL) 13 | Base.ENVIRONMENT = config.ENVIRONMENT 14 | Base.USER_BASE_URL = config.AUTOMATION_PRACTICE_URL 15 | -------------------------------------------------------------------------------- /core/conf/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/core/conf/__init__.py -------------------------------------------------------------------------------- /core/conf/environments/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/core/conf/environments/__init__.py -------------------------------------------------------------------------------- /core/conf/environments/base.py: -------------------------------------------------------------------------------- 1 | class BaseConfig(object): 2 | pass 3 | -------------------------------------------------------------------------------- /core/conf/environments/config.py: -------------------------------------------------------------------------------- 1 | import importlib 2 | import os 3 | 4 | 5 | def get_config_object(): 6 | environment = os.environ.get('TEST_ENV', 'default') 7 | module_name = 'core.conf.environments.{}'.format(environment) 8 | config_module = importlib.import_module(module_name) 9 | class_ = getattr(config_module, 'Config') 10 | return class_() 11 | 12 | 13 | project_dir = os.path.dirname(__file__) 14 | -------------------------------------------------------------------------------- /core/conf/environments/default.py: -------------------------------------------------------------------------------- 1 | from core.conf.environments.base import BaseConfig 2 | 3 | 4 | class Config(BaseConfig): 5 | ENVIRONMENT = "default" 6 | AUTOMATION_PRACTICE_URL = "http://automationpractice.com/index.php?controller=authentication&back=my-account" 7 | 8 | 9 | class Prod(BaseConfig): 10 | 11 | def __init__(self): 12 | print "" 13 | -------------------------------------------------------------------------------- /core/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/core/utils/__init__.py -------------------------------------------------------------------------------- /core/utils/fileutils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import lemoncheesecake.api as lcc 4 | 5 | from core.common.constants import Global 6 | 7 | 8 | def capture_screenshot(driver, target_path=os.path.join(Global.SCREENSHOTS_DIR, "screenshot.png")): 9 | driver.save_screenshot(target_path) 10 | lcc.save_attachment_file(filename=target_path, description="Click here to view the screenshot") 11 | 12 | 13 | def delete_file(file_path): 14 | try: 15 | if os.path.exists(file_path): 16 | print("Deleting file {}".format(file_path)) 17 | os.remove(file_path) 18 | else: 19 | print("File {} does not exist for deletion.".format(file_path)) 20 | except OSError: 21 | print("Error deleting file {}!".format(file_path)) 22 | -------------------------------------------------------------------------------- /core/utils/utils.py: -------------------------------------------------------------------------------- 1 | import math 2 | import random 3 | import time 4 | from datetime import date 5 | from datetime import datetime 6 | from string import ascii_uppercase 7 | 8 | 9 | def generate_number_between(num1, num2): 10 | random_num = random.randrange(num1, num2) 11 | print("Random number: {}".format(random_num)) 12 | return random_num 13 | 14 | 15 | def generate_float_number_between(num1, num2): 16 | random_float_num = random.uniform(num1, num2) 17 | print("Random number: {}".format(random_float_num)) 18 | return random_float_num 19 | 20 | 21 | def floor_two_decimals(num): 22 | floored_value = math.floor(num * 100) / 100.0 23 | return floored_value 24 | 25 | 26 | def generate_number_of_length_n(n): 27 | range_start = 10 ** (n - 1) 28 | range_end = (10 ** n) - 1 29 | random_number = random.randint(range_start, range_end) 30 | print("Generated random number of length {}: {}".format(n, random_number)) 31 | return random_number 32 | 33 | 34 | def pick_random_list_item(my_list): 35 | random_index = random.randint(0, len(my_list) - 1) 36 | random_element = my_list[random_index] 37 | print("List element: {}".format(random_element)) 38 | return random_element 39 | 40 | 41 | def pick_random_dict_item(my_dict): 42 | random_element = random.choice(my_dict.keys()) 43 | print("Dict element: {}".format(random_element)) 44 | return random_element 45 | 46 | 47 | def generate_random_string(): 48 | random_string = ''.join(random.choice(ascii_uppercase)) 49 | print("Generated random string: {}".format(random_string)) 50 | return random_string 51 | 52 | 53 | def generate_random_string_of_length_n(n): 54 | random_string = ''.join(random.choice(ascii_uppercase) for i in range(n)) 55 | print("Generated random string of length {}: {}".format(n, random_string)) 56 | return random_string 57 | 58 | 59 | def generate_string_ending_with_number(string_starts_with): 60 | string = "{}{}".format(string_starts_with, random.randint(0, 100)) 61 | print("Generated string {} starting with {}".format(string, string_starts_with)) 62 | return string 63 | 64 | 65 | def generate_now_timestamp_rc3339(): 66 | return datetime.now().isoformat('T') 67 | 68 | 69 | def get_current_date_and_time(): 70 | return time.strftime("%Y-%m-%d %H:%M:%S") 71 | 72 | 73 | def get_today_date(): 74 | return str(date.today()) 75 | 76 | 77 | def get_current_time(): 78 | return datetime.now().strftime("%H:%M:%S") 79 | 80 | 81 | def get_utc_ms_time(value): 82 | try: 83 | date_obj = value 84 | if isinstance(value, str): 85 | date_obj = datetime.strptime(value, "%Y-%m-%d %H:%M:%S") 86 | return int(time.mktime(date_obj.timetuple())) * 1000 87 | except: 88 | return '' 89 | -------------------------------------------------------------------------------- /entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | find ./resources -name "*.json" -type f -delete 3 | find ./resources -name "*.html" -type f -delete 4 | export SLACK_AUTH_TOKEN="your_slack_token" 5 | export SLACK_CHANNEL="#yourSlackChannel" 6 | TEST_SKIP_MESSAGE="*[$TEST_ENV] One or more services required for the tests are unavailable, skipping tests.* :sleeping:" 7 | TEST_FAIL_MESSAGE="*[$TEST_ENV] One or more tests from one or more suites have failed.* :cry:" 8 | TEST_PASS_MESSAGE="*[$TEST_ENV] All tests from all suites have passed.* :dancing_panda:" 9 | if [ $# -eq 0 ]; then 10 | declare -a ALL_TEST_SUITES=("LoginTests") 11 | else 12 | declare -a ALL_TEST_SUITES=($@) 13 | fi 14 | ALL_TESTS_PASSED=1 15 | if python scripts/test_ping.py; then 16 | for i in "${ALL_TEST_SUITES[@]}" 17 | do 18 | source ./run.sh ${i} 19 | if [ ${CURRENT_SUITE_EXECUTION_STATUS} == 0 ]; then 20 | echo "All tests from test suite ${i} passed." 21 | else 22 | ALL_TESTS_PASSED=0 23 | fi 24 | done 25 | if [ ${ALL_TESTS_PASSED} -eq 0 ]; then 26 | python scripts/send_message_to_slack.py -t "${SLACK_AUTH_TOKEN}" -c "${SLACK_CHANNEL}" -m "${TEST_FAIL_MESSAGE}" 27 | else 28 | python scripts/send_message_to_slack.py -t "${SLACK_AUTH_TOKEN}" -c "${SLACK_CHANNEL}" -m "${TEST_PASS_MESSAGE}" 29 | fi 30 | else 31 | echo ${TEST_SKIP_MESSAGE} 32 | python scripts/send_message_to_slack.py -t "${SLACK_AUTH_TOKEN}" -c "${SLACK_CHANNEL}" -m "${TEST_SKIP_MESSAGE}" 33 | fi 34 | -------------------------------------------------------------------------------- /pages/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/pages/__init__.py -------------------------------------------------------------------------------- /pages/base_page.py: -------------------------------------------------------------------------------- 1 | class BasePage(object): 2 | 3 | def __init__(self, driver): 4 | self.driver = driver 5 | self.driver.implicitly_wait(5) 6 | -------------------------------------------------------------------------------- /pages/locators.py: -------------------------------------------------------------------------------- 1 | EMAIL_ID = "email" 2 | PASSWORD_ID = "passwd" 3 | SIGN_IN_BTN_ID = "SubmitLogin" 4 | LOGIN_FAILURE_MESSAGE_XPATH = "//li[contains(text(),'Authentication failed.')]" 5 | MY_ACCOUNT_TEXT = "//span[text()='My account']" 6 | -------------------------------------------------------------------------------- /pages/login_page.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.by import By 2 | 3 | from pages.base_page import BasePage 4 | from pages.locators import * 5 | 6 | from core.conf.environments.config import get_config_object 7 | 8 | 9 | class LoginPage(BasePage): 10 | def __init__(self, driver): 11 | self.driver = driver 12 | config = get_config_object() 13 | self.driver.get(config.AUTOMATION_PRACTICE_URL) 14 | 15 | email = (By.ID, EMAIL_ID) 16 | password = (By.ID, PASSWORD_ID) 17 | sign_in_btn = (By.ID, SIGN_IN_BTN_ID) 18 | failure_message = (By.XPATH, LOGIN_FAILURE_MESSAGE_XPATH) 19 | 20 | def set_email(self, email): 21 | email_element = self.driver.find_element(*LoginPage.email) 22 | email_element.clear() 23 | email_element.send_keys(email) 24 | 25 | def set_password(self, password): 26 | password_element = self.driver.find_element(*LoginPage.password) 27 | password_element.clear() 28 | password_element.send_keys(password) 29 | 30 | def click_sign_in_btn(self): 31 | sign_in_element = self.driver.find_element(*LoginPage.sign_in_btn) 32 | sign_in_element.click() 33 | 34 | def is_failure_message_displayed(self): 35 | failure_message_element = self.driver.find_element(*LoginPage.failure_message) 36 | return failure_message_element.is_displayed() 37 | 38 | def login(self, email, password): 39 | self.set_email(email) 40 | self.set_password(password) 41 | self.click_sign_in_btn() 42 | -------------------------------------------------------------------------------- /pages/my_account_page.py: -------------------------------------------------------------------------------- 1 | from selenium.webdriver.common.by import By 2 | 3 | from pages.base_page import BasePage 4 | from pages.locators import * 5 | 6 | 7 | class MyAccountPage(BasePage): 8 | my_account_text = (By.XPATH, MY_ACCOUNT_TEXT) 9 | 10 | def is_my_account_text_displayed(self): 11 | email_element = self.driver.find_element(*MyAccountPage.my_account_text) 12 | return email_element.is_displayed() 13 | -------------------------------------------------------------------------------- /project.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | 3 | from lemoncheesecake.project import SimpleProjectConfiguration, HasPreRunHook 4 | 5 | try: 6 | from core.common.init import init_session 7 | except: 8 | print("Error! Please ensure following:\n- PYTHONPATH/TEST_ENV environment variables are set properly before" 9 | " running any tests.\n- All test URLs are valid and reachable.") 10 | exit(1) 11 | 12 | 13 | class MyProjectConfig(SimpleProjectConfiguration, HasPreRunHook): 14 | def pre_run(self, cli_args, report_dir): 15 | init_session() 16 | 17 | 18 | project_dir = os.path.dirname(__file__) 19 | project = MyProjectConfig( 20 | suites_dir=os.path.join(project_dir, "tests"), 21 | fixtures_dir=os.path.join(project_dir, "core/fixtures"), 22 | ) 23 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | certifi==2018.4.16 2 | chardet==3.0.4 3 | colorama==0.3.9 4 | idna==2.7 5 | lemoncheesecake==1.4.0 6 | slacker==0.13.0 7 | requests==2.20.2 8 | six==1.11.0 9 | slackclient==1.2.1 10 | termcolor==1.1.0 11 | terminaltables==3.1.0 12 | urllib3==1.24.2 13 | websocket-client==0.48.0 14 | selenium 15 | -------------------------------------------------------------------------------- /resources/chromedriver_linux: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/resources/chromedriver_linux -------------------------------------------------------------------------------- /resources/chromedriver_mac: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/resources/chromedriver_mac -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | SERVER_URL="http://someserver.com" 4 | WWW_REPORTS_DIR="server_report_dir" 5 | LOCAL_REPORTS_DIR="reports" 6 | VENV_NAME="selenium-pom-python-venv" 7 | echo "Running test suite $1" 8 | REPORT_DIR_NAME=`date +'%d-%m-%Y-%H-%M-%S'` 9 | if test ! -d reports/; then 10 | echo "reports directory not found, creating the same" 11 | mkdir -p reports/ 12 | fi 13 | echo "Creating directory reports/$REPORT_DIR_NAME" 14 | mkdir -p reports/${REPORT_DIR_NAME} 15 | mkdir -p docker-report/${REPORT_DIR_NAME} 16 | export SLACK_MESSAGE_TEMPLATE="[$TEST_ENV] $1: {passed}/{enabled} passed | $SERVER_URL/$WWW_REPORTS_DIR/$REPORT_DIR_NAME/report/report.html" 17 | ${VENV_NAME}/bin/lcc run $1 --enable-reporting slack console html --exit-error-on-failure 18 | export CURRENT_SUITE_EXECUTION_STATUS=$? 19 | echo "Test suite execution completed with exit code" ${CURRENT_SUITE_EXECUTION_STATUS} 20 | echo "Copying the latest report in reports/$REPORT_DIR_NAME" 21 | cp -r report/ ${LOCAL_REPORTS_DIR}/${REPORT_DIR_NAME} 22 | cp -r report/ docker-report/${REPORT_DIR_NAME} 23 | -------------------------------------------------------------------------------- /screenshots/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/screenshots/.gitkeep -------------------------------------------------------------------------------- /scripts/send_message_to_slack.py: -------------------------------------------------------------------------------- 1 | import argparse 2 | 3 | from slackclient import SlackClient 4 | 5 | cli = argparse.ArgumentParser() 6 | cli.add_argument('-t', 7 | '--slacktoken', 8 | type=str) 9 | cli.add_argument('-c', 10 | '--channel', 11 | type=str) 12 | cli.add_argument('-m', 13 | '--message', 14 | type=str) 15 | args = cli.parse_args() 16 | slack_token = args.slacktoken 17 | slack_channel = args.channel 18 | message = args.message 19 | sc = SlackClient(slack_token) 20 | sc.api_call("chat.postMessage", channel=slack_channel, text=message) 21 | -------------------------------------------------------------------------------- /scripts/test_ping.py: -------------------------------------------------------------------------------- 1 | pass -------------------------------------------------------------------------------- /tests/LoginTests.py: -------------------------------------------------------------------------------- 1 | import lemoncheesecake.api as lcc 2 | from lemoncheesecake.matching import check_that, is_true 3 | from selenium import webdriver 4 | 5 | from core.common.constants import Global 6 | from core.utils.fileutils import capture_screenshot 7 | from pages.login_page import LoginPage 8 | from pages.my_account_page import MyAccountPage 9 | 10 | 11 | @lcc.suite("Login page tests") 12 | class LoginTests(object): 13 | login, my_account, driver = None, None, None 14 | 15 | def setup_suite(self): 16 | lcc.log_info("Inside setup") 17 | self.driver = webdriver.Chrome(executable_path=Global.CHROME_DRIVER) 18 | self.login = LoginPage(driver=self.driver) 19 | self.my_account = MyAccountPage(driver=self.driver) 20 | 21 | @lcc.test("check login failure") 22 | def verify_login_failure(self): 23 | self.login.login(email="akshaymaldhure@gmail.com", password="admin123") 24 | check_that("Failure message is displayed", self.login.is_failure_message_displayed(), is_true()) 25 | 26 | @lcc.test("check login success") 27 | def verify_login_success(self): 28 | self.login.login(email="akshaymaldhure@gmail.com", password="admin") 29 | check_that("My Account text is displayed", self.my_account.is_my_account_text_displayed(), is_true()) 30 | 31 | def teardown_test(self, test_name): 32 | lcc.log_info("Finished running test " + test_name) 33 | capture_screenshot(self.driver) 34 | 35 | def teardown_suite(self): 36 | lcc.log_info("Inside teardown") 37 | self.driver.quit() 38 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/akshayamaldhure/selenium-python-page-object-model/a6c628066067ecd114e1a6e3850fa8df3de386d3/tests/__init__.py --------------------------------------------------------------------------------