# Imperative Extensions

Imperative extensions enable you to create reusable utility code to address complex use cases that aren't supported in UTAM's JSON grammar. For example, you can't use the JSON grammar to navigate a data table where each column shows data from a different type of component with different markup.

:::important
While imperative extensions are powerful, only use them as a last resort. They violate the declarative nature of UTAM and require you to individually implement and maintain them in each programming language that you use with UTAM.
:::

To author an imperative extension:

- In JavaScript, use an **ES module** that exports a set of **named functions**.
- In Java, use a class with a set of **static public methods**.

The utility code is referenced from a page object's JSON file so that a test writer can call the code.

## Reference Imperative Code from a Page Object

Declare an imperative utility method in a `compose` statement in a page object. A page object can reference any number of utility classes.

This page object declares a compose method, `myMethod`, that calls two utility methods, `utilityA` and `utilityB`. There's a separate `applyExternal` statement for each utility method.

```json
{
  "methods": [
    {
      "name": "myMethod",
      "return": "actionable",
      "returnList": true,
      "compose": [
        {
          "applyExternal": {
            "type": "utam-impext/utils/impext/exampleUtils",
            "invoke": "utilityA"
          }
        },
        {
          "applyExternal": {
            "type": "utam-impext/utils/impext/exampleUtils",
            "invoke": "utilityB",
            "args": [
              {
                "name": "stringArg",
                "type": "string"
              }
            ]
          }
        }
      ]
    }
  ]
}
```

The `applyExternal` property declares an imperative extension. For a full explanation of the syntax, see [Grammar: imperative extensions](/grammar/imperative-extensions).

## JavaScript Example

A JavaScript imperative extension must:

- Be an ES module (ESM) that exports a set of named functions.
- Have `.utam.js` as its file extension.

Additionally, the first parameter of each exported function must be a `context` object that represents the context that an imperative extension requires to interact with the page object. The `context` object holds a single `pageObject` property, which is a reference to the page object.

This example implements the `utilityA` and `utilityB` functions declared in the page object.

```javascript
// An imperative extension is authored as a JavaScript ES module.
// It exports a set of named functions.

// The first parameter of every function is a context object.
// It has a single pageObject property that holds a reference
// to the current page object in which the function has been referenced.
export async function utilityA(context) {
  const { pageObject } = context;
  // add logic for utility method here
}

// Destructure the context parameter to access the pageObject
// as alternative syntax with less code
export async function utilityB({ pageObject }, stringArg) {
  // add logic for utility method here
}
```

The return value is based on what the last action (`utilityB`) in the compose statement returns.

To call the `myMethod` method declared in the page object from test code, use `await context.pageObject.myMethod()` or `await pageObject.myMethod()` if you use destructuring.

For an interactive JavaScript example, see [this tutorial](https://utam.dev/tutorial/compose-utility).

## Java Example

To author a Java imperative extension, use a class with a set of **static public** methods.

The first parameter of each static public must be a `context` object that's an instance of `UtamUtilitiesContext`, which is responsible for passing the page object's context to the static method.

This example implements the `utilityA` and `utilityB` methods declared in the page object.

```java
package utam.utils.impext;

import utam.examples.pageobjects.ExamplePageObject;

public class ExampleUtils {

  public static void utilityA(UtamUtilitiesContext context) {
    // Explicit casting to the page object type
    ExamplePageObject examplePO =
        (ExamplePageObject)context.getPageObject();

    // call methods on page object here
  }

  public static List<Actionable> utilityB(UtamUtilitiesContext context,
                                          String stringArg) {
    // Explicit casting to the page object type
    ExamplePageObject examplePO =
        (ExamplePageObject)context.getPageObject();

    // call methods on page object here

    // return List<Actionable>
  }
}
```

The `UtamUtilitiesContext` object exposes the `getPageObject()` getter that returns an object of type `PageObject`. You must explicitly cast the type of the object returned by `getPageObject()` to the type of the current page object instance, which is a subclass of the `PageObject` type. In this example, the page object instance is `ExamplePageObject`.

:::note
The method implementation shouldn't interact with `Driver` or `Element` directly.
:::

## Return Value

By default, the return value of a compose statement is the return value of the last action in the statement. The framework can infer the return value from the `apply` value in the page object. The framework can't infer the return type of an imperative extension so you sometimes have to explicitly declare the return type if you write Java utility code.

A compose method has two optional properties where you can explicitly declare the return type.

- `return` is a string that declares the return type
- `returnAll` is a boolean that declares whether the return value is a list (`true`) or not (`false`). The default value is `false`. You must declare a `return` property if you declare `returnAll`.

These properties are declared at the method level, which means they are siblings of the `name` and `compose` properties. The page object for our example declares that the method returns a list of actionable elements.

```json
{
  "methods": [
    {
      "name": "myMethod",
      "return": "actionable",
      "returnAll": true,
      "compose": [ ...
      ]
    }
  ]
}
```

For JavaScript, you don't have to declare the `return` or `returnAll` properties because the default behavior suffices. However, for Java, you must declare the `return` property if the last action in the compose statement invokes utility code that has a non-void return type.

In Java, if the last action in the compose statement invokes utility code, these rules apply for the method's return type:

- If the `return` property is absent, the return type defaults to `void`.
- If the `return` property is declared, this value is set for the return type.

A utility method should return a type that can be referenced from JSON, which is one of:

- `void`
- A primitive type (string, number, boolean) or a list or an array of primitives
- Another page object or a list or an array of page objects
- A basic element (actionable, editable, clickable) or a list or an array of basic elements
