New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ElementsCollection object does not 'refresh' itself when calling get() or size() #181
Comments
Because loading of the entire collection can be slow, the ElementsCollection class was initially designed so that it reuses previously loaded element. That's why method So, I am not sure it's a bug. Fixing this issue may cause performance downgrade. |
What about $$.get ? But how then the following code work: open("http://google.com/ncr");
$(By.name("q")).setValue("selenium").pressEnter();
ElementsCollection results = $$(".st");
assert results.size() == 0;
results.get(9).shouldHave(text("Downloading Selenium server")); If $$.get reloads the ElementsCollection, why then not to make size to reload for consistency? And why not to make this "optional" via Configuration for those who need this? :) |
Hm... Seems like get is not like size... $.get at least can know what to wait... - the element index for which is passed as param... Hm... Nevertheless... currently the only way to fix "bdd step with check" problem is to use tasks as method not variable... What is not handy and not consistent... I think that then at least the $.refresh method should be added for manual refresh in such cases... About performance... So far I can hardly imagine the drawback taking into account that "calling raw $.size" will be so often in tests... Maybe it's a good idea to do some "assessment"... |
I think the "bdd step with check" problem is not a real problem. In Selenide, it's natural to use methods |
Sorry that I have not given up yet. I called it "BDD" check, just becuase sometimes in BDD you want to write a "step" that does two things: action/operation + check of its result. In addition this "check" should be "general", it should work for different contexts. Can you help to build such "step with check" (let's even forget about "bdd" word) with selenide? :) The pattern you recommend will give something like this: 1 public void addTask(String taskText){
int oldSize = tasks.size
$("#new-todo").setValue("1").pressEnter();
tasks.get(oldSize).shouldHave(exactText(taskText));
} or 2 public void addTask(String taskText){
int oldSize = tasks.size
$("#new-todo").setValue("1").pressEnter();
int newSize = oldSize + 1
tasks.shouldHave(size(newSize));
tasks.get(newSize - 1).shouldHave(exactText(taskText));
} or are there better options? And now look into these examples - 1 and 2 - once more.
We will get newSize not oldSize. Yeah, under cover, the tasks are not smart... But they look like smart - and this confuses. I want to say that current Selenide behavior is not consistent and confuses the user. Now about the "philosophy". P.S. 1 P.S. 2 Seems like Selenide can't give the alternative to Selenium in this context. P.S. 3 About performance... You said that we will loose in performance... But think - when will we use the tasks.shouldHave(size(newSize));
tasks.get(newSize - 1).shouldHave(exactText(taskText)); So we definitly need to wait... And this is not a "waste of time", because we "want to wait here". We just have to do this explicitly, not like in other "selenide" contexts, when we have "implicit smart waits" by default. When I write tests with Selenide - I really rarely use |
The issue described here happened to be valuable for one more person here: http://automated-testing.info/t/pomogite-razobratsya-s-problemoj-czikla-v-selenide/10467 Here is a bit more "research" describing the problem of "ElementsCollection's size(), get(int), and iterator" being not working as expected by users (i.e. being up to date at any time we ask the ElementsCollection object about something): import com.codeborne.selenide.ElementsCollection;
import com.codeborne.selenide.SelenideElement;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import static com.codeborne.selenide.CollectionCondition.empty;
import static com.codeborne.selenide.Selenide.*;
public class IteratingElementsCollectionShouldBeUpToDateTest {
@Before
public void openPage(){
open("http://todomvc4tasj.herokuapp.com/");
}
@After
public void clearData(){
executeJavaScript("localStorage.clear()");
}
@Test
public void WhenUsingIterator_OfSameElementsCollectionObject(){
$("#new-todo").setValue("a").pressEnter();
$("#new-todo").setValue("b").pressEnter();
$("#new-todo").setValue("c").pressEnter();
for (SelenideElement task : $$("#todo-list>li")) {
task.hover().find(".destroy").click();
}
$$("#todo-list>li").shouldBe(empty);
/*
* removes only a & c, leaving b, and then FAILS here with:
ListSizeMismatch : expected: = 0, actual: 1, collection: #todo-list>li
Elements: [
<li class="active" data-index="1" value="0">b</li>
]
Screenshot: file:/Users/ayia/projects/tmp/selenide-tests/build/reports/tests/1470479873538.0.png
Timeout: 6 s.
*/
}
@Test
public void WhenUsingGet_OnNewElementsCollectionObject(){
$("#new-todo").setValue("a").pressEnter();
$("#new-todo").setValue("b").pressEnter();
$("#new-todo").setValue("c").pressEnter();
for (SelenideElement task : $$("#todo-list>li")) {
task.hover().find(".destroy").click();
}
while (!$$("#todo-list>li").isEmpty()) {
$$("#todo-list>li").get(0).hover().find(".destroy").click();
}
$$("#todo-list>li").shouldBe(empty);
/*
* PASSED
*/
}
@Test
public void WhenUsingGet_OnSameElementsCollectionObject_WithIterationBasedOnIsEmpty(){
$("#new-todo").setValue("a").pressEnter();
$("#new-todo").setValue("b").pressEnter();
$("#new-todo").setValue("c").pressEnter();
for (SelenideElement task : $$("#todo-list>li")) {
task.hover().find(".destroy").click();
}
ElementsCollection tasks = $$("#todo-list>li");
while (!tasks.isEmpty()) {
tasks.get(0).hover().find(".destroy").click();
/*
* removes all and then FAILS here with
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
*/
}
tasks.shouldBe(empty);
}
} Current workaround for this issues is described in a
instead of
|
Close old issue. Feel free to reopen and start disscussion again if it still needs to implement. |
If you store SelenideElement object in the variable like here:
Then calling
should
willrefresh
elements collection object (i.e. search again for all elements matching locator on the page).But calling
get()
orsize
will not refresh the object.This make impossible an implementation of some "BDD style steps" when you combine action and assertion of its results in one step-method
Example:
Full code: https://www.refheap.com/101119
The text was updated successfully, but these errors were encountered: