pythonselenium-webdriver

Python | Selenium | Adjusting the value on a price slider with min/max values


I'm working on a practice Selenium script to adjust the value of a price slider that has min and max value sliders on the same bar. The code technically works, and I see the max slider value adjust, but not to the exact value I want. Is there a better way I can be doing this?

The code I'm working with at the moment is:

def test_priceScale():
    driver.get('https://www.practicesoftwaretesting.com')

    slider = driver.find_element(By.CSS_SELECTOR, "span[aria-label = 'ngx-slider-max']")

    current_value = float(slider.get_attribute('aria-valuenow'))
    max_value = float(slider.get_attribute('aria-valuemax'))

    target_value = 10

    slider_width = slider.size["width"]
    offset = (target_value - current_value) / (max_value * slider_width)

    actions = ActionChains(driver)
    actions.click_and_hold(slider).move_by_offset(offset, 0).release().perform()

My hope is to find a solution that if I change the value of target_value, I can see the slider adjust to that specific price.


Solution

  • This was challenging...

    I kinda went overboard for a typical SO answer... I created a page object for the home page because I thought it would help with code reuse, etc. The test itself is very simple and short... the page object holds the guts of the logic, as it should.

    The basic concept is I set a step value to 5 px. I step to the right until I've passed the desired value. Then I step left until I've passed the desired value. If I haven't found the desired value, I decrease the step value by 1 and repeat... stepping right then left. This continues until the desired value is reached or the step value = 0.

    I've tried several different values for min and max and it's worked each time. You could increase the initial step value to get there faster, if you want.

    Here's the working code:

    slider_test.py

    from selenium import webdriver
    
    from home_page import HomePage
    
    driver = webdriver.Chrome()
    
    url = "https://www.practicesoftwaretesting.com/"
    driver.get(url)
    
    desired_min_value = 51
    desired_max_value = 151
    
    homePage = HomePage(driver)
    homePage.set_limit(desired_min_value, homePage.Limit.MIN)
    homePage.set_limit(desired_max_value, homePage.Limit.MAX)
    
    driver.quit()
    

    home_page.py

    import time
    from enum import Enum
    from selenium.webdriver.common.action_chains import ActionChains
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support.ui import WebDriverWait
    from selenium.webdriver.support import expected_conditions as EC
    from selenium import webdriver
    
    
    class HomePage:
        def __init__(self, driver: webdriver):
            self.driver = driver
            self.label_max_locator = (By.CSS_SELECTOR, "span.ngx-slider-model-high")
            self.label_min_locator = (By.CSS_SELECTOR, "span.ngx-slider-model-value")
            self.slider_max_locator = (By.CSS_SELECTOR, "span.ngx-slider-pointer-max")
            self.slider_min_locator = (By.CSS_SELECTOR, "span.ngx-slider-pointer-min")
            self.wait = WebDriverWait(driver, 10)
            self.Limit = Enum("Limit", [("MIN", 1), ("MAX", 2)])  # an enum to set MIN or MAX
    
        def set_limit(self, desired_value: int, limit):
            match limit:
                case self.Limit.MIN:
                    slider_locator = self.slider_min_locator
                    label_locator = self.label_min_locator
                case self.Limit.MAX:
                    slider_locator = self.slider_max_locator
                    label_locator = self.label_max_locator
    
            bubble = self.wait.until(EC.visibility_of_element_located(slider_locator))
            current_value = self.wait.until(EC.visibility_of_element_located(label_locator))
            actions = ActionChains(self.driver)
            step = 5
            while step > 0:
                while int(current_value.text) < desired_value:
                    actions.drag_and_drop_by_offset(bubble, step, 0).perform()
                    time.sleep(0.1)
                while int(current_value.text) > desired_value:
                    actions.drag_and_drop_by_offset(bubble, -step, 0).perform()
                    time.sleep(0.1)
                step = step - 1