Tutorial: Relational Selectors in askui
Tags: tutorial, testing
Published: 2022-12-22 15:01:38

In this tutorial, we will explain how all the different relational selectors work in askui, so you get a thorough understanding of them.  

Relational selectors can be difficult and sometimes confusing to work with at first. Sometimes it is even not clear why a specific element will not be selected or why the selector does not seem to work.  

After reading this tutorial you will know how to use the full power of all the relational selectors. Additionally, you learn what pitfalls you can fall into and how to avoid them in the future.

In this article we’ll discuss the following relational selectors:

* [above()](#above())
* [below()](#below())
* [contains()](#contains())
* [in()](#in())
* [leftOf()](#leftOf())
* [rightOf()](#rightOf())
* [nearestTo()](#nearestTo())

## Prerequisites

* You have askui installed ([Follow our guide!](https://docs.askui.com/docs/general/Getting%20Started/getting-started))
* You can access [the Selectorshub practice page](https://selectorshub.com/xpath-practice-page/)

## above() <a name="above()"></a>
When you want to click on a textfield and it is above an element, like for example a button with the text _Submit_. You can do it with `above()`. The following code snippet moves the mouse to the textfield above the _Submit_-button:

```typescript
await aui
  .click()
  .textfield()
  .above()
  .button()
  .withText('Submit')
  .exec();
```

![Gif showcasing above().](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v4xrmtwo1dizb4nk2akm.gif)

## below() <a name="below()"></a>
When you want to select a textfield you can do so by finding the correct label, which is often above the textfield. The following code snippet moves the mouse to the textfield below the text _Mobile Number_:

```typescript
await aui
  .moveMouseTo()
  .textfield()
  .below()
  .text()
  .withText('Mobile Number')
  .exec();
```

![Gif showcasing below().](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/iaw0ekyqefa05qyklfj7.gif)

## contains() <a name="contains()"></a>
For selecting an element, that contains another element,  `contains()` is the right candidate. It is especially useful if you want to select a textfield with a placeholder text inside it. The text inside the textfield is annotated as an element itself.

If you have problems with selecting a specific element, always run `annotate()` to create a screenshot of all the annotations or use `annotateInteractively()` to see if you need to use `contains()`.

The following snippet moves the mouse to a textfield based on its placeholder text _First Crush_ which is contained in the textfield:

```typescript
await aui
  .moveMouseTo()
  .textfield()
  .contains()
  .text()
  .withText('First Crush')
  .exec();
```

![Gif showcasing contains().](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i6bxkxrji733v9zkj0os.gif)

## in() <a name="in()"></a>
When you want to target an element that is _inside_ another element you can use `in()`.

```sh
--------------------
|     outerEl      |
|  --------------  |
|  |  innerEl   |  |
|  --------------  |
|                  |
--------------------
```

The following code snippet moves the mouse pointer to the text of the first textfield askui found:

```typescript
await aui
  .moveMouseTo()
  .text()
  .in()
  .textfield()
  .exec();
```

![Gif showcasing in().](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6e0owvn908s6mut94mql.gif)

## leftOf() and rightOf() <a name="leftOf()"></a><a name="rightOf()"></a>
If you want to select an element based on its location left or right of another element you have to use `leftOf()` or `rightOf()` respectively.

💡 If you do not specify another filter like `withText()` then you will get the nearest element. Otherwise, askui retrieves the nearest element that matches the filter!

```typescript
await aui
  .moveMouseTo()
  .text()
  .leftOf()
  .text()
  .withText('Denmark')
  .exec();
```

![Gif showcasing leftOf().](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dt5ts3zw3z3sabzlyd6e.gif)

```typescript
await aui
  .moveMouseTo()
  .text()
  .rightOf()
  .text()
  .withExactText('Joe Root')
  .exec();
```

![Gif showcasing rightOf()](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/alz2fypb3hu7mllnm2cm.gif)

## nearestTo() <a name="nearestTo()"></a>
Filtering with the `nearestTo()` filter will return the element nearest to another element. This is useful when the direction is not clear on where to search. Especially responsive designs are prone to wrap elements into a new line where `leftOf()` and `rightOf()` would fail.

```typescript
await aui
  .moveMouseTo()
  .textfield()
  .nearestTo()
  .text()
  .withTextRegex('User Em*')
  .exec();
```

![Gif showcasing nearestTo().](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/82ogwddy1h3yoapuwkb0.gif)

## Additional Considerations About the Distance Metric
The distance is not entirely based on physical distance. If you use an additional filter like `withText()` it optimizes to find the best match. It also considers special cases, for example, modal dialogs. Therefore the element selected by askui might sometimes be wrong from a user's point of view.

You can use `moveMouseTo()` like in the following example to see what element a command targets.

```typescript
await aui
  .moveMouseTo()
  .textfield()
  .above()
  .button()
  .withText('Submit')
  .exec()
```

## Conclusion
Relational selectors are a powerful tool to create robust automation. However, sometimes they are tricky to master.

This tutorial equipped you with the knowledge to use their full power in your automation.

[If you have a recurring or persisting issue, don’t hesitate to ask the Discord community for help!](https://discord.gg/KFYJ5xuyBA)