Skip to content

Commit

Permalink
Merge pull request #943 from emberjs/fix-trigger-event
Browse files Browse the repository at this point in the history
  • Loading branch information
rwjblue committed Nov 12, 2020
2 parents 2f3a0d3 + d8e2c37 commit 2c825ed
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import getElement from './-get-element';
import Target, { isWindow } from './-target';

/**
Used internally by the DOM interaction helpers to find either window or an element.
@private
@param {string|Element} target the window, an element or selector to retrieve
@returns {Element|Window} the target or selector
*/
export function getWindowOrElement(target: Target): Element | Document | Window | null {
if (isWindow(target)) {
return target as Window;
}

return getElement(target);
}
8 changes: 6 additions & 2 deletions addon-test-support/@ember/test-helpers/dom/-is-focusable.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import isFormControl from './-is-form-control';
import { isDocument, isContentEditable } from './-target';
import { isDocument, isContentEditable, isWindow } from './-target';

const FOCUSABLE_TAGS = ['A'];

Expand All @@ -16,8 +16,12 @@ function isFocusableElement(element: Element): element is FocusableElement {
@returns {boolean} `true` when the element is focusable, `false` otherwise
*/
export default function isFocusable(
element: HTMLElement | SVGElement | Element | Document
element: HTMLElement | SVGElement | Element | Document | Window
): element is HTMLElement | SVGElement {
if (isWindow(element)) {
return false;
}

if (isDocument(element)) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isDocument } from './-target';
import { isDocument, isWindow } from './-target';

const FORM_CONTROL_TAGS = ['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA'];

Expand All @@ -13,8 +13,11 @@ export type FormControl =
@param {Element} element the element to check
@returns {boolean} `true` when the element is a form control, `false` otherwise
*/
export default function isFormControl(element: Element | Document): element is FormControl {
export default function isFormControl(
element: Element | Document | Window
): element is FormControl {
return (
!isWindow(element) &&
!isDocument(element) &&
FORM_CONTROL_TAGS.indexOf(element.tagName) > -1 &&
(element as HTMLInputElement).type !== 'hidden'
Expand Down
5 changes: 5 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/-target.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ export function isElement(target: any): target is Element {
return target.nodeType === Node.ELEMENT_NODE;
}

// eslint-disable-next-line require-jsdoc
export function isWindow(target: Target): target is Window {
return target instanceof Window;
}

// eslint-disable-next-line require-jsdoc
export function isDocument(target: any): target is Document {
return target.nodeType === Node.DOCUMENT_NODE;
Expand Down
6 changes: 3 additions & 3 deletions addon-test-support/@ember/test-helpers/dom/click.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assign } from '@ember/polyfills';
import getElement from './-get-element';
import { getWindowOrElement } from './-get-window-or-element';
import fireEvent from './fire-event';
import { __focus__ } from './focus';
import settled from '../settled';
Expand Down Expand Up @@ -31,7 +31,7 @@ export const DEFAULT_CLICK_OPTIONS = {
@param {Element} element the element to click on
@param {MouseEventInit} options the options to be merged into the mouse events
*/
export function __click__(element: Element | Document, options: MouseEventInit): void {
export function __click__(element: Element | Document | Window, options: MouseEventInit): void {
fireEvent(element, 'mousedown', options);

if (isFocusable(element)) {
Expand Down Expand Up @@ -97,7 +97,7 @@ export default function click(target: Target, _options: MouseEventInit = {}): Pr
throw new Error('Must pass an element or selector to `click`.');
}

let element = getElement(target);
let element = getWindowOrElement(target);
if (!element) {
throw new Error(`Element not found when calling \`click('${target}')\`.`);
}
Expand Down
9 changes: 6 additions & 3 deletions addon-test-support/@ember/test-helpers/dom/double-click.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assign } from '@ember/polyfills';
import getElement from './-get-element';
import { getWindowOrElement } from './-get-window-or-element';
import fireEvent from './fire-event';
import { __focus__ } from './focus';
import settled from '../settled';
Expand All @@ -20,7 +20,10 @@ registerHook('doubleClick', 'start', (target: Target) => {
@param {Element} element the element to double-click on
@param {MouseEventInit} options the options to be merged into the mouse events
*/
export function __doubleClick__(element: Element | Document, options: MouseEventInit): void {
export function __doubleClick__(
element: Element | Document | Window,
options: MouseEventInit
): void {
fireEvent(element, 'mousedown', options);

if (isFocusable(element)) {
Expand Down Expand Up @@ -98,7 +101,7 @@ export default function doubleClick(target: Target, _options: MouseEventInit = {
throw new Error('Must pass an element or selector to `doubleClick`.');
}

let element = getElement(target);
let element = getWindowOrElement(target);
if (!element) {
throw new Error(`Element not found when calling \`doubleClick('${target}')\`.`);
}
Expand Down
4 changes: 2 additions & 2 deletions addon-test-support/@ember/test-helpers/dom/trigger-event.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import getElement from './-get-element';
import { getWindowOrElement } from './-get-window-or-element';
import fireEvent from './fire-event';
import settled from '../settled';
import { nextTickPromise } from '../-utils';
Expand Down Expand Up @@ -72,7 +72,7 @@ export default function triggerEvent(
throw new Error(`Must provide an \`eventType\` to \`triggerEvent\``);
}

let element = getElement(target);
let element = getWindowOrElement(target);
if (!element) {
throw new Error(`Element not found when calling \`triggerEvent('${target}', ...)\`.`);
}
Expand Down
16 changes: 16 additions & 0 deletions tests/unit/dom/click-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,19 @@ module('DOM Helper: click', function (hooks) {
});
});
});

module('DOM Helper: click with window', function () {
test('clicking window without context set fires the given event type', async function (assert) {
let listener = e => {
assert.step('click');
assert.ok(e instanceof Event, `click listener receives a native event`);
};
window.addEventListener('click', listener);

await click(window, 'click');

assert.verifySteps(['click']);

window.removeEventListener('click', listener);
});
});
16 changes: 16 additions & 0 deletions tests/unit/dom/double-click-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -278,3 +278,19 @@ module('DOM Helper: doubleClick', function (hooks) {
});
});
});

module('DOM Helper: doubleClick with window', function () {
test('double clicking window without context set fires the given event type', async function (assert) {
let listener = e => {
assert.step('click');
assert.ok(e instanceof Event, `click listener receives a native event`);
};
window.addEventListener('click', listener);

await doubleClick(window, 'click');

assert.verifySteps(['click', 'click']);

window.removeEventListener('click', listener);
});
});
16 changes: 16 additions & 0 deletions tests/unit/dom/trigger-event-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -171,3 +171,19 @@ module('DOM Helper: triggerEvent', function (hooks) {
assert.verifySteps(['inner: mouseenter', 'outer: mouseenter', 'mouseenter']);
});
});

module('DOM Helper: triggerEvent with window', function () {
test('triggering event via window without context set fires the given event type', async function (assert) {
let listener = e => {
assert.step('resize');
assert.ok(e instanceof Event, `resize listener receives a native event`);
};
window.addEventListener('resize', listener);

await triggerEvent(window, 'resize');

assert.verifySteps(['resize']);

window.removeEventListener('resize', listener);
});
});

0 comments on commit 2c825ed

Please sign in to comment.