- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago - last edited 3 weeks ago
Hello - This might be an old question, but trying to get some answers or is there any workarounds for this.
I am trying to keep the common library of functions in one place, and want to use inside my custom UI step config definitions, instead maintaining duplicate copies in each/every custom UI step config.
So, I understood like System UI - UI Scripts is for client-side actions, and Script Includes for server-side tasks.
Both the System UI - UI Scripts and SCRIPT ICNLUDES are not showing or accessible inside the custom UI step config scripts.
Is there any business rules or polices that should be modified or it is not intended or cannot be used this way?
Appreciate any inputs on how I can use them or enable to access them inside the UI step config.
Solved! Go to Solution.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
The first parameter for getScripts is the name of the ui script record + ".jsdbx". And you still need to call the method of the object as you didn't declare a global function.
var ATFAllUtils = {
test_ui: function() {
alert("-------- HELLO - I AM TEST_UI-----");
console.log("-------- HELLO - I AM TEST_UI-----");
return;
}
};
//...
assertionObject.executeStep = function(step, stepResult) {
ScriptLoader.getScripts("ATFAllUtils.jsdbx", my_call_back);
alert("-----------------HELLO MY STEP CONFIG A------------------");
passStep();
};
function my_call_back() {
ATFAllUtils.test_ui();
}Scriptloader is just an api to control how the script tags are loaded so probably you will have to remember to kill the test runner every time you make changes to the ui script (unless you load the ui script to the iframe inside the runner). It's also good to remember that ui scripts are cached so if you make changes to the ui script and they don't show you might need to flush system cache as well.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago - last edited 3 weeks ago
Not sure if I understand correctly but you are probably running into timing issues because the scripts are loaded asynchronously. You'd need to execute the step logic in the callback function but this might break the runner or your step
console.log("hello")
ScriptLoader.getScripts("Test.jsdbx", () => console.log("callback fired"));
console.log("world")
/*
print:
**hello
**world
**callback fired
*/Might be your best bet is to have a test step in the beginning that loads the ui script. Once it's loaded then you should be able to use it in any following step.
There are a quite a few workarounds available, one would be to use async/await and wrap the script loading into a promise.
function loadScriptAsync(name) {
return new Promise((resolve, reject) => {
ScriptLoader.getScripts(name, function () {
resolve();
});
})
}
await loadScriptAsync("Test.jsdbx");
ATFAllUtils.test_ui()You can just create a script tag and append it to head in dom, it would run synchronously.
<script src="https://instance.service-now.com/Test.jsdbx"></script>Or as you only run atfs in subprod anyway it does not matter if you make your ui script globally available, just keep it in subprod or inactivate in prod. Then you don't need to worry about loading it
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago - last edited 3 weeks ago
@lauri457 Thanks. Actually, I got my callback function called, and working for me. My Actual question is how I can get the return value out of it. I have tried like below, but no luck.
Is there any tips to get the return value?
//Global variable
var return_from_cb = "BEFORE ASSIGNING";
//---> Approach# 1
function loadScript() {
return new Promise((resolve, reject) => {
ScriptLoader.getScripts('ATFAllUtils.jsdbx', function() {
console.log("---- CONSOLE --- Loaded....");
alert("---- ALERT --- Loaded....");
});
});
}
async function my_call_back() {
try {
alert("Loading script ..............");
await loadScript();
alert("Calling testui..........");
return_from_cb = ATFAllUtils.test_ui();
alert("Called testui.........." + return_from_cb );
} catch (error) {
alert("my call back error --- " + error);
}
}
//---> Approach# 2
function my_load_callback() {
try {
alert("Loading script ..............");
ScriptLoader.getScripts('ATFAllUtils.jsdbx', function() {
console.log("---- CONSOLE --- Loaded....");
alert("---- ALERT --- Loaded....");
});
// Run code that depends on the script here
alert("Calling testui..........");
return_from_cb = ATFAllUtils.test_ui();
setTimeout(() => {
console.log("----1--" + return_from_cb);
alert("----1--" + return_from_cb);
passStep();
}, 5000);
} catch (error) {
alert("my call back error --- " + error);
}
}
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
3 weeks ago
That is my point, to get the script loading to await you have to make executestep async. The script that calls executeStep will not handle the promise so I doubt you will get this to work in a nice manner. The test runner will just start hanging as it progresses without failing or passing the step. I at least couldn't figure a good way to do it other than the "workarounds" above. Just having the ui script globally available will save you a lot of trouble
Consider this script
(function (step, stepResult, assertionObject) {
function loadScriptAsync(name) {
return new Promise((resolve, reject) => {
ScriptLoader.getScripts(name, function () {
resolve("script loaded");
});
});
}
assertionObject.executeStep = async function (step, stepResult) {
try {
console.log(await loadScriptAsync("Test.jsdbx"))
var test = ATFAllUtils.test_ui();
stepResult.outputs.u_test = test;
stepResult.message = `${stepResult.outputs.u_test}`;
stepResult.success = true;
console.log("step finished")
} catch (e) {
stepResult.message = `Step failed: ${e}`;
stepResult.success = false;
}
};
assertionObject.canMutatePage = step.can_mutate_page;
})(step, stepResult, assertionObject);What happens is something like
executeStep immediately returns a promise
test runner does not pause, because it has no handler for the promise
the async function begins executing until the await and then yields
after yielding, the async function is placed in the microtask queue
test runner continues as if the function finished instantly and has no idea about the actual result of the step
- test runner starts hanging and will fail
