Selenium - after bootstrap modal test, subsequent test fail with error ElementClickInterceptedError
You don't need to use the implicitwait everytime. What you need to wait for is the visibility of the elements before doing the click operations.
There is a elementIsVisible
method available in the wait condition. I've modified the code to check for the presence of the element and then the visibility of the element before doing the click.
(async function uitest() { let driver = await new Builder().forBrowser('chrome').build(); let element try { await driver.get(fileName) //Launch Modal 1 and close await driver.findElement(By.id('launchModalButton')).click() let closeButton1 = await driver.wait(until.elementLocated(By.id('closeButton'))) closeButton1 = await driver.wait(until.elementIsVisible(closeButton1)) await closeButton1.click() // middle button click await driver.findElement(By.id('button')).click() //Launch Modal 2 and close await driver.findElement(By.id('launchModalButton_2')).click() let closeButton2 = await driver.wait(until.elementLocated(By.id('closeButton_2'))) closeButton2 = await driver.wait(until.elementIsVisible(closeButton2)) await closeButton2.click() } catch (err) { console.log(err) } finally { await driver.quit(); }})()
This error message...
[13108:12832:0501/100716.495:ERROR:browser_switcher_service.cc(238)] XXX Init() ElementClickInterceptedError: element click intercepted: Element ... is not clickable at po int (233, 67). Other element would receive the click: ... (Session info: chrome=81.0.4044.129)
...implies that the desired element wasn't clickable when you invoked click()
on it.
As you mentioned test which launch a modal and close it, will pass, but subsequent test fails with ElementClickInterceptedError essentially means that when you invoked click()
on the second element Button at that point of time the Modal Dialog Box containing the element with text as Launch modal was still obsecuring the desired element. Hence the click on the desired element failed.
Details
To start with implicit wait may not be effective with modern application built using JavaScript, Angular, ReactJS, jQuery, AJAX, Vue.js, Ember.js, etc.
Effectively you need to replace implicit wait with explicit wait.
selenium-webdriver/lib/until
elementLocated: Creates a condition that will loop until an element is found with the given locator.
/** * Creates a condition that will loop until an element is * {@link ./webdriver.WebDriver#findElement found} with the given locator. * * @param {!(By|Function)} locator The locator to use. * @return {!WebElementCondition} The new condition. */exports.elementLocated = function elementLocated(locator) { locator = by.checkedLocator(locator); let locatorStr = typeof locator === 'function' ? 'by function()' : locator + ''; return new WebElementCondition('for element to be located ' + locatorStr, function(driver) { return driver.findElements(locator).then(function(elements) { return elements[0]; }); });};
elementIsVisible: Creates a condition that will wait for the given element to become visible.
/** * Creates a condition that will wait for the given element to become visible. * * @param {!./webdriver.WebElement} element The element to test. * @return {!WebElementCondition} The new condition. * @see ./webdriver.WebDriver#isDisplayed */exports.elementIsVisible = function elementIsVisible(element) { return new WebElementCondition('until element is visible', function() { return element.isDisplayed().then(v => v ? element : null); });};
Solution
So your effective code block replacing implicit wait with explicit wait will be:
(async function uitest() { let driver = await new Builder().forBrowser('chrome').build(); let element try { await driver.get(fileName) //Click Launch Modal let launchModal = await driver.wait(until.elementLocated(By.id('launchModalButton'))) launchModal = await driver.wait(until.elementIsVisible(launchModal)) await launchModal.click() //Close Launch Modal let closeModal = await driver.wait(until.elementLocated(By.id('closeButton'))) closeModal = await driver.wait(until.elementIsVisible(closeModal)) await closeModal.click() //Click Button let button = await driver.wait(until.elementLocated(By.id('button'))) button = await driver.wait(until.elementIsVisible(button)) await button.click() //Click Launch Modal 2 and close let launchModal2 = await driver.wait(until.elementLocated(By.id('launchModalButton_2'))) launchModal2 = await driver.wait(until.elementIsVisible(launchModal2)) await launchModal2.click() //Close Launch Modal 2 let closeButton2 = await driver.wait(until.elementLocated(By.id('closeButton_2'))) closeButton2 = await driver.wait(until.elementIsVisible(closeButton2)) await closeButton2.click() } catch (err) { console.log(err) } finally { await driver.quit(); } })()
References
You can find a couple of related discussions in:
To bypass ElementNotClickable (this is web-driver logic), you can just use JavaScript click.
var element = await driver.findElement(By.id('button'))driver.executeScript('arguments[0].click();', element)