Skip to content

App

The App variable contains functions relating to the app itself.

Location

Returns the current location (if applicable for the given application type – non-webapps do not support this).

Example

javascript
var loc = App.location();

DANGER

Only web

Navigates to the given url. If the url is relative (e.g. somefolder/somefile.html) it will get appended to the current url.

Parameters

  • url a string representing the destination for the navigation act

Example

javascript
// Absolute url
App.navigate("http://dr.dk");

// Relative url
App.navigate("news");

DANGER

Only web

Session write

Store a value in the current session storage. This will be available across flows and for all applications.

Parameters

  • key a string denoting the key to store the value under
  • value an object to store
  • options an optional options object. Supported options are;
    • expires a timeout in minutes - after this interval has passed the value will be deleted. Default is 1440 min (= 1 day).

Example

javascript
// Storing a simple value - a string
App.session().write('mykey', 'myvalue');

// Storing an object - expires in 1 hour
App.session().write('myotherkey', { greeting: 'hello' }, { expires: 60 });

Session read

Read a value stored in the current session.

Parameters

  • key a string denoting the key to retrieve the value for

Example

javascript
var v = App.session().read('mykey'); // e.g. will return 'myvalue'

Session delete

Delete a value.

Parameters

  • key a string denoting the key to delete

Returns

The value deleted.

Example

javascript
var v = App.session().delete('mykey'); // e.g. will return 'myvalue'

Quit

Quits the application - be aware that this is a hard shutdown and the user will not be prompted to save any information before the application exits.

Example

javascript
App.quit();

Focused field

Returns a special field, which targets the currently focused UI element of the application. This can help in tricky cases where a UI element must be reached by means of tabbing. Using App.focusedField, even such a UI element can support actions like inspect, read and input. App.focusedField can also be used to verify that the focus is where it’s meant to be.

Example

javascript
var inspect = App.focusedField.inspect();

Getting access to an embedded browser instance

Note: The following only applies to native applications with embedded Internet Explorers and java applications with the teamdev JxBrowser commercial browser component.

Use the App.browserAt(path, options) method to get a DOM instance. The path argument is the path to the UI element containing the embedded browser - this normally has the url of the page displayed as its name and you can thus use the url as (part of) the path.

Alternatively you can use an existing field;

js
var f = new Field("**/Browser");
var b = App.browserAt(f);
// or simply
b = f.asBrowser();

DOM methods

Once you have DOM object you can invoke methods on it and read selected properties.

Title

js
var b = App.browserAt("**/Browser");
// Access the title
var title = b.title;

Location

js
var b = App.browserAt("**/Browser");
// Access the location
var url = b.location;

Eval(js)

Eval some JavaScript in the embedded instance.

WARNING

Note that apps running in Chrome and Edge are getting new restrictions rolled out for browser plugins at some point in 2024, which severely limit what can be done with eval in those browsers. Hosted browsers and java are not affected by this.

js
var b = App.browserAt("**/Browser");
var result = b.eval("(function() { return 'Hello, world!'; })();");

getElementById(id)

Returns a DOMElement (see below) given one with the id exists.

js
var b = App.browserAt("**/Browser");
var elm = b.getElementById("foo");

getElementsByTagName(tag)

Returns an array of DOMElements with the given tag.

js
var b = App.browserAt("**/Browser");
var allInputElements = b.getElementsByTagName("input");

querySelector(query)

Returns the first DOMElement matching the given query.

js
var b = App.browserAt("**/Browser");
var foo = b.querySelector(".foo");

querySelectorAll(query)

Returns an array of DOMElements matching the given query.

js
var b = App.browserAt("**/Browser");
var allFooClassedElements = b.querySelectorAll(".foo");

DOMElement methods

A DOMElement represents a single element in the DOM. It has the following properties and methods.

TagName

js
// we assume we have gotten the `elm` from a `DOM` method invocation e.g. via `getElementById`
var tag = elm.tagName;

InnerText, innerHTML and outerHtml

js
var t = elm.innerText;
var hi = elm.innerHTML;
var ho = elm.outerHTML;

Checked

Applies only to checkboxes and radio buttons.

js
var isChecked = elm.checked;
// we can also check the input using this property
if (!isChecked) {
  elm.checked = true;
}

GetAttribute(attr)

Get an attribute of the DOMElement.

js
var id = elm.getAttribute("id");

Click()

Click the DOMElement - only makes sense for elements that are clickable.

js
elm.click();

Input

Get/set the value of an input- or textarea element.

js
var content = elm.input;
// update it
elm.input = "foo";

Select()

Selects and element.

js
elm.select();

Eval()

Evaluate javascript with the dom element available in the variable element. Note: this is currently only supported for the teamdev JxBrowser embedded in a java app.

js
// trigger event on an input
elm.eval('element.dispatchEvent(new Event("input", { bubbles: true }));');

QuerySelectorAll()

Query for child elements under the given element. Note: this is currently only supported for the teamdev JxBrowser embedded in a java app.

js
var allInputs = elm.querySelectorAll('form input');

Set browser popup behavior

For the embedded chrome browser, you can specify what should happen when the automated page wants to open a popup window. The available options are as follows:

  • default the popup is loaded in a new desktop window. Note that no automation is available in such a popup window. As the name suggests, this is the default behavior.
  • prevent no popup window is shown. The user does not see any indication that a popup window was requested by the site
  • navigate the main window navigates to the url that was to be shown in a popup. This allows automation of the popup content but no further automation of the page that triggerede creation of the popup.
js
App.setPopupBehavior('prevent');

Evaluate javascript inside the application

For browser apps (chrome/firefox/edge/IE) and some java apps (with a javascript interpreter available) it is possible to send bits of javascript to the app in order to do things that are not directly possible with the combined Sirenia flow api.

WARNING

This is an advanced topic which often requires experimentation to gain the required knowledge of the app internals. This feature is also experimental in the sense that it can potentially affect the stability of the host application. Make sure to test thoroughly for regressions in the host app if you must go this route.

An example of using this api:

javascript
// Extract information by calling a static method in a java app
var patientId = App.eval("Class.get('com.somecompany.MainController').static.getCurrentPatientId()");

// Trigger event in web app
App.eval("document.querySelector('#userName').dispatchEvent(new InputEvent('input'))");

Java eval engines

In java apps there is sometimes a choice of javascript engines to choose between. The following example shows how to obtain a json summary of available engines:

javascript
var availableEngines = App.eval("", { engine: 'list-engines' });

The returned result shows the name of the engine and a list of aliases by which it can be selected.

Example output:

json
{
  "Oracle Nashorn": [
    "nashorn",
    "Nashorn"
  ],
  "Graal.js": [
    "Graal.js",
    "graal.js",
    "Graal-js",
    "graal-js",
    "Graal.JS",
    "Graal-JS",
    "GraalJS",
    "GraalJSPolyglot",
    "js",
    "JS",
    "JavaScript",
    "javascript",
    "ECMAScript",
    "ecmascript"
  ]
}

If no engine is specified in the engine option, the engine that responds to the js alias will be selected.

The following eval example targets the nashorn engine (which is available in java versions 8 through 14):

javascript
App.eval("Class.get('com.somecompany.SomeClass').static.aStaticMethod()", 
  { engine: 'nashorn' }
);

Java eval api

For java apps, multiple javascript statements can be passed to eval. The value of the last statement is returned.

A small javascript api is made available to make it easier to interact with the host application.

  • Class.get(String name) resolves the given fully qualified class name and returns the class. The above examples demonstrate how to access static members on the return value.
  • Class.info(String name|Object o|Class c) returns a json summary of a class either identified by its full name or by an instance of it or by a reference to the class. The methods array includes all public methods from the class itself and all of its super classes. The ownMethods array includes all public and private methods on the class itself.

Example output:

json
{
  "name": "eu.sirenia.dugong.TestClass",
  "methods": [
    "public boolean eu.sirenia.dugong.TestClass.testMethod(int,java.lang.String)",
    "public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException",
    "public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException",
    "public final void java.lang.Object.wait() throws java.lang.InterruptedException",
    "public boolean java.lang.Object.equals(java.lang.Object)",
    "public java.lang.String java.lang.Object.toString()",
    "public native int java.lang.Object.hashCode()",
    "public final native java.lang.Class java.lang.Object.getClass()",
    "public final native void java.lang.Object.notify()",
    "public final native void java.lang.Object.notifyAll()"
  ],
  "ownMethods": [
    "public boolean eu.sirenia.dugong.TestClass.testMethod(int,java.lang.String)",
  ],
  "fields": [
    "public java.lang.String eu.sirenia.dugong.TestClass.someField",
    "public final java.lang.String eu.sirenia.dugong.TestClass.argField"
  ],
  "constructors": [
    "public eu.sirenia.dugong.TestClass(java.lang.String)"
  ]
}
  • Class.inspect(Object o) returns a json representation of the given object complete with all public and private fields of primitive type. To follow references see the next overload.
  • Class.inspect(Object o, int depth) returns a nested json representation where the number of public/private field references followed is given in the second argument.

Tip: Start with low values of depth as the data returned may grow exponentially as depth is increased.

  • Class.inspect(Object o, String[] refs) returns a json representation of the object obtained by following field names given in the string array starting at the given object. Only primitive valued fields are included. To follow references from the target object see the next overload.
  • Class.inspect(Object o, String[] refs, int depth) returns a nested json representation of the object obtained by following the references given in the string array starting at the given object. The depth of the nesting is determined by the third argument.
  • Class.deref(Object o, String[] refs) returns the java Object (not a json representation) obtained by following the given references from the given object. This is a convenience allowing safe traversal of an object graph without having to handle individual null checks and other edge cases.

Examples:

javascript
// Examine members of host application class
var json = App.eval('Class.info("com.somecompany.MainController")');

// Examine field values from host application object
var script = 'var o = Class.get("com.somecompany.MainController").static.getInstance();' +
  'Class.inspect(o, 2);';
var json = App.eval(script)

// Extract system properties from java vm
var script = 'var props = Class.get("java.lang.System").static.getProperties();' +
  'Class.inspect(props, 1);';
var systemProperties = App.eval(script);

// Follow a list of references
var script = 'var c = Class.get("com.somecompany.MainController");' +
  'Class.deref(c, ["selectedPatient", "basicInfo", "name"]);';
var patientName = App.eval(script);

Getting hold of object instances

The observant reader may at this point wonder how to get hold of object instances in practice, when all we have access to are static fields and methods.

Static fields and methods will sometimes give access to object instances, but there is a more direct approach. See Field.eval

Eval in web apps

For web app types there is currently an extra limitation imposed on the script you pass to App.eval. It has to consist of a single javascript expression.

This needn’t limit the creativity you can employ when automating your app. The following example demonstrates a way to execute sequential statements despite this limitation.

javascript
var script = "var userNameInput = document.querySelector('#form input.user-name');" +
  "userNameInput.value = userNameInput.value.reverse();" +
  "userNameInput.dispatchEvent(new InputEvent('input'));" +
  "return userNameInput.value;"
var wrappedScript = "(function() {" + script + " })();";
var reversedName = App.eval(wrappedScript);

This construct is known as an Immediately Invoked Anonymous Function. It allows us to wrap sequential statements into a single expression thus circumventing the single-expression limitation.

Return values

App.eval always returns a string. To make the format of the string predictable, it is a good idea to make sure to format the result of your javascript statements as a string you can parse in your flow. If you return something other than a string from your eval javascript, a default serialization will attempt to serialize the result for you. For web apps, this consists of normal json serialization, which should be fine in most cases. For java apps, however, default serialization will not be quite so universally useful.

One thing to note is that strings returned from eval in a java app are currently subjected to some transformations before arriving back in your flow. You can undo those transformations by running the text through a function such as the following:

javascript
function restoreJson(j) {
  return j.replace(/<quote>/g'"').replace(/<colon>/g':').replace(/<semicolon>/g';');
}

With such a function, json text returned from App.eval can be parsed in your flow with ease as in the following example:

javascript
var serializedResult = App.eval("Class.info('java.util.ArrayList')");
var result = JSON.parse(restoreJson(serializedResult));

Script errors in eval

Any exceptions raised while evaluating your eval script will be raised as exceptions in your flow. This allows them to be handled in the normal way with a try/catch construct.