πŸ”Œ Simple library to manipulate HTTP requests/responses and capture network logs made by the browser using selenium tests without using any proxies

Overview

Simple library to manipulate HTTP requests and responses, capture the network logs made by the browser using selenium tests without using any proxies

Although selenium is used for e2e and especially UI testing, you might want to mock certain HTTP response to test few error scenarios and to assess HTTP requests done by your client code (e.g. when you don't have immediate UI feedback, like in metrics or tracking calls).

There's one catch though: you can't intercept HTTP calls that are initiated on page load (like in most SPAs), as it requires some setup work that can only be done after the page is loaded (due to limitations in selenium). That means you can just capture requests that were initiated inside a test. If you're fine with that, this plugin might be for you, so read on.

Installation

Maven

<dependency>
    <groupId>io.github.sudharsan-selvaraj</groupId>
    <artifactId>wow-xhr</artifactId>
    <version>1.0.0</version>
</dependency> 

Gradle

implementation group: 'io.github.sudharsan-selvaraj', name: 'wow-xhr', version: '1.0.0'

Also while downloading selenium, make sure to exclude net.bytebuddy:byte-buddy library by using

Maven

<dependency>
   <groupId>org.seleniumhq.selenium</groupId>
   <artifactId>selenium-java</artifactId>
   <version>3.141.59</version>
   <exclusions>
      <exclusion>
         <groupId>net.bytebuddy</groupId>
         <artifactId>byte-buddy</artifactId>
      </exclusion>
   </exclusions>
</dependency>

Gradle

implementation (group: 'org.seleniumhq.selenium', name: 'selenium-java', version: '3.141.59') {
   exclude group: 'net.bytebuddy', module: 'byte-buddy'
 }

Features:

  1. Intercept any HTTP request and modify the header, query param, body of the request.
  2. Modify the header, body, status of the HTTP response.
  3. Get the complete details of all API calls made by the browser along with the header, body, initiated time and completed time.
  4. Add a delay to any API call to simulate network speed for specific API call.

Quickstart

Create wowXhr object,

WowXHR wowXhr = new WowXHR(new ChromeDriver()); //any selenium webdriver or RemoteWebDriver
WebDriver driver = wowXhr.getMockDriver()

That's it. Now the driver object can be used in the test. No extra configurations required for browser running on remote machine or browserstack or saucelabs.

Mock

Modify HTTP request

Add or update header

import static io.github.sudharsan_selvaraj.wowxhr.mock.Mockable.*;

driver.get("http://localhost:3000");

wowXHR.mock().add(
        whenGET("/api")
        .modifyRequest(
                mockRequest()
                .setHeader("Authorization", "invalid-auth-token")
        )
);

Above mock will update the Authorization header with invalid-auth-token for all HTTP request that has /api regular expression in its url.

Add or update query param

import static io.github.sudharsan_selvaraj.wowxhr.mock.Mockable.*;

driver.get("http://localhost:3000");

wowXHR.mock().add(
        whenGET("/api/users")
        .modifyRequest(
                mockRequest()
                .setQueryParam("filter_fname", "sudharsan")
        )
);

Above mock will add ?filter_fname=sudharsan or update the value of filter_fname query param for all /api/users api requests.

Update the request body

import static io.github.sudharsan_selvaraj.wowxhr.mock.Mockable.*;

driver.get("http://localhost:3000");

wowXHR.mock().add(
        whenPOST("/api/login")
        .modifyRequest(
                mockRequest()
                .setBody("{\"email\":\"[email protected]\",\"password\":\"somepassword\"}")
        )
);

Above mock will update the request body with {\"email\":\"[email protected]\",\"password\":\"somepassword\"} for all subsequent /api/login requests.

Modify HTTP response

Add or update header

import static io.github.sudharsan_selvaraj.wowxhr.mock.Mockable.*;

driver.get("http://localhost:3000");

wowXHR.mock().add(
        whenPOST("/api/login")
        .respond(
            mockResponse()
            .withHeader("Set-Cookie", "refresh-token=invalid-refresh-token; expires=Mon, 17-Jul-2021 16:06:00 GMT; Max-Age=31449600; Path=/; secure")
         )
);

Above mock will update the response header and add's the new cookie to the browser.

Update the response body

import static io.github.sudharsan_selvaraj.wowxhr.mock.Mockable.*;

driver.get("http://localhost:3000");

wowXHR.mock().add(
        whenPOST("/api/login")
        .respond(
            mockResponse()
            .withBody("{\"error\": \"true\" ,\"message\" : \"User account is locked\"}")
         )
);

Above mock will update the response body with "{\"error\": \"true\" ,\"message\" : \"User account is locked\"}" for all login api calls.

update the response status

import static io.github.sudharsan_selvaraj.wowxhr.mock.Mockable.*;

driver.get("http://localhost:3000");

wowXHR.mock().add(
        whenPOST("/api/login")
        .respond(
            mockResponse()
            .withStatus(500) //internal server error
         )
);

Above mock will change the response status code to 500 and makes the application to assume that the API call has been failed.

update the response status

import static io.github.sudharsan_selvaraj.wowxhr.mock.Mockable.*;

driver.get("http://localhost:3000");

wowXHR.mock().add(
        whenPOST("/api/login")
        .respond(
            mockResponse()
            .withDelay(10) //in seconds
         )
);

Above mock will add a delay of 10 seconds before the response is returned to the application. This will be very useful in testing any loading UI elements that is displayed when API calls are made.

Pausing and Resume the mock

At any point in the test if you decide to pause the mocking, then it can be achieved using

 wowhXhr.mock().pause();

and you can resume using,

wowhXhr.mock().resume();

Logs

Get XHR logs

List<XHRLog> logs = wowXHR.log().getXHRLogs();
logs.forEach(log -> {
        Date initiatedTime =  log.getInitiatedTime();
        Date completedTime =  log.getCompletedTime();

        String method = log.getRequest().getMethod().name(); // GET or POST or PUT etc
        String url = log.getRequest().getUrl();
        Integer status = log.getResponse().getStatus();
        String requestBody = (String) log.getRequest().getBody();
        String responseBody = (String) log.getResponse().getBody();
        Map<String, String> requestHeaders = log.getRequest().getHeaders();
        Map<String, String> responseHeaders = log.getResponse().getHeaders();
});

Note: By default wowXHR.log().getXHRLogs() will clear the previously fetched logs. If you want the logs to be preserved, then you can use the overloaded method wowXHR.log().getXHRLogs(false)

Manually clear the logs

 wowXHR.log().clear();

Upcoming features

  1. Support for making the tests to wait for all api calls to get completed (similar to protractor's waitForAngular)
  2. Ability to mock the HTTP requests that are triggered during initial page load.
  3. Currently, the request can be mocked based on its URL only(Regex). In the future, we will also support for finding requests using query params(partial and exact) and body(partial and exact).
  4. TBD
Comments
  • Mockito cannot mock this class: class org.openqa.selenium.chrome.ChromeDriver.

    Mockito cannot mock this class: class org.openqa.selenium.chrome.ChromeDriver.

    HI,

    I want to try this lib to intercept a response, however, I am getting an exception .

    org.mockito.exceptions.base.MockitoException: Mockito cannot mock this class: class org.openqa.selenium.chrome.ChromeDriver.

    Mockito can only mock non-private & non-final classes. If you're not sure why you're getting this error, please report to the mailing list.

    Java : 11 JVM vendor name : Oracle Corporation JVM vendor version : 11.0.10+8-LTS-162 JVM name : Java HotSpot(TM) 64-Bit Server VM JVM version : 11.0.10+8-LTS-162 JVM info : mixed mode OS name : Mac OS X OS version : 10.16

    Underlying exception : java.lang.IllegalArgumentException: Could not create type

    at io.github.sudharsan_selvaraj.SpyDriver.(SpyDriver.java:20) at io.github.sudharsan_selvaraj.SpyDriver.(SpyDriver.java:13) at io.github.sudharsan_selvaraj.wowxhr.WowXHR.(WowXHR.java:20) at SeleniumMocking.MockTags.beforeSuite(MockTags.java:20) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.testng.internal.MethodInvocationHelper.invokeMethod(MethodInvocationHelper.java:124) at org.testng.internal.MethodInvocationHelper.invokeMethodConsideringTimeout(MethodInvocationHelper.java:59) at org.testng.internal.Invoker.invokeConfigurationMethod(Invoker.java:458) at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:222) at org.testng.internal.Invoker.invokeConfigurations(Invoker.java:142) at org.testng.SuiteRunner.privateRun(SuiteRunner.java:401) at org.testng.SuiteRunner.run(SuiteRunner.java:364) at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52) at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84) at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208) at org.testng.TestNG.runSuitesLocally(TestNG.java:1137) at org.testng.TestNG.runSuites(TestNG.java:1049) at org.testng.TestNG.run(TestNG.java:1017) at com.intellij.rt.testng.IDEARemoteTestNG.run(IDEARemoteTestNG.java:66) at com.intellij.rt.testng.RemoteTestNGStarter.main(RemoteTestNGStarter.java:109) Caused by: java.lang.IllegalArgumentException: Could not create type at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:139) at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:344) at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:159) at net.bytebuddy.TypeCache$WithInlineExpunction.findOrInsert(TypeCache.java:353) at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator.mockClass(TypeCachingBytecodeGenerator.java:32) at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMockType(SubclassByteBuddyMockMaker.java:71) at org.mockito.internal.creation.bytebuddy.SubclassByteBuddyMockMaker.createMock(SubclassByteBuddyMockMaker.java:42) at org.mockito.internal.creation.bytebuddy.ByteBuddyMockMaker.createMock(ByteBuddyMockMaker.java:25) at org.mockito.internal.util.MockUtil.createMock(MockUtil.java:35) at org.mockito.internal.MockitoCore.mock(MockitoCore.java:63) at org.mockito.Mockito.mock(Mockito.java:1908) at org.mockito.Mockito.mock(Mockito.java:1880) ... 23 more Caused by: java.lang.NoSuchMethodError: net.bytebuddy.dynamic.loading.MultipleParentClassLoader$Builder.appendMostSpecific(Ljava/util/Collection;)Lnet/bytebuddy/dynamic/loading/MultipleParentClassLoader$Builder; at org.mockito.internal.creation.bytebuddy.SubclassBytecodeGenerator.mockClass(SubclassBytecodeGenerator.java:84) at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:37) at org.mockito.internal.creation.bytebuddy.TypeCachingBytecodeGenerator$1.call(TypeCachingBytecodeGenerator.java:34) at net.bytebuddy.TypeCache.findOrInsert(TypeCache.java:137) ... 34 more

    My code is :-

    public class MockTags {
    
        WebDriver driver;
        WowXHR wowXhr;
        @BeforeSuite
        public void beforeSuite() throws DriverNotSupportedException {
            WebDriverManager.chromedriver().setup();
            wowXhr = new WowXHR(new ChromeDriver());
            driver = wowXhr.getMockDriver();
            driver.navigate().to("https://react-redux.realworld.io/");
        }
    
        @Test
        public void mockTest() throws InterruptedException {
            driver.findElement(By.linkText("Sign in")).click();
            driver.findElement(By.cssSelector("input[type='email']")).sendKeys("[email protected]");
            driver.findElement(By.cssSelector("input[type='password']")).sendKeys("Qwerty@123");
            driver.findElement(By.xpath("//button[@type='submit']")).click();
    
            Thread.sleep(5000);
    
            wowXhr.mock().add(
                    Mockable.whenGET("/api/tags")
                    .respond(
                            Mockable.mockResponse()
                            .withBody("{\"tags\" : [\"mockTag1\", \"mockTag2\"]}")
                    )
            );
    
        }
    
    }
    
    opened by sunnysachdeva99 3
  • Mocked Fetch API returns an empty response

    Mocked Fetch API returns an empty response

    Hello, I'm getting an undefined response when call mocked endpoint with fetch API

    fetch(endpoint).then(response => {
       console.log({ response }); // πŸ‘ˆ response undefined
       return response.json();
    }
    

    I'm not sure if the data is being set when resolving the promise in XhrMock#afterXHR What do you think?

    opened by MaxwelSant 0
  • Unable to mock the API call from different domain

    Unable to mock the API call from different domain

    I have a usecase where there is an api call being made in the page from iframe in the page. The api is of different domain from that of the page it is being called. Will it be possible to mock this api if the domain is different?

    Thanks, Avinash k

    opened by avinashkandimalla 0
  • Facing Login issue when using webdriver with xhr

    Facing Login issue when using webdriver with xhr

    public WebDriver wowXhr() { WebDriverManager.chromedriver().setup(); WowXHR wowXHR = null; try { wowXHR = new WowXHR(new ChromeDriver()); } catch (DriverNotSupportedException e) { e.printStackTrace(); } return wowXHR.getMockDriver(); }

    I'm using above code to create Webdriver, when I tried to login to my application with valid credentials from automation the application was throwing Invalid Credential error. And with selenium Webdriver script the login was successful.

    opened by rajugade 1
  • Browser exception : Setting the value of '_wow_xhr_log_completed_calls_' exceeded the quota

    Browser exception : Setting the value of '_wow_xhr_log_completed_calls_' exceeded the quota

    When we use the WOW_XHR driver to run the scripts, then the application was broken., And while doing analysis, then found browser throws the below exception in console.

    Kindly help to check and advise to resolve the issue., Thanks.

    Uncaught (in promise) DOMException: Failed to execute 'setItem' on 'Storage': Setting the value of '_wow_xhr_log_completed_calls_' exceeded the quota. at e.setCompletedCalls (eval at executeScript (:1:1), <anonymous>:3:8618) at e.afterXHR (eval at executeScript (:1:1), <anonymous>:3:8489) at eval (eval at executeScript (:1:1), <anonymous>:3:13335) at eval (eval at executeScript (:1:1), <anonymous>:3:12640) at Object.eval [as next] (eval at executeScript (:1:1), <anonymous>:3:12745) at a (eval at executeScript (:1:1), <anonymous>:3:11483)

    bug 
    opened by jduraisamy 3
Releases(v1.0.0)
Owner
Sudharsan Selvaraj
Senior Test Engineer | Automation enthusiast | TestNinja
Sudharsan Selvaraj
A sample repo to help you capture JavaScript exception for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to capture JavaScript exception for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Wi

null 12 Jul 13, 2022
A sample repo to help you clear browser cache with Selenium 4 Java on LambdaTest cloud. Run your Java Selenium tests on LambdaTest platform.

How to clear browser cache with Selenium 4 Java on LambdaTest cloud Prerequisites Install and set environment variable for java. Windows - https://www

null 12 Jul 13, 2022
A sample repo to help you emulate network conditions in Java-selenium automation test on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to emulate network conditions in Java-selenium automation test on LambdaTest Prerequisites Install and set environment variable for java. Windows

null 12 Jul 13, 2022
A sample repo to help you capture JavaScript exception for automation test in Java-TestNG on LambdaTest. Run Selenium tests with TestNG on LambdaTest platform.

How to capture JavaScript exception for automation test in Java-TestNG on LambdaTest Environment Setup Global Dependencies Install Maven Or Install Ma

null 11 Jul 13, 2022
A sample repo to help you emulate network control using CDP in Java-TestNG automation test on LambdaTest. Run Selenium tests with TestNG on LambdaTest platform.

How to emulate network control using CDP in Java-TestNG automation test on LambdaTest Environment Setup Global Dependencies Install Maven Or Install M

null 12 Oct 23, 2022
Clear browser cache by running Selenium tests with JUnit on LambdaTest cloud.

Run Selenium Tests With JUnit On LambdaTest (Browser Cache Clearing Example) Blog β‹… Docs β‹… Learning Hub β‹… Newsletter β‹… Certifications β‹… YouTube      

null 16 Jul 11, 2022
Intercept network request by running Selenium tests with JUnit on LambdaTest cloud.

Run Selenium 4 Tests With JUnit On LambdaTest Blog β‹… Docs β‹… Learning Hub β‹… Newsletter β‹… Certifications β‹… YouTube       Learn how to use JUnit framewor

null 11 Jul 11, 2022
A sample repo to help you intercept network with Java-TestNG on LambdaTest cloud. Run Selenium tests with TestNG on LambdaTest platform.

How to intercept network with Java-TestNG on LambdaTest cloud Environment Setup Global Dependencies Install Maven Or Install Maven with Homebrew (Easi

null 12 Oct 23, 2022
Capture JavaScript error by running Selenium test with JUnit on LambdaTest cloud.

Run Selenium 4 Tests With JUnit On LambdaTest Blog β‹… Docs β‹… Learning Hub β‹… Newsletter β‹… Certifications β‹… YouTube       Learn how to use JUnit framewor

null 12 Jul 11, 2022
A sample repo to help you handle basic auth for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to handle basic auth for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - htt

null 12 Jul 13, 2022
A sample repo to help you run automation test in incognito mode in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to run automation test in incognito mode in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - htt

null 12 Jul 13, 2022
A sample repo to help you handle cookies for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to handle cookies for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - https:

null 13 Jul 13, 2022
A sample repo to help you set geolocation for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to set geolocation for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows - https

null 12 Jul 13, 2022
A sample repo to help you find an element by text for automation test in Java-selenium on LambdaTest. Run your Java Selenium tests on LambdaTest platform.

How to find an element by text for automation test in Java-selenium on LambdaTest Prerequisites Install and set environment variable for java. Windows

null 12 Jul 13, 2022
πŸŸͺ DeepfakeHTTP is a web server that uses HTTP dumps as a source for responses.

DeepfakeHTTP – Your 100% static dynamic backend DeepfakeHTTP is a web server that uses HTTP dumps as a source for responses. What are people using it

null 445 Dec 30, 2022
Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium web browsers, or anything else that can run in a Docker container.

Testcontainers Testcontainers is a Java library that supports JUnit tests, providing lightweight, throwaway instances of common databases, Selenium we

null 6.7k Jan 9, 2023
This repository includes selenium tests examples using cucumber-jvm framework.

Cucumber Selenium Tests This repository includes cucumber selenium tests examples using wikipedia.org. Run tests To run tests on your local machine, y

Denys Vozniuk 3 Nov 27, 2022
A sample repo to help you set device mode using CDP in Java-TestNG automation test on LambdaTest. Run Selenium tests with TestNG on LambdaTest platform.

How to set device mode using CDP in Java-TestNG automation test on LambdaTest Environment Setup Global Dependencies Install Maven Or Install Maven wit

null 11 Jul 13, 2022
πŸŽ‰Ultimate test automation for testing any application on any platform

boyka-java Ultimate test automation for testing any application on any platform boyka-java Setup Write conventional commits 1.

Wasiq Bhamla 52 Dec 30, 2022