How to setup testing framework for user journeys with scripted nodes

Hi,

I was wondering if anyone here has setup any sort of unit testing setup for scripted nodes in user journeys. In some cases, the scripted nodes can get quite complex with multiple REST calls to third party applications. There are chances that scripted nodes could break if not handled carefully, and unit tests would be handy to ensure that doesn’t happen. But since journeys are run within ForgeRock, I couldn’t think of any good way to do it. Any idea on how one could do it? Or if it is needed at all?

Hi Anishetty,

Testing is overly complex when scripts depend heavily on external behaviour - and as much as possible it is recommended to avoid these - not only it increases the design complexity, therefore makes testing difficult, but also impact performances, burdens troubleshooting and monitoring tasks, and therefore, increases cost ownership. Granted there are cases where it is unavoidable - such as validating user credentials or biometrics against an external system. But this can be limited by either using as much as possible OOTB functionality (you don’t have to test it), or make sure that any data relevant to IAM is already provisioned (when the external call purpose is to complete partial identity data). In other word, simplify testing by simplifying the design.

Then for the remaining part where external calls are unavoidable, I know that few strategies have been around, which, if I remember well is around these lines:

  • Unit testing with mocks for AM objects and external services, OUTSIDE of the AM/Journey environment.
  • Unit testing within the journey - using artefacts in the journey to inject state and enable test results validation [ which then need to be removed in Production ].
  • Integration testing with the real journey - testing from the client application layer.

But note that I have seen the first 2 bullet points implemented very rarely (actually only once) - as this requires substantial development - this is quite an elaborated test environment.

Regards
Patrick

1 Like

Hi Anishetty,

I’m not from ForgeRock, but AFAIAA ForgeRock don’t currently provide any unit testing support for groovy/JS scripts. Like Patrick said, it is doable, but it’d require creating a test harness. It’d be nice if ForgeRock did provide such a test harness though, as with unit testing, you can more easily and quickly test various scenarios, especially various scenarios that can be harder to reproduce with an integration test.

For example, you could create a Java project where the unittests create the necessary mock objects, call the script, and check the output of the script and that the mocks were used correctly. For groovy scripts, there’ll probably be a straightforward way of doing this (or you could do the whole unittest harness in groovy). For javascript scripts, you’ll need to use a JS engine/interpreter e.g. graalvm.

The downside is that the script engine whitelisting/blacklisting won’t get tested by any of this. You could try and incorporate that in the test harness, potentially. At a certain point though, it would be easier if ForgeRock just created and provided such a test harness for people to use.

Thanks,
Ismail

1 Like

Just a reminder that Groovy scripts are not supported in ForgeRock Identity Cloud :slightly_smiling_face:

I actually did this recently by leveraging JUnit 5, Mockito, and Rhino (Rhino is ForgeRock’s JS engine). It was a pain to initially set up, mainly on figuring out the Maven dependencies and objects to mock. Now that I have learned how to do it, it’s not difficult to copy/paste the boilerplate into additional test cases.

I was able to write both unit and integration tests this way (the main difference being the integration tests can actually call REST services via the FR HTTP client).

I’m working with my team to further expand the project by converting it to Gradle and creating some custom tasks to also manage and deploy the script via the REST API. Once that is done, I plan to have a conversation with my company’s OSS team about releasing it to the community.

In the meantime, a few hints if you want to try this yourself:

  • You will need some additional dependencies beyond a typical Java auth node project. The more painful ones to figure out were add auth-nodes and openam-legacy-debug-api, so hopefully that saves you some time.
  • The general pattern should look something like this
cx = Context.enter();
scope = cx.initStandardObjects();
logger = LoggerFactory.getLogger(YourTest.class);
scope.defineProperty("logger", logger, 0);
scope.defineProperty("nodeName", "YourNodeName", 0);
scope.defineProperty("nodeState", nodeState, 0);
scope.defineProperty("systemEnv", systemEnv, 0);
scope.defineProperty("httpClient", httpClient, 0);
scope.defineProperty("action", action, 0);
String content = new String(Files.readAllBytes(Paths.get("path/to/nodescript.js")));
Object result = cx.evaluateString(scope, content, "node-name", 1, null);
1 Like