paint-brush
Interacting With Sliders Using Playwrightby@truuts
1,977 reads
1,977 reads

Interacting With Sliders Using Playwright

by Eugene TruutsOctober 30th, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

In this guide, you will learn how to interact with sliders in Playwright. Find the slider element on a page. Detect its current value to be able to click on it. Move the slider into the final position (95%) and set the slider value random.
featured image - Interacting With Sliders Using Playwright
Eugene Truuts HackerNoon profile picture


Sometimes, you need to deal with sliders in your tests but Playwright does not have any built-in tools to interact with sliders. However, it is not a problem at all.


In this guide, you will learn how to interact with sliders in Playwright.


Let’s start by adding a simple slider element to our page using the setContent() method, which internally calls document.write() and adds anything you want in the DOM.

import {test, expect, Page} from '@playwright/test';

let page: Page;


const sliderHTML = `<div>
    <p><input type="range" id="slider" min="0" max="100"/></p>
</div>`

test('Slider test', async ({page}) => {
  await page.setContent(sliderHTML);
});


In this case, all you get is the simple range slider on the page.


I suggest making the task more complicated and setting the slider value random. This makes us consider how to interact with the slider depending on its value.

import {test, expect, Page} from '@playwright/test';

let page: Page;

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

const sliderHTML = `<div>
    <p><input type="range" id="slider" min="0" max="100" value="${getRandomInt(0, 100)}"/></p>
</div>`

test('Slider test', async ({page}) => {
  await page.setContent(sliderHTML);
  await setSliderValue(page, "//*[@id = 'slider']",75);
});


So, the final task is to set the slider to the given value, let’s say 95%.


The solution will include multiple steps:

  1. Find the slider element on a page.
  2. Detect its current value to be able to click on it.
  3. Move the slider into the final position (95%).


It looks pretty simple. Starting with finding the slider, I will use the XPath locator to find it. Feel free to check my XPath mastering guide.


For this case, I suggest using the following:

"//*[@id = 'slider']"


The next step is getting the bounding box of the slider element to determine its position and size.

const sliderBound = await page.locator("//*[@id = 'slider']").boundingBox();


An element's bounding box is the smallest possible rectangle (aligned with the axes of that element’s user coordinate system) that entirely encloses it and its descendants.

The bounding box will help us to click and move the mouse cursor inside that box.

Since the slider pin can have a random position, we must find its actual coordinates. We need to obtain the current slider value from the HTML to do this. It is possible by using the page.evaluate() method.


const currentSliderValue = await page.evaluate(`document.evaluate(""//*[@id = 'slider']"", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.value`);


This method returns the current slider value as a number. This number will help you to calculate the slider pin coordinate. You need to calculate two points for X and Y coordinates.

Because the slider pin moves horizontally, the only X coordinate is crucial for us.


To calculate it, use the formula:

const targetX = sliderBound.x + (sliderBound.width * currentSliderValue / 100);


To get the Y, calculate the vertical middle point:

const targetY = sliderBound.y + sliderBound.height / 2;


Next, move the mouse cursor to the calculated point and hold its button:

await page.mouse.move(targetX, targetY);
await page.mouse.down();


Now, you can move the mouse cursor horizontally to any position you want.

await page.mouse.move(
    sliderBound.x + (sliderBound.width * 95) / 100,
    sliderBound.y + sliderBound.height / 2,
);
await page.mouse.up();


Let’s bring all parts together and create a method for setting a wanted value to any slider element by its XPath:

async function setSliderValue(page: Page, sliderXPath: string, valueAsPercent: number) {
  // Find the slider element using the provided XPath and obtain its bounding box
  const sliderBound = await page.locator(sliderXPath).boundingBox();

  // Use page.evaluate to obtain the current slider value from the HTML using the same XPath
  const currentSliderValue = await page.evaluate(`document.evaluate("${sliderXPath}", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.value`);

  // Calculate the target X and Y coordinates for the mouse cursor based on the current slider value
  const targetX = sliderBound.x + (sliderBound.width * currentSliderValue / 100);
  const targetY = sliderBound.y + sliderBound.height / 2;

  // Move the mouse cursor to the calculated position
  await page.mouse.move(targetX, targetY);

  // Simulate a mouse click by pressing the mouse button
  await page.mouse.down();

  // Move the mouse cursor to the desired position by the provided valueAsPercent
  await page.mouse.move(
      sliderBound.x + (sliderBound.width * valueAsPercent) / 100,
      sliderBound.y + sliderBound.height / 2,
  );

  // Release the mouse button to complete the interaction
  await page.mouse.up();
}


Now you can use it in your test just by passing the slider locator and a wanted value:

import {test, expect, Page} from '@playwright/test';

let page: Page;

function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

async function setSliderValue(page: Page, sliderXPath: string, valueAsPercent: number) {
  // Find the slider element using the provided XPath and obtain its bounding box
  const sliderBound = await page.locator(sliderXPath).boundingBox();

  // Use page.evaluate to obtain the current slider value from the HTML using the same XPath
  const currentSliderValue = await page.evaluate(`document.evaluate("${sliderXPath}", document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue.value`);

  // Calculate the target X and Y coordinates for the mouse cursor based on the current slider value
  const targetX = sliderBound.x + (sliderBound.width * currentSliderValue / 100);
  const targetY = sliderBound.y + sliderBound.height / 2;

  // Move the mouse cursor to the calculated position
  await page.mouse.move(targetX, targetY);

  // Simulate a mouse click by pressing the mouse button
  await page.mouse.down();

  // Move the mouse cursor to the desired position by the provided valueAsPercent
  await page.mouse.move(
      sliderBound.x + (sliderBound.width * valueAsPercent) / 100,
      sliderBound.y + sliderBound.height / 2,
  );

  // Release the mouse button to complete the interaction
  await page.mouse.up();
}

const sliderHTML = `<div>
    <p><input type="range" id="slider" min="0" max="100" value="${getRandomInt(0, 100)}"/></p>
</div>`

const sliderElementLocator = "//*[@id = 'slider']";
test('Slider test', async ({page}) => {
  await page.setContent(sliderHTML);
  await setSliderValue(page, sliderElementLocator, 75);
});

I hope this guide helped you to understand how to handle the sliders in Playwright. Happy testing!


Also published here.