diff --git a/.circleci/config.yml b/.circleci/config.yml index 4a6a6620..4cb8a936 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -17,7 +17,7 @@ jobs: - run: git clone https://github.com/qxf2/bitcoin-info.git - - run: openssl aes-256-cbc -d -md sha256 -in ./conf/remote_credentials_enc.py -out ./conf/remote_credentials.py -pass env:KEY + - run: openssl aes-256-cbc -d -md sha256 -in ./conf/env_remote_enc -out ./.env.remote -pass env:KEY - run: git clone https://github.com/qxf2/cars-api.git @@ -54,4 +54,4 @@ workflows: myproj: jobs: - - toxify \ No newline at end of file + - toxify diff --git a/Readme.md b/Readme.md index 225a4416..9c01d52d 100644 --- a/Readme.md +++ b/Readme.md @@ -30,7 +30,7 @@ This GUI and API test automation framework is developed and maintained by [Qxf2 We've implemented some version of this framework at several [clients](https://qxf2.com/clients). In all cases, this framework helped us write automated tests within the first week of our engagement. We hope you find this framework useful too! -If you end up using our framework, please let us know by giving us a star on GitHub and/or dropping an email to __mak@qxf2.com__ +If you end up using our framework, please let us know by giving us a star on GitHub and/or dropping an email to __mak@qxf2.com__. ------ Setup @@ -55,6 +55,18 @@ c) If you do not have it already, get pip (NOTE: Most recent Python distribution d) pip install -r requirements.txt to install dependencies +e)configure environmental variables + +Templates for.env files are provided. +Kindly fill in the credentials and rename the files according to the specified format. + +* env_conf to .env + Tesults, TestRail, Gmail , Report portal crentials details can be entered here. +* env_ssh_conf to .env.ssh + ssh server credentials used by the SSHKeywords keyword to connect to remote servers. +* env_remote to .env.remote + Remote WebDriver Server Details (BrowserStack/SauceLabs). + If you ran into some problems on step (d), please report them as an issue or email Arun(mak@qxf2.com). @@ -119,7 +131,7 @@ a) Directory structure of our current Templates ./ - |__conf: For all configurations and credential files + |__conf: For all configurations |__log: Log files for all tests @@ -163,8 +175,8 @@ c)python -m pytest tests/test_example_form.py --browser Chrome (to run against c d)python -m pytest tests/test_api_example.py (make sure to run sample cars-api available at qxf2/cars-api repository before api test run) -e)python -m pytest tests/test_mobile_bitcoin_price --mobile_os_version (android version) --device_name (simulator) --app_path (.apk location on local) --remote_flag Y (to run Mobile test case on Broswestack)remote_credentials.py -NOTE: For running tests in Browserstack, need to update Username/Accesskey from Browserstack Account to remote_credentials.py under conf. +e)python -m pytest tests/test_mobile_bitcoin_price --mobile_os_version (android version) --device_name (simulator) --app_path (.apk location on local) --remote_flag Y (to run Mobile test case on Broswerstack) +NOTE: For running tests in Browserstack, need to update Username/Accesskey from Browserstack Account to .env.remote . -------- ISSUES? diff --git a/conf/browser_os_name_conf.py b/conf/browser_os_name_conf.py index 3d0b105d..9de77d22 100644 --- a/conf/browser_os_name_conf.py +++ b/conf/browser_os_name_conf.py @@ -1,7 +1,10 @@ """ Conf file to generate the cross browser cross platform test run configuration """ -from . import remote_credentials as conf + +import os + + #Conf list for local default_browser = ["chrome"] #default browser for the tests to run against when -B option is not used local_browsers = ["firefox","chrome"] #local browser list against which tests would run if no -M Y and -B all is used @@ -25,7 +28,7 @@ def generate_configuration(browsers=browsers,firefox_versions=firefox_versions,c os_list=os_list,windows_versions=windows_versions,os_x_versions=os_x_versions): "Generate test configuration" - if conf.REMOTE_BROWSER_PLATFORM == 'SL': + if os.getenv('REMOTE_BROWSER_PLATFORM') == 'SL': os_x_versions = sauce_labs_os_x_versions test_config = [] for browser in browsers: @@ -65,6 +68,3 @@ def generate_configuration(browsers=browsers,firefox_versions=firefox_versions,c #variable to hold the configuration that can be imported in the conftest.py file cross_browser_cross_platform_config = generate_configuration() - - - diff --git a/conf/env_remote_enc b/conf/env_remote_enc new file mode 100644 index 00000000..f1b6a6ba --- /dev/null +++ b/conf/env_remote_enc @@ -0,0 +1 @@ +Salted__ ܯvlcV5+`P"7 wTAOl>2+1n0;S>n^,D[d8y0#̈́cK}(*tD -2>>Pڪ.\o2Z_KzP._!)QdLl5`UĜBU[Mbqrͫ=YJxGs`UnןmMvxZf \ No newline at end of file diff --git a/conf/remote_credentials_enc.py b/conf/remote_credentials_enc.py deleted file mode 100644 index 23e44368..00000000 Binary files a/conf/remote_credentials_enc.py and /dev/null differ diff --git a/conf/remote_credentials.py b/env_remote similarity index 64% rename from conf/remote_credentials.py rename to env_remote index 8bf22e70..dcbafa68 100644 --- a/conf/remote_credentials.py +++ b/env_remote @@ -2,12 +2,5 @@ #SET REMOTE_BROWSER_PLATFORM TO SL TO RUN ON SAUCE LABS REMOTE_BROWSER_PLATFORM = "BS" -USERNAME = "Enter your username" -ACCESS_KEY = "Enter your access key" - - - - - - - +REMOTE_USERNAME = "Enter your username" +REMOTE_ACCESS_KEY = "Enter your access key" \ No newline at end of file diff --git a/page_objects/Base_Page.py b/page_objects/Base_Page.py index 7739ba36..232518a6 100644 --- a/page_objects/Base_Page.py +++ b/page_objects/Base_Page.py @@ -2,6 +2,7 @@ Page class that all page models can inherit from There are useful wrappers for common Selenium operations """ + from selenium.webdriver.common.keys import Keys from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @@ -11,7 +12,6 @@ from .driverfactory import DriverFactory from page_objects import PageFactory from utils.stop_test_exception_util import Stop_Test_Exception -import conf.remote_credentials import conf.base_url_conf import conf.screenshot_conf from utils import Gif_Maker @@ -105,7 +105,7 @@ def register_driver(self,remote_flag,os_name,os_version,browser,browser_version, self.driver.implicitly_wait(5) self.driver.maximize_window() - if conf.remote_credentials.REMOTE_BROWSER_PLATFORM == 'BS' and remote_flag.lower() == 'y': + if os.getenv('REMOTE_BROWSER_PLATFORM') == 'BS' and remote_flag.lower() == 'y': self.register_browserstack() self.session_url = self.browserstack_obj.get_session_url() self.browserstack_msg = 'BrowserStack session URL:' diff --git a/page_objects/driverfactory.py b/page_objects/driverfactory.py index ec2c617f..1193baae 100644 --- a/page_objects/driverfactory.py +++ b/page_objects/driverfactory.py @@ -7,13 +7,14 @@ from selenium import webdriver from selenium.webdriver.remote.webdriver import RemoteConnection from appium import webdriver as mobile_webdriver +from dotenv import load_dotenv from appium.options.android import UiAutomator2Options -from conf import remote_credentials from page_objects.drivers.remote_options import RemoteOptions from page_objects.drivers.local_browsers import LocalBrowsers from conf import ports_conf from conf import screenshot_conf +load_dotenv('.env.remote') localhost_url = 'http://localhost:%s'%ports_conf.port #Set the url of localhost browserstack_url = "http://hub-cloud.browserstack.com/wd/hub" saucelabs_url = "https://ondemand.eu-central-1.saucelabs.com:443/wd/hub" @@ -64,7 +65,7 @@ def select_remote_platform(self, remote_flag, os_name, os_version, browser, browser_version, remote_project_name, remote_build_name): """Select the remote platform to run the test when the remote_flag is Y.""" try: - if remote_credentials.REMOTE_BROWSER_PLATFORM == 'BS': + if os.getenv('REMOTE_BROWSER_PLATFORM') == 'BS': web_driver = self.run_browserstack(os_name, os_version, browser, browser_version, remote_project_name, remote_build_name) else: @@ -80,8 +81,8 @@ def run_browserstack(self, os_name, os_version, browser, browser_version, remote_project_name, remote_build_name): """Run the test in browser stack when remote flag is 'Y'.""" #Get the browser stack credentials from browser stack credentials file - username = remote_credentials.USERNAME - password = remote_credentials.ACCESS_KEY + username = os.getenv('REMOTE_USERNAME') + password = os.getenv('REMOTE_ACCESS_KEY') #Set browser options = self.get_browser(browser, browser_version) @@ -114,8 +115,8 @@ def run_browserstack(self, os_name, os_version, browser, browser_version, def run_sauce_lab(self, os_name, os_version, browser, browser_version): """Run the test in sauce labs when remote flag is 'Y'.""" #Get the sauce labs credentials from sauce.credentials file - username = remote_credentials.USERNAME - password = remote_credentials.ACCESS_KEY + username = os.getenv('REMOTE_USERNAME') + password = os.getenv('REMOTE_ACCESS_KEY') #set browser options = self.get_browser(browser, browser_version) @@ -165,8 +166,8 @@ def run_mobile(self, mobile_os_name, mobile_os_version, device_name, app_package ud_id, org_id, signing_id, no_reset_flag, appium_version): """Specify the mobile device configurations and get the mobile driver.""" #Get the remote credentials from remote_credentials file - username = remote_credentials.USERNAME - password = remote_credentials.ACCESS_KEY + username = os.getenv('REMOTE_USERNAME') + password = os.getenv('REMOTE_ACCESS_KEY') #setup mobile device desired_capabilities = self.set_mobile_device(mobile_os_name, mobile_os_version, device_name) @@ -249,7 +250,7 @@ def remote_platform_mobile(self, remote_flag, app_path, app_name, desired_capabi """ try: #Gets driver when test is run on Saucelab - if remote_credentials.REMOTE_BROWSER_PLATFORM == 'SL': + if os.getenv('REMOTE_BROWSER_PLATFORM') == 'SL': mobile_driver = self.saucelab_mobile(app_path, app_name, desired_capabilities, username, password) #Gets driver when test is run on Browserstack @@ -302,7 +303,7 @@ def browserstack_mobile(self, app_path, app_name, desired_capabilities, username def print_exception(exception, remote_flag): """Print out the exception message and suggest the solution based on the remote flag.""" if remote_flag.lower() == 'y': - solution = "It looks like you are trying to use a cloud service provider(BrowserStack or Sauce Labs) to run your test. \nPlease make sure you have updated ./conf/remote_credentials.py with the right credentials and also check for BrowserStack upload url changes and try again. \nTo use your local browser please run the test with the -M N flag" + solution = "It looks like you are trying to use a cloud service provider(BrowserStack or Sauce Labs) to run your test. \nPlease make sure you have updated .env.remote with the right credentials and also check for BrowserStack upload url changes and try again. \nTo use your local browser please run the test with the -M N flag" else: solution = "It looks like you are trying to run test cases with Local Appium Setup. \nPlease make sure to run Appium Server and try again." diff --git a/page_objects/drivers/remote_options.py b/page_objects/drivers/remote_options.py index 3ed300b2..1fbb511b 100644 --- a/page_objects/drivers/remote_options.py +++ b/page_objects/drivers/remote_options.py @@ -1,16 +1,16 @@ """ Set the desired option for running the test on a remote platform. """ + +import os +import json +from datetime import datetime +import requests from selenium.webdriver.common.desired_capabilities import DesiredCapabilities from selenium.webdriver.firefox.options import Options as FirefoxOptions from selenium.webdriver.ie.options import Options as IeOptions from selenium.webdriver.chrome.options import Options as ChromeOptions from selenium.webdriver.safari.options import Options as SafariOptions -from conf import remote_credentials -import os -import requests -import json -from datetime import datetime class RemoteOptions(): """Class contains methods for various remote options for browserstack and saucelab.""" @@ -87,8 +87,8 @@ def set_mobile_device(mobile_os_name, mobile_os_version, device_name): @staticmethod def sauce_upload(app_path, app_name): """Upload the apk to the sauce temperory storage.""" - username = remote_credentials.USERNAME - password = remote_credentials.ACCESS_KEY + username = os.getenv('REMOTE_USERNAME') + password = os.getenv('REMOTE_ACCESS_KEY') result_flag = False try: headers = {'Content-Type':'application/octet-stream'} @@ -115,8 +115,8 @@ def sauce_upload(app_path, app_name): @staticmethod def browser_stack_upload(app_name, app_path): """Upload the apk to the BrowserStack storage if its not done earlier.""" - username = remote_credentials.USERNAME - access_key = remote_credentials.ACCESS_KEY + username = os.getenv('REMOTE_USERNAME') + access_key = os.getenv('REMOTE_ACCESS_KEY') try: #Upload the apk apk_file = os.path.join(app_path, app_name) diff --git a/utils/BrowserStack_Library.py b/utils/BrowserStack_Library.py index 4676fb93..5186cb7a 100644 --- a/utils/BrowserStack_Library.py +++ b/utils/BrowserStack_Library.py @@ -8,11 +8,8 @@ To do: a) Handle expired sessions better """ - +import os import requests -from conf import remote_credentials as remote_credentials - - class BrowserStack_Library(): "BrowserStack library to interact with BrowserStack artifacts" def __init__(self): @@ -23,8 +20,8 @@ def __init__(self): def get_auth(self): "Set up the auth object for the Requests library" - USERNAME = remote_credentials.USERNAME - PASSWORD = remote_credentials.ACCESS_KEY + USERNAME = os.getenv('REMOTE_USERNAME') + PASSWORD = os.getenv('REMOTE_ACCESS_KEY') auth = (USERNAME,PASSWORD) return auth diff --git a/utils/interactive_mode.py b/utils/interactive_mode.py index 0c035c41..0cedd171 100644 --- a/utils/interactive_mode.py +++ b/utils/interactive_mode.py @@ -1,12 +1,12 @@ """ Implementing the questionaty library to fetch the users choices for different arguments """ +import os import sys import questionary from clear_screen import clear from conf import base_url_conf from conf import browser_os_name_conf as conf -from conf import remote_credentials def display_gui_test_options(browser,browser_version,os_version, os_name,remote_flag,testrail_flag,tesults_flag): @@ -298,10 +298,10 @@ def set_remote_credentials(): platform = "SL" username = questionary.text("Enter the Username").ask() password = questionary.password("Enter the password").ask() - with open("conf/remote_credentials.py",'w') as cred_file: + with open(".env.remote",'w') as cred_file: cred_file.write("REMOTE_BROWSER_PLATFORM = '%s'\ - \nUSERNAME = '%s'\ - \nACCESS_KEY = '%s'"%(platform,username,password)) + \nREMOTE_USERNAME = '%s'\ + \nREMOTE_ACCESS_KEY = '%s'"%(platform,username,password)) questionary.print("Updated the credentials successfully", style="bold fg:green") @@ -338,7 +338,7 @@ def get_os_version(os_name): os_version = questionary.select("Select the OS version", choices=conf.windows_versions).ask() elif os_name == "OS X": - if remote_credentials.REMOTE_BROWSER_PLATFORM == "SL": + if (os.getenv('REMOTE_BROWSER_PLATFORM') == "SL"): os_version = questionary.select("Select the OS version", choices=conf.sauce_labs_os_x_versions).ask() else: