Closed spbrantan closed 3 weeks ago
The article you posted is using vue-fragment
, but I'm getting the same issue using the vue-frag
library.
Reading vue-frag
's documentation I saw the below excerpt:
How does this work?
Vue associates vNodes with specific DOM references so once a component has mounted, the DOM nodes can be moved around and Vue will still be able to mutate them by reference. The Frag directive simply replaces the root element of a component in the DOM with it's children upon DOM insertion, and monkey-patches native properties like parentNode on the children to make Vue think they're still using the component root element.
Perhaps the monkey-patching behaves in a non-native way that makes Selenium interpret it wrong?
Can you please provide a complete code snippet so we can have a look? Without any 3rd party dependencies.
public static void main(String[] args) throws IOException {
WebDriverManager.chromedriver().setup();
WebDriver driver = new ChromeDriver();
driver.manage().window().maximize();
driver.manage().timeouts().implicitlyWait(20, TimeUnit.SECONDS);
try {
driver.navigate().to("https://oel-auto.pandodev.in");
Thread.sleep(5000);
driver.findElement(By.xpath("//label[text()='User name:']/preceding-sibling::input")).sendKeys("testuser@testuser.in");;
driver.findElement(By.xpath("//label[text()='Password:']/preceding-sibling::input")).sendKeys("test@1234");;
Thread.sleep(1000);
driver.findElement(By.xpath("//button[contains(text(),'Log in')]")).click();;
driver.findElement(By.xpath("//main[@class='container-fluid main-content']"));
driver.navigate().to("https://oel-auto.pandodev.in/exim-master-indent-list");
Thread.sleep(3000);
driver.findElement(By.xpath("//span[@class='row-expand']")).click();
Thread.sleep(2000);
System.out.println(driver.findElement(By.xpath("(//div[contains(@Class,'grid-list')]//div)[4]/p")).getText()); //Blue-highlighted PFA. Returns text "FOB" as expected.
System.out.println(driver.findElement(By.xpath("((//div[@class='nested-list']/div)[1]//div[contains(@class,'vendor')]//span)[last()]")).getText()); //Red-highlighted PFA. Returns text "HELLMAN LOGISTI..." but expected is "t320210730071752".
} catch (Exception e) {
e.printStackTrace();
} finally {
driver.close();
driver.quit();
}
}
In the above code, first sysout gives me expected output which is "FOB". But the second sysout gives me "HELLMAN LOGISTI..." but expected output is "t320210730071752".
If you check the xpath in DOM then it highlights the "t320210727141945" but since it is in vue fragment block selenium could not read that and instead returns the wrong text.
Blue Highlighted Element is accessible to webdriver
Red-Highlighted Element is not accessible to webdriver since that is generated by vue Fragment.
@diemol
As discussed in #10157
Something in isDisplayed.js
atom is returning false
and I'm not sure where to start with it.
Using the example from https://github.com/SeleniumHQ/selenium/issues/10157 the reason for this is the Vue fragment addons screwing with the parentNode
property on the inserted template element. In that example the
<main fragment="13484d9094b" class="App---main---2ArFP">…</main>
element has had parentNode modified to return an element which isn't actually in the render tree
<div fragment="13484d9094b"></div>
That alone wouldn't be so bad but the element returned as the parent doesn't have childNodes set
$0.parentNode.childNodes.length
0
So it's a 0 height, 0 width element with no children to overflow and therefore calculates as non-visible (positiveSize function returns false). Capybara is not affected by this because it had overridden the isDisplayed atom with it's own version which used parentElement
to get the parent - which Vue hasn't monkeyed with
This issue may only affect Vue 2 projects using vue-fragment - vue-frag
appears to set childNodes
on the container so the atom should correctly calculate visibility and Vue 3 appears to use a different method for implementing this functionality
So, the problem is with how Vue is messing with the DOM, and presumably users can update their code to avoid this issue.
That said, this is probably a good opportunity to discuss slimming down the atom and we can address the issue on the Selenium side as well.
Add $(element).css({"overflow": "visible", "position": "static"}) will resolve this issue. isDisplayed.js use this style to check whether element exists.
Any updates on this issue? Should we expect this to be fixed sometime?
Technically this is a bug in vue-fragment
which removes ChildNodes from the container. vue-frag
and Vue 3 both do this correctly.
If Selenium changed the atom to use parentElement
instead of parentNode
it could also solve it, but that may or may not be the right fix. @AutomatedTester was looking into this, but I should have had this discussion on the other Issue, because that's where the reproducible use case is — https://github.com/SeleniumHQ/selenium/issues/10157
I am trying to reduce this down as there isn't reduced html show casing this... it might take some time unless someone with vue experience can give me a single page html with everything. Until then I will be trying to reduce down the html in #10157
Still no updates here?
@GgStormer please change/update your library or raise an issue with vue-fragment. This is not a defect in Selenium.
Additionally, the Selenium atom is not an easy thing to work with in its current state and it has some bigger limitations than this issue. Really it needs an overhaul and maybe a move away from Closure to TypeScript. This particular issue might be addressed as part of that move, or it might not, because moving from parentElement to parentNode might not be the right choice for it.
@GgStormer did you raise an issue with vue-fragment
? Could you please link it here?
Facing this too. I understand that this is not an issue within Selenium, but is there any hacky workaround that could be used here when changing vue-fragment
isn't an option? The workaround @jasonfreec mentioned doesn't seem to work currently, maybe something has changed in the past year.
I forked the XPath libary and replaced the native implementation https://github.com/NikhilVerma/xpath-next this handles Vue 3 issues by ignoring the vue fragments and adds supports for shadow DOM elements
I also logged an issue here - https://github.com/vuejs/core/issues/8444
Maybe this is related to #13132 (get-text
atom)?
One more question. Do these vue.js components use a closed Shadow DOM? If yes, I noticed https://github.com/SeleniumHQ/selenium/issues/13132 by the end of last week.
This issue is looking for contributors.
Please comment below or reach out to us through our IRC/Slack/Matrix channels if you are interested.
This issue is stale because it has been open 280 days with no activity. Remove stale label or comment or this will be closed in 14 days.
This issue was closed because it has been stalled for 14 days with no activity.
🐛 Bug Report
Elements with attribute 'fragment' are not visible. Impossible to interact with child elements.
Root Cause vue.js uses a concept called Fragments to create more than one root node in a Vue component. This is done for Accessibility support which is necessary to allow assistive technology like screen readers to interpret web pages and applications, More about this in -> https://blog.logrocket.com/fragments-in-vue-js/
So, basically they are creating HTML tag that would not read as a node by the DOM and called it fragments.
Hence the webelements inside such fragments are not visible for Webdriver. This is more or less like a iframe inside html page where we do switchToIFrame and interact with it. Only that for Fragments there are no ways to make it visible to the webdriver.
PFA Screenshot of DOM snapshot containing the Fragment.
To Reproduce
https://jsfiddle.net/brantansp/bwdkx1tg/3/#&togetherjs=eM6k1p6Iaz
Detailed steps to reproduce the behavior:
System.out.println(webDriver.findElement(By.xpath("((//div[@class='nested-list']/div)[1]//div)[4]")).getText()); //returns null
Expected behavior
System.out.println(webDriver.findElement(By.xpath("((//div[@class='nested-list']/div)[1]//div)[4]")).getText()); //should return value
Test script or set of commands reproducing this issue
WebDriverManager.chromedriver().setup(); WebDriver webDriver = new ChromeDriver(); System.out.println(webDriver.findElement(By.xpath("((//div[@class='nested-list']/div)[1]//div)[4]")).getText());
Environment
OS: Windows 10 x64 Browser: Chrome Browser version: 89 Browser Driver version: ChromeDriver 89 Language Bindings version: Java 3.141.59