Skip to content

Commit

Permalink
The typeIn helper should not wait for settled promises between i… (#707)
Browse files Browse the repository at this point in the history
The typeIn helper should not wait for settled promises between inputs

Co-authored-by: Robert Jackson <[email protected]>
  • Loading branch information
rwjblue and rwjblue authored Oct 25, 2019
2 parents 2b37be4 + 1c365f3 commit d60115f
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 33 deletions.
70 changes: 43 additions & 27 deletions addon-test-support/@ember/test-helpers/dom/trigger-key-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,47 @@ function keyCodeFromKey(key: string) {
return keyCode !== undefined ? parseInt(keyCode) : undefined;
}

/**
@private
@param {Element | Document} element the element to trigger the key event on
@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
*/
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) };
} 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.`
);
}

let keyCode = keyCodeFromKey(key);
props = { keyCode, which: keyCode, key };
} else {
throw new Error(`Must provide a \`key\` or \`keyCode\` to \`triggerKeyEvent\``);
}

let options = assign(props, modifiers);

fireEvent(element, eventType, options);
}

/**
Triggers a keyboard event of given type in the target element.
It also requires the developer to provide either a string with the [`key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values)
Expand All @@ -128,7 +169,7 @@ function keyCodeFromKey(key: string) {
@param {boolean} [modifiers.altKey=false] if true the generated event will indicate the alt key was pressed during the key event
@param {boolean} [modifiers.shiftKey=false] if true the generated event will indicate the shift key was pressed during the key event
@param {boolean} [modifiers.metaKey=false] if true the generated event will indicate the meta key was pressed during the key event
@return {Promise<void>} resolves when the application is settled
@return {Promise<void>} resolves when the application is settled unless awaitSettled is false
@example
<caption>
Expand Down Expand Up @@ -163,32 +204,7 @@ export default function triggerKeyEvent(
);
}

let props;
if (typeof key === 'number') {
props = { keyCode: key, which: key, key: keyFromKeyCodeAndModifiers(key, 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.`
);
}

let keyCode = keyCodeFromKey(key);
props = { keyCode, which: keyCode, key };
} else {
throw new Error(`Must provide a \`key\` or \`keyCode\` to \`triggerKeyEvent\``);
}

let options = assign(props, modifiers);

fireEvent(element, eventType, options);
__triggerKeyEvent__(element, eventType, key, modifiers);

return settled();
});
Expand Down
13 changes: 7 additions & 6 deletions addon-test-support/@ember/test-helpers/dom/type-in.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import isFocusable from './-is-focusable';
import { Promise } from 'rsvp';
import fireEvent from './fire-event';
import Target from './-target';
import triggerKeyEvent from './trigger-key-event';
import { __triggerKeyEvent__ } from './trigger-key-event';

export interface Options {
delay?: number;
Expand All @@ -29,12 +29,12 @@ export interface Options {
* @param {string} text the test to fill the element with
* @param {Object} options {delay: x} (default 50) number of milliseconds to wait per keypress
* @return {Promise<void>} resolves when the application is settled
*
*
* @example
* <caption>
* Emulating typing in an input using `typeIn`
* </caption>
*
*
* typeIn('hello world');
*/
export default function typeIn(target: Target, text: string, options: Options = {}): Promise<void> {
Expand Down Expand Up @@ -82,13 +82,14 @@ function keyEntry(element: FormControl, character: string): () => void {
let characterKey = character.toUpperCase();

return function() {
return triggerKeyEvent(element, 'keydown', characterKey, options)
.then(() => triggerKeyEvent(element, 'keypress', characterKey, options))
return nextTickPromise()
.then(() => __triggerKeyEvent__(element, 'keydown', characterKey, options))
.then(() => __triggerKeyEvent__(element, 'keypress', characterKey, options))
.then(() => {
element.value = element.value + character;
fireEvent(element, 'input');
})
.then(() => triggerKeyEvent(element, 'keyup', characterKey, options));
.then(() => __triggerKeyEvent__(element, 'keyup', characterKey, options));
};
}

Expand Down
21 changes: 21 additions & 0 deletions tests/unit/dom/type-in-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { module, test } from 'qunit';
import { typeIn, setupContext, teardownContext } from '@ember/test-helpers';
import { buildInstrumentedElement } 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';

/*
Expand Down Expand Up @@ -153,4 +155,23 @@ module('DOM Helper: typeIn', function(hooks) {
assert.strictEqual(document.activeElement, element, 'activeElement updated');
assert.equal(element.value, 'foo');
});

test('does not wait for other promises to settle', async function(assert) {
element = buildInstrumentedElement('input');

let runcount = 0;
let onInput = function() {
return Promise.resolve().then(() => runcount++);
};

element.oninput = function() {
// debounce 2 seconds for easy visualization in test
debounce(onInput, 2000);
};

await typeIn(element, 'foo');

assert.verifySteps(expectedEvents);
assert.equal(runcount, 1, 'debounced function only called once');
});
});

0 comments on commit d60115f

Please sign in to comment.