| 'use strict'; |
| |
| /** |
| ResizeTestHelper is a framework to test ResizeObserver |
| notifications. Use it to make assertions about ResizeObserverEntries. |
| This framework is needed because ResizeObservations are |
| delivered asynchronously inside the event loop. |
| |
| Features: |
| - can queue multiple notification steps in a test |
| - handles timeouts |
| - returns Promise that is fullfilled when test completes. |
| Use to chain tests (since parallel async ResizeObserver tests |
| would conflict if reusing same DOM elements). |
| |
| Usage: |
| |
| create ResizeTestHelper for every test. |
| Make assertions inside notify, timeout callbacks. |
| Start tests with helper.start() |
| Chain tests with Promises. |
| Counts animation frames, see startCountingRaf |
| */ |
| |
| /* |
| @param name: test name |
| @param steps: |
| { |
| setup: function(ResizeObserver) { |
| // called at the beginning of the test step |
| // your observe/resize code goes here |
| }, |
| notify: function(entries, observer) { |
| // ResizeObserver callback. |
| // Make assertions here. |
| // Return true if next step should start on the next event loop. |
| }, |
| timeout: function() { |
| // Define this if your test expects to time out. |
| // If undefined, timeout is assert_unreached. |
| } |
| } |
| */ |
| function ResizeTestHelper(name, steps) |
| { |
| this._name = name; |
| this._steps = steps || []; |
| this._stepIdx = -1; |
| this._harnessTest = null; |
| this._observer = new ResizeObserver(this._handleNotification.bind(this)); |
| this._timeoutBind = this._handleTimeout.bind(this); |
| this._nextStepBind = this._nextStep.bind(this); |
| } |
| |
| ResizeTestHelper.TIMEOUT = 500; |
| |
| ResizeTestHelper.prototype = { |
| get _currentStep() { |
| return this._steps[this._stepIdx]; |
| }, |
| |
| _nextStep: function() { |
| if (++this._stepIdx == this._steps.length) |
| return this._done(); |
| this._timeoutId = this._harnessTest.step_timeout( |
| this._timeoutBind, ResizeTestHelper.TIMEOUT); |
| try { |
| this._steps[this._stepIdx].setup(this._observer); |
| } |
| catch(err) { |
| this._harnessTest.step(() => { |
| assert_unreached("Caught a throw, possible syntax error"); |
| }); |
| } |
| }, |
| |
| _handleNotification: function(entries) { |
| if (this._timeoutId) { |
| window.clearTimeout(this._timeoutId); |
| delete this._timeoutId; |
| } |
| this._harnessTest.step(() => { |
| let rafDelay = this._currentStep.notify(entries, this._observer); |
| if (rafDelay) |
| window.requestAnimationFrame(this._nextStepBind); |
| else |
| this._nextStep(); |
| }); |
| }, |
| |
| _handleTimeout: function() { |
| delete this._timeoutId; |
| this._harnessTest.step(() => { |
| if (this._currentStep.timeout) { |
| this._currentStep.timeout(); |
| } |
| else { |
| assert_unreached("Timed out waiting for notification. (" + ResizeTestHelper.TIMEOUT + "ms)"); |
| } |
| this._nextStep(); |
| }); |
| }, |
| |
| _done: function() { |
| this._observer.disconnect(); |
| delete this._observer; |
| this._harnessTest.done(); |
| if (this._rafCountRequest) { |
| window.cancelAnimationFrame(this._rafCountRequest); |
| delete this._rafCountRequest; |
| } |
| window.requestAnimationFrame(() => { this._resolvePromise(); }); |
| }, |
| |
| start: function() { |
| this._harnessTest = async_test(this._name); |
| this._harnessTest.step(() => { |
| assert_equals(this._stepIdx, -1, "start can only be called once"); |
| this._nextStep(); |
| }); |
| return new Promise( (resolve, reject) => { |
| this._resolvePromise = resolve; |
| this._rejectPromise = reject; |
| }); |
| }, |
| |
| get rafCount() { |
| if (!this._rafCountRequest) |
| throw "rAF count is not active"; |
| return this._rafCount; |
| }, |
| |
| _incrementRaf: function() { |
| if (this._rafCountRequest) { |
| this._rafCount++; |
| this._rafCountRequest = window.requestAnimationFrame(this._incrementRafBind); |
| } |
| }, |
| |
| startCountingRaf: function() { |
| if (this._rafCountRequest) |
| window.cancelAnimationFrame(this._rafCountRequest); |
| if (!this._incrementRafBind) |
| this._incrementRafBind = this._incrementRaf.bind(this); |
| this._rafCount = 0; |
| this._rafCountRequest = window.requestAnimationFrame(this._incrementRafBind); |
| } |
| } |