From 2228f6787cde3096273ae9d5f5da7e1cc8720fea Mon Sep 17 00:00:00 2001 From: Kevin Schaaf Date: Thu, 14 Mar 2019 15:45:53 -0700 Subject: [PATCH] Sync with fixes on master branch. --- lib/utils/debounce.html | 9 ++-- test/unit/debounce.html | 117 +++++++++++++++++++++++++++------------- 2 files changed, 85 insertions(+), 41 deletions(-) diff --git a/lib/utils/debounce.html b/lib/utils/debounce.html index 5b9e4d2a82..5290285e3b 100644 --- a/lib/utils/debounce.html +++ b/lib/utils/debounce.html @@ -39,8 +39,8 @@ this._callback = callback; this._timer = this._asyncModule.run(() => { this._timer = null; - this._callback(); debouncerQueue.delete(this); + this._callback(); }); } /** @@ -51,7 +51,6 @@ cancel() { if (this.isActive()) { this._cancelAsync(); - this._timer = null; // Canceling a debouncer removes its spot from the flush queue, // so if a debouncer is manually canceled and re-debounced, it // will reset its flush order (this is a very minor difference from 1.x) @@ -65,7 +64,10 @@ * @return {void} */ _cancelAsync() { - this._asyncModule.cancel(/** @type {number} */(this._timer)); + if (this.isActive()) { + this._asyncModule.cancel(/** @type {number} */(this._timer)); + this._timer = null; + } } /** * Flushes an active debouncer and returns a reference to itself. @@ -158,7 +160,6 @@ }); } }); - debouncerQueue = new Set(); return didFlush; }; diff --git a/test/unit/debounce.html b/test/unit/debounce.html index b380a62185..c9fb0195ea 100644 --- a/test/unit/debounce.html +++ b/test/unit/debounce.html @@ -34,6 +34,86 @@ Polymer({is: 'x-basic'}); }); + suite('enqueueDebouncer & flush', function() { + + // NOTE: This is a regression test; the bug it fixed only occurred if the + // debouncer was flushed before any microtasks run, hence it should be + // first in this file + test('re-enqueue canceled debouncer', function() { + const cb = sinon.spy(); + let db; + db = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb); + Polymer.enqueueDebouncer(db); + db.cancel(); + assert.equal(db.isActive(), false); + assert.equal(cb.callCount, 0); + db = Polymer.Debouncer.debounce(db, Polymer.Async.microTask, cb); + Polymer.enqueueDebouncer(db); + Polymer.flush(); + assert.isTrue(cb.calledOnce); + }); + + test('flushDebouncers from enqueued debouncer', function(done) { + const cb = sinon.spy(() => Polymer.flush()); + let db = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb); + Polymer.enqueueDebouncer(db); + setTimeout(() => { + assert.isTrue(cb.calledOnce); + done(); + }); + }); + + const testEnqueue = (shouldFlush, done) => { + const actualOrder = []; + const enqueue = (type, {db, cb} = {}) => { + cb = cb || (() => actualOrder.push(cb)); + db = Polymer.Debouncer.debounce(db, type, cb); + Polymer.enqueueDebouncer(db); + return {db, cb}; + }; + const db1 = enqueue(Polymer.Async.microTask); + const db2 = enqueue(Polymer.Async.microTask); + const db3 = enqueue(Polymer.Async.timeOut); + const db4 = enqueue(Polymer.Async.microTask); + enqueue(Polymer.Async.microTask, db2); + enqueue(Polymer.Async.microTask, db1); + if (shouldFlush) { + Polymer.flush(); + assert.deepEqual(actualOrder, [db1.cb, db2.cb, db3.cb, db4.cb]); + done(); + } else { + Polymer.Async.timeOut.run(() => { + assert.deepEqual(actualOrder, [db4.cb, db2.cb, db1.cb, db3.cb]); + done(); + }); + } + }; + + test('non-flushed', function(done) { + testEnqueue(false, done); + }); + + test('flushed', function(done) { + testEnqueue(true, done); + }); + + test('reentrant flush', function() { + const cb2 = sinon.spy(); + let db2; + const cb1 = sinon.spy(() => { + Polymer.flush(); + db2 = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb2); + Polymer.enqueueDebouncer(db2); + }); + const db1 = Polymer.Debouncer.debounce(null, Polymer.Async.microTask, cb1); + Polymer.enqueueDebouncer(db1); + Polymer.flush(); + assert.isTrue(cb1.calledOnce); + assert.isTrue(cb2.calledOnce); + }); + + }); + suite('debounce', function() { var element; @@ -208,43 +288,6 @@ }); }); - }); - - suite('enqueueDebouncer & flush', function() { - - const testEnqueue = (shouldFlush, done) => { - const actualOrder = []; - const enqueue = (type, {db, cb} = {}) => { - cb = cb || (() => actualOrder.push(cb)); - db = Polymer.Debouncer.debounce(db, type, cb); - Polymer.enqueueDebouncer(db); - return {db, cb}; - }; - const db1 = enqueue(Polymer.Async.microTask); - const db2 = enqueue(Polymer.Async.microTask); - const db3 = enqueue(Polymer.Async.timeOut); - const db4 = enqueue(Polymer.Async.microTask); - enqueue(Polymer.Async.microTask, db2); - enqueue(Polymer.Async.microTask, db1); - if (shouldFlush) { - Polymer.flush(); - assert.deepEqual(actualOrder, [db1.cb, db2.cb, db3.cb, db4.cb]); - done(); - } else { - Polymer.Async.timeOut.run(() => { - assert.deepEqual(actualOrder, [db4.cb, db2.cb, db1.cb, db3.cb]); - done(); - }); - } - }; - - test('non-flushed', function(done) { - testEnqueue(false, done); - }); - - test('flushed', function(done) { - testEnqueue(true, done); - }); });