Skip to content

teslae1/harpi

Repository files navigation

Harpi

Harpi is a cli tool that executes *.harpi.yml files which are simple text based http request scripts. The file format of the *.harpi.yml files support sending http requests and asserting response data. Example:

variables:
  baseAddress: "https://test.com"
  itemId: "1" 
  itemTitle: "item 1"

requests:
  - name: "create data"
    method: "post"
    url: "$(baseAddress)/api/data/$(itemId)"
    jsonBody: 
      title: "$(itemTitle)"

  - name: "verify data now available"
    method: "get"
    url: "$(baseAddress)/api/data/$(itemId)"
    asserts:
      statusCodeEquals: 200
      codeAsserts:
        - name: "has expected title" 
          code: "response.title == '$(itemTitle)'"

The file can then be executed by using the "run" command

harpi run mytestfile.harpi.yml

Installing

npm install harpi_cli -g

Example

Download the example script to your current directory

curl -O https://raw.githubusercontent.com/teslae1/harpi/main/example.harpi.yml

List the requests of the script

harpi ls example.harpi.yml

Run the script

harpi run example.harpi.yml 

Saving and using response data

It is possible to assign response data to a variable for later use:

variables:
  myResponseValue: #Assigned by first request
  baseAddress: "https://test.com"

requests:
  - name: "create data with auto generated id"
    method: "post"
    url: "$(baseAddress)/api/data"
    variableAssignments:
      - variableName: myResponseValue
        code: "response.id"

  - name: "verify data now available at id"
    method: "get"
    url: "$(baseAddress)/api/data/$(myResponseValue)"
    asserts:
      statusCodeEquals: 200

Executing an individual request

It is possible to execute a single request - using the "ls" command all the http requests are listed with an id:

$> harpi ls myfile.harpi.yml
$> - request
$>   - id: 1
$>   - url: $(baseAddress)/api/data
$>   - method: post
$> - request
$>   - id: 2
$>   - url: $(baseAddress)/api/data/$(myResponseValue)
$>   - method: get

It is then possible to only execute request 2:

$> harpi run myfile.harpi.yml 2

Taking values as parameters

It is possible to take parameters from the command line - which then will be assigned to a variable. This is achieved by using the "required" keyword:

variables:
  token: required 
  apiKey: required

headers:
  Authorization: "Bearer $(token)"
  ApiKey: "$(apiKey)"

requests:
  - name: "verify data now available at id"
    method: "get"
    url: "https://test.com/api/data/2"
    asserts:
      statusCodeEquals: 200

This will now make it required to provide the defined variables when running the file:

$> harpi run myfile.harpi.yml --variables token=MYTOKEN,apiKey=MYAPIKEY

Headers

Example of setting headers for all requests

variables:
  token: required 
  apiKey: required

headers:
  Authorization: "Bearer $(token)"
  ApiKey: "$(apiKey)"

requests:
  - name: "This request will have both the headers defined in header"
    method: "get"
    url: "https://test.com/api/data/2"
    asserts:
      statusCodeEquals: 200
  - name: "This request will also have both the headers defined in header"
    method: "get"
    url: "https://test.com/api/data/2"
    asserts:
      statusCodeEquals: 200

Waiting between requests

It is possible to insert a wait between two requests:

variables:
  myResponseValue: #Assigned by first request
  baseAddress: "https://test.com"

requests:
  - name: "create data with auto generated id"
    method: "post"
    url: "https://test.com/api/data/1"
    #Waiting 500 milliseconds before executing next request
    waitBeforeNextRequest:
      name: "Waiting for data to be prepared"
      milliseconds: 500

  - name: "verify data now available at id"
    method: "get"
    url: "https://test.com/api/data/1"
    asserts:
      statusCodeEquals: 200

Auto generated values

It is possible to auto generate values like guids and dates. The values will be regenerated whenever the first request is executed

variables:
  currentDate: $(date)
  dateFiveMinutesInFuture: $(date.addMinutes(5))
  autoGeneratedId: $(guid)
  
requests:
  - url: "https://test.com/api/data/$(autoGeneratedId)"
    method: "post"
    jsonBody:
      someDateProperty: "$(currentDate)"
      anotherDateProperty: "$(dateFiveMinutesInFuture)"

all supported types of asserts

Harpi supports a set of asserts and also supports you defining custom asserts as 'codeAsserts". codeAsserts have replaced "javascriptAsserts" since they are safer and evaluated using a minimal intepreter that does not allowed access to environment. The 'code' part of codeAsserts uses javascript-like syntax that makes it possible to define custom expressions that are expected to evaluate to a boolean value. The 'response' is the object representing the current response. if the response was json then the available 'response' object is an object deserialized from that json. If it was not json then the object is just the response body represented as a string.

variables:
  baseAddress: "https://test.com"

requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      statusCodeEquals: 200
      responseContains: "testTitle"
      codeAsserts:
        - name: "assert first element has expected title"
          code: "response[0].title == 'testTitle'"

The following is a list of examples that are supported by as code asserts

requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "assert text response includes value"
          code: "Object.values(response).includes('val')"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "assert element was inactive"
          code: "response.isActive == false"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "assert value had length more than zero"
          code: "response.value.length > 0"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "Assert first response had expected content inside of description"
          code: "response.value[0].Description.includes('desc')"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "Assert response first element description is either null or had expected content in description"
          code: "(response.value[0].Description == null) || (response.value[0].Description.includes('desc'))"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "Assert first element had a time generated that was older than 2025-10-02"
          code: "new Date(response[0].timeGenerated).getTime() < new Date('2025-10-02T00:00:00.9625552+00:00').getTime()"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "Assert start of incomingText has the expected value"
          code: "response.incomingText.substring(0,8) == 'expsubtext'.substring(0,8)"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "assert array response has atleast one element that is active"
          code: "response.some(r => r.isActive)"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "assert array response has atleast one element that is active"
          code: "response.some(r => r.isActive)"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "assert array response has exactly two elements that are active"
          code: "response.filter(r => r.isActive).length == 2"
requests:
  - name: "assert on response"
    method: "get"
    url: "$(baseAddress)/api/data/1"
    asserts:
      codeAsserts:
        - name: "assert array response first active element has expected id"
          code: "response.find(r => r.isActive).id == 1"

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 3

  •  
  •  
  •  

Languages