Skip to content

Commit

Permalink
Merge pull request #258 from rwjblue/dom-helpers
Browse files Browse the repository at this point in the history
Bring over DOM helper implementation.
  • Loading branch information
rwjblue authored Dec 15, 2017
2 parents df72e53 + 1848f83 commit 3be6f1b
Show file tree
Hide file tree
Showing 31 changed files with 1,921 additions and 231 deletions.
9 changes: 9 additions & 0 deletions addon-test-support/@ember/test-helpers/-utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Promise } from 'rsvp';

export const nextTick = setTimeout;

export function nextTickPromise() {
return new Promise(resolve => {
nextTick(resolve);
});
}
21 changes: 21 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/-get-element.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { getContext } from '../setup-context';

export default function getElement(selectorOrElement) {
if (
selectorOrElement instanceof Window ||
selectorOrElement instanceof Document ||
selectorOrElement instanceof Element
) {
return selectorOrElement;
} else if (typeof selectorOrElement === 'string') {
let context = getContext();
let rootElement = context && context.element;
if (!rootElement) {
throw new Error(`Must setup rendering context before attempting to interact with elements.`);
}

return rootElement.querySelector(selectorOrElement);
} else {
throw new Error('Must use an element or a selector string');
}
}
14 changes: 14 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/-is-focusable.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import isFormControl from './-is-form-control';

const FOCUSABLE_TAGS = ['A'];
export default function isFocusable(element) {
if (
isFormControl(element) ||
element.isContentEditable ||
FOCUSABLE_TAGS.indexOf(element.tagName) > -1
) {
return true;
}

return element.hasAttribute('tabindex');
}
11 changes: 11 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/-is-form-control.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const FORM_CONTROL_TAGS = ['INPUT', 'BUTTON', 'SELECT', 'TEXTAREA'];

export default function isFormControl(el) {
let { tagName, type } = el;

if (type === 'hidden') {
return false;
}

return FORM_CONTROL_TAGS.indexOf(tagName) > -1;
}
49 changes: 49 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/blur.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import getElement from './-get-element';
import fireEvent from './fire-event';
import settled from '../settled';
import isFocusable from './-is-focusable';
import { nextTickPromise } from '../-utils';

/**
@private
@method __blur__
@param {Element} element
*/
export function __blur__(element) {
let browserIsNotFocused = document.hasFocus && !document.hasFocus();

// makes `document.activeElement` be `body`.
// If the browser is focused, it also fires a blur event
element.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) {
fireEvent(element, 'blur', { bubbles: false });
fireEvent(element, 'focusout');
}
}

/**
@method blur
@param {String|Element} [target=document.activeElement] the element to blur
@return {Promise<void>}
@public
*/
export default function blur(target = document.activeElement) {
return nextTickPromise().then(() => {
let element = getElement(target);
if (!element) {
throw new Error(`Element not found when calling \`blur('${target}')\`.`);
}

if (!isFocusable(element)) {
throw new Error(`${target} is not focusable`);
}

__blur__(element);

return settled();
});
}
44 changes: 44 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/click.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import getElement from './-get-element';
import fireEvent from './fire-event';
import { __focus__ } from './focus';
import settled from '../settled';
import isFocusable from './-is-focusable';
import { nextTickPromise } from '../-utils';

/**
@private
@method __click__
@param {Element} element
*/
export function __click__(element) {
fireEvent(element, 'mousedown');

if (isFocusable(element)) {
__focus__(element);
}

fireEvent(element, 'mouseup');
fireEvent(element, 'click');
}

/**
@method click
@param {String|Element} target
@return {Promise<void>}
@public
*/
export default function click(target) {
return nextTickPromise().then(() => {
if (!target) {
throw new Error('Must pass an element or selector to `click`.');
}

let element = getElement(target);
if (!element) {
throw new Error(`Element not found when calling \`click('${target}')\`.`);
}

__click__(element);
return settled();
});
}
47 changes: 47 additions & 0 deletions addon-test-support/@ember/test-helpers/dom/fill-in.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import getElement from './-get-element';
import isFormControl from './-is-form-control';
import { __focus__ } from './focus';
import settled from '../settled';
import fireEvent from './fire-event';
import { nextTickPromise } from '../-utils';

/*
@method fillIn
@param {String|Element} target
@param {String} text
@return {Promise<void>}
@public
*/
export default function fillIn(target, text) {
return nextTickPromise().then(() => {
if (!target) {
throw new Error('Must pass an element or selector to `fillIn`.');
}

let element = getElement(target);
if (!element) {
throw new Error(`Element not found when calling \`fillIn('${target}')\`.`);
}

if (!isFormControl(element) && !element.isContentEditable) {
throw new Error('`fillIn` is only usable on form controls or contenteditable elements.');
}

if (!text) {
throw new Error('Must provide `text` when calling `fillIn`.');
}

__focus__(element);

if (element.isContentEditable) {
element.innerHTML = text;
} else {
element.value = text;
}

fireEvent(element, 'input');
fireEvent(element, 'change');

return settled();
});
}
Loading

0 comments on commit 3be6f1b

Please sign in to comment.