---
schema_version: "1"
id: 4a222009536f70193598a16e915d00ddd2529936bea461d8d1b1d973352d50d2
title: Compose Methods
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/lwc/utam/references/methods.md
canonical_url: https://developer.salesforce.com/docs/platform/utam/references/utam-grammar/methods.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: 547bf5653793ded3d461a10f22c66ef1a94daa7a8ada98c7a9e090dd0118ea7a
products:
  - UI Test Automation Model
  - lwc
---
# Compose Methods

To combine several element actions, such as a method for login that sets a username, sets a password, and clicks a button, declare a `compose` method.

## Method Properties

A `compose` method has these properties:

- `name` (Required) String. The unique name of the method within this JSON file.
- `description` (Optional) String or Object. See [Method Description](#method-descriptions).
- `compose` (Required) Array. Each object is an element and a method.
  - `element` (Optional) String. The name of a basic element from the same JSON file. Defaults to `self`, which is a reference to the current page object. When a statement refers to the current page object, it can apply the page object's methods. Specify an element only if you need to operate on or interact with it. For an [explicit wait using the `waitFor` keyword](/grammar/explicit-waits), omit the element.
  - `apply` (Optional) String. If this property isn't defined, the getter method for the `element` property is called.
    - Basic element: the name of a [supported action](https://developer.salesforce.com/docs/platform/utam/references/utam-grammar/basic-actions.md) to apply to the element.
    - Custom element: any public method.
  - `args` (Optional) Array. If the `apply` action needs parameters, provide them in an array. Each element of the array has these properties:
    - `name` (Required) String. A parameter name that is unique in the scope of the `args` array.
    - `type` (Required) String. One of these primitive types: `string`, `number`, or `boolean`.
  - `matcher` (Optional) Object. Defines the filter criteria for the data returned by the `apply` method or the element's getter method.
    - `type` (Required) String. The matcher type for filtering data. For supported types, see [Matchers](#matchers).
    - `args` (Optional) Array. If the matcher type requires arguments, pass them in this array.
  - `returnAll` (Optional) Boolean. If `true`, the method returns an array (in JavaScript) or a list (in Java) of objects. The default is `false`.
  - `returnType` (Optional) String. Explicitly set the return type for the method. You can set a primitive type, such as `"string"`, `"number"`, `"boolean"`, or a custom type, such as `"my/page/object"`. This property is optional because the return type for a compose method can sometimes be inferred by the UTAM compiler. For more information, see [Method Return Types](https://developer.salesforce.com/docs/platform/utam/references/utam-grammar/method-return-types.md).
- `args` (Optional) Array. To access an argument passed to a compose method in multiple statements, declare a reusable argument at the method level. For more information, see [Argument Reference](https://developer.salesforce.com/docs/platform/utam/references/utam-grammar/arguments.md#argument-reference).

## Method Descriptions

A compose method or element can have a description that explains its usage, return value, and parameters. The description is used to generate JavaDoc or JSDoc.

The simplified `description` format is one string property:

```json
{
  "methods": [
    {
      "name": "myMethod",
      "description": "Gets an attribute of the root element",
      "compose": [
        {
          "element": "root",
          "apply": "getAttribute",
          "args": [
            {
              "name": "attrName",
              "type": "string"
            }
          ]
        }
      ]
    }
  ]
}
```

The generated method includes the following Javadoc or JSDoc. By default, the `@return` tag contains the inferred return type and the `@param` tag has the name and type of the parameter:

```java
/**
 * Gets an attribute of the root element
 *
 * @return String
 * @param attrName String
 */
```

The extended object `description` format enables you to describe more information, such as the return value:

```json
{
  "methods": [
    {
      "name": "myMethod",
      "description": {
        "text": ["Gets an attribute of the root element"],
        "return": "string with an attribute value",
        "throws": "NullPointerException if the attribute name is null",
        "deprecated": "in Summer '22 release"
      },
      "compose": [
        {
          "element": "root",
          "apply": "getAttribute",
          "args": [
            {
              "name": "attrName",
              "type": "string",
              "description": "string with attribute name"
            }
          ]
        }
      ]
    }
  ]
}
```

- `text` string array describing what the method or element does
- `return` (Optional) string that describes the return value
- `throws` (Optional) string that describes a thrown exception and when it's thrown
- `deprecated` (Optional) if the method is no longer supported, this string explains when and why the method was deprecated.

To provide a description for the parameter, we added a `description` property for the `attrName` argument. The description is only possible for non-literal (not hardcoded by value) arguments.

The generated method has the following Javadoc or JSDoc:

```java
/**
 * Gets an attribute of the root element
 *
 * @return string with attribute value
 * @param attrName string with attribute name to get
 * @throws NullPointerException if the attribute name is null
 * @deprecated in Summer '22 release
 */
```

In Java, the generated method is marked with an `@Deprecated` annotation.

The same `description` format can be added to any element:

```json
{
  "elements": [
    {
      "public": true,
      "name": "custom",
      "type": "utam/pageObjects/MyCustomObject",
      "description": "get area inside table",
      "selector": {
        "css": "css%s",
        "args": [
          {
            "name": "selectorArg",
            "type": "string",
            "description": "parameter description"
          }
        ]
      }
    }
  ]
}
```

## Return Types

See [Method Return Types](https://developer.salesforce.com/docs/platform/utam/references/utam-grammar/method-return-types.md).

## Invoke action for a basic element

This compose method sets text on the root element and clicks a submit button.

```json
{
  "type": ["editable"],
  "elements": [
    {
      "name": "submitBtn",
      "type": ["clickable"],
      "selector": {
        "css": ".submit"
      }
    }
  ],
  "methods": [
    {
      "name": "submitForm",
      "compose": [
        {
          "element": "root",
          "apply": "setText",
          "args": [
            {
              "type": "string",
              "name": "stringToEnter"
            }
          ]
        },
        {
          "element": "submitBtn",
          "apply": "click"
        }
      ]
    }
  ]
}
```

Here's the generated Java code:

```java
public void submitForm(String stringToEnter) {
    getRoot().setText(stringToEnter);
    submitBtn.click();
  }
```

Here's the generated JavaScript code:

```js
async submitForm(stringToEnter) {
    const _statement0 = await this.__getRoot();
    await _statement0.setText(stringToEnter);
    const _statement1 = await this.__getSubmitBtn();
    const _result1 = await _statement1.click();
    return _result1;
}
```

## Invoke method from the same page object

The `invokeSubmitForm` method simply invokes the `submitForm` method declared in the same page object.

```json
{
  "elements": [
    // ...
  ],
  "methods": [
    {
      "name": "submitForm",
      "compose": [
        // ...
      ]
    },
    {
      "name": "invokeSubmitForm",
      "compose": [
        {
          "apply": "submitForm",
          "args": [
            {
              "type": "string",
              "name": "stringToEnter"
            }
          ]
        }
      ]
    }
  ]
}
```

This pattern is useful if you want to reuse the same method in multiple compose statements. For example, you could call `submitForm` from `login` and `loginWithDeepLink` methods.

Here's the generated JavaScript code:

```js
async invokeSubmitForm(stringToEnter) {
    const _result0 = await this.submitForm(stringToEnter);
    return _result0;
}
```

## Invoke an element's getter

This compose method invokes the getter for the `myCustomComponent` element.

```json
{
  "elements": [
    {
      "name": "myCustomComponent",
      "type": "my/custom/component",
      "selector": {
        "css": "custom-component"
      }
    }
  ],
  "methods": [
    {
      "name": "composeGettingCustomElement",
      "compose": [
        {
          "element": "myCustomComponent"
        }
      ]
    }
  ]
}
```

Here's the generated JavaScript code.

```js
async composeGettingCustomElement() {
    const _result0 = await this.__getMyCustomComponent();
    return _result0;
}
```

## Invoke method from a different page object

This compose method applies the `someUnknownPublicMethod` method to the `myCustomComponent` custom element.

```json
{
  "elements": [
    {
      "name": "myCustomComponent",
      "type": "my/custom/component",
      "selector": {
        "css": "custom-component"
      }
    }
  ],
  "methods": [
    {
      "name": "invokeCustomElementMethod",
      "compose": [
        {
          "element": "myCustomComponent",
          "apply": "someUnknownPublicMethod"
        }
      ]
    }
  ]
}
```

Note that the compiler can't know if the `someUnknownPublicMethod` method actually exists, and what are its return value or parameters. The responsibility to validate those things belongs to the developer or a preruntime compilation step (depending on the setup).

Here's the generated JavaScript code:

```js
async invokeCustomElementMethod() {
    const _statement0 = await this.__getMyCustomComponent();
    const _result0 = await _statement0.someUnknownPublicMethod();
    return _result0;
}
```

## Matchers

Use a matcher to transform the return value of a compose statement.

This compose statement uses a matcher to return a non-null value.

```json
{
  "name": "matcherNotNull",
  "compose": [
    {
      "element": "single",
      "apply": "getAttribute",
      "args": [
        {
          "value": "\"readonly\""
        }
      ],
      "matcher": {
        "type": "notNull"
      }
    }
  ]
}
```

For more information on matchers, see [Element Filters: Matchers](https://developer.salesforce.com/docs/platform/utam/references/utam-grammar/element-filters.md#matchers).

## Chain Compose Statements

It's possible to "chain" compose statements. A chain applies a method or a getter to the result of the previous statement.

**important:** Chains are supported only if the previous statement returns a custom type (another page object).

To apply a method or a getter from the current statement to the result of the previous statement, use the `"chain": true` property inside a statement.

The chain methods approach has some disadvantages and limitations:

- Because the referenced elements and methods (except the first) are defined in other JSON files, the UTAM compiler can’t validate the correctness of the chain until the page object is generated. If the element doesn’t exist, if it isn’t public, or if the type is incorrect, the problem is discovered when the generated code is compiled.
- The current page object now depends on the content of other page objects, so changes in those might prevent the page object from compiling. We notice the issue during build, but it's more difficult to manage.
- The page object author might not be aware of the internals. If another team adds a chained method, ownership of the page object is unclear.

Here are some examples of chaining compose statements.

### Compose container element with getter and public action

Consider the following test code samples:

```js
const myModal = await utam.load(MyModalWithDynamicContent);

// long version
const footerArea = await myModal.getContent(FooterAreaWrapper);
const footerButtonsPanel = await footerArea.getFooterButtonsPanel();
await footerButtonsPanel.clickButtonByIndex(1);

// short version
await myModal.clickSave();
```

It's possible to compose the long version into a short version using a chain.

```json
{
  "elements": [
    {
      "name": "content",
      "type": "container"
    }
  ],
  "methods": [
    {
      "name": "clickSave",
      "compose": [
        {
          // invoke container method with hardcoded type
          "element": "content",
          "args": [
            {
              "type": "pageObject",
              "value": "my/pageObjects/FooterAreaWrapper"
            }
          ],
          "returnType": "my/pageObjects/FooterAreaWrapper"
        },
        {
          // invoke getter
          "chain": true,
          "element": "footerButtonsPanel",
          "returnType": "my/pageObjects/FooterButtonsPanel"
        },
        {
          // invoke public method
          "chain": true,
          "apply": "clickButtonByIndex",
          "args": [
            {
              "value": 1
            }
          ]
        }
      ]
    }
  ]
}
```

### Chaining list to a list

If both previous and current statements return lists (`"returnAll": true`), the method is applied to each returned element using `flatMap`.

Consider the use case of a table with multiple rows and cells. Assume that each row and cell is a separate component.
Let's write a method that returns all cells inside a table.

- table row JSON

```json
{
    "elements": [
        {
            "type": "my/pageObjects/tableCell",
            "name": "tableCells",
            "selector": {
                "css": "table-cell",
                "returnAll": true
            }
        }
    ]
```

- table JSON

```json
{
  "elements": [
    {
      "type": "my/pageObjects/tableRow",
      "name": "tableRows",
      "selector": {
        "css": "table-row",
        "returnAll": true
      }
    }
  ],
  "methods": [
    {
      "name": "getAllCells",
      "compose": [
        {
          "returnType": "my/pageObjects/tableRow",
          "returnAll": true,
          "element": "tableRows"
        },
        {
          "chain": true,
          "returnType": "my/pageObjects/tableCell",
          "returnAll": true,
          "element": "tableCells"
        }
      ]
    }
  ]
}
```

Generated Java code:

```java
public final List<TableCell> getAllCells() {
    List<TableRow> statement0 = this.getTableRowsElement();
    List<TableCell> statement1 =
        statement0
            .stream()
            .flatMap(element -> element.getTableCells().stream())
            .collect(Collectors.toList());
    return statement1;
}
```

## Compose Container Invocation

A `pageObject` type parameter can be used to invoke a container method inside a compose statement.

```json
{
  "elements": [
    {
      "name": "containerElement",
      "type": "container"
    }
  ],
  "methods": [
    {
      "name": "composeContainerHardcoded",
      "compose": [
        {
          "element": "containerElement",
          "args": [
            {
              "type": "pageObject",
              "value": "utam-tests/pageObjects/myPageObject"
            }
          ],
          "returnType": "utam-tests/pageObjects/myPageObject"
        }
      ]
    },
    {
      "name": "composeContainer",
      "compose": [
        {
          "element": "containerElement",
          "args": [
            {
              "type": "pageObject",
              "name": "pageObjectCtor"
            }
          ]
        }
      ]
    }
  ]
}
```

Generated JavaScript code:

```js
// declaration
composeContainerHardcoded(): Promise<unknown>;
composeContainer<T extends _UtamBasePageObject>(pageObjectCtor: _PageObjectCtor<T>): Promise<unknown>;

// implementation
import _MyPageObject from 'utam-tests/pageObjects/myPageObject';

async composeContainerHardcoded() {
    const _result0 = await this.__getContainer(_MyPageObject);
    return _result0;
}

async composeContainer(pageObjectCtor) {
    const _result0 = await this.__getContainer(pageObjectCtor);
    return _result0;
}
```

## Compose Entering Frame

Frame and Root Page Object type parameters can be used to compose entering a frame:

```json
{
  "elements": [
    {
      "name": "frameElement",
      "type": "frame",
      "selector": {
        "css": "#frame"
      }
    }
  ],
  "methods": [
    {
      "name": "composeEnterFrameHardcoded",
      "compose": [
        {
          "element": "document",
          "returnType": "utam-tests/pageObjects/frameArea",
          "apply": "enterFrameAndLoad",
          "args": [
            {
              "type": "elementReference",
              "value": "frameElement"
            },
            {
              "type": "rootPageObject",
              "value": "utam-tests/pageObjects/frameArea"
            }
          ]
        }
      ]
    },
    {
      "name": "composeEnterFrame",
      "compose": [
        {
          "element": "document",
          "returnType": "rootPageObject",
          "apply": "enterFrameAndLoad",
          "args": [
            {
              "type": "frame",
              "name": "frameElementParameter"
            },
            {
              "type": "rootPageObject",
              "name": "pageObjectCtor"
            }
          ]
        }
      ]
    }
  ]
}
```

Generated JavaScript code:

```js
// declaration
import _FrameArea from 'utam-tests/pageObjects/frameArea';

composeEnterFrameHardcoded(): Promise<_FrameArea>;
composeEnterFrame<T extends _UtamBaseRootPageObject>(frameElementParameter: _FrameUtamElement, pageObjectCtor: _PageObjectCtor<T>): Promise<T>;


// implementation
import _FrameArea from 'utam-tests/pageObjects/frameArea';

async composeEnterFrameHardcoded() {
    const _statement0 = await this.getDocument();
    const _result0 = await _statement0.enterFrameAndLoad(await this.__getFrameElement(), _FrameArea);
    return _result0;
}

async composeEnterFrame(frameElementParameter, pageObjectCtor) {
    const _statement0 = await this.getDocument();
    const _result0 = await _statement0.enterFrameAndLoad(frameElementParameter, pageObjectCtor);
    return _result0;
}
```
