├── .github └── workflows │ └── Semgrep.yml ├── .gitignore ├── CODEOWNERS ├── README.md ├── google-search-browserstack.py ├── nose-test ├── README.md └── google-search-browserstack.py ├── parallel_tests ├── README.md ├── browsers.json ├── run_parallel_tests.py └── test.py ├── py.test ├── README.md └── google-search-browserstack.py ├── screenshot-sample.py └── unittest └── google-search-browserstack.py /.github/workflows/Semgrep.yml: -------------------------------------------------------------------------------- 1 | # Name of this GitHub Actions workflow. 2 | name: Semgrep 3 | 4 | on: 5 | # Scan changed files in PRs (diff-aware scanning): 6 | # The branches below must be a subset of the branches above 7 | pull_request: 8 | branches: ["master", "main"] 9 | push: 10 | branches: ["master", "main"] 11 | schedule: 12 | - cron: '0 6 * * *' 13 | 14 | 15 | permissions: 16 | contents: read 17 | 18 | jobs: 19 | semgrep: 20 | # User definable name of this GitHub Actions job. 21 | permissions: 22 | contents: read # for actions/checkout to fetch code 23 | security-events: write # for github/codeql-action/upload-sarif to upload SARIF results 24 | name: semgrep/ci 25 | # If you are self-hosting, change the following `runs-on` value: 26 | runs-on: ubuntu-latest 27 | 28 | container: 29 | # A Docker image with Semgrep installed. Do not change this. 30 | image: returntocorp/semgrep 31 | 32 | # Skip any PR created by dependabot to avoid permission issues: 33 | if: (github.actor != 'dependabot[bot]') 34 | 35 | steps: 36 | # Fetch project source with GitHub Actions Checkout. 37 | - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 38 | # Run the "semgrep ci" command on the command line of the docker image. 39 | - run: semgrep ci --sarif --output=semgrep.sarif 40 | env: 41 | # Add the rules that Semgrep uses by setting the SEMGREP_RULES environment variable. 42 | SEMGREP_RULES: p/default # more at semgrep.dev/explore 43 | 44 | - name: Upload SARIF file for GitHub Advanced Security Dashboard 45 | uses: github/codeql-action/upload-sarif@6c089f53dd51dc3fc7e599c3cb5356453a52ca9e # v2.20.0 46 | with: 47 | sarif_file: semgrep.sarif 48 | if: always() -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[cod] 2 | 3 | # C extensions 4 | *.so 5 | 6 | # Packages 7 | *.egg 8 | *.egg-info 9 | dist 10 | build 11 | eggs 12 | parts 13 | bin 14 | var 15 | sdist 16 | develop-eggs 17 | .installed.cfg 18 | lib 19 | lib64 20 | 21 | # Installer logs 22 | pip-log.txt 23 | 24 | # Unit test / coverage reports 25 | .coverage 26 | .tox 27 | nosetests.xml 28 | 29 | # Translations 30 | *.mo 31 | 32 | # Mr Developer 33 | .mr.developer.cfg 34 | .project 35 | .pydevproject 36 | 37 | # Sample files(generated while execution) 38 | sample.png 39 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @browserstack/automate-public-repos 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # automate-python-samples 2 | 3 | Documentation for writing Automate test scripts in Python. 4 | 5 | Master branch contains **Selenium 3** samples, for **Selenium 4 - W3C protocol** please checkout [selenium-4](https://github.com/browserstack/automate-python-samples/tree/selenium-4) branch 6 | 7 | 8 | ## Environment variables 9 | To test various sample repositories with ease, it is recommended to setup `BROWSERSTACK_USERNAME` and `BROWSERSTACK_ACCESS_KEY` environment variables. Alternatively you can directly update the samples with the credentials or pass the appropriate command line parameters. 10 | 11 | ## Install Python 12 | 13 | ### For Windows: 14 | 15 | - Download the latest python build for windows - https://www.python.org/downloads/windows/ 16 | - Run the installer exe and follow the instructions to install python. 17 | 18 | ### For Mac and Linux: 19 | 20 | - Run python --version to see what python version is installed and make sure it is 3.X and above. 21 | - Mac OS, Ubuntu and many flavors of linux come with pre-installed python. 22 | 23 | ## Install Selenium 24 | 25 | ### For Unix: 26 | ``` 27 | sudo easy_install selenium 28 | ``` 29 | 30 | ### For Windows: 31 | ``` 32 | easy_install selenium 33 | ``` 34 | 35 | If you prefer pip, then use the following command: 36 | ``` 37 | sudo pip install selenium 38 | ``` 39 | 40 | If pip is not installed, you can install it using: 41 | ``` 42 | sudo easy_install pip 43 | ``` 44 | 45 | For Python frameworks samples and integrations with BrowserStack, refer to their individual repositories - 46 | 47 | - [Behave](https://github.com/browserstack/behave-browserstack) 48 | - [Lettuce](https://github.com/browserstack/lettuce-browserstack) 49 | - [Salad](https://github.com/browserstack/salad-browserstack) 50 | -------------------------------------------------------------------------------- /google-search-browserstack.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from selenium import webdriver 5 | from selenium.webdriver.common.keys import Keys 6 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 7 | 8 | try: 9 | USERNAME = os.environ.get('BROWSERSTACK_USERNAME') or sys.argv[1] 10 | BROWSERSTACK_ACCESS_KEY = os.environ.get('BROWSERSTACK_ACCESS_KEY') or sys.argv[2] 11 | except IndexError: 12 | print("Please provide the username and browserstack access key as command line arguments.") 13 | sys.exit(1) 14 | 15 | driver = webdriver.Remote( 16 | command_executor='https://%s:%s@hub.browserstack.com/wd/hub' % ( 17 | USERNAME, BROWSERSTACK_ACCESS_KEY 18 | ), 19 | desired_capabilities=DesiredCapabilities.FIREFOX 20 | ) 21 | 22 | driver.get("http://www.google.com") 23 | if not "Google" in driver.title: 24 | raise Exception("Unable to load google page!") 25 | 26 | elem = driver.find_element_by_name("q") 27 | elem.send_keys("selenium") 28 | elem.submit() 29 | 30 | print(driver.title) 31 | driver.quit() 32 | -------------------------------------------------------------------------------- /nose-test/README.md: -------------------------------------------------------------------------------- 1 | # A sample to run nosetests over BrowserStack Automate. 2 | 3 | ### Setup 4 | `pip install nose2` 5 | 6 | 7 | ### Running the tests 8 | 9 | To run the tests, add you credentials to `google-search-browserstack.py` and execute: 10 | 11 | ``` 12 | nose2 google-search-browserstack 13 | ``` 14 | -------------------------------------------------------------------------------- /nose-test/google-search-browserstack.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | 5 | from selenium import webdriver 6 | from selenium.webdriver.common.keys import Keys 7 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 8 | 9 | # Edit these to match your credentials 10 | USERNAME = os.environ.get('BROWSERSTACK_USERNAME') or sys.argv[3] 11 | BROWSERSTACK_ACCESS_KEY = os.environ.get('BROWSERSTACK_ACCESS_KEY') or sys.argv[4] 12 | 13 | if not (USERNAME and BROWSERSTACK_ACCESS_KEY): 14 | raise Exception("Please provide your BrowserStack username and access key") 15 | 16 | class PythonOrgSearch(unittest.TestCase): 17 | 18 | def setUp(self): 19 | url = "https://%s:%s@hub.browserstack.com/wd/hub" %( 20 | USERNAME, BROWSERSTACK_ACCESS_KEY 21 | ) 22 | 23 | self.driver = webdriver.Remote( 24 | command_executor=url, 25 | desired_capabilities=DesiredCapabilities.FIREFOX 26 | ) 27 | 28 | def test_search_in_python_org(self): 29 | driver = self.driver 30 | driver.get("http://www.google.com") 31 | elem = driver.find_element_by_name("q") 32 | elem.send_keys("selenium") 33 | elem.submit() 34 | self.assertIn("Google", driver.title) 35 | 36 | def tearDown(self): 37 | self.driver.quit() 38 | -------------------------------------------------------------------------------- /parallel_tests/README.md: -------------------------------------------------------------------------------- 1 | # Parallel Testing on BrowserStack 2 | 3 | This project contains 3 files. Each of the files is described below. 4 | 5 | `browsers.json` - This file specifies the browser capabilites for the tests. Here, each test would be run in these two browsers. 6 | 7 | [ 8 | { 9 | "browserName": "iPhone", 10 | "platform": "MAC", 11 | "device": "iPhone 5" 12 | }, 13 | { 14 | "browser": "firefox", 15 | "browser_version": "17.0", 16 | "os": "Windows", 17 | "os_version": "8" 18 | } 19 | ] 20 | 21 | 22 | `test.py ` - This file contains the selenium test which would be run in each of the browsers specificed by "browsers.json". 23 | 24 | `run_parallel_tests.py ` - This is the runner which runs the tests in parallel. 25 | 26 | To run the tests in parallel execute the following command: 27 | 28 | ```sh 29 | python3 run_parallel_tests.py test.py browsers.json 30 | ``` 31 | -------------------------------------------------------------------------------- /parallel_tests/browsers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "os_version": "11", 4 | "device": "iPhone 8", 5 | "real_mobile": "true" 6 | }, 7 | { 8 | "os": "Windows", 9 | "os_version": "8", 10 | "browserName": "Firefox", 11 | "browser_version": "65.0" 12 | }, 13 | { 14 | "os": "Windows", 15 | "os_version": "7", 16 | "browserName": "IE", 17 | "browser_version": "8.0" 18 | }, 19 | { 20 | "os": "Windows", 21 | "os_version": "7", 22 | "browserName": "IE", 23 | "browser_version": "9.0" 24 | }, 25 | { 26 | "os": "Windows", 27 | "os_version": "8", 28 | "browserName": "IE", 29 | "browser_version": "10.0" 30 | }, 31 | { 32 | "os": "OS X", 33 | "os_version": "Snow Leopard", 34 | "browserName": "Firefox", 35 | "browser_version": "42.0" 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /parallel_tests/run_parallel_tests.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | import subprocess 4 | 5 | try: 6 | file_name = sys.argv[1] 7 | json_name = sys.argv[2] 8 | except IndexError: 9 | print("Please provide test script and browserconfig as first and second argument, respectively, from command line.") 10 | sys.exit(1) 11 | 12 | with open(json_name, "r") as f: 13 | obj = json.loads(f.read()) 14 | 15 | num_of_tests = len(obj) 16 | process = [] 17 | for counter in range(num_of_tests): 18 | cmd = "python3 %s %s %s" % (file_name, json_name, counter) 19 | process.append(subprocess.Popen(cmd, shell=True)) 20 | 21 | for counter in range(num_of_tests): 22 | process[counter].wait() 23 | 24 | -------------------------------------------------------------------------------- /parallel_tests/test.py: -------------------------------------------------------------------------------- 1 | from selenium import webdriver 2 | import os, sys, json 3 | 4 | try: 5 | json_name = sys.argv[1] 6 | counter_val = sys.argv[2] 7 | except IndexError: 8 | print('Json name and counter val must be passed as first and second argument, respectively, from the comamnd line') 9 | sys.exit(1) 10 | 11 | USERNAME = os.environ.get('BROWSERSTACK_USERNAME') or sys.argv[2] 12 | BROWSERSTACK_ACCESS_KEY = os.environ.get('BROWSERSTACK_ACCESS_KEY') or sys.argv[3] 13 | 14 | with open(json_name, "r") as f: 15 | obj = json.loads(f.read()) 16 | 17 | instance_caps = obj[int(counter_val)] 18 | print("Test %s started" % (counter_val)) 19 | 20 | #------------------------------------------------------# 21 | # Mention any other capabilities required in the test 22 | caps = {} 23 | caps["browserstack.debug"] = "true" 24 | caps["build"] = "parallel tests" 25 | 26 | #------------------------------------------------------# 27 | 28 | caps = {**caps, **instance_caps} 29 | 30 | #------------------------------------------------------# 31 | # THE TEST TO BE RUN PARALLELY GOES HERE 32 | 33 | driver = webdriver.Remote( 34 | command_executor='https://%s:%s@hub.browserstack.com/wd/hub' % ( 35 | USERNAME, BROWSERSTACK_ACCESS_KEY 36 | ), 37 | desired_capabilities=caps 38 | ) 39 | 40 | driver.get("http://www.google.com") 41 | inputElement = driver.find_element_by_name("q") 42 | inputElement.send_keys("browserstack") 43 | inputElement.submit() 44 | print(driver.title) 45 | driver.quit() 46 | #------------------------------------------------------# 47 | -------------------------------------------------------------------------------- /py.test/README.md: -------------------------------------------------------------------------------- 1 | # A sample to run py.test over BrowserStack Automate. 2 | 3 | ## Setup 4 | 5 | `pip install pytest` 6 | 7 | ## Execution 8 | To run the tests, set correct environment variables or add you credentials to `google-search-browserstack.py` and execute: 9 | 10 | ``` 11 | py.test google-search-browserstack.py 12 | ``` 13 | -------------------------------------------------------------------------------- /py.test/google-search-browserstack.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | 4 | from selenium import webdriver 5 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 6 | 7 | # Edit these to match your credentials 8 | USERNAME = os.environ.get('BROWSERSTACK_USERNAME') or sys.argv[1] 9 | BROWSERSTACK_ACCESS_KEY = os.environ.get('BROWSERSTACK_ACCESS_KEY') or sys.argv[2] 10 | 11 | if not (USERNAME and BROWSERSTACK_ACCESS_KEY): 12 | raise Exception("Please provide your BrowserStack username and access key") 13 | 14 | def test_run(): 15 | url = "https://%s:%s@hub.browserstack.com/wd/hub" %( 16 | USERNAME, BROWSERSTACK_ACCESS_KEY 17 | ) 18 | 19 | driver = webdriver.Remote(command_executor=url, desired_capabilities=DesiredCapabilities.FIREFOX) 20 | driver.get('http://www.google.com') 21 | 22 | if not "Google" in driver.title: 23 | raise Exception("Are you not on google? How come!") 24 | elem = driver.find_element_by_name("q") 25 | elem.send_keys("selenium") 26 | elem.submit() 27 | driver.quit() 28 | -------------------------------------------------------------------------------- /screenshot-sample.py: -------------------------------------------------------------------------------- 1 | """ 2 | @param USERNAME: Browserstack username 3 | @type USERNAME: string 4 | @param BROWSERSTACK_ACCESS_KEY: Browserstack api key 5 | @type BROWSERSTACK_ACCESS_KEY: string 6 | @description: Supply these arguments from commandline while running this script 7 | """ 8 | import sys 9 | import base64 10 | from selenium import webdriver 11 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 12 | from selenium.webdriver.remote.webdriver import WebDriver 13 | 14 | # Input capabilities 15 | caps = {} 16 | caps["browser"] = "Firefox" 17 | caps["browser_version"] = "24.0" 18 | caps["os"] = "OS X" 19 | caps["os_version"] = "Snow Leopard" 20 | caps["browserstack.debug"] = "true" 21 | 22 | # Take input of user credentials 23 | try: 24 | USERNAME = sys.argv[1] 25 | BROWSERSTACK_ACCESS_KEY = sys.argv[2] 26 | FILENAME = sys.argv[3] 27 | except IndexError: 28 | print("Pleaes provide the username, browserstack access key and filename with which screenshot should be saved as command line arguments.") 29 | sys.exit(1) 30 | 31 | # Define take_screenshot 32 | def take_screenshot(webdriver, file_name="sample.png"): 33 | """ 34 | @param webdriver: WebDriver handler. 35 | @type webdriver: WebDriver 36 | @param file_name: Name to label this screenshot. 37 | @type file_name: str 38 | """ 39 | if isinstance(webdriver, WebDriver): 40 | base64_data = webdriver.get_screenshot_as_base64() 41 | screenshot_data = base64.b64decode(base64_data) 42 | screenshot_file = open(file_name, "wb") 43 | screenshot_file.write(screenshot_data) 44 | screenshot_file.close() 45 | else: 46 | webdriver.save_screenshot(filename) 47 | 48 | driver = webdriver.Remote( 49 | command_executor = 'http://%s:%s@hub.browserstack.com/wd/hub' % (USERNAME, BROWSERSTACK_ACCESS_KEY), 50 | desired_capabilities = caps 51 | ) 52 | 53 | driver.get("http://www.google.com") 54 | inputElement = driver.find_element_by_name("q") 55 | inputElement.send_keys("browserstack") 56 | inputElement.submit() 57 | print(driver.title) 58 | take_screenshot(driver, FILENAME) 59 | driver.quit() 60 | -------------------------------------------------------------------------------- /unittest/google-search-browserstack.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import unittest 4 | 5 | from selenium import webdriver 6 | from selenium.webdriver.common.keys import Keys 7 | from selenium.webdriver.common.desired_capabilities import DesiredCapabilities 8 | 9 | try: 10 | USERNAME = os.environ.get('BROWSERSTACK_USERNAME') or sys.argv[1] 11 | BROWSERSTACK_ACCESS_KEY = os.environ.get('BROWSERSTACK_ACCESS_KEY') or sys.argv[2] 12 | except IndexError: 13 | print("Please provide the username and browserstack access key as command line arguments.") 14 | sys.exit(1) 15 | 16 | class PythonOrgSearch(unittest.TestCase): 17 | 18 | def setUp(self): 19 | url = "https://%s:%s@hub.browserstack.com/wd/hub" %( 20 | USERNAME, BROWSERSTACK_ACCESS_KEY 21 | ) 22 | 23 | self.driver = webdriver.Remote( 24 | command_executor=url, 25 | desired_capabilities=DesiredCapabilities.FIREFOX 26 | ) 27 | 28 | def test_search_in_python_org(self): 29 | driver = self.driver 30 | driver.get("http://www.google.com") 31 | elem = driver.find_element_by_name("q") 32 | elem.send_keys("selenium") 33 | elem.submit() 34 | self.assertIn("Google", driver.title) 35 | 36 | def tearDown(self): 37 | self.driver.quit() 38 | 39 | if __name__ == "__main__": 40 | unittest.main(argv=sys.argv[:1]) 41 | --------------------------------------------------------------------------------