eventloop.html (7431B)
1 <!doctype html> 2 <title>ResizeObserver notification event loop tests</title> 3 <script src="/resources/testharness.js"></script> 4 <script src="/resources/testharnessreport.js"></script> 5 <script src="./resources/resizeTestHelper.js"></script> 6 <div id="log"></div> 7 <script> 8 'use strict'; 9 10 // allow uncaught exception because ResizeObserver posts exceptions 11 // to window error handler when limit is exceeded. 12 // This codepath is tested in this file. 13 14 setup({allow_uncaught_exception: true}); 15 16 function template() { 17 let helper = new ResizeTestHelper( 18 "test0: title", 19 [ 20 { 21 setup: observer => { 22 }, 23 notify: (entries, observer) => { 24 return true; // Delay next step 25 } 26 } 27 ]); 28 return helper.start(); 29 } 30 31 var onErrorCalled = false; 32 33 window.onerror = err => { 34 onErrorCalled = true; 35 } 36 37 function test0() { 38 let t1 = createAndAppendElement("div"); 39 let t2 = createAndAppendElement("div", t1); 40 let t3 = createAndAppendElement("div", t2); 41 42 let divs = [t1, t2, t3]; 43 let rAF = 0; 44 let helper = new ResizeTestHelper( 45 "test0: multiple notifications inside same event loop", 46 [ 47 { 48 setup: observer => { 49 onErrorCalled = false; 50 observer.observe(t1); 51 observer.observe(t2); 52 observer.observe(t3); 53 }, 54 notify: (entries, observer) => { 55 assert_equals(entries.length, 3, "3 notifications"); 56 } 57 }, 58 { 59 setup: observer => { 60 helper.startCountingRaf(); 61 divs.forEach( el => { el.style.width = "101px";}); 62 }, 63 notify: (entries, observer) => { 64 // t1 is not delivered 65 assert_equals(entries.length, 2, "2 notifications"); 66 assert_equals(helper.rafCount, 0, "still in same loop"); 67 } 68 }, 69 { 70 setup: observer => { 71 divs.forEach( el => { el.style.width = "102px";}); 72 }, 73 notify: (entries, observer) => { 74 assert_equals(entries.length, 1, "1 notifications"); 75 assert_equals(helper.rafCount, 0, "same loop"); 76 } 77 }, 78 { // t1 and t2 get notified 79 setup: observer => { 80 }, 81 notify: (entries, observer) => { 82 assert_equals(entries.length, 2, "2 notifications"); 83 assert_equals(helper.rafCount, 1, "new loop"); 84 assert_equals(onErrorCalled, true, "error was fired"); 85 observer.disconnect(); 86 } 87 } 88 ]); 89 90 return new Promise((resolve, reject) => { 91 // This test uses requestAnimationFrame() to check the count of event loop, 92 // but on some browsers, the FrameRequestCallback may be throttled (i.e. 93 // simply fired after some extra time) in cases where this test is running 94 // in an iframe that hasn't yet been painted (i.e. we're not visible). 95 // This may result in some intermittent failures if this test didn't get a 96 // first paint (and hence may not have started firing FrameRequestCallbacks) 97 // by the time the test starts expecting helper.rafCount to have changed. 98 // 99 // Therefore, we don't start the test logic until body.onload has fired. 100 // This increases the likelihood that this testcase will have gotten a 101 // chance to paint when we start invoking requestAnimationFrame, and that 102 // its rAF callbacks will fire when the test logic expects them to. 103 document.body.onload = () => resolve(); 104 }).then(() => { 105 return helper.start(() => t1.remove()); 106 }); 107 } 108 109 function test1() { 110 let t1 = createAndAppendElement("div"); 111 t1.style.width = '100px'; 112 let t2 = createAndAppendElement("div", t1); 113 let t3 = createAndAppendElement("div", t2); 114 let shadow = t3.attachShadow({ mode: "open" }); 115 let t4 = createAndAppendElement("div", shadow); 116 let t5 = createAndAppendElement("div", t4); 117 118 let resizers = [t1, t2, t3, t4, t5]; 119 120 // Testing depths of shadow roots 121 // DOM: t1 <- t2 <- t3 <-shadow- t4 <- t5 122 let helper = new ResizeTestHelper( 123 "test1: depths of shadow roots", 124 [ 125 { 126 setup: observer => { 127 onErrorCalled = false; 128 resizers.forEach( el => observer.observe(el) ); 129 }, 130 notify: (entries, observer) => { 131 assert_equals(entries.length, 5, "all entries resized"); 132 } 133 }, 134 { 135 setup: observer => { 136 resizers.forEach( el => el.style.width = "111px" ); 137 }, 138 notify: (entries, observer) => { 139 assert_equals(entries.length, 4, "depth limited"); 140 } 141 }, 142 { 143 setup: observer => { 144 resizers.forEach( el => el.style.width = "112px" ); 145 }, 146 notify: (entries, observer) => { 147 assert_equals(entries.length, 3, "depth limited"); 148 } 149 }, 150 { 151 setup: observer => { 152 resizers.forEach( el => el.style.width = "113px" ); 153 }, 154 notify: (entries, observer) => { 155 assert_equals(entries.length, 2, "depth limited"); 156 } 157 }, 158 { 159 setup: observer => { 160 resizers.forEach( el => el.style.width = "114px" ); 161 }, 162 notify: (entries, observer) => { 163 assert_equals(entries.length, 1, "depth limited"); 164 } 165 }, 166 { 167 setup: observer => { 168 }, 169 notify: (entries, observer) => { 170 assert_equals(entries.length, 4, "limit notifications"); 171 assert_equals(onErrorCalled, true, "breached limit"); 172 observer.disconnect(); 173 } 174 }, 175 ]); 176 return helper.start(() => t1.remove()); 177 } 178 179 function test2() { 180 // <div id="container"> 181 // <div id="a1" style="width:100px;height:100px"> 182 // <div id="a2" style="width:100px;height:100px"></div> 183 // </div> 184 // <div id="b1" style="width:100px;height:100px"> 185 // <div id="b2" style="width:100px;height:100px"></div> 186 // </div> 187 // </div> 188 let container = createAndAppendElement("div"); 189 let a1 = createAndAppendElement("div", container); 190 let a2 = createAndAppendElement("div", a1); 191 let b1 = createAndAppendElement("div", container); 192 let b2 = createAndAppendElement("div", b1); 193 let targets = [a1, a2, b1, b2]; 194 195 let helper = new ResizeTestHelper( 196 "test2: move target in dom while inside event loop", 197 [ 198 { 199 setup: observer => { 200 for (let t of targets) 201 observer.observe(t); 202 }, 203 notify: (entries, observer) => { 204 return true; // delay next observation 205 } 206 }, 207 { // resize them all 208 setup: observer => { 209 for (let t of targets) 210 t.style.width = "110px"; 211 }, 212 notify: (entries, observer) => { 213 assert_equals(entries.length, targets.length, "all targets observed"); 214 } 215 }, 216 { // resize all, move dom upwards 217 setup: observer => { 218 for (let t of targets) 219 t.style.width = "130px"; 220 container.appendChild(b2); 221 }, 222 notify: (entries, observer) => { 223 assert_equals(entries.length, 1, "b2 moved upwards"); 224 assert_equals(entries[0].target, a2); 225 } 226 }, 227 { // resize all, move dom downwards 228 setup: observer => { 229 for (let t of targets) 230 t.style.width = "130px"; 231 a2.appendChild(b2); 232 }, 233 notify: (entries, observer) => { 234 assert_equals(entries.length, 1, "b2 moved downwards"); 235 assert_equals(entries[0].target, b2); 236 } 237 }, 238 ]); 239 return helper.start(() => container.remove()); 240 } 241 242 let guard; 243 test(_ => { 244 assert_own_property(window, "ResizeObserver"); 245 guard = async_test('guard'); 246 }, "ResizeObserver implemented") 247 248 test0() 249 .then(() => test1()) 250 .then(() => test2()) 251 .then(() => guard.done()); 252 253 </script>