1

I am working on a web automation project. The project is personally for myself as I have to constantly click and fill out text fields on a web app (IBM Maximo Asset Management). The login, and then clicking the link where I want to go initially work fine, but it's when I start clicking on text fields on each new row that I get errors. It's as if adding a new row changes the whole DOM, but it only creates another table in the DOM while others remain unchanged. I would love to have a collaborator if possible to get me through this problem.

You will see in some places I have had to use full XPATHs due to the automation just breaking, such as:

if driver.find_element(
                By.XPATH,
                "/html/body/form/div/table[2]/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[2]/td/div/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr[2]/td/table/tbody/tr[2]/td/div/table/tbody/tr[3]/td/table/tbody/tr[3]/td/table/tbody/tr[4]/td[10]").text == "WSCH":

Without full XPATH, the code just can't find this element. Should I code using full XPATH for all elements then? Suggestions please.

I feel like I should do it for the entire code, but it would make it really hard to change if the web app is changed or updated.

This is my entire code.

import datetime
import time

from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException, StaleElementReferenceException
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.ui import WebDriverWait

# from selenium.webdriver.common.action_chains import ActionChains

options = webdriver.ChromeOptions()

prefs = {"download.default_directory": "C:\\Users\\Administrator\\Desktop\\NewWO\\NEW"}

options.add_experimental_option("prefs", prefs)

PATH = "C:\\Users\\Administrator\\Desktop\\chromedriver_win32\\chromedriver.exe"

driver = webdriver.Chrome(PATH, options=options)

# Wait 3 seconds for the "chromedriver.exe" to load

time.sleep(3)

action = ActionChains(driver)

# Open IBM MAXIMO Asset Management Web App

driver.get("http://10.1.84.87/maximo/webclient/login/login.jsp?appservauth=true")

driver.maximize_window()

# Wait 2 seconds for login elements to load

time.sleep(4)

# Login to IBM Maximo Asset Management

# Pass login parameters

with open("C:\\Users\\Administrator\\Desktop\\WO_Automation\\pass.txt", "r") as p:

    maximo_pass_supervisor = p.read()

id_box = driver.find_element(By.ID, 'j_username')

id_box.send_keys("07780141")

pass_box = driver.find_element(By.ID, 'j_password')

pass_box.send_keys(maximo_pass_supervisor)

pass_box.submit()

# Click on "Work Order Tracking" link after login

element_wo_tracking = WebDriverWait(driver, 600).until(
    ec.visibility_of_element_located((By.LINK_TEXT, "Work Order Tracking")))

wo_track = driver.find_element(By.LINK_TEXT, "Work Order Tracking")

wo_track.click()

time.sleep(3)

# Create a list of arguments to be entered into fields based on the 'description.txt' file

pm_actuals = []

with open("C:\\Users\\Administrator\\Desktop\\PM.txt", "r") as pm_number:

    pm = pm_number.readlines()[11:12]

    for line in pm:

        line = line.upper().strip().split(",")

        pm_actuals.append(line)


# A function to send text to an element one character at a time with a delay of 0.1s

def slow_type(el, text, delay=0.1):

    for character in text:

        el.send_keys(character)

        time.sleep(delay)


# Check for PM availability

pm_availability = []

for pm in range(0, len(pm_actuals[0])):

    time.sleep(1)

    ignore_exceptions = (NoSuchElementException, StaleElementReferenceException,)

    element_search_text_wo = WebDriverWait(driver, 120, 5, ignore_exceptions).until(
        ec.element_to_be_clickable((By.XPATH, "//input[@id='m6a7dfd2f_tfrow_[C:1]_txt-tb']")))

    search_text_wo = driver.find_element(By.XPATH, "//input[@id='m6a7dfd2f_tfrow_[C:1]_txt-tb']")

    search_text_wo.clear()

    slow_type(search_text_wo, pm_actuals[0][pm].replace(" ", "", 1))

    search_text_wo.send_keys(Keys.RETURN)

    element_len_elements_list = WebDriverWait(driver, 120, 5, ignore_exceptions).until(
        ec.visibility_of_any_elements_located((By.XPATH, "//*[contains(@id, 'm6a7dfd2f_tbod_tdrow-tr[R:')]")))

    len_elements_list = driver.find_elements(By.XPATH, "//*[contains(@id, 'm6a7dfd2f_tbod_tdrow-tr[R:')]")

    if len(len_elements_list) != 0:

        # Check if PM status is WSCH

        if driver.find_element(
                By.XPATH,
                "/html/body/form/div/table[2]/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[2]/td/div/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr[2]/td/table/tbody/tr[2]/td/div/table/tbody/tr[3]/td/table/tbody/tr[3]/td/table/tbody/tr[4]/td[10]").text == "WSCH":

            pm_availability.append(pm_actuals[0][pm].replace(" ", "", 1))

            continue

        # If PM status is not WSCH, continue searching

        else:

            continue

    else:

        continue

# Exceptions to ignore

ignore_exceptions = (NoSuchElementException, StaleElementReferenceException,)

# Start PM routing

counter = 0

while len(pm_availability) != 0:

    for i in range(0, len(pm_availability)):

        element_search_text_wo = WebDriverWait(driver, 120, 5, ignore_exceptions).until(
            ec.element_to_be_clickable((By.XPATH, "//input[@id='m6a7dfd2f_tfrow_[C:1]_txt-tb']")))

        search_text_wo = driver.find_element(By.XPATH, "//input[@id='m6a7dfd2f_tfrow_[C:1]_txt-tb']")

        search_text_wo.clear()

        slow_type(search_text_wo, pm_availability[i])

        search_text_wo.send_keys(Keys.RETURN)

        # Start PM routing procedure if the status is WSCH

        # Select the PM

        element_first_row_search = WebDriverWait(driver, 600, 5, ignore_exceptions).until(
            ec.presence_of_element_located(
                (By.XPATH,
                 "/html/body/form/div/table[2]/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[2]/td/div/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr[2]/td/table/tbody/tr[2]/td/div/table/tbody/tr[3]/td/table/tbody/tr[3]/td/table/tbody/tr[4]/td[3]/span[@id='m6a7dfd2f_tdrow_[C:1]_ttxt-lb[R:0]']")))

        first_row = driver.find_element(
            By.XPATH, "/html/body/form/div/table[2]/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[2]/td/div/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr[2]/td/table/tbody/tr[2]/td/div/table/tbody/tr[3]/td/table/tbody/tr[3]/td/table/tbody/tr[4]/td[3]/span[@id='m6a7dfd2f_tdrow_[C:1]_ttxt-lb[R:0]']")

        first_row.click()

        time.sleep(3)

        # Go to ACTUALS tab

        element_actuals_tab = WebDriverWait(driver, 120, 5, ignore_exceptions).until(
            ec.element_to_be_clickable((By.XPATH, "//*[@id='m272f5640-tab']")))

        actuals_tab = driver.find_element(By.XPATH, "//*[@id='m272f5640-tab']")

        actuals_tab.click()

        # Create a list of all labor information

        pm_labor = []

        with open("C:\\Users\\Administrator\\Desktop\\PM.txt", "r") as pm_info:

            pm = pm_info.readlines()[14:]

            for line in pm:

                line = line.upper().strip().split(",")

                pm_labor.append(line)

        # Create a list of duration to calculate the PM start and end times

        duration = []

        with open("C:\\Users\\Administrator\\Desktop\\PM.txt", "r") as pm_duration:

            pm = pm_duration.readlines()[8:9]

            for line in pm:

                line = line.upper().strip().split(".")

                duration.append(line)

        # Create a list for the start_time_pm values

        starting_time = []

        with open("C:\\Users\\Administrator\\Desktop\\PM.txt", "r") as pm_start:

            start = pm_start.readlines()[3:5]

            for line in start:

                line = line.upper().strip().split("=")

                starting_time.append(line)

        # Start time for all PMs will be 0700 hours

        start_time_pm = datetime.timedelta(hours=int(starting_time[0][1]),
                                           minutes=int(starting_time[1][1]), seconds=0)

        # Create a list of times based on the duration of PM in PM.txt file

        start_time = []

        end_time = []

        # Iterate the time starting from 0700 hours to create PM time slots

        while start_time_pm < datetime.timedelta(hours=14, minutes=0):

            end_time_pm = start_time_pm + datetime.timedelta(hours=int(duration[0][0])) + \
                          datetime.timedelta(minutes=int(duration[0][1]))

            # If end time is 1415 hours or less, append the time values to the lists

            if end_time_pm <= datetime.timedelta(hours=14, minutes=15):

                start_time.append(str(start_time_pm))

                end_time.append(str(end_time_pm))

                start_time_pm = start_time_pm + datetime.timedelta(hours=int(duration[0][0])) + \
                                datetime.timedelta(minutes=int(duration[0][1])) + \
                                datetime.timedelta(minutes=15)

            # If end time is 1400 hours or more, break out of the loop

            elif end_time_pm >= datetime.timedelta(hours=14, minutes=0):

                break

            else:

                continue

        time.sleep(2)

        # Add labor information

        for labor_row in range(0, len(pm_labor)):

            try:

                # Click on new labor for a new row to enter labor information

                element_new_labor = WebDriverWait(driver, 60, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((By.XPATH, "//*[@id='m4dfd8aef_bg_button_addrow-pb']")))

                new_labor = driver.find_element(By.XPATH, "//*[@id='m4dfd8aef_bg_button_addrow-pb']")

                new_labor.click()

                time.sleep(2)

                # Add labor ID from pm_labour list

                element_labor_id = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:2]_txt-tb[R:" + str(labor_row) + "]']")))

                labor_id = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:2]_txt-tb[R:" + str(labor_row) + "]']")

                labor_id.clear()

                slow_type(labor_id, pm_labor[labor_row][0].replace(" ", "", 1))

                time.sleep(2)

                # Add start date for PM from pm_labour list

                element_start_date = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:6]_txt-tb[R:" + str(labor_row) + "]']")))

                start_date = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:6]_txt-tb[R:" + str(labor_row) + "]']")

                start_date.clear()

                slow_type(start_date, pm_labor[labor_row][1].replace(" ", "", 1))

                time.sleep(2)

                # Add end date for PM from pm_labour list

                element_end_date = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:7]_txt-tb[R:" + str(labor_row) + "]']")))

                end_date = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:7]_txt-tb[R:" + str(labor_row) + "]']")

                end_date.clear()

                slow_type(end_date, pm_labor[labor_row][1].replace(" ", "", 1))

                time.sleep(2)

                # Add start time for PM from start_time list

                element_start_time = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:8]_txt-tb[R:" + str(labor_row) + "]']")))

                start_time_text = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:8]_txt-tb[R:" + str(labor_row) + "]']")

                start_time_text.clear()

                slow_type(start_time_text, start_time[counter])

                time.sleep(2)

                # Add end time for PM from end_time list

                element_end_time = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:9]_txt-tb[R:" + str(labor_row) + "]']")))

                end_time_text = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:9]_txt-tb[R:" + str(labor_row) + "]']")

                end_time_text.clear()

                slow_type(end_time_text, end_time[counter])

                time.sleep(3)

            except StaleElementReferenceException:

                # Delete row if exception is thrown and continue with loop

                element_delete_row = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH,
                         "//*[@id='m900f2d81_tdrow_[C:9]_toggleimage-ti[R:" + str(labor_row) + "]']")))

                driver.find_element(
                    By.XPATH,
                    "//*[@id='m900f2d81_tdrow_[C:9]_toggleimage-ti[R:" + str(labor_row) + "]']").click()

                if labor_row == 0:

                    labor_row = 0

                    continue

                else:

                    labor_row += 0

                    continue

        # If labor rows are filled, then route the PM work order

        for rout in range(0, 3):

            if driver.find_element(By.XPATH, "//*[@id='md489b5d4-tb']").text != "COMP":

                # Click on the route button

                element_route = WebDriverWait(driver, 180, 20, ignore_exceptions).until(
                    ec.element_to_be_clickable((By.XPATH, "//*[@id='ROUTEWF_KAUWO_-tbb_anchor']")))

                route = driver.find_element(By.XPATH, "//*[@id='ROUTEWF_KAUWO_-tbb_anchor']")

                route.click()

                time.sleep(5)

                # Click on OK in the corresponding dialog box

                # element_click_ok = WebDriverWait(driver, 180, 20, ignore_exceptions).until(
                #     ec.element_to_be_clickable((By.XPATH, "//button[@type='button' and @id='md875c1f9-pb']")))
                #
                # click_ok = driver.find_element(By.XPATH, "//button[@type='button' and @id='md875c1f9-pb']")
                #
                # click_ok.click()

                driver.switch_to.alert.accept()

                time.sleep(5)

            else:

                pass

        # Once the PM work order is routed, go back to search field

        element_list_view = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
            ec.visibility_of_element_located((By.XPATH,
                                              "//*[@id='m397b0593-tabs_backToList']/table/tbody/tr/td[1]")))

        list_view = driver.find_element(By.XPATH,
                                        "//*[@id='m397b0593-tabs_backToList']/table/tbody/tr/td[1]")

        time.sleep(2)

        list_view.click()

        time.sleep(2)

        pms_routed = [print(f"WO {pm_actuals[0][i]} is closed.")]

        counter += 1

        time.sleep(2)

        len(pm_availability) - 1

# Log out and quit

element_logout = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
    ec.element_to_be_clickable((
        By.XPATH,
        "//div[@id='m4cd0065c-co_0_div']//*[@id='titlebar_hyperlink_8-co_0']//*[@id='titlebar_hyperlink_8-lbsignout']"))
)

logout = driver.find_element(
    By.XPATH,
    "//div[@id='m4cd0065c-co_0_div']//*[@id='titlebar_hyperlink_8-co_0']//*[@id='titlebar_hyperlink_8-lbsignout']")

logout.click()

time.sleep(2)

element_quit = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
    ec.visibility_of_element_located((By.XPATH, "//*[@id='returnFrm']//*[@id='submit']")))

return_login = driver.find_element(By.XPATH, "//*[@id='returnFrm']//*[@id='submit']")

return_login.click()

time.sleep(2)

driver.quit()

Am I doing something wrong? I have used a 'try-except' block but haven't been able to test it yet but would like feedback if that's how a 'try-except' block is coded. I checked the DOM when working manually, except when creating new rows or adding stuff to my work order, the DOM doesn't really change.

Here is the 'try-except' block:

for labor_row in range(0, len(pm_labor)):

            try:

                # Click on new labor for a new row to enter labor information

                element_new_labor = WebDriverWait(driver, 60, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((By.XPATH, "//*[@id='m4dfd8aef_bg_button_addrow-pb']")))

                new_labor = driver.find_element(By.XPATH, "//*[@id='m4dfd8aef_bg_button_addrow-pb']")

                new_labor.click()

                time.sleep(2)

                # Add labor ID from pm_labour list

                element_labor_id = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:2]_txt-tb[R:" + str(labor_row) + "]']")))

                labor_id = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:2]_txt-tb[R:" + str(labor_row) + "]']")

                labor_id.clear()

                slow_type(labor_id, pm_labor[labor_row][0].replace(" ", "", 1))

                time.sleep(2)

                # Add start date for PM from pm_labour list

                element_start_date = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:6]_txt-tb[R:" + str(labor_row) + "]']")))

                start_date = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:6]_txt-tb[R:" + str(labor_row) + "]']")

                start_date.clear()

                slow_type(start_date, pm_labor[labor_row][1].replace(" ", "", 1))

                time.sleep(2)

                # Add end date for PM from pm_labour list

                element_end_date = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:7]_txt-tb[R:" + str(labor_row) + "]']")))

                end_date = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:7]_txt-tb[R:" + str(labor_row) + "]']")

                end_date.clear()

                slow_type(end_date, pm_labor[labor_row][1].replace(" ", "", 1))

                time.sleep(2)

                # Add start time for PM from start_time list

                element_start_time = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:8]_txt-tb[R:" + str(labor_row) + "]']")))

                start_time_text = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:8]_txt-tb[R:" + str(labor_row) + "]']")

                start_time_text.clear()

                slow_type(start_time_text, start_time[counter])

                time.sleep(2)

                # Add end time for PM from end_time list

                element_end_time = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:9]_txt-tb[R:" + str(labor_row) + "]']")))

                end_time_text = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:9]_txt-tb[R:" + str(labor_row) + "]']")

                end_time_text.clear()

                slow_type(end_time_text, end_time[counter])

                time.sleep(3)

            except StaleElementReferenceException:

                # Delete row if exception is thrown and continue with loop

                element_delete_row = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH,
                         "//*[@id='m900f2d81_tdrow_[C:9]_toggleimage-ti[R:" + str(labor_row) + "]']")))

                driver.find_element(
                    By.XPATH,
                    "//*[@id='m900f2d81_tdrow_[C:9]_toggleimage-ti[R:" + str(labor_row) + "]']").click()

                if labor_row == 0:

                    labor_row = 0

                    continue

                else:

                    labor_row += 0

                    continue

The error is mostly:

StaleElementException: element is not attached to page'

The specific parts where the error occurs is:

(Sometimes the error is thrown in the first iteration itself or it will work fine for the first few iterations and then break again which is more frustrating!)

1.

pm_availability = []

for pm in range(0, len(pm_actuals[0])):

    time.sleep(1)

    ignore_exceptions = (NoSuchElementException, StaleElementReferenceException,)

    element_search_text_wo = WebDriverWait(driver, 120, 5, ignore_exceptions).until(
        ec.visibility_of_element_located((By.XPATH, "//input[@id='m6a7dfd2f_tfrow_[C:1]_txt-tb']")))

    search_text_wo = driver.find_element(By.XPATH, "//input[@id='m6a7dfd2f_tfrow_[C:1]_txt-tb']")

    search_text_wo.clear()

    slow_type(search_text_wo, pm_actuals[0][pm].replace(" ", "", 1))

    action.move_to_element(search_text_wo).send_keys(Keys.RETURN).release().perform()

    element_len_elements_list = WebDriverWait(driver, 120, 5, ignore_exceptions).until(
        ec.visibility_of_any_elements_located((By.XPATH, "//*[contains(@id, 'm6a7dfd2f_tbod_tdrow-tr[R:')]")))

    len_elements_list = driver.find_elements(By.XPATH, "//*[contains(@id, 'm6a7dfd2f_tbod_tdrow-tr[R:')]")

    if len(len_elements_list) != 0:

        # Check if PM status is WSCH

        if driver.find_element(
                By.XPATH,
                "/html/body/form/div/table[2]/tbody/tr/td/table/tbody/tr/td/table/tbody/tr/td/table/tbody/tr[2]/td/div/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr/td/div/table/tbody/tr/td/table/tbody/tr[2]/td/table/tbody/tr[2]/td/div/table/tbody/tr[3]/td/table/tbody/tr[3]/td/table/tbody/tr[4]/td[10]").text == "WSCH":

            pm_availability.append(pm_actuals[0][pm].replace(" ", "", 1))

            continue

        # If PM status is not WSCH, continue searching

        else:

            continue

    else:

        continue
        for labor_row in range(0, len(pm_labor)):

            try:

                # Click on new labor

                element_new_labor = WebDriverWait(driver, 60, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((By.XPATH, "//*[@id='m4dfd8aef_bg_button_addrow-pb']")))

                new_labor = driver.find_element(By.XPATH, "//*[@id='m4dfd8aef_bg_button_addrow-pb']")

                new_labor.click()

                time.sleep(2)

                # Add labor ID from pm_labour list

                element_labor_id = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:2]_txt-tb[R:" + str(labor_row) + "]']")))

                labor_id = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:2]_txt-tb[R:" + str(labor_row) + "]']")

                labor_id.clear()

                slow_type(labor_id, pm_labor[labor_row][0].replace(" ", "", 1))

                time.sleep(2)

                # Add start date for PM from pm_labour list

                element_start_date = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:6]_txt-tb[R:" + str(labor_row) + "]']")))

                start_date = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:6]_txt-tb[R:" + str(labor_row) + "]']")

                start_date.clear()

                slow_type(start_date, pm_labor[labor_row][1].replace(" ", "", 1))

                time.sleep(2)

                # Add end date for PM from pm_labour list

                element_end_date = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable((
                        By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:7]_txt-tb[R:" + str(labor_row) + "]']")))

                end_date = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:7]_txt-tb[R:" + str(labor_row) + "]']")

                end_date.clear()

                slow_type(end_date, pm_labor[labor_row][1].replace(" ", "", 1))

                time.sleep(2)

                # Add start time for PM from start_time list

                element_start_time = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:8]_txt-tb[R:" + str(labor_row) + "]']")))

                start_time_text = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:8]_txt-tb[R:" + str(labor_row) + "]']")

                start_time_text.clear()

                slow_type(start_time_text, start_time[counter])

                time.sleep(2)

                # Add end time for PM from end_time list

                element_end_time = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:9]_txt-tb[R:" + str(labor_row) + "]']")))

                end_time_text = driver.find_element(
                    By.XPATH, "//input[@id='m4dfd8aef_tdrow_[C:9]_txt-tb[R:" + str(labor_row) + "]']")

                end_time_text.clear()

                slow_type(end_time_text, end_time[counter])

                time.sleep(3)

            except StaleElementReferenceException:

                element_delete_row = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
                    ec.element_to_be_clickable(
                        (By.XPATH,
                         "//*[@id='m900f2d81_tdrow_[C:9]_toggleimage-ti[R:" + str(labor_row) + "]']")))

                driver.find_element(
                    By.XPATH,
                    "//*[@id='m900f2d81_tdrow_[C:9]_toggleimage-ti[R:" + str(labor_row) + "]']").click()

                if labor_row == 0:

                    labor_row = 0

                    continue

                else:

                    labor_row += 0

                    continue
        for rout in range(0, 3):

            if driver.find_element(By.XPATH, "//*[@id='md489b5d4-tb']").text != "COMP":

                # Click on the route button

                element_route = WebDriverWait(driver, 180, 20, ignore_exceptions).until(
                    ec.element_to_be_clickable((By.XPATH, "//*[@id='ROUTEWF_KAUWO_-tbb_anchor']")))

                route = driver.find_element(By.XPATH, "//*[@id='ROUTEWF_KAUWO_-tbb_anchor']")

                route.click()

                time.sleep(5)

                # Click on OK in the corresponding dialog box

                # element_click_ok = WebDriverWait(driver, 180, 20, ignore_exceptions).until(
                #     ec.element_to_be_clickable((By.XPATH, "//button[@type='button' and @id='md875c1f9-pb']")))
                #
                # click_ok = driver.find_element(By.XPATH, "//button[@type='button' and @id='md875c1f9-pb']")
                #
                # click_ok.click()

                driver.switch_to.alert.accept()

                time.sleep(5)

            else:

                pass

        element_list_view = WebDriverWait(driver, 30, 5, ignore_exceptions).until(
            ec.visibility_of_element_located((By.XPATH,
                                              "//*[@id='m397b0593-tabs_backToList']/table/tbody/tr/td[1]")))

        list_view = driver.find_element(By.XPATH,
                                        "//*[@id='m397b0593-tabs_backToList']/table/tbody/tr/td[1]")

        time.sleep(2)

        list_view.click()

        time.sleep(2)

        pms_routed = [print(f"WO {pm_actuals[0][i]} is closed.")]

        counter += 1

        time.sleep(2)

        len(pm_availability) - 1
undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • It will be very difficult for anyone to help you, without actual access to the actual page (which is not possible in this instance). However, you mention you are adding new elements to the DOM: try re-reading the DOM each time after adding a new element (do something like `correct_page_source = driver.page_source`). Also, I notice you are using XPATH to locate elements with static id's: locate those with By.ID instead of By.XPATH. You also have big try/except loops: make those smaller and more frequent, to pinpoint the actual errors. – Barry the Platipus Jul 23 '22 at 10:19
  • @platipus_on_fire_333 The try-except I can perhaps change within the loop. But I don't understand the re-reading of the element part. Do you mean I assign another variable to the same element after I work on it or before? How would you do it? And would you like to work on it with me? – Md. Masum Omar Jashim Jul 23 '22 at 11:20
  • I meant - once you add a new element to the DOM, assign it to a variable, and move to the next step only if presence of that element returns True. Unfortunately I'm not sure I have the time and resources to work with you, however I can try and help as/if possible. – Barry the Platipus Jul 23 '22 at 12:05
  • @platipus_on_fire_333 In all for loops, elements are reassigned every time the for loop is initiated. Check the 2nd loop. Every time new_labor is clicked, a new row is added with a text field for labor_id, start_date, end_date, start_time, and end_time which are assigned to a variable before interaction every time the for loop runs. The clicking (adding a new row) has no problem, it's when I input text in the fields when the stale element exception occurs. Meaning, that every time I have the clear() method called on text fields, just before input the code will throw a stale element exception. – Md. Masum Omar Jashim Jul 23 '22 at 12:31
  • @platipus_on_fire_333 I forgot to ask. What does the page_source() method do? Googling only showed that it gives back HTML code in string format. I would like to know does it function like re-initializing the elements within the page, kind of like a soft refresh without actually reloading the page? Or it has some other hidden function because the selenium source website didn't say anything. So, I am confused about the page_source() method's benefit here. – Md. Masum Omar Jashim Jul 23 '22 at 12:40
  • it returns html content - implying it reads it, then returns it, hence finding any eventual newly added element. Although Waits should do that as well. – Barry the Platipus Jul 23 '22 at 12:43
  • @platipus_on_fire_333 Ok I will try the page_source method. I wanted to ask about fluent wait though. What does the polling do really? Is it like ping in Networking? Because it doesn't work, the fluent wait. Or any wait for that matter. As you can see, I have waits with 5 minutes timer, yet the Stale Element Exception occurs. Polling should definitely have worked because it polls the element. But yet, it too fails. – Md. Masum Omar Jashim Jul 23 '22 at 20:01
  • @platipus_on_fire_333 I think if all else fails, then I should just code the whole thing with pyautogui, although that will beat the purpose of me trying to automate my work, but it's better than nothing I guess. – Md. Masum Omar Jashim Jul 23 '22 at 20:06

1 Answers1

0
StaleElementException: element is not attached to page

...implies that the previous reference of the element is now stale and the element reference is no longer present in the current state of the HTML DOM of the page.

The common reasons behind this this exception can be either of the following:

  • The element have changed it's position within the HTML DOM.
  • The element is no longer attached to the DOM TREE.
  • The webpage on which the element was part of has been refreshed.
  • The previous instance of element has been refreshed by a JavaScript.

This usecase

Your suspicion "when I start clicking on text fields on each new row that I get errors. It's as if adding a new row changes the whole DOM" is absolutely correct as "creates another table in the DOM" definitely changes the position of the previously identified element within the DOM Tree though others remain unchanged.


References

You can find a couple of relevant detailed discussions in:

undetected Selenium
  • 183,867
  • 41
  • 278
  • 352
  • That's what I don't understand. I add a new row, and then when I click on this new row text fields, such as labor ID, start time, end time, etc. (all text fields) that's when I get an error. The DOM does change when adding new rows, but shouldn't the new element be available in the DOM. I just created it. – Md. Masum Omar Jashim Jul 24 '22 at 07:15
  • Can you check the 2nd for loop where my error occurs too. In that 'try-except' block, I know it's quite big, I want to catch an error because sometimes the error will show up right at the end or at the beginning because those elements are within the same row in the div/table. And I had studied about Page Factory Model. It seems a lot more convenient because elements can be reevoked so I guess there shouldn't be any errors ever if I use that. Can you confirm if that is true for Page Factory Models? – Md. Masum Omar Jashim Jul 24 '22 at 07:24