codycotulla
Tera Guru

Hi,

As part of my ATF test development, I ran into cases where I wanted to call a server-side script and pass in inputs and get outputs. Essentially, I wanted the functionality of the the OOTB Run Server Side Script, but I wanted to have inputs and additional outputs. 

I created a step configuration that includes input variables and output variables of different types, such as Document ID, Table, JSON, String. It also includes an input script like the OOTB Run Server Side Script. I've found having this step configuration available has made my testing easier. I use this step configuration, to pass parameters and other step outputs to server side scripts.

Here is the information on creating this step configuration:

Step Environment: Server Independent

Category: Server

Description Script:

function generateDescription() {
    // the global variable 'step' represents the current glide record
    try {
        // the global variable 'step' represents the current glide record

        var tokens = [];

        var description = "";

        // your code here
        description = "Run the script using the following parameters.";
        if (!gs.nil(step.inputs.u_table.getDisplayValue())) {
            description += "\n-- u_table: " + step.inputs.u_table.getDisplayValue() + "";
        }
        if (!gs.nil(step.inputs.u_record.getDisplayValue())) {
            description += "\n-- u_record: " + step.inputs.u_record.getDisplayValue() + "";
        }
        if (!gs.nil(step.inputs.u_input_string)) {
            description += "\n-- u_input_string: " + step.inputs.u_input_string + "";
        }
        if (!gs.nil(step.inputs.u_json_string)) {
            description += "\n-- u_json_string: " + step.inputs.u_json_string;
        }

  
		var outparams = "";
        var scriptString = step.inputs.u_script + "";
		
		if(scriptString.search(/^[\s]*outputs\.u_json_string/gm) != -1){
			outparams += "-- u_json_string\n";
		}
		if(scriptString.search(/^[\s]*outputs\.u_out_string/gm) != -1){
			outparams += "-- u_out_string\n";
		}
		if(scriptString.search(/^[\s]*outputs\.u_table/gm) != -1){
			outparams += "-- u_table\n";
		}
		if(scriptString.search(/^[\s]*outputs\.u_record/gm) != -1){
			outparams += "-- u_record\n";
		}
		
		if(!gs.nil(outparams)){
			description += "\n\n The script outputs values in following output parameters\n";
			description += outparams;
		}

        description = gs.getMessage(description, tokens);
        return description;
    } catch (e) {
        return description + "\n" + e;
    }

}
generateDescription();

Execution Script:

(function executeStep(inputs, outputs, stepResult, timeout) {
    var outputMessage = "";
    var errorText = "";
    if (gs.nil(inputs.u_script)) {
        // desired outcome did not occur within the timeout
        errorText = "Missing the script parameter.";
        outputMessage += "Failure! {0}";
        stepResult.setOutputMessage(get.getMessage(outputMessage, errorText));
        stepResult.setFailed();
    }
    try {
        var script = inputs.u_script;
        eval(script); // Here is where the input script gets executed.
    } catch (e) {
        outputMessage += "\n\nFailure! {0}";
        stepResult.setOutputMessage(gs.getMessage(outputMessage, e));
        stepResult.setFailed();
    }
}(inputs, outputs, stepResult, timeout));

Input Variables:

  • Table: Column Name = u_table, Type = Table Name
  • Record: Column Name = u_record, Type = Document ID
  • Input String: Column Name = u_input_string, Type = String, Max = 5000
  • JSON String: Column Name = u_json_string, Type = String, Max = 5000
  • Script: Column Name = u_script, Type = Script

Output Variables:

  • Table: Column Name = u_table, Type = Table Name
  • Record: Column Name = u_record, Type = Document ID
  • Out String: Column Name = u_out_string, Type = String, Max = 5000
  • JSON String: Column Name = u_json_string, Type = String, Max = 5000

Default Value for the u_script Input Variable:

Because this is executing inside the function in the Execute script, it has access to the variables set in that function: inputs, outputs, stepResult, timeout.

try {

// Get the input parameters
    var record = (!gs.nil(inputs.u_record)) ? inputs.u_record  + "" :  "";
    var table = (!gs.nil(inputs.u_table )) ? inputs.u_table + "" :  "";
    var jsonString = (!gs.nil(inputs.u_json_string )) ? inputs.u_json_string + "" :  "";
    var inputString = (!gs.nil(inputs.u_input_string )) ? inputs.u_input_string + "" :  "";

   if(!gs.nil(inputs.u_json_string)){
    var obj = JSON.parse(jsonString);
}
// add content to the message;
     var message = "";

// set the "success" variable to false if there is an expected result in the script
    var success = true;

// Set output values
// outputs.u_record = "";
// outputs.u_table= "";
// outputs.u_json_string = "";
// outputs.u_out_string = "";

    if (success) {
        stepResult.setOutputMessage('Success!' + message);
        stepResult.setSuccess();
    } else {
        stepResult.setOutputMessage('Failure!\n' + message);
        stepResult.setFailed();
    }

} catch (e) {
    stepResult.setOutputMessage('Failure!\n' + e + message);
    stepResult.setFailed();
}



// The inputs are a map of the variables defined in the inputs related list below.
// Inputs are consumed in the step configuration. Input
// values may be hardcoded or mapped from the outputs of a previous step.
// If a test author using your step uses mapping to pass in an output from a previous 
// test step then when referencing the input variable the mapping will be resolved 
// automatically
//  Example:
//      var myRecords = new GlideRecord(inputs.table);
//
// The outputs are a map of the variables defined in the outputs related list.
// Outputs should be set (assigned) in order to pass data out of a test step that
// can be consumed my mapping as an input to subsequent steps. 
//  Example:
//      outputs.table = gr.getRecordClassName()
//
//
// Note that inputs and outputs are strongly typed as defined in their variable definition.
// Their behavior is the same as a dictionary defined field of the same type in a table.
//
// The stepResult is a simple API for controlling the step pass/fail and logging with three
// methods:
//      stepResult.setFailed: Causes step to fail
//
//      stepResult.setSuccess: Causes step to succeed
//
//      stepResult.setOutputMessage: Log a message to step results after step executes.
//            Can only be called once or will overwrite previous 
//            message
//
// If neither setFailed or setSuccess is called the default is to succeed.
//
// See 'Record Query' for an example of a scripted step config 
// or see test 'Check change approvals get generated'
//
// Example usage of step timeout in script
//      var counter = 0;
//      // 'timeout' is a field on the step form
//      while (counter <= timeout) {
//            if (desiredOutcome) {
//                stepResult.setOutputMessage('Success!');
//                stepResult.setSuccess();
//                return;
//            }
//            counter++;
//            gs.sleep(1000);
//      }
//
//      // desired outcome did not occur within the timeout
//      stepResult.setOutputMessage('Failure!');
//      stepResult.setFailed();
//

Note: This custom step configuration cannot be used to run Jasmine tests. It's not a problem for me because I don't know how to run Jasmine tests.

One thing, I've been thinking about doing is adding a few more output variables, so that I can get more than one record ID from a script.

I hope that this helps someone else as much as it has helped me.

Thanks,

Cody

Comments
catwood
Tera Contributor

Great post! I came across this hunting for confirmation that Jasmine could not be utilized in the custom step configuration. Did you come across that info on the docs site or determine it by the fact that it blows up? Just wanted to understand the 'why' on that one. Thanks!

codycotulla
Tera Guru

Hi, I wish I had done some research on why the Jasmine couldn't be used with a custom step configuration. I didn't. I just saw that in the OOTB Run Server Side Script step configuration has a class type of Java and that it takes an jasmine_version as an input. From the information available, I couldn't see how to connect Jasmine with the script that I was running. Not an awesome justification for not supporting Jasmine in my custom step configuration, but it's the justification I have. 

Thanks,

Cody 

Gorkshanath Man
Tera Contributor

Hi Cody,

 

I was trying to read/get text as output from page using by passing xpath as input. But not able to succeed yet as I am new at ATF. For now when I am trying to create normal and use custom step. browser is closing in Client test runner. Can you able to help me in this If you have tried this kind of scenario ?

 

Thanks,

Gorkshanath

Sarah Zavala
Tera Explorer

Fantastic post! This really helped me to achieve so much in a short amount of time. I appreciate you, Cody! You're still helping people in 2022.

 

Thanks!

Version history
Last update:
‎09-06-2020 05:25 PM
Updated by: