JavaScript Tests
JavaScript Tests can be created very easily and quickly, but you need some programming knowledge in JavaScript.
There are many templates available that require only minor customization. For example for SSL tests, HTTP tests, Tests calling OS commands (for example “ping”) and DNS Resolve tests.
If you have no programming knowledge or would like to record entire surfing sessions and run them as a test, we recommend using the HTTP Test Wizard.
Programming Guidelines and Performance
The JavaScript engine used is “Rhino”, which is very performant but somewhat limited in its JavaScript functionality.
There are two major limitations regarding programming Rhino JavaScripts:
- Variables in loops must not be declared with const. ‘const’ means ‘const forever’ in Rhino. Use ’let’ or ‘var’ instead of ‘const’ in loops.
- Optional function parameters are not supported. This means that function parameters cannot contain default values. For example, the function x(a = 5) is not valid. Workaround: In such a case, pass an object as function parameter.
We haven’t noticed any further limitations so far - everything else should work as expected.

This is due to Rhino itself, as hundreds of thousands of instructions are executed per second. It is also crucial that precompiled Java classes can be called directly as JavaScript functions during test execution.
JavaScript Test Editor
With the JavaScript Test Editor, you can create new tests and modify existing ones. You can also clone (deep-copy) a test.
Running a First SSL Test
The following will create a test that checks whether an SSL server certificate has expired or is about to expire. This test also measures the TCP connection establishment time and the SSL handshake time – which, if a Synthetic Monitoring Job is configured accordingly, can trigger an alert if the sum these values is too high.
Click “New JavaScript Test” in the editor:
Proceed as follows:
- Select the project and resource set in which the test files will be saved. Alternatively, you can create a new project or resource set. We recommend creating a separate resource set for each test.
- Select the appropriate test template.
- Enter any JavaScript file name.
- Enter the test name.
The test is now created and ready to run. You can also change the values of “serverHost” and “warnExpiredCertificateHoursBefore”:
Now click “Save & Execute” and select the Measuring Agent from which the test is executed:
Then click “Start Test Jobs” and wait a few seconds until the test is completed:
Then look at the log file of the job, which also contains the output of the JavaScript console:
If you click the “Analyze Result” button of the load test job you will see also the TCP connection establishment time and the SSL handshake time:
Now you might try what happens if you use a tyrannically high value for the expiration warning time
With the following test result:
User Input Fields
As you may have already noticed, the hard-coded values for “serverHost”, “serverPort” and “warnExpiredCertificateHoursBefore” in the test before are not practical, since a separate test would have to be created for each “serverHost”.
To make these values dynamic, so-called User Input Fields can be used.
To create such User Input Fields click “Resource Files of Test” in the editor:
Then click the User Input Fields Icon an call the wizard:
Enter the User Input Fields and then click “Save File”:
In “Select Resource Files of Test” select the corresponding file and click “Save” and “Close”:
First only a console.log statement is added to the code to try out what happens when executing the test:
The code of the test can now be modified as follows:
const serverHost = dkfqsRhinoTest.getUserInputFieldValue('host');
const serverPort = dkfqsRhinoTest.getUserInputFieldValue('port');
const warnExpiredCertificateHoursBefore = dkfqsRhinoTest.getUserInputFieldValue('warnExpiredBeforeHours');
That’s it
PKCS12 Client Certificates for SSL Test
The previously created SSL test doesn’t support PKCS12 client certificates. To implement this feature, follow these steps:
Click “Resource Files of Test” in the editor:
Copy or upload the *.p12 file of the client certificate to the resource set of the test. Then set the password for the client certificate:
In “Select Resource Files of Test” select the corresponding file and click “Save” and “Close”:
In the editor, scroll down to where the SSL test is executed and add the following two lines of code. Replace the file name ‘fischer@dkfqa.com.p12 ’ by our own file:
const clientCertAuthKeyManagers = dkfqsRhinoTest.getClientCertificateAuthKeyManagersByFileName(testContext, 'fischer@dkfqa.com.p12');
sslPortTest.setClientAuthKeyManagers(clientCertAuthKeyManagers);
That’s it
HTTP Tests
There are several templates for HTTP tests. We recommend starting with the test template “A Generic HTTP Session” which is explained in more detail below.
If you create such a test from the template, you will see that the test consists of two components:
- A specific part of the test, that specifies which HTTP requests are executed and how their results are checked.
- A generic part that executes the test.
Note: There are no hard rules for extracting variables from HTTP responses and using them in subsequent HTTP requests. You can do this in both parts of the test.
Let us first consider the generic part of the test, which is implemented in the JavaScript functions declareStatistics and executeTest:
Since there is nothing else to do at the moment, let’s look at the specific part of the test. This part of the test is located at the beginning of the source code:
The specific part of this test only supports two Session Element Types:
- pageBreak
- httpRequest
These session element types will now be explained in more detail.
Object pageBreak
- elementType : ‘pageBreak’
- statisticId : Must be unique across all elements
- sleepMillis : Delay time in milliseconds
- pageDescription : Description
Object httpRequest
- elementType : ‘httpRequest’
- statisticId : Must be unique across all elements
- httpMethod : The HTTP Method such as ‘GET’, ‘POST’, ‘HEAD’ …
- url : The URL, inclusive query parameters
- specificRequestHeaderFields : An array of HTTP request header fields that are additionally required for this HTTP request. The array elements are objects of { name : “…”, value: “…”}. It can also be an empty array. Never specify the header field “Content-Length”, this is assigned automatically by the HTTP client when required.
- hasRequestContent : Boolean flag, specifies whether the HTTP request has a request content.
- requestContent : Only considered if hasRequestContent === true. The request content as string.
- requestContentType : Only considered if hasRequestContent === true. The request content type. Example ‘application/json’.
- validHttpStatusCodes : An array of valid HTTP status codes of the HTTP response. Instead of the array, null can also be specified, then the HTTP status code will not be checked
- onReceivedResponse : A callback function with the parameters (responseHeaderFields, responseContentType, responseContent)
Callback function onReceivedResponse(responseHeaderFields, responseContentType, responseContent)
The function parameters contain the received HTTP response. This function can be used to check whether the HTTP response is correct, and can also be used to extract variable values from the response.
The function must return an object as return value that is structured as follows:
- responseOk : Required. A boolean flag. If this is false, an error is measured and the current session is aborted. if this is true, the total time of the HTTP call is measured (HTTP request time + HTTP response time).
- errorMessage : Required if responseOk === false. The error message as string.
- errorLog : Optional, only considered if responseOk === false. The error log as string which may contain also line terminators.
- errorContext : Optional, only considered if responseOk === false. The error context as string which may contain also line terminators.
After you have created the code for a session element, you must add the object to the session using sessionElements.push(<element>)
That’s basically all there is to it.
PKCS12 Client Certificates for HTTP Tests
Client certificates for HTTP tests are configured in the same way as described under PKCS12 Client Certificates for SSL Test
Additionally, you must tell the HTTP client which host and port the client certificate applies to.
let clientCertAuthKeyManagers = dkfqsRhinoTest.getClientCertificateAuthKeyManagersByFileName(testContext, '<certificate-filename>'); let parseURL = ParseURL.newInstance(url_1); let host = parseURL.getHost(); let port = parseURL.getPort(); httpClient.addClientAuthKeyManagers(host, port, clientCertAuthKeyManagers); // set the PKCS12 client certificate for the specific host and port
Input Files
Input files contain data that are dynamically available during test execution. For example, an input file can contain user accounts, i.e., their login name and password. In contrast to User Input Fields which can only be added once per test, a test can use multiple input files.
We recommend creating the input file in your local environment and then uploading it to the test’s resource set. Alternatively, you can create and edit such a file directly in the test’s resource set.
Example:
# Accounts Brown ; apr101995 Meier ; topsecret Miller ; 1234 Smith ; Dogs&Cats$23
To upload an input file click “Resource Files of Test” in the editor. Then click the Upload Icon, upload the file and check the Checkbox of the Input File. After that configure how the lines of the input file are parsed:
The following fields can be entered or checked:
- Token Delimiter: This is usually a single character, but can be also a string.
- Comment Tag: Lines which are starting with the comment tag are skipped. You can place also the comment tag within a line which means that the remaining part of the line is ignored. The comment tag is usually a single character, but can be also a string.
- Cyclic Read: If not checked, then the Lib.getInputFileNextLineTokens(’<file-name>’) function will return null when no further line can be read (at eof). On the other hand, if checked, the file is re-read after the end of file was reached.
- Randomize Lines: if checked then the order of the lines is randomized each time when the file is read.
- Trim Values: If checked then whitespace characters are removed from the start and end of the extracted values (tokens).
- Remove Double Quotes: If checked then double quotes are removed from the extracted values (tokens).
After testing the input file, click ‘Save Settings’ and don’t forget to click ‘Save’ in the ‘Select Resource Files of Test’ popup:
Then you can enter inside the function executeTest(testContext, virtualUserNumber) the code for getting the tokens of a next line, such as:
let inputFileName = 'UserAccounts.txt'; let nextLineTokensArray = Lib.getInputFileNextLineTokens(inputFileName); if (nextLineTokensArray === null) { console.log(`End of File reached for input file ${inputFileName} - user [${virtualUserNumber}] aborted`); // Lib.registerLoopFailed(); break; }
You may have also a look at the template Demonstration code for ‘additional job arguments’, ‘user input fields’ and ‘input files’.
Output Files
Output files are very easy to implement, you can simply write to these data line by line without having to declare the files beforehand:
// the output file will be created if it does not exist yet Lib.appendLineToOutputFile('out.txt', `user = ${virtualUserNumber}, url = ${url}, status code = ${httpResult.statusCode}`);
Executing Tests using OS Commands
Executing operating system processes, or calling processes that execute operating system commands, is supported:
After starting the process, you can wait for its completion. The process output can then be interpreted and measured as a test result.
For example, a “ping” of a host
Note that the OS command and the command line arguments must be passed as an array of strings.
// let osProcess = OsProcess.newInstance(['bash', '-c', 'ping -c 3 -W 5 -n ' + host]); let osProcess = OsProcess.newInstance(['ping', '-c', '3', '-W', '5', '-n', host]); // execute the ping directly osProcess.setCollectStdout(); osProcess.start(); Lib.registerSampleStart(statisticId); // 'All Purpose Interface' osProcess.waitFor(); let errorLog = ""; let processStdoutLinesArray = osProcess.getStdoutLines(); let averagePingTime = null; for (let line of processStdoutLinesArray) { errorLog = errorLog + line + '\n'; console.log(line); if (line.includes('min/avg/max')) { // rtt min/avg/max/mdev = 0.045/0.075/0.091/0.021 ms averagePingTime = Math.round(Number(line.split('/')[4])); console.log(`averagePingTime = ${averagePingTime} ms`); } } if (averagePingTime === null) { Lib.addSampleError(statisticId, `ping to host ${host} failed`, "error", `ping failed`, errorLog, ""); Lib.registerLoopFailed(); // report the loop as failed continue; // abort the loop and continue with next loop } Lib.addSampleValue(statisticId, averagePingTime); // 'All Purpose Interface' loopTime = loopTime + averagePingTime;
DNS Resolver Test
With such a test you can check the IPv4 and IPv6 addresses of a DNS hostname. This test also detects unwanted IP addresses and reports them.
Create a new test by selecting the template Get and verify the IPv4 and IPv6 addresses for a DNS hostname:
Modify the upper part of the test:
- dnsServer
- hostname
- expectedIPv4Addresses (an array of strings)
- expectedIPv6Addresses (an array of strings that can also be empty)
That’s it