# Overview

HyperTest is a no-code test automation tool designed to seamlessly integrate into your codebase and accelerate the process of generating unit tests for various types of service interfaces including HTTP, GraphQL, gRPC, Kafka, and RabbitMQ.

It focuses on auto-generating test cases that can be executed in isolation, free from external dependencies, by creating mocks.

HyperTest enables developers to catch logical bugs that could affect upstream or downstream services before their changes get merged.


# How It Works?

HyperTest operates in two modes: RECORD & REPLAY.\
The test case generation happens in RECORD mode and the Test Run is called the REPLAY.

There are 3 major components at play here:

* SDK: Facilitates capturing incoming/outgoing traffic by instrumenting libraries thus generating test cases and mocks, also it provides appropriate mocks in REPLAY mode.
* CLI: Runs Test by spinning up your app in isolation by injecting required mocks, replay's recorded traffic, and generates the report.
* HyperTest Server: Serves the HyperTest Dashboard and stores all the test cases and results.

<figure><img src="/files/sZq5HJLOkzq8a2BYh0aj" alt=""><figcaption></figcaption></figure>

### Real World Scenario:

With HyperTest SDK integration in place, when a Client makes an API call to the UI Gateway Service it in turn makes some requests to external services to give a response.

All the outbound calls to the downstream services such as Redis or Catalog Services are being recorded by HyperTest SDK with their responses to be mocked during REPLAY.\
\
The Catalog service is also instrumented with the SDK it captures the Incoming Request from Gateway Service and records it as a test case with its mocks.

### Testing:

Whenever a Test is Initiated by HT CLI, it spawns a new process of the Application Under Test and supplies the mocks required for boot via SDK.

After successfully starting the App it starts running the same requests(Test Cases) with the mocks and generates a regression report which can be accessed by the Dashboard.


# Node.js QuickStart Guide

This guide will walk you through integrating Hypertest into your Node.js application.\
In about 10 minutes, you'll capture your first tests, run them against your code, and see HyperTest automatically catch a bug.<br>

## Prerequisites

* A working Node.js application.
* Access to your HyperTest dashboard to get your API Key and Service ID.

{% hint style="warning" %}
Before adding HyperTest code, confirm your application starts correctly on your machine.

This ensures that any future issues are related to the integration, not your base application.

Start your app and hit a few requests to confirm this before proceeding further.
{% endhint %}

## 1. Update Project Files

First, modify package.json to include the required dependencies and scripts.

### **1. Update package.json**

Open your package.json and merge the following dependencies, devDependencies, and scripts.

```json
{
  "name": "my-awesome-app",
  "version": "1.0.0",
  // ... other properties

  "dependencies": {
    "@hypertestco/node-sdk": "0.2.28-96",  // check the latest version from npm
    // ... your other dependencies
  },
  "devDependencies": {
    "@hypertestco/ht-cli": "0.2.28-96", // check the latest version from npm
    "nyc": "^17.1.0",
    // ... your other devDependencies
  },
  "scripts": {
    "start": "node index.js", // <-- IMPORTANT: Ensure this runs your app
    // ... your other scripts

    "start-app-with-nyc": "nyc --nycrc-path .ht-nycrc npm start",
    "ht:test": "htcli start-new-test --config-file-path .htConf.js",
    "ht:update-coverage": "htcli update-coverage --config-file-path .htConf.js --deduplicate",
    "ht:update-packages": "htcli update-ht-packages --package-manager npm --config-file-path ./.htConf.js"
  }
}
```

### **2. Install Packages**

After saving the file, run this command in your terminal. It will read the updated package.json and install the new dependencies.

```bash
npm install
# or
yarn install
# or
pnpm install
```

### 3. Add Config Files in project root

Create two configuration files in your project's root directory.

#### **1. .ht-nycrc** (Tells nyc how to report coverage for HyperTest)

{% code title=".ht-nycrc" %}

```json
{
    "exclude": ["node_modules", ".htConf.js", "coverage", ".nyc_output", "ht-coverage"],
    "reporter": ["json-summary", "html"],
    "report-dir": "ht-coverage",
    "cache": false
}
```

{% endcode %}

#### **2. .htConf.js** (Main configuration for the HyperTest CLI)

{% code title=".htConf.js" %}

```javascript
const requestTypes = { HTTP: 'HTTP' };

module.exports = {
  // --- Required Configuration ---
  htBackendBaseUrl: "<URL of your HyperTest server>",
  serviceIdentifier: "<your-service-identifier-from-dashboard>",
  appStartCommand: process.platform === 'win32' ? 'npm.cmd' : 'npm',
  appStartCommandArgs: ["run", "start-app-with-nyc"],

  // --- Optional but Recommended ---
  httpCandidateUrl: "http://localhost:3000",
  appWorkingDirectory: __dirname,
  appStartTimeoutSec: 90,
  masterBranch: 'main', // Or 'master'
  requestTypesToTest: [requestTypes.HTTP],
};

```

{% endcode %}

## 2. Instrument Your Application

Now, add the HyperTest SDK to your app's main entry point (e.g., index.js, server.js, app.ts etc).

### **1. Initialize the SDK**

Add this code to the **very top** of your entry file, before any other imports.

```typescript
// process.env.APPLY_HT_OTEL_PATCH = 'yes'; // Set this env only if opentelemetry is already being used in your application.
process.env.HT_MODE = process.env.HT_MODE || 'RECORD'; // TODO: REMOVE THIS LINE BEFORE DEPLOYING TO PRODUCTION

import * as htSdk from '@hypertestco/node-sdk'; // for esm/ts
// const htSdk = require('@hypertestco/node-sdk'); // for commonJS
htSdk.initialize({
    apiKey: '<your-api-key>', // <-- Get from HyperTest dashboard
    serviceId: '<your-service-identifier-from-dashboard>', // <-- Get from dashboard
    serviceName: '<organizationName:service-name>', // e.g., "acme-corp:user-service"
    exporterUrl: '<hypertest-logger-url>', // <-- Provided by the HyperTest team
});

// No imports or require calls should be made before htSdk.initialize is called.
// Fight your instincts and your linters for this :)

```

### **2. Mark the App as Ready**

Call htSdk.markAppAsReady() once your app is listening for requests.

```
// Example for an Express.js app
app.listen(3000, () => {
  console.log(`Listening for requests on http://localhost:3000`);
  // This tells HyperTest the app is ready for test replays.
  htSdk.markAppAsReady();
});
```

## 3. **Capture & Establish Baseline**

Let's generate your initial test suite and lock it in as the baseline.

### **1. Capture Tests**

&#x20;Start your app using the special nyc script.

```
npm run start-app-with-nyc
```

Now, use your app and make API calls (via Postman, cURL, etc.) to the endpoints you want to test. Check your HyperTest dashboard to see tests appear in real-time. When you're done, **stop your application** (Ctrl+C).

### **2. Establish Coverage Baseline**

Run this command to save the current code coverage as the "golden" version.

```
npm run ht:update-coverage -- --skip-git-uncommitted-check
```

{% hint style="danger" %}
The `update-coverage` command is only supposed to be run on your master branch beacuse that establishes your current baseline of both reponses and code coverage\
\
The `--skip-git-uncommitted-check` flag is for debugging only which lets `update-coverage` command run on any branch\
\
After integration, you'll not be using the `--skip-git-uncommitted-check` flag
{% endhint %}

## 4. **Catch Your First Bug!**

This is the magic moment. Let's introduce a bug and watch HyperTest catch it.<br>

### **1. Make a code change**

In one of your API endpoints captured previously, introduce a small breaking change (e.g., change a response message, status code, or calculation).

### **2. Run the Test**

Execute the main test command.

{% code fullWidth="false" %}

```bash
npm run ht:test
```

{% endcode %}

HyperTest will now start your app, replay the captured tests against your modified code, and compare the behavior against the baseline.

### **3. See the Results**

&#x20;The CLI will output a link to the test run on your HyperTest dashboard. Click it to see a detailed report of the regression you just introduced, complete with payload diffs and coverage changes.

\
\
**Congratulations! You have successfully integrated HyperTest.**

<br>


# Installation

This page shows to install hypertest server on a linux VM using docker compose

Lets quickly get you started with Hypertest. Our Setup can be done in two simple steps:

1. Deploy HyperTest Server
2. Integrate Node SDK


# Deploy HyperTest Server

This page shows to install hypertest server on a linux VM using docker compose

In this guide, we will install [HyperTest](https://hypertest.co/) in a new ubuntu VM.

{% hint style="warning" %}
The VM should preferably be latest Ubuntu version - 24.04.
{% endhint %}

{% hint style="info" %}
If you are using AWS EC2, you can reduce cost by installing HyperTest on a spot instance and attaching an elastic IP to it.
{% endhint %}

## Tech Stack Overview

[Docker](https://www.docker.com/): Docker is an open platform for developing, shipping, and running applications

[HyperTest](https://www.hypertest.co/): A No-code API testing tool

## Recommended Resources

Recommended minimum resources required to run HyperTest on a VM are as follows:

| 4 vCPU | 16 GB RAM | 100 GB Disk |
| ------ | --------- | ----------- |

## Prerequisites

{% hint style="info" %}
You should have root user access in VM
{% endhint %}

Your system should have the following installed:

1. [Docker](https://www.docker.com/): (>= 20.10.6)

### 1. Installing Docker

Check if you have docker installed in your VM already by using the following command

```bash
docker -v
```

If you don’t have docker, install it using the following command

```bash
curl -fsSL https://get.docker.com -o get-docker.sh && sudo sh get-docker.sh
```

> If you have an older version of docker (< 18.09.7), remove it and reinstall the latest version using above command

Check if docker is installed successfully by using the following command

```bash
docker -v
```

## Getting Started

### 1. Deploy HyperTest Services

Switch to sudo user

```bash
sudo -i
```

download the starter archive docker-compose.yml with the below content

<pre class="language-bash"><code class="lang-bash"><strong>mkdir -p /opt/hypertest
</strong>cd /opt/hypertest
curl -O https://hypertest-documentation-assets.s3.ap-south-1.amazonaws.com/docker-compose/ht-init.tar.xz
tar -xf ht-init.tar.xz

## verify contents using ls -a 
</code></pre>

You should now have these files

* docker-compose.yml
* dynamic.yml
* .env
* .htpasswd
* otel-collector.yml

**The following are the details of the env variables in the .env file**\
**These ports should be opened on your VM**<br>

```properties
HOST_TRAEFIK_STATS_PORT_TRAEFIK=8080
HOST_BACKEND_PORT_TRAEFIK=8001
HOST_LOGGER_PORT_TRAEFIK=4319
HOST_CONSUL_HTTP_PORT_TRAEFIK=8500
HOST_DB_PORT=16544
HOST_JAEGER_PORT=16687
HYPERTEST_VERSION=0.2.23-4
```

* HOST\_BACKEND\_PORT\_TRAEFI&#x4B;**:** 8001 - This is the port on which HyperTest Dashboard will be accessible by the users
* HOST\_LOGGER\_PORT\_TRAEFI&#x4B;**:** 4319 - This port will be used internally for mirroring traffic. You have to allow incoming traffic to HyperTest on this port from your application
* HOST\_CONSUL\_HTTP\_PORT\_TRAEFI&#x4B;**: 8500** - This port will be used to expose consul
* **HYPERTEST\_VERSION: 0.2.23-4** -  Version of HyperTest (Get the latest from the HT team)

Bring up the services by the following command

```bash
docker compose up -d
```

Verify the containers are up and running by `docker ps`&#x20;

HT Dashboard will be accessible on`http://<hypertest-vm-ip/domain>:<`HOST\_BACKEND\_PORT\_TRAEFIK`>`


# Creating your first User

Once the [hypertest server is deployed](/setup-guide/readme/deploy-hypertest-server), Go to hypertest dashboard at `http://<hypertest-vm-ip/domain>:<BACKEND_PORT>.`

You will be prompted to create a user. The first that you create will be an Admin User.

An Admin can add other users to the platform and give access to the existing services.

<figure><img src="/files/0WGbLkEDnHibrjTwkgPU" alt=""><figcaption></figcaption></figure>

Once you've logged in as an Admin user now you can add other users, and they can start creating their services and start testing.

<figure><img src="/files/7ISDQ7QBUaJnFwCRo5yZ" alt=""><figcaption></figcaption></figure>


# Adding your first service

Once you're done with [creating an user](/setup-guide/readme/creating-your-first-user), Go to the services dashboard and proceed to add your first service from the UI `http://<hypertest-vm-ip/domain>:<BACKEND_PORT>/#/services`

<figure><img src="/files/71XQ2axOmsUjSi6vYKE0" alt=""><figcaption></figcaption></figure>

Note the service identifier created. Click on the name of the service and it will be revealed here. This would be used to initialize your SDK.

<figure><img src="/files/JlOyvUf95blqmNV0yHeO" alt=""><figcaption></figcaption></figure>


# Integrate SDK


# Node.js


# Node.js SDK with CJS

How to add nodejs sdk into your application

## 1.  Installing node-SDK package

```bash
npm install @hypertestco/node-sdk --save-exact 
```

## 2.  Initializing sdk

#### &#x20;2.1 Adding SDK in code and Initialize&#x20;

* Initalize hypertest node sdk.

{% hint style="warning" %}
This needs to happen as early in your app as possible. Make sure no require/import call is made before these lines
{% endhint %}

```typescript
// process.env.APPLY_HT_OTEL_PATCH = 'yes'; // Set this env only if opentelemetry is already being used in your application.
process.env.HT_MODE = process.env.HT_MODE || 'RECORD'; // TODO: REMOVE THIS LINE BEFORE DEPLOYING TO PRODUCTION

import * as htSdk from '@hypertestco/node-sdk'; // for esm/ts
// const htSdk = require('@hypertestco/node-sdk'); // for commonJS
htSdk.initialize({
    apiKey: '<your-api-key>',
    serviceId: '<your-service-identifier-from-dashboard>',
    serviceName: '<organizationName:service-name>',
    exporterUrl: '<hypertest-logger-url>',
    // ignoredHostsForHttpReqs: ['abc.xyz.com', /^\d+\.abcd\.co(m|)$/],
    // disableInstrumentations: [] // htSdk.HtInstrumentations enum 
});

// No imports or require calls should be made before htSdk.initialize is called. Fight your instincts and your linters for this :)
```

#### 2.2 Mark app as ready

Call the markAppAsReady method when the app is ready to receive traffic, it indicates that tests can be started (This is important ONLY FOR REPLAY mode).

<pre class="language-javascript"><code class="lang-javascript">// Rest Application code...
// add htSdk.markAppAsReady(); when your app is ready to accept requests
<strong>app.listen(3000, () => {
</strong>  console.log(`Listening for requests on http://localhost:3000`);
  // Indicates the App has booted up successfully for REPLAY And Tests can be started
  htSdk.markAppAsReady();
});
</code></pre>

**2.3 Enable Test Creation**\
\
To enable hypertest, set the `HT_MODE` env variable to `RECORD` and start your app

```javascript
// Set this on top inside your JS app
process.env.HT_MODE = process.env.HT_MODE || 'RECORD';
```

OR while booting&#x20;

{% code fullWidth="false" %}

```bash
HT_MODE=RECORD node my-app.js

OR

export HT_MODE=RECORD
node my-app.js
```

{% endcode %}

#### 2.4 Set env if opentelemetry is already being used.

```javascript
// DO THIS ONLY IF YOU ARE USING OPENTELEMETRY ALREADY
// Set this on top inside your JS app
process.env.APPLY_HT_OTEL_PATCH = 'yes'; // Set this env only if opentelemetry is already being used in your application.
```

## 3. Verifying traffic is captured

Start sending http requests on your app running with hypertest sdk.

You should start seeing requests under All requests section on the dashboard

<figure><img src="/files/krogi7xn6W8mvMdR4l2e" alt=""><figcaption></figcaption></figure>


# Node.js SDK with ESM

How to add nodejs sdk into your application

## 1.  Installing node-SDK package

```bash
npm install @hypertestco/node-sdk --save-exact 
```

## 2.  Initializing sdk

#### &#x20;2.1 Adding SDK in code and Initialize open telemetry sdk with hypertest

* ***Create a new file*** and add this code to initialize hypertest node sdk, then import that file at the top of your entryfile.

{% hint style="warning" %}
It is necessary to initialize sdk in a separate file and then import that file at the top of your entry file. This is needed with esm because imports are loaded before the file's code is run.
{% endhint %}

{% hint style="warning" %}
Hypertest sdk needs to be initialized as early as possible. Make sure no require/import call is made before that.
{% endhint %}

```typescript
// import * as htSdk from '@hypertestco/node-sdk'; // for esm/ts
const htSdk = require('@hypertestco/node-sdk'); // for commonJS
htSdk.initialize({
    apiKey: '<your-api-key>',
    serviceId: '<your-service-identifier-from-dashboard>',
    serviceName: '<organizationName:service-name>',
    exporterUrl: '<hypertest-logger-url>',
    // ignoredHostsForHttpReqs: ['abc.xyz.com', /^\d+\.abcd\.co(m|)$/],
    // disableInstrumentations: [] // htSdk.HtInstrumentations enum. 
});
```

#### 2.2 Mark app as ready

Call the markAppAsReady method when the app is ready to receive traffic, it indicates that tests can be started (This is important ONLY FOR REPLAY mode).

<pre class="language-javascript"><code class="lang-javascript">// Rest Application code...
// add htSdk.markAppAsReady(); when your app is ready to accept requests
<strong>app.listen(3000, () => {
</strong><strong>  console.log(`Listening for requests on http://localhost:3000`);
</strong>  // Indicates the App has booted up successfully for REPLAY And Tests can be started
  htSdk.markAppAsReady();
});
</code></pre>

#### 2.3 Use hypertest esm hooks

Give hypertest's esm hooks to the node's esm hooks loader API. This will happen where you start your app with node

```bash
HT_MODE=RECORD node --loader=@hypertestco/node-sdk/hooks.mjs my-app.js
```

{% hint style="warning" %}
*ts-node* or *tsx* can't be used to run your project. Your source code needs to be transpiled to js and then run using node.
{% endhint %}

To enable hypertest, set the `HT_MODE` env variable to `RECORD` and start your app

{% hint style="warning" %}
HT\_MODE can't be set at the top of your entryfile like this.

```javascript
// DO NOT DO THIS AT ALL FOR ESM !!!
process.env.HT_MODE = process.env.HT_MODE || 'RECORD';
```

It only works with cjs because cjs preserves the order of execution of code. Esm imports all modules before the file's code is run.
{% endhint %}

HT\_MODE needs to be set on boot

{% code fullWidth="false" %}

```bash
HT_MODE=RECORD node my-app.js

OR

export HT_MODE=RECORD
node my-app.js
```

{% endcode %}

#### 2.3 Set env if opentelemetry is already being used.

```
// Set this on top inside your JS app
process.env.APPLY_HT_OTEL_PATCH = 'yes'; // Set this env only if opentelemetry is already being used in your application.
```

## 3. Verifying traffic is captured

Start sending http requests on your app running with hypertest sdk.

You should start seeing requests under All requests section on the dashboard

<figure><img src="/files/krogi7xn6W8mvMdR4l2e" alt=""><figcaption></figcaption></figure>


# Java

How to add java sdk into your application

## 1.  Installing java-SDK package

HyperTest's Maven packages are hosted on a GitHub public Maven registry.\
To install and use HyperTest's `java-sdk` package in your application, follow these steps:

1. Create MVN\_TOKEN - The Hypertest Team may share this with you, or you can generate your own personal access token by visiting [GitHub Personal Access Tokens](https://github.com/settings/tokens).
2. Add Repository Configuration in `pom.xml`
   1. Define Properties in `pom.xml` file
   2. Add the Repository in  `pom.xml` file
3. Add the HyperTest agent dependency to your project. You can check for the latest version on the [HyperTest Java SDK](https://central.sonatype.com/artifact/co.hypertest/hypertest-agent/versions).
4. Install HyperTest's java-sdk package

Add the following content in your `pom.xml`

<details>

<summary>pom.xml</summary>

```xml
<dependencies>
    .
    .
    .
    
    <dependency>
        <groupId>co.hypertest</groupId>
        <artifactId>hypertest-agent</artifactId>
        <version>0.1.13-alpha.43</version>
    </dependency>
</dependencies>

<properties>
    <MVN_USERNAME>hypertestcustomers/[YOUR_GITHUB_USERNAME]</MVN_USERNAME>
    <MVN_TOKEN>[YOUR_MVN_TOKEN]</MVN_TOKEN>
</properties>

<repositories>
    <repository>
        <id>github</id>
        <url>https://${MVN_USERNAME}:${MVN_TOKEN}@maven.pkg.github.com/hypertestco/autoqa_v2_java</url>
    </repository>
</repositories>
```

</details>

We support multiple package manager&#x20;

1. Maven
2. Gradle
3. Bazel

To run with maven

```bash
mvn clean install
```

To run with gradle

```gradle
./gradlew build
```

To run with bazel

```python
bazel run //:<YOUR-APPLICATION-MODULE>
```

## 2.  Initializing SDK

#### &#x20;2.1 Adding SDK in code

* Initalize the HyperTest Java SDK in the `public static void main` method of your service. This must be the first thing in your main method.
* \<HT\_SERVICE\_ID> is the identifier that we created in [**Adding your first service section**](/setup-guide/readme/adding-your-first-service)

{% hint style="warning" %}
This needs to happen as early in your app as possible.
{% endhint %}

```typescript
new HypertestAgentBuilder("<HT_SERVICE_ID>", "<YOUR_SERVICE_NAME>",  "<API_KEY>",
 "<LOGGER_URL>", "<APPLICATION_CLASS>").build();
```

#### 2.2 Mark app as ready

Call this method after `SpringApplication.run` when the app is ready to receive traffic, it indicates that tests can be started (This is important ONLY FOR REPLAY mode).

```javascript
// Rest Application code...
System.setProperty(APP_STATUS, UP_STATUS);
```

To enable hypertest, set the `HT_MODE` env variable to `RECORD` and start your app

## 3. Verifying traffic is captured

Start sending http requests on your app running with hypertest sdk.

You should start seeing requests under All requests section on the dashboard

<figure><img src="/files/krogi7xn6W8mvMdR4l2e" alt=""><figcaption></figcaption></figure>


# Start a Test Run

Please select your plaform from the below options to get started on running a test.


# Node

## Prerequisites

### 1. Install/update ht-cli npm package

<pre class="language-bash"><code class="lang-bash"><strong>npm install -g @hypertestco/ht-cli --save-exact
</strong></code></pre>

Verify htcli has been installed using the below command:

```bash
htcli --help
```

## Getting Started:

### 1. Create a Test Configuration File

Available Configurations:

{% code title=".htTestConf.js" fullWidth="false" %}

```javascript
const requestTypes = {
  HTTP: 'HTTP',
  GRAPHQL: 'GRAPHQL',
  KAFKA: 'KAFKA',
  GRPC: 'GRPC',
  AMQP: 'AMQP',
};

module.exports = {
  htBackendBaseUrl: "", // URL of HyperTest server (Required)
  serviceIdentifier: "", // UUID for the service (Required)
  requestTypesToTest: [requestTypes.HTTP], // What kind of requests to include in the test
  httpCandidateUrl: "", // HTTP URL of App under test (Optional)
  // graphqlCandidateUrl: "", // GraphQL URL of App under test (Optional)
  appStartCommand: process.platform === 'win32' ? 'npm.cmd' : 'npm', // Command to start the app (Required)
  appStartCommandArgs: ["run", "start-app-with-nyc"],  // App start command arguments (Required)
  appWorkingDirectory: __dirname, // Working directory for the app (default: current working dir) (Optional)
  appStartTimeoutSec: 90, // Timeout in seconds for the start command (default: 10) (Optional)
  testBatchSize: 50, // Number of concurrent test requests (default: 50) (Optional)
  //testRequestsLimit": 10, // Number requests to test (Optional)
  //httpReqFiltersArr: [], // "<GET /users>", "<ANY REGEX:^/payments>" (Optional)
  htExtraHeaders: { // Object containing additional headers for HyperTest server requests (Optional)
    // authorization: 'Basic ' + Buffer.from('USERNAME:PASSWORD').toString('base64')
  },
  // httpReqsToTest: [], // specific http requests to be tested can be mentioned. Request Id can be taken from "All Requests" page in dashboard.
  // graphqlReqsToTest: [], // specific graphql requests to be tested can be mentioned.
  // grpcReqsToTest: [], // specific grpc requests to be tested can be mentioned.
  // kafkaReqsToTest: [], // specific kafka requests to be tested can be mentioned.
  // amqpReqsToTest: [], // specific amqp requests to be tested can be mentioned.
  // tags: [{name: '', value: ''}], // requests which contain the mentioned tags will be tested. Refer Tags under "User Guides/Node.js SDK" for more information.
  
  // exitCodeSetter({ testResult }) {
  //  console.log('==test results==')
  //  console.log(testResult)
  //  return 0;
  //},
 
  // exclusionStringsForDifferences: [], // e.g., ['01\.02\.03\.04', 'HyPeRtEsT'],
  // reservedAppPorts: [], // Ports used by the host application e.g., [3001,4001]
};
```

{% endcode %}

Please refer this [link](/user-guides/node.js-sdk/type-references) for param type references in filterFunctionToIgnoreMockDiffs and filterFunctionToIgnoreResponseDiffs.

### 2. CLI token generation

Please follow this [link](/user-guides/node.js-sdk/cli-login#id-1-if-running-test-in-ci) to complete token generation if test is being run in CI env.

Please follow this [link](/user-guides/node.js-sdk/cli-login#id-2-if-running-test-on-local) to complete CLI login if test is being run in local.

### 3. Start new test

Start a new test by running this command.

```
htcli start-new-test --config-file-path ./.htTestConf.js
```

Open the help to list all possible options available

```
htcli start-new-test --help
```

### 4. Update HT Packages

The following command updates the ht-cli and node-sdk packages to the latest deployed backend version. Please refer this [link](/user-guides/node.js-sdk/update-ht-cli-and-node-sdk) for addtional details.

```
htcli update-ht-packages --package-manager <package manager name> --config-file-path <path-to-your-cli-config>
```

### 5. Update Code Coverage

The following command saves the code coverage of your application's requests on the latest master branch to the hypertest backend. Please refer this [link](/user-guides/node.js-sdk/code-coverage-based-features/updating-test-coverage) for additional details.

```
htcli update-coverage --config-file-path <path-to-your-cli-config>
```

### 6. Adding Hypertest CLI commands as scripts to your app's package.json

The best way to utilize the CLI commands is to add them as scripts in your package.json and use them flexibly in your CI and local env's.

<pre><code>// App's package.json
{
    "scripts" : {
<strong>        "run-test": "htcli start-new-test --config-file-path ./.htConf.js",
</strong>        "update-ht-packages" : "htcli update-ht-packages --package-manager &#x3C;package manager name> --config-file-path ./.htConf.js",
        "update-cov": "htcli update-coverage --config-file-path ./.htConf.js"
    }, 
}
</code></pre>

### 7. Test reports

After the test is completed. You can see the results on the dashboard under Test Results

<figure><img src="/files/hRp5HWFvz1nWqcwFh7or" alt=""><figcaption></figcaption></figure>


# Java

## Prerequisites

### 1. Install/update ht-cli npm package

```
npm install -g @hypertestco/ht-cli --save-exact
```

Verify htcli has been installed using the below command:

```
htcli --help
```

## Getting Started:

### 1. Create a Test Configuration File

Navigate to root directory of your application and create a `.htTestConf.js` file

Available Configurations:

<pre class="language-javascript" data-title=".htTestConf.js" data-full-width="false"><code class="lang-javascript"><strong>const requestTypes = {
</strong>  HTTP: 'HTTP',
  GRAPHQL: 'GRAPHQL',
  KAFKA: 'KAFKA',
  GRPC: 'GRPC',
  AMQP: 'AMQP',
};

module.exports = {
  htBackendBaseUrl: "", // URL of HyperTest server (Required)
  htCliRefreshToken: "",  // Auth token for the CLI (Required)
  serviceIdentifier: "", // UUID for the service (Required)
  requestTypesToTest: [requestTypes.HTTP], // What kind of requests to include in the test
  httpCandidateUrl: "", // HTTP URL of App under test (Optional)
  // graphqlCandidateUrl: "", // GraphQL URL of App under test (Optional)
  appStartCommand: "mvn", // Command to start the app (Required)
  appStartCommandArgs: ["spring-boot:run"],  // App start command arguments (Required)
  appWorkingDirectory: __dirname, // Working directory for the app (default: current working dir) (Optional)
  appStartTimeoutSec: 30, // Timeout in seconds for the start command (default: 10) (Optional)
  showAppLogs: true, // Whether to show app logs (default: false) (Optional)
  shouldReportHeaderDiffs: false, // Whether to report differences in headers (default: false) (Optional)
  testBatchSize: 50, // Number of concurrent test requests (default: 50) (Optional)
  //testRequestsLimit": 10, // Number requests to test (Optional)
  //httpReqFiltersArr: [], // "&#x3C;GET /users>", "&#x3C;ANY REGEX:^/payments>" (Optional)
  htExtraHeaders: { // Object containing additional headers for HyperTest server requests (Optional)
    // authorization: 'Bearer xyz'
  },
  fastMode: true, // Default false. (aggregate requests only on the basis of request input and output schema - ignoring mock schemas)
  // httpReqsToTest: [], // specific http requests to be tested can be mentioned. Request Id can be taken from "All Requests" page in dashboard.
  // graphqlReqsToTest: [], // specific graphql requests to be tested can be mentioned.
  // grpcReqsToTest: [], // specific grpc requests to be tested can be mentioned.
  // kafkaReqsToTest: [], // specific kafka requests to be tested can be mentioned.
  // amqpReqsToTest: [], // specific amqp requests to be tested can be mentioned.
  // tags: [{name: '', value: ''}], // requests which contain the mentioned tags will be tested. Refer Tags under "User Guides/Node.js SDK" for more information.
  // shouldIgnoreErrStackTraceDiffs: true, // Stack trace differences are ignored in errors.(default: true) (Optional)
  
  // filterFunctionToIgnoreMockDiffs:({ mockDiff, currentMock, requestObj }) => { 
  //  // if false is returned then the diff will be ignored
  //  if(mockDiff?.originalValue?.langType === 'Date') return false;
  //  if(mockDiff?.evaluatedPath?.at(-1) === "url" || mockDiff?.evaluatedPath?.at(-2) === "headers") return false;
  //  if(mockDiff?.evaluatedPath?.at(-1) === "host") return false;
  //  return true;
  //},
  
  // filterFunctionToIgnoreResponseDiffs: ({ responseDiff, requestObj }) => { // Param Types are mentioned in Type References page
  // // if false is returned then the response difference will be ignored  
  //  if(responseDiff?.evaluatedPath?.at(-1) === "url" || evaluatedPath?.evaluatedPath?.at(-2) === "headers") return false;
  //  if(responseDiff?.evaluatedPath?.at(-1) === "host") return false;
  //  return true;
  //},
  // exitCodeSetter({ testResult }) {
  //  console.log('==test results==')
  //  console.log(testResult)
  //  return 0;
  //},
  // initialTimestamp: "", // Initial timestamp in ISO format (Optional)
  // finalTimestamp: "", // Final timestamp in ISO format (Optional)
  // cliServerHost: "", // HT CLI server Host to be Used by Clients(server ignores this) (default: localhost) (Optional)
  // sdkServerHost: "", // HT SDK server Host to be Used by Clients(server ignores this) (default: localhost) (Optional)
  // autoAcceptChangesInCaseOnlyNoiseDetected: false,
  // shouldIgnoreErrStackTraceDiffs: true,
  // exclusionStringsForDifferences: [], // e.g., ['01\.02\.03\.04', 'HyPeRtEsT'],
  // reservedAppPorts: [], // Ports used by the host application e.g., [3001,4001]
};
</code></pre>

Please refer this [link](/user-guides/node.js-sdk/type-references) for param type references in filterFunctionToIgnoreMockDiffs and filterFunctionToIgnoreResponseDiffs.

### Troubleshooting

#### Alternative Approach #1: Using `java -cp`

1. **Navigate** to your application's root directory.
2. **Compile** the application:

   ```bash
   mvn clean install
   ```
3. **Copy Dependencies**:

   ```bash
   mvn dependency:copy-dependencies -DoutputDirectory=target/dependency
   ```
4. **Update `.htConfig.js`:**
   * Replace `<YOUR-APPLICATION-MAIN-FILE>` with your main class.

**Updated `appStartCommand` Configuration:**

```javascript
appStartCommand: "java", // Command to start the application (Required)
appStartCommandArgs: [
  "-cp",
  "target/classes:target/dependency/*",
  "<YOUR-APPLICATION-MAIN-FILE>"
]
```

#### Alternative Approach #2: Using `bazel run`

1. **Navigate** to your application's root directory.
2. **Run the Application**:

   ```bash
   bazel run //:<YOUR-BAZEL-MODULE>
   ```
3. **Update `.htConfig.js`:**
   * Replace `<YOUR-APPLICATION-MAIN-FILE>` with your main class.

**Updated `appStartCommand` Configuration:**

```javascript
appStartCommand: "bazel", // Command to start the application (Required)
appStartCommandArgs: [
  "run",
  "",
  "<YOUR-APPLICATION-MAIN-FILE>"
]
```

### 2. CLI token generation

Please follow this [link](/user-guides/node.js-sdk/cli-login#id-1-if-running-test-in-ci) to complete token generation if test is being run in CI env.

Please follow this [link](/user-guides/node.js-sdk/cli-login#id-2-if-running-test-on-local) to complete CLI login if test is being run in local.

### 3. Start new test

Start a new test by running this command.

```
htcli start-new-test --config-file-path ./.htTestConf.js
```

Open the help to list all possible options available

```
htcli start-new-test --help
```

### 4. Test reports

After the test is completed. You can see the results on the dashboard under Test Results

<figure><img src="/files/hRp5HWFvz1nWqcwFh7or" alt=""><figcaption></figcaption></figure>


# Interpreting  Test Results

In this section, we will understand how to interpret your results from a test.


# Test Results

Once you have run your test from CLI, you will be able to view the result from the dashboard itself. When you go to your service, it will be visible in 'Test Results'.

<figure><img src="/files/CYnxmTsdUAsWoAhtkkEj" alt=""><figcaption></figcaption></figure>

## Types of Results

These results have been categorized in five different ways. These are:-

* **Total Requests:** This is the list of all the requests run in a test.
* **Failed Requests:** Requests with regressions in response or outbound calls.
* **Passed Requests:** Requests with no regressions in response or outbound calls.
* **Mock Not Found:** It means that an outbound call was made by the application in the Replay Mode, however, in record mode no such outbound call was seen by HT.
* **AI Matched Mocks:** When HyperTest AI finds an outbound call during replay that does not have an exact same outbound call in Record, it matches it with one closest in schema to avoid Mock not founds.

You can open each one of these results and check for any regression or unusual behavior in your application.

&#x20;


# Understanding Results Categories

## 1. Passed Requests

These requests will have no regressions in the responses or their outbound calls.&#x20;

<figure><img src="/files/2lfwIk24u359YCleusrv" alt=""><figcaption><p>In this example, the response of the request or it's outbound calls show no regression.</p></figcaption></figure>

## 2. Failed Requests

Requests with regressions in responses or any of its outbound calls.

**2.1 Understanding a failed request**

Check any failed requests to understand what Hypertest reports. It asserts for response codes, schema and data across responses and outbound call. See the example below of a data regression

<figure><img src="/files/TdlIV9eXggT0oB9A97IR" alt=""><figcaption></figcaption></figure>

1. This is an example of **Value Modified,** in the path, '**newBalance**'.
2. Why did Hypertest report this problem.  When the API works fine, the field **newBalance** gets correctly updated when someone adds $500, as seen in **Expected Response**. However, when the code was updated it caused an error making it debit instead of credit the same amount. When HyperTest ran the request with the same data set it caught the difference you see in **newBalance.**&#x20;
3. We can magnify the scope of our investigation by looking at the JSON View, which tells us the actual difference in the form of a JSON file.

<figure><img src="/files/KC8tyeqlvd95VDxJQOVz" alt=""><figcaption></figcaption></figure>

**2.2 Checking the Outbound call responsible**

HyperTest can similarly assert the schema and data in outbound calls.

<figure><img src="/files/PH0IrqoEUoZU4QwGYKvy" alt=""><figcaption></figcaption></figure>

In the same example,  once the **NewBalance** is computed the service updates it to a database like PostgreSQL here. HyperTest asserts for schema and data in the db query like it did for API response above and reports a regression like you see above.


# Mock Not Found

Mock not found or Outbound call not found means that an outbound call was made by the application in the Replay Mode, however, it was not recorded by HyperTest in record mode.&#x20;

<figure><img src="/files/PJFfkt9B2BYuoKv3Sb2A" alt=""><figcaption></figcaption></figure>

## Why it happens?

This corresponds to a change in your code that HyperTest cannot mock in replay since it was not seen before. Consider this as a new change

This can be understood as a change in the behavior in the application which was not present during the record mode, however, has resurfaced in the replay mode.

## Resolution

In case this behavior is expected, you can go ahead and click on 'Accept all changes' to validate this change.

<figure><img src="/files/EMcOu2MWL1r7IeInWarC" alt=""><figcaption></figcaption></figure>

**Note: Accepting all changes for any test means that a user is forcefully making sure that the following test has passed. It will go straight to the 'passed' section of the test.**


# AI Match Mocks

When HyperTest AI finds an outbound call during the Replay mode that does not have an exact same outbound call in Record mode, it matches this call with one closest in schema to avoid Mock Not Found scenarios.

<figure><img src="/files/4b1nXCZamvZqiGXxmQJr" alt=""><figcaption></figcaption></figure>

This is a best match scenario orchestrated by HyperTest's AI. It matches mocks of requests between record and replay with minimal difference in schema of the response as well as the outbound calls.

#### Let's try to understand this by taking an Example:

Suppose you've 2 APIs: createProduct and updateStock, and now you've introduced a new column to your stock table called "restockNeeded" whose value will be set on the count stock we have.\
\
When we recorded these 2 APIs we did not have that column, now in your new PR you've added it and you're trying to run a Test, you would see something like this:

<figure><img src="/files/Akebg85eSoIUaINqp9eL" alt=""><figcaption></figcaption></figure>

Both the APIs have reported a change that a new Key has been added to the **sequelize-mode-update** mock.

This has been made possible by AI matches, here we looked at all the available recorded mocks and decided to pick a closest mock to the current input of the mock and reported this change.


# Accepting Changes

## 1. Accepting Changes

Accept changes to confirm to HyperTest that this is a desired change so that we do not report this in future. This is the same as updating your unit tests if they fail because of an intentional code change.

1. Click on 'Accept All Changes' when you see a failed request

<figure><img src="/files/1Cwgh0J9a83GCWPgqctt" alt=""><figcaption></figcaption></figure>

2. Once this is done, you will get a prompt confirming if you want to accept these changes or undo this operation.&#x20;

<figure><img src="/files/7dSUfF4XYuEiR7bwlPSa" alt=""><figcaption></figcaption></figure>

2. If you want to move ahead, click on 'Confirm & Submit' else you can go ahead and Undo these changes.

This feature is particularly useful when you want to accept your results, be it a 'Mock Not Found' or 'AI Matched' result, and just merge your changes to your main branch.

**Note: Accepting all changes for any test means that a user is forcefully making sure that the following test has passed. It will go straight to the 'passed' section of the test.**

## 2. Bulk Accepting Changes

Like accepting intended code changes for one particular API, you can also filter the test cases based on certain difference criteria's and accept changes in Bulk.\
\
First you've to enable the bulk actions like this:

<figure><img src="/files/5xXu8baeOzny7il1HcMs" alt=""><figcaption></figcaption></figure>

Then click on filters to select the particular difference for which you want to bulk accept changes:

<figure><img src="/files/ZdmlUzJbi2Q4Ek0Z3Jod" alt=""><figcaption></figcaption></figure>

Then click on Accept Changes to update these test cases:\
&#x20;

<figure><img src="/files/t1mNGqgYQ9NXhKjvAwgq" alt=""><figcaption></figcaption></figure>

This tells us that accept changes job completed successfully:

<figure><img src="/files/LDpIkILjoUHKuhbgahYo" alt=""><figcaption></figcaption></figure>

## 3. Mark as Noise

Mark those changes as Noise where an output value gets changed quite often and this change is not related to any regression in your code. For e.g. time stamp changes, geographical values(latitude & longitude), etc. from a geolocation application can give different values for same inputs.\
\
We try to detect frequently changing values on our own, but in certain scenarios we might not be able to detect it e.g., a timestamp resolution that changes every mins/hours.

We encourage you to write rules to ignore these fields for reporting of difference, you can checkout its documentation [here](/user-guides/ignoring-differences). This is because we would like to keep the accumulating test data minimal which could affect the test run performance.\
\
Use of this feature is encouraged for rare scenarios where same issue is not observed in other APIs/Tests.

You just need to:

1. Click on the error and select 'Mark as Noise'.
2. Click on 'Accept all Changes'

<figure><img src="/files/yqHOhVW42gdYyT1O1zo3" alt=""><figcaption></figcaption></figure>

This will help HyperTest identify that these changes are noise and it will not report them as error in future.


# Node.js SDK


# Limit memory usage

Hypertest provides an inbuilt way to limit your memory usage to avoid using too much memory. You can provide us a config to limit the memory usage that looks like this.

```typescript
htSdk.setMemoryUsageLimiterConfig({
  memoryUsageUpperThresholdMB: 500, // megabytes
  memoryUsageLowerThresholdMB: 400, // megabytes
  memoryCheckIntervalMs: 10, // Milliseconds
});
```

***memoryUsageUpperThresholdMB*** is the upper bound for memory. Hypertest will get disabled if your memory consumption goes above this value.

***memoryUsageLowerThresholdMB*** is the lower bound for memory. Hypertest will get enabled if your memory consumption goes below this value.

***memoryCheckIntervalMs*** is the value in milliseconds. Hypertest calls the `process.memoryUsage` API periodically with an interval of this value.

***memoryUsageUpperThresholdMB*** and ***memoryUsageLowerThresholdMB*** are required fields whereas ***memoryCheckIntervalMs*** has a default value of 10 milliseconds if you don't provide it.


# Supported NPM packages

List of NPM packages that are automatically mocked by HyperTest

{% embed url="<https://docs.google.com/spreadsheets/d/e/2PACX-1vQ_5djCr9fd-XZFVjlw8lP9GxYkXTMfTduzS3jS62ybUkL0AzSkfC8Ms-9GorZnnzgm6sucMhKqL9Iv/pubhtml?gid=568039904&single=true>" fullWidth="true" %}


# Mock Dependencies Manually

HyperTest provides a way for you to manually mock certain dependencies that are not instrumented automatically.

Please check the list of [automatically instrumented packages](/user-guides/node.js-sdk/supported-npm-packages), before proceeding with manual mocks.

These mocks also come in handy when you want to reduce false positives in the test reports caused by a utility that returns arbitrary values e.g., timestamps, and UUIDs.&#x20;

Let's look at an example where manual mocks can be utilized.

Below is an API route that generates PROMO code for a user.

```javascript
function generatePromoCode(userId) {
  // Generate a unique promo code based on userId or any other logic
  const uniquePart = uuidv4().split('-')[0]; // Take the first part of a UUID
  return `PROMO-${uniquePart}-${userId}`;
}

app.post('/generate_promo_code', (req, res) => {
  const { emailId } = req.body;
  const userInst = db.User.findOne({ where: { emailId } });
  
  const promoCode = generatePromoCode(userInst.id);
  res.json({ promoCode });
});
```

If we record this API interaction and run a Test then HyperTest will report a value-modified error, but this is a false positive and it's not a real change that was made in the logic.

<figure><img src="/files/i9343ioVa2pR9mipljhY" alt=""><figcaption></figcaption></figure>

To eliminate this recurrent issue we can manually mock the generation of the Promo code. When we re-record this API interaction we will also have the exact value of the Promo code that was generated and the same will be used in the Test.

```javascript
const { createManualMock } = require('@hypertestco/node-sdk');

app.post('/generate_promo_code', (req, res) => {
  const { emailId } = req.body;
  const userInst = db.User.findOne({ where: { emailId } });
  
  const promoCode = createManualMock({
    uniqueIdentifier: 'generatePromoCode',
    defaultValue: 'PROMO-DEFAULT-123',
    execFn() {
      return generatePromoCode(userInst.id);
    },
  });

  res.json({ promoCode });
});

function generatePromoCode(userId) {
  // Generate a unique promo code based on user_id or any other logic
  const uniquePart = uuidv4().split('-')[0]; // Take the first part of a UUID
  return `PROMO-${uniquePart}-${userId}`;
}
```

To create a manual mock you need to give these input params:

* uniqueIdentifier: An identifier is needed to pick the right mock during REPLAY, if you are making the same kind of function calls then consider adding a number to the identifier.
* defaultValue: A default value is required for a case where we are unable to find the recorded mock, e.g., you changed the identifier value or added a new manual mock and if we run an old recorded test that has different mocks then this default value will be used.
* execFn: This is a wrapper function that contains the logic you want to mock manually, in RECORD mode the return value of this function will be kept to use in the REPLAY mode(Test).

If we run a test with the manual mock in place it passes.

<figure><img src="/files/3LrWXF7AUkSRlYIL7Z98" alt=""><figcaption></figcaption></figure>

### Manual Mock V2

Allows you to capture mocks with a readable input, which will help you better understand the mocks on the dashboard.\
\
Example:

```typescript
// Async function to check, create, truncate, insert, and select data from a table
async function createTableIfNotExistAndGetData({ users }: {
  users: { name: string; age: number }[]
}) {
  // Logic...
}


const htPatchedFunction = htSdk.createManualMockV2({
  functionType: 'ASYNC',
  identifier: 'createTableIfNotExistAndGetData',
  originalFn: createTableIfNotExistAndGetData,
  thisValue: this,
});

app.get('/test/manualMockV2/async', async (req, res) => {
  const users = [{ name: 'A', age: 2 }, { name: 'B', age: 3 }, { name: 'C', age: 4 }];
  const result = await htPatchedFunction({ users });
  res.send(result);
});


```

### Input Parameters:

#### 1. **identifier** (`string`):

* A unique name for the mock function.
* Used for correctly Identifying the mock during REPLAY.

**Example**: `'mock-getUserData'`

#### 2. **originalFn** (`Function`):

* The original function being mocked.
* This function can be synchronous, asynchronous, or callback-based.

#### 3. **functionType** (`FunctionTypeEnum`):

* Describes the type of function being mocked:
  * `SYNC`: For synchronous functions.
  * `ASYNC`: For functions that return a `Promise`.
  * `CALLBACK`: For functions that take a callback.

#### 4. **thisValue** (`unknown`):

* The value to bind as `this` when the `originalFn` is called.
* Defaults to the current `this` context, but can be any custom object or value.

#### 5. **normalizeInputFn** (`Function`, optional):

* A function that normalizes or transforms the input arguments.
* It accepts the same arguments as `originalFn` and returns an object with normalized input values.
* Return value of this function will be used as readableInput and would be used for display on dashboard.

**Example**:

```typescript
const normalizeInputFn = (...args) => ({ input1: args[0], input2: args[1] });
```


# CLI Login

## 1. If running tests in CI env. <a href="#id-1-if-running-test-in-ci" id="id-1-if-running-test-in-ci"></a>

a. Go to your accounts page

<figure><img src="/files/5OkzmFZ4IA33WR8ykXzJ" alt=""><figcaption></figcaption></figure>

b. Click to create a new CLI token

<figure><img src="/files/KIjDTICp9oDdaWtKzJWJ" alt=""><figcaption></figcaption></figure>

c. Copy the newly generated CLI token and add it as a env var with key "HT\_CLI\_REFRESH\_TOKEN"

<figure><img src="/files/V91DYiK92y1nPSKpRlfk" alt=""><figcaption></figcaption></figure>

## 2. If running tests locally. <a href="#id-2-if-running-test-on-local" id="id-2-if-running-test-on-local"></a>

a. Once the test is started, cli will prompt the user to login by opening the dashboard url.

b. If cli is unable to open the url then it will log the url, user can manually click on the link to open dashboard.

<figure><img src="/files/rBxrrljrbic7F3OzPGBL" alt=""><figcaption></figcaption></figure>

c. User can login with SSO or email password option.

d. Once login is successful the user is redirected to accounts page where the cli token is generated if it doesn't exist and the test execution will resume.

<figure><img src="/files/nwtpmTjvccxCszxQ4uJV" alt=""><figcaption></figcaption></figure>

e. If the cli session times out then the process needs to be repeated. Once the token is saved in local, the same token will be reused for future test runs.


# Unmocking/Passing Through

This page documents how to tell the hypertest sdk to not mock certain parts of your code.

{% hint style="danger" %}
UnMocked Calls will be called as-is in both RECORD and REPLAY modes. Any network calls make inside the  callback of `executeUnmocked()`  would be actually made&#x20;
{% endhint %}

```typescript

import * as htSdk from '@hypertestco/node-sdk';
/**
   .. code normally instrumented by hypertest
**/

// old code
// const axiosResponse = await axios.post('https://myexampleurl.com/api/v1/sample', {"key":"value"});


// new code
const axiosResponse = await htSdk.executeUnmocked(async () => {
  // Anything called here is not captured/mocked by hypertest in any mode
  
  await axios.post('https://myexampleurl.com/api/v1/sample', {"key":"value"});
  // the above http call would not be captured by hypertest during record mode.
  // it would actually hit myexampleurl.com in replay mode.
  
})
```


# Sampling and blocking requests

## Sampling

### How it works

It is possible that while using hypertest sdk the latency of your APIs increase. Hypertest provides a mechanism called sampling to deal with this. There are three sampling paradigms in hypertest.

### Paradigm 1 - Adaptive sampling

Under this paradigm we make a prediction if the next incoming request will be unique or a duplicate. This prediction is based on the coverage data of each request that we record. As we encounter less and less unique cases, the probability of recording a request decreases. If we encounter more unique cases the probability of recording adapts and goes up.

#### Code

```typescript
htSdk.setSamplingConfig({
  http: [
    {
      path: '/user/signup',
      method: '*',
      useAdaptiveSampling: true,
    }
  ]
})
```

### Paradigm 2 - Cool off time intensive requests

Under this paradigm, sdk stops recording for requests that take too long to execute. Maximum response time and the corresponding cool off period are configurable. The requests taking more than maximum response time are blocked for time mentioned in coolOffPeriod. So, the next time such a request comes it wont be recorded, decreasing your latency.

#### Code

```typescript
htSdk.setSamplingConfig({
  http: [
    {
      path: '/user/signup',
      method: '*',
      coolOffPeriodMs: 10 * 1000,
      maxResponseTimeMs: 5000,
    }
  ]
})
```

### Paradigm 3 - Sampling rate

Third way is by specifying the sampling rate for requests. Example: A sampling rate of 65 percent would mean, out of all the requests roughly 65 percent would actually end up recorded, other 35 would be blocked.

#### Code

```typescript
htSdk.setSamplingConfig({
  http: [
    {
      path: '/user/signup',
      method: '*',
      samplingRate: 0.65,
    }
  ]
})
```

### Using multiple paradigms together

These three paradigms can be used together and are additive in nature.

{% code overflow="wrap" %}

```typescript
htSdk.setSamplingConfig({
  http: [
    {
      path: '/user/signup',
      samplingRate: 1,
      coolOffPeriodMs: 10 * 1000,
      maxResponseTimeMs: 5000,
    },
    {
      path: '*',
      coolOffPeriodMs: 10 * 1000,
      maxResponseTimeMs: 5000,
      useAdaptiveSampling: true,
    }
  ],
  grpc: [
    {
      service: 'Service1.greeter',
      method: 'SayHello',
      coolOffPeriodMs: 10 * 1000,
      maxResponseTimeMs: 5000
    }
  ]
});
```

{% endcode %}

You can provide a list of configs for a protocol, each targetting a group of requests. The sdk starts matching the requests from top to bottom. There exists a default config for sampling at the bottom of the list by default that looks like this. It matches with all the requests, providing a fallback in case no configs match.

```typescript
{
  path: '*',
  method: '*',
  samplingRate: 1,
  maxResponseTimeMs: 10 * 1000,
  coolOffPeriodMs: 60 * 1000
}
```

## Blocking requests

Hypertest sdk allows you to specify a config to stop recording certain requests. You can specify the method and the path of the request you want to be be blocked.

```typescript
htSdk.setBlockRequestsConfig({
  http: [
    {
      path: '/sampling/blocking'
    },
    {
      path: '/test/blocking',
      method: '*'
    },
    {
      path: /sampling\/blocking/,
      method: 'put'
    },
    {
      path: '/sampling/:id'
    },
    {
      path: '/sampling/{id}'
    }
  ],
  grpc: [
    {
      service: 'helloworld.Greeter',
      method: '*'
    }
  ]
})
```

* Method is a string that takes '\*' or any valid http verb as value. It is case insensitive. If you dont specify it, it is assumed to be '\*' which matches it with all the possible verbs
* Path can take the absolute request path or a regex or the cluster path of the http request.


# Manage Global Variables

The kvStore utility within our Node.js SDK provides a key-value storage mechanism designed to capture and mock the state of global variables or objects accessed during API calls.

### Why mock Global Variables?

In the development of unit tests, especially within environments where global variables or objects are accessed or modified, it is crucial to maintain a consistent state across tests to ensure their reliability and accuracy.

Changes to the global state can lead to unpredictable behavior in tests, potentially resulting in false positives or negatives. This is particularly true in scenarios where tests run in parallel.

The `kvStore` utility addresses this issue by allowing developers to capture and mock the state of global variables or objects.

By doing so, it ensures that each test runs in a controlled environment, with predefined states, making the tests deterministic and independent of external factors or changes in the global state.

### How to use `kvStore`

The utility is straightforward to use, involving simple methods to **set**, **get**, and **remove** key-value pairs that represent the state of global variables or objects.

Consider a scenario where your e-commerce application uses a global configuration `shouldReturnStockQuantity` that dictates whether the platform displays the exact number of items left in stock (e.g., "Only 2 items left!") or a simple in-stock/out-of-stock message.

This mode affects how product APIs respond to queries on product details, influencing purchasing decisions.

```javascript
import { kvStore } from "@hypertestco/node-sdk";

// let SHOULD_RETURN_STOCK_QUANTITY = true; // old global variable
async function updateStockQuantityConfig() {
  setInterval(async () => {
    const { data: { shouldReturnStockQuantity } } = await axios.get('http://host/getConfig');

    // SHOULD_RETURN_STOCK_QUANTITY = shouldReturnStockQuantity;
    kvStore.set('shouldReturnStockQuantity', shouldReturnStockQuantity === true);
  }, 5 * 1000); // Poll every 5 seconds
}

updateStockQuantityConfig();

app.get('/getInventoryStats', (req, res) => {
  const inventoryStats = db.InventoryStats.find({
    select: {
      // stock: SHOULD_RETURN_STOCK_QUANTITY, // source of inconsistency
      stock: kvStore.get('shouldReturnStockQuantity'),
    }
  });


  res.json({ inventoryStats });
});
```

By using `kvStore` we ensure that the tests are immune to unpredictable behavior caused by external factors.


# Mocking Environment Variables

Sometimes, your app might behave differently depending on an ENV variable's value or presence/absence.

Ideally, you'd want the values of a few important ENV vars to be the same across RECORD and REPLAY modes. You can achieve this by telling the hypertest sdk what these important ENV vars are.

Hypertest will monitor the important ENV vars in RECORD mode, and mock this value u REPLAY MODE transparently for you.

Monitoring only works in server contexts (inside an http/grpc/amqp etc request) and not for root contexts

&#x20;This is how you tell hypertest to monitior specific env vars\ <br>

```typescript
import * as htSdk from '@hypertestco/node-sdk';
htSdk.setImportantEnvVariables(['SAMPLE_ENV_VAR', 'ANOTHER_IMPORTANT_ENV_NAME']);
```

```javascript
/* sample usage in rest of app code */
app.get('/my_url', (req, res) => {
 // unrelated code
  if(process.env.SAMPLE_ENV_VAR === 'some_value') {
     console.log('do something')
  } else {
     console.log('do something else')
  }
  
  // unrelated code
  
});

```

You can only set important env variables once, so do this after the SDK has been initialized at the start of your application


# Tags

Tags are used to provide additional information for the request and contribute to a better control over deduplication. A request can only contain a unique tag with same name and value.

There are three types of tags.

1. Case
2. Label
3. Annotation

### 1. Case

Case is a tag that is used to create a mock at a particular branching which needs to be covered in a request and does not let it get deduplicated if there is a version of the same request already present.

Case is created with the following syntax in source code.

```
htSdk.htTags.addCase({name: 'case name', value: 'case value'});
```

Case contributes to the deduplicating hash and essentially creates a new version of the request if the latter was already present. Typically this is used to create different versions of the same request to increase code coverage and cover all branching statements.&#x20;

Case can also be added in the root context of an application. If a case is added in root context then the same case is inserted in every incoming request when the server span is created.

Case is created at root context with the following syntax in source code.&#x20;

```
htSdk.htRootTags.addRootCase({name: 'case name', value: 'case value'});
```

### 2. Label

Label is a tag that is used to create a mock inside a particular route to avoid more versions of the same request due to difference in response schema. If there is a label inside a request, then only the cases and labels are considered for creating the deduplicating hash value thereby retaining the desired version of the request.

Label is created with the following syntax in source code.

```
htSdk.htTags.addLabel({name: 'label name', value: 'label value'});
```

Label can also be added in the root context of an application. If a label is added in root context then the same label is inserted in every incoming request when the server span is created.

Label is created at root context with the following syntax in source code.&#x20;

```
htSdk.htRootTags.addRootLabel({name: 'label name', value: 'label value'});
```

### 3. Annotation

Annotation is a tag that is used to create an unimportant mock inside a route to provide additional context to the request. This does not contribute to the deduplicating hash.

Annotation is created with the following syntax in source code.

```
htSdk.htTags.addAnnotation({name: 'annotation name', value: 'annotation value'});
```

Annotation can also be added in the root context of an application. If a annotation is added in root context then the same annotation is inserted in every incoming request when the server span is created.

Annotation is created at root context with the following syntax in source code.&#x20;

```
htSdk.htRootTags.addRootAnnotation({name: 'annotation name', value: 'annotation value'});
```


# Set HTTP path patterns

Define HTTP path patterns for outbound calls to improve test case deduplication

Users can provide known HTTP endpoints which are called from their application to reduce the number of duplicate root mocks and test cases we record.

Hypertest does try to identify path params using its own in-house algorithm, but there might be some cases where the path params are not that generic and very customized to your use case.

In such cases you should provide the know patterns for HTTP endpoints that your application calls.

```javascript
htSdk.setOutboundHttpRequestPathPatterns([
  '/test/:custom_id'
]);
```


# Discard a test case(Request) while recording

For any reason if you want to avoid recording a request at run time you can use "discardRequest" API exposed by HyperTest SDK.

```typescript
app.get('/api/getProducts', async (req: Request, res: Response) => {
    const data = await getProducts();
    htSdk.discardRequest(); // discard recorded test case of the current request
    res.send(data);
});
```


# Set Git Commit Hash

How to set Git Commit Hash?

Hypertest provides a way to set the Git commit hash for your application. This enables accurate tracking of coverage across different builds which will helps in comparing coverage metrics across multiple versions.

You can directly set the Git commit hash by adding the below code to your `index.js`:

```javascript
htSdk.setGitCommitHash(<git-commitHash>);
```

{% hint style="info" %}
The above call to set git commitHash should be done before starting the coverage measurement using `htSdk.measureContinuousCoverage()`.
{% endhint %}


# Code coverage based features

Prerequisite for these features, add nyc to your project.

1. Install nyc

```bash
npm i nyc --save-dev
```

2. create .nycrc in your project ( or .ht-nycrc if you already have one )

Hypertest needs json-summary reporter to store the coverage summary. Hypertest expects reports to be present in ht-coverage folder.

```json
{
    "exclude":["node_modules", "htConfSample.js", "coverage", ".nyc_output", "ht-coverage"],
    "reporter": ["json-summary"],
    "report-dir": "ht-coverage",
    "cache": false
}
```


# Continuous Coverage

How to measure Continuous Coverage?

Continuous Coverage helps you measure the coverage of requests made to your application in real time. Once you start your app, Hypertest will begin tracking coverage from the beginning.

&#x20;This feature supports two modes:

* **RECORD**
* **DISABLED**

{% hint style="warning" %}
Make sure you go through the steps to add nyc to your project [here](https://docs-v2.hypertest.co/user-guides/node.js-sdk/code-coverage-based-features) before this.
{% endhint %}

### Steps to Measure Continuous Coverage

Follow these steps to enable and measure Continuous Coverage using Hypertest:

{% hint style="warning" %}
Make Sure you set the [Git Commit Hash](/user-guides/node.js-sdk/set-git-commit-hash) when measuring continuous coverage. It helps in accurately mapping the coverage data to the correct code version.
{% endhint %}

#### Step 1: Configure Continuous Coverage in Your App

Add the following code snippet to your app's `index.js` file:

```javascript
// App's index.js
htSdk.measureContinuousCoverage({
  backendBaseUrl: '<your-hypertest-backend-url>',
  htExtraHeaders: {},
  buildId: '',
  serviceId: '<your-service-identifier-from-dashboard>',
  refreshIntervalInSec: 60 // Default interval is 60 seconds
});
```

#### Step 2: Access the Hypertest Dashboard

1. Navigate to the **Hypertest Dashboard**.
2. Select your service and go to the **Continuous Coverage** page.
3. Click on the **Measure Continuous Coverage** button to start tracking.

*Example:*

<figure><img src="/files/SCoATm2AEEGViVuJ5wY5" alt=""><figcaption></figcaption></figure>

#### Step 3: Start Your App with NYC

Update the `start` command in your `package.json` to run your app with NYC:

```json
// App's package.json
{
  "scripts": {
    "start": "nyc <your app start command>"
  }
}
```

#### Step 4: View Real-Time Coverage

Once the app is running, Hypertest will update the coverage data automatically at intervals defined by `refreshIntervalInSec` (default: 60 seconds).

You can monitor the results on the Hypertest Dashboard.


# Updating test coverage

How to update test coverage ?

{% hint style="warning" %}
Make sure you go through the steps to add nyc to your project [here](/user-guides/node.js-sdk/code-coverage-based-features) before this.
{% endhint %}

Hypertest allows you to update coverage of the tests that have so far been recorded. This is run using a cli command. Running this will spawn your application instance, hit all the test cases recorded so far and store the code coverage generated.

{% hint style="warning" %}
Make sure that you checkout to your master (Or the branch that is your baseline for recording requests) and have no local changes before you run this command. We want to store the lines covered on master.
{% endhint %}

1. Create ht cli config file. This is the same that is used to run cli test.
2. Your app will be spawned using the command you give in the cli config. Make sure you run your app using nyc in that command. (Don't run the cli process with nyc, just your app)

Example

```json
// App's package.json
{
    "scripts" : {
        "start-app-with-nyc" : "nyc --nycrc-path <nyc-config-file> <your app start command>"
    }, 
}
```

3. Change the `appStartCommand` and `appStartCommandArgs` ( inside your cli config ) to the what you created in step 2.

Example:&#x20;

```json
{
  /*
    Rest of your cli config...
  */
  appStartCommand: 'npm',
  appStartCommandArgs: ['run', 'start-app-with-nyc'],
}
```

4. Please complete the CLI token generation as mentioned [here](/user-guides/node.js-sdk/cli-login).
5. Run the cli command to update coverage

```bash
htcli update-coverage --config-file-path <path-to-your-cli-config>
```


# Running post test deduplication

How to run post test deduplication ?

Once you record tests, you can update their coverages. In this process, we store the coverage for each test in db. This stored coverage is then used to deduplicate tests. Tests with same coverage are deleted from db.

{% hint style="warning" %}
Make sure you go through the steps to add nyc to your project [here](/user-guides/node.js-sdk/code-coverage-based-features) before this.
{% endhint %}

Go through the steps to update coverage [here](/user-guides/node.js-sdk/code-coverage-based-features/updating-test-coverage). Then add the `--deduplicate` flag to `update-coverage` command.

Please complete the CLI token generation as mentioned [here](/user-guides/node.js-sdk/cli-login).

```bash
htcli update-coverage --deduplicate --config-file-path <path-to-your-cli-config>
```


# Only testing modified requests

How to only test modified requests ?

This feature enables you to test only those requests that were modified in the new commits added. Hypertest considers a request to be modified when the code covered in that request gets modified. So this feature requires the code coverage of the requests to be updated using `htcli update-coverage` command. Requests not having code coverage are not tested.

1. Add nyc to your the command that starts your app. Follow [this](/user-guides/node.js-sdk/code-coverage-based-features/updating-test-coverage) for help
2. Add `shouldExcludeUnmodifiedRequests` in cli config

```json
// Your cli config
{
    /*
        ...Rest of your cli config
    */
    shouldExcludeUnmodifiedRequests: true
}
```

{% hint style="info" %}
We  don't need to know your master branch for this feature, we store the commitId while updating coverage. We use that to calculate git diff.
{% endhint %}

3. Run cli test


# Ignore differences for unmodified requests

How to ignore differences for unmodified requests?

After the test runs, there can be some requests that contain noises. Sometimes these noises can't be detected by hypertest and they are marked as errors. You can reduce the number of such noises using this feature. In this feature we will calculate the code coverage for a particular request, then check if there were any modifications in that part of code. Differences for unmodified requests are ignored. We use git diff to list the modifications. You are required to set your baseline branch to compute git diff in the cli config.

1. Add nyc to your the command that starts your app. Follow [this](/user-guides/node.js-sdk/code-coverage-based-features/updating-test-coverage) for help
2. Add this to your cli config

```json
// Your cli config
{
    /*
        ...Rest of your cli config
    */
    shouldIgnoreDifferencesInUnmodifiedRequests: true,
    masterBranch: <your-baseline-branch>
}
```

{% hint style="info" %}
This feature doesn't require you to store coverage for the baseline branch
{% endhint %}


# Experimental flags

For certain specific scenarios we have exposed experimental flags on sdk to cater to different edge cases in an application.

This above call to enable experimental flags should be done before initializing sdk.

```
htSdk.enableExperimentalFlags([]); // The desired "ExperimentalFlags" enum values should be passed in the array.

/*
ExperimentalFlags enum is available on htSdk.
The following are the supported flags.
enum ExperimentalFlags {
  EnableSqlite3Instrumentation,
  EnableRedisShortSubmoduleName,
  EnableMongooseConnectionUnmocking,
}
*/
```

Please contact hypertest support if you need more information to use them.&#x20;


# Manual Request

How to create a manual request ?

It is possible that your server requests operate using clients/servers that hypertest has not yet instrumented. You won't be able to record and replay requests for them. Hypertest provides a workaround for that known as manual requests. Manual request allows you to define your own server request and test them.

### How to create a manual request ?

Hypertest exposes the following API to create your own manual request

```typescript
const manualRequestResolver = htSdk.manualRequest.create({
  name: 'consumer-1',
  resolver: async (arg1, arg2) => {
    /* 
     *
     Your server request's business logic
    *
    */

    return output;
  },
  normalizeInputFn(arg1, arg2) {
    return { username: arg1, password: arg2 }
  },
  generateOutputForHt: (output: { conn: ConnectionObj, user: User }) => {
    return { user }
  }
})
```

1. `name`  is what uniquely identifies your manual request
2. `resolver` contains the business logic of your server request
3. `normalizeInputFn` This is an optional function, purpose of this function is to tell hypertest the meaning of input args of resolver, the labels you give here will be the ones you see on the dashboard while running tests. If you dont give, you will just see the input array without any labels for args
4. `generateOutputForHt` This is an optional function, purpose of this function is to remove things from the output that you dont wan't to test. It is possible that you might be returning connectionObj or something similar to that, that you don't want hypertest to test. You can use `generateOutputForHt` to return the output that you want to test

### What to choose as input ?

You can choose the input of your manual request as you wish (strings, Date, booleans, arrays, objects, numbers, bigints... etc),  the only restriction is that you can't send objects having methods on them that you will call in the resolver.

Don't give something like connection obj in the input of manual request. Hypertest has no context of which library is being used and it cannot provide the appropriate obj methods in replay. If you need something from the connection obj, extract that from the connection obj while preprocessing the input and pass the extracted data to your resolver.

{% hint style="warning" %}
Please note that hypertest only tests the code that you write inside the manual request resolver, anything outside it won't be tested.
{% endhint %}

### How to change your controller to use manual request ?

This example assumes you are using some kind of queue that you want to test using manual request

```typescript
// Your queue consumer 
queueClient.consume('consumer-1', async (input) => {
  /*
    Preprocess your input to extract the data you want to pass into the manualRequestResolver
  */
  
  // Call the manual request resolver to run your business logic
  const { user } = await manualRequestResolver(username, password);
  
  /*
    Do whatever you need to do post that;
  */
  queueClient.acknowledge(input.messageId);
})
```


# Only testing modified requests

How to only test modified requests ?

This feature enables you to test only those requests that were modified in the new commits added. Hypertest considers a request to be modified when the code covered in that request gets modified. So this feature requires the code coverage of the requests to be updated using `htcli update-coverage` command. Requests not having code coverage are not tested.

1. Add nyc to your the command that starts your app. Follow [this](/user-guides/node.js-sdk/code-coverage-based-features/updating-test-coverage) for help
2. Add `shouldExcludeUnmodifiedRequests` in cli config

```json
// Your cli config
{
    /*
        ...Rest of your cli config
    */
    shouldExcludeUnmodifiedRequests: true
}
```

{% hint style="info" %}
We  don't need to know your master branch for this feature, we store the commitId while updating coverage. We use that to calculate git diff.
{% endhint %}

3. Run cli test


# Server hooks

Server hooks, what are they? How to implement them ?

Hypertest provides server hooks to intercept incoming server requests and their responses. This is valuable when your requests and responses are encoded or encrypted. You can intercept your requests and responses via the hooks and write the decoding/decryption logic in the hooks

### How to implement ?

#### Http

Hypertest provides hooks for http request and response. There are two hooks each for both of them. A hook that runs in record mode and one that runs in replay mode.

1. Http request, record and replay hooks

An http request hook in record mode would usually deal with decrypting your http request and an http request hook in replay mode would be responsible to do the exact opposite of record mode hook (i.e encrypt or encode the request for your controller to consume)

```typescript
htSdk.hooks.httpServer.request.v1({
  beforeRecord({ readableInput, inputMeta, userMeta }) {
    // Write your decryption/decoding logic
    // console.log(readableInput, inputMeta, userMeta);

    return { inputMeta, readableInput, userMeta }
  },
  beforeReplay({ readableInput, inputMeta, userMeta }) {
    // Write your encoding/encryption logic
    // console.log(readableInput, inputMeta, userMeta);

    return { inputMeta, readableInput, userMeta };
  },
});
```

2. Http response, record and replay hooks

The purpose of a response hook in record and replay modes is to decode/decrypt the http response for hypertest.

```typescript
htSdk.hooks.httpServer.response.v1({
  beforeRecord({ realOutput, outputMeta, userMeta, }) {
    // Write your decryption/decoding logic
    // console.log(realOutput, outputMeta, userMeta);

    return { realOutput, outputMeta, userMeta }
  },
  beforeReplay({ realOutput, outputMeta, userMeta, }) {
    // Write your decryption/decoding logic
    // console.log(realOutput, outputMeta, userMeta);

    return { outputMeta, realOutput, userMeta };
  },
})
```

#### UserMeta

You can add any key value pairs in user meta. Its purpose is to facilitate you in marking certain requests. You can add a key value pair in record mode, and that would be given to you in the subsequent replay mode hooks. Then you can use the key value pairs present to take necessary actions.


# Update HT-CLI and Node-SDK

The following is the command to update HT-CLI and Node-SDK.

```
htcli update-ht-packages --package-manager <package manager name> --config-file-path <path-to-your-cli-config>
```

This command can be added as a script in your package.json and run it before every test run on CI or local to update the hypertest packages to the latest deployed version, in sync with the hypertest backed.

<pre><code><strong>// App's package.json
</strong>{
    "scripts" : {
        "update-ht-packages" : "htcli update-ht-packages --package-manager &#x3C;package manager name> --config-file-path &#x3C;path-to-your-cli-config>"
    }, 
}
</code></pre>


# Type References

The following object types are used in config for running a test in hypertest cli.

<details>

<summary>Response Difference</summary>

<pre class="language-markdown"><code class="lang-markdown">### responseDiff

<strong>Describes a single difference between expected response to the actual response.
</strong>
#### Properties

| Property Name          | Type                | Non-Optional | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|      
| `differenceSection`    | `DifferenceSection` | Yes          | The category of difference.               
| `differenceType`       | `DifferenceType`    | Yes          | This exemplifies the kind of difference.  
| `evaluatedPath`        | `string[]`          | Yes          | Path of the key abstracting array indices.
| `newPath`              | `string[]`          | Yes          | Path of the key in the actual response.   
| `newValue`             | `ValueType`         | Yes          | Value in the actual response.
| `originalPath`         | `string[]`          | Yes          | Path of the key in original response difference.
| `originalValue`        | `ValueType`         | Yes          | Value in the original response.
| `requestIdentifier`    | `string`            | Yes          | A unique key to identify a request.
| `requestType`          | `RequestType`       | Yes          | Type that distinguishes the server used.
| `severityScore`        | `number`            | Yes          | Severity of the error.


#### Enum: DifferenceSection

Possible values for DifferenceSection.

- `NOISY_ERROR`: error due to a ever changing value in a field.
- `ERROR`: Indicates that there was an error processing the request.

#### Enum: DifferenceType

Possible values for DifferenceType

- `VALUE_MODIFIED`
- `DATA_TYPE_CHANGED` and more.

#### ValueType

Keys present in ValueType

- `htType`: string
- `langType`: string
- `value`: any 

#### RequestType

Possible values for RequestType

- `HTTP`
- `GRAPHQL`
- `GRPC`
- `KAFKA`
- `AMQP`
<strong>
</strong></code></pre>

</details>

<details>

<summary>Mock Difference</summary>

<pre class="language-markdown"><code class="lang-markdown">### mockDiff

<strong>Describes a single difference between recorded mock to the actual mock.
</strong>
#### Properties

| Property Name          | Type                | Non-Optional | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|      
| `differenceSection`    | `DifferenceSection` | Yes          | The category of difference.               
| `differenceType`       | `DifferenceType`    | Yes          | This exemplifies the kind of difference.  
| `evaluatedPath`        | `string[]`          | Yes          | Path of the key abstracting array indices.
| `newPath`              | `string[]`          | Yes          | Path of the key in the actual response.   
| `newValue`             | `ValueType`         | Yes          | Value in the actual response.
| `originalPath`         | `string[]`          | Yes          | Path of the key in original response difference.
| `originalValue`        | `ValueType`         | Yes          | Value in the original response.
| `mockIdentifier`       | `string`            | Yes          | A unique key to identify a mock.
| `originalMockId`       | `bigint`            | Yes          | Mock Id corresponding to the recorded mock.
| `severityScore`        | `number`            | Yes          | Severity of the error.


#### Enum: DifferenceSection

Possible values for DifferenceSection.

- `NOISY_ERROR`: error due to a ever changing value in a field.
- `ERROR`: Indicates that there was an error processing the request.

#### Enum: DifferenceType

Possible values for DifferenceType

- `VALUE_MODIFIED`
- `DATA_TYPE_CHANGED` and more.

#### ValueType

Keys present in ValueType

- `htType`: string
- `langType`: string
- `value`: any 
<strong>
</strong></code></pre>

</details>

<details>

<summary>Current Mock</summary>

```markdown
### currentMock

Original mock recorded which now has a difference with the replayed mock.

#### Properties

| Property Name          | Type                | Non-Optional | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|
| `submoduleName`        | `string`            | Yes          | Submodule name of the mock.        
| `moduleName`           | `string`            | Yes          | Module name of the mock.               
| `id`                   | `bigint`            | Yes          | Recorded mock id.
| `OutputStatus`         | `OutputStatus`      | Yes          | Status of mock. 
| `readableInput`        | `object`            | Yes          | Mock input.
| `readableOutput`       | `object`            | Yes          | Mock output.   
| `err`                  | `object`            | Yes          | Mock error.

#### Enum: OutputStatus

Possible values for OutputStatus.

- `ERROR`
- `OKAY`
```

</details>

#### Request Object

{% tabs %}
{% tab title="HTTP" %}

```markdown
### requestObj

Describes the components of a recorded http request.

#### Properties

| Property Name          | Type                | Non-Opitonal | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|
| `i_bodyType`           | `BodyType`          | Yes          | Body type of the http request.        
| `i_clusterPath`        | `string`            | Yes          | Cluster path for the http request.               
| `i_headers`            | `object`            | Yes          | Headers for the request.  
| `i_method     `        | `string`            | Yes          | Verb of the request.
| `i_path`               | `string`            | Yes          | Actual path of the request.   
| `i_query`              | `object`            | Yes          | Query of the request.
| `id`                   | `bigint`            | Yes          | Id of the recorded request.
| `i_host`               | `string`            | Yes          | Host of the request.
| `i_jsonBody`           | `object`            | Yes          | Request body.
| `requestType`          | `RequestType`       | Yes          | Server type.
| `o_jsonBody`           | `string`            | Yes          | Response body.
| `o_headers`            | `object`            | Yes          | Response headers.
| `o_statusCode`         | `number`            | Yes          | Response status code.
| `OutputStatus`         | `OutputStatus`      | Yes          | Status of the request.

#### Enum: BodyType

Possible values for BodyType.

- `JSON`
- `MULTIPART`
- `RAW` and more.

#### RequestType

Possible values for RequestType

- `HTTP`
- `GRAPHQL`
- `GRPC`
- `KAFKA`
- `AMQP`

#### Enum: OutputStatus

Possible values for OutputStatus.

- `ERROR`
- `OKAY`
```

{% endtab %}

{% tab title="GRAPHQL" %}

```markdown
### requestObj

Describes the components of a recorded graphql request.

#### Properties

| Property Name          | Type                | Non-Optional | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|
| `i_gqlOpType`          | `HtGraphqlOpType`   | Yes          | Graphql request type.        
| `i_gqlHeaders`         | `Object`            | Yes          | Headers for the request.               
| `i_gqlQuery`           | `string`            | Yes          | Query for the request.  
| `im_gqlOpName`         | `string`            | Yes          | Graphql Operation name.
| `i_gqlVars`            | `object`            | Yes          | Variables for the graphql request.   
| `i_gqlResolverChain`   | `string[]`          | Yes          | Resolvers encountered in the response.
| `id`                   | `bigint`            | Yes          | Id of the recorded request.
| `o_data`               | `object`            | Yes          | Response data.
| `o_error`              | `object`            | Yes          | Response error.
| `requestType`          | `RequestType`       | Yes          | Server type.
| `OutputStatus`         | `OutputStatus`      | Yes          | Status of the request.

#### Enum: HtGraphqlOpType

Possible values for HtGraphqlOpType.

- `QUERY`
- `MUTATION`
- `SUBSCRIPTION`

#### RequestType

Possible values for RequestType

- `HTTP`
- `GRAPHQL`
- `GRPC`
- `KAFKA`
- `AMQP`

#### Enum: OutputStatus

Possible values for OutputStatus.

- `ERROR`
- `OKAY`
```

{% endtab %}

{% tab title="GRPC" %}

```markdown
### requestObj

Describes the components of a recorded GRPC request.

#### Properties

| Property Name          | Type                | Non-Optional | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|
| `i_method`             | `string`            | Yes          | Request method.        
| `i_service`            | `string`            | Yes          | Name of the service.               
| `i_metaData`           | `object`            | Yes          | Request meta data.  
| `i_body`               | `object`            | No           | Request body.
| `o_metaData`           | `object`            | Yes          | Response meta data.   
| `o_error`              | `object`            | No           | Response error.
| `id`                   | `bigint`            | Yes          | Id of the recorded request.
| `o_status`             | `object`            | Yes          | Response status.
| `o_body`               | `object`            | No           | Response body.
| `requestType`          | `RequestType`       | Yes          | Server type.
| `OutputStatus`         | `OutputStatus`      | Yes          | Status of the request.

#### RequestType

Possible values for RequestType

- `HTTP`
- `GRAPHQL`
- `GRPC`
- `KAFKA`
- `AMQP`

#### Enum: OutputStatus

Possible values for OutputStatus.

- `ERROR`
- `OKAY`
```

{% endtab %}

{% tab title="KAFKA" %}

```markdown
### requestObj

Describes the components of a recorded kafka request.

#### Properties

| Property Name          | Type                | Non-Optional | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|
| `i_groupId`            | `string`            | Yes          | Kafka group id.        
| `i_highWaterMark`      | `string`            | No           | Last message offset.               
| `i_topic`              | `string`            | Yes          | Topic name.  
| `i_jsonValue`          | `object`            | No           | Request body value.
| `i_headers`            | `object`            | No           | Request headers.   
| `i_offset`             | `string`            | Yes          | Current message offset.
| `id`                   | `bigint`            | Yes          | Id of the recorded request.
| `i_timestamp`          | `string`            | Yes          | Timestamp.
| `im_valueString`       | `string`            | No           | Message stringified.
|`im_valueStringEncoding`| `HtRawEncoding`     | No           | Encoding for the value string.
| `im_attributes`        | `int`               | Yes          | Config.
| `im_size`              | `int`               | No           | Message size.
| `im_partition`         | `int`               | Yes          | Partition name.
| `requestType`          | `RequestType`       | Yes          | Server type.
| `OutputStatus`         | `OutputStatus`      | Yes          | Status of the request.

#### Enum: HtRawEncoding

Possible values for HtRawEncoding.

- `NONE`
- `UTF8`
- `BASE64`

#### RequestType

Possible values for RequestType

- `HTTP`
- `GRAPHQL`
- `GRPC`
- `KAFKA`
- `AMQP`

#### Enum: OutputStatus

Possible values for OutputStatus.

- `ERROR`
- `OKAY`

```

{% endtab %}

{% tab title="AMQP" %}

```markdown
### requestObj

Describes the components of a recorded AMQP request.

#### Properties

| Property Name          | Type                | Non-Optional | Description                               
|------------------------|---------------------|--------------|-------------------------------------------|
| `i_queue`              | `string`            | Yes          | Queue name.        
| `i_msg`                | `object`            | Yes          | Message sent in the request.               
| `i_messageType`        | `HtAmqpMessageType` | Yes          | Message Type.  
| `i_options`            | `object`            | No           | Options for the request.
|`im_ContentBufferBase64`| `string`            | No           | Content buffer encoded in base64.   
| `OutputStatus`         | `OutputStatus`      | Yes          | Status of the request.
| `id`                   | `bigint`            | Yes          | Id of the recorded request.
| `requestType`          | `RequestType`       | Yes          | Server type.

#### Enum: OutputStatus

Possible values for OutputStatus.

- `ERROR`
- `OKAY`

#### RequestType

Possible values for RequestType

- `HTTP`
- `GRAPHQL`
- `GRPC`
- `KAFKA`
- `AMQP`

```

{% endtab %}
{% endtabs %}


# Java SDK


# Sampling and blocking requests

## Sampling

### How it works

It is possible that while using Hypertest SDK the latency of your APIs increase. Hypertest provides a mechanism called sampling to deal wiith this. There are two ways by which Hypertest SDK samples.

First is by telling the SDK to stop recording the requests for a certain cool off period. You tell us which requests should be sampled by providing a maximum response time. The requests taking more than maximum response time are marked to be sampled. So, the next time such a request comes it wont be recorded, decreasing your latency.

Second way is by specifying the sampling rate for requests. Example: A sampling rate of 65 percent would mean, out of all the requests roughly 65 percent would actually end up recorded, other 35 would be blocked.

These two methods can be used together and are additive in nature. Sampling config must be defined at the initialization of SDK.

### Code

{% code overflow="wrap" %}

```typescript
new HypertestAgentBuilder("<HT_SERVICE_ID>", "<YOUR_SERVICE_NAME>",  "<API_KEY>", "<LOGGER_URL>", "<APPLICATION_CLASS>")
.addHttpSamplingConfig(".*", "GET", 1.0, 10*1000, 5000)
.addHttpSamplingConfig("/api", "*", 0.5, 10*1000, 1000)
.build()
```

{% endcode %}

Arguments:

1. Path: You can provide a string or a regex (using Pattern class) to tell which requests should be sampled.
2. Method: Type of request (GET, POST, PUT, etc). This is case insensitive.
3. Sampling rate: The amount of requests to be sampled.
4. Max response time (ms): Requests taking more than this time would be sampled.
5. Cool off period (ms): Requests taking more than max response time would be sampled for this cool off time period only.

You can provide a list of configs, each targeting a group of requests. The sdk starts matching the requests from top to bottom. There exists a default config for sampling at the bottom of the list by default that looks like this. It matches with all the requests, providing a fallback in case no configs match.

```typescript
{
  path: '.*',
  method: '*',
  samplingRate: 1,
  maxResponseTimeMs: 10 * 1000,
  coolOffPeriodMs: 60 * 1000
}
```

## Blocking requests

Hypertest SDK allows you to specify a config to stop recording certain requests. You can specify the method and the path of the request you want to be be blocked.

```typescript
new HypertestAgentBuilder("<HT_SERVICE_ID>", "<YOUR_SERVICE_NAME>",
 "<API_KEY>", "<LOGGER_URL>", "<APPLICATION_CLASS>")
.addHttpBlockRequestsConfig("/sampling/blocking", "*")
.addHttpBlockRequestsConfig("/test/blocking", "PUT")
.build()
```

Arguments:

1. Path: You can provide a string or a regex (using Pattern class) to tell which requests should be blocked.
2. Method: Type of request (GET, POST, PUT, etc). This is case insensitive.


# Mock Dependencies Manually

HyperTest provides a way for you to manually mock certain dependencies that are not instrumented automatically. Allows you to capture mocks with a readable input, which will help you better understand the mocks on the dashboard.

Please check the list of [automatically instrumented packages](https://docs-v2.hypertest.co/user-guides/java-sdk/supported-java-packages), before proceeding with manual mocks.

These mocks also come in handy when you want to reduce false positives in the test reports caused by a utility that returns arbitrary values e.g., timestamps, and UUIDs.&#x20;

Let's look at an example where manual mocks can be utilized.

Below is an API route that generates PROMO code for a user.

```javascript
@RestController
@RequestMapping("/api")
public class PromoCodeController {

    @Autowired
    private UserRepository userRepository;

    // Generate promo code based on userId
    private String generatePromoCode(Long userId) {
        String uniquePart = UUID.randomUUID().toString().split("-")[0]; // Take the first part of a UUID
        return "PROMO-" + uniquePart + "-" + userId;
    }

    @PostMapping("/generate_promo_code")
    public ResponseEntity<?> generatePromoCode(@RequestBody UserRequest userRequest) {
        // Retrieve user from the database using emailId
        User user = userRepository.findByEmailId(userRequest.getEmailId());

        if (user == null) {
            return ResponseEntity.status(404).body("User not found");
        }

        // Generate promo code
        String promoCode = generatePromoCode(user.getId());

        return ResponseEntity.ok(new PromoCodeResponse(promoCode));
    }
}

```

If we record this API interaction and run a Test then HyperTest will report a value-modified error, but this is a false positive and it's not a real change that was made in the logic.

<figure><img src="/files/i9343ioVa2pR9mipljhY" alt=""><figcaption></figcaption></figure>

To eliminate this recurrent issue we can manually mock the generation of the Promo code. When we re-record this API interaction we will also have the exact value of the Promo code that was generated and the same will be used in the Test.

```javascript
@RestController
@RequestMapping("/api")
public class PromoCodeController {

    @Autowired
    private UserRepository userRepository;

    // Generate promo code based on userId
    @HtManualMock(configClass = GeneratePromoCodeConfig.class)
    private String generatePromoCode(Long userId) {
        String uniquePart = UUID.randomUUID().toString().split("-")[0]; // Take the first part of a UUID
        return "PROMO-" + uniquePart + "-" + userId;
    }

    @PostMapping("/generate_promo_code")
    public ResponseEntity<?> generatePromoCode(@RequestBody UserRequest userRequest) {
        // Retrieve user from the database using emailId
        User user = userRepository.findByEmailId(userRequest.getEmailId());

        if (user == null) {
            return ResponseEntity.status(404).body("User not found");
        }

        // Generate promo code
        String promoCode = generatePromoCode(user.getId());

        return ResponseEntity.ok(new PromoCodeResponse(promoCode));
    }
    
    public class GeneratePromoCodeConfig implements HtManualMockConfig {
        @Override
        public String generateIdentifier(Object... functionArgs) throws Exception {
            return "generatePromoCode";
        }
        
        @Override
        public EnumManager.FunctionTypeEnum getFunctionType() {
            return EnumManager.FunctionTypeEnum.SYNC;
        }
        
        @Override
        public Object[] normalizeArguments(Object... functionArgs) {
            return functionArgs;
        }
    }
}

```

To create a manual mock you need to follow these steps:

* Add annotation: Add an annotation (@HtManualMock) above the method you want to manually mock. This annotation accepts an argument called configClass.
* Create a config class: Create a config class for this mock. This class must implement ***HtManualMockConfig*** interface. You have to implement 2 mandatory methods and 1 optional method:
  * generateIdentifier(Object ...args): It accepts the same arguments as `originalFn`. It should return a string which will be your unique identifier (An identifier is needed to pick the right mock during REPLAY, if you are making the same kind of function calls then consider adding a number to the identifier).
  * getFunctionType(): It should return an ENUM (EnumManager.FunctionTypesEnum). It tells us that that method you are trying to manually mock is a SYNC/ASYNC/CALLBACK method.
  * normalizeArguments(Object... args): This method is optional and normalizes or transforms the input arguments. It accepts the same arguments as `originalFn` and returns an object with normalized input values. Return value of this function will be used as readableInput and would be used for display on dashboard.

If we run a test with the manual mock in place it passes.

<figure><img src="/files/3LrWXF7AUkSRlYIL7Z98" alt=""><figcaption></figcaption></figure>


# Tags

Tags are used to provide additional information for the request and contribute to a better control over deduplication. A request can only contain a unique tag with same name and value.

There are three types of tags.

1. Case
2. Label
3. Annotation

### 1. Case

Case is a tag that is used to create a mock at a particular branching which needs to be covered in a request and does not let it get deduplicated if there is a version of the same request already present.

Case is created with the following syntax in source code.

```java
import hypertest.javaagent.HypertestAgent;
import hypertest.javaagent.bootstrap.EnumManager;

HypertestAgent.addTag("case name", "case value", EnumManager.TagType.CASE);
```

Case contributes to the deduplicating hash and essentially creates a new version of the request if the latter was already present. Typically this is used to create different versions of the same request to increase code coverage and cover all branching statements.&#x20;

Case can also be added in the root context of an application. If a case is added in root context then the same case is inserted in every incoming request when the server span is created.

Case is created at root context with the following syntax in source code.&#x20;

```java
import hypertest.javaagent.HypertestAgent;

HypertestAgent.addRootCase("case name", "case value");
```

**E.g.,**&#x20;

Imagine an api where the logic splits based on a requestParam <mark style="color:blue;">`action`</mark>.&#x20;

Suppose, we hit a request with requestParam `itemType` as <mark style="color:blue;">`credit`</mark>, and then with requestParam `itemType` as <mark style="color:blue;">`debit`</mark> then the 2nd request would get deduplicated (so there won't be generation of test case for it).

To generate a test case for both the branches we can use case tag like this:

```java
@GetMapping("/updateBalance")
public ResponseEntity<?> updateBalance(@RequestParam("userId") String userId,
                                       @RequestParam("amount") BigDecimal amount,
                                       @RequestParam("action") String action) {
    // Use the CASE tag to record the branch of execution based on the action parameter.
    HypertestAgent.addTag("action", action, EnumManager.TagType.CASE);
    
    // Fetch the current balance for the user
    BigDecimal currentBalance = userService.getBalance(userId);
    
    if ("credit".equalsIgnoreCase(action)) {
         // Credit branch: add the specified amount to the current balance
         BigDecimal updatedBalance = currentBalance.add(amount);
         userService.updateBalance(userId, updatedBalance);
         return ResponseEntity.ok("User " + userId + " credited with " + amount +
                                  ". Current balance: " + updatedBalance);
    } else if ("debit".equalsIgnoreCase(action)) {
         // Debit branch: subtract the specified amount from the current balance
         BigDecimal updatedBalance = currentBalance.subtract(amount);
         userService.updateBalance(userId, updatedBalance);
         return ResponseEntity.ok("User " + userId + " debited with " + amount +
                                  ". Current balance: " + updatedBalance);
    } else {
         // Invalid action handling
         return ResponseEntity.badRequest().body("Invalid action specified.");
    }
}
```

### 2. Label

Label is a tag that is used to create a mock inside a particular route to avoid more versions of the same request due to difference in response schema. If there is a label inside a request, then only the cases and labels are considered for creating the deduplicating hash value thereby retaining the desired version of the request.

Label is created with the following syntax in source code.

```java
import hypertest.javaagent.HypertestAgent;
import hypertest.javaagent.bootstrap.EnumManager;

HypertestAgent.addTag("label name", "label value", EnumManager.TagType.LABEL);
```

Label can also be added in the root context of an application. If a label is added in root context then the same label is inserted in every incoming request when the server span is created.

Label is created at root context with the following syntax in source code.&#x20;

```java
import hypertest.javaagent.HypertestAgent;

HypertestAgent.addRootLabel("label name", "label value");
```

**E.g.,**&#x20;

Imagine an endpoint that returns user details in two different response schemas based on the `detailLevel` query parameter.&#x20;

The underlying business logic remains similar, but the schema of outbound JPA call varies. Without intervention, these schema differences would result in multiple test cases.&#x20;

By adding a Label tag, you ensure that the deduplication process considers only your defined label value (e.g., a fixed output schema version), thus retaining a single desired version of the request.

```java
@GetMapping("/users")
public ResponseEntity<?> getUser(@RequestParam("detailLevel") String detailLevel) {
    // By adding a label with a constant value (e.g., "v1"),
    // we ensure that differences in the output details don't result in separate test cases.
    HypertestAgent.addTag("outputSchema", "v1", EnumManager.TagType.LABEL);
    
    if ("full".equals(detailLevel)) {
        // Full branch: returns comprehensive user details.
        User fullUser = userService.getFullUser();
        return ResponseEntity.ok(fullUser);
    } else {
        // Basic branch: returns minimal user details.
        User basicUser = userService.getBasicUser();
        return ResponseEntity.ok(basicUser);
    }
}
```

### 3. Annotation

Annotation is a tag that is used to create an unimportant mock inside a route to provide additional context to the request. This does not contribute to the deduplicating hash.

Annotation is created with the following syntax in source code.

```java
import hypertest.javaagent.HypertestAgent;
import hypertest.javaagent.bootstrap.EnumManager;

HypertestAgent.addTag("annotation name", "annotation value", EnumManager.TagType.ANNOTATION);
```

Annotation can also be added in the root context of an application. If a annotation is added in root context then the same annotation is inserted in every incoming request when the server span is created.

Annotation is created at root context with the following syntax in source code.&#x20;

```java
import hypertest.javaagent.HypertestAgent;

HypertestAgent.addRootAnnotation("label name", "label value");
```

**E.g.,**

In this scenario, there are 2 kind of APIs one for handling user operations (such as creating a user and logging in), while the other manages order-related operations.&#x20;

The annotations add metadata that can later be used on Hypertest dashboard to filter or in `.htTestConf.js`  to run only selected groups of APIs.

```java
@RestController
public class Controller {

    @PostMapping("/create")
    public ResponseEntity<?> createUser(@RequestBody User user) {
        // Annotate this endpoint as belonging to the "user" group.
        HypertestAgent.addTag("apiGroup", "user", EnumManager.TagType.ANNOTATION);
        
        // Business logic for creating a user
        userService.createUser(user);
        return ResponseEntity.ok("User created successfully");
    }

    @PostMapping("/login")
    public ResponseEntity<?> loginUser(@RequestBody LoginRequest loginRequest) {
        // Annotate this endpoint as belonging to the "user" group.
        HypertestAgent.addTag("apiGroup", "user", EnumManager.TagType.ANNOTATION);
        
        // Business logic for logging in a user
        boolean success = userService.login(loginRequest);
        if (success) {
            return ResponseEntity.ok("User logged in successfully");
        } else {
            return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Invalid credentials");
        }
    }
    
    @PostMapping("/place")
    public ResponseEntity<?> placeOrder(@RequestBody Order order) {
        // Annotate this endpoint as belonging to the "order" group.
        HypertestAgent.addTag("apiGroup", "order", EnumManager.TagType.ANNOTATION);
        
        // Business logic for placing an order
        orderService.placeOrder(order);
        return ResponseEntity.ok("Order placed successfully");
    }
}
```


# Unmocking/Passing Through

This page documents how to tell the hypertest sdk to not mock certain parts of your code.

{% hint style="danger" %}
UnMocked Calls will be called as-is in both RECORD and REPLAY modes. Any network calls make inside the  callback of `executeUnmocked()`  would be actually made&#x20;
{% endhint %}

```typescript

import hypertest.javaagent.HypertestAgent;
/**
   .. code normally instrumented by hypertest
**/

// old code
// ResponseEntity<String> xmlResponse = restTemplate.postForEntity("https://myexampleurl.com/api/v1/sample", requestEntityXml, String.class);


// new code
HypertestAgent.executeUnmocked(() -> {
  // Anything called here is not captured/mocked by hypertest in any mode
  ResponseEntity<String> xmlResponse = restTemplate.postForEntity("https://myexampleurl.com/api/v1/sample", requestEntityXml, String.class);
  // the above http call would not be captured by hypertest during record mode.
  // it would actually hit myexampleurl.com in replay mode.
});
```


# Code Coverage Setup and Report Generation

Follow these steps to set up and view the code coverage report for your application:

1. Navigate to the root directory of your application
2. Download the JaCoCo library and extract it:
   1. Using Browser ([Link](https://www.jacoco.org/jacoco/trunk/index.html))&#x20;
   2. or Using Terminal
      1. For Linux OS
      2. For Windows OS

```
curl -L -o jacoco-0.8.12.zip https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.12/jacoco-0.8.12.zip
unzip jacoco-0.8.12.zip -d jacoco-0.8.12
mkdir jars
mv jacoco-0.8.12/lib/* jars
```

```
curl -L -o jacoco-0.8.12.zip https://search.maven.org/remotecontent?filepath=org/jacoco/jacoco/0.8.12/jacoco-0.8.12.zip
tar -xf jacoco-0.8.12.zip -C jacoco-0.8.12
mkdir jars
move jacoco-0.8.12\lib\* jars
```

3. Update `.htTestConf.js` 's `appStartCommandArgs`

```json
appStartCommandArgs: [
"-Dspring-boot.run.jvmArguments=-javaagent:jars/jacocoagent.jar=output=file,destfile=./coverage.exec",
"spring-boot:run"]
```

4. Execute the application in Replay mode
5. Generate and view coverage report

```
java -jar jars/jacococli.jar report ./coverage.exec \
    --classfiles target/classes \
    --sourcefiles src/main/java \
    --html report
```

6. To view the code coverage results, open the following `report/index.html` file.


# Supported Java packages

List of java packages that are automatically mocked by HyperTest

{% embed url="<https://docs.google.com/spreadsheets/d/1KKxNL44oHx7wJdRBrFB6g-8M2zgnV01snTGlo_CugCo/edit?gid=568039904#gid=568039904>" fullWidth="true" %}


# Build your own Docker Image

## Build your own custom Docker Image of HyperTest <a href="#build-you-own-custom-docekr-image-for-hypertest" id="build-you-own-custom-docekr-image-for-hypertest"></a>

HyperTest's docker images uses `node:20-bookworm-slim` as a base docker image. \
If you want to use your own node image as base image for  HyperTest, you can do so and rebuild the image with the following script.

To build your own custom image follow the steps given in this page

1. Create the file named docker-image-HT-script.sh

<details>

<summary> docker-image-HT-script.sh</summary>

```bash
#!/bin/bash

# Load environment variables from .env file
if [ -f .env ]; then
    export $(cat .env | grep -v ^# | xargs)
fi

# Clone the git repo
git clone https://${GIT_FT_PAT}@github.com/hypertestco/v2-artifacts.git

# Navigate into the cloned repository
cd v2-artifacts || exit

# Checkout to version of HT
git checkout ${HYPERTEST_VERSION}

# Function to parse dependenciesVersion.txt and extract version numbers
parse_dependencies() {
    local file="dependenciesVersion.txt"
    if [ -f "$file" ]; then
        prismaEngVersion=$(grep -E "^prismaEngVersion:" "$file" | sed 's/prismaEngVersion://' | tr -d '[:space:]')
        bcryptVersion=$(grep -E "^bcryptVersion:" "$file" | sed 's/bcryptVersion://' | tr -d '[:space:]')
    else
        echo "Error: dependenciesVersion.txt not found"
        exit 1
    fi
}

# Parse dependenciesVersion.txt to extract version numbers
parse_dependencies

# Build Docker image
docker build -t ${DOCKER_IMAGE_NAME} \
             --build-arg NODE_BASE_IMAGE=${NODE_BASE_IMAGE} \
             --build-arg PRIMSA_ENG_PKG_VERSION=${PRIMSA_ENG_PKG_VERSION} \
             --build-arg BCRYPT_VERSION=${BCRYPT_VERSION} .
```

</details>

2. Create the file named .env&#x20;

<details>

<summary>.env</summary>

```
GIT_FT_PAT=<Fine_grained_PAT_received from HT Team(diff than NPM)>
HYPERTEST_VERSION=<Get the latest version from HT team>
DOCKER_IMAGE_NAME=<c_docker_image_name>
NODE_BASE_IMAGE=<Node_base_image, we are using node:20-bookworn-slim>
```

</details>

3. Update the auth token, docker image name and node base image in .env file
4. Run the script using below command

```sh
sh  docker-image-HT-script.sh
```

The above script will do the following steps

1. Clone the repo[^1]sitory containing docker artifacts
2. Fetch package versions from repo content for a few packages required to run HT
3. Build a docker image based on the name and base image you passed in .env file

{% hint style="success" %}
NOTE: The base image should have node (version 20 as of now) and npm installed in it
{% endhint %}

[^1]:


# CLI Config

These are all the available CLI config options:

<pre class="language-javascript"><code class="lang-javascript">{
  // The URL for HyperTest's backend that serves your dashboard
  htBackendBaseUrl: 'http://your-domain-host.com',

  // It's a UUID(generated by HyperTest) of the service you want to test,
  // you can find this on the dashboard (http://[[ADD_HOST_HERE]]/dashboard/#/services)
  // Required Config (Can't be blank)
  serviceIdentifier: '[[SERCVICE_UUID]]',

  // This is authentication token required for running the test
  // you can generate one from the dashboard (http://[[ADD_HOST_HERE]]/dashboard/#/profile)
  // Required Config (Can't be blank)
  htCliRefreshToken: 'your-refresh-token',

  // This tells us what kind of request types you want to test for the current service
  // If you're service exposes both HTTP and GRAPHQL APIs and you want to cover them
  // in the same test them include them like: ['HTTP','GRAPHQL']
  // All the available options: ['HTTP','GRAPHQL','KAFKA','GRPC','AMQP']
  requestTypesToTest: ['HTTP'],

  // The base URL for the HTTP application being tested
  // as the CLI spawns the application process, the host should be localhost
  // or other host that would resolve locally e.g., "127.0.0.1", "0.0.0.0", "::"
  // localhost should be fine for most cases
  // Required Config when requestTypesToTest includes: 'HTTP'
  httpCandidateUrl: 'http://localhost:9999',

  // The base URL for the GRAPHQL application being tested
  // as the CLI spawns the application process, the host should be localhost
  // or other host that would resolve locally e.g., "127.0.0.1", "0.0.0.0", "::"
  // localhost should be fine for most cases
  // Required Config when requestTypesToTest includes: 'GRAPHQL'
  graphqlCandidateUrl: 'http://localhost:9999',

  // `httpReqsToTest` is an optional array of HTTP request IDs to be tested
  // only these IDs will be tested
  httpReqsToTest: [1, 2, 3],

  // `grpcReqsToTest` is an optional array of gRPC request IDs to be tested
  // only these IDs will be tested
  grpcReqsToTest: [101, 102],

  // `appStartCommand` is the command to start the application
  // for example if you want to run your application using npm
  // the whole command would look like this: npm run start-app
  // In this config option you just need to pass the initial command
  // which is just "npm", other bits will be covered in appStartCommandArgs
  // e.g., appStartCommand = 'npm';  appStartCommandArgs = ['run', 'start-app'],
  appStartCommand: 'npm',

  // `appStartCommandArgs` is an array of additional arguments for the start command
  appStartCommandArgs: [],

  // the directory where the app should be started, defaults to the current working directory
  appWorkingDirectory: '/path/to/working/directory',

  // this tells how long we should wait before the app under test becomes responsive
  // defaults to 10sec
  appStartTimeoutSec: 10,

  // `showAppStdErrLogs` indicates whether to show stderr logs of the application
  // defaults to true
  showAppStdErrLogs: true,

  // `showAppStdOutLogs` indicates whether to show stdout logs of the application
  // defaults to false
  showAppStdOutLogs: false,

  // indicates whether to report differences in HTTP headers,
  // defaults to false
  shouldReportHeaderDiffs: false,

  // specifies the batch size for concurrent tests, defaults to 50
  testBatchSize: 50,

  // optional limit for the number of requests to be tested
  testRequestsLimit: 100,

  // Optional config for filtering and testing particular HTTP requests based on method and path
  // the strings could be plain combination of method and path for exact matches or 
  // you could also pass a string containing regex for the path, examples given below:
  // 1. plain exact match: "GET /api/v1/users"
  // 2. path exact match without specific method: "/api/v1/users"
  // 3. regex for path: "ANY REGEX:^/payments"
  httpReqFiltersArr: ['/api/v1/users'],

  // Optional headers for requests to the HyperTest's backend service
  // When you host your own instance of HyperTest you might need to add these headers
  // for the reverse proxy to allow these CLI requests
  // NOTE: In the hosted trial a basic auth header is always required
  htExtraHeaders: {
    'X-Custom-Header': 'custom-value',
  },

  // An optional function to ignore certain mock differences
  // You can check out the documentation for it: Ignoring Differences
  filterFunctionToIgnoreMockDiffs: ({ mockDiff, requestObj, currentMock }) => {
    // Custom logic to ignore certain mock differences
    
    // Return false to discard a difference form the report
    // return false;
    // Return true to keep the difference in report
    return true;
  },
  
  
  // An optional function to ignore certain response differences
  // You can check out the documentation for it: Ignoring Differences
  filterFunctionToIgnoreResponseDiffs: ({ responseDiff, requestObj }) => {
    // Custom logic to ignore certain response differences
    
    // Return false to discard a difference form the report
    // return false;
    // Return true to keep the difference in report
    return true;
  }

  // `exitCodeSetter` is an optional function to set the exit code based on the
  // outcome of the test. This is helpful when you're running test in CI env
  // dont want the job to fail because of failure in HyperTest's test run.
  exitCodeSetter: (result) => {
    return result.success ? 0 : 1;
  },

  // `autoAcceptChangesInCaseOnlyNoiseDetected` specifies whether to auto-accept changes with only noise
  // defaults to true
  autoAcceptChangesInCaseOnlyNoiseDetected: true,

  // requests which contain the mentioned tags will be tested.
  // Refer Tags under "User Guides/Node.js SDK" for more information.
  // Is an optional array of key-value pairs of tags 
  tags: [{ name: 'env', value: 'production' }],

  // Optional list of strings to ingore while comparing string values for
  // reporting differences, these strings are combined to build one regex for comparison
  // you need to escape characters that are used in regex such as: "."
  // e.g., ['01\.02\.03\.04', 'HyPeRtEsT']
<strong>  exclusionStringsForDifferences: []
</strong> 
  // Optional config to let HyperTest know which ports are being used by the app itself
  // this would avoid port clashes
  reservedAppPorts: [9999],

  // specifies the buffer size of the SDK client which fetches the root mocks
  // You might want to tweak this if you get a maxBuffer exceeded error on SDK side
  // defaults to 200MB
  fetchRootMockBufferSizeInMB: 200,

  // `fastMode` indicates whether to run the tests in fast mode, defaults to false
  // You can read the detailed documentation here: Impact Features/ Fast Mode
  fastMode: false,

  // optional array of statuses to test for, must be 'OKAY' or 'ERROR'
  // This is useful when you want to only test the requests which were successfull
  // the only one that failed. The success and failure of a request is decided
  // on the basis on status codes.
  // OKAY === SUCCESS | ERROR === FAILURE
  outputStatusesToTest: ['OKAY'],
  
  // Indicates whether the SDK should throw and error during REPLAY in a HTTP outbound call
  // deaults to false
  shouldEmitErrorInHttpOutbound: false,

  // `shouldReportRootMockDifferences` indicates whether to report root mock differences
  // defaults to false
  shouldReportRootMockDifferences: false,
}

</code></pre>


# Ignoring Differences

Ignoring differences programmatically

In some scenarios, you might want to ignore certain differences between expected mocks/responses and actual ones.

These differences may be due to env variables, timestamps, or other non-critical factors that don't represent true regressions.

HyperTest allows to provide custom filtering logic to ignore such differences through two filter functions:

#### **filterFunctionToIgnoreMockDiffs**:

* This function allows users to specify conditions under which a particular mock difference should be ignored.
* **Input parameters**:

  * [mockDiff](/user-guides/ignoring-differences/type-references-for-filter-functions#mockdifference): An object describing the difference between the recorded mock and the replayed one.
  * [currentMock](/user-guides/ignoring-differences/type-references-for-filter-functions#currentmock-type): The original mock object recorded during testing.
  * [requestObj](/user-guides/ignoring-differences/type-references-for-filter-functions#requestobj-types): The request for which this mock difference was captured.

  Check out detailed Type Reference for Input Parameters [here](/user-guides/ignoring-differences/type-references-for-filter-functions).
* **Return value**:&#x20;

  The function should return a boolean, **false for ignoring** and **true for keeping** the difference.

Consider a case where you're making an outbound call to a 3rd party service and some metadata is being sent along with it, getting this error for random metadata is undesirable.

<figure><img src="/files/oC2BA3Q24eEnAiWeXaP1" alt=""><figcaption></figcaption></figure>

You can ignore any differences originating from metadata field like shown in the given example:

{% code fullWidth="false" %}

```javascript
function filterFunctionToIgnoreMockDiffs({ mockDiff, currentMock, requestObj }) { 
  // Ignore differences in the metadata field
  if (mockDiff?.evaluatedPath?.at(-2) === "metadata") return false;

  // Return true to consider this mock difference as critical
  return true;
}
```

{% endcode %}

#### **filterFunctionToIgnoreResponseDiffs**:

* This function allows users to specify conditions under which a particular response difference should be ignored.
* **Input parameters**:

  * [responseDiff](/user-guides/ignoring-differences/type-references-for-filter-functions#responsedifference): An object describing the difference between the expected response and the actual one.
  * [requestObj](/user-guides/ignoring-differences/type-references-for-filter-functions#requestobj-types): The request for which this response difference was captured.

  Check out detailed Type Reference for Input Parameters [here](/user-guides/ignoring-differences/type-references-for-filter-functions).
* **Return value**:&#x20;

  The function should return a boolean, **false for ignoring** and **true for keeping** the difference.

Consider a case where you're sending out some metrics about the order processing to the client, the processing time would definitely vary from an actual env vs a mocked environment, as this is not a real regression it should not be considered.

<figure><img src="/files/RmYTXJGPze7Id5FwDXcr" alt=""><figcaption></figcaption></figure>

```javascript
function filterFunctionToIgnoreResponseDiffs({ responseDiff, requestObj }) { 
  // Ignore differences in the metadata field
  if (responseDiff?.evaluatedPath?.at(-2) === "metadata") return false;

  // Return true to consider this mock difference as critical
  return true;
}
```

By customizing these functions, you can tailor the test results to focus on actual regressions while ignoring known, non-critical changes.


# Type References for Filter functions

This page provides detailed descriptions of the various TypeScript types used in the HyperTest CLI's filtering functions:

**`filterFunctionToIgnoreMockDiffs`** an&#x64;**`filterFunctionToIgnoreResponseDiffs`**

to help users identify and ignore known non-critical differences in mocks and responses.

***

#### **`MockDifferenceType`**

Defines the types of differences that can be identified between the recorded and replayed mocks:

```typescript
enum MockDifferenceType {
  MOCK_NOT_USED,
  MOCK_NOT_FOUND,
  MOCK_FORCE_MATCHED,
  
  // Instrumentation mock diff types
  INSTRUMENTATION_MOCK_INPUT_KEY_REMOVED,
  INSTRUMENTATION_MOCK_INPUT_KEY_ADDED,
  INSTRUMENTATION_MOCK_INPUT_VALUE_MODIFIED,
  INSTRUMENTATION_MOCK_INPUT_DATA_TYPE_CHANGED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ORDER_CHANGED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ORDER_CHANGED_KEY_REMOVED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ORDER_CHANGED_KEY_ADDED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ORDER_CHANGED_VALUE_MODIFIED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ORDER_DATA_TYPE_CHANGED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ITEMS_ADDED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ITEMS_REMOVED,
  INSTRUMENTATION_MOCK_INPUT_LIST_ITEMS_MODIFIED,
  INSTRUMENTATION_MOCK_INPUT_KEY_MODIFIED,
  INSTRUMENTATION_MOCK_INPUT_VALUE_REMOVED,
  INSTRUMENTATION_MOCK_INPUT_VALUE_ADDED,
  INSTRUMENTATION_MOCK_INPUT_DATA_TYPE_MODIFIED,
}
```

***

#### **`DifferenceType`**

Defines the types of differences identified between the expected and actual responses:

```typescript
enum DifferenceType {
  OUTPUT_STATUS_CHANGED,
  CONTENT_TYPE_CHANGED,
  STATUS_CODE_CHANGED,
  HEADER_REMOVED,
  HEADER_ADDED,
  HEADER_MODIFIED,
  KEY_REMOVED,
  KEY_ADDED,
  VALUE_MODIFIED,
  DATA_TYPE_CHANGED,
  LIST_ORDER_CHANGED,
  LIST_ORDER_CHANGED_KEY_REMOVED,
  LIST_ORDER_CHANGED_KEY_ADDED,
  LIST_ORDER_CHANGED_VALUE_MODIFIED,
  LIST_ORDER_DATA_TYPE_CHANGED,
  LIST_ITEMS_ADDED,
  LIST_ITEMS_REMOVED,
  MANUAL_ASSERTION_FAILED,
  MANUAL_ASSERTION_EXCEPTION,
  HTTP_CLIENT_ERROR,
  ERROR_LIST_ORDER_CHANGED,
  ERROR_LIST_ORDER_CHANGED_VALUE_MODIFIED,
  ERROR_LIST_ORDER_DATA_TYPE_CHANGED,
  ERROR_LIST_ORDER_CHANGED_KEY_ADDED,
  ERROR_LIST_ORDER_CHANGED_KEY_REMOVED,
  ERROR_DATA_TYPE_CHANGED,
  ERROR_LIST_ITEMS_ADDED,
  ERROR_LIST_ITEMS_REMOVED,
  ERROR_VALUE_MODIFIED,
  ERROR_KEY_ADDED,
  ERROR_KEY_REMOVED,
}
```

***

#### **`DifferenceSection`**

Categorizes the type of difference detected:

```typescript
enum DifferenceSection {
  ERROR,
  POST_IGNORED_NOISE,
  POST_IGNORED_ERROR,
  PRE_IGNORED_NOISE_DB,
  PRE_IGNORED_NOISE_CLI,
  PRE_IGNORED_ERROR_CLI,
  NOISY_ERROR,
}
```

***

#### **`RequestType`**

Represents the type of request that is being tested:

```typescript
enum RequestType {
  UNKNOWN,
  ROOT_MOCK,
  HTTP,
  HTTP_2,
  GRAPHQL,
  GRPC,
  KAFKA,
  AMQP,
}
```

***

#### **`BodyType`**

Defines the body format used in the requests, such as JSON, Multipart, or Raw:

```typescript
enum BodyType {
  JSON,
  MULTIPART,
  RAW,
}
```

***

#### **`HtGraphqlOpType`**

Represents the type of GraphQL operation in a GraphQL request:

```typescript
enum HtGraphqlOpType {
  QUERY,
  MUTATION,
  SUBSCRIPTION,
}
```

***

#### **`HtRawEncoding`**

Specifies the encoding used for the message in a request's payload or response:

```typescript
enum HtRawEncoding {
  NONE,
  UTF8,
  BASE64,
}
```

***

#### **`OutputStatus`**

Defines the status of the mock or response:

```typescript
enum OutputStatus {
  ERROR,
  OKAY,
}
```

***

#### **`MockDifference`**

Describes the structure of the mock difference object, capturing the details of the difference between the original and replayed mocks:

```typescript
type MockDifference = {
  mockIdentifier: string;
  replayMockId?: string;
  originalMockId?: bigint;
  mockType: MockType;
  differenceType: MockDifferenceType;
  severityScore: number;
  differenceSection: DifferenceSection;
  originalPath?: string[];
  newPath?: string[];
  evaluatedPath: string[];
  originalSchemaPath?: string[];
  newSchemaPath?: string[];
  differenceSchemaPath: string[];
  newValue?: any;  // Optional new value in the difference
  newValueHash?: string;
  originalValue?: any;  // Optional original value in the difference
  originalValueHash?: string;
};
```

***

#### **`ResponseDifference`**

Describes the structure of the response difference object, capturing details of the difference between the expected and actual responses:

```typescript
type ResponseDifference = {
  requestType: RequestType;
  requestIdentifier: string;
  differenceType: DifferenceType;
  severityScore: number;
  differenceSection: DifferenceSection;
  originalPath?: string[];
  newPath?: string[];
  evaluatedPath: string[];
  originalSchemaPath?: string[];
  newSchemaPath?: string[];
  differenceSchemaPath: string[];
  newValue?: any;  // Optional new value in the difference
  newValueHash?: string;
  originalValue?: any;  // Optional original value in the difference
  originalValueHash?: string;
};
```

***

#### **`currentMock` Type**

The `Mock` represents the original mock that was recorded during testing.

**Type Definition:**

```typescript
type Mock = {
  submoduleName: string;
  moduleName: string;
  id: bigint;
  OutputStatus: OutputStatus;
  readableInput: Record<string, any>;
  readableOutput: Record<string, any>;
  err: Record<string, any>;
};
```

***

#### **`requestObj` Types**

**HTTP Request Object**

Describes the components of an HTTP request recorded during testing:

```typescript
type HttpRequestObj = {
  i_bodyType: BodyType,
  i_clusterPath: string,
  i_headers: Record<string, string>,
  i_method: string,
  i_path: string,
  i_query: Record<string, string>,
  id: bigint,
  i_host: string,
  i_jsonBody: Record<string, any>,
  requestType: RequestType,
  o_jsonBody: Record<string, any>,
  o_headers: Record<string, string>,
  o_statusCode: number,
  OutputStatus: OutputStatus,
};
```

**GraphQL Request Object**

Describes the components of a GraphQL request recorded during testing:

```typescript
type GraphqlRequestObj = {
  i_gqlOpType: HtGraphqlOpType,
  i_gqlHeaders: Record<string, string>,
  i_gqlQuery: string,
  im_gqlOpName: string,
  i_gqlVars: Record<string, any>,
  i_gqlResolverChain: string[],
  id: bigint,
  o_data: Record<string, any>,
  o_error: Record<string, any>,
  requestType: RequestType,
  OutputStatus: OutputStatus,
};
```

**GRPC Request Object**

Describes the components of a GRPC request recorded during testing:

```typescript
type GrpcRequestObj = {
  i_method: string,
  i_service: string,
  i_metaData: Record<string, any>,
  i_body: Record<string, any>,
  o_metaData: Record<string, any>,
  o_error: Record<string, any>,
  id: bigint,
  o_status: Record<string, any>,
  o_body: Record<string, any>,
  requestType: RequestType,
  OutputStatus: OutputStatus,
};
```

**Kafka Request Object**

Describes the components of a Kafka request recorded during testing:

```typescript
type KafkaRequestObj = {
  i_groupId: string,
  i_highWaterMark: string,
  i_topic: string,
  i_jsonValue: Record<string, any>,
  i_headers: Record<string, string>,
  i_offset: string,
  id: bigint,
  i_timestamp: string,
  im_valueString: string,
  im_valueStringEncoding: HtRawEncoding,
  im_attributes: number,
  im_size: number,
  im_partition: number,
  requestType: RequestType,
  OutputStatus: OutputStatus,
};
```

**AMQP Request Object**

Describes the components of an AMQP request recorded during testing:

```typescript
type AmqpRequestObj = {
  i_queue: string,
  i_msg: Record<string, any>,
  i_messageType: HtAmqpMessageType,
  i_options: Record<string, any>,
  im_ContentBufferBase64: string,
  OutputStatus: OutputStatus,
  id: bigint,
  requestType: RequestType,
};
```


# Impact Features

In this section, we will discuss some essential features and functionalities of HyperTest.


# Fast Mode

Fast mode is a way to further reduce test execution time by aggressively deduplicating recorded requests. Our deduplication algorithm compares the schema of request, response and outbound calls of requests and only retaining one of the entire group of requests that have the same schema.&#x20;

Fast mode takes it one step further aggregating requests based on schema of the request & its response, thereby, ignoring the outbound call's schemas.&#x20;

This will will replay only a fraction of requests that we have recorded.

To enable Express Mode:-

1. Go to your *.htTestConf.js*
2. Enable *fastMode: true,*

<figure><img src="/files/1LhjCOT0hDYoj5eprExc" alt=""><figcaption></figcaption></figure>

Please note that Express mode is enabled by default for a user.


# Code Coverage Report

In simple words, code coverage is a white-box testing method that shows the percentage of code that gets executed during test runs. It aids us in evaluating the extent to which our tests address the code and identify any potential gaps.

With HyperTest, you can achieve over 90% code coverage. When you run your tests through the HyperTest CLI, it generates a comprehensive code coverage report, clearly highlighting which code paths are covered and which ones need more attention.

## **1. Run Code Coverage from CLI**

* Go to your Visual Code Studio
* Run the command :&#x20;

  ```json
  run-test-cov-html
  ```
* After this, a coverage folder will be generated and a code coverage report will be displayedon your CLI along with the test result. This will give you a general idea on how many statements, branches, functions and lines are covered when your test ran.

&#x20;

<figure><img src="/files/rhY5ZJbsJSZ1bODKXskW" alt=""><figcaption></figcaption></figure>

## 2. View Coverage Folder

You can open this report on your browser to get a more granular view of how many lines have been covered by your code.

Go to the coverage folder and open the file *.htConf.js.html* in your browser.

* Click on 'All Files' to view all of your code.

<figure><img src="/files/xKxqJMPA0gCKON0rj9fU" alt=""><figcaption></figcaption></figure>

* Open the file whose code coverage you want to take a look into.

<figure><img src="/files/H5huGR6BNJLWlcWc2Tnf" alt=""><figcaption></figcaption></figure>

* Once you open your file, you will able to see the lines we have not covered marked in pink.&#x20;

  <figure><img src="/files/F4YuQwviea1Azf0hdFwS" alt=""><figcaption></figcaption></figure>

For the lines marked in pink, we just need some traffic and we will be able to cover these scenarios instantly.


# Delete Recorded Requests

You can delete requests recorded via Hypertest on any service you have integrated from the UI itself.&#x20;

From the  dashboard:-

* Go to your Service and click on it's name.
* Click on 'Clear All Requests'

<figure><img src="/files/kHwgnZ1fVa4EI5p4qUop" alt=""><figcaption></figcaption></figure>

* Validate again to clear your requests

<figure><img src="/files/uuamct7PYB2xvQiI4E84" alt=""><figcaption></figcaption></figure>


# AI Summaries

Users can click on 'Ask AI- What went wrong' to interpret their failed requests.&#x20;

This summary will not only tell you what lead to this error and it's root cause but will also provide a comprehensive answer on what can be done to fix this error.

Users can find out the likelihood of any error being a false positive as well.

<figure><img src="/files/jJKBDLWCXeG14RuyXGBs" alt=""><figcaption></figcaption></figure>

<figure><img src="/files/Ffa7DXCuRm9fDd9d8lNb" alt=""><figcaption></figcaption></figure>

With git diff, users can get an expanded view of the changes in the commits tested by HyperTest. for example, in the given example, it is clear that user added a calculation error which was not there when HyperTest recorded this scenario from this branch.

<figure><img src="/files/C9KWKq535ZMRovOXZ3T7" alt=""><figcaption></figcaption></figure>

**Note: This feature is not available by default for self hosted users. If they try use this feature, HyperTest will ask for an API key from Gemini and users need to have their own Gemini model and set their own Gemini API key. (**[**Refer to this doc**](https://ai.google.dev/gemini-api/docs/api-key)**)**

**Contact HyperTest team if you are unable to set this up for yourself.**


# Inter Service Testing

HyperTest, when integrated with all of your services, enables a developer to visualize their service mesh and service interactions.

<figure><img src="https://lh7-rt.googleusercontent.com/slidesz/AGV_vUdjL5Ow-F3g9361HFAGsYltmAsasPWmFpaSt1nThcKdDHdZDiqplSIMgn4oiSbA7p5igda4xRR05w49L3qys2SAYs1vEbTrLqWiGVKlrpPw6XPB1q_S5JOa5m86FJlTJT2F0KayFl9nufetqdFBpTcW9yZXcSq_=s2048?key=P14UqOXts9F7iNY3Vy8xhg" alt=""><figcaption></figcaption></figure>

This helps users in catching any inter-service breaks.

## How to view Upstream Trace

Assume HyperTest is deployed in five services, microservice-app-1, microservice-app-2, microservice-app-3, microservice-app-4 and microservice-app-5. All of these services are interacting with each other.

These services have HyperTest running on them and recording traffic 24\*7. Also, we have recorded requests and replayed them to check for any deviations.

<figure><img src="/files/s1kQBLtRRjzUqiA2QFhi" alt=""><figcaption></figcaption></figure>

1. We will open the service, microservice-app-4 , open it's TEST RESULTS and open any of the test cases that are present.
2. Click on up *Upstream Trace.*

<figure><img src="/files/4V3XaBN01gxuzgIpkEC9" alt=""><figcaption></figcaption></figure>

3. A chart pops up which shows how this current service is dependent on the other services. You can use the zoom option to visualize the depth inter-service interactions better.

<figure><img src="/files/zQ4Sx7O6Iuy0jM3k5auq" alt=""><figcaption></figcaption></figure>

4. This shows which of these services upstream will be effected directly or indirectly if this service goes down.

## Interservice Testing: Accepting Changes&#x20;

In one of the previous sections, we discussed that the users can accept changes to confirm to HyperTest that this is a desired change so that we do not report this in future.&#x20;

With *upstream trace,* users can visualize which service upstream will be directly affected if this change is accepted.&#x20;

Once you click on *Accept All Changes,* a window pops up which warns the user that this mock is also utilized in a call upstream.

<figure><img src="/files/1wTMgu7sjs3bY1Vec2Tc" alt=""><figcaption></figcaption></figure>

You can click on *Show Upstream Trace* to understand which service will get effected directly if this change is accepted.

<figure><img src="/files/gfwmkRUqpxkUDQjf4zil" alt=""><figcaption></figcaption></figure>

**Note: Accepting changes in your current mock will also update the mock in the service upstream.**&#x20;


# Slack Integration

Every time a test is run, you can get a slack notification in a channel of  your choice. You can configure a slack webhook url in HyperTest's UI for your individual services to regularly get updates for your tests.

Please use this [link ](https://api.slack.com/messaging/webhooks)to generate your slack webhook url. Once this is done, please follow the steps given below:-

1. Go to your existing service and click on 'view service'.

<figure><img src="/files/ETj7ZK1yZ6bSJYUiFRzv" alt=""><figcaption></figcaption></figure>

2. Go to Settings>Add Webhook URL.

<figure><img src="/files/FlfjSM5QMNj1sSQ83ste" alt=""><figcaption></figcaption></figure>

3. Now add the webhook url and test it by sending a dummy notification via 'Test Webhook' option. You can go ahead and click on 'Add' to add this webhook URL

<figure><img src="/files/rFIW0HLUg1g2qUegmAko" alt=""><figcaption></figcaption></figure>

4. Once this is set up, you will start receiving your test notifications along with the dashboard results and it's UI link on Slack.

<figure><img src="/files/ewgMcsC61bvNeFSUT6Nx" alt=""><figcaption></figcaption></figure>


# Version History

<details>

<summary>0.2.28-50</summary>

Bug fixes:-

1. Total totalRequests count fixed inn Tests in UI
2. Fixed partial requests being recorded issue

Enhancements:-

1. Handling noise, undefined test cases and non deterministic usecases via update-cov command.

</details>

<details>

<summary>0.2.28-47</summary>

Bug fixes:-

1. Generate AI summaries for MOCK\_NOT\_FOUND status  test cases.
2. For Express Apps, if '?' is in clusterpath, then it is  forcefully removed to record requests
3. UI fix for test cases with single outbound calls
4. Fixed MySQL2 timeout error on replay&#x20;
5. Removed flag to add coverage from .htConfTest for coverage and only need nyc for it

Enhancements:-

1. Checkbox added to show date mocks
2. Option to invert mocks in a test case
3. Manual Mocks: We track the identifiers and not create mocks for the same mock if it was already present by directly calling the original fn inside patch
4. Hiding date mocks from UI

</details>

<details>

<summary>0.2.28-37</summary>

Bug Fixes:-

Enhancements:-

1. Provide a raw request and an option to copy the curL for requests recorded in All Requests
2. Provide commit from which tests are recorded and deduplicated under 'More Coverage Info'
3. Commit ID shown in Test Results
4. Commit Hashes shown in AI summaries
5. Hooks released for running encrypted APIs

</details>

<details>

<summary>0.2.28-27</summary>

Bug fixes:-

1. Redis 3 handler fix for internalSendCommandMock

Enhancements:-

1. Redis 3.0 Instrumentation released
2. Couchbase Instrumentation released
3. AI summaries feature released

</details>

<details>

<summary>0.2.28-17</summary>

Bug fixes:-

1. Remove duplicate instrumentation spans for better deduplication during RECORD mode
2. Fixed token expiry pop up when creating a service from UI
3. Issue with request's response in a test case, where the visibility was impacted, is solved.

Enhancements:-

1. Check span context to see if unique else not unique when recording a request.
2. Add created\_at or a user added in the platform
3. Adding a note to explain significance for exporterUrl in sdk initialization
4. typeOrm demo app support for 0.2.X
5. Added this env filterDuplicateMocksInInstrumentations, which helps user in telling us which other instrumentations they want apart from the default ones.

</details>

<details>

<summary>0.2.28-7</summary>

Bug Fixes:-

1. Fix code coverage issue- if the request is already recorded and we encounter new data, update the existing coverage
2. &#x20;Issues with stringifications of manual requests is fixed
3. Added  option for viewing manual requests in 'All Requests'
4. Removed double stringification in code coverage
5. If no coverage data is found when running tests with git diff, we give out a prompt to the user to run coverage command for coverage data

Enhancements:-

1. More coverage available now for all services and indexes via deduplication command(update-coverage)
2. Update code coverage via deduplication command in a single call
3. To Show committ ID and test branch in test results
4. Sub-set deduplication for graphql requests for better deduplication of requests
5. Compute git diff for AI summaries

</details>

<details>

<summary>0.2.28-3</summary>

Bug Fixes:-

1. Recorded requests are ordered by request ids in all requests.
2. Bug when adding service by the user has been fixed

Enhancements:-

1. More options on the services menu

</details>

<details>

<summary>0.2.27</summary>

Bug Fixes:-

1. If a user was on the test results page, accidentally logs out and tries to log back in with the same link, they get directed to the test results page.
2. Added "last updated" timestamp when hovering over the coverage progress bar in the UI.
3. Throw error when there are uncommitted changes while running post test dedupe command
4. Filter bulk APIs errors fixed.
5. Manual Mocks working in disabled mode.
6. Ability to bulk delete test cases from Test Results.
7. Mark as Noise feature removed from UI
8. Fixed issues with the copy button when viewing the text in JSON view.
9. Issues with downloading raw and multipart data from API responses resolved
10. If error is received after deduplication is completed when running update-cov command, the UI code coverage will still be updated.

Enhancements:-

1. Reserve App Ports: This is an optional config to let HyperTest know which ports are being used by the app itself. This is present in your .htTestConfig.js file and would avoid any port clashes.
2. Adaptive Sampling: In adaptive sampling, HyperTest makes a prediction if the incoming request will be unique or a duplicate.

   <br>

</details>

<details>

<summary>0.2.25-62</summary>

Bug Fixes:-

1. Issues with viewing JSON view for responses solved by implementing DOM
2. Not using ioredis pipeline class if its required use moduleExports
3. Issues with downloading raw and multipart data from API responses resolved
4. If error is received after deduplication is completed when running update-cov command, the UI code coverage will still be updated.
5. grpc instrumentation fix for buffer responses in client request(input and output) and server request input and output. (For Temporal Support)
6. Mongoose Callback Error Handling

Enhancements:-

1. Prisma Version 6 support included

</details>

<details>

<summary>0.2.23-56</summary>

Bug Fixes:-

1. Bug fix in docker for prisma integration
2. Bug fix for issue in opening JSON view for mocks in "All Requests"
3. Bug fix in search email option in reset password popup&#x20;

Enhancements:-

1. If mongo accessed from mongoose then experimental flag must be set for mongoose connection unmocking.
2. Check if ht-coverage directory doesn't exist, then create it

</details>

<details>

<summary>0.2.25-52</summary>

Bug Fixes:-

1. Ability to bulk delete test cases from Test Results.
2. Mark as Noise feature removed
3. Noisy differences will be there, we will not automatically delete them. However, they wont be marked as failure
4. Fixed issues with copy button when viewing the text in JSON view.

Enhancements:-

1. Iterative Duplication introduced to keep on deduplication for posttest deduplication even if the process is stopped. It will deduplicate till it gets interrupted, however, won't update test coverage in UI
2. If different versions of GRPC requests are used, we will be able to mock them.
3. Ensure backend compatibility for old CLI versions

</details>

<details>

<summary>0.2.23-50</summary>

Bug Fixes:-

Enhancements:-

1. Download htcli config file directly from UI
2. Added "last updated" timestamp when hovering over the coverage progress bar in the UI.

</details>

<details>

<summary>0.2.25-45</summary>

Bug Fixes:-

1. Making sure that ports mentioned in reservedAppPorts are free before starting a test by killing all process on those ports.
2. Throw error when there are uncommitted changes while running post test dedupe command
3. Filter bulk APIs errors fixed.
4. Manual Mocks working in disabled mode.

Enhancements:-

1. Removed password support. Login only via SSO
2. An Admin user can add/create another admin user via backend.
3. Copy request id button.
4. Filter Mocks/Outbound calls in a request via numbers.
5. Removed got library
6. Stretch Code Coverage by a few lines at the start and the end to capture more differences.
7. HyperTest CLI gives non zero exit code when no requests found

</details>

<details>

<summary>0.2.23-46</summary>

Bug Fixes:-

1. Fix for the UI error when displaying Kafka Timestamp. (Error displayed as "NAN undefined NAN")
2. UI glitch fixed when adding a new service on UI

Enhancements:-

1. Ensure that new users logging into the UI for the first time see a list of all available services in the UI
2. Introduction to a UI for self-signup functionality
3. Added a test progress bar on UI when running tests via CLI&#x20;
4. 'Unknown Keys' info provided if any unknown key is added by the user

</details>

<details>

<summary>0.2.23-40</summary>

Bug Fixes:-

1. To improve portability, store relative path instead of absolute path in NYC JSON summary

Enhancements:-

1. Added documentation to create webhook url in slack notifications page
2. Get more coverage info data from the option 'more coverage info' in UI
3. Deleting service data outside of transaction. Can help delete large amounts of data and will not revert deleted data if this 'delete job' fails

</details>

<details>

<summary>0.2.25-39</summary>

Bug fixes:-

1. Kill application when update-cov is completed to make sure that the coverage is updated
2. TYPEORM queryrunner mocks were leaking and pg mocks were getting created, leading to issues in replay. This has been fixed.
3. Pagination issue in requestCount page has been fixed

Enhancements:-

1. Support for mysql2 instrumentation versions 3.11.5 and above
2. Added app crash listners for better error understanding
3. Add libraries to ignore when initializing hypertest sdk to ignore already required packages
4. Blocking elastic apm, sentry, data-dog, newrelic in replay mode and disabling http2 instrumentation of data dog in record mode.
5. Continuous coverage feature released.

</details>

<details>

<summary>0.2.23-35</summary>

Bug Fixes:-

1. get filtered services query fix for service page
2. Graphql: Handling partial data errors in Replay. Now HT stores error only when selection set matches or no data is returned
3. Adding Further details in Coverage report in UI

Enhancements:-

1. Code Coverage being shown on UI

</details>

<details>

<summary>0.2.23-30</summary>

Bug Fixes:-

1. If user was on test results page, then accidentally logs out and then logs back in with the same link, they get directed to the test results page.
2. Added backend port to HT\_BACKEND\_BASE\_URL.
3. Redis Fix: Proper Handling of empty test results.

Enhancements:-

1. Freeze the versions of cjs module 'lexer'
2. update coverage info at the end of post test deduplication
3. Cron job terminates the test after 2 minutes if there is no progress&#x20;

</details>

<details>

<summary>0.2.25-26</summary>

Bug Fixes:-

1. Deleting service data outside of transaction- Can help delete large amounts of requests from UI and will not revert deleted data if this 'delete job' fails in the backend.
2. CLI reports ‘No requests found to Test’ if there are no changes done by the user while in REPLAY mode and git diff is enabled.
3. Fix for the UI error when displaying Kafka Timestamp. (Error displayed as "NAN undefined NAN")
4. Stop sending headers to (via http calls) AWS when uploading an image.
5. Exit code provided if no git diff found
6. Redis automatic pipelining feature has been disabled to avoid errors
7. Header propagation fixed for GraphQl requests, i.e., missing header issue has been fixed.

Enhancements:-

1. Public NPM library- All our packages are public now and can be viewed online. This also makes sure that there is no need for a .npmrc token to install HyperTest anymore.
2. Download .htTestConf.js with backendbaseURL directly from UI SDK snippet.
3. No Need for HtCLI token in the .htTestConf.js file
4. Microsoft SSO support added
5. Added support for Opossum Circuit Breaker: Now any request failed by this circuit breaker will automatically be discarded during the RECORD mode.
6. Added support for Elastic Transport- Enables users to use Elastic Search version 8 and above.
7. Reduced no of root mocks from backend to CLI to reduce memory usage.
8. EnableRecordModeExceptionHandling: An experimental flag. Can be enabled when initialising HyperTest SDK in the beginning. This makes sure that if any errors happen during the RECORD mode before we call onto a specific instrumentation, the whole RECORD mode doesn’t stop.&#x20;
9. Elastic Search v8  support via elastic transport
10. When recording and replaying tests, CLI automatically updates the user about newer versions of SDK and CLI

</details>

<details>

<summary>0.2.23-25</summary>

Bug Fixes:-

Enhancements:-

1. Create functions from UI(settings) to filter out mock differences
2. Add rules to ignore noise from UI

</details>

<details>

<summary>0.2.23-24</summary>

Bug Fixes:-

Enhancements:-

1. Reduced no of root mocks from backend to CLI to reduce memory usage
2. Add coverage percent in backend db
3. Notify user on UI about latest version of the sdk/CLI
4. Added nyc for other protocols(graphql, amqp)
5. In testResponse table, graphql headers are added in requestObj

</details>

<details>

<summary>0.2.23-21</summary>

Bug Fixes:-

1. RedisShortSubModuleName experimental flag added

Enhancements:-

1. Separating paths for root user and a normal user
2. Added a new mock class for sqllite-3

</details>

<details>

<summary>0.2.23-17</summary>

Bug Fixes:-

1. Fix/missing types after router change: In the `ht-cli` (HyperTest CLI) build process, it ensures that type definitions are now properly accounted for to prevent type errors in the system.
2. Root mocks bug fixed

Enhancements:-

1. Route added on UI to configure Slack notifications. Now user can add slack webhooks themselves.

</details>

<details>

<summary>0.2.23-15</summary>

Bug Fixes:-

Enhancements:-

1. Added the new Feature: Post Test Deduplication. Deduplicate requests via code coverage
2. CLI checks user application without making an http call, to improve performance
3. Introducing a new router with authentication middleware
4. Ability to view diffs for noise

</details>

<details>

<summary>0.2.23-10</summary>

Bug Fixes:-

1. If a noise and a difference were both present, it was marking everything as a noise. We have fixed that.

Enhancements:-

1. CLI version can be seen in 'Show More Details' in a test.
2. After importing htsdk, a user can dynamically import the underlying methods&#x20;

</details>

<details>

<summary>0.2.23-9</summary>

Bug Fixes:-

1. Mongoose: Now Mongoose connect call returns a promise with "this".

Enhancements:-

1. added inputSchemaHash, inputValueHash, collectiveHash in requestObject of testResponse table to enable this in Test results.
2. Redis Instrumentation: added patch for redis JSON, GRAPH, SEARCH, TIMESERIES, BLOOM instrumentation

</details>

<details>

<summary>0.2.23-4</summary>

Bug Fixes:-

Enhancements:-

1. (UI) Added documentation link to the dashboard
2. (UI) rules written in the config file are indented properly when shown in UI.&#x20;
3. changed the env file from 'env' to 'env-ht'.

</details>

<details>

<summary>0.2.23-1</summary>

Bug Fixes:-

1. (UI)Intermittent issue in viewing the  'JSON View' for outbound calls fixed.

Enhancements:-

1. (UI) Timestamp column when tests were in REPLAY mode added in UI
2. (UI) Alignment fix for 'Download Raw' button in UI

</details>

<details>

<summary>0.2.21</summary>

Bug Fixes:-

1. (UI)Ignore MOCK\_FORCE\_MATCHED(AI MATCHED) differences if all other difference are ignored of that mock by some predefined rules and UI changes

Enhancements:-

1. Removed accept header requests for better performance
2. Optimized LRU cache to make sure if HyperTest is not used for the past 10 days, request count doesn't increase to more than 5000.

</details>

<details>

<summary>0.2.21-7</summary>

Bug Fixes:-

Enhancements:-

1. Added support for aws and sequelize instrumentation to work with esm modules
2. (UI) Bulk accepting all the changes in the test cases from UI&#x20;
3. Automatically accept  the differences in a test case and pass the test case if their is no change found in the actual code.

</details>

<details>

<summary>0.2.21-4</summary>

Bug Fixes:-

Enhancements:-

1. adding http server client instrumentation mocks for a graphql request.

</details>

<details>

<summary>0.2.21-2</summary>

Bug Fixes:-

Enhancements:-

1. Provided Support for esm modules
2. To aid in deduplication of the request, we will consider the unique outbound call hash in the deduplication hash.

</details>

<details>

<summary>0.2.21-1</summary>

Bug Fixes:-

Enhancements:-

1. False positives removed in http tests by taking intersection with git diff.&#x20;
2. If the response of the request is other than 'OK', it will be run in fastMode by default.

</details>

<details>

<summary>0.2.20-4</summary>

Bug Fixes:-

1. SSO issue: Making messages more readable when logging in via SSO.

Enhancements:-

1. Ability to serialize bigint data type values by introducing a function for this

</details>

<details>

<summary>0.2.20-3</summary>

Bug Fixes:-

1. 'No email found' cases handled for SSO
2. AMQP biome fix for better code performance
3. (UI)Scrolling glitches resolved

Enhancements:-

</details>

<details>

<summary>0.2.20-1</summary>

Bug Fixes:-

1. Response difference error fixed. Now only the actual error will be marked red instead of the whole column.

Enhancements:-

1. Update in redirect URL for slack notifications. Now it will show the dashboard view
2. Introduction to SSO
3. Migration to prisma  db version 5.20.0 for better performance.

</details>

<details>

<summary>0.2.19-60</summary>

Bug Fixes:-

Enhancements:-

1. Increased tRPC error handling for non json input
2. Increased database performance by optimizing prisma db behaviour&#x20;

</details>

<details>

<summary>0.2.19-59</summary>

Bug Fixes:-

1. (UI) When accepting changes and updating the mock table we will coalesce globalMockVersion\_real.

Enhancements:-

</details>

<details>

<summary>0.2.19-57</summary>

Bug Fixes:-

1. Mongoose Instrumentation: Fields are considered  if at least one is key present. If nothing is present, then fields will not be shown in UI

Enhancements:-

</details>

<details>

<summary>0.2.19-56</summary>

Bug Fixes:-

1. Fixed the issue where the cluster path coming as an empty string in request due to body parser&#x20;

Enhancements:-

</details>

<details>

<summary>0.2.19-55</summary>

Bug Fixes:-

Enhancements:-

1. (UI)Wrap trimmed string and make the string expandable

</details>

<details>

<summary>0.2.19-54</summary>

Bug Fixes:-

1. Mongoose Instrumentation: Added filter fix in mock's readableInput for findAndUpdate. (Added support for distinct and projections)
2. Fixed discard request feature

Enhancements:-

1. Introduced Slack Notifications feature
2. Better logging capabilities for tRPC failures&#x20;
3. Storing time taken to boot the application via markappasready()

</details>

<details>

<summary>0.2.19-51</summary>

Bug Fixes:-

1. New redis patch : SELECT method to select a db number
2. Axios errors in auth0 instrumentations handled to reduce no of requests&#x20;

Enhancements:-

1. Show differences in the output of tags
2. The 'headers' key ignored while taking schema. This will further increase deduplication
3. Check Candidate URL is up to verify if app is up and running at correct port (for http and graphql)
4. The global mock version attribute added to improve in handling false positives of  'AI Matched' cases.

</details>

<details>

<summary>0.2.19-48</summary>

Bug Fixes:-

1. Aggressive deduplication for graphql by processing only input schema change in graphql requests’ 0th index in resolver chain&#x20;
2. Removed promise.all in updateRootReplayMocksAndDifferences API to avoid errors in CLI

Enhancements:-

1. Mark as noise from front end
2. bot to check in package.json to check if there is a stable updated version for the dependency

</details>

<details>

<summary>0.2.19-47</summary>

Bug Fixes:-

1. Sequelize Instrumentation: only perform transformation (changing models into names) up to a depth of 5 levels to avoid maximum call stack exceeded errors.
2. Stop capturing http requests generated by popular APMs when running in record & replay for HyperTest

Enhancements:-

</details>

<details>

<summary>0.2.19-45</summary>

Bug Fixes:-

1. Fixed AI forced matched mocks that were coming out in red, which implied an error.&#x20;

Enhancements:-

</details>

<details>

<summary>0.2.19-44</summary>

Bug Fixes:-

1. Sequelize Instrumentation: If toJSON is available in each index, then remove circular ref object from readable input

Enhancements:-

</details>

<details>

<summary>0.2.19-43</summary>

Bug Fixes:-

Enhancements:-

1. (UI)”Outbound Calls Not Found” changed to “Outbound Calls not Made”
2. (UI) Not of Outbound calls will be visible when the dropdown is collapsed.

</details>

<details>

<summary>0.2.19-42</summary>

Bug Fixes:-

Enhancements:-

1. (UI)- If a string value is too large in the response and the mock, it gets truncated partially and a copy button is presented to view it separately
2. (UI)- Requests recorded will be sorted by id instead of timestamp
3. (UI)- ‘Forced Matched’ gets renamed to ‘AI Matched’

</details>

<details>

<summary>0.2.19-41</summary>

Bug Fixes:-

1. (UI) Able to accept requests which have been deleted

Enhancements:-

1. Introduction to fetch instrumentation (http client)
2. Increase deduplication in GRPC by converting or decoding any JSON strings that appear as part of the payload, but only at the first level&#x20;
3. Output status is now a filter available while fetching tests from the cli. we can now run tests which only have say 'OKAY' status

</details>

<details>

<summary>0.2.19-38</summary>

Bug Fixes

Enhancements:-

1. (UI)-query, variables and headers are arranged in different tabs of request info for graphql in UI
2. (UI)-request id as a filter as well in all requests and test results
3. (UI)-mock id search filter for root mocks page in UI
4. (UI)-original mock id instead of testResponseMock id if present in UI
5. (UI)-sort requests by timestamp (ascending and descending) on UI

</details>


