From eccda41fe0356cf8121c408bfb4768d3333e1ff1 Mon Sep 17 00:00:00 2001 From: joelamb <42837452+joelamb@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:00:21 +0100 Subject: [PATCH 1/3] fix: column resize preferences save the queueUpdate was uses requestFrameAnimation to schedule the calls to the resize columns function. To ensure that the call to save preferences is called after the resize the queueUpdate now takes an optional callback function that is called after the resize. This ensures that these pseudo-async events are always performed in a predictable and correct sequence. --- .../src/plugins/column-resizing/handle.ts | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/ember-headless-table/src/plugins/column-resizing/handle.ts b/ember-headless-table/src/plugins/column-resizing/handle.ts index db75eca2..b41d20ea 100644 --- a/ember-headless-table/src/plugins/column-resizing/handle.ts +++ b/ember-headless-table/src/plugins/column-resizing/handle.ts @@ -111,24 +111,41 @@ class ResizeHandle extends Modifier<{ Args: { Positional: [Column] } }> { } }; - queueUpdate = () => { - cancelAnimationFrame(this.dragFrame); + /** + * queueUpdate takes an optional function argument that is called + * in the requestAnimationFrame callback _after_ the resize function. + * + * We can use this to ensure that preferences are only ever saved after + * we have completed column resizing. + * + * Because the requestAnimationFrame 'hides' these function calls from the + * the ember test waiter, we also ensure that we track them by also cancelling + * the waiter in the requestAnimationFrame callback. + */ + queueUpdate = (callback?: () => void) => { + if (this.dragFrame) { + cancelAnimationFrame(this.dragFrame); + } + this.dragFrame = requestAnimationFrame(() => { this.meta.resize(this.pointerX - this.pointerStartX); this.pointerStartX = this.pointerX; + + if (callback) { + callback(); + } + + if (this.token) { + waiter.endAsync(this.token); + this.token = undefined; + } }); }; dragEndHandler = () => { this.meta.isResizing = false; - this.queueUpdate(); - - if (this.token) { - waiter.endAsync(this.token); - this.token = undefined; - } - this.meta.save(); + this.queueUpdate(this.meta.save); /** * No need to listen if we aren't dragging From e45589135359f0fe7be9d373c6838b56f732dcc1 Mon Sep 17 00:00:00 2001 From: joelamb <42837452+joelamb@users.noreply.github.com> Date: Tue, 19 Sep 2023 14:03:12 +0100 Subject: [PATCH 2/3] test: update test and test helpers Test helpers simplified since we now handle test waiting in the queueUpdate function of the resize handle. Column resizing test updated to affect multiple columns and more explicitly check the width of the adjusted columns, not just verify the delta. --- .../src/test-support/index.ts | 9 ----- .../column-resizing/rendering-test.gts | 33 ++++++++++--------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/ember-headless-table/src/test-support/index.ts b/ember-headless-table/src/test-support/index.ts index 6f23b350..cdf21d6d 100644 --- a/ember-headless-table/src/test-support/index.ts +++ b/ember-headless-table/src/test-support/index.ts @@ -28,18 +28,9 @@ export function createHelpers(selectors: Selectors) { triggerEvent(element, 'mousedown', { clientX: startX, button: 0 }); triggerEvent(element, 'mousemove', { clientX: targetX, button: 0 }); - - await new Promise((resolve) => setTimeout(resolve, 50)); - triggerEvent(element, 'mouseup', { clientX: targetX, button: 0 }); await settled(); - - /** - * This has been super finnicky... :( - */ - await new Promise((resolve) => setTimeout(resolve, 100)); - await requestAnimationFrameSettled(); } function horizontalScrollElement() { diff --git a/test-app/tests/plugins/column-resizing/rendering-test.gts b/test-app/tests/plugins/column-resizing/rendering-test.gts index d4ed9e95..67459404 100644 --- a/test-app/tests/plugins/column-resizing/rendering-test.gts +++ b/test-app/tests/plugins/column-resizing/rendering-test.gts @@ -297,9 +297,7 @@ module('Plugins | resizing', function (hooks) { }, 'All column preferences reset'); }); - test('it resizes each column', async function (assert) { - // Columns are set to equal widths so each of the four columns - // will initially be 250px wide in the 1000px wide container + test('it resizes each column and persists the new widths in the preferences', async function (assert) { ctx.setContainerWidth(1000); await render(