@@ -6,9 +6,66 @@ def wait_for_javascript_to_return_true(script, options)
66 while Time . now - start < options [ :wait ]
77 if evaluate_script ( script )
88 return true
9+ else
10+ sleep 0.05
911 end
1012 end
11- raise Error . new ( "JavaScript `#{ script } ` did not return true, even after #{ options [ :wait ] } s" )
13+ raise Exception . new ( "JavaScript `#{ script } ` did not return true, even after #{ options [ :wait ] } s" )
14+ end
15+
16+ # Runs the given block and stalls until animations on selector stop.
17+ #
18+ # Assumes animations will *start* on the selected elements, and that the
19+ # elements will remain in the DOM until the animations stop.
20+ #
21+ # Also assumes selector doesn't include apostrophes.
22+ #
23+ # Also assumes no elements have two transition speeds/delays. In other
24+ # words: if the border and width transitions on an element end at
25+ # different times, you'll get undefined behavior.
26+ #
27+ # Why add all these assumptions, instead of simply waiting for all CSS
28+ # transitions to end? Because Chromium 63 doesn't support transitionstart or
29+ # transitionrun. We implement the workaround similar to
30+ # https://bugs.chromium.org/p/chromium/issues/detail?id=439056
31+ # which means we:
32+ #
33+ # 1. Store the matching HTML elements in a global variable
34+ # 2. Add a transitionend listener to each matching HTML element to remove
35+ # it from the global (and nix the listener)
36+ # 3. Wait until the global is empty
37+ def waiting_for_css_transitions_on_selector ( selector , &block )
38+ varname = "waiting_for_css_transitions_#{ rand ( 9999999 ) } "
39+
40+ evaluate_script ( <<-EOT
41+ (function() {
42+ const els = window.#{ varname } = Array.from(document.querySelectorAll('#{ selector } '))
43+ function listener(ev) {
44+ const el = ev.target
45+ const index = els.indexOf(el)
46+ if (index === -1) return
47+ els.splice(index, 1)
48+ el.removeEventListener('transitionend', listener)
49+ }
50+ els.forEach(el => el.addEventListener('transitionend', listener))
51+ })()
52+ EOT
53+ )
54+
55+ yield
56+
57+ js = <<-EOT
58+ (function() {
59+ if (!window.#{ varname } ) true
60+ if (window.#{ varname } .length === 0) {
61+ delete window.#{ varname }
62+ return true
63+ } else {
64+ return false
65+ }
66+ })()
67+ EOT
68+ wait_for_javascript_to_return_true ( js , wait : WAIT_TRANSITION )
1269 end
1370 end
1471end
0 commit comments