---
schema_version: "1"
id: 186145f1f1aaf0c6cebdcd509f43af21bf24a530f5f1af8f3433455934e6dbc1
title: Guide for JavaScript Developers
collection: developer
version: current
locale: en-us
portal_url: https://docs.salesforce.com/developer/current/en-us/lwc/utam/guide/js-guide.md
canonical_url: https://developer.salesforce.com/docs/platform/utam/guide/js-guide.html
source_site: developer.salesforce.com
content_type: documentation
content_hash: d6f081ef1eb188ee1add79c9c11b3a2e31990dce388fc2acb8b171a82acf2144
products:
  - UI Test Automation Model
  - lwc
---
# Guide for JavaScript Developers

This document explains how to configure the UTAM compiler, generate UTAM JavaScript page objects and use them in a JavaScript or TypeScript UI test. Examples of tests and setup are available in the [JavaScript recipes repo](https://github.com/salesforce/utam-js-recipes).

## Compiler Setup

To configure the UTAM compiler, add a dependency for UTAM in your project. Optionally, create a JSON configuration file and declare the required options and the optional values for which the default values don't match your project structure.

### Project Dependencies for JavaScript

The `package.json` file configures the dependencies for a JavaScript project.

Add a development dependency for the UTAM compiler by running one of these commands:

- `yarn add utam --dev`
- `npm install utam --save-dev`

These commands are equivalent and add `utam` to the `devDependencies` property in `package.json`, where `x.y.z` represents the installed version and is the latest version by default.

```json
{
  "devDependencies": {
    "utam": "x.y.z"
  }
}
```

For a working example, see the [utam-js-recipes](https://github.com/salesforce/utam-js-recipes/blob/main/utam-preview/package.json) repo.

The `wdio-utam-service` dependency includes an adapter between UTAM page objects and the browser API that WebdriverIO provides. The dependency includes a transitive dependency on the UTAM compiler. If the project needs the UTAM compiler only, use the `"utam"` dependency instead.

Add a development dependency for `wdio-utam-service` by running one of these commands:

- `yarn add wdio-utam-service --dev`
- `npm install wdio-utam-service --save-dev`

Running one of these commands updates `devDependencies` to look like this:

```json
{
  "devDependencies": {
    "wdio-utam-service": "x.y.z"
  }
}
```

### Set Up Compile Step in package.json

This `package.json` file has a script that runs the `utam` compile CLI command. The `utam` CLI is installed locally in your project because you added it to the `devDependencies` in `package.json`. In this example, the compiler configuration file is `utam.config.json`.

```json
{
  "scripts": {
    "build": "yarn build:utam && yarn build:ts",
    "build:ts": "tsc -b tsconfig.json",
    "build:utam": "utam -c utam.config.json"
  }
}
```

The `build` script name is arbitrary. You could use another name, such as `compile`. Use the script name with `yarn` or `npm` to run the script. For example:

```bash
yarn build
or
npm run build
```

The `"build:ts"` option is needed only if you're using TypeScript.

### Compiler Configuration File

The compiler configuration file enables you to customize the [options](#configure-the-javascript-compiler) supported by the JavaScript compiler. We recommend `utam.config.json` as the name of the compiler configuration file. The file can have any name, as long as the name matches the value of the `-c` flag used with the `utam` CLI.

After you've added `utam` as a dependency, run the compiler using one of these approaches:

- Set up a script in `package.json`. If the script is called `build`, run `yarn build` or `npm run build`.
- Invoke the `utam` CLI. Use yarn: `yarn utam -c utam.config.json` or npx: `npx utam -c utam.config.json`. The `-c` flag points the compiler at the `utam.config.json` configuration file.

Some developers prefer to use a `utam.config.js` configuration file because it's easier to add comments to a JavaScript file compared to a JSON file. The compiler automatically looks for a `utam.config.js` configuration file at the project root. If you use `utam.config.js`, you don't need to use the `-c` flag.

### Configure the JavaScript Compiler

To configure the JavaScript compiler, you have two options:

1. Use the default convention, which is the easiest way to configure the compiler. It implies that your project structure adheres with some built-in assumptions; for example, where to find declarative page objects, and where to output compiled page objects. That's the recommended approach when starting a new project because you don't have to tweak the compiler configuration.
2. Explicitly declare compiler options to fit your project structure. Consider this option when you integrate UTAM with an existing project or when the default convention doesn't align with your project structure. It gives you more control at the expense of additional configuration time.

#### Option 1: JavaScript Compiler Default Convention

You don't have to explicitly declare any options for the JavaScript compiler because all options have default values. If your project
structure follows the default convention, the compiler works out of the box. In that case, set the `utam.config.json` compiler
configuration file to be an empty object, `{}`.

Here's an overview of all configuration options supported by the JavaScript compiler with their associated default values:

```json
{
  "pageObjectsRootDir": "./", // config file directory name
  "pageObjectsFileMask": ["**/__utam__/**/*.utam.json"],
  "extensionsFileMask": ["**/__utam__/**/*.utam.js"],
  "pageObjectsOutputDir": "pageObjects",
  "extensionsOutputDir": "utils",
  "moduleTarget": "commonjs",
  "skipCommonJs": false,
  "alias": {},
  "version": undefined,
  "copyright": undefined,
  "module": undefined,
  "profiles": undefined
}
```

Let's look at an example project that follows the default convention.

```
<packageRoot>
├── package.json
├── utam.config.json
└── src/
   └── modules/
      └── component1/
         └── __utam__/
            └── component1.utam.json
      ├── component2/
         └── __utam__/
            ├── component2.utam.json
            └── extension.utam.js
      ..
      └── componentN/
         └── __utam__/
            └── componentN.utam.json
```

This sample project structure follows the default convention. The `utam.config.json` compiler configuration file is
at the package root level and is a sibling to `package.json`. The declarative page objects are next to their associated components in `__utam__` subfolders.

The resulting project structure after compiling is:

```
<packageRoot>
├── package.json
├── utam.config.json
├── pageObjects/
   ├── component1.d.ts
   ├── component1.js
   ├── component1.mjs
   ..
   ├── componentN.d.ts
   ├── componentN.js
   └── componentN.mjs
├── src/
   └── modules/
      ├── component1/
         └── __utam__/
            └── component1.utam.json
      ├── component2/
         └── __utam__/
            ├── component2.utam.json
            └── extension.utam.js
      ..
      └── componentN/
         └── __utam__/
            └── componentN.utam.json
└── utils/
   ├── extension.js
   └── extension.mjs
```

By following the default convention, the compiler finds the declarative page objects and [extensions](https://developer.salesforce.com/docs/platform/utam/guide/imperatives.md) and
generates their respective implementations in `pageObjects` and `utils` folders at the package root level.

#### Option 2: Explicitly Declare Compiler Options

Explicitly declare [compiler options](#configure-the-javascript-compiler) when the default convention doesn't align with your project structure.

There are multiple approaches to configure compiler options. We offer these different approaches to allow for different project structures and different developer preferences.

### Use a compiler configuration file

You can specify options in the compiler configuration file.

Use the `-c` flag of the `utam` CLI to point at the configuration file. In this example, we use `utam.config.json`.

```bash
utam -c utam.config.json
```

Use the `-p` flag of the `utam` CLI to point the compiler at multiple configuration files. Pass in a list of space-separated UTAM compiler configuration file paths. This approach is useful if you have a repo where you need different compiler configuration options in different subprojects. In most scenarios, the `-c` flag suffices and you don't need to use the `-p` flag.

```bash
utam -p 'path/to/project1/utam.config.json' 'path/to/project2/utam.config.json'
```

### Use a configuration object in package.json

Alternatively, you can specify options in a configuration object for the `utam` key in `package.json`. For example:

```json
{
  "devDependencies": {
    "utam": "x.y.z"
  },
  "utam": {
    "pageObjectsOutputDir": "pageObjectsJS",
    "extensionsOutputDir": "pageObjects/utils"
  }
}
```

As you can see, we offer multiple approaches to configure compiler options. With great flexibility comes the risk of over complicating your configuration. We recommend that you stick to one approach for each project for the sake of simplicity.

The compiler looks for configuration options in this order:

1. `utam` CLI with the `-c` or `-p` flags
2. Default `utam.config.js` configuration file
3. Configuration object in `package.json`

### JavaScript Compiler Options Reference

This section lists all the options supported by the JavaScript compiler. For each option, we describe its JSON type, its
default value, and what it does.

**`pageObjectsRootDir`**

- Type: `string`
- Default: `path.dirname(configFilePath)`

The relative path from the configuration file's directory that represents the root directory path. The compiler looks recursively in the root directory for declarative JSON page objects and [extensions](https://developer.salesforce.com/docs/platform/utam/guide/imperatives.md). It's also the
directory in which the compiler generates compiled page objects and extensions.

Defaults to the configuration file's directory if not specified. For instance, if your `utam.config.json` configuration file is
at the package root (the same level as the `package.json` file), the page object root directory defaults to the package root directory.

**`pageObjectsFileMask`**

- Type: `string[]`
- Default: `["**/__utam__/**/*.utam.json"]`

The file mask pattern used by the compiler to find input JSON page objects. It tells the compiler
where to find the source JSON page objects relative to `pageObjectsRootDir`. Declare the file mask as a list of glob
patterns.

For example, if we want to search for input files inside the `src` directory only, set the `pageObjectsFileMask` as follows:

```json
{
  "pageObjectsFileMask": ["src/**/__utam__/**/*.utam.json"]
}
```

**`extensionsFileMask`**

- Type: `string[]`
- Default: `["**/__utam__/**/*.utam.js"]`

The file mask pattern used by the compiler to find input [extensions](https://developer.salesforce.com/docs/platform/utam/guide/imperatives.md) (JavaScript ESM extensions). It works exactly as the `pageObjectsFileMask` option but for extensions rather than declarative page objects.

**`pageObjectsOutputDir`**

- Type: `string`
- Default: `"pageObjects"`

The relative path from the root directory to the target directory for generated page objects. That's where the
compiler generates compiled JavaScript modules from the JSON page objects.

**`extensionsOutputDir`**

- Type: `string`
- Default: `"utils"`

The relative path from the root directory to the target directory for generated [extensions](https://developer.salesforce.com/docs/platform/utam/guide/imperatives.md). That's where the
compiler copies and transpiles JavaScript extensions.

**`moduleTarget`**

- Type: `"module" | "commonjs"`
- Default: `"commonjs"`

The module system used for compiled page objects and extensions whose file extension is `.js`. Configure this option to match
your package's module system. If your package uses ES Modules, set this option to `"module"`. If your package uses CommonJS,
set this option to `"commonjs"` or use the default value.

This table illustrates the module format used for a generated file extension depending on the `moduleTarget`
value. CJS stands for "CommonJS" and ESM stands for "ES Modules."

| Page Objects file ext | commonjs | module |
| --------------------- | -------- | ------ |
| `*.js`                | CJS      | ESM    |
| `*.cjs`               |          | CJS ¹  |
| `*.mjs`               | ESM      |        |

**note:** ¹ The CJS file is only generated if `skipCommonJs` is set to `false`.

**`skipCommonJs`**

- Type: `boolean`
- Default: `false`

Toggle page objects and extensions transpilation from ES Modules to CommonJS. If set to `false` or missing,
the compiler transpiles ESM Page Objects and extensions to CJS. If set to `true`, the compiler doesn't
transpile ESM page objects and extensions and only generates ES Modules.

**note:** This option is only useful when `moduleTarget` is set to `module`

**`alias`**

- Type: `string | Record<string, string>`
- Default: `{}`

A collection of matching patterns and replacement values used to map `type` values to import paths for custom elements and extensions. An alias provides flexibility by enabling you to match a `type` value and replace it in the generated import path.

When you declare a custom element or extension in a declarative page object, the `type` property represents the path
used by the platform module resolver. By default, the `type` property value translates to the custom
element or extension module specifier.

Let's look at an example that illustrates how the compiler translates the `type` property value into an `import` path:

Let's declare a custom element in a JSON page object:

```json
// filename: myPageObject.utam.json
{
  "elements": [
    {
      "name": "myCustomElement",
      "selector": {
        "css": ".my-custom-element"
      },
      "type": "packageName/pageObjects/path/to/myCustomElement"
    }
  ]
}
```

The import statement for that element in the generated page object is:

```js
// filename: myPageObject.mjs
import _myCustomElement from "packageName/pageObjects/path/to/myCustomElement";
```

That built-in behavior ensures that the `type` property value has a specific semantic structure with three parts:

1. the first part represents the package name (required)
2. the path to the page object (optional)
3. the page object name (required)

Sometimes, that coupling between the `type` property value and the import path lacks flexibility.
For instance, you might want to use an internal import reference that's different from the package name published
on the public registry.

An alias decouples the 1-to-1 relationship between `type` and `import` paths. Let's look at how we can use aliases to
add a package scope in front of your custom element.

Define an alias in the compiler configuration file:

```json
// filename: utam.config.json
{
  "alias": {
    "packageName/*": "@scope/packageName/*"
  }
}
```

With this mapping, the compiler replaces all `type` values that contain `packageName` by `@scope/packageName`.
The generated import statement is:

```js
// filename: myPageObject.mjs
import _myCustomElement from "@scope/packageName/pageObjects/path/to/myCustomElement";
```

The `*` character is replaced by everything it matches in the `type` property value. Here, `*` matches `path/to/myCustomElement`
so `@scope/packageName/*` translates to `@scope/packageName/path/to/myCustomElement` in the import path.

**note:** The matching pattern is a simple string matching pattern that supports the `*` wildcard.

There are two ways to declare type aliases:

1. Inline in the compiler configuration file
2. Externally in another JSON file that is referenced in the compiler config file

To declare type aliases inline, set the `alias` property value to be an object:

```json
// filename: utam.config.json
{
  "alias": {}
}
```

Declare all aliases as key-value pairs where the keys represent matching patterns and the values represent replacement values.

```json
// filename: utam.config.json
{
  "alias": {
    // aliases are key-values of
    // type Matching Pattern: import Replacement Value
    "packageName/pageObjects/*": "@scope/packageName/pageObjects/*"
  }
}
```

To declare type aliases externally, create a JSON file that defines the aliases:

```json
// filename: utam-alias.config.json
{
  "packageName/pageObjects/*": "@scope/packageName/pageObjects/*"
}
```

Then set the `alias` property in the compiler configuration file to reference the aliases JSON config file:

```json
// filename: utam.config.json
{
  // assuming both config files are siblings
  "alias": "./utam-alias.config.json"
}
```

The JavaScript compiler automatically resolves the alias configuration path and loads the aliases.

**`version`**

- Type: `string`
- Default: the current date and time

Version is an optional string that is propagated as `@version` in the generated page object JSDoc.
For example, if version is set:

```json
{
  "version": "Spring '22"
}
```

The generated JSDoc in the code is:

```js
/**
 * ...
 * @version Spring '22
 */
export default class DescriptionClass extends _UtamBasePageObject {
```

If the version isn't set, the current date and time is used:

```js
/**
 * ...
 * @version 2022-12-01 09:12:01
 */
export default class DescriptionClass extends _UtamBasePageObject {
```

**`copyright`**

- Type: `string[]`
- Default: none

An optional array of strings that is added at the top of the generated page object.
If the copyright is set:

```json
{
  "copyright": ["Copyright (c) 2022, salesforce.com, inc.", "All rights reserved."]
}
```

The generated JSDoc in the code is:

```js
/**
 * Copyright (c) 2022, salesforce.com, inc.
 * All rights reserved.
 */
import { By as _By } from "@utam/core";

// ... class code
```

**`module`**

- Type: `String`
- Default: none

The name of the module used to generate [injections config](#set-up-injection-config-for-interfaces). It's a mandatory configuration parameter if the UTAM compiler generates page objects for [interfaces](/docs/platform/utam/references/utam-grammar/interfaces.html).

**`profiles`**

- Type: array of objects
- Default: none

Used in injections config. See [interfaces](/docs/platform/utam/references/utam-grammar/interfaces.html).

**`interruptCompilerOnError`**

- Type: `boolean`
- Default: true

By default, the compiler interrupts execution if a compilation error occurs. If this parameter is set to `false`, the compiler continues to generate other page objects, combines all compilation errors into one report, and throws an error at the end. All the errors are added to the `utam.errors.txt` file and printed to the console.

## Test Setup

After you generate UTAM page objects, you can create a UI test that uses the page objects. Before your test can interact with the UI, UTAM needs to have access to a driver and to certain configuration parameters.

### UTAM and WebdriverIO Integration

This `package.json` file includes a dependency for [WebdriverIO](https://webdriver.io/docs/what-is-webdriverio), which is an automation framework for JavaScript apps.

```json
{
  "devDependencies": {
    "wdio-utam-service": "0.0.7"
  }
}
```

`wdio-utam-service` is an adapter between UTAM page objects and the browser API that WebdriverIO provides. The dependency includes a transitive dependency on the UTAM compiler.

### WDIO config and utam service

The `wdio.config.js` file configures WebdriverIO and requires `wdio-utam-service`. It's set in the root folder of the project.

We describe only the relevant parts of the wdio configuration. For the full configuration, see the [JavaScript recipes](https://github.com/salesforce/utam-js-recipes) repository.

For the complete list of WebdriverIO configuration properties, see [WebdriverIO's configuration page](https://webdriver.io/docs/configurationfile.html).

```js
const { UtamWdioService } = require('wdio-utam-service');
...
exports.config = {
    ...
    services: ['chromedriver', [UtamWdioService, {}]]
    ...
}
```

A driver instance is created by WebDriverIO. `UtamWdioService` wraps the driver instance and uses the configured timeouts. Now, you can create an instance of a UTAM page object in a test.

### Set Timeouts for JavaScript in WebDriverIO

The `wdio.config.js` file also configures the [timeouts](/docs/platform/utam/references/utam-grammar/explicit-waits.html#explicit-wait-timeout) and should be set depending on the speed of your testing environment.

```js
// This service creates an instance of UtamLoader from a WebDriverIO driver
const { UtamWdioService } = require("wdio-utam-service");
// ...

exports.config = {
  // ...
  // sets explicit timeout to 5 seconds
  waitforTimeout: 1000 * 5,
  // optional parameter that sets the polling interval for explicit waits
  waitforInterval: 200,
  // ....
  services: [
    // WebDriverIO doesn't allow setting an implicit timeout through config
    // so we set it via UtamWdioService parameters
    [UtamWdioService, { implicitTimeoutMsec: 0 }],
  ],
  // ...
};
```

`waitforTimeout` property sets the default timeout for all `waitFor*` basic actions and for explicit waits. This example sets the explicit wait timeout to 5 seconds.

The implicit wait timeout is set via `implicitTimeout` argument of the UTAM WDIO service and we recommend using 0 (which is also the default).

## Set up injection config for interfaces

If your UI tests use [UTAM interfaces](/docs/platform/utam/references/utam-grammar/interfaces.html), you must set up [injection configs](/docs/platform/utam/references/utam-grammar/interfaces.html#interface-implementation-resolution-at-run-time).

### Find injection configs in consumed modules

The injection config is generated with page objects. It can be:

- in the root folder of your local generated page objects
  ![injection-js](https://developer.salesforce.com/docs/media/utam/injection-js.png)
- or a file from a dependency package

### Add injection configs to UtamLoader

Add `injectionConfigs` to WebDriverIO config as a UtamWdioService parameter:

```js
{
    // ...
    services: [
        'chromedriver',
        [
            UtamWdioService,
            {
                implicitTimeout: 0,
                injectionConfigs: [
                       // load a dependency config from a dependency
                       'vanilla-js-components/profile.config.json',
                       // load a dependency config local to the project
                       path.join(__dirname, '../path/to/anotherProfile.config.json')
                ]
            }
        ]
    ],
    // ...
}
```

Each string in the `injectionConfigs` array should point to the actual JSON injection configuration file generated with page objects.

### Set active profile

Setting the active profile affects which implementing class is picked. A common example is mobile tests, which must set the current platform in UtamWdioService:

```js
// utam variable is instance of UtamLoader
utam.setProfile("platform", getMobilePlatformType(browser));
```

## Mobile setup

To execute a test using a UTAM page object against a local simulator or emulator, the UTAM framework needs to know your local environment through the wdio configuration file.

For iOS:

```js
exports.config = {
    ...baseMobileConfig,
    capabilities: [
        {
            ...
            'appium:deviceName': 'iPhone 12',
            'appium:app': '<path to iOS test app>',
            'appium:platformVersion': '15.2',
        },
    ]
};
```

For Android:

```js
exports.config = {
    ...baseMobileConfig,
    capabilities: [
        {
            ...
            'appium:deviceName': 'emulator-5554',
            'appium:app': '<path to Android test app>',
            'appium:appActivity': 'com.salesforce.chatter.Chatter',
            'appium:appPackage': 'com.salesforce.chatter',
        },
    ]
};
```

### Start Appium server

Start an Appium server locally before executing any test by running `appium --port 4444`.

## Write UI Tests

Before you start to write test code, clarify the use case for your test. Identify the DOM elements that your test needs to exercise and ensure that those elements are accessible in your page objects. Start small and iterate when you're creating your first test and page objects.

The [Write a Test tutorial](https://utam.dev/tutorial/write-tests) gives you a good introduction to test code for a Hello World example. The UI enables you to see the DOM, JSON page object, generated JavaScript code, test code, and a DOM tree viewer. The sidebar walks you through the moving parts.

Let's look at the test code in the [compose method tutorial](https://utam.dev/tutorial/compose-method).

```js
// Import a root page object
import LoginFormRoot from "tutorial/loginForm";

runPlaygroundTest(async () => {
  // Load the page object
  const loginFormRoot = await utam.load(LoginFormRoot);
  const usernameElement = await loginFormRoot.getUsername();
  const passwordElement = await loginFormRoot.getPassword();

  await loginFormRoot.login("utam@salesforce.com", "azerty123");

  assert.strictEqual(await usernameElement.getValue(), "utam@salesforce.com");
  assert.strictEqual(await passwordElement.getValue(), "azerty123");
});
```

**note:** The `runPlaygroundTest()` method is specific to the tutorial environment. For a more generic test, see [Sample Repo Using WebDriverIO](https://github.com/salesforce/utam-js-recipes/blob/main/wdio.conf.js).

Here are the basic steps you perform in test code.

### Import the root page object

Import a root page object using JavaScript module syntax. You can use any name to refer to the default export from the module. The tutorial code uses `LoginFormRoot`.

```js
import LoginFormRoot from "tutorial/loginForm";
```

**tip:** To load a page object directly from a UI test, the page object must declare `"root" : true` in its JSON page object file.

### Load a page object

This line loads the root page object.

```js
const loginFormRoot = await utam.load(LoginFormRoot);
```

The `utam.load()` method guarantees that by the time you load, the root element is available and present. If the page object can't be loaded, you get an error. UTAM always tries to fail as fast as possible if there's an error. The fast failure makes it easier to locate the line of code that's failing when you debug a test.

### Call page object methods

The page object exposes the `getUsername()`, `getPassword()`, and `login()` methods so you can call them in your test.

**tip:** Use a compose method instead of a public element in a page object where possible. A compose method provides better encapsulation of element structure and gives you better flexibility for page-object maintenance.

```js
const usernameElement = await loginFormRoot.getUsername();
const passwordElement = await loginFormRoot.getPassword();

await loginFormRoot.login("utam@salesforce.com", "azerty123");
```

The `getPassword()` method returns an element on the page. You can then call a [basic action](/docs/platform/utam/references/utam-grammar/basic-actions.html) on the element. The `getValue()` basic action returns the value of an `input` element's `value` property. For example:

```js
await passwordElement.getValue();
```

### Use assertions

Use assertions to ensure that your test returns expected results. Use any assertion library of choice, such as [Node.js assertions](https://nodejs.org/dist/latest-v14.x/docs/api/assert.html). For example:

```js
assert.strictEqual(await passwordElement.getValue(), "azerty123");
```

### Run tests

The process to run tests depends on your test automation framework and the programming language that you use. For an example, see [Sample Repo Using WebDriverIO](https://github.com/salesforce/utam-js-recipes/blob/main/wdio.conf.js).

We looked at the basic steps in a test. Now, let's see some other common actions in a test.

### Use Developer Tools and console.log()

If you're playing around with tutorial code, you can add a `debugger;` statement to invoke the Developer Tools debugger and step through your code. Call `console.log()` to output a message to the browser console and to the tutorial console.

### Wait until a condition is met

Write more durable tests by waiting for certain actions to complete and yield until the conditions are met. Use an [explicit wait](/docs/platform/utam/references/utam-grammar/explicit-waits.html) to wait for a condition to be ready for the test to proceed.

### Use Jasmine to structure tests

[Jasmine](https://jasmine.github.io/) is a behavior-driven development framework for testing JavaScript code. This repo uses a [WebdriverIO Jasmine plugin](https://www.npmjs.com/package/@wdio/jasmine-framework) that's an adapter for the Jasmine testing framework.

When you look at the test code in [utam-js-recipes repo](https://github.com/salesforce/utam-js-recipes), you see some standard Jasmine methods.

- [`describe()`](https://jasmine.github.io/api/edge/global.html#describe) creates a group of specs, also known as a suite.

- [`it()`](https://jasmine.github.io/api/edge/global.html#it) defines a single spec. A spec should contain one or more expectations that test the state of the code.

We don't have documentation yet for integrating with other test frameworks.

## Code completion (IntelliSense) for UTAM JSON files

The JSON schema for UTAM page objects is available at [Schema Store](https://json.schemastore.org/utam-page-object.json).

Most source code editors or IDEs support code completion (IntelliSense) for `.utam.json` file extensions either automatically or through configuration.

### Example configuration for Visual Studio Code

To configure IntelliSense for UTAM JSON files, add the following snippet to `.vscode/settings.json`.

```json
{
  "json.schemas": [
    {
      "fileMatch": ["*.utam.json"],
      "url": "https://json.schemastore.org/utam-page-object.json"
    }
  ]
}
```
