Updating a BrowserStack session’s name and result

2 minute read

Intro

BrowserStack’s REST API provides the ability to update various aspects of a session, e.g. test result, test name, etc. They do seem to provide a client library called browserstack-automate-java for interacting with the API (GitHub, maven-central), but it doesn’t seem to get much love and I can’t find any documentation for it. Its basic functions appear to work but using it to update anything in browserstack seems to fail.

Solving the problem

Wanting to update the session name and result, I wrote my own client based on Spring-Flux’s WebClient. Here’s what you need if you want to do the same.

Some dependencies

First, you’ll need some dependencies:

<dependencies>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webflux</artifactId>
    <version>5.1.5.RELEASE</version>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.4</version>
  </dependency>
  <dependency>
    <groupId>io.projectreactor.netty</groupId>
    <artifactId>reactor-netty</artifactId>
    <version>0.8.5.RELEASE</version>
  </dependency>
</dependencies>

Getting the BrowserStack Session ID

To update a BrowserStack session you need its ID; you can get that from your RemoteWebDriver instance:

RemoteWebDriver driver = ...;

// do some navigation, testing, etc.

String sessionId = driver.getSessionId().toString();

// sessionId is now "d430d61935a66ddd9c5c9a9e15362c520414b082"

Preparing the payload

Next, because you’re going to be sending JSON you’ll need a simple class that when converted to JSON matches what the API expects. Given we’re updating the session name and status the following is enough for our needs:

public class SessionDetails {
  private String name;
  private String status;

  private SessionDetails(String name, String status) {
    this.name = name;
    this.status = status;
  }

  public String getName() {
    return name;
  }

  public String getStatus() {
    return status;
  }
}

Assuming you’re using cucumber-jvm you’ll probably be making calls to BrowserStack’s API in an @After step. You’ll therefore have access to the scenario’s name as well as its result and can set the BrowserStack session’s result accordingly:

@After
public void setBrowserStackSessionDetails(Scenario scenario) {
  String testName = scenario.getName();
  
  // The API expects either "passed" or "failed". Here's a
  // rubbish way to ensure that. Maybe use an enum instead.
  String testResult = scenario.isFailed() ? "failed" : "passed";
}

We can now create an instance of the SessionDetails with the details we want to send:

@After
public void setBrowserStackSessionDetails(Scenario scenario) {
  String testName = scenario.getName();
  String testResult = scenario.isFailed() ? "failed" : "passed";
  
  SessionDetails sessionDetails = new sessionDetails(testName, testResult);
}

Making the call to BrowserStack

Now that we’ve got something we want to send to BrowserStack we need to get a HTTP client ready.

Preparing the WebClient

The old resttemplate way of doing things will be deprecated in the near future and replaced with WebClient. Its API isn’t all that intuitive but it makes sense in the end. Here’s how to set up a WebClient`:

import org.springframework.web.reactive.function.client.ExchangeFilterFunctions;
import org.springframework.web.reactive.function.client.WebClient;

//...

String browserStackUsername = "MY_BROWSERSTACK_USERNAME";
String browserStackAccessKey = "MY_BROWSERSTACK_ACCESS_KEY";

WebClient client = WebClient.builder()
  .baseUrl("https://api.browserstack.com")
  .filter(ExchangeFilterFunctions.basicAuthentication(browserStackUsername, browserStackAccessKey))
  .build();

Updating BrowserStack’s session details

The final thing to do is make the call to browserstack. Here’s how it’s done:

import org.springframework.http.MediaType;
import reactor.core.publisher.Mono;

//...

client.put().uri(builder -> builder.path("/automate/sessions/" + sessionId + ".json").build())
  .contentType(MediaType.APPLICATION_JSON)
  .body(Mono.just(sessionDetails), SessionDetails.class)
  .retrieve()
  .bodyToMono(String.class)
  .block();

That takes the sessionDetails containing the test name and status (passed/failed), converts it to JSON, and makes a PUT call to the session ID extracted from the RemoteWebDriver earlier.

Given your scenario name was “My Scenario Name” and the scenario failed, here’s what you should see:

Here’s what you should see:

Updated BrowserStack session details

Hope that helps.