Skip to content
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

Wait For Asynchronous Text Changes #211

Open
DeLongShot opened this issue Apr 4, 2018 · 1 comment
Open

Wait For Asynchronous Text Changes #211

DeLongShot opened this issue Apr 4, 2018 · 1 comment

Comments

@DeLongShot
Copy link

DeLongShot commented Apr 4, 2018

The current matchers visible_in_page?/1 and visible_in_element?/2 currently immediately return the body/element if it is found. It will then try to immediately match the pattern against the body/element.

Problem:
If you are making an asynchronous change to the text within the body of the page or element, a race condition exists where those methods may return the body/element before the change has been made. Thus, this can cause 'flapping' failures.

For a use case that I think is fairly common, say I have a counter that updates when a user makes some action, which fires an AJAX request.

<ul>
  <li class="counter">10</li>
  ...
</ul>

I understand that this is a bit of a loophole in the WebDriver spec since there is no way to select an element purely by its text.

Solution
For Hound? Not sure, but it would be nice if there was some matcher or other way to have Hound to retry a matcher for text a couple of times before failing. Similar to how make_req/5 works.

Quick Solution
For those that want a quick workaround, I found two ways to implement this on my own.

  1. Use visible_in_element?/2 with a couple of retries. Here's how I implemented it. It's a bit crude, but works.
defp text_visible?(element, pattern, retries \\ 5)

defp text_visible?(element, pattern, 0) do
  visible_in_element?(element, pattern)
end

defp text_visible?(element, pattern, retries) do
  case visible_in_element?(element, pattern) do
    true -> true

    false ->
      :timer.sleep(10) # however you want to wait, 10 ms seemed consistent for me
      text_visible?(element, pattern, retries - 1)
  end
end

assert text_visible?({:css, ".counter"}, ~r/11/)
  1. Use find_element/2 with the :xpath strategy
find_element(:xpath, "//ul/li[text()=\"11\"]")
  1. Use element?/2 with the :xpath strategy and an assertion
assert element?(:xpath, "//ul/li[text()=\"11\"]")

I haven't benchmarked any of these solutions, but testing them manually, they all seem to take about the same time when running the test.

I'd be interested in putting together a PR to add this, but not sure the feelings on this feature and how best to add it.

@JGjumpshot
Copy link

Would I put these private functions above any of my test cases and call them down in the actual test? I struggled to implement the above solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants