Requests

Learn how to specify a request in your test case.

You can make GET, POST, PUT, PATCH, DELETE and HEAD requests.

Each HTTP verb has a corresponding method defined on session: session.get("/path") or session.post("/users/create").

All requests require at least the request path and can have additional options.

Note that targets have to be specified using definition.addTarget().

session.get("/users/sign_up", requestOptions);

session.post("/users/create", {
  tag: "create-user",
  payload: {
    name: "Smith",
    email: "smith@example.com",
    password: "secret"
  }
});

Request options You can specify options for each request. Request options are optional and are specified within each request as a hash. Read on for a full list of all available options.

Request URL parameters using Placeholder

Use :placeholder keywords in the request URL and fill them with the params key in the request options object:

definition.session("get-url-parameters-session", function(session) {
  session.get("/root/:category/:product_id?view=:view", {
    params: {
      category: "foo",
      view: "FULL",
    }
  });
});

Mind that we replace category and view, but not product_id. The result is a GET request to /root/foo/:product_id?view=FULL.

Request Options

Payload for POST/PUT/PATCH/DELETE requests

payload can either be:

  • a string, which is send as plain text
  • or an object (key-value pairs), which is encoded and send as application/x-www-form-urlencoded.

Note that some applications might require an application/json Content-Type header for JSON encoded payloads.

{

  // as a plain text string
  payload: "payload string"

  // -OR- as application/x-www-form-urlencoded
  payload: {
    email: user.get("email"),
    password: user.get("password"),
  }

  // -OR- as a JSON string
  payload: JSON.stringify({
    productId: article.get("productId"),
    amount: 1
  })

}

Uploading binary payloads

If you need to upload binary payloads you can use the payload_from_file option:

var picture = session.ds.getRawFile("picture.png");
session.post("/upload", {
  payload_from_file: picture,
  // [more options]
});

In this example, the file picture.png will be loaded from the data sources of your organization. Make sure to upload it as a Raw File beforehand.

Multipart Payload

If you need to upload multipart payloads you can pass in a MultiPartBuilder to the multi_part_payload option. See the MultiPart Requests page for details and example.

Request Compression

You can request gzip compression for responses. The gzip option will set an Accept-Encoding header to request compressed responses from the server. The default value is false.

Note that the target server has to support that functionality to deliver compressed responses.

{
  // use gzip compression, default: false
  gzip: true
}

HTTP Headers

The headers option is used to set HTTP request headers (key-value pairs).

Note that you cannot set headers beginning with X-StormForger-.

Although allowed by RFC 2616 we currently only support unique header names.

{
  headers: {
    "X-AwesomeApp-Token": user.get("api_token"),
    "X-AwesomeApp-Mail": user.get("mail"),
  }
}

Tag Requests

The tag option specifies an identifier (tag) that is associated with the request. A tag may consist of letters, numbers, underscores and dashes and has to start with a letter.

Tags can be used when analyzing the test run.

{
  tag: "logout"
}

NOTE: You can skip requests based on their tag with the exclude_tags test option.

HTTP Basic Authentication

You can use HTTP basic access authentication. The authentication option is providing an HTTP Basic Authentication.

{
  authentication: {
    username: "tisba",
    password: "letmein",
  }
}

Response Extraction

The extraction option is a way to tell the test to extract parts of the response body, headers or cookies (see extraction).

{
  // use response content extraction
  extraction: {
    jsonpath: {
      "accessToken": "authorization.token",
    }
  }
}

Cookies

Each client automatically manages a cookie jar. Cookies sent by the server in responses to requests (via Set-Cookie header) are automatically added, updated and removed. You can add a cookie to a request using the additional_cookies option. Note that this cookies will only be set for the specific request.

{
  additional_cookies: [
    {
      name: "csrfToken",
      value: session.getVar("token"),
    },
  ]
}

XHR-Shorthand

Set the xhr option to true to perform a request with the correct headers for an XHR-Request.

session.get(url, {
  xhr: true
});

This will add the X-Requested-With: XMLHttpRequest header to the current request.

CORS-Shorthand

When performing a request that require a CORS preflight request you can set the following option that will create a preceding OPTIONS-Request that includes the correct Access-Control-Request-Method, Access-Control-Request-Headers and Origin-Headers.

session.get("/api/login", {
  cors: { origin: "https://www.example.com", tag: "cors-request-tag" }
});
  • origin is required and has to be a valid Origin-Header according to RFC 6454.
  • tag is optional and will default to either the requests tag-value (if provided, see Tag Requests) or the literal "cors"

Abort on Error

The abort_on_error option allows to abort the session if any http status code in the 400 to 500 range is received. This is an alternative to assertions and can also be set as a session default.

Setting Defaults

You can set defaults which will apply to requests like this:

session.defaults.setGzip(true);
session.defaults.setAuthentication({ username: "user", password: "letmein" });
session.defaults.setHeader("Host", "www.example.com");
session.defaults.sendRequestId(false);                        // to deactivate the request-id
session.defaults.sendRequestId({"header": "Correlation-ID"}); // change the request-id header
session.defaults.setAbortOnError(true);

Note that the following rules apply:

  • defaults apply only for requests following the definition of defaults
  • defaults are passed into sub-contexts (e.g. in case of if, times, etc)
  • defaults can be unset (using session.defaults.unset()). This only unsets defaults for the current context! Defaults will apply again if the sub-context has ended
  • defaults defined in sub-contexts do not apply after the sub-context has ended

Request Tracing

All requests are sent with certain headers to help tracing and understanding requests flowing through your infrastructure.

Header Example Value Comment
User-Agent StormForger-X/%VERSION (+https://stormforger.com) The user agent. The version will change over time.
X-Request-ID sf-{test_run_uid}-{request_id} A unique ID for every request - The test run UID makes it easy to correlate which test run originated the request
X-StormForger-User 154123c:1512415123415123acdf The user that started the test run. Note that is an internal format and users should not rely on a specific value

The X-Request-ID header can be deactivated by setting the request_id option to false. You can also change the header to a different name as follows:

session.get("/", {
  "request_id": {
    "header": "Correlation-ID"
  }
});

Note that this can also be configured in the setting defaults. If you want to provide your own request-ids, just set them via headers - We will not add a request-id if there is a conflict.

Connection Keep-Alive

Connection keep-alive only works within a single session. If the test case starts many sessions all doing only one request, no connections will be reused and you also test the number of connections per second.

If you want to actively close a connection after a request, you can simply set the header: Connection: close.

Timeouts

Each client launched with an arrival phase has its own HTTP client with individual timeouts. You can see these timeouts below.

Name Value Comment
KeepAliveInterval 30s KeepAlive is the interval between keep-alive probes to check if the connection is still alive
IdleConnTimeout 90s How long connections are kept open if unused
ConnectTimeout 30s TCP connect timeout
TLSHandshakeTimeout 10s Timeout for the TLS handshake
RequestTimeout 120s Overall request timeout - Includes connection, sending the request and receiving the response

session.lastHttpStatus()

The session.lastHttpStatus() helper returns the status code of the last request performed by the current session. If no status code is available, 999 is returned.

session.post(...);
session.check("checkout", session.lastHttpStatus(), "=", 200);

session.get("/products/:product", {params: {product: randomProductId}});
session.check("product_access_denied", session.lastHttpStatus(), ">=", 400);

NOTE: the lastHttpStatus() function returns the status of the previous request. If you want to keep the status around for longer, you have to save it to variable via setVar().

session.redirectTarget()

session.redirectTarget() returns an URL based the location header of the last request/response performed on the current session. Note that the status code must be a redirect status (3xx, except 304). This function guarantees that the returned URL has a protocol and host by backfilling the missing data from the previous request, if needed.

session.post("http://example.com/login", { abort_on_error: true });
session.assert("redirect_received", session.redirectTarget(), "!=", "");
session.get(session.redirectTarget());

In the example above, we perform a request to /login, aborting the session if we don’t receive a status code in the 2xx or 3xx range. Next, we check if we received a redirect target and follow it. Assuming we receive a 307 (temporary redirect) status code and /welcome in the location header, the second request would go against http://example.com/welcome, since session.redirectTarget() returns an URL backfilled with a host and protocol.

Please note: If you use session.redirectTarget() to follow a redirect, you need to make sure that the target is allowed. Otherwise you will see “URL forbidden” errors in your test run.

Last modified November 23, 2022