Java Script Code Block Example
Code Blocks
So far, we've mostly been working with steps that perform a single action at a time, like HTTP steps in Protocol Scripts or navigate, click, and type steps in Browser Scripts. Those single steps can accomplish a lot if your script proceeds in a linear fashion (as most test scripts should), but what if you need special control flow or conditional logic or looping?
Loadster's answer is Code Blocks.
JavaScript Code Blocks
Code blocks can exist anywhere in your script. In fact, if you wanted to you could make a script that's just a single code block, and do everything in JavaScript.
Code blocks are more flexible than ordinary step-by-step scripting because you have the control flow of an actual programming language: looping, conditionals, functions, etc.
To add a code block to your script, select Add Code Block from the top bar.
Code block variable and function scoping
Code blocks are individually scoped to the bot that is executing them. That means that if you declare a variable or function in a script, it will exist only for that bot running the script, and not for any other bots that might also be running the script.
Just like a real human user, each bot interacts with your site independently of all the others.
Also, since the scripting language is JavaScript, ordinary JavaScript variables (declared with let
or const
or var
) within a code block might be undefined outside that code block. If you need a variable to persist between steps, set it as a special bot variable with bot.setVariable("v", v)
so that the value ${v}
remains in scope throughout the script.
Global JavaScript objects
Beyond all the standard JavaScript language constructs, code blocks expose a few important objects specific to Loadster that you can use in your scripts.
bot
The bot
object is global within the context of a single bot. It represents the bot currently executing the code block. This bot
object exposes the following methods:
/** * Pause for a specific number of milliseconds (these are synonymous). */ bot . wait ( milliseconds ); bot . sleep ( milliseconds ); /** * Get the time, in milliseconds, relative to the start of the test. */ bot . getTime (); /** * Get and set bot variables. */ bot . getVariable ( 'account' ); // get the value of the "account" bot variable bot . getVariable ( 'account' , 1 ); // get the second column, if it's a multi-column dataset bot . setVariable ( 'user' , 'a1350' ); // set a bot variable /** * Override the global halt setting, just for this bot. * This will allow HTTP 4xx/5xx and other things that would normally stop the script, without stopping the script. */ bot . setHaltOnErrors ( false ); /** * Tells how many iterations of the script have been completed by this bot, starting with 0. */ bot . getIteration (); /** * Tells which bot is currently running the script, if the bot is running in a group. * This can be useful in uncommon cases when only certain bots should perform certain actions. */ bot . getBotNumber (); /** * Starts and stops a timer. When you use custom timers, the amount of time elapsed between starting and * stopping the timer will be reported in the results. */ bot . startTimer ( "My Checkout Flow" ); bot . stopTimer ( "My Checkout Flow" ); /** * Runs a custom function inside a timer. This is shorthand for starting and stopping the timer separately. */ bot . timer ( "My Checkout Flow" , () => { }); /** * Makes the bot exit the script early. */ bot . exit ();
It's important to note that, even though the syntax is JavaScript, these methods are all synchronous. There is no need to do a promise chain or callbacks or anything like that, because the actual processing is done behind the scenes by multithreaded workers, so synchronous programming here is not the dangerous practice it might seem to be if you come from a background in single-threaded JavaScript development.
http
Every bot has access to an HTTP client called http
that can make requests. These equate to regular HTTP steps in an HTTP script, but you can run them programmatically from a code block too.
// Make HTTP requests http . get ( url , args ); http . post ( url , body , args ); http . put ( url , body , args ); http . patch ( url , body , args ); http . delete ( url , args ); http . options ( url , args ); http . trace ( url , args ); // Add a header to all future requests to a host http . addHostHeader ( 'slothereum.cc' , 'X-Slothentication' , 'ymmv2880' ); // Remove host headers matching a host/name/value http . removeHostHeaders ( 'slothereum.cc' ); http . removeHostHeaders ( 'slothereum.cc' , 'X-Slothentication' ); http . removeHostHeaders ( 'slothereum.cc' , 'X-Slothentication' , 'ymmv2880' ); // Add or remove global headers for all requests to all hosts http . addGlobalHeader ( 'X-Automated-Testing' , 'yes' ); http . removeGlobalHeader ( 'X-Automated-Testing' );
browser
In browser scripts, code blocks also give you direct programmable access to the bot's browser instance. Here are a few examples of what you can do.
// Navigate to a page and click on a link browser . navigate ( 'https://slothereum.cc' ); browser . click ( 'a[href=/login]' ); // Wait 3 seconds bot . wait ( 3000 ); // Wait for an element to be "visible", "hidden", "attached", or "detached" browser . waitFor ( '.spinning-overlay' , 'hidden' ); // Wait up to 5 seconds for an element to be hidden, and then silently move on browser . waitFor ( '.spinning-overlay' , 'hidden' , { timeout : 5000 , silent : true }); // Type a username and password and submit the form browser . type ( '.username' , 'sloth' ); browser . type ( '.password' , 'chunk' ); // Type instantly with no delay between keystrokes browser . type ( '.greeting' , 'Hello' , { delay : 0 }); // Type very slowly with 1250ms between keystrokes browser . type ( '.greeting' , 'Hello' , { delay : 1250 }); // Click the submit button on a form browser . click ( 'form input[type=submit]' ); // Click something if it shows up within 3 seconds, otherwise move on without complaining browser . click ( '#cookie-warning' , { timeout : 3000 , silent : true }); // Choose a file in a file input browser . chooseFiles ( 'input[type=file]' , [{ name : 'lolcat' , contentType : 'image/jpeg' , contentBase64 : 'UklGRuZ/AABXRUJQVlA4INp/AABwrAGdASr0AQACPjkYi0QiIaET' }]); // Set HTTP Basic or NTLM credentials for any site that requires them browser . setHttpAuthentication ( 'myUsername' , 'myPassword' ); // Hover a menu and click the first item browser . hover ( '.menu' ); browser . click ( '.menu li:first-child' ); // Select an option from a select element browser . selectByIndex ( 'select[name=countries]' , 1 ); browser . selectByValue ( 'select[name=countries]' , 'HR' ); browser . selectByText ( 'select[name=countries]' , 'Croatia' ); // Evaluate JavaScript in the browser window let greeting = browser . eval ( 'document.getElementById("#greeting").innerHTML' ); // Resize the browser viewport and take a screenshot browser . setViewportSize ( 1800 , 1200 ); browser . screenshot (); // Answer confirm() dialogs with "OK" instead of "Cancel" browser . setDialogConfirmation ( true ); // List all of the bot's browser windows/tabs browser . listWindows (); // Opens a new window/tab and makes it active browser . openWindow (); // Get the bot's currently active browser window/tab browser . getActiveWindow (); // 0, 1, 2... // Focus a different browser window/tab browser . setActiveWindow ( 0 ); // the bot's original tab browser . setActiveWindow ( 1 ); // the first opened tab browser . setActiveWindow ( 2 ); // and so on... // Close a browser window/tab browser . closeWindow ( 1 ); // Set and unset global request headers browser . setGlobalHeader ( 'X-Loadster' , 'true' ); browser . removeGlobalHeader ( 'X-Loadster' );
Again, these are blocking synchronous calls with processing happening behind the scenes, so you don't need to use await
or callbacks or promise chains for sequential browser actions.
console
Code blocks also expose a simple console
for logging:
console . log ( message ); console . warn ( message ); console . error ( message );
Messages written to the console show up in the script logs and assist you in debugging the script.
JSON
If you're testing APIs, you'll often need to parse JSON data to look at specific properties. You can use the ordinary JSON.parse
for this.
var simple = JSON . parse ( "{a: 1}" ); // parse an arbitrary JSON string var body = JSON . parse ( response . string ()); // parse the response body in a validator
XML
Since XML parsing isn't a standard language feature of JavaScript, Loadster includes the open source xmldoc parser. Additional documentation for this parser is available on GitHub, but here's a quick example:
var xml = XML . parse ( response . string ()); var users = xml . childrenNamed ( "user" );
formats
Loadster provides a built-in formats
library to help you with encoding and decoding strings, and with generating timestamps, UUIDs, and random data. Here are some examples of inputs and outputs.
formats . uppercase ( "hello" ); // HELLO formats . lowercase ( "HELLO" ); // hello formats . urlencode ( "user@example.com" ); // user%40example.com formats . urldecode ( "user%40example.com" ); // user@example.com formats . base64encode ( "user:pass" ); // dXNlcjpwYXNz formats . base64decode ( "dXNlcjpwYXNz" ); // user:pass formats . xmlescape ( "11 > 10" ); // 11 > 10 formats . xmlunescape ( "11 > 10" ); // 11 > 10 formats . htmlescape ( "<p>" ); // <p> formats . htmlunescape ( "<p>" ); // <p> formats . timestamp ( "%Y-%M-%d" ); // 2020-07-04 formats . randomalpha ( 12 ); // zmLkWMwtEhOD formats . randomalphanumeric ( 10 ); // F6kEq53p3W formats . randomnumeric ( 8 ); // 62331478 formats . uuid (); // 8ffdb4ef-9e87-4b58-9415-f4c454f0a2ee
crypto
Occasionally you might need to apply a hashing function to a piece of data (with an optional secret) to generate a hashed value that your server expects. Some of the more commonly used hashes are included in Loadster's built-in crypto
library, which you can call from any code block.
crypto . hmacsha512base64 ( "input" , "secret" ); // Ksle03F+BCxwZKX6fDGCMM022F4G+P+Dc9BMoX42Fingn0a38VH/OCo/SMWxkSFEbkXCWI8P8d6fdLBADa74Hw== crypto . hmacsha384base64 ( "input" , "secret" ); // is0XLFfl9kpaMnpDdiMkwOJ4eYP7ez481SOKgiu6p/mC4SXCJzeVtbuU0z6auD7F crypto . hmacsha256base64 ( "input" , "secret" ); // jYmF0Et6vTLLqjd5o9qgGeDSaaIq7BWvjnKW9wLMaMY= crypto . hmacsha224base64 ( "input" , "secret" ); // LDdw8G3Ykt8vLV9+8gXABot+TCB01il0Hy5S8A== crypto . hmacsha1base64 ( "input" , "secret" ); // MEQPNt3CgJu9TIsfN6boDXWIwwM= crypto . hmacsha512hex ( "input" , "secret" ); // 2ac95ed3717e042c7064a5fa7c318230cd36d85e06f8ff8373d04ca17e361629e09f46b7f151ff382a3f48c5b19121446e45c2588f0ff1de9f74b0400daef81f crypto . hmacsha384hex ( "input" , "secret" ); // 8acd172c57e5f64a5a327a43762324c0e2787983fb7b3e3cd5238a822bbaa7f982e125c2273795b5bb94d33e9ab83ec5 crypto . hmacsha256hex ( "input" , "secret" ); // 8d8985d04b7abd32cbaa3779a3daa019e0d269a22aec15af8e7296f702cc68c6 crypto . hmacsha224hex ( "input" , "secret" ); // 2c3770f06dd892df2f2d5f7ef205c0068b7e4c2074d629741f2e52f0 crypto . hmacsha1hex ( "input" , "secret" ); // 30440f36ddc2809bbd4c8b1f37a6e80d7588c303 crypto . md5 ( "input" ); // a43c1b0aa53a0c908810c06ab1ff3967 crypto . sha1 ( "input" ); // 140f86aae51ab9e1cda9b4254fe98a74eb54c1a1 crypto . sha256 ( "input" ); // c96c6d5be8d08a12e7b5cdc1b207fa6b2430974c86803d8891675e76fd992c20 crypto . sha512 ( "input" ); // dc6d6c30f2be9c976d6318c9a534d85e9a1c3f3608321a04b4678ef408124d45d7164f3e562e68c6c0b6c077340a785824017032fddfa924f4cf400e6cbb6adc
Don't get too excited by the word "crypto" – the object is called that because it's a container for cryptography and hashing functions, not necessarily related to cryptocurrencies.
Examples of things to do in code blocks
There's nothing like learning by example! Here are a few contrived examples of things you can do with code blocks.
Example 1: Execute chained programmatic HTTP requests
The http
object (representing the HTTP user agent belonging to the currently running bot) has methods for all of the common HTTP methods (GET, POST, etc).
// GET http . get ( "https://slothereum.cc" ); // GET with additional page resources http . get ( "https://slothereum.cc" , { resources : [ "/style.css" , "/favicon.ico" ] }); // POST with a JSON body and custom header http . post ( "https://api.slothereum.cc/transactions" , { source : "08c2d5" , destination : "9a6bce" , amount : 1.05 }, { headers : { "Content-Type" : "application/json" } } ); // POST with a form body http . post ( "https://admin.slothereum.cc/login" , "username=sloth&password=chunk" , { headers : { "Content-Type" : "application/x-www-form-urlencoded" } } ); // DELETE http . delete ( "https://api.slothereum.cc/receipts/1133423" );
You can pass custom request headers with each request, either as an object with key-value pairs, or in an array.
// Pass request headers in an object http . get ( "https://slothereum.cc/api/profile" , { headers : { "Accept" : "application/json" } }); // Pass request headers in an array http . get ( "https://slothereum.cc/api/profile" , { headers : [ { name : "Accept" , value : "application/json" } ] });
Example 3: Validate HTTP responses with validator functions
Validators (similar to the Validation Rules that you can use with ordinary HTTP steps) call a JavaScript function to examine the response and return true if it's valid, or false if it's not.
Validator functions can be normal JavaScript functions or the newer ES2016+ arrow functions.
You can specify multiple validator functions for a single response.
// A POST with a JSON body and validator function that requires an HTTP 201 status http . post ( "https://api.slothereum.cc/transactions" , { source : "08c2d5" , destination : "9a6bce" , amount : 1.05 }, { headers : [ { name : "Content-Type" , value : "application/json" } ], validators : [ // regular function validator syntax function ( response ) { return response . status == 201 ; }, // arrow function validator syntax works too! response => response . status === 201 ] } );
Example 4: Capture variables programmatically from an HTTP response
Often, the server will send you some data that you need to save and use later in your script.
In code blocks, you can capture these from the response and store them using a validator function. Note that we use the validators
for capturing too; there is no separate property for Capturing Rules as there is with ordinary HTTP steps.
Simply call bot.setVariable(name, value)
anywhere in your code block to set a bot-scoped variable. These special variables are available for the bot's entire iteration of the Loadster script, unlike ordinary JavaScript variables which are scoped to the individual code block and may not be available to subsequent steps.
// Create a random numeric string between 0-999999 let random = String ( Math . floor ( 1000000 * Math . random ())) // POST to register an account with the random username and capture a user_id http . post ( "https://admin.slothereum.cc/register" , { username : "sloth_" + random , password : "chunk" }, { headers : { "Accept" : "application/json" , "Content-Type" : "application/json" }, validators : [ response => { var body = JSON . parse ( response . string ()); if ( body . profile . user_id ) { bot . setVariable ( "user_id" , name ); // save the user_id for later return true ; // valid response! treat as a success } else { return false ; // invalid response! treat as a failure } } ] } );
Example 5: Accept HTTP 4xx/5xx status codes
By default, Loadster automatically interprets any HTTP 400 or higher status code as an error, and reports it as such.
But there are times when you might actually want an HTTP 4xx or 5xx status code. For example, you might be testing a REST API and expect it to return HTTP 409 Conflict when the resource already exists.
In such cases, you can use ignoreHttpErrors: true
with your request, so that Loadster will ignore the HTTP status codes and you can interpret the status code yourself.
// Make sure we get HTTP 409 when we try to register a duplicate user http . post ( "https://admin.slothereum.cc/register" , { username : "admin" , password : "admin" }, { ignoreHttpErrors : true , headers : { "Accept" : "application/json" , "Content-Type" : "application/json" }, validators : [ response => { return response . status === 409 ; } ] } );
Looping and conditional logic
Looping and conditionals can be done with all the usual JavaScript language constructs. This trivial example shows looping with a for
loop, the %
modulus function, an if
statement, and setting and getting special bot variables with variable interpolation of ${random}
.
console . log ( "We're in a nonsensical code step." ); console . log ( "It exists only to demonstrates random numbers, bot vars, and conditionals." ); // Set a bot variable to a random integer from 0 to 19 bot . setVariable ( "random" , Math . floor ( Math . random () * 20 )); // Loop and make 20 requests, with a random value and random wait times for ( var i = 0 ; i & lt ; 20 ; i ++ ) { if ( i % 2 == 0 ) { http . get ( "https://example.com/evens/${random}" ); } else { http . get ( "https://example.com/odds/${random}" ); } http . wait ( Math . random () * 2000 ); }
Limitations of code blocks
Keep in mind that code blocks do not run in the browser, so they don't have direct access to the live DOM the way browser-based JavaScript does. Be careful not to confuse them with on-page JavaScript (jQuery, React, etc). Rather, the scripts are executed by your bots running on the load engine, and they have access to objects like bot
, http
, response
, console
, etc.
If you need to run code inside the browser itself, check out Evaluate Blocks.
Getting help with code blocks
If you get stuck with code blocks or want to request another helper library, we're happy to help. Just shoot us an email. We're always interested in how you're using code blocks in Loadster.
Source: https://loadster.app/manual/code-blocks/
0 Response to "Java Script Code Block Example"
Post a Comment