Obtaining BrowserStack screenshots and video links

At Qxf2 we use BrowserStack to run our automated checks against different browsers. BrowserStack is a cloud-based, cross-browser, testing tool that takes away the pain of maintaining a physical lab and saves us a lot of time.


Why this post?

BrowserStack is a great tool to execute your automated tests. However BrowserStack is not a good tool to report the test results. At our clients, we usually execute our tests on BrowserStack and then report our automated test results to a test case management tool like TestRail or rely on the CI server as the test reporting tool. BrowserStack has useful debug artifacts that we want to share with whatever test reporting system that we integrate with. We especially find the BrowserStack screenshot URLs and the BrowserStack URL for the video replay to be helpful in investigating and reporting failures. We created a BrowserStack library using Python and BrowserStack’s API to help us share these BrowserStack artifacts across our automation framework. We wanted to share it with the testing community.


Overview

We will run a test similar to what we ran in our previous post on BrowserStack. If you need more details on BrowserStack set up and access key please refer to the previous post. We will take one screenshot during the test. BrowserStack saves the screenshot and stores a video recording of the test. We will write a library that will help us access these artifacts and print them out in our test’s log.

Note 1: BrowserStack screenshots are available on Amazon’s S3 for 90 days.
Note 2: BrowserStack’s video recording of your test run is available for 30 days.
So if you are working in a highly risk conscious industry with the chance of being audited, you may want to store these artifacts somewhere else.


A step by step guide

Here are the six steps we will perform:
1. Authenticate
2. Get replay url
3. Get latest screenshot
4. Putting it all together
5. Example usage
6. Running the test

You can use REST API to access information about your tests like build, sessions, session logs etc. We will use Python requests module to achieve this.

Step1. Authenticate
Use your BrowserStack username and access key for authentication

self.auth = ('USERNAME','ACCESSKEY')

Step2. Get replay url
The replay URL is of form: /builds/$build_id/session/$session_id/. To get the replay URL you need the build id and session id. Let us write methods to get the build id as well as the active session id.

    def get_build_id(self):
        "Get the build ID"
        self.build_url = self.browserstack_url + "builds.json"
        builds = requests.get(self.build_url, auth=self.auth).json()
        build_id =  builds[0]['automation_build']['hashed_id']
 
        return build_id
 
 
    def get_sessions(self):
        "Get a JSON object with all the sessions"
        build_id = self.get_build_id()
        sessions= requests.get(self.browserstack_url + 'builds/%s/sessions.json'%build_id, auth=self.auth).json()
 
        return sessions
 
 
    def get_active_session_id(self):
        "Return the session ID of the first active session"
        session_id = None
        sessions = self.get_sessions()
        for session in sessions:
            #Get session id of the first session with status = running 
            if session['automation_session']['status']=='running':
                session_id = session['automation_session']['hashed_id']
                break
 
        return session_id
 
 
     def get_session_url(self,session_id):
        "Get the video URL from build and session details. Needs to be called after session is completed"
        build_id = self.get_build_id()
        self.build_session_url = self.browserstack_url + "builds/"+build_id+"/sessions/"+session_id
        build_session_details = requests.get(self.build_session_url, auth=self.auth).json()
 
        #Get the video url from session details
        video_url = build_session_details[u'automation_session'][u'video_url']
        session_url= video_url.encode("utf-8")
 
        return session_url

Step3. Get latest screenshot
This step is a bit of a hack. There is no direct API call to get a list of screenshots saved by BrowserStack. There is no way to explicitly name the image BrowserStack saves on Amazon’s S3. To get past this, we end up parsing the session logs and find the latest screenshot. Then in our test, we can explicitly name and store the screenshot URL.

    def get_session_logs(self):
        "Return the session log in text format"
        build_id = self.get_build_id()
        session_id = self.get_active_session_id()
        session_log = requests.get(self.browserstack_url + 'builds/%s/sessions/%s/logs'%(build_id,session_id),auth=self.auth).text
 
        return session_log
 
 
    def get_latest_screenshot_url(self):
        "Get the URL of the latest screenshot"
        session_log = self.get_session_logs()
 
        #Process the text to locate the URL of the last screenshot
        screenshot_request = session_log.split('screenshot {}')[-1]
        response_result = screenshot_request.split('REQUEST')[0]
        image_url = response_result.split('https://')[-1]
        image_url = image_url.split('.png')[0]
        screenshot_url = 'https://' + image_url + '.png'
 
        return screenshot_url

Step4. Putting it all together Library
This is how our library looks.

"""
Qxf2 BrowserStack library to interact with BrowserStack's artifacts.
For now, this is useful for:
a) Obtaining the session URL
b) Obtaining URLs of screenshots
"""
 
import os,requests
 
 
class BrowserStack_Library():
    "BrowserStack library to interact with BrowserStack artifacts"
    def __init__(self,credentials_file=None):
        "Constructor for the BrowserStack library"
        self.browserstack_url = "https://www.browserstack.com/automate/"
        self.auth = ('USERNAME','ACCESS_KEY')
 
 
    def get_build_id(self):
        "Get the build ID"
        self.build_url = self.browserstack_url + "builds.json"
        builds = requests.get(self.build_url, auth=self.auth).json()
        build_id =  builds[0]['automation_build']['hashed_id']
 
        return build_id
 
 
    def get_sessions(self):
        "Get a JSON object with all the sessions"
        build_id = self.get_build_id()
        sessions= requests.get(self.browserstack_url + 'builds/%s/sessions.json'%build_id, auth=self.auth).json()
 
        return sessions
 
 
    def get_active_session_id(self):
        "Return the session ID of the first active session"
        session_id = None
        sessions = self.get_sessions()
        for session in sessions:
            #Get session id of the first session with status = running 
            if session['automation_session']['status']=='running':
                session_id = session['automation_session']['hashed_id']
                break
 
        return session_id
 
 
     def get_session_url(self,session_id):
        "Get the video URL from build and session details. Needs to be called after session is completed"
        build_id = self.get_build_id()
        self.build_session_url = self.browserstack_url + "builds/"+build_id+"/sessions/"+session_id
        build_session_details = requests.get(self.build_session_url, auth=self.auth).json()
 
        #Get the video url from session details
        video_url = build_session_details[u'automation_session'][u'video_url']
        session_url= video_url.encode("utf-8")
 
        return session_url
 
 
    def get_session_logs(self):
        "Return the session log in text format"
        build_id = self.get_build_id()
        session_id = self.get_active_session_id()
        session_log = requests.get(self.browserstack_url + 'builds/%s/sessions/%s/logs'%(build_id,session_id),auth=self.auth).text
 
        return session_log
 
 
    def get_latest_screenshot_url(self):
        "Get the URL of the latest screenshot"
        session_log = self.get_session_logs()
 
        #Process the text to locate the URL of the last screenshot
 
        screenshot_request = session_log.split('screenshot {}')[-1]
        response_result = screenshot_request.split('REQUEST')[0]
        image_url = response_result.split('https://')[-1]
        image_url = image_url.split('.png')[0]
        screenshot_url = 'https://' + image_url + '.png'
 
        return screenshot_url

Step5. Example usage
We are going to execute a Selenium test that visits http://www.chess.com/, asserts the title page and then clicks on the Sign up button and then take a screenshot. We will get and print the BrowserStack video replay URL and screenshot URL using the BrowserStack Library we just created.

import unittest, time
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
from BrowserStack_Library import BrowserStack_Library
 
class SeleniumOnBrowserStack(unittest.TestCase):
    "Example class written to run Selenium tests on BrowserStack"
    def setUp(self):
        desired_cap = {'platform': 'Windows', 'browserName': 'Firefox', 'browser_version':'65', 'browserstack.debug': 'true' }
        self.driver = webdriver.Remote(command_executor='http://USERNAME:[email protected]:80/wd/hub',desired_capabilities=desired_cap)
        self.browserstack_obj = BrowserStack_Library()
 
 
     def test_chess(self):
        "An example test: Visit chess.com and click on sign up link"        
        # Go to the URL 
        self.driver.get("http://www.chess.com")
        # Assert that the Home Page has title "Chess.com - Play Chess Online - Free Games"
        self.assertIn("Chess.com - Play Chess Online - Free Games", self.driver.title)
        # Identify the xpath for Play Now button which will take you to the sign up page
        elem = self.driver.find_element_by_xpath("//a[@title='Play Now']")
        elem.click()
        self.driver.save_screenshot("test_chess.png")
        # Print the title
        print self.driver.title
        # Get the Browserstack Screenshot url
        print "BrowserStack Screenshot url :",self.browserstack_obj.get_latest_screenshot_url()
        # Get the Browserstack active session id
        active_session_id = self.browserstack_obj.get_active_session_id()
        print "BrowserStack session id :",active_session_id
        # Complete the session
        self.driver.quit()
        # Get the Browserstack Session/Video url
        print "BrowserStack Session url :",self.browserstack_obj.get_session_url(active_session_id)
 
if __name__ == '__main__':
    unittest.main()

Step6. Run the Test
You can run the test script the normal way you do. We run it via the command prompt.

Running Browserstack Test


We’ll leave you with a screenshot of how we end up hyperlinking these artifacts when reporting to TestRail.
Example BrowserStack report to TestRail
We plan to write a post (within the next 6 months) showing you how to take screenshots automatically, numbers them intelligently, integrate screenshot naming with BrowserStack and then hyperlinking the artifacts to TestRail. If you are in a hurry to get this information, please post a comment below and we will directly share code with you.


26 thoughts on “Obtaining BrowserStack screenshots and video links

  1. Hi Avinash,

    I have used your code to get the session url from Browserstack. I am facing issues in getting the correct session_url. It prints the session_url, but it is not correct. The link just downloads a file which can’t be viewed. The session_url varies from the video_url on the site.

    1. Hi,
      The URL is the BrowserStack URL which would download the video link. You can try opening that file using VLC media player or any other player and can see the video of the test run.

Leave a Reply

Your email address will not be published. Required fields are marked *