UTAM generator

UTAM Generator is a tool that generates UTAM JSON files from HTML files. An input HTML file can be either a raw HTML downloaded from a browser or a Web Component source code in HTML format; for example, a Lightning web component.

Any logic or page content that isn't stored inside static HTML files, for example JavaScript, isn't processed.

Downloads and recipes

The generator artifact is published in npm.

To find the latest version of the artifact, see npm or the dependencies in the utam-generator module in utam-js-recipes repository.

For example:

"utam": "1.2.3"

To use the generator as a utility, clone the utam-js-recipes repository and follow the instructions.

To configure and run the generator in your own repository, see the user guide.

How generator works

The generator traverses the tree of the HTML elements and produces the following output.

Basic element

<div>
    <button type="button">Click Me!</button>
</div>

The generator produces the following public element:

{
    "public": true,
    "name": "button",
    "type": ["actionable", "clickable"],
    "selector": { "css": "button" }
}
<div onchange={handle}>test events</div>

Custom element

A custom element is generated from a custom HTML element. An HTML element is considered custom if its tag isn't part of the HTML5 standard and contains "-"; for example, <custom-element>.

<template>
    <custom-element>Custom content</custom-element>
</template>

The generator produces the following public custom element:

{
    "public": true,
    "name": "element",
    "type": "utam/pageObjects/element",
    "selector": { "css": "custom-element" }
}

The type is decided based on the namespaces configuration.

When the generator processes a custom element, it doesn't traverse its content further unless the generateCustomContent option is set to true in the generator configuration. If the option is set to true, the generator creates another JSON file from the content of the custom element.

Container element

A container element is generated from a <slot> HTML element.

<template if:false={computedShowOutputField}>
    <span class="test-id__field-value slds-size_1-of-1">
        <slot name="inputField"></slot>
        <slot></slot>
    </span>
</template>

The generator produces the following public container element:

{
    "public": true,
    "name": "inputField",
    "type": "container",
    "selector": { "css": "[slot='inputField']" }
}

If the slot doesn't have a name attribute, it's the default slot, so the generated selector depends on the generator configuration. The content of the slot isn't processed further because a container can't have child elements.

Frame

A frame element is generated from an <iframe> HTML element.

<div class="frame">
    <iframe src="https://www.w3schools.com" title="W3Schools Free Online Web Tutorials"></iframe>
 </div>

The generator produces the following public frame element:

{
    "public": true,
    "name": "iframe",
    "type": "frame",
    "selector": { "css": "iframe" }
}

Lists

<template for:each={filteredTodos} for:item="todo">
    <todo-item onupdate={handleTodoUpdate}></todo-item>
</template>

The generator produces the following public list element with "returnAll": true:

{
    "public": true,
    "name": "items",
    "type": "utam/pageObjects/item",
    "selector": { "css": "todo-item", "returnAll": true }
}

In addition, the generator adds a public element with an indexed selector:

{
    "public": true,
    "name": "itemByIndex",
    "type": "utam/pageObjects/item",
    "selector": {
        "css": "todo-item:nth-of-type(%d)",
        "args": [{ "name": "index", "type": "number"}]
    }
}

For example, repeated options in a select tag.

<select>
    <option>one</option>
    <option>two</option>
</select>

The generator produces the following output:

{
    "public": true,
    "name": "select",
    "type": ["actionable", "clickable", "editable"],
    "selector": { "css": "select" },
    "elements": [
        {
            "public": true,
            "name": "options",
            "type": ["actionable", "clickable"],
            "selector": { "css": "option", "returnAll": true }
        }
    ]
}

The content of the list elements isn't processed further because a list can't have child elements.

Text

If an HTML element contains text, the generator creates a public compose method to access the text. The previous HTML snippet has text inside the <option> tags, so the following compose method is generated:

{
    "name": "getOptionByIndexText",
    "args": [{ "name": "index", "type": "number" }],
    "compose": [{
        "element": "optionByIndex",
        "apply": "getText"
    }]
}

The method name is get<Name of the element>Text.

Shadow boundary

A <template> HTML element is considered a shadow boundary. For example:

<template>
    <div class="wrapper">
        <!-- content -->
    </div>
</template>

The generator produces a shadow boundary:

"shadow": {
     "elements": [
        { }
    ]
}

Root page object

Generated JSON can be marked as a root based on the generator configuration.

The JSON is marked as root if the root HTML element is one of: <html>,<form>,<body>. The root selector is the same as the root HTML element:

<html>
    <body>
        <!-- content -->
    </body>
</html>

Generated JSON:

{
    "root": true,
    "selector": {
        "css": "html"
    },
    "elements": []
}

Description

The generator adds a description at the root level and inside the methods depending on the generator configuration. The root HTML element is added to the description:

{
    "description": {
        "author": "UTAM generator",
        "text": ["Page Object: plain-html", "Root element: html"]
    },
    "root": true,
    "selector": {
        "css": "html"
    },
    "elements": []
}

Element names

An element name is generated based on the following rules:

{
    // HTML: <div data-aura-class="forceInlineSpinner"><div>
    "name" : "forceInlineSpinner"
}
{
    // HTML: <todo-item onupdate={handleTodoUpdate}></todo-item>
    "name" : "item"
}
{
    // HTML: <button>click me</button>
    "name" : "button"
}
{
    "name" : "item2"
}

Location strategy

Explained in the configuration guide.