Closed jontonsoup closed 9 years ago
The second half of this is irrelevant now after this PR: https://github.com/HashNuke/hound/pull/36
@jontonsoup In an Ember app I had a func to load app and check if Ember loaded every 3 seconds using execute_script. If loaded then return.
I think we could have a helper like wait_for_javascript. Not sure if there's anything generic to check and confirm if page is loaded
I thought about it a little more. The problem lies in that page_source
returns immediately (without blocking for JS) and the assertion is done after this.
How does adding a function is_visible_text?/1
sound? It would retry several times before failure like the finders do.
I can implement this if you think it makes sense.
On Mon, Jun 29, 2015 at 12:34 AM, Akash Manohar notifications@github.com wrote:
I think we could have a helper like wait_for_javascript. Not sure if there's anything generic.
Reply to this email directly or view it on GitHub: https://github.com/HashNuke/hound/issues/35#issuecomment-116432039
@jontonsoup I would look at capybara's implementation of wait_for_javascript instead. That aside, we could have a separate matchers module to use with assert() easily.
@HashNuke I'm thinking of this functionality in capybara: https://github.com/jnicklas/capybara#asynchronous-javascript-ajax-and-friends, which seems to be implimented with a retry mechinism.
I do think this functionality is important as well (https://robots.thoughtbot.com/automatically-wait-for-ajax-with-capybara) but it wasn't the use case I was thinking.
Let me know which one you prefer (I like the former), and I can take a crack at it.
@jontonsoup elements are already retried by default. Finders in Hound accept a retry argument in the end to change the default.
I'm open to ideas. Below are some notes:
wait_for_element/1
seems implementable, to return only when an element appears.wait_for_ajax/0
: I'm not sure how they are implementable across frameworks (plain jQuery, Ember, React, Angular, etc)wait_for_javascript/0
should be possible. Could use best practices to check for Ember, React & jQuery app loads. For others we can allow wait_for_javascript/1
, where the first arg is the javascript to run in execute_script to run the check.@HashNuke ah I see, digging deeper into the docs it seems capybara implements this with custom rspec matchers. I assumed it was done with the retry functionality inside capybara itself. https://github.com/jnicklas/capybara/blob/master/lib/capybara/rspec/matchers.rb#L166
IMO seems like we should strive for a couple things:
My goal is to be able to write this code without knowing the implementation of how the text gets there.
expect(page).to have_text("some_text")
Adding wait_for_X
seems counter to the idea of abstracting away from the implementation. It seems like everything should wait (which is currently done via retry).
If we went the custom matcher route as you proposed, how do you see that being implemented under the hood?
@jontonsoup Hound provides no matchers right now. With ExUnit you would write something like this
element_text = find_element(:css, ".post") |> visible_text
assert Regex.match?(~r/foo/, element_text)
find_*
helpers accept an arg for number of retries - http://hexdocs.pm/hound/Hound.Helpers.Page.html
Adding wait_for_X seems counter to the idea of abstracting away from the implementation. It seems like everything should wait (which is currently done via retry).
Abstracting the waiting increases the time to run tests that will fail since every element will end up being checked for a long time. Adding a wait_for_*
would mean that the user knows that there's going to be a delay for the element to appear and can explicitly use it when required.
That's the problem with testing all frontend-heavy apps. When testing a frontend-heavy app, I wrote custom wait functions.
@HashNuke Ah yes, I was using espec notation. Regardless of the notation / matchers, my concern is that feature testing that conflates implementation with user actions can lead to brittle tests, which is my hesitation around explicitly waiting for javascript.
We always try to test from the perspective of the user (preferring user actions over CSS finders etc), which has a long term advantage of more stable tests. If the test is independent from the implementation of the feature, I can switch my feature's implementation while preserving the functionality without having to refactor the tests. This has saved our company countless hours over the years as we've transitioned front end technologies.
Hound does a great job of doing this for clicking / form interaction etc, but is missing the ability to do this for text assertions. I love the idea of having the option to explicitly use a wait for javascript if I need to, but also would prefer for the framework to take care of javascript for me in the majority of simple cases, which would make using wait_for_javascript reserved for exceptional cases.
My main concern is having to use find_element
in your example. I should be able to find text without knowing the underlying HTML structure. Although the example works fine with javascript as written, there is no way to write this currently that works with javascript and does not require me to know the underlying implementation.
I'd love to be able to write or something like this
assert visible_on_page?(element_text)
and have this work with javascript.
Capybara allows me to do this very easily. What do you think?
@jontonsoup
I should be able to find text without knowing the underlying HTML structure
Go ahead and see if you can implement visible_on_page?/2
in a new module called Hound.Matchers
.
The second arg being the number of retries, depending on how you implement it.
AFAIK the retries default to 5 in finders, so you can have the same default.
@HashNuke thanks! I'll take stab at it asap.
@jontonsoup if you have any other matchers in mind, please do create an issue(s) with todo list if required. I'll pitch in too and implement some if required.
@HashNuke will do. I have another one in mind.
Closing issue since PR has been merged.
In an Ember app I had a func to load app and check if Ember loaded every 3 seconds using execute_script. If loaded then return.
@HashNuke Could you share a gist with your Ember-related functions?
I have a test that submits a form via ajax andthen does a page redirect. Is there a way to block until these actions are finished before the next hound command is run? Currently I have to throw a :timer.sleep(5000) into my code to make the tests pass.
I'm using
page_source
as a poor stand in forexpect(page).to have_text("some_text")
. If there is a more direct way of doing either of these things, I'd love to know. Thanks! :).