First AJAX heavy app I worked on, we rigged the game so that we could win.
We wired up all of the asynchronous bits to tweak a hidden DOM element at the bottom of the page, so that our tests could wait for that element to settle before validating anything.
We'd already had a lot of our async code run through a couple of helper methods (to facilitate cache busting and Karma tests), so it was 'just' a matter of finishing what we'd started.
I kinda feel like the browsers are letting us down by not exposing this sort of stuff.
A great deal of your non-determinism is in trying to run an End-to-End test while the UI is still trying to settle.
For instance, your negative tests (click something and make sure nothing happens) can fail to detect anything at all because they perform an action and then validate the UI before the action has even processed.
Yes, of course nothing has happened, because you didn't let it.
Non-determinism is just one issue. The other issue is how frequently the UI changes. For example, a large form can get broken out into a wizard. The UI is completely semantically different, but performs the same functionality.
How do you make such UI changes without your test suite slowing you down?
We wired up all of the asynchronous bits to tweak a hidden DOM element at the bottom of the page, so that our tests could wait for that element to settle before validating anything.
We'd already had a lot of our async code run through a couple of helper methods (to facilitate cache busting and Karma tests), so it was 'just' a matter of finishing what we'd started.
I kinda feel like the browsers are letting us down by not exposing this sort of stuff.