Skip to content

Commit e6a7205

Browse files
Merge pull request #1446 from bendemboski/dom-element-descriptors
Support passing IDOMElementDescriptors as targets
2 parents 5dca0a8 + aa465cc commit e6a7205

32 files changed

+656
-80
lines changed

API.md

+14-14
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ to continue to emulate how actual browsers handle unfocusing a given element.
8787

8888
#### Parameters
8989

90-
* `target` **([string][64] | [Element][65])** the element or selector to unfocus (optional, default `document.activeElement`)
90+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to unfocus (optional, default `document.activeElement`)
9191

9292
#### Examples
9393

@@ -129,7 +129,7 @@ You can use this to specifiy modifier keys as well.
129129

130130
#### Parameters
131131

132-
* `target` **([string][64] | [Element][65])** the element or selector to click on
132+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to click on
133133
* `_options` **MouseEventInit** the options to be merged into the mouse events. (optional, default `{}`)
134134

135135
#### Examples
@@ -185,7 +185,7 @@ Use the `options` hash to change the parameters of the [MouseEvents][67].
185185

186186
#### Parameters
187187

188-
* `target` **([string][64] | [Element][65])** the element or selector to double-click on
188+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to double-click on
189189
* `_options` **MouseEventInit** the options to be merged into the mouse events (optional, default `{}`)
190190

191191
#### Examples
@@ -212,7 +212,7 @@ events on the specified target.
212212

213213
#### Parameters
214214

215-
* `target` **([string][64] | [Element][65])** the element or selector to enter text into
215+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to enter text into
216216
* `text` **[string][64]** the text to fill into the target element
217217

218218
#### Examples
@@ -242,7 +242,7 @@ to continue to emulate how actual browsers handle focusing a given element.
242242

243243
#### Parameters
244244

245-
* `target` **([string][64] | [Element][65])** the element or selector to focus
245+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to focus
246246

247247
#### Examples
248248

@@ -256,11 +256,11 @@ Returns **[Promise][66]\<void>** resolves when the application is settled
256256

257257
### scrollTo
258258

259-
Scrolls DOM element or selector to the given coordinates.
259+
Scrolls DOM element, selector, or descriptor to the given coordinates.
260260

261261
#### Parameters
262262

263-
* `target` **([string][64] | [HTMLElement][68])** the element or selector to trigger scroll on
263+
* `target` **([string][64] | [HTMLElement][68] | IDOMElementDescriptor)** the element, selector, or descriptor to trigger scroll on
264264
* `x` **[Number][69]** x-coordinate
265265
* `y` **[Number][69]** y-coordinate
266266

@@ -284,7 +284,7 @@ multiple attribute is set true on the HTMLSelectElement) then trigger
284284

285285
#### Parameters
286286

287-
* `target` **([string][64] | [Element][65])** the element or selector for the select element
287+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor for the select element
288288
* `options` **([string][64] | [Array][70]<[string][64]>)** the value/values of the items to select
289289
* `keepPreviouslySelected` **[boolean][71]** a flag keep any existing selections (optional, default `false`)
290290

@@ -365,7 +365,7 @@ Use the `options` hash to change the parameters of the tap events.
365365

366366
#### Parameters
367367

368-
* `target` **([string][64] | [Element][65])** the element or selector to tap on
368+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to tap on
369369
* `options` **[Object][72]** the options to be merged into the touch events (optional, default `{}`)
370370

371371
#### Examples
@@ -384,7 +384,7 @@ Triggers an event on the specified target.
384384

385385
#### Parameters
386386

387-
* `target` **([string][64] | [Element][65])** the element or selector to trigger the event on
387+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to trigger the event on
388388
* `eventType` **[string][64]** the type of event to trigger
389389
* `options` **[Object][72]** additional properties to be set on the event
390390

@@ -432,7 +432,7 @@ Optionally the user can also provide a POJO with extra modifiers for the event.
432432

433433
#### Parameters
434434

435-
* `target` **([string][64] | [Element][65])** the element or selector to trigger the event on
435+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to trigger the event on
436436
* `eventType` **(`"keydown"` | `"keyup"` | `"keypress"`)** the type of event to trigger
437437
* `key` **([number][69] | [string][64])** the `keyCode`(number) or `key`(string) of the event being triggered
438438
* `modifiers` **[Object][72]?** the state of various modifier keys (optional, default `DEFAULT_MODIFIERS`)
@@ -466,7 +466,7 @@ per character of the passed text (this may vary on some browsers).
466466

467467
#### Parameters
468468

469-
* `target` **([string][64] | [Element][65])** the element or selector to enter text into
469+
* `target` **([string][64] | [Element][65] | IDOMElementDescriptor)** the element, selector, or descriptor to enter text into
470470
* `text` **[string][64]** the test to fill the element with
471471
* `options` **[Object][72]** {delay: x} (default 50) number of milliseconds to wait per keypress (optional, default `{}`)
472472

@@ -618,7 +618,7 @@ interim DOM states (e.g. loading states, pending promises, etc).
618618

619619
#### Parameters
620620

621-
* `selector` **[string][64]** the selector to wait for
621+
* `target` **([string][64] | IDOMElementDescriptor)** the selector or DOM element descriptor to wait for
622622
* `options` **[Object][72]?** the options to be used (optional, default `{}`)
623623

624624
* `options.timeout` **[number][69]** the time to wait (in ms) for a match (optional, default `1000`)
@@ -876,7 +876,7 @@ Responsible for:
876876
#### Parameters
877877

878878
* `context` **[Object][72]** the context to setup
879-
* `options` **[Object][72]?** options used to override defaults
879+
* `options` **[Object][72]?** options used to override defaults (optional, default `{}`)
880880

881881
* `options.waitForSettled` **[boolean][71]** should the teardown wait for `settled()`ness (optional, default `true`)
882882

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { isDescriptor, lookupDescriptorData } from 'dom-element-descriptors';
2+
import type Target from './-target';
3+
4+
/**
5+
Used internally by the DOM interaction helpers to get a description of a
6+
target for debug/error messaging.
7+
8+
@private
9+
@param {Target} target the target
10+
@returns {string} a description of the target
11+
*/
12+
export default function getDescription(target: Target): string {
13+
let data = isDescriptor(target) ? lookupDescriptorData(target) : null;
14+
if (data) {
15+
return data.description || '<unknown descriptor>';
16+
} else {
17+
return `${target}`;
18+
}
19+
}

addon/addon-test-support/@ember/test-helpers/dom/-get-element.ts

+15-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import getRootElement from './get-root-element';
22
import Target, { isDocument, isElement } from './-target';
3+
import {
4+
type IDOMElementDescriptor,
5+
lookupDescriptorData,
6+
resolveDOMElement,
7+
} from 'dom-element-descriptors';
38

49
function getElement<
510
K extends keyof (HTMLElementTagNameMap | SVGElementTagNameMap)
@@ -12,8 +17,10 @@ function getElement<K extends keyof SVGElementTagNameMap>(
1217
): SVGElementTagNameMap[K] | null;
1318
function getElement(target: string): Element | null;
1419
function getElement(target: Element): Element;
20+
function getElement(target: IDOMElementDescriptor): Element | null;
1521
function getElement(target: Document): Document;
1622
function getElement(target: Window): Document;
23+
function getElement(target: string | IDOMElementDescriptor): Element | null;
1724
function getElement(target: Target): Element | Document | null;
1825
/**
1926
Used internally by the DOM interaction helpers to find one element.
@@ -32,7 +39,14 @@ function getElement(target: Target): Element | Document | null {
3239
} else if (target instanceof Window) {
3340
return target.document;
3441
} else {
35-
throw new Error('Must use an element or a selector string');
42+
let descriptorData = lookupDescriptorData(target);
43+
if (descriptorData) {
44+
return resolveDOMElement(descriptorData);
45+
} else {
46+
throw new Error(
47+
'Must use an element, selector string, or DOM element descriptor'
48+
);
49+
}
3650
}
3751
}
3852

Original file line numberDiff line numberDiff line change
@@ -1,18 +1,35 @@
1+
import {
2+
type IDOMElementDescriptor,
3+
lookupDescriptorData,
4+
resolveDOMElements,
5+
} from 'dom-element-descriptors';
16
import getRootElement from './get-root-element';
27

8+
function getElements(target: string): NodeListOf<Element>;
9+
function getElements(target: IDOMElementDescriptor): Iterable<Element>;
10+
function getElements(target: string | IDOMElementDescriptor): Iterable<Element>;
311
/**
412
Used internally by the DOM interaction helpers to find multiple elements.
513
614
@private
715
@param {string} target the selector to retrieve
816
@returns {NodeList} the matched elements
917
*/
10-
export default function getElements(target: string): NodeListOf<Element> {
18+
function getElements(
19+
target: string | IDOMElementDescriptor
20+
): NodeListOf<Element> | Iterable<Element> {
1121
if (typeof target === 'string') {
1222
let rootElement = getRootElement();
1323

1424
return rootElement.querySelectorAll(target);
1525
} else {
16-
throw new Error('Must use a selector string');
26+
let descriptorData = lookupDescriptorData(target);
27+
if (descriptorData) {
28+
return resolveDOMElements(descriptorData);
29+
} else {
30+
throw new Error('Must use a selector string or DOM element descriptor');
31+
}
1732
}
1833
}
34+
35+
export default getElements;

addon/addon-test-support/@ember/test-helpers/dom/-target.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
type Target = string | Element | Document | Window;
1+
import type { IDOMElementDescriptor } from 'dom-element-descriptors';
2+
3+
type Target = string | Element | IDOMElementDescriptor | Document | Window;
24

35
export default Target;
46

addon/addon-test-support/@ember/test-helpers/dom/blur.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import Target from './-target';
55
import { log } from './-logging';
66
import isFocusable from './-is-focusable';
77
import { runHooks, registerHook } from '../helper-hooks';
8+
import getDescription from './-get-description';
89

910
registerHook('blur', 'start', (target: Target) => {
1011
log('blur', target);
@@ -59,7 +60,7 @@ export function __blur__(
5960
to continue to emulate how actual browsers handle unfocusing a given element.
6061
6162
@public
62-
@param {string|Element} [target=document.activeElement] the element or selector to unfocus
63+
@param {string|Element|IDOMElementDescriptor} [target=document.activeElement] the element, selector, or descriptor to unfocus
6364
@return {Promise<void>} resolves when settled
6465
6566
@example
@@ -77,8 +78,9 @@ export default function blur(
7778
.then(() => {
7879
let element = getElement(target);
7980
if (!element) {
81+
let description = getDescription(target);
8082
throw new Error(
81-
`Element not found when calling \`blur('${target}')\`.`
83+
`Element not found when calling \`blur('${description}')\`.`
8284
);
8385
}
8486

addon/addon-test-support/@ember/test-helpers/dom/click.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import isFormControl from './-is-form-control';
66
import Target, { isWindow } from './-target';
77
import { log } from './-logging';
88
import { runHooks, registerHook } from '../helper-hooks';
9+
import getDescription from './-get-description';
910

1011
const PRIMARY_BUTTON = 1;
1112
const MAIN_BUTTON_PRESSED = 0;
@@ -72,7 +73,7 @@ export function __click__(
7273
You can use this to specify modifier keys as well.
7374
7475
@public
75-
@param {string|Element} target the element or selector to click on
76+
@param {string|Element|IDOMElementDescriptor} target the element, selector, or descriptor to click on
7677
@param {MouseEventInit} _options the options to be merged into the mouse events.
7778
@return {Promise<void>} resolves when settled
7879
@@ -99,13 +100,16 @@ export default function click(
99100
.then(() => runHooks('click', 'start', target, _options))
100101
.then(() => {
101102
if (!target) {
102-
throw new Error('Must pass an element or selector to `click`.');
103+
throw new Error(
104+
'Must pass an element, selector, or descriptor to `click`.'
105+
);
103106
}
104107

105108
let element = getWindowOrElement(target);
106109
if (!element) {
110+
let description = getDescription(target);
107111
throw new Error(
108-
`Element not found when calling \`click('${target}')\`.`
112+
`Element not found when calling \`click('${description}')\`.`
109113
);
110114
}
111115

addon/addon-test-support/@ember/test-helpers/dom/double-click.ts

+7-3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import Target, { isWindow } from './-target';
77
import { log } from './-logging';
88
import isFormControl from './-is-form-control';
99
import { runHooks, registerHook } from '../helper-hooks';
10+
import getDescription from './-get-description';
1011

1112
registerHook('doubleClick', 'start', (target: Target) => {
1213
log('doubleClick', target);
@@ -72,7 +73,7 @@ export function __doubleClick__(
7273
Use the `options` hash to change the parameters of the [MouseEvents](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent).
7374
7475
@public
75-
@param {string|Element} target the element or selector to double-click on
76+
@param {string|Element|IDOMElementDescriptor} target the element, selector, or descriptor to double-click on
7677
@param {MouseEventInit} _options the options to be merged into the mouse events
7778
@return {Promise<void>} resolves when settled
7879
@@ -100,13 +101,16 @@ export default function doubleClick(
100101
.then(() => runHooks('doubleClick', 'start', target, _options))
101102
.then(() => {
102103
if (!target) {
103-
throw new Error('Must pass an element or selector to `doubleClick`.');
104+
throw new Error(
105+
'Must pass an element, selector, or descriptor to `doubleClick`.'
106+
);
104107
}
105108

106109
let element = getWindowOrElement(target);
107110
if (!element) {
111+
let description = getDescription(target);
108112
throw new Error(
109-
`Element not found when calling \`doubleClick('${target}')\`.`
113+
`Element not found when calling \`doubleClick('${description}')\`.`
110114
);
111115
}
112116

addon/addon-test-support/@ember/test-helpers/dom/fill-in.ts

+13-5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import fireEvent from './fire-event';
77
import Target, { isContentEditable } from './-target';
88
import { log } from './-logging';
99
import { runHooks, registerHook } from '../helper-hooks';
10+
import getDescription from './-get-description';
1011

1112
registerHook('fillIn', 'start', (target: Target, text: string) => {
1213
log('fillIn', target, text);
@@ -18,7 +19,7 @@ registerHook('fillIn', 'start', (target: Target, text: string) => {
1819
events on the specified target.
1920
2021
@public
21-
@param {string|Element} target the element or selector to enter text into
22+
@param {string|Element|IDOMElementDescriptor} target the element, selector, or descriptor to enter text into
2223
@param {string} text the text to fill into the target element
2324
@return {Promise<void>} resolves when the application is settled
2425
@@ -34,13 +35,16 @@ export default function fillIn(target: Target, text: string): Promise<void> {
3435
.then(() => runHooks('fillIn', 'start', target, text))
3536
.then(() => {
3637
if (!target) {
37-
throw new Error('Must pass an element or selector to `fillIn`.');
38+
throw new Error(
39+
'Must pass an element, selector, or descriptor to `fillIn`.'
40+
);
3841
}
3942

4043
let element = getElement(target) as Element | HTMLElement;
4144
if (!element) {
45+
let description = getDescription(target);
4246
throw new Error(
43-
`Element not found when calling \`fillIn('${target}')\`.`
47+
`Element not found when calling \`fillIn('${description}')\`.`
4448
);
4549
}
4650

@@ -50,11 +54,15 @@ export default function fillIn(target: Target, text: string): Promise<void> {
5054

5155
if (isFormControl(element)) {
5256
if (element.disabled) {
53-
throw new Error(`Can not \`fillIn\` disabled '${target}'.`);
57+
throw new Error(
58+
`Can not \`fillIn\` disabled '${getDescription(target)}'.`
59+
);
5460
}
5561

5662
if ('readOnly' in element && element.readOnly) {
57-
throw new Error(`Can not \`fillIn\` readonly '${target}'.`);
63+
throw new Error(
64+
`Can not \`fillIn\` readonly '${getDescription(target)}'.`
65+
);
5866
}
5967

6068
guardForMaxlength(element, text, 'fillIn');

0 commit comments

Comments
 (0)