From eded8e7ac5ab4456bb49418cd78dfa69f854e7f1 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Thu, 13 Jan 2022 10:23:24 -0500 Subject: [PATCH 01/39] feat: add `start` and `end` hooks to `fireEvent` helper --- .../@ember/test-helpers/dom/fire-event.ts | 106 ++++++++++-------- tests/unit/dom/fire-event-test.js | 64 +++++++++++ 2 files changed, 125 insertions(+), 45 deletions(-) create mode 100644 tests/unit/dom/fire-event-test.js diff --git a/addon-test-support/@ember/test-helpers/dom/fire-event.ts b/addon-test-support/@ember/test-helpers/dom/fire-event.ts index 5728c9c8d..2b0efa51a 100644 --- a/addon-test-support/@ember/test-helpers/dom/fire-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/fire-event.ts @@ -1,5 +1,13 @@ import { isDocument, isElement } from './-target'; import tuple from '../-tuple'; +import Target from './-target'; +import { log } from '@ember/test-helpers/dom/-logging'; +import { runHooks, registerHook } from '../-internal/helper-hooks'; +import settled from '../settled'; + +registerHook('fireEvent', 'start', (target: Target) => { + log('fireEvent', target); +}); // eslint-disable-next-line require-jsdoc const MOUSE_EVENT_CONSTRUCTOR = (() => { @@ -61,19 +69,19 @@ function fireEvent( element: Element | Document | Window, eventType: KeyboardEventType, options?: any -): Event; +): Promise; function fireEvent( element: Element | Document | Window, eventType: MouseEventType, options?: any -): Event | void; +): Promise; function fireEvent( element: Element | Document | Window, eventType: string, options?: any -): Event; +): Promise; /** Internal helper used to build and dispatch events throughout the other DOM helpers. @@ -88,48 +96,56 @@ function fireEvent( element: Element | Document | Window, eventType: string, options = {} -): Event | void { - if (!element) { - throw new Error('Must pass an element to `fireEvent`'); - } - - let event; - if (isKeyboardEventType(eventType)) { - event = _buildKeyboardEvent(eventType, options); - } else if (isMouseEventType(eventType)) { - let rect; - if (element instanceof Window && element.document.documentElement) { - rect = element.document.documentElement.getBoundingClientRect(); - } else if (isDocument(element)) { - rect = element.documentElement!.getBoundingClientRect(); - } else if (isElement(element)) { - rect = element.getBoundingClientRect(); - } else { - return; - } - - let x = rect.left + 1; - let y = rect.top + 1; - let simulatedCoordinates = { - screenX: x + 5, // Those numbers don't really mean anything. - screenY: y + 95, // They're just to make the screenX/Y be different of clientX/Y.. - clientX: x, - clientY: y, - ...options, - }; - - event = buildMouseEvent(eventType, simulatedCoordinates); - } else if ( - isFileSelectionEventType(eventType) && - isFileSelectionInput(element) - ) { - event = buildFileEvent(eventType, element, options); - } else { - event = buildBasicEvent(eventType, options); - } - - element.dispatchEvent(event); - return event; +): Promise { + return Promise.resolve() + .then(() => runHooks(`fireEvent:${eventType}`, 'start', element)) + .then(() => { + if (!element) { + throw new Error('Must pass an element to `fireEvent`'); + } + + let event; + if (isKeyboardEventType(eventType)) { + event = _buildKeyboardEvent(eventType, options); + } else if (isMouseEventType(eventType)) { + let rect; + if (element instanceof Window && element.document.documentElement) { + rect = element.document.documentElement.getBoundingClientRect(); + } else if (isDocument(element)) { + rect = element.documentElement!.getBoundingClientRect(); + } else if (isElement(element)) { + rect = element.getBoundingClientRect(); + } else { + return; + } + + let x = rect.left + 1; + let y = rect.top + 1; + let simulatedCoordinates = { + screenX: x + 5, // Those numbers don't really mean anything. + screenY: y + 95, // They're just to make the screenX/Y be different of clientX/Y.. + clientX: x, + clientY: y, + ...options, + }; + + event = buildMouseEvent(eventType, simulatedCoordinates); + } else if ( + isFileSelectionEventType(eventType) && + isFileSelectionInput(element) + ) { + event = buildFileEvent(eventType, element, options); + } else { + event = buildBasicEvent(eventType, options); + } + + element.dispatchEvent(event); + return event; + }) + .then((event) => settled().then(() => event)) + .then((event) => + runHooks(`fireEvent:${eventType}`, 'end', element).then(() => event) + ); } export default fireEvent; diff --git a/tests/unit/dom/fire-event-test.js b/tests/unit/dom/fire-event-test.js new file mode 100644 index 000000000..8ec16d1ba --- /dev/null +++ b/tests/unit/dom/fire-event-test.js @@ -0,0 +1,64 @@ +import { module, test } from 'qunit'; +import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { + render, + find, + click, + tap, + focus, + settled, + setupContext, + setupRenderingContext, + teardownContext, + _registerHook, +} from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('DOM Helper: fireEvent', function (hooks) { + if (!hasEmberVersion(2, 4)) { + return; + } + + hooks.beforeEach(async function () { + await setupContext(this); + await setupRenderingContext(this); + }); + + hooks.afterEach(async function () { + await settled(); + await teardownContext(this); + }); + + const SIMPLE_ACTION_HELPER_FUNCS = [click, tap, focus]; + + SIMPLE_ACTION_HELPER_FUNCS.forEach((helperFn) => { + test(`it executes registered fireEvent hooks for "${helperFn.name}" helper`, async function (assert) { + await render(hbs``); + + const element = find('input'); + + const startHook = _registerHook( + `fireEvent:${helperFn.name}`, + 'start', + () => { + assert.step(`fireEvent:${helperFn.name}:start`); + } + ); + const endHook = _registerHook(`fireEvent:${helperFn.name}`, 'end', () => { + assert.step(`fireEvent:${helperFn.name}:end`); + }); + + try { + await helperFn(element); + + assert.verifySteps([ + `fireEvent:${helperFn.name}:start`, + `fireEvent:${helperFn.name}:end`, + ]); + } finally { + startHook.unregister(); + endHook.unregister(); + } + }); + }); +}); From 5b2c2aea7d003e4d45b823e66d3111bf2913076a Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Thu, 13 Jan 2022 12:55:16 -0500 Subject: [PATCH 02/39] refactor: migrate blur, click, focus, tap to fire async events --- .../@ember/test-helpers/dom/blur.ts | 19 +-- .../@ember/test-helpers/dom/click.ts | 25 ++-- .../@ember/test-helpers/dom/fire-event.ts | 2 + .../@ember/test-helpers/dom/focus.ts | 106 +++++++++------- .../@ember/test-helpers/dom/tap.ts | 25 ++-- tests/unit/dom/fire-event-test.js | 118 +++++++++++++----- 6 files changed, 188 insertions(+), 107 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/blur.ts b/addon-test-support/@ember/test-helpers/dom/blur.ts index c85ae4dfd..260b708cd 100644 --- a/addon-test-support/@ember/test-helpers/dom/blur.ts +++ b/addon-test-support/@ember/test-helpers/dom/blur.ts @@ -15,11 +15,12 @@ registerHook('blur', 'start', (target: Target) => { @private @param {Element} element the element to trigger events on @param {Element} relatedTarget the element that is focused after blur + @return {Promise} resolves when settled */ export function __blur__( element: HTMLElement | Element | Document | SVGElement, relatedTarget: HTMLElement | Element | Document | SVGElement | null = null -): void { +): Promise { if (!isFocusable(element)) { throw new Error(`${element} is not focusable`); } @@ -36,11 +37,13 @@ export function __blur__( // Chrome/Firefox does not trigger the `blur` event if the window // does not have focus. If the document does not have focus then // fire `blur` event via native event. - if (browserIsNotFocused || needsCustomEventOptions) { - let options = { relatedTarget }; - fireEvent(element, 'blur', { bubbles: false, ...options }); - fireEvent(element, 'focusout', options); - } + let options = { relatedTarget }; + return browserIsNotFocused || needsCustomEventOptions + ? Promise.resolve() + .then(() => fireEvent(element, 'blur', { bubbles: false, ...options })) + .then(() => fireEvent(element, 'focusout', options)) + .then(() => settled()) + : Promise.resolve(); } /** @@ -81,9 +84,7 @@ export default function blur( ); } - __blur__(element); - - return settled(); + return __blur__(element); }) .then(() => runHooks('blur', 'end', target)); } diff --git a/addon-test-support/@ember/test-helpers/dom/click.ts b/addon-test-support/@ember/test-helpers/dom/click.ts index ba506e155..77b8436b5 100644 --- a/addon-test-support/@ember/test-helpers/dom/click.ts +++ b/addon-test-support/@ember/test-helpers/dom/click.ts @@ -1,7 +1,6 @@ import { getWindowOrElement } from './-get-window-or-element'; import fireEvent from './fire-event'; import { __focus__ } from './focus'; -import settled from '../settled'; import { Promise } from '../-utils'; import isFormControl from './-is-form-control'; import Target, { isWindow } from './-target'; @@ -28,19 +27,21 @@ export const DEFAULT_CLICK_OPTIONS = { @private @param {Element} element the element to click on @param {MouseEventInit} options the options to be merged into the mouse events + @return {Promise} resolves when settled */ export function __click__( element: Element | Document | Window, options: MouseEventInit -): void { - let mouseDownEvent = fireEvent(element, 'mousedown', options); - - if (!isWindow(element) && !mouseDownEvent?.defaultPrevented) { - __focus__(element); - } - - fireEvent(element, 'mouseup', options); - fireEvent(element, 'click', options); +): Promise { + return Promise.resolve() + .then(() => fireEvent(element, 'mousedown', options)) + .then((mouseDownEvent) => + !isWindow(element) && !mouseDownEvent?.defaultPrevented + ? __focus__(element) + : Promise.resolve() + ) + .then(() => fireEvent(element, 'mouseup', options)) + .then(() => fireEvent(element, 'click', options)); } /** @@ -112,9 +113,7 @@ export default function click( throw new Error(`Can not \`click\` disabled ${element}`); } - __click__(element, options); - - return settled(); + return __click__(element, options); }) .then(() => runHooks('click', 'end', target, _options)); } diff --git a/addon-test-support/@ember/test-helpers/dom/fire-event.ts b/addon-test-support/@ember/test-helpers/dom/fire-event.ts index 2b0efa51a..6fb6f0f64 100644 --- a/addon-test-support/@ember/test-helpers/dom/fire-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/fire-event.ts @@ -98,6 +98,7 @@ function fireEvent( options = {} ): Promise { return Promise.resolve() + .then(() => runHooks('fireEvent', 'start', element)) .then(() => runHooks(`fireEvent:${eventType}`, 'start', element)) .then(() => { if (!element) { @@ -143,6 +144,7 @@ function fireEvent( return event; }) .then((event) => settled().then(() => event)) + .then((event) => runHooks('fireEvent', 'end', element).then(() => event)) .then((event) => runHooks(`fireEvent:${eventType}`, 'end', element).then(() => event) ); diff --git a/addon-test-support/@ember/test-helpers/dom/focus.ts b/addon-test-support/@ember/test-helpers/dom/focus.ts index ede77df07..121c12398 100644 --- a/addon-test-support/@ember/test-helpers/dom/focus.ts +++ b/addon-test-support/@ember/test-helpers/dom/focus.ts @@ -12,6 +12,11 @@ registerHook('focus', 'start', (target: Target) => { log('focus', target); }); +type FocusRecord = { + focusTarget: HTMLElement | SVGElement; + previousFocusedElement?: HTMLElement | SVGElement | null; +}; + /** Get the closest focusable ancestor of a given element (or the element itself if it's focusable) @@ -39,51 +44,68 @@ function getClosestFocusable( /** @private @param {Element} element the element to trigger events on + @return {Promise} resolves when settled */ export function __focus__( element: HTMLElement | Element | Document | SVGElement -): void { - let focusTarget = getClosestFocusable(element); - - const previousFocusedElement = - document.activeElement && - document.activeElement !== focusTarget && - isFocusable(document.activeElement) - ? document.activeElement - : null; - - // fire __blur__ manually with the null relatedTarget when the target is not focusable - // and there was a previously focused element - if (!focusTarget) { - if (previousFocusedElement) { - __blur__(previousFocusedElement, null); - } - - return; - } - - let browserIsNotFocused = document.hasFocus && !document.hasFocus(); - - // fire __blur__ manually with the correct relatedTarget when the browser is not - // already in focus and there was a previously focused element - if (previousFocusedElement && browserIsNotFocused) { - __blur__(previousFocusedElement, focusTarget); - } - - // makes `document.activeElement` be `element`. If the browser is focused, it also fires a focus event - focusTarget.focus(); +): Promise { + return Promise.resolve() + .then(() => { + let focusTarget = getClosestFocusable(element); + + const previousFocusedElement = + document.activeElement && + document.activeElement !== focusTarget && + isFocusable(document.activeElement) + ? document.activeElement + : null; + + // fire __blur__ manually with the null relatedTarget when the target is not focusable + // and there was a previously focused element + return !focusTarget && previousFocusedElement + ? __blur__(previousFocusedElement, null).then(() => + Promise.resolve({ focusTarget, previousFocusedElement }) + ) + : Promise.resolve({ focusTarget, previousFocusedElement }); + }) + .then(({ focusTarget, previousFocusedElement }) => { + if (!focusTarget) { + throw new Error('There was a previously focused element'); + } - // Firefox does not trigger the `focusin` event if the window - // does not have focus. If the document does not have focus then - // fire `focusin` event as well. - if (browserIsNotFocused) { - // if the browser is not focused the previous `el.focus()` didn't fire an event, so we simulate it - fireEvent(focusTarget, 'focus', { - bubbles: false, - }); + let browserIsNotFocused = !document?.hasFocus(); - fireEvent(focusTarget, 'focusin'); - } + // fire __blur__ manually with the correct relatedTarget when the browser is not + // already in focus and there was a previously focused element + return previousFocusedElement && browserIsNotFocused + ? __blur__(previousFocusedElement, focusTarget).then(() => + Promise.resolve({ focusTarget }) + ) + : Promise.resolve({ focusTarget }); + }) + .then(({ focusTarget }) => { + // makes `document.activeElement` be `element`. If the browser is focused, it also fires a focus event + focusTarget.focus(); + + // Firefox does not trigger the `focusin` event if the window + // does not have focus. If the document does not have focus then + // fire `focusin` event as well. + let browserIsFocused = document?.hasFocus(); + return browserIsFocused + ? Promise.resolve() + : // if the browser is not focused the previous `el.focus()` didn't fire an event, so we simulate it + Promise.resolve() + .then(() => + fireEvent(focusTarget as HTMLElement | SVGElement, 'focus', { + bubbles: false, + }) + ) + .then(() => + fireEvent(focusTarget as HTMLElement | SVGElement, 'focusin') + ) + .then(() => settled()); + }) + .catch(() => {}); } /** @@ -130,9 +152,7 @@ export default function focus(target: Target): Promise { throw new Error(`${element} is not focusable`); } - __focus__(element); - - return settled(); + return __focus__(element); }) .then(() => runHooks('focus', 'end', target)); } diff --git a/addon-test-support/@ember/test-helpers/dom/tap.ts b/addon-test-support/@ember/test-helpers/dom/tap.ts index 4cedbcba5..d072ce597 100644 --- a/addon-test-support/@ember/test-helpers/dom/tap.ts +++ b/addon-test-support/@ember/test-helpers/dom/tap.ts @@ -45,7 +45,7 @@ registerHook('tap', 'start', (target: Target) => { @public @param {string|Element} target the element or selector to tap on @param {Object} options the options to be merged into the touch events - @return {Promise} resolves when settled + @return {Promise} resolves when settled @example @@ -57,7 +57,7 @@ registerHook('tap', 'start', (target: Target) => { export default function tap( target: Target, options: object = {} -): Promise { +): Promise { return Promise.resolve() .then(() => { return runHooks('tap', 'start', target, options); @@ -76,14 +76,19 @@ export default function tap( throw new Error(`Can not \`tap\` disabled ${element}`); } - let touchstartEv = fireEvent(element, 'touchstart', options); - let touchendEv = fireEvent(element, 'touchend', options); - - if (!touchstartEv.defaultPrevented && !touchendEv.defaultPrevented) { - __click__(element, options); - } - - return settled(); + return fireEvent(element, 'touchstart', options); + }) + .then((touchstartEv) => { + let element = getElement(target); + return fireEvent(element as Element, 'touchend', options).then( + (touchendEv) => [touchstartEv, touchendEv] + ); + }) + .then(([touchstartEv, touchendEv]) => { + let element = getElement(target); + return !touchstartEv.defaultPrevented && !touchendEv.defaultPrevented + ? __click__(element as Element, options) + : Promise.resolve(); }) .then(() => { return runHooks('tap', 'end', target, options); diff --git a/tests/unit/dom/fire-event-test.js b/tests/unit/dom/fire-event-test.js index 8ec16d1ba..f012e8ca6 100644 --- a/tests/unit/dom/fire-event-test.js +++ b/tests/unit/dom/fire-event-test.js @@ -5,7 +5,6 @@ import { find, click, tap, - focus, settled, setupContext, setupRenderingContext, @@ -14,6 +13,54 @@ import { } from '@ember/test-helpers'; import { hbs } from 'ember-cli-htmlbars'; +// +// Helpers +// + +/** Register and return mock `fireEvent` hooks */ +const setupMockHooks = (assert, eventTypes) => { + const startHook = _registerHook('fireEvent', 'start', () => { + assert.step(`fireEvent:start`); + }); + const endHook = _registerHook('fireEvent', 'end', () => { + assert.step(`fireEvent:end`); + }); + + const eventSpecificHooks = eventTypes.flatMap((eventType) => [ + _registerHook(`fireEvent:${eventType}`, 'start', () => { + assert.step(`fireEvent:${eventType}:start`); + }), + _registerHook(`fireEvent:${eventType}`, 'end', () => { + assert.step(`fireEvent:${eventType}:end`); + }), + ]); + + return [startHook, endHook, ...eventSpecificHooks]; +}; + +/** Unregister mock hooks */ +const unregisterMockHooks = (mockHooks) => { + mockHooks.forEach((mockHook) => mockHook.unregister()); +}; + +/** + * Build list of expected `fireEvent` steps for verification + * + * @param {string[]} eventTypes List of eventTypes + * @return {string[]} List of expected `fireEvent` steps + */ +const buildExpectedSteps = (eventTypes) => + eventTypes.flatMap((eventType) => [ + 'fireEvent:start', + `fireEvent:${eventType}:start`, + `fireEvent:end`, + `fireEvent:${eventType}:end`, + ]); + +// +// Tests +// + module('DOM Helper: fireEvent', function (hooks) { if (!hasEmberVersion(2, 4)) { return; @@ -29,36 +76,43 @@ module('DOM Helper: fireEvent', function (hooks) { await teardownContext(this); }); - const SIMPLE_ACTION_HELPER_FUNCS = [click, tap, focus]; - - SIMPLE_ACTION_HELPER_FUNCS.forEach((helperFn) => { - test(`it executes registered fireEvent hooks for "${helperFn.name}" helper`, async function (assert) { - await render(hbs``); - - const element = find('input'); - - const startHook = _registerHook( - `fireEvent:${helperFn.name}`, - 'start', - () => { - assert.step(`fireEvent:${helperFn.name}:start`); - } - ); - const endHook = _registerHook(`fireEvent:${helperFn.name}`, 'end', () => { - assert.step(`fireEvent:${helperFn.name}:end`); - }); - - try { - await helperFn(element); - - assert.verifySteps([ - `fireEvent:${helperFn.name}:start`, - `fireEvent:${helperFn.name}:end`, - ]); - } finally { - startHook.unregister(); - endHook.unregister(); - } - }); + test(`it executes registered fireEvent hooks for "click" helper`, async function (assert) { + await render(hbs``); + + const eventTypes = ['mousedown', 'mouseup', 'click']; + const mockHooks = setupMockHooks(assert, eventTypes); + + try { + const element = find('button'); + await click(element); + + const expectedSteps = buildExpectedSteps(eventTypes); + assert.verifySteps(expectedSteps); + } finally { + unregisterMockHooks(mockHooks); + } + }); + + test(`it executes registered fireEvent hooks for "tap" helper`, async function (assert) { + await render(hbs``); + + const eventTypes = [ + 'touchstart', + 'touchend', + 'mousedown', + 'mouseup', + 'click', + ]; + const mockHooks = setupMockHooks(assert, eventTypes); + + try { + const element = find('button'); + await tap(element); + + const expectedSteps = buildExpectedSteps(eventTypes); + assert.verifySteps(expectedSteps); + } finally { + unregisterMockHooks(mockHooks); + } }); }); From 1b890950570df72471c554eb9522ee9e6fb2eb27 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Thu, 13 Jan 2022 13:58:55 -0500 Subject: [PATCH 03/39] refactor: migrate fillIn, typeIn to fire async events --- .../@ember/test-helpers/dom/fill-in.ts | 6 +- .../@ember/test-helpers/dom/fire-event.ts | 5 +- .../test-helpers/dom/trigger-key-event.ts | 57 ++++++++++--------- .../@ember/test-helpers/dom/type-in.ts | 11 ++-- tests/unit/dom/fire-event-test.js | 36 ++++++++++++ 5 files changed, 76 insertions(+), 39 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/fill-in.ts b/addon-test-support/@ember/test-helpers/dom/fill-in.ts index bab2f31d6..e5758702a 100644 --- a/addon-test-support/@ember/test-helpers/dom/fill-in.ts +++ b/addon-test-support/@ember/test-helpers/dom/fill-in.ts @@ -72,10 +72,10 @@ export default function fillIn(target: Target, text: string): Promise { '`fillIn` is only usable on form controls or contenteditable elements.' ); } - fireEvent(element, 'input'); - fireEvent(element, 'change'); - return settled(); + return fireEvent(element, 'input').then(() => + fireEvent(element, 'change') + ); }) .then(() => runHooks('fillIn', 'end', target, text)); } diff --git a/addon-test-support/@ember/test-helpers/dom/fire-event.ts b/addon-test-support/@ember/test-helpers/dom/fire-event.ts index 6fb6f0f64..03ccd4c85 100644 --- a/addon-test-support/@ember/test-helpers/dom/fire-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/fire-event.ts @@ -98,7 +98,9 @@ function fireEvent( options = {} ): Promise { return Promise.resolve() - .then(() => runHooks('fireEvent', 'start', element)) + .then(() => { + return runHooks('fireEvent', 'start', element); + }) .then(() => runHooks(`fireEvent:${eventType}`, 'start', element)) .then(() => { if (!element) { @@ -143,7 +145,6 @@ function fireEvent( element.dispatchEvent(event); return event; }) - .then((event) => settled().then(() => event)) .then((event) => runHooks('fireEvent', 'end', element).then(() => event)) .then((event) => runHooks(`fireEvent:${eventType}`, 'end', element).then(() => event) diff --git a/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts b/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts index 8e1943916..661fac457 100644 --- a/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts @@ -140,44 +140,47 @@ function keyCodeFromKey(key: string) { @param {'keydown' | 'keyup' | 'keypress'} eventType the type of event to trigger @param {number|string} key the `keyCode`(number) or `key`(string) of the event being triggered @param {Object} [modifiers] the state of various modifier keys + @return {Promise} resolves when settled */ export function __triggerKeyEvent__( element: Element | Document, eventType: KeyboardEventType, key: number | string, modifiers: KeyModifiers = DEFAULT_MODIFIERS -) { - let props; - if (typeof key === 'number') { - props = { - keyCode: key, - which: key, - key: keyFromKeyCodeAndModifiers(key, modifiers), - ...modifiers, - }; - } else if (typeof key === 'string' && key.length !== 0) { - let firstCharacter = key[0]; - if (firstCharacter !== firstCharacter.toUpperCase()) { - throw new Error( - `Must provide a \`key\` to \`triggerKeyEvent\` that starts with an uppercase character but you passed \`${key}\`.` - ); - } +): Promise { + return Promise.resolve().then(() => { + let props; + if (typeof key === 'number') { + props = { + keyCode: key, + which: key, + key: keyFromKeyCodeAndModifiers(key, modifiers), + ...modifiers, + }; + } else if (typeof key === 'string' && key.length !== 0) { + let firstCharacter = key[0]; + if (firstCharacter !== firstCharacter.toUpperCase()) { + throw new Error( + `Must provide a \`key\` to \`triggerKeyEvent\` that starts with an uppercase character but you passed \`${key}\`.` + ); + } + + if (isNumeric(key) && key.length > 1) { + throw new Error( + `Must provide a numeric \`keyCode\` to \`triggerKeyEvent\` but you passed \`${key}\` as a string.` + ); + } - if (isNumeric(key) && key.length > 1) { + let keyCode = keyCodeFromKey(key); + props = { keyCode, which: keyCode, key, ...modifiers }; + } else { throw new Error( - `Must provide a numeric \`keyCode\` to \`triggerKeyEvent\` but you passed \`${key}\` as a string.` + `Must provide a \`key\` or \`keyCode\` to \`triggerKeyEvent\`` ); } - let keyCode = keyCodeFromKey(key); - props = { keyCode, which: keyCode, key, ...modifiers }; - } else { - throw new Error( - `Must provide a \`key\` or \`keyCode\` to \`triggerKeyEvent\`` - ); - } - - fireEvent(element, eventType, props); + return fireEvent(element, eventType, props); + }); } /** diff --git a/addon-test-support/@ember/test-helpers/dom/type-in.ts b/addon-test-support/@ember/test-helpers/dom/type-in.ts index 64eaa3410..26873436e 100644 --- a/addon-test-support/@ember/test-helpers/dom/type-in.ts +++ b/addon-test-support/@ember/test-helpers/dom/type-in.ts @@ -91,16 +91,13 @@ export default function typeIn( } } - __focus__(element); - let { delay = 50 } = options; - return fillOut(element, text, delay) + return __focus__(element) + .then(() => fillOut(element, text, delay)) .then(() => fireEvent(element, 'change')) .then(settled) - .then(() => { - return runHooks('typeIn', 'end', target, text, options); - }); + .then(() => runHooks('typeIn', 'end', target, text, options)); }); } @@ -147,7 +144,7 @@ function keyEntry( const newValue = element.innerHTML + character; element.innerHTML = newValue; } - fireEvent(element, 'input'); + return fireEvent(element, 'input'); }) .then(() => __triggerKeyEvent__(element, 'keyup', characterKey, options)); }; diff --git a/tests/unit/dom/fire-event-test.js b/tests/unit/dom/fire-event-test.js index f012e8ca6..d999b1de8 100644 --- a/tests/unit/dom/fire-event-test.js +++ b/tests/unit/dom/fire-event-test.js @@ -4,7 +4,9 @@ import { render, find, click, + fillIn, tap, + typeIn, settled, setupContext, setupRenderingContext, @@ -115,4 +117,38 @@ module('DOM Helper: fireEvent', function (hooks) { unregisterMockHooks(mockHooks); } }); + + test(`it executes registered fireEvent hooks for "fillIn" helper`, async function (assert) { + await render(hbs``); + + const eventTypes = ['input', 'change']; + const mockHooks = setupMockHooks(assert, eventTypes); + + try { + const element = find('input'); + await fillIn(element, 'foo'); + + const expectedSteps = buildExpectedSteps(eventTypes); + assert.verifySteps(expectedSteps); + } finally { + unregisterMockHooks(mockHooks); + } + }); + + test(`it executes registered fireEvent hooks for "typeIn" helper`, async function (assert) { + await render(hbs``); + + const eventTypes = ['keydown', 'keypress', 'input', 'keyup', 'change']; + const mockHooks = setupMockHooks(assert, eventTypes); + + try { + const element = find('input'); + await typeIn(element, 'a'); + + const expectedSteps = buildExpectedSteps(eventTypes); + assert.verifySteps(expectedSteps); + } finally { + unregisterMockHooks(mockHooks); + } + }); }); From 599ae7409eb11f665bb5cb7d37502afcb25b5fad Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 09:01:51 -0500 Subject: [PATCH 04/39] docs: add details to JSDoc --- tests/unit/dom/fire-event-test.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/unit/dom/fire-event-test.js b/tests/unit/dom/fire-event-test.js index d999b1de8..b3a33c439 100644 --- a/tests/unit/dom/fire-event-test.js +++ b/tests/unit/dom/fire-event-test.js @@ -19,7 +19,13 @@ import { hbs } from 'ember-cli-htmlbars'; // Helpers // -/** Register and return mock `fireEvent` hooks */ +/** + * Register and return mock `fireEvent` hooks + * + * @param {Assert} assert Test assertion context + * @param {string[]} eventTypes Event types to register + * @returns {HookUnregister[]} Unregisterable hooks + */ const setupMockHooks = (assert, eventTypes) => { const startHook = _registerHook('fireEvent', 'start', () => { assert.step(`fireEvent:start`); From d488116541ee2167553cd5b4595458cad8baba4d Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 09:25:52 -0500 Subject: [PATCH 05/39] test: move all register hook tests into helper modules --- tests/helpers/register-hooks.js | 57 +++++++++++ tests/unit/dom/click-test.js | 24 +++-- tests/unit/dom/fill-in-test.js | 24 +++-- tests/unit/dom/fire-event-test.js | 160 ------------------------------ tests/unit/dom/tap-test.js | 30 ++++-- tests/unit/dom/type-in-test.js | 28 ++++-- 6 files changed, 137 insertions(+), 186 deletions(-) create mode 100644 tests/helpers/register-hooks.js delete mode 100644 tests/unit/dom/fire-event-test.js diff --git a/tests/helpers/register-hooks.js b/tests/helpers/register-hooks.js new file mode 100644 index 000000000..5bc258b02 --- /dev/null +++ b/tests/helpers/register-hooks.js @@ -0,0 +1,57 @@ +import { _registerHook } from '@ember/test-helpers'; + +/** + * Register mock `fireEvent` hooks for provided event types. + * + * @param {Assert} assert Test assertion context + * @param {string[]} eventTypes Event types to register + * @returns {HookUnregister[]} Unregisterable hooks + */ +export const registerFireEventHooks = (assert, eventTypes) => { + const startHook = _registerHook('fireEvent', 'start', () => { + assert.step(`fireEvent:start`); + }); + const endHook = _registerHook('fireEvent', 'end', () => { + assert.step(`fireEvent:end`); + }); + + const eventSpecificHooks = eventTypes.flatMap((eventType) => [ + _registerHook(`fireEvent:${eventType}`, 'start', () => { + assert.step(`fireEvent:${eventType}:start`); + }), + _registerHook(`fireEvent:${eventType}`, 'end', () => { + assert.step(`fireEvent:${eventType}:end`); + }), + ]); + + return [startHook, endHook, ...eventSpecificHooks]; +}; + +/** + * Unregister list of provided mock hooks + * + * @param {HookUnregister[]} hooks Unregister hook objects + */ +export const unregisterHooks = (hooks) => { + hooks.forEach((hook) => hook.unregister()); +}; + +/** + * Build expected `fireEvent` steps for verification. + * + * @param {string[]} eventTypes List of eventTypes + * @return {string[]} List of expected `fireEvent` steps + */ +export const buildFireEventSteps = (eventTypes) => + eventTypes.flatMap((eventType) => [ + 'fireEvent:start', + `fireEvent:${eventType}:start`, + `fireEvent:end`, + `fireEvent:${eventType}:end`, + ]); + +export default { + registerFireEventHooks, + buildFireEventSteps, + unregisterHooks, +}; diff --git a/tests/unit/dom/click-test.js b/tests/unit/dom/click-test.js index f72cd8922..878cc5d36 100644 --- a/tests/unit/dom/click-test.js +++ b/tests/unit/dom/click-test.js @@ -12,6 +12,11 @@ import { } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { + registerFireEventHooks, + unregisterHooks, + buildFireEventSteps, +} from '../../helpers/register-hooks'; module('DOM Helper: click', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -38,25 +43,32 @@ module('DOM Helper: click', function (hooks) { }); test('it executes registered click hooks', async function (assert) { - assert.expect(3); + assert.expect(15); element = document.createElement('div'); insertElement(element); - let startHook = _registerHook('click', 'start', () => { + const eventTypes = ['mousedown', 'mouseup', 'click']; + const mockHooks = registerFireEventHooks(assert, eventTypes); + const startHook = _registerHook('click', 'start', () => { assert.step('click:start'); }); - let endHook = _registerHook('click', 'end', () => { + const endHook = _registerHook('click', 'end', () => { assert.step('click:end'); }); + mockHooks.push(startHook, endHook); try { await click(element); - assert.verifySteps(['click:start', 'click:end']); + const expectedSteps = [ + 'click:start', + ...buildFireEventSteps(eventTypes), + 'click:end', + ]; + assert.verifySteps(expectedSteps); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); diff --git a/tests/unit/dom/fill-in-test.js b/tests/unit/dom/fill-in-test.js index fba2b887c..98fc31945 100644 --- a/tests/unit/dom/fill-in-test.js +++ b/tests/unit/dom/fill-in-test.js @@ -8,6 +8,11 @@ import { import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { + registerFireEventHooks, + unregisterHooks, + buildFireEventSteps, +} from '../../helpers/register-hooks'; let clickSteps = ['focus', 'focusin', 'input', 'change']; @@ -41,25 +46,32 @@ module('DOM Helper: fillIn', function (hooks) { }); test('it executes registered fillIn hooks', async function (assert) { - assert.expect(3); + assert.expect(11); element = document.createElement('input'); insertElement(element); - let startHook = _registerHook('fillIn', 'start', () => { + const eventTypes = ['input', 'change']; + const mockHooks = registerFireEventHooks(assert, eventTypes); + const startHook = _registerHook('fillIn', 'start', () => { assert.step('fillIn:start'); }); - let endHook = _registerHook('fillIn', 'end', () => { + const endHook = _registerHook('fillIn', 'end', () => { assert.step('fillIn:end'); }); + mockHooks.push(startHook, endHook); try { await fillIn(element, 'foo'); - assert.verifySteps(['fillIn:start', 'fillIn:end']); + const expectedSteps = [ + 'fillIn:start', + ...buildFireEventSteps(eventTypes), + 'fillIn:end', + ]; + assert.verifySteps(expectedSteps); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); diff --git a/tests/unit/dom/fire-event-test.js b/tests/unit/dom/fire-event-test.js deleted file mode 100644 index b3a33c439..000000000 --- a/tests/unit/dom/fire-event-test.js +++ /dev/null @@ -1,160 +0,0 @@ -import { module, test } from 'qunit'; -import hasEmberVersion from '@ember/test-helpers/has-ember-version'; -import { - render, - find, - click, - fillIn, - tap, - typeIn, - settled, - setupContext, - setupRenderingContext, - teardownContext, - _registerHook, -} from '@ember/test-helpers'; -import { hbs } from 'ember-cli-htmlbars'; - -// -// Helpers -// - -/** - * Register and return mock `fireEvent` hooks - * - * @param {Assert} assert Test assertion context - * @param {string[]} eventTypes Event types to register - * @returns {HookUnregister[]} Unregisterable hooks - */ -const setupMockHooks = (assert, eventTypes) => { - const startHook = _registerHook('fireEvent', 'start', () => { - assert.step(`fireEvent:start`); - }); - const endHook = _registerHook('fireEvent', 'end', () => { - assert.step(`fireEvent:end`); - }); - - const eventSpecificHooks = eventTypes.flatMap((eventType) => [ - _registerHook(`fireEvent:${eventType}`, 'start', () => { - assert.step(`fireEvent:${eventType}:start`); - }), - _registerHook(`fireEvent:${eventType}`, 'end', () => { - assert.step(`fireEvent:${eventType}:end`); - }), - ]); - - return [startHook, endHook, ...eventSpecificHooks]; -}; - -/** Unregister mock hooks */ -const unregisterMockHooks = (mockHooks) => { - mockHooks.forEach((mockHook) => mockHook.unregister()); -}; - -/** - * Build list of expected `fireEvent` steps for verification - * - * @param {string[]} eventTypes List of eventTypes - * @return {string[]} List of expected `fireEvent` steps - */ -const buildExpectedSteps = (eventTypes) => - eventTypes.flatMap((eventType) => [ - 'fireEvent:start', - `fireEvent:${eventType}:start`, - `fireEvent:end`, - `fireEvent:${eventType}:end`, - ]); - -// -// Tests -// - -module('DOM Helper: fireEvent', function (hooks) { - if (!hasEmberVersion(2, 4)) { - return; - } - - hooks.beforeEach(async function () { - await setupContext(this); - await setupRenderingContext(this); - }); - - hooks.afterEach(async function () { - await settled(); - await teardownContext(this); - }); - - test(`it executes registered fireEvent hooks for "click" helper`, async function (assert) { - await render(hbs``); - - const eventTypes = ['mousedown', 'mouseup', 'click']; - const mockHooks = setupMockHooks(assert, eventTypes); - - try { - const element = find('button'); - await click(element); - - const expectedSteps = buildExpectedSteps(eventTypes); - assert.verifySteps(expectedSteps); - } finally { - unregisterMockHooks(mockHooks); - } - }); - - test(`it executes registered fireEvent hooks for "tap" helper`, async function (assert) { - await render(hbs``); - - const eventTypes = [ - 'touchstart', - 'touchend', - 'mousedown', - 'mouseup', - 'click', - ]; - const mockHooks = setupMockHooks(assert, eventTypes); - - try { - const element = find('button'); - await tap(element); - - const expectedSteps = buildExpectedSteps(eventTypes); - assert.verifySteps(expectedSteps); - } finally { - unregisterMockHooks(mockHooks); - } - }); - - test(`it executes registered fireEvent hooks for "fillIn" helper`, async function (assert) { - await render(hbs``); - - const eventTypes = ['input', 'change']; - const mockHooks = setupMockHooks(assert, eventTypes); - - try { - const element = find('input'); - await fillIn(element, 'foo'); - - const expectedSteps = buildExpectedSteps(eventTypes); - assert.verifySteps(expectedSteps); - } finally { - unregisterMockHooks(mockHooks); - } - }); - - test(`it executes registered fireEvent hooks for "typeIn" helper`, async function (assert) { - await render(hbs``); - - const eventTypes = ['keydown', 'keypress', 'input', 'keyup', 'change']; - const mockHooks = setupMockHooks(assert, eventTypes); - - try { - const element = find('input'); - await typeIn(element, 'a'); - - const expectedSteps = buildExpectedSteps(eventTypes); - assert.verifySteps(expectedSteps); - } finally { - unregisterMockHooks(mockHooks); - } - }); -}); diff --git a/tests/unit/dom/tap-test.js b/tests/unit/dom/tap-test.js index 1a812b186..cd6275d4e 100644 --- a/tests/unit/dom/tap-test.js +++ b/tests/unit/dom/tap-test.js @@ -8,6 +8,11 @@ import { import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { + registerFireEventHooks, + unregisterHooks, + buildFireEventSteps, +} from '../../helpers/register-hooks'; module('DOM Helper: tap', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -39,25 +44,38 @@ module('DOM Helper: tap', function (hooks) { }); test('it executes registered tap hooks', async function (assert) { - assert.expect(3); + assert.expect(23); element = document.createElement('div'); insertElement(element); - let startHook = _registerHook('tap', 'start', () => { + const eventTypes = [ + 'touchstart', + 'touchend', + 'mousedown', + 'mouseup', + 'click', + ]; + const mockHooks = registerFireEventHooks(assert, eventTypes); + const startHook = _registerHook('tap', 'start', () => { assert.step('tap:start'); }); - let endHook = _registerHook('tap', 'end', () => { + const endHook = _registerHook('tap', 'end', () => { assert.step('tap:end'); }); + mockHooks.push(startHook, endHook); try { await tap(element); - assert.verifySteps(['tap:start', 'tap:end']); + const expectedSteps = [ + 'tap:start', + ...buildFireEventSteps(eventTypes), + 'tap:end', + ]; + assert.verifySteps(expectedSteps); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); diff --git a/tests/unit/dom/type-in-test.js b/tests/unit/dom/type-in-test.js index 14d6556be..0e0c5fa4a 100644 --- a/tests/unit/dom/type-in-test.js +++ b/tests/unit/dom/type-in-test.js @@ -10,6 +10,11 @@ import { isIE11 } from '../../helpers/browser-detect'; import { debounce } from '@ember/runloop'; import { Promise } from 'rsvp'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { + registerFireEventHooks, + unregisterHooks, + buildFireEventSteps, +} from '../../helpers/register-hooks'; /* * Event order based on https://jsbin.com/zitazuxabe/edit?html,js,console,output @@ -77,25 +82,32 @@ module('DOM Helper: typeIn', function (hooks) { }); test('it executes registered typeIn hooks', async function (assert) { - assert.expect(3); + assert.expect(23); element = document.createElement('input'); insertElement(element); - let startHook = _registerHook('typeIn', 'start', () => { + const eventTypes = ['keydown', 'keypress', 'input', 'keyup', 'change']; + const mockHooks = registerFireEventHooks(assert, eventTypes); + const startHook = _registerHook('typeIn', 'start', () => { assert.step('typeIn:start'); }); - let endHook = _registerHook('typeIn', 'end', () => { + const endHook = _registerHook('typeIn', 'end', () => { assert.step('typeIn:end'); }); + mockHooks.push(startHook, endHook); try { - await typeIn(element, 'foo'); - - assert.verifySteps(['typeIn:start', 'typeIn:end']); + await typeIn(element, 'f'); + + const expectedSteps = [ + 'typeIn:start', + ...buildFireEventSteps(eventTypes), + 'typeIn:end', + ]; + assert.verifySteps(expectedSteps); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); From 31b62f8c0b74c53329923394214ef000f1bb4f32 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 09:28:36 -0500 Subject: [PATCH 06/39] refactor: promisify `triggerEvent` helper --- addon-test-support/@ember/test-helpers/dom/trigger-event.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/trigger-event.ts b/addon-test-support/@ember/test-helpers/dom/trigger-event.ts index 25e590523..c38320239 100644 --- a/addon-test-support/@ember/test-helpers/dom/trigger-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/trigger-event.ts @@ -83,9 +83,7 @@ export default function triggerEvent( throw new Error(`Can not \`triggerEvent\` on disabled ${element}`); } - fireEvent(element, eventType, options); - - return settled(); + return fireEvent(element, eventType, options).then(settled); }) .then(() => { return runHooks('triggerEvent', 'end', target, eventType, options); From 2690988d8749f050a3de20ab1e1dd56ebecf18a7 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 09:33:39 -0500 Subject: [PATCH 07/39] chore: remove lingering import --- addon-test-support/@ember/test-helpers/dom/fire-event.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/addon-test-support/@ember/test-helpers/dom/fire-event.ts b/addon-test-support/@ember/test-helpers/dom/fire-event.ts index 03ccd4c85..178c41d70 100644 --- a/addon-test-support/@ember/test-helpers/dom/fire-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/fire-event.ts @@ -3,7 +3,6 @@ import tuple from '../-tuple'; import Target from './-target'; import { log } from '@ember/test-helpers/dom/-logging'; import { runHooks, registerHook } from '../-internal/helper-hooks'; -import settled from '../settled'; registerHook('fireEvent', 'start', (target: Target) => { log('fireEvent', target); From 37a94147974fa5e99595b107abcf65e522e89841 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 09:33:55 -0500 Subject: [PATCH 08/39] refactor: promisify `doubleClick` helper --- .../@ember/test-helpers/dom/double-click.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/double-click.ts b/addon-test-support/@ember/test-helpers/dom/double-click.ts index 4a74bbefd..51bd57219 100644 --- a/addon-test-support/@ember/test-helpers/dom/double-click.ts +++ b/addon-test-support/@ember/test-helpers/dom/double-click.ts @@ -17,23 +17,25 @@ registerHook('doubleClick', 'start', (target: Target) => { @private @param {Element} element the element to double-click on @param {MouseEventInit} options the options to be merged into the mouse events + @returns {Promise} resolves when settled */ export function __doubleClick__( element: Element | Document | Window, options: MouseEventInit -): void { - let mouseDownEvent = fireEvent(element, 'mousedown', options); - - if (!isWindow(element) && !mouseDownEvent?.defaultPrevented) { - __focus__(element); - } - - fireEvent(element, 'mouseup', options); - fireEvent(element, 'click', options); - fireEvent(element, 'mousedown', options); - fireEvent(element, 'mouseup', options); - fireEvent(element, 'click', options); - fireEvent(element, 'dblclick', options); +): Promise { + return Promise.resolve() + .then(() => fireEvent(element, 'mousedown', options)) + .then((mouseDownEvent) => { + if (!isWindow(element) && !mouseDownEvent?.defaultPrevented) { + __focus__(element); + } + }) + .then(() => fireEvent(element, 'mouseup', options)) + .then(() => fireEvent(element, 'click', options)) + .then(() => fireEvent(element, 'mousedown', options)) + .then(() => fireEvent(element, 'mouseup', options)) + .then(() => fireEvent(element, 'click', options)) + .then(() => fireEvent(element, 'dblclick', options)); } /** @@ -113,9 +115,7 @@ export default function doubleClick( throw new Error(`Can not \`doubleClick\` disabled ${element}`); } - __doubleClick__(element, options); - - return settled(); + return __doubleClick__(element, options).then(settled); }) .then(() => runHooks('doubleClick', 'end', target, _options)); } From ab797ef4fc6c99436983ddba27c3591e50e504df Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 10:49:46 -0500 Subject: [PATCH 09/39] test: add more/improve register hooks helpers --- tests/helpers/register-hooks.js | 56 +++++++++++++++++++++++++++++---- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/tests/helpers/register-hooks.js b/tests/helpers/register-hooks.js index 5bc258b02..46ea5b521 100644 --- a/tests/helpers/register-hooks.js +++ b/tests/helpers/register-hooks.js @@ -1,5 +1,32 @@ import { _registerHook } from '@ember/test-helpers'; +/** + * Register mock hooks for a helper and optional list of expected events performed while the helper is executed. + * + * @param {Assert} assert Test assertion context + * @param {string} helperName Helper name + * @param {Object} [options] Options object + * @param {string[]} [options.eventTypes] Event types to register + * @returns {HookUnregister[]} Unregisterable hooks + */ +export const registerHooks = (assert, helperName, { eventTypes } = {}) => { + const mockHooks = [ + _registerHook(helperName, 'start', () => { + assert.step(`${helperName}:start`); + }), + _registerHook(helperName, 'end', () => { + assert.step(`${helperName}:end`); + }), + ]; + + if (Array.isArray(eventTypes)) { + const fireEventHooks = registerFireEventHooks(assert, eventTypes); + mockHooks.push(...fireEventHooks); + } + + return mockHooks; +}; + /** * Register mock `fireEvent` hooks for provided event types. * @@ -15,7 +42,7 @@ export const registerFireEventHooks = (assert, eventTypes) => { assert.step(`fireEvent:end`); }); - const eventSpecificHooks = eventTypes.flatMap((eventType) => [ + const eventSpecificHooks = [...new Set(eventTypes)].flatMap((eventType) => [ _registerHook(`fireEvent:${eventType}`, 'start', () => { assert.step(`fireEvent:${eventType}:start`); }), @@ -39,19 +66,36 @@ export const unregisterHooks = (hooks) => { /** * Build expected `fireEvent` steps for verification. * - * @param {string[]} eventTypes List of eventTypes - * @return {string[]} List of expected `fireEvent` steps + * @param {string[]} eventTypes Event types + * @return {string[]} Expected executed `fireEvent` steps */ -export const buildFireEventSteps = (eventTypes) => - eventTypes.flatMap((eventType) => [ +export const buildExpectedFireEventSteps = (eventTypes) => + eventTypes?.flatMap((eventType) => [ 'fireEvent:start', `fireEvent:${eventType}:start`, `fireEvent:end`, `fireEvent:${eventType}:end`, ]); +/** + * Build list of expected executed steps for verification. + * + * @param {string} helperName Helper name + * @param {Object} [options] Options object + * @param {string[]} [options.eventTypes] Event types to register + * @return {string[]} Expected executed steps + */ +export const buildExpectedSteps = (helperName, { eventTypes } = {}) => + [ + `${helperName}:start`, + ...buildExpectedFireEventSteps(eventTypes), + `${helperName}:end`, + ].filter(Boolean); + export default { + registerHooks, registerFireEventHooks, - buildFireEventSteps, + buildExpectedSteps, + buildExpectedFireEventSteps, unregisterHooks, }; From 96ea1258ac1157450ece6a431f286651ebc3b72c Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 10:51:36 -0500 Subject: [PATCH 10/39] refactor: always return Promise for focus step --- addon-test-support/@ember/test-helpers/dom/double-click.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/double-click.ts b/addon-test-support/@ember/test-helpers/dom/double-click.ts index 51bd57219..c0f044086 100644 --- a/addon-test-support/@ember/test-helpers/dom/double-click.ts +++ b/addon-test-support/@ember/test-helpers/dom/double-click.ts @@ -26,9 +26,9 @@ export function __doubleClick__( return Promise.resolve() .then(() => fireEvent(element, 'mousedown', options)) .then((mouseDownEvent) => { - if (!isWindow(element) && !mouseDownEvent?.defaultPrevented) { - __focus__(element); - } + return !isWindow(element) && !mouseDownEvent?.defaultPrevented + ? __focus__(element) + : Promise.resolve(); }) .then(() => fireEvent(element, 'mouseup', options)) .then(() => fireEvent(element, 'click', options)) From c6e3ff2e8c2b0198ba253c0224c9317bd10ec9c0 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 10:58:39 -0500 Subject: [PATCH 11/39] test: add assertions for fire event hook steps --- tests/unit/dom/double-click-test.js | 83 ++++++++++------------------- 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/tests/unit/dom/double-click-test.js b/tests/unit/dom/double-click-test.js index 36a84881c..7b6730fd8 100644 --- a/tests/unit/dom/double-click-test.js +++ b/tests/unit/dom/double-click-test.js @@ -3,7 +3,6 @@ import { doubleClick, setupContext, teardownContext, - _registerHook, } from '@ember/test-helpers'; import { buildInstrumentedElement, @@ -12,6 +11,21 @@ import { } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { + registerHooks, + unregisterHooks, + buildExpectedSteps, +} from '../../helpers/register-hooks'; + +const expectedEvents = [ + 'mousedown', + 'mouseup', + 'click', + 'mousedown', + 'mouseup', + 'click', + 'dblclick', +]; module('DOM Helper: doubleClick', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -39,25 +53,24 @@ module('DOM Helper: doubleClick', function (hooks) { }); test('it executes registered doubleClick hooks', async function (assert) { - assert.expect(3); + assert.expect(31); element = document.createElement('div'); insertElement(element); - let startHook = _registerHook('doubleClick', 'start', () => { - assert.step('doubleClick:start'); - }); - let endHook = _registerHook('doubleClick', 'end', () => { - assert.step('doubleClick:end'); + const mockHooks = registerHooks(assert, 'doubleClick', { + eventTypes: expectedEvents, }); try { await doubleClick(element); - assert.verifySteps(['doubleClick:start', 'doubleClick:end']); + const expectedSteps = buildExpectedSteps('doubleClick', { + eventTypes: expectedEvents, + }); + assert.verifySteps(expectedSteps); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); @@ -68,15 +81,7 @@ module('DOM Helper: doubleClick', function (hooks) { await setupContext(context); await doubleClick(`#${element.id}`); - assert.verifySteps([ - 'mousedown', - 'mouseup', - 'click', - 'mousedown', - 'mouseup', - 'click', - 'dblclick', - ]); + assert.verifySteps(expectedEvents); }); test('double-clicking a div via element with context set', async function (assert) { @@ -85,15 +90,7 @@ module('DOM Helper: doubleClick', function (hooks) { await setupContext(context); await doubleClick(element); - assert.verifySteps([ - 'mousedown', - 'mouseup', - 'click', - 'mousedown', - 'mouseup', - 'click', - 'dblclick', - ]); + assert.verifySteps(expectedEvents); }); test('double-clicking a div via element without context set', async function (assert) { @@ -121,15 +118,7 @@ module('DOM Helper: doubleClick', function (hooks) { await promise; - assert.verifySteps([ - 'mousedown', - 'mouseup', - 'click', - 'mousedown', - 'mouseup', - 'click', - 'dblclick', - ]); + assert.verifySteps(expectedEvents); }); test('rejects if selector is not found', async function (assert) { @@ -307,15 +296,7 @@ module('DOM Helper: doubleClick', function (hooks) { await doubleClick(iframeElement); - assert.verifySteps([ - 'mousedown', - 'mouseup', - 'click', - 'mousedown', - 'mouseup', - 'click', - 'dblclick', - ]); + assert.verifySteps(expectedEvents); }); }); @@ -410,15 +391,7 @@ module('DOM Helper: doubleClick', function (hooks) { await doubleClick(nonFocusableElement); await doubleClick(element); - assert.verifySteps([ - 'mousedown', - 'mouseup', - 'click', - 'mousedown', - 'mouseup', - 'click', - 'dblclick', - ]); + assert.verifySteps(expectedEvents); }); test('preventDefault() on the mousedown event prevents triggering focus/blur events', async function (assert) { From f292678051a8f83a3f6c8e2eb91417bdb1b1fc4f Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 10:59:08 -0500 Subject: [PATCH 12/39] test: use improved hook test helpers --- tests/unit/dom/click-test.js | 26 +++++--------------------- 1 file changed, 5 insertions(+), 21 deletions(-) diff --git a/tests/unit/dom/click-test.js b/tests/unit/dom/click-test.js index 878cc5d36..8126e3924 100644 --- a/tests/unit/dom/click-test.js +++ b/tests/unit/dom/click-test.js @@ -1,10 +1,5 @@ import { module, test } from 'qunit'; -import { - click, - setupContext, - teardownContext, - _registerHook, -} from '@ember/test-helpers'; +import { click, setupContext, teardownContext } from '@ember/test-helpers'; import { buildInstrumentedElement, instrumentElement, @@ -13,9 +8,9 @@ import { import { isIE11 } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; import { - registerFireEventHooks, + registerHooks, unregisterHooks, - buildFireEventSteps, + buildExpectedSteps, } from '../../helpers/register-hooks'; module('DOM Helper: click', function (hooks) { @@ -49,23 +44,12 @@ module('DOM Helper: click', function (hooks) { insertElement(element); const eventTypes = ['mousedown', 'mouseup', 'click']; - const mockHooks = registerFireEventHooks(assert, eventTypes); - const startHook = _registerHook('click', 'start', () => { - assert.step('click:start'); - }); - const endHook = _registerHook('click', 'end', () => { - assert.step('click:end'); - }); - mockHooks.push(startHook, endHook); + const mockHooks = registerHooks(assert, 'click', { eventTypes }); try { await click(element); - const expectedSteps = [ - 'click:start', - ...buildFireEventSteps(eventTypes), - 'click:end', - ]; + const expectedSteps = buildExpectedSteps('click', { eventTypes }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); From 2e8de27377cf8304f940857a9f63dc3a908232c8 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 13:38:33 -0500 Subject: [PATCH 13/39] test: use improved hook test helpers --- tests/unit/dom/fill-in-test.js | 26 ++++-------------- tests/unit/dom/tap-test.js | 30 +++++++-------------- tests/unit/dom/type-in-test.js | 48 ++++++++++++++++++---------------- 3 files changed, 39 insertions(+), 65 deletions(-) diff --git a/tests/unit/dom/fill-in-test.js b/tests/unit/dom/fill-in-test.js index 98fc31945..8eb21c4a4 100644 --- a/tests/unit/dom/fill-in-test.js +++ b/tests/unit/dom/fill-in-test.js @@ -1,17 +1,12 @@ import { module, test } from 'qunit'; -import { - fillIn, - setupContext, - teardownContext, - _registerHook, -} from '@ember/test-helpers'; +import { fillIn, setupContext, teardownContext } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; import { - registerFireEventHooks, + registerHooks, unregisterHooks, - buildFireEventSteps, + buildExpectedSteps, } from '../../helpers/register-hooks'; let clickSteps = ['focus', 'focusin', 'input', 'change']; @@ -52,23 +47,12 @@ module('DOM Helper: fillIn', function (hooks) { insertElement(element); const eventTypes = ['input', 'change']; - const mockHooks = registerFireEventHooks(assert, eventTypes); - const startHook = _registerHook('fillIn', 'start', () => { - assert.step('fillIn:start'); - }); - const endHook = _registerHook('fillIn', 'end', () => { - assert.step('fillIn:end'); - }); - mockHooks.push(startHook, endHook); + const mockHooks = registerHooks(assert, 'fillIn', { eventTypes }); try { await fillIn(element, 'foo'); - const expectedSteps = [ - 'fillIn:start', - ...buildFireEventSteps(eventTypes), - 'fillIn:end', - ]; + const expectedSteps = buildExpectedSteps('fillIn', { eventTypes }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); diff --git a/tests/unit/dom/tap-test.js b/tests/unit/dom/tap-test.js index cd6275d4e..66e0777c9 100644 --- a/tests/unit/dom/tap-test.js +++ b/tests/unit/dom/tap-test.js @@ -1,17 +1,12 @@ import { module, test } from 'qunit'; -import { - tap, - setupContext, - teardownContext, - _registerHook, -} from '@ember/test-helpers'; +import { tap, setupContext, teardownContext } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; import { - registerFireEventHooks, + registerHooks, unregisterHooks, - buildFireEventSteps, + buildExpectedSteps, } from '../../helpers/register-hooks'; module('DOM Helper: tap', function (hooks) { @@ -49,30 +44,23 @@ module('DOM Helper: tap', function (hooks) { element = document.createElement('div'); insertElement(element); - const eventTypes = [ + const expectedEvents = [ 'touchstart', 'touchend', 'mousedown', 'mouseup', 'click', ]; - const mockHooks = registerFireEventHooks(assert, eventTypes); - const startHook = _registerHook('tap', 'start', () => { - assert.step('tap:start'); - }); - const endHook = _registerHook('tap', 'end', () => { - assert.step('tap:end'); + const mockHooks = registerHooks(assert, 'tap', { + eventTypes: expectedEvents, }); - mockHooks.push(startHook, endHook); try { await tap(element); - const expectedSteps = [ - 'tap:start', - ...buildFireEventSteps(eventTypes), - 'tap:end', - ]; + const expectedSteps = buildExpectedSteps('tap', { + eventTypes: expectedEvents, + }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); diff --git a/tests/unit/dom/type-in-test.js b/tests/unit/dom/type-in-test.js index 0e0c5fa4a..0ef8727c2 100644 --- a/tests/unit/dom/type-in-test.js +++ b/tests/unit/dom/type-in-test.js @@ -1,19 +1,14 @@ import { module, test } from 'qunit'; -import { - typeIn, - setupContext, - teardownContext, - _registerHook, -} from '@ember/test-helpers'; +import { typeIn, setupContext, teardownContext } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; import { debounce } from '@ember/runloop'; import { Promise } from 'rsvp'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; import { - registerFireEventHooks, + registerHooks, unregisterHooks, - buildFireEventSteps, + buildExpectedSteps, } from '../../helpers/register-hooks'; /* @@ -82,29 +77,36 @@ module('DOM Helper: typeIn', function (hooks) { }); test('it executes registered typeIn hooks', async function (assert) { - assert.expect(23); + assert.expect(55); element = document.createElement('input'); insertElement(element); - const eventTypes = ['keydown', 'keypress', 'input', 'keyup', 'change']; - const mockHooks = registerFireEventHooks(assert, eventTypes); - const startHook = _registerHook('typeIn', 'start', () => { - assert.step('typeIn:start'); - }); - const endHook = _registerHook('typeIn', 'end', () => { - assert.step('typeIn:end'); + const expectedEvents = [ + 'keydown', + 'keypress', + 'input', + 'keyup', + 'keydown', + 'keypress', + 'input', + 'keyup', + 'keydown', + 'keypress', + 'input', + 'keyup', + 'change', + ]; + const mockHooks = registerHooks(assert, 'typeIn', { + eventTypes: expectedEvents, }); - mockHooks.push(startHook, endHook); try { - await typeIn(element, 'f'); + await typeIn(element, 'foo'); - const expectedSteps = [ - 'typeIn:start', - ...buildFireEventSteps(eventTypes), - 'typeIn:end', - ]; + const expectedSteps = buildExpectedSteps('typeIn', { + eventTypes: expectedEvents, + }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); From 43182121b98835702f841f5ab56fbf5c15513c04 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 13:38:49 -0500 Subject: [PATCH 14/39] docs: clarify param description --- tests/helpers/register-hooks.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/helpers/register-hooks.js b/tests/helpers/register-hooks.js index 46ea5b521..cb5395c26 100644 --- a/tests/helpers/register-hooks.js +++ b/tests/helpers/register-hooks.js @@ -6,7 +6,7 @@ import { _registerHook } from '@ember/test-helpers'; * @param {Assert} assert Test assertion context * @param {string} helperName Helper name * @param {Object} [options] Options object - * @param {string[]} [options.eventTypes] Event types to register + * @param {string[]} [options.eventTypes] Event types to register as `fireEvent` hooks. NOTE: These are deduplicated to prevent duplicate step assertions. * @returns {HookUnregister[]} Unregisterable hooks */ export const registerHooks = (assert, helperName, { eventTypes } = {}) => { @@ -31,7 +31,7 @@ export const registerHooks = (assert, helperName, { eventTypes } = {}) => { * Register mock `fireEvent` hooks for provided event types. * * @param {Assert} assert Test assertion context - * @param {string[]} eventTypes Event types to register + * @param {string[]} [options.eventTypes] Event types to register as `fireEvent` hooks (these are deduplicated) * @returns {HookUnregister[]} Unregisterable hooks */ export const registerFireEventHooks = (assert, eventTypes) => { From f410f57d59ae6eafd09db9d7dac5fc9e444c3d3c Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 13:54:23 -0500 Subject: [PATCH 15/39] refactor: promisify `tab` fire event func --- .../@ember/test-helpers/dom/tab.ts | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/tab.ts b/addon-test-support/@ember/test-helpers/dom/tab.ts index 5b0444aca..1c6611960 100644 --- a/addon-test-support/@ember/test-helpers/dom/tab.ts +++ b/addon-test-support/@ember/test-helpers/dom/tab.ts @@ -227,11 +227,9 @@ function triggerResponderChange( return Promise.resolve() .then(() => runHooks('tab', 'start', debugData)) .then(() => getActiveElement(ownerDocument)) - .then((activeElement) => { - return runHooks('tab', 'targetFound', activeElement).then( - () => activeElement - ); - }) + .then((activeElement) => + runHooks('tab', 'targetFound', activeElement).then(() => activeElement) + ) .then((activeElement) => { let event = _buildKeyboardEvent('keydown', keyboardEventOptions); let defaultNotPrevented = activeElement.dispatchEvent(event); @@ -242,19 +240,22 @@ function triggerResponderChange( let target = findNextResponders(rootElement, activeElement); if (target) { if (backwards && target.previous) { - __focus__(target.previous); + return __focus__(target.previous); } else if (!backwards && target.next) { - __focus__(target.next); + return __focus__(target.next); } else { - __blur__(activeElement); + return __blur__(activeElement); } } } }) .then(() => { let activeElement = getActiveElement(ownerDocument); - fireEvent(activeElement, 'keyup', keyboardEventOptions); - + return fireEvent(activeElement, 'keyup', keyboardEventOptions).then( + () => activeElement + ); + }) + .then((activeElement) => { if (!unRestrainTabIndex && activeElement.tabIndex > 0) { throw new Error( `tabindex of greater than 0 is not allowed. Found tabindex=${activeElement.tabIndex}` From 0a6e687bd02dbda9657c6b0d1335a926be679505 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 13:55:45 -0500 Subject: [PATCH 16/39] refactor: promisify `trigger-key-event` helper --- .../@ember/test-helpers/dom/trigger-key-event.ts | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts b/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts index 661fac457..56cc8eae5 100644 --- a/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts @@ -245,11 +245,9 @@ export default function triggerKeyEvent( throw new Error(`Can not \`triggerKeyEvent\` on disabled ${element}`); } - __triggerKeyEvent__(element, eventType, key, modifiers); - - return settled(); + return __triggerKeyEvent__(element, eventType, key, modifiers).then( + settled + ); }) - .then(() => { - return runHooks('triggerKeyEvent', 'end', target, eventType, key); - }); + .then(() => runHooks('triggerKeyEvent', 'end', target, eventType, key)); } From 786c245452f13374e7e5cac33bc33c0088b7d8a0 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:09:19 -0500 Subject: [PATCH 17/39] refactor: promisify `select` helper --- addon-test-support/@ember/test-helpers/dom/select.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/select.ts b/addon-test-support/@ember/test-helpers/dom/select.ts index 7ad5721df..afb4927ce 100644 --- a/addon-test-support/@ember/test-helpers/dom/select.ts +++ b/addon-test-support/@ember/test-helpers/dom/select.ts @@ -77,8 +77,9 @@ export default function select( ); } - __focus__(element); - + return __focus__(element).then(() => element); + }) + .then((element) => { for (let i = 0; i < element.options.length; i++) { let elementOption = element.options.item(i); if (elementOption) { @@ -90,10 +91,9 @@ export default function select( } } - fireEvent(element, 'input'); - fireEvent(element, 'change'); - - return settled(); + return fireEvent(element, 'input') + .then(() => fireEvent(element, 'change')) + .then(settled); }) .then(() => runHooks('select', 'end', target, options, keepPreviouslySelected) From f633cf18d43ba6c2578cd36ff0ea0e13146e7b5b Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:10:02 -0500 Subject: [PATCH 18/39] test: add event hooks assertions to execution test --- tests/unit/dom/select-test.js | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/unit/dom/select-test.js b/tests/unit/dom/select-test.js index a72437ff0..df1144558 100644 --- a/tests/unit/dom/select-test.js +++ b/tests/unit/dom/select-test.js @@ -1,12 +1,12 @@ import { module, test } from 'qunit'; -import { - select, - setupContext, - teardownContext, - _registerHook, -} from '@ember/test-helpers'; +import { select, setupContext, teardownContext } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11 } from '../../helpers/browser-detect'; +import { + buildExpectedSteps, + registerHooks, + unregisterHooks, +} from '../../helpers/register-hooks'; let selectSteps = ['focus', 'focusin', 'input', 'change']; let additionalSteps = ['input', 'change']; @@ -35,25 +35,25 @@ module('DOM Helper: select', function (hooks) { }); test('it executes registered select hooks', async function (assert) { - assert.expect(3); + assert.expect(11); element = document.createElement('select'); insertElement(element); - let startHook = _registerHook('select', 'start', () => { - assert.step('select:start'); - }); - let endHook = _registerHook('select', 'end', () => { - assert.step('select:end'); + const expectedEvents = ['input', 'change']; + const mockHooks = registerHooks(assert, 'select', { + eventTypes: expectedEvents, }); try { await select(element, 'apple'); - assert.verifySteps(['select:start', 'select:end']); + const expectedSteps = buildExpectedSteps('select', { + eventTypes: expectedEvents, + }); + assert.verifySteps(expectedSteps); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); From c7c851f967bb3e6a33e9ef69cac685dca2f9ffa0 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:24:00 -0500 Subject: [PATCH 19/39] test: rename helper `eventTypes` params to `expectedEvents` --- tests/helpers/register-hooks.js | 48 ++++++++++++++++------------- tests/unit/dom/click-test.js | 6 ++-- tests/unit/dom/double-click-test.js | 6 ++-- tests/unit/dom/fill-in-test.js | 6 ++-- tests/unit/dom/select-test.js | 8 ++--- tests/unit/dom/tap-test.js | 8 ++--- tests/unit/dom/type-in-test.js | 8 ++--- 7 files changed, 40 insertions(+), 50 deletions(-) diff --git a/tests/helpers/register-hooks.js b/tests/helpers/register-hooks.js index cb5395c26..ee51a1840 100644 --- a/tests/helpers/register-hooks.js +++ b/tests/helpers/register-hooks.js @@ -6,10 +6,10 @@ import { _registerHook } from '@ember/test-helpers'; * @param {Assert} assert Test assertion context * @param {string} helperName Helper name * @param {Object} [options] Options object - * @param {string[]} [options.eventTypes] Event types to register as `fireEvent` hooks. NOTE: These are deduplicated to prevent duplicate step assertions. + * @param {string[]} [options.expectedEvents] Expected events to register as `fireEvent` hooks. (NOTE: These are deduplicated to prevent registering duplicate step assertions.) * @returns {HookUnregister[]} Unregisterable hooks */ -export const registerHooks = (assert, helperName, { eventTypes } = {}) => { +export const registerHooks = (assert, helperName, { expectedEvents } = {}) => { const mockHooks = [ _registerHook(helperName, 'start', () => { assert.step(`${helperName}:start`); @@ -19,8 +19,8 @@ export const registerHooks = (assert, helperName, { eventTypes } = {}) => { }), ]; - if (Array.isArray(eventTypes)) { - const fireEventHooks = registerFireEventHooks(assert, eventTypes); + if (Array.isArray(expectedEvents)) { + const fireEventHooks = registerFireEventHooks(assert, expectedEvents); mockHooks.push(...fireEventHooks); } @@ -31,10 +31,10 @@ export const registerHooks = (assert, helperName, { eventTypes } = {}) => { * Register mock `fireEvent` hooks for provided event types. * * @param {Assert} assert Test assertion context - * @param {string[]} [options.eventTypes] Event types to register as `fireEvent` hooks (these are deduplicated) + * @param {string[]} [options.expectedEvents] Expected events to register as `fireEvent` hooks (NOTE: These are deduplicated to prevent registering duplicate step assertions.) * @returns {HookUnregister[]} Unregisterable hooks */ -export const registerFireEventHooks = (assert, eventTypes) => { +export const registerFireEventHooks = (assert, expectedEvents) => { const startHook = _registerHook('fireEvent', 'start', () => { assert.step(`fireEvent:start`); }); @@ -42,14 +42,16 @@ export const registerFireEventHooks = (assert, eventTypes) => { assert.step(`fireEvent:end`); }); - const eventSpecificHooks = [...new Set(eventTypes)].flatMap((eventType) => [ - _registerHook(`fireEvent:${eventType}`, 'start', () => { - assert.step(`fireEvent:${eventType}:start`); - }), - _registerHook(`fireEvent:${eventType}`, 'end', () => { - assert.step(`fireEvent:${eventType}:end`); - }), - ]); + const eventSpecificHooks = [...new Set(expectedEvents)].flatMap( + (eventType) => [ + _registerHook(`fireEvent:${eventType}`, 'start', () => { + assert.step(`fireEvent:${eventType}:start`); + }), + _registerHook(`fireEvent:${eventType}`, 'end', () => { + assert.step(`fireEvent:${eventType}:end`); + }), + ] + ); return [startHook, endHook, ...eventSpecificHooks]; }; @@ -66,15 +68,16 @@ export const unregisterHooks = (hooks) => { /** * Build expected `fireEvent` steps for verification. * - * @param {string[]} eventTypes Event types + * @param {string[]} expectedEvents Events expected to be executed * @return {string[]} Expected executed `fireEvent` steps */ -export const buildExpectedFireEventSteps = (eventTypes) => - eventTypes?.flatMap((eventType) => [ +// TODO: rename `eventTypes` to `expectedEvents` +export const buildExpectedFireEventSteps = (expectedEvents) => + expectedEvents?.flatMap((event) => [ 'fireEvent:start', - `fireEvent:${eventType}:start`, + `fireEvent:${event}:start`, `fireEvent:end`, - `fireEvent:${eventType}:end`, + `fireEvent:${event}:end`, ]); /** @@ -82,13 +85,14 @@ export const buildExpectedFireEventSteps = (eventTypes) => * * @param {string} helperName Helper name * @param {Object} [options] Options object - * @param {string[]} [options.eventTypes] Event types to register + * @param {string[]} [options.expectedEvents] Events expected to be executed * @return {string[]} Expected executed steps */ -export const buildExpectedSteps = (helperName, { eventTypes } = {}) => +// TODO: rename `eventTypes` to `expectedEvents` +export const buildExpectedSteps = (helperName, { expectedEvents } = {}) => [ `${helperName}:start`, - ...buildExpectedFireEventSteps(eventTypes), + ...buildExpectedFireEventSteps(expectedEvents), `${helperName}:end`, ].filter(Boolean); diff --git a/tests/unit/dom/click-test.js b/tests/unit/dom/click-test.js index 8126e3924..55fb3dd2c 100644 --- a/tests/unit/dom/click-test.js +++ b/tests/unit/dom/click-test.js @@ -43,13 +43,13 @@ module('DOM Helper: click', function (hooks) { element = document.createElement('div'); insertElement(element); - const eventTypes = ['mousedown', 'mouseup', 'click']; - const mockHooks = registerHooks(assert, 'click', { eventTypes }); + const expectedEvents = ['mousedown', 'mouseup', 'click']; + const mockHooks = registerHooks(assert, 'click', { expectedEvents }); try { await click(element); - const expectedSteps = buildExpectedSteps('click', { eventTypes }); + const expectedSteps = buildExpectedSteps('click', { expectedEvents }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); diff --git a/tests/unit/dom/double-click-test.js b/tests/unit/dom/double-click-test.js index 7b6730fd8..f35714332 100644 --- a/tests/unit/dom/double-click-test.js +++ b/tests/unit/dom/double-click-test.js @@ -58,15 +58,13 @@ module('DOM Helper: doubleClick', function (hooks) { element = document.createElement('div'); insertElement(element); - const mockHooks = registerHooks(assert, 'doubleClick', { - eventTypes: expectedEvents, - }); + const mockHooks = registerHooks(assert, 'doubleClick', { expectedEvents }); try { await doubleClick(element); const expectedSteps = buildExpectedSteps('doubleClick', { - eventTypes: expectedEvents, + expectedEvents, }); assert.verifySteps(expectedSteps); } finally { diff --git a/tests/unit/dom/fill-in-test.js b/tests/unit/dom/fill-in-test.js index 8eb21c4a4..dfc5188bb 100644 --- a/tests/unit/dom/fill-in-test.js +++ b/tests/unit/dom/fill-in-test.js @@ -46,13 +46,13 @@ module('DOM Helper: fillIn', function (hooks) { element = document.createElement('input'); insertElement(element); - const eventTypes = ['input', 'change']; - const mockHooks = registerHooks(assert, 'fillIn', { eventTypes }); + const expectedEvents = ['input', 'change']; + const mockHooks = registerHooks(assert, 'fillIn', { expectedEvents }); try { await fillIn(element, 'foo'); - const expectedSteps = buildExpectedSteps('fillIn', { eventTypes }); + const expectedSteps = buildExpectedSteps('fillIn', { expectedEvents }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); diff --git a/tests/unit/dom/select-test.js b/tests/unit/dom/select-test.js index df1144558..f87929b79 100644 --- a/tests/unit/dom/select-test.js +++ b/tests/unit/dom/select-test.js @@ -41,16 +41,12 @@ module('DOM Helper: select', function (hooks) { insertElement(element); const expectedEvents = ['input', 'change']; - const mockHooks = registerHooks(assert, 'select', { - eventTypes: expectedEvents, - }); + const mockHooks = registerHooks(assert, 'select', { expectedEvents }); try { await select(element, 'apple'); - const expectedSteps = buildExpectedSteps('select', { - eventTypes: expectedEvents, - }); + const expectedSteps = buildExpectedSteps('select', { expectedEvents }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); diff --git a/tests/unit/dom/tap-test.js b/tests/unit/dom/tap-test.js index 66e0777c9..4e9e672cb 100644 --- a/tests/unit/dom/tap-test.js +++ b/tests/unit/dom/tap-test.js @@ -51,16 +51,12 @@ module('DOM Helper: tap', function (hooks) { 'mouseup', 'click', ]; - const mockHooks = registerHooks(assert, 'tap', { - eventTypes: expectedEvents, - }); + const mockHooks = registerHooks(assert, 'tap', { expectedEvents }); try { await tap(element); - const expectedSteps = buildExpectedSteps('tap', { - eventTypes: expectedEvents, - }); + const expectedSteps = buildExpectedSteps('tap', { expectedEvents }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); diff --git a/tests/unit/dom/type-in-test.js b/tests/unit/dom/type-in-test.js index 0ef8727c2..70188cadb 100644 --- a/tests/unit/dom/type-in-test.js +++ b/tests/unit/dom/type-in-test.js @@ -97,16 +97,12 @@ module('DOM Helper: typeIn', function (hooks) { 'keyup', 'change', ]; - const mockHooks = registerHooks(assert, 'typeIn', { - eventTypes: expectedEvents, - }); + const mockHooks = registerHooks(assert, 'typeIn', { expectedEvents }); try { await typeIn(element, 'foo'); - const expectedSteps = buildExpectedSteps('typeIn', { - eventTypes: expectedEvents, - }); + const expectedSteps = buildExpectedSteps('typeIn', { expectedEvents }); assert.verifySteps(expectedSteps); } finally { unregisterHooks(mockHooks); From 2d6170cffae340e2984134d3672fa077bdecd9ac Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:29:06 -0500 Subject: [PATCH 20/39] test: use hook test helpers --- tests/unit/dom/blur-test.js | 11 +++-------- tests/unit/dom/focus-test.js | 11 +++-------- tests/unit/dom/trigger-event-test.js | 11 +++-------- tests/unit/dom/trigger-key-event-test.js | 11 +++-------- 4 files changed, 12 insertions(+), 32 deletions(-) diff --git a/tests/unit/dom/blur-test.js b/tests/unit/dom/blur-test.js index 331395b27..cbb63b8ba 100644 --- a/tests/unit/dom/blur-test.js +++ b/tests/unit/dom/blur-test.js @@ -9,6 +9,7 @@ import { import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11, isEdge } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; let focusSteps = ['focus', 'focusin']; let blurSteps = ['blur', 'focusout']; @@ -62,20 +63,14 @@ module('DOM Helper: blur', function (hooks) { await focus(element); - let startHook = _registerHook('blur', 'start', () => { - assert.step('blur:start'); - }); - let endHook = _registerHook('blur', 'end', () => { - assert.step('blur:end'); - }); + const mockHooks = registerHooks(assert, 'blur'); try { await blur(elementWithFocus); assert.verifySteps(['blur', 'focusout', 'blur:start', 'blur:end']); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); diff --git a/tests/unit/dom/focus-test.js b/tests/unit/dom/focus-test.js index abe3d208f..519e84543 100644 --- a/tests/unit/dom/focus-test.js +++ b/tests/unit/dom/focus-test.js @@ -12,6 +12,7 @@ import { } from '../../helpers/events'; import { isIE11, isEdge } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; let focusSteps = ['focus', 'focusin']; let blurSteps = ['blur', 'focusout']; @@ -54,20 +55,14 @@ module('DOM Helper: focus', function (hooks) { element = document.createElement('input'); insertElement(element); - let startHook = _registerHook('focus', 'start', () => { - assert.step('focus:start'); - }); - let endHook = _registerHook('focus', 'end', () => { - assert.step('focus:end'); - }); + const mockHooks = registerHooks(assert, 'focus'); try { await focus(element); assert.verifySteps(['focus:start', 'focus:end']); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); diff --git a/tests/unit/dom/trigger-event-test.js b/tests/unit/dom/trigger-event-test.js index 792b5f476..9bf773c45 100644 --- a/tests/unit/dom/trigger-event-test.js +++ b/tests/unit/dom/trigger-event-test.js @@ -7,6 +7,7 @@ import { } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; module('DOM Helper: triggerEvent', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -44,20 +45,14 @@ module('DOM Helper: triggerEvent', function (hooks) { element = document.createElement('div'); insertElement(element); - let startHook = _registerHook('triggerEvent', 'start', () => { - assert.step('triggerEvent:start'); - }); - let endHook = _registerHook('triggerEvent', 'end', () => { - assert.step('triggerEvent:end'); - }); + const mockHooks = registerHooks(assert, 'triggerEvent'); try { await triggerEvent(element, 'mouseenter'); assert.verifySteps(['triggerEvent:start', 'triggerEvent:end']); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); diff --git a/tests/unit/dom/trigger-key-event-test.js b/tests/unit/dom/trigger-key-event-test.js index 7bdbeb0ac..16c34f4d8 100644 --- a/tests/unit/dom/trigger-key-event-test.js +++ b/tests/unit/dom/trigger-key-event-test.js @@ -7,6 +7,7 @@ import { } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; module('DOM Helper: triggerKeyEvent', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -44,20 +45,14 @@ module('DOM Helper: triggerKeyEvent', function (hooks) { element = document.createElement('div'); insertElement(element); - let startHook = _registerHook('triggerKeyEvent', 'start', () => { - assert.step('triggerKeyEvent:start'); - }); - let endHook = _registerHook('triggerKeyEvent', 'end', () => { - assert.step('triggerKeyEvent:end'); - }); + const mockHooks = registerHooks(assert, 'triggerKeyEvent'); try { await triggerKeyEvent(element, 'keypress', 13); assert.verifySteps(['triggerKeyEvent:start', 'triggerKeyEvent:end']); } finally { - startHook.unregister(); - endHook.unregister(); + unregisterHooks(mockHooks); } }); From 93bc5dfd1ae44f073bdd68a9b5576e194d231674 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:29:49 -0500 Subject: [PATCH 21/39] chore: remove finished TODOs --- tests/helpers/register-hooks.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/helpers/register-hooks.js b/tests/helpers/register-hooks.js index ee51a1840..40634a3db 100644 --- a/tests/helpers/register-hooks.js +++ b/tests/helpers/register-hooks.js @@ -71,7 +71,6 @@ export const unregisterHooks = (hooks) => { * @param {string[]} expectedEvents Events expected to be executed * @return {string[]} Expected executed `fireEvent` steps */ -// TODO: rename `eventTypes` to `expectedEvents` export const buildExpectedFireEventSteps = (expectedEvents) => expectedEvents?.flatMap((event) => [ 'fireEvent:start', @@ -88,7 +87,6 @@ export const buildExpectedFireEventSteps = (expectedEvents) => * @param {string[]} [options.expectedEvents] Events expected to be executed * @return {string[]} Expected executed steps */ -// TODO: rename `eventTypes` to `expectedEvents` export const buildExpectedSteps = (helperName, { expectedEvents } = {}) => [ `${helperName}:start`, From 9ded7a2b5709562227311d4ebc3ff5657fc79961 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:32:58 -0500 Subject: [PATCH 22/39] refactor: encapsulate specific start/end hooks with generic hooks --- addon-test-support/@ember/test-helpers/dom/fire-event.ts | 8 +++----- tests/helpers/register-hooks.js | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/fire-event.ts b/addon-test-support/@ember/test-helpers/dom/fire-event.ts index 178c41d70..1fca4495c 100644 --- a/addon-test-support/@ember/test-helpers/dom/fire-event.ts +++ b/addon-test-support/@ember/test-helpers/dom/fire-event.ts @@ -97,9 +97,7 @@ function fireEvent( options = {} ): Promise { return Promise.resolve() - .then(() => { - return runHooks('fireEvent', 'start', element); - }) + .then(() => runHooks('fireEvent', 'start', element)) .then(() => runHooks(`fireEvent:${eventType}`, 'start', element)) .then(() => { if (!element) { @@ -144,10 +142,10 @@ function fireEvent( element.dispatchEvent(event); return event; }) - .then((event) => runHooks('fireEvent', 'end', element).then(() => event)) .then((event) => runHooks(`fireEvent:${eventType}`, 'end', element).then(() => event) - ); + ) + .then((event) => runHooks('fireEvent', 'end', element).then(() => event)); } export default fireEvent; diff --git a/tests/helpers/register-hooks.js b/tests/helpers/register-hooks.js index 40634a3db..8612bbbed 100644 --- a/tests/helpers/register-hooks.js +++ b/tests/helpers/register-hooks.js @@ -75,8 +75,8 @@ export const buildExpectedFireEventSteps = (expectedEvents) => expectedEvents?.flatMap((event) => [ 'fireEvent:start', `fireEvent:${event}:start`, - `fireEvent:end`, `fireEvent:${event}:end`, + `fireEvent:end`, ]); /** From b70b17a6d3b10e7caf36ab1c352a5419fa324d9b Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:43:06 -0500 Subject: [PATCH 23/39] refactor: fully promisify `fillIn` helper --- .../@ember/test-helpers/dom/fill-in.ts | 32 +++++++++++-------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/fill-in.ts b/addon-test-support/@ember/test-helpers/dom/fill-in.ts index e5758702a..181624526 100644 --- a/addon-test-support/@ember/test-helpers/dom/fill-in.ts +++ b/addon-test-support/@ember/test-helpers/dom/fill-in.ts @@ -1,5 +1,5 @@ import getElement from './-get-element'; -import isFormControl from './-is-form-control'; +import isFormControl, { FormControl } from './-is-form-control'; import guardForMaxlength from './-guard-for-maxlength'; import { __focus__ } from './focus'; import settled from '../settled'; @@ -21,7 +21,7 @@ registerHook('fillIn', 'start', (target: Target, text: string) => { @public @param {string|Element} target the element or selector to enter text into @param {string} text the text to fill into the target element - @return {Promise} resolves when the application is settled + @return {Promise} resolves when the application is settled @example @@ -30,7 +30,10 @@ registerHook('fillIn', 'start', (target: Target, text: string) => { fillIn('input', 'hello world'); */ -export default function fillIn(target: Target, text: string): Promise { +export default function fillIn( + target: Target, + text: string +): Promise { return Promise.resolve() .then(() => runHooks('fillIn', 'start', target, text)) .then(() => { @@ -60,22 +63,25 @@ export default function fillIn(target: Target, text: string): Promise { guardForMaxlength(element, text, 'fillIn'); - __focus__(element); - - element.value = text; + return __focus__(element).then(() => { + (element as FormControl).value = text; + return element; + }); } else if (isContentEditable(element)) { - __focus__(element); - - element.innerHTML = text; + return __focus__(element).then(() => { + element.innerHTML = text; + return element; + }); } else { throw new Error( '`fillIn` is only usable on form controls or contenteditable elements.' ); } - - return fireEvent(element, 'input').then(() => - fireEvent(element, 'change') - ); }) + .then((element) => + fireEvent(element, 'input').then(() => + fireEvent(element, 'change').then(settled) + ) + ) .then(() => runHooks('fillIn', 'end', target, text)); } From ef8f92bacef3b1ce9b0296092571713a0209ed0f Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:58:11 -0500 Subject: [PATCH 24/39] fix: re-add `settled` func after events fired --- addon-test-support/@ember/test-helpers/dom/click.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addon-test-support/@ember/test-helpers/dom/click.ts b/addon-test-support/@ember/test-helpers/dom/click.ts index 77b8436b5..f05a44cbc 100644 --- a/addon-test-support/@ember/test-helpers/dom/click.ts +++ b/addon-test-support/@ember/test-helpers/dom/click.ts @@ -6,6 +6,7 @@ import isFormControl from './-is-form-control'; import Target, { isWindow } from './-target'; import { log } from '@ember/test-helpers/dom/-logging'; import { runHooks, registerHook } from '../-internal/helper-hooks'; +import settled from '../settled'; const PRIMARY_BUTTON = 1; const MAIN_BUTTON_PRESSED = 0; @@ -113,7 +114,7 @@ export default function click( throw new Error(`Can not \`click\` disabled ${element}`); } - return __click__(element, options); + return __click__(element, options).then(settled); }) .then(() => runHooks('click', 'end', target, _options)); } From b2f08fe9570f5fac4f09ac499767194896169ecc Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 14:59:39 -0500 Subject: [PATCH 25/39] chore: remove unused imports --- tests/unit/dom/blur-test.js | 1 - tests/unit/dom/focus-test.js | 7 +------ tests/unit/dom/trigger-event-test.js | 1 - tests/unit/dom/trigger-key-event-test.js | 1 - 4 files changed, 1 insertion(+), 9 deletions(-) diff --git a/tests/unit/dom/blur-test.js b/tests/unit/dom/blur-test.js index cbb63b8ba..66c37b8f6 100644 --- a/tests/unit/dom/blur-test.js +++ b/tests/unit/dom/blur-test.js @@ -4,7 +4,6 @@ import { blur, setupContext, teardownContext, - _registerHook, } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11, isEdge } from '../../helpers/browser-detect'; diff --git a/tests/unit/dom/focus-test.js b/tests/unit/dom/focus-test.js index 519e84543..8631bbd0a 100644 --- a/tests/unit/dom/focus-test.js +++ b/tests/unit/dom/focus-test.js @@ -1,10 +1,5 @@ import { module, test } from 'qunit'; -import { - focus, - setupContext, - teardownContext, - _registerHook, -} from '@ember/test-helpers'; +import { focus, setupContext, teardownContext } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement, diff --git a/tests/unit/dom/trigger-event-test.js b/tests/unit/dom/trigger-event-test.js index 9bf773c45..bee318f57 100644 --- a/tests/unit/dom/trigger-event-test.js +++ b/tests/unit/dom/trigger-event-test.js @@ -3,7 +3,6 @@ import { triggerEvent, setupContext, teardownContext, - _registerHook, } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; diff --git a/tests/unit/dom/trigger-key-event-test.js b/tests/unit/dom/trigger-key-event-test.js index 16c34f4d8..74793cb2b 100644 --- a/tests/unit/dom/trigger-key-event-test.js +++ b/tests/unit/dom/trigger-key-event-test.js @@ -3,7 +3,6 @@ import { triggerKeyEvent, setupContext, teardownContext, - _registerHook, } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; From 03db0d7ce06f35f66aee525c0692a5c9b441dd5a Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:04:04 -0500 Subject: [PATCH 26/39] refactor: promisify `scrollTo` helper --- addon-test-support/@ember/test-helpers/dom/scroll-to.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/scroll-to.ts b/addon-test-support/@ember/test-helpers/dom/scroll-to.ts index 8f44e70f3..467c168b2 100644 --- a/addon-test-support/@ember/test-helpers/dom/scroll-to.ts +++ b/addon-test-support/@ember/test-helpers/dom/scroll-to.ts @@ -53,9 +53,7 @@ export default function scrollTo( element.scrollTop = y; element.scrollLeft = x; - fireEvent(element, 'scroll'); - - return settled(); + return fireEvent(element, 'scroll').then(settled); }) .then(() => runHooks('scrollTo', 'end', target)); } From 75067003014d82e9c3b0a1fd1ac8d496bb271838 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:04:29 -0500 Subject: [PATCH 27/39] test: add event hooks assertions to execution test --- tests/integration/dom/scroll-to-test.js | 27 ++++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/tests/integration/dom/scroll-to-test.js b/tests/integration/dom/scroll-to-test.js index 205aa2127..4b064af3a 100644 --- a/tests/integration/dom/scroll-to-test.js +++ b/tests/integration/dom/scroll-to-test.js @@ -9,6 +9,11 @@ import { _registerHook, } from '@ember/test-helpers'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; +import { + buildExpectedSteps, + registerHooks, + unregisterHooks, +} from '../../helpers/register-hooks'; module('DOM Helper: scroll-to', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -25,14 +30,10 @@ module('DOM Helper: scroll-to', function (hooks) { }); test('it executes registered scrollTo hooks', async function (assert) { - assert.expect(3); + assert.expect(7); - let startHook = _registerHook('scrollTo', 'start', () => { - assert.step('scrollTo:start'); - }); - let endHook = _registerHook('scrollTo', 'end', () => { - assert.step('scrollTo:end'); - }); + const expectedEvents = ['scroll']; + const mockHooks = registerHooks(assert, 'scrollTo', { expectedEvents }); await render(hbs`
`); - await scrollTo('.container', 0, 50); - - assert.verifySteps(['scrollTo:start', 'scrollTo:end']); + try { + await scrollTo('.container', 0, 50); - startHook.unregister(); - endHook.unregister(); + const expectedSteps = buildExpectedSteps('scrollTo', { expectedEvents }); + assert.verifySteps(expectedSteps); + } finally { + unregisterHooks(mockHooks); + } }); test('Scroll in vertical direction', async function (assert) { From add69f664c24c970d4da9ac806da2be24c5b9756 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:26:53 -0500 Subject: [PATCH 28/39] refactor: restore prior `settled` behaviour --- .../@ember/test-helpers/dom/blur.ts | 3 +-- .../@ember/test-helpers/dom/click.ts | 2 +- .../@ember/test-helpers/dom/tap.ts | 25 +++++++++---------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/blur.ts b/addon-test-support/@ember/test-helpers/dom/blur.ts index 260b708cd..f75aaac2e 100644 --- a/addon-test-support/@ember/test-helpers/dom/blur.ts +++ b/addon-test-support/@ember/test-helpers/dom/blur.ts @@ -42,7 +42,6 @@ export function __blur__( ? Promise.resolve() .then(() => fireEvent(element, 'blur', { bubbles: false, ...options })) .then(() => fireEvent(element, 'focusout', options)) - .then(() => settled()) : Promise.resolve(); } @@ -84,7 +83,7 @@ export default function blur( ); } - return __blur__(element); + return __blur__(element).then(() => settled()); }) .then(() => runHooks('blur', 'end', target)); } diff --git a/addon-test-support/@ember/test-helpers/dom/click.ts b/addon-test-support/@ember/test-helpers/dom/click.ts index f05a44cbc..0d6c55b96 100644 --- a/addon-test-support/@ember/test-helpers/dom/click.ts +++ b/addon-test-support/@ember/test-helpers/dom/click.ts @@ -2,11 +2,11 @@ import { getWindowOrElement } from './-get-window-or-element'; import fireEvent from './fire-event'; import { __focus__ } from './focus'; import { Promise } from '../-utils'; +import settled from '../settled'; import isFormControl from './-is-form-control'; import Target, { isWindow } from './-target'; import { log } from '@ember/test-helpers/dom/-logging'; import { runHooks, registerHook } from '../-internal/helper-hooks'; -import settled from '../settled'; const PRIMARY_BUTTON = 1; const MAIN_BUTTON_PRESSED = 0; diff --git a/addon-test-support/@ember/test-helpers/dom/tap.ts b/addon-test-support/@ember/test-helpers/dom/tap.ts index d072ce597..e651e628f 100644 --- a/addon-test-support/@ember/test-helpers/dom/tap.ts +++ b/addon-test-support/@ember/test-helpers/dom/tap.ts @@ -76,19 +76,18 @@ export default function tap( throw new Error(`Can not \`tap\` disabled ${element}`); } - return fireEvent(element, 'touchstart', options); - }) - .then((touchstartEv) => { - let element = getElement(target); - return fireEvent(element as Element, 'touchend', options).then( - (touchendEv) => [touchstartEv, touchendEv] - ); - }) - .then(([touchstartEv, touchendEv]) => { - let element = getElement(target); - return !touchstartEv.defaultPrevented && !touchendEv.defaultPrevented - ? __click__(element as Element, options) - : Promise.resolve(); + return fireEvent(element, 'touchstart', options) + .then((touchstartEv) => + fireEvent(element as Element, 'touchend', options).then( + (touchendEv) => [touchstartEv, touchendEv] + ) + ) + .then(([touchstartEv, touchendEv]) => + !touchstartEv.defaultPrevented && !touchendEv.defaultPrevented + ? __click__(element as Element, options) + : Promise.resolve() + ) + .then(settled); }) .then(() => { return runHooks('tap', 'end', target, options); From 5b7bf9c1f93752580bbd6dbd0b1d805a6272077f Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:27:05 -0500 Subject: [PATCH 29/39] refactor: let -> const --- addon-test-support/@ember/test-helpers/dom/focus.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/focus.ts b/addon-test-support/@ember/test-helpers/dom/focus.ts index 121c12398..ab826b498 100644 --- a/addon-test-support/@ember/test-helpers/dom/focus.ts +++ b/addon-test-support/@ember/test-helpers/dom/focus.ts @@ -73,7 +73,7 @@ export function __focus__( throw new Error('There was a previously focused element'); } - let browserIsNotFocused = !document?.hasFocus(); + const browserIsNotFocused = !document?.hasFocus(); // fire __blur__ manually with the correct relatedTarget when the browser is not // already in focus and there was a previously focused element @@ -90,7 +90,7 @@ export function __focus__( // Firefox does not trigger the `focusin` event if the window // does not have focus. If the document does not have focus then // fire `focusin` event as well. - let browserIsFocused = document?.hasFocus(); + const browserIsFocused = document?.hasFocus(); return browserIsFocused ? Promise.resolve() : // if the browser is not focused the previous `el.focus()` didn't fire an event, so we simulate it @@ -152,7 +152,7 @@ export default function focus(target: Target): Promise { throw new Error(`${element} is not focusable`); } - return __focus__(element); + return __focus__(element).then(settled); }) .then(() => runHooks('focus', 'end', target)); } From 03f93db27c4c9ff5f07e0c0f8b2f681354e74fc8 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:27:16 -0500 Subject: [PATCH 30/39] chore: remove unused import --- tests/integration/dom/scroll-to-test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/integration/dom/scroll-to-test.js b/tests/integration/dom/scroll-to-test.js index 4b064af3a..e24804a1c 100644 --- a/tests/integration/dom/scroll-to-test.js +++ b/tests/integration/dom/scroll-to-test.js @@ -6,7 +6,6 @@ import { setupContext, setupRenderingContext, teardownContext, - _registerHook, } from '@ember/test-helpers'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; import { From 056a8b31c45f7ee45d301a12f89b23abddfa38e4 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:39:50 -0500 Subject: [PATCH 31/39] chore: restore import statements order --- addon-test-support/@ember/test-helpers/dom/click.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon-test-support/@ember/test-helpers/dom/click.ts b/addon-test-support/@ember/test-helpers/dom/click.ts index 0d6c55b96..2fe64623e 100644 --- a/addon-test-support/@ember/test-helpers/dom/click.ts +++ b/addon-test-support/@ember/test-helpers/dom/click.ts @@ -1,8 +1,8 @@ import { getWindowOrElement } from './-get-window-or-element'; import fireEvent from './fire-event'; import { __focus__ } from './focus'; -import { Promise } from '../-utils'; import settled from '../settled'; +import { Promise } from '../-utils'; import isFormControl from './-is-form-control'; import Target, { isWindow } from './-target'; import { log } from '@ember/test-helpers/dom/-logging'; From 51af5a49006b2d8dd5fea0608bdfa829677bec47 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:41:40 -0500 Subject: [PATCH 32/39] refactor: flatten Promise chain --- addon-test-support/@ember/test-helpers/dom/fill-in.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/fill-in.ts b/addon-test-support/@ember/test-helpers/dom/fill-in.ts index 181624526..97a998cfd 100644 --- a/addon-test-support/@ember/test-helpers/dom/fill-in.ts +++ b/addon-test-support/@ember/test-helpers/dom/fill-in.ts @@ -79,9 +79,9 @@ export default function fillIn( } }) .then((element) => - fireEvent(element, 'input').then(() => - fireEvent(element, 'change').then(settled) - ) + fireEvent(element, 'input') + .then(() => fireEvent(element, 'change')) + .then(settled) ) .then(() => runHooks('fillIn', 'end', target, text)); } From 53815e09a910529d07b05bd12d116e499cb283c0 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Fri, 14 Jan 2022 15:48:21 -0500 Subject: [PATCH 33/39] test: improve helper readability --- tests/helpers/register-hooks.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/helpers/register-hooks.js b/tests/helpers/register-hooks.js index 8612bbbed..351864f36 100644 --- a/tests/helpers/register-hooks.js +++ b/tests/helpers/register-hooks.js @@ -42,16 +42,15 @@ export const registerFireEventHooks = (assert, expectedEvents) => { assert.step(`fireEvent:end`); }); - const eventSpecificHooks = [...new Set(expectedEvents)].flatMap( - (eventType) => [ - _registerHook(`fireEvent:${eventType}`, 'start', () => { - assert.step(`fireEvent:${eventType}:start`); - }), - _registerHook(`fireEvent:${eventType}`, 'end', () => { - assert.step(`fireEvent:${eventType}:end`); - }), - ] - ); + const eventTypes = [...new Set(expectedEvents)]; + const eventSpecificHooks = eventTypes.flatMap((eventType) => [ + _registerHook(`fireEvent:${eventType}`, 'start', () => { + assert.step(`fireEvent:${eventType}:start`); + }), + _registerHook(`fireEvent:${eventType}`, 'end', () => { + assert.step(`fireEvent:${eventType}:end`); + }), + ]); return [startHook, endHook, ...eventSpecificHooks]; }; From 27cde9368fa41e07776d50d9bafb075c7af349e3 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Sat, 15 Jan 2022 10:31:04 -0500 Subject: [PATCH 34/39] refactor: add fallback Promise resolution --- addon-test-support/@ember/test-helpers/dom/tab.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/addon-test-support/@ember/test-helpers/dom/tab.ts b/addon-test-support/@ember/test-helpers/dom/tab.ts index 1c6611960..97231f138 100644 --- a/addon-test-support/@ember/test-helpers/dom/tab.ts +++ b/addon-test-support/@ember/test-helpers/dom/tab.ts @@ -248,6 +248,8 @@ function triggerResponderChange( } } } + + return Promise.resolve(); }) .then(() => { let activeElement = getActiveElement(ownerDocument); From f1ff12842b4edb972bb0a15c020db98c4833b74c Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Sat, 15 Jan 2022 10:42:08 -0500 Subject: [PATCH 35/39] Revert "refactor: let -> const" This reverts commit 5b7bf9c1f93752580bbd6dbd0b1d805a6272077f. --- addon-test-support/@ember/test-helpers/dom/focus.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/addon-test-support/@ember/test-helpers/dom/focus.ts b/addon-test-support/@ember/test-helpers/dom/focus.ts index ab826b498..121c12398 100644 --- a/addon-test-support/@ember/test-helpers/dom/focus.ts +++ b/addon-test-support/@ember/test-helpers/dom/focus.ts @@ -73,7 +73,7 @@ export function __focus__( throw new Error('There was a previously focused element'); } - const browserIsNotFocused = !document?.hasFocus(); + let browserIsNotFocused = !document?.hasFocus(); // fire __blur__ manually with the correct relatedTarget when the browser is not // already in focus and there was a previously focused element @@ -90,7 +90,7 @@ export function __focus__( // Firefox does not trigger the `focusin` event if the window // does not have focus. If the document does not have focus then // fire `focusin` event as well. - const browserIsFocused = document?.hasFocus(); + let browserIsFocused = document?.hasFocus(); return browserIsFocused ? Promise.resolve() : // if the browser is not focused the previous `el.focus()` didn't fire an event, so we simulate it @@ -152,7 +152,7 @@ export default function focus(target: Target): Promise { throw new Error(`${element} is not focusable`); } - return __focus__(element).then(settled); + return __focus__(element); }) .then(() => runHooks('focus', 'end', target)); } From 126d4b007e5fb0862f8f733f6245dacbfbd2ea25 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Sat, 15 Jan 2022 10:44:08 -0500 Subject: [PATCH 36/39] Revert "test: use hook test helpers" This reverts commit 2d6170cffae340e2984134d3672fa077bdecd9ac. --- tests/unit/dom/blur-test.js | 11 ++++++++--- tests/unit/dom/focus-test.js | 11 ++++++++--- tests/unit/dom/trigger-event-test.js | 11 ++++++++--- tests/unit/dom/trigger-key-event-test.js | 11 ++++++++--- 4 files changed, 32 insertions(+), 12 deletions(-) diff --git a/tests/unit/dom/blur-test.js b/tests/unit/dom/blur-test.js index 66c37b8f6..c9af7f135 100644 --- a/tests/unit/dom/blur-test.js +++ b/tests/unit/dom/blur-test.js @@ -8,7 +8,6 @@ import { import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11, isEdge } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; -import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; let focusSteps = ['focus', 'focusin']; let blurSteps = ['blur', 'focusout']; @@ -62,14 +61,20 @@ module('DOM Helper: blur', function (hooks) { await focus(element); - const mockHooks = registerHooks(assert, 'blur'); + let startHook = _registerHook('blur', 'start', () => { + assert.step('blur:start'); + }); + let endHook = _registerHook('blur', 'end', () => { + assert.step('blur:end'); + }); try { await blur(elementWithFocus); assert.verifySteps(['blur', 'focusout', 'blur:start', 'blur:end']); } finally { - unregisterHooks(mockHooks); + startHook.unregister(); + endHook.unregister(); } }); diff --git a/tests/unit/dom/focus-test.js b/tests/unit/dom/focus-test.js index 8631bbd0a..47a669191 100644 --- a/tests/unit/dom/focus-test.js +++ b/tests/unit/dom/focus-test.js @@ -7,7 +7,6 @@ import { } from '../../helpers/events'; import { isIE11, isEdge } from '../../helpers/browser-detect'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; -import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; let focusSteps = ['focus', 'focusin']; let blurSteps = ['blur', 'focusout']; @@ -50,14 +49,20 @@ module('DOM Helper: focus', function (hooks) { element = document.createElement('input'); insertElement(element); - const mockHooks = registerHooks(assert, 'focus'); + let startHook = _registerHook('focus', 'start', () => { + assert.step('focus:start'); + }); + let endHook = _registerHook('focus', 'end', () => { + assert.step('focus:end'); + }); try { await focus(element); assert.verifySteps(['focus:start', 'focus:end']); } finally { - unregisterHooks(mockHooks); + startHook.unregister(); + endHook.unregister(); } }); diff --git a/tests/unit/dom/trigger-event-test.js b/tests/unit/dom/trigger-event-test.js index bee318f57..bb96ab1d0 100644 --- a/tests/unit/dom/trigger-event-test.js +++ b/tests/unit/dom/trigger-event-test.js @@ -6,7 +6,6 @@ import { } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; -import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; module('DOM Helper: triggerEvent', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -44,14 +43,20 @@ module('DOM Helper: triggerEvent', function (hooks) { element = document.createElement('div'); insertElement(element); - const mockHooks = registerHooks(assert, 'triggerEvent'); + let startHook = _registerHook('triggerEvent', 'start', () => { + assert.step('triggerEvent:start'); + }); + let endHook = _registerHook('triggerEvent', 'end', () => { + assert.step('triggerEvent:end'); + }); try { await triggerEvent(element, 'mouseenter'); assert.verifySteps(['triggerEvent:start', 'triggerEvent:end']); } finally { - unregisterHooks(mockHooks); + startHook.unregister(); + endHook.unregister(); } }); diff --git a/tests/unit/dom/trigger-key-event-test.js b/tests/unit/dom/trigger-key-event-test.js index 74793cb2b..2930e7a38 100644 --- a/tests/unit/dom/trigger-key-event-test.js +++ b/tests/unit/dom/trigger-key-event-test.js @@ -6,7 +6,6 @@ import { } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; -import { registerHooks, unregisterHooks } from '../../helpers/register-hooks'; module('DOM Helper: triggerKeyEvent', function (hooks) { if (!hasEmberVersion(2, 4)) { @@ -44,14 +43,20 @@ module('DOM Helper: triggerKeyEvent', function (hooks) { element = document.createElement('div'); insertElement(element); - const mockHooks = registerHooks(assert, 'triggerKeyEvent'); + let startHook = _registerHook('triggerKeyEvent', 'start', () => { + assert.step('triggerKeyEvent:start'); + }); + let endHook = _registerHook('triggerKeyEvent', 'end', () => { + assert.step('triggerKeyEvent:end'); + }); try { await triggerKeyEvent(element, 'keypress', 13); assert.verifySteps(['triggerKeyEvent:start', 'triggerKeyEvent:end']); } finally { - unregisterHooks(mockHooks); + startHook.unregister(); + endHook.unregister(); } }); From 1bab92ae30c35f26fc7aea8f149c0b29d96b2200 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Sat, 15 Jan 2022 10:50:12 -0500 Subject: [PATCH 37/39] revert: undo unrelated assertion replacements --- tests/unit/dom/double-click-test.js | 50 ++++++++++++++++++++++++++--- 1 file changed, 45 insertions(+), 5 deletions(-) diff --git a/tests/unit/dom/double-click-test.js b/tests/unit/dom/double-click-test.js index f35714332..5608c5a2c 100644 --- a/tests/unit/dom/double-click-test.js +++ b/tests/unit/dom/double-click-test.js @@ -79,7 +79,15 @@ module('DOM Helper: doubleClick', function (hooks) { await setupContext(context); await doubleClick(`#${element.id}`); - assert.verifySteps(expectedEvents); + assert.verifySteps([ + 'mousedown', + 'mouseup', + 'click', + 'mousedown', + 'mouseup', + 'click', + 'dblclick', + ]); }); test('double-clicking a div via element with context set', async function (assert) { @@ -88,7 +96,15 @@ module('DOM Helper: doubleClick', function (hooks) { await setupContext(context); await doubleClick(element); - assert.verifySteps(expectedEvents); + assert.verifySteps([ + 'mousedown', + 'mouseup', + 'click', + 'mousedown', + 'mouseup', + 'click', + 'dblclick', + ]); }); test('double-clicking a div via element without context set', async function (assert) { @@ -116,7 +132,15 @@ module('DOM Helper: doubleClick', function (hooks) { await promise; - assert.verifySteps(expectedEvents); + assert.verifySteps([ + 'mousedown', + 'mouseup', + 'click', + 'mousedown', + 'mouseup', + 'click', + 'dblclick', + ]); }); test('rejects if selector is not found', async function (assert) { @@ -294,7 +318,15 @@ module('DOM Helper: doubleClick', function (hooks) { await doubleClick(iframeElement); - assert.verifySteps(expectedEvents); + assert.verifySteps([ + 'mousedown', + 'mouseup', + 'click', + 'mousedown', + 'mouseup', + 'click', + 'dblclick', + ]); }); }); @@ -389,7 +421,15 @@ module('DOM Helper: doubleClick', function (hooks) { await doubleClick(nonFocusableElement); await doubleClick(element); - assert.verifySteps(expectedEvents); + assert.verifySteps([ + 'mousedown', + 'mouseup', + 'click', + 'mousedown', + 'mouseup', + 'click', + 'dblclick', + ]); }); test('preventDefault() on the mousedown event prevents triggering focus/blur events', async function (assert) { From 1fb879ad33d4caf68153c07661bc65bade3a4eb4 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Sat, 15 Jan 2022 10:52:12 -0500 Subject: [PATCH 38/39] revert: restore chained `settled` Promise --- addon-test-support/@ember/test-helpers/dom/focus.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon-test-support/@ember/test-helpers/dom/focus.ts b/addon-test-support/@ember/test-helpers/dom/focus.ts index 121c12398..7be0525fa 100644 --- a/addon-test-support/@ember/test-helpers/dom/focus.ts +++ b/addon-test-support/@ember/test-helpers/dom/focus.ts @@ -152,7 +152,7 @@ export default function focus(target: Target): Promise { throw new Error(`${element} is not focusable`); } - return __focus__(element); + return __focus__(element).then(settled); }) .then(() => runHooks('focus', 'end', target)); } From 61cfbb3abf45ee310f91697ecab771067edb4d77 Mon Sep 17 00:00:00 2001 From: Shane Martin Date: Sat, 15 Jan 2022 10:54:57 -0500 Subject: [PATCH 39/39] revert: restore `_registerHook` import --- tests/unit/dom/blur-test.js | 1 + tests/unit/dom/focus-test.js | 7 ++++++- tests/unit/dom/trigger-event-test.js | 1 + tests/unit/dom/trigger-key-event-test.js | 1 + 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/tests/unit/dom/blur-test.js b/tests/unit/dom/blur-test.js index c9af7f135..331395b27 100644 --- a/tests/unit/dom/blur-test.js +++ b/tests/unit/dom/blur-test.js @@ -4,6 +4,7 @@ import { blur, setupContext, teardownContext, + _registerHook, } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import { isIE11, isEdge } from '../../helpers/browser-detect'; diff --git a/tests/unit/dom/focus-test.js b/tests/unit/dom/focus-test.js index 47a669191..abe3d208f 100644 --- a/tests/unit/dom/focus-test.js +++ b/tests/unit/dom/focus-test.js @@ -1,5 +1,10 @@ import { module, test } from 'qunit'; -import { focus, setupContext, teardownContext } from '@ember/test-helpers'; +import { + focus, + setupContext, + teardownContext, + _registerHook, +} from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement, diff --git a/tests/unit/dom/trigger-event-test.js b/tests/unit/dom/trigger-event-test.js index bb96ab1d0..792b5f476 100644 --- a/tests/unit/dom/trigger-event-test.js +++ b/tests/unit/dom/trigger-event-test.js @@ -3,6 +3,7 @@ import { triggerEvent, setupContext, teardownContext, + _registerHook, } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version'; diff --git a/tests/unit/dom/trigger-key-event-test.js b/tests/unit/dom/trigger-key-event-test.js index 2930e7a38..7bdbeb0ac 100644 --- a/tests/unit/dom/trigger-key-event-test.js +++ b/tests/unit/dom/trigger-key-event-test.js @@ -3,6 +3,7 @@ import { triggerKeyEvent, setupContext, teardownContext, + _registerHook, } from '@ember/test-helpers'; import { buildInstrumentedElement, insertElement } from '../../helpers/events'; import hasEmberVersion from '@ember/test-helpers/has-ember-version';