I am trying to write a stable code to input a date into calendar input field. Native Selenium inputs work only locally, but when I run this code in CICD I see that numbers are sometime inputted into wrong places.
For example, the timestamp is 2022-07-22 00:56:42.
Expected input by user is 220720220056
.
By experimenting I found out that year works if there are two zeros in front of the year. Therefore, what I actually send is 22070020220056
input_field = driver.find_element(By.XPATH, "//div[@role='dialog']//input[@type='datetime-local']")
input_field.click()
input_field.clear()
input_field.send_keys(22070020220056)
<input _ngcontent-pau-c188="" clrinput="" type="datetime-local" name="expiry" aria-describedby="clr-form-control-9-helper" id="clr-form-control-9" >
#shadow-root (user-agent) == $0
<div pseudo="-webkit-datetime-edit" id="date-time-edit" datetimeformat="dd/MM/y, HH:mm">
<div pseudo="-webkit-datetime-edit-fields-wrapper">
<span role="spinbutton" aria-placeholder="dd" aria-valuemin="1" aria-valuemax="31" aria-label="Day" pseudo="-webkit-datetime-edit-day-field" aria-valuenow="25" aria-valuetext="25">25</span>
<div pseudo="-webkit-datetime-edit-text">/</div>
<span role="spinbutton" aria-placeholder="mm" aria-valuemin="1" aria-valuemax="12" aria-label="Month" pseudo="-webkit-datetime-edit-month-field" aria-valuenow="7" aria-valuetext="07">07</span>
<div pseudo="-webkit-datetime-edit-text">/</div>
<span role="spinbutton" aria-placeholder="yyyy" aria-valuemin="1" aria-valuemax="275760" aria-label="Year" pseudo="-webkit-datetime-edit-year-field" aria-valuenow="2022" aria-valuetext="2022">2022</span>
<div pseudo="-webkit-datetime-edit-text">, </div>
<span role="spinbutton" aria-placeholder="--" aria-valuemin="0" aria-valuemax="23" aria-label="Hours" pseudo="-webkit-datetime-edit-hour-field" aria-valuenow="0" aria-valuetext="00">00</span>
<div pseudo="-webkit-datetime-edit-text">:</div>
<span role="spinbutton" aria-placeholder="--" aria-valuemin="0" aria-valuemax="59" aria-label="Minutes" pseudo="-webkit-datetime-edit-minute-field" aria-valuenow="1" aria-valuetext="01">01</span>
</div>
</div>
</input>
I tried few other options to make the test more stable.
Option 1.
Tried to set the value directly.
driver.execute_script(f"arguments[0].setAttribute('value', '{my_timestamp}')", input_field)
Option 2
Tried to access shadow root:
date_field = driver.execute_script("return document.querySelector('input[type=datetime-local]').shadowRoot.getElementById('#date-time-edit')")
date_field.send_keys(my_timestamp)
Option 3
Tried to get parent element with execute_script
instead of Selenium and send value:
date_field = driver.execute_script("return document.querySelector('input[type=datetime-local]')")
date_field.send_keys(my_timestamp)
Option 4
Tried to send text with a small delay before each letter:
for letter in timestamp:
time.sleep(0.1)
print(f"Sending letter {letter}")
date_field.send_keys(letter)
None of these methods worked on CICD, Only initial one and Option 3 always work locally.
I think the only stable solution would be the use of Javascipt code, but still not sure.
Any suggestion would be greatly appreciated.
CodePudding user response:
Ah yes, the shadow root. For me, what works is something like the following:
shadowRootElement = driver.execute_script('''return document.querySelector("selector for shadowRoot's parent").shadowRoot''')
shadowRootChild = driver.execute_script('''return arguments[0].querySelector("selector for shadowRoot's parent").shadowRoot''', shadowRootElement)
shadowRootChild.find_element(By.CSS_SELECTOR, 'input[type=datetime-local]').send_keys("This is a test");
CodePudding user response:
The <input>
looks perfectly out of #shadow-root (user-agent) ambit.
<input _ngcontent-pau-c188="" clrinput="" type="datetime-local" name="expiry" aria-describedby="clr-form-control-9-helper" id="clr-form-control-9" >
#shadow-root (user-agent) == $0
<div pseudo="-webkit-datetime-edit" id="date-time-edit" datetimeformat="dd/MM/y, HH:mm">
<div pseudo="-webkit-datetime-edit-fields-wrapper">
.
.
.
</div>
</div>
</input>
However, the desired element is a Angular element, so ideally to send a character sequence to the element you need to induce WebDriverWait for the element_to_be_clickable() and you can use the following locator strategy:
Using XPATH:
input_field = WebDriverWait(driver, 20).until(EC.element_to_be_clickable((By.XPATH, "//input[@class='clr-input ng-pristine ng-valid ng-touched' and @name='expiry'][@type='datetime-local']"))) driver.execute_script(f"arguments[0].setAttribute('value', '{my_timestamp}')", input_field)
Note: You have to add the following imports :
from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC