├── .github └── workflows │ └── Semgrep.yml ├── .gitignore ├── .travis.yml ├── CODEOWNERS ├── README.md ├── composer.json ├── config ├── local.conf.yml ├── parallel.conf.yml └── single.conf.yml ├── features ├── bootstrap │ └── FeatureContext.php ├── local │ └── local.feature └── single │ └── single.feature └── lib ├── BrowserStackContext.php └── parallel.php /.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 | composer.phar 2 | composer.lock 3 | local.log 4 | vendor/ 5 | bin/ 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - '5.5' 5 | - '5.6' 6 | - '7.0' 7 | 8 | before_install: 9 | - true && `base64 --decode <<< ZXhwb3J0IEJST1dTRVJTVEFDS19BQ0NFU1NfS0VZPUh5VmZydXJvb3dYb041eGhLZEs2Cg==` 10 | - true && composer install 11 | 12 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @browserstack/automate-public-repos 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # behat-browserstack 2 | [Behat](https://github.com/Behat/Behat) Integration with BrowserStack. 3 | 4 | ![BrowserStack Logo](https://d98b8t1nnulk5.cloudfront.net/production/images/layout/logo-header.png?1469004780) 5 | 6 | ## Setup 7 | * Clone the repo 8 | * Install dependencies `composer install` 9 | * Update `*.conf.yml` files inside the `config/` directory with your [BrowserStack Username and Access Key](https://www.browserstack.com/accounts/settings) 10 | 11 | ## Running your tests 12 | - To run tests, run `composer parallel` 13 | - To run local tests, run `composer local` 14 | 15 | Understand how many parallel sessions you need by using our [Parallel Test Calculator](https://www.browserstack.com/automate/parallel-calculator?ref=github) 16 | 17 | 18 | ## Notes 19 | * You can view your test results on the [BrowserStack Automate dashboard](https://www.browserstack.com/automate) 20 | * To test on a different set of browsers, check out our [platform configurator](https://www.browserstack.com/automate/php#setting-os-and-browser) 21 | * You can export the environment variables for the Username and Access Key of your BrowserStack account 22 | 23 | ``` 24 | export BROWSERSTACK_USERNAME= && 25 | export BROWSERSTACK_ACCESS_KEY= 26 | ``` 27 | 28 | ## Additional Resources 29 | * [Documentation for writing Automate test scripts in PHP](https://www.browserstack.com/automate/php) 30 | * [Customizing your tests on BrowserStack](https://www.browserstack.com/automate/capabilities) 31 | * [Browsers & mobile devices for selenium testing on BrowserStack](https://www.browserstack.com/list-of-browsers-and-platforms?product=automate) 32 | * [Using REST API to access information about your tests via the command-line interface](https://www.browserstack.com/automate/rest-api) 33 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "require": { 3 | "behat/behat": "3.10.*@stable", 4 | "facebook/webdriver": "dev-master", 5 | "browserstack/browserstack-local": "dev-master", 6 | "symfony/yaml": "*" 7 | }, 8 | "config": { 9 | "bin-dir": "bin/" 10 | }, 11 | "scripts": { 12 | "test": "composer single && composer local && composer parallel", 13 | "single": "\"./bin/behat\" --config=config/single.conf.yml", 14 | "local": "\"./bin/behat\" --config=config/local.conf.yml", 15 | "parallel": [ 16 | "@putenv CONFIG_FILE=config/parallel.conf.yml", 17 | "php lib/parallel.php" 18 | ] 19 | }, 20 | "autoload": { 21 | "classmap": ["lib/"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /config/local.conf.yml: -------------------------------------------------------------------------------- 1 | default: 2 | autoload: 3 | '': '%paths.base%/../features/bootstrap' 4 | suites: 5 | default: 6 | paths: ['../features/local'] 7 | contexts: 8 | - FeatureContext: 9 | parameters: 10 | server: "hub-cloud.browserstack.com" 11 | user: "BROWSERSTACK_USERNAME" 12 | key: "BROWSERSTACK_ACCESS_KEY" 13 | 14 | capabilities: 15 | build: "browserstack build 1" 16 | name: "BStack local test" 17 | "browserstack.debug": true 18 | "browserstack.local": true 19 | "browserstack.source": "behat:sample-master-v1.0" 20 | 21 | environments: 22 | - 23 | browser: "Chrome" 24 | os: "Windows" 25 | -------------------------------------------------------------------------------- /config/parallel.conf.yml: -------------------------------------------------------------------------------- 1 | default: 2 | autoload: 3 | '': '%paths.base%/../features/bootstrap' 4 | suites: 5 | default: 6 | paths: ['../features/single'] 7 | contexts: 8 | - FeatureContext: 9 | parameters: 10 | server: "hub-cloud.browserstack.com" 11 | user: "BROWSERSTACK_USERNAME" 12 | key: "BROWSERSTACK_ACCESS_KEY" 13 | 14 | capabilities: 15 | build: "browserstack build 1" 16 | name: "BStack parallel test" 17 | "browserstack.debug": true 18 | "browserstack.source": "behat:sample-master-v1.0" 19 | 20 | environments: 21 | - 22 | browser: "Chrome" 23 | browser_version: "latest" 24 | - 25 | browser: "Firefox" 26 | os: "Windows" 27 | - 28 | browser: "Safari" 29 | os: "OS X" 30 | - 31 | browser: "Internet explorer" 32 | os: "Windows" 33 | -------------------------------------------------------------------------------- /config/single.conf.yml: -------------------------------------------------------------------------------- 1 | default: 2 | autoload: 3 | '': '%paths.base%/../features/bootstrap' 4 | suites: 5 | default: 6 | paths: ['../features/single'] 7 | contexts: 8 | - FeatureContext: 9 | parameters: 10 | server: "hub-cloud.browserstack.com" 11 | user: "BROWSERSTACK_USERNAME" 12 | key: "BROWSERSTACK_ACCESS_KEY" 13 | 14 | capabilities: 15 | build: "browserstack build 1" 16 | name: "BStack single test" 17 | "browserstack.debug": true 18 | "browserstack.source": "behat:sample-master-v1.0" 19 | 20 | environments: 21 | - 22 | browser: "Chrome" 23 | os: "Windows" 24 | -------------------------------------------------------------------------------- /features/bootstrap/FeatureContext.php: -------------------------------------------------------------------------------- 1 | get($url); 9 | } 10 | 11 | /** @When /^I search for "([^"]*)"$/ */ 12 | public function iSearchFor($searchText) { 13 | $element = self::$driver->findElement(WebDriverBy::name("q")); 14 | $element->sendKeys($searchText); 15 | $element->sendKeys(WebDriverKeys::ENTER); 16 | sleep(5); 17 | } 18 | 19 | /** @Then /^I get title as "([^"]*)"$/ */ 20 | public function iShouldGet($string) { 21 | $title = self::$driver->getTitle(); 22 | if ((string) $string !== $title) { 23 | throw new Exception("Expected title: '". $string. "'' Actual is: '". $title. "'"); 24 | } 25 | } 26 | 27 | /** @Then /^I should see "([^"]*)"$/ */ 28 | public function iShouldSee($string) { 29 | $source = self::$driver->getPageSource(); 30 | if (strpos($source, $string) === false) { 31 | throw new Exception("Expected to see: '". $string. "'' Actual is: '". $source. "'"); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /features/local/local.feature: -------------------------------------------------------------------------------- 1 | Feature: BrowserStack Local Testing 2 | 3 | Scenario: Can check tunnel working 4 | Given I am on "http://bs-local.com:45691/check" 5 | Then I should see "Up and running" 6 | -------------------------------------------------------------------------------- /features/single/single.feature: -------------------------------------------------------------------------------- 1 | Feature: Google's Search Functionality 2 | 3 | Scenario: Can find search results 4 | Given I am on "https://www.google.com/ncr" 5 | When I search for "BrowserStack" 6 | Then I get title as "BrowserStack - Google Search" 7 | -------------------------------------------------------------------------------- /lib/BrowserStackContext.php: -------------------------------------------------------------------------------- 1 | $value) { 32 | if(!array_key_exists($key, $caps)) 33 | $caps[$key] = $value; 34 | } 35 | if(array_key_exists("browserstack.local", $caps) && $caps["browserstack.local"]) 36 | { 37 | $bs_local_args = array("key" => self::$CONFIG['BROWSERSTACK_ACCESS_KEY']); 38 | self::$bs_local = new BrowserStack\Local(); 39 | self::$bs_local->start($bs_local_args); 40 | } 41 | 42 | self::$driver = RemoteWebDriver::create($url, $caps); 43 | } 44 | 45 | /** @AfterFeature */ 46 | public static function tearDown() 47 | { 48 | self::$driver->quit(); 49 | if(self::$bs_local) self::$bs_local->stop(); 50 | } 51 | } 52 | ?> 53 | -------------------------------------------------------------------------------- /lib/parallel.php: -------------------------------------------------------------------------------- 1 | $value) { 15 | if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { 16 | // Windows 17 | $cmd = "set TASK_ID=$key& \"./bin/behat\" --config=". getenv("CONFIG_FILE")." 2>&1\n"; 18 | } else { 19 | // Linux or Mac 20 | $cmd = "TASK_ID=$key ./bin/behat --config=". getenv("CONFIG_FILE")." 2>&1\n"; 21 | } 22 | print_r($cmd); 23 | 24 | $procs[$key] = popen($cmd, "r"); 25 | } 26 | 27 | foreach ($procs as $key => $value) { 28 | while (!feof($value)) { 29 | print fgets($value, 4096); 30 | } 31 | pclose($value); 32 | } 33 | 34 | ?> 35 | --------------------------------------------------------------------------------