Skip navigation

Automation is the name of the game for streamlining your organization’s processes, and adopting the ServiceNow platform is the first step to transforming your business.

 

So we have to ask - are you still condemning one of your employees to sit and perform tests manually, over and over, each time you’ve modified forms or upgraded your instance? Or are you the poor soul stuck with that task?

 

By setting up automated testing that you can reuse and modify, you take the error-prone human factor out of the loop. The Automated Test Framework (ATF) allows you to create and run automated tests on your ServiceNow instance to confirm that the instance still works as designed after being upgraded or modified. In this installment of our NOWSupport best practices series list, the following best practices will help you leverage the power of ATF.

 

But first, if you want to understand the basics of ATF, check out this video on our NowSupport YouTube channel:

 

 

And now, within the guiding principle of Always safeguard your production instance comes our first best practice:

 

Always run ATF, or any other testing framework, within a dev or test instance but never within prod

 

This best practice goes hand-in-hand with why you shouldn’t develop on your production instance. You may be tempted to run a quick test on your production instance to verify a minor change, but never succumb to that urge. Why? Here are a couple scenarios:

  • A test can change data that may be designed to trigger actionable events, like sending out emails. You don’t want to have to explain to your manager why your test sent emails to your entire customer base, do you?
  • A test can impersonate users with extensive security access. Even a minor oversight could allow test user Joe Admin to run amok.

 

Start a test with an Impersonate step to ensure the test user has the required roles

 

We recommend that you always configure an Impersonate step as the first step in your test. To do this, select Impersonate as the first test step, and specify the user to impersonate. In doing so, you can ensure that the test user has the required roles and behaves like that specific user.

 

Why bother to employ this step if you run the test as the test designer user? Because your test could break if someone changes the test designer user roles, or disables the test designer user.  Or, you may find that the test can’t access a record or form properly based on the correct user roles. Setting up an impersonate step helps you avoid all these pitfalls.

 

Be aware of the browser throttling issue and how it can affect your tests

 

What causes ATF tests to fail? There are several possible root causes for this, including the tester failing to open the Client Test Runner, logging out of the session, or clearing the browser history on another tab, which affects all tabs. But inadequate central processing unit (CPU) power due to browser “throttling” is often at fault. Our previous best practices post, How to avoid ATF Testing Failures, gives you the lowdown on this issue.

 

When testing a form, set fields critical to your business process to ensure they all work

 

When creating a test for a form, you may be tempted to take shortcuts and only set the form’s required fields, or fields that you’ve edited. We recommend setting form fields critical to your business process, so that every time you run the test you’re verifying these fields.

A field must be present on the form in order to set it with Set Field Values.

 

Use the Test Logs and Test Transactions to troubleshoot test errors

 

And finally, here’s a shout out to the Test Logs and Test Transactions that provide a treasure trove of information for troubleshooting. Check them first before contacting customer support – the reason why a test is failing is probably recorded in one of these lists.

 

These are easy to find. After running your test, click Go to Result and the Test Results page displays.

ATF_test_results.jpg

 

  • Click the Test Logs tab to see a record of all the detailed information that the test can track, including browser console logs and other errors:

ATF_test_log.jpg

 

  • Click the Test Transactions tab to see a record of all system transactions recorded during the test:

ATF_test_transactions.jpg

 

Ready to get started with ATF? In this video, we show you how to set up your first ATF test:

 

 

For more information:

 

Getting started with the Automated Test Framework (product documentation)

Build and run your first automated test (product documentation)

Jakarta Juices Up Automated Test Framework (ATF) (blog post)

 

--

 

Behind the scenes here at ServiceNow, the Knowledge Management and Multimedia teams work closely with subject matter experts to disseminate critical information to our customers. We’ve found that certain topics come up frequently, in the form of best practices that can help you keep your ServiceNow instances running smoothly. This series targets those topics so that you and your organization can benefit from our collective expertise. If you have a best practices topic you’d like us to cover in this series, please let us know in the comments below.

 

To access all of the blog posts in this series, see our NOWSupport best practices series list.

One of the things I came across when prepping for my Jakarta blog post was that we've released a new field type called Name-Value Pairs. Intrigued by the name I looked into it and found this description from the field types article on the docs site:

 

Field that maps text values. Each mapping is one-to-one, however a single Name-Value Pairs field can contain multiple mappings. Each mapping must use a unique name, and the name cannot be empty.

 

From here I fired up a dev instance and created a scoped app (that's just how I roll), created a new table called Data, and added a name-value pair field called Data values. This is what the default record looks like:

 

Screen Shot 2017-09-19 at 9.48.18 AM.png

Adding values is very straightforward.

 

Screen Shot 2017-09-19 at 10.06.39 AM.png

 

It's nice to be able to store data like this, but I think the real value comes in when you start working with it from a script. For example, here is a script I can run against the record created above.

 

//grab the gliderecord object for the record in the screenshot
var gr = new GlideRecord('x_85636_name_value_data');
if (gr.get('a49e63a56f110300d8c252b10b3ee41e')) {

    //iterate over the current properties in the data values field and print the values
    for (var name in gr.data_values) {
        gs.info(name + " = " + gr.data_values[name]);
    }

    //add another property to the data values field
    gs.info("Adding a height property")
    gr.data_values.height = '50';
    gr.update();

    //iterate over the current properties in the data values field and print the values
    for (var name in gr.data_values) {
        gs.info(name + " = " + gr.data_values[name]);
    }

}

 

Here are the printed values:

x_85636_name_value: color = Blue

x_85636_name_value: length = 27

x_85636_name_value: width = 10

x_85636_name_value: Adding a height property

x_85636_name_value: color = Blue

x_85636_name_value: length = 27

x_85636_name_value: width = 10

x_85636_name_value: height = 50

 

And this is what the record looks like after I've added the height property to the field from the script:

Screen Shot 2017-09-19 at 10.10.58 AM.png

 

The docs article points out that this field type would be useful for holding header information for a web service request where the name of each mapping is the header such as Content-Type and the value is the header value, such as Application/json. I would expect that there are a lot of other good use cases out there for this type of field, where you need to store some data that is less structured and you don't want to create a field for every possible option.

 

If you can think of a use case where this field type could help, please share it in the comments below.

ServiceNow is a fantastic platform that is easy to learn - but hard to master. Despite having a thriving, friendly online community to ask for help, it can be very daunting as a beginner when you are enthusiastically bombarded with multiple solutions. You finally get a solution that seems to make sense, and seems to work - when an expert with even more points and badges tells you that what you are doing "is not best practice". You're then provided with 100 lines of code, that need to be added in multiple different places in the system, that all need to link up together somehow It's all very confusing and you don't understand any of it! And yes, I'm talking about GlideAjax.

 

Rarely a day goes by when someone isn't reaching out for help with Client Scripts. It is very easy to get a value from any table in ServiceNow from business rules and Script Includes, but Client Scripts are so much harder! The API is similar - yet different. It's hard to know what functions work on both client side and server side. You're suddenly told not to use GlideRecord Queries - or that you must have a callback method. The next developer will tell you that you must use GlideAjax and write lines and lines of code. But how - and why?

 

You finally get a grasp of the code, after 10 posts back and forth through 5 different people in 3 different time zones. You've got your Client Script, you've got your Script Include - and it finally works! That is until you realize your original requirement won't do exactly what your boss wants. You have no idea how and where to change the code and in the process of it your code doesn't work at all anymore! You wish you understood how you got there in the first place.

 

Well, you're in luck. Today I am going to go through my process of writing GlideAjax scripts, which I have learned from years of writing Client Scripts and GlideAjax Script Includes for customers and helping ServiceNow community members. I will show you the order I write them in and compartmentalize them - all testable along the way - and leave you with a library to reuse in future. I highly recommend installing Xplore in your instance before proceeding - however, I will also show you how OOB tools can be used.

 

  1. Proof of concept your Client Script (with getReference callback)
  2. Create a testable GlideAjax Script Include
  3. Refactor & Bring it all together
  4. Make your existing GlideAjax scripts reusable (Part 2)

 

Proof of concept your Client Script (with getReference callback)

Let's refactor an established OOB Client Script to be GlideAjax - (BP) Set Location to User. Add the Location field to the Incident form, under the Caller field, if it is not already present.

There is nothing wrong with using getReference as a quick way to setup a proof of concept for a requirement. See the client script code below.

 

function onChange(control, oldValue, newValue, isLoading) {
   if (isLoading)
      return;

   if (newValue == '') {
      g_form.setValue('location', '');
      return;
   }

   if (!g_form.getControl('location'))
      return;

   var caller = g_form.getReference('caller_id', setLocation);
}

function setLocation(caller) {
   if (caller)
       g_form.setValue('location', caller.location);
}

    

Create a testable GlideAjax Script Include
Navigate to "System Definition > Script Includes" and click "New". Populate the 'Name' field with something meaningful (like UserAjaxUtil) and click the 'Client callable' checkbox. This will automatically add the code to extend your script from AbstractAjaxProcessor, so you'll be able to call it from your Client Script. Save the record.

 

Separate Logic from Input
Create two functions in your Script Include as shown below. The golden rule of programming is that a complex problem is just a many simple problems that you need to solve at the same time. So break everything down into its problems! We have two problems to solve here:

  • Get data to and from the form
  • Do something with the data

As a first step, I like to create separate functions for your input from the client and your server side logic, so it becomes testable with different input parameters.

This is the pattern I use for all my GlideAjax scripts.

 

var UserAjaxUtil = Class.create();
UserAjaxUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {

     ajaxClientDataHandler: function() {
          //Get data from the form
          var gformData1 = this.getParameter('sysparm_parm1');
          //Setup data to return to form
          var answer={};
          //Do server side stuff
          answer['location'] = this.doServerSideStuff(gformData1);
          //Encode data to send back to the form
          return new JSON().encode(answer); 
     },

     doServerSideStuff: function() {
          //Put your logic here
     },

    type: 'UserAjaxUtil'
});

 

Now, let's put our logic into the doServideStuff() function

 

doServerSideStuff: function(userUID) {
     var grUser = new GlideRecordSecure('sys_user');
     if (grUser.get(userUID)) {
          return grUser.getValue('u_location');
     }
},

 

Notice that I have used GlideRecordSecure. Whenever you expose API to the client side, you want to ensure it enforces ACL's - otherwise you are introducing a security hole into your system.
Now, your function is testable using any given user.

 

Now you can call this doServerSideStuff() function using your favorite code testing tool.

 

var userAjaxUtil = new UserAjaxUtil();
userAjaxUtil.doServerSideStuff(gs.getUserID());

 

Output

2c22f8536f541200bbf707574f3ee44f

    

This way, we can test our logic is sound before we call the script from the Client Side and just 'hope for the best'.

 

Now you can simulate values that the client would be sending the Script Include. You can also write all the appropriate Unit Tests if you are doing Automated Testing.

Let's write the ajax input function now too. The whole code will look like this:

 

var UserAjaxUtil = Class.create();  
UserAjaxUtil.prototype = Object.extendsObject(AbstractAjaxProcessor, {  
  
     ajaxClientDataHandler: function() {  
          //Get data from the form
          var gformData1 = this.getParameter('sysparm_parm1');
          //Setup data to return to form
          var answer={};
          //Do server side stuff
          answer['location'] = this.doServerSideStuff(gformData1);
          //Encode data to send back to the form
          return new JSON().encode(answer); 
     },  
  
     doServerSideStuff: function(userUID) {  
          var grUser = new GlideRecordSecure('sys_user');  
          if (grUser.get(userUID)) {  
               return grUser.getValue('location');  
          }
     },  
  
    type: 'UserAjaxUtil'  
});  

 

Refactor & Bring it all together

Next up, we will need to alter our original onChange Client Script.

 

function onChange(control, oldValue, newValue, isLoading) {
   if (isLoading)
      return;


   if (newValue == '') {
      g_form.setValue('location', '');
      return;
   }


   if (!g_form.getControl('location'))
      return;

     var ga = new GlideAjax('UserAjaxUtil'); //Name of the Ajax Script Inclide
     ga.addParam('sysparm_name','ajaxClientDataHandler'); //Method to call
     ga.addParam('sysparm_parm1',newValue); //Parm1
     ga.getXML(userCallback);
}


function userCallback(response) {
     var answer = response.responseXML.documentElement.getAttribute("answer");
     answer = answer.evalJSON(); 
     g_form.addInfoMessage(answer.location);
     setLocation(answer);
}


function setLocation(caller) {
   if (caller)
       g_form.setValue('location', caller.location);
}

 

You can see below that the old Line of code has been commented out and replaced with the GlideAjax code. This is only for instructional purposes - it is generally a bad idea to comment out code with no explanation. If it's not needed - it should be removed. ServiceNow has Version Control via Update Sets, so you can always go back and look at past state.

 

Make your existing GlideAjax scripts reusable

You've now been given a procedure for writing GlideAjax that hopefully makes it a much more enjoyable process. You're happy that you've learned something new and that you've been able to implement a requirement using Best Practice. That is until your boss gives you a new requirement. He wants the Callers job title shown on the screen as well. Never fear - we have already written the foundations to make this a whole lot easier!

 

Part 2 Coming Soon! Feedback Welcome

------------
Please mark response with a Like, Helpful or Correct :)

If you been working with Order guides you know that there is room for improvement on how it works in ServiceNow. I've been looking into this in the view of that a requirement was to set a SLA on the order guide it self. Not on a specific item connecting to it, but the whole "request". Problem here was that on the request, you can't see from which order guide it was generated from or even if it was generated from a order guide or not.

 

So I made this video showing you how you can to do make this reality. It doesn't require so many steps and hopefully it will be useful to a lot of people out there and making you come up with your own areas to use this.

 

 

//Göran

 

Symfoni Logo Color Box.jpgsn-community-mvp.png

//Göran

ServiceNow Witch Doctor and MVP
-----------------------------------
For all my blog posts: http://bit.ly/2fCzj1g

Filter Blog

By date: By tag: