> ## Documentation Index
> Fetch the complete documentation index at: https://relivai-63.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom Actions

> You can define actions through code.

***

For more flexible and diverse test writing, **you can define actions using Playwright-based code**.

## 1. Creating Custom Actions

You can add a custom action by clicking the **\[+] button > \[Add Custom Action]** button at the top right of the **\[Test Steps]** panel in the Reliv Editor.

Click the **\[>]** (detail view) button on the custom action to write the code.

<img src="https://mintcdn.com/relivai-63/BAb91s59wIPEUR8S/assets/advanced/custom-action/custom-action.png?fit=max&auto=format&n=BAb91s59wIPEUR8S&q=85&s=7dda98cfb2139cfb25ac1bcc22093455" width="2841" height="2255" data-path="assets/advanced/custom-action/custom-action.png" />

## 2. Writing Custom Action Code

The following Playwright objects can be used within custom code:

* [browser](https://playwright.dev/docs/api/class-browser)
* [context](https://playwright.dev/docs/api/class-browsercontext)
* [page](https://playwright.dev/docs/api/class-page)
* [expect](https://playwright.dev/docs/test-assertions)

For detailed API descriptions, please refer to the [Playwright Docs](https://playwright.dev/docs/locators).

## 3. Custom Action Code Examples Reference

#### Click

```jsx theme={null}
await page.getByRole("button", { name: "Buy" }).click();

await page.locator("nav").getByRole("link", { name: "Tutor" }).click();
```

#### Fill

```jsx theme={null}
await page.locator(`input[value="Reliv one"]`).fill("Reliv two");
```

#### Hover

```jsx theme={null}
await page
  .locator("#AdminListItem")
  .filter({ hasText: "Reliv Test Channel" })
  .hover();
```

#### Navigate

```jsx theme={null}
await page.goto("https://google.com/");
```

#### Check URL

```jsx theme={null}
await expect(page).toHaveURL(/https:\/\/google\.com\/products/);
```

#### Check Clipboard

```jsx theme={null}
const clipboardText = await page.evaluate("navigator.clipboard.readText()");

// Check if the clipboard value contains the target text
expect(clipboardText).toContain("text");

// Check if the clipboard value matches exactly
expect(clipboardText).toEqual("equalText");
```

#### Handling iframes

```jsx theme={null}
await page
  .locator(`iframe[title="Modal Message"]`)
  .frameLocator(":scope")
  .locator(`button.bz-close-btn`)
  .click();
```

#### Handling popup page

```jsx theme={null}
const pagePromise = context.waitForEvent("page");

const googleBtn = page.getByAltText("Google Login").click();

const newPage = await pagePromise;
await expect(newPage).toHaveTitle(/Google/);

await newPage.getByLabel(/Email/).fill("reliv@gmail.com");

await newPage.getByRole("button", { name: "Next" }).click();

await newPage.getByLabel("Enter your password").fill("testtest");

await newPage.locator("#passwordNext").click();
```

#### Using for loop

```jsx theme={null}
const trialLinks = await page.locator("#Card");

expect(trialLinks).toBeVisible();
const linkCount = await trialLinks.count();

for (let i = 0; i < linkCount; i++) {
  await trialLinks.nth(i).click();
  await expect(page).toHaveURL(/https:\/\/google\.com\/products/);
  await page.goBack();
}
```

#### API Login

```jsx theme={null}
await page.evaluate(async () => {
  // Set your API login URL, username, and password
  const loginUrl = "https://your-api-domain.com/api/login";
  const payload = {
    username: "testuser",
    password: "testpassword",
  };

  const response = await fetch(loginUrl, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify(payload),
  });

  const data = response.json();

  // Save token to localStorage (change this to your own logic)
  if (data.token) {
    localStorage.setItem("token", data.token);
  }
});

// refresh (if needed)
await page.reload();
```

#### Evaluating custom JS code

[https://playwright.dev/docs/evaluating](https://playwright.dev/docs/evaluating)
