Skip to content

Commit e0033ad

Browse files
committed
main - 207bc6c build: clean-up to use fine-grained targets for faster rebuilds
1 parent 57a65e3 commit e0033ad

22 files changed

+453
-674
lines changed

fesm2022/test-element-errors-83375db9.mjs

Lines changed: 0 additions & 10 deletions
This file was deleted.

fesm2022/test-element-errors-83375db9.mjs.map

Lines changed: 0 additions & 1 deletion
This file was deleted.

fesm2022/testing.mjs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
export { C as ComponentHarness, a as ContentContainerComponentHarness, b as HarnessEnvironment, H as HarnessPredicate, T as TestKey, _ as _getTextWithExcludedElements, h as handleAutoChangeDetectionStatus, m as manualChangeDetection, p as parallel, s as stopHandlingAutoChangeDetectionStatus } from './text-filtering-e9a6b8d9.mjs';
2-
export { g as getNoKeysSpecifiedError } from './test-element-errors-83375db9.mjs';
1+
export { C as ComponentHarness, a as ContentContainerComponentHarness, b as HarnessEnvironment, H as HarnessPredicate, T as TestKey, _ as _getTextWithExcludedElements, g as getNoKeysSpecifiedError, h as handleAutoChangeDetectionStatus, m as manualChangeDetection, p as parallel, s as stopHandlingAutoChangeDetectionStatus } from './text-filtering-55cbd0d9.mjs';
32
import 'rxjs';
43
//# sourceMappingURL=testing.mjs.map

fesm2022/testing.mjs.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fesm2022/testing/private.mjs

Lines changed: 0 additions & 34 deletions
This file was deleted.

fesm2022/testing/private.mjs.map

Lines changed: 0 additions & 1 deletion
This file was deleted.

fesm2022/testing/selenium-webdriver.mjs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as webdriver from 'selenium-webdriver';
2-
import { g as getNoKeysSpecifiedError } from '../test-element-errors-83375db9.mjs';
3-
import { T as TestKey, _ as _getTextWithExcludedElements, b as HarnessEnvironment } from '../text-filtering-e9a6b8d9.mjs';
2+
import { T as TestKey, g as getNoKeysSpecifiedError, _ as _getTextWithExcludedElements, b as HarnessEnvironment } from '../text-filtering-55cbd0d9.mjs';
43
import 'rxjs';
54

65
/**

fesm2022/testing/selenium-webdriver.mjs.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

fesm2022/testing/testbed.mjs

Lines changed: 289 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
import { flush } from '@angular/core/testing';
22
import { takeWhile } from 'rxjs/operators';
33
import { BehaviorSubject } from 'rxjs';
4-
import { l as triggerBlur, m as isTextInput, o as clearElement, t as triggerFocus, c as dispatchMouseEvent, n as typeInElement, a as dispatchFakeEvent, k as createFakeEvent, d as dispatchEvent, e as dispatchPointerEvent } from '../type-in-element-de7fd3bb.mjs';
5-
import { _ as _getTextWithExcludedElements, T as TestKey, b as HarnessEnvironment, h as handleAutoChangeDetectionStatus, s as stopHandlingAutoChangeDetectionStatus } from '../text-filtering-e9a6b8d9.mjs';
6-
import { B as BACKSPACE, T as TAB, h as ENTER, S as SHIFT, C as CONTROL, A as ALT, e as ESCAPE, b as PAGE_UP, P as PAGE_DOWN, E as END, H as HOME, L as LEFT_ARROW, U as UP_ARROW, R as RIGHT_ARROW, D as DOWN_ARROW, I as INSERT, n as DELETE, au as F1, av as F2, aw as F3, ax as F4, ay as F5, az as F6, aA as F7, aB as F8, aC as F9, aD as F10, aE as F11, aF as F12, a as META, aT as COMMA } from '../keycodes-0e4398c6.mjs';
7-
import '../test-element-errors-83375db9.mjs';
4+
import { g as getNoKeysSpecifiedError, _ as _getTextWithExcludedElements, T as TestKey, b as HarnessEnvironment, h as handleAutoChangeDetectionStatus, s as stopHandlingAutoChangeDetectionStatus } from '../text-filtering-55cbd0d9.mjs';
5+
import { aV as PERIOD, B as BACKSPACE, T as TAB, h as ENTER, S as SHIFT, C as CONTROL, A as ALT, e as ESCAPE, b as PAGE_UP, P as PAGE_DOWN, E as END, H as HOME, L as LEFT_ARROW, U as UP_ARROW, R as RIGHT_ARROW, D as DOWN_ARROW, I as INSERT, n as DELETE, au as F1, av as F2, aw as F3, ax as F4, ay as F5, az as F6, aA as F7, aB as F8, aC as F9, aD as F10, aE as F11, aF as F12, a as META, aT as COMMA } from '../keycodes-0e4398c6.mjs';
86

97
/** Unique symbol that is used to patch a property to a proxy zone. */
108
const stateObservableSymbol = Symbol('ProxyZone_PATCHED#stateObservable');
@@ -81,6 +79,293 @@ class TaskStateZoneInterceptor {
8179
}
8280
}
8381

82+
/** Used to generate unique IDs for events. */
83+
/**
84+
* Creates a browser MouseEvent with the specified options.
85+
* @docs-private
86+
*/
87+
function createMouseEvent(type, clientX = 0, clientY = 0, offsetX = 0, offsetY = 0, button = 0, modifiers = {}) {
88+
// Note: We cannot determine the position of the mouse event based on the screen
89+
// because the dimensions and position of the browser window are not available
90+
// To provide reasonable `screenX` and `screenY` coordinates, we simply use the
91+
// client coordinates as if the browser is opened in fullscreen.
92+
const screenX = clientX;
93+
const screenY = clientY;
94+
const event = new MouseEvent(type, {
95+
bubbles: true,
96+
cancelable: true,
97+
composed: true, // Required for shadow DOM events.
98+
view: window,
99+
detail: 1,
100+
relatedTarget: null,
101+
screenX,
102+
screenY,
103+
clientX,
104+
clientY,
105+
ctrlKey: modifiers.control,
106+
altKey: modifiers.alt,
107+
shiftKey: modifiers.shift,
108+
metaKey: modifiers.meta,
109+
button: button,
110+
buttons: 1,
111+
});
112+
// The `MouseEvent` constructor doesn't allow us to pass these properties into the constructor.
113+
// Override them to `1`, because they're used for fake screen reader event detection.
114+
if (offsetX != null) {
115+
defineReadonlyEventProperty(event, 'offsetX', offsetX);
116+
}
117+
if (offsetY != null) {
118+
defineReadonlyEventProperty(event, 'offsetY', offsetY);
119+
}
120+
return event;
121+
}
122+
/**
123+
* Creates a browser `PointerEvent` with the specified options. Pointer events
124+
* by default will appear as if they are the primary pointer of their type.
125+
* https://www.w3.org/TR/pointerevents2/#dom-pointerevent-isprimary.
126+
*
127+
* For example, if pointer events for a multi-touch interaction are created, the non-primary
128+
* pointer touches would need to be represented by non-primary pointer events.
129+
*
130+
* @docs-private
131+
*/
132+
function createPointerEvent(type, clientX = 0, clientY = 0, offsetX, offsetY, options = { isPrimary: true }) {
133+
const event = new PointerEvent(type, {
134+
bubbles: true,
135+
cancelable: true,
136+
composed: true, // Required for shadow DOM events.
137+
view: window,
138+
clientX,
139+
clientY,
140+
...options,
141+
});
142+
if (offsetX != null) {
143+
defineReadonlyEventProperty(event, 'offsetX', offsetX);
144+
}
145+
if (offsetY != null) {
146+
defineReadonlyEventProperty(event, 'offsetY', offsetY);
147+
}
148+
return event;
149+
}
150+
/**
151+
* Creates a keyboard event with the specified key and modifiers.
152+
* @docs-private
153+
*/
154+
function createKeyboardEvent(type, keyCode = 0, key = '', modifiers = {}, code = '') {
155+
return new KeyboardEvent(type, {
156+
bubbles: true,
157+
cancelable: true,
158+
composed: true, // Required for shadow DOM events.
159+
view: window,
160+
keyCode,
161+
key,
162+
shiftKey: modifiers.shift,
163+
metaKey: modifiers.meta,
164+
altKey: modifiers.alt,
165+
ctrlKey: modifiers.control,
166+
code,
167+
});
168+
}
169+
/**
170+
* Creates a fake event object with any desired event type.
171+
* @docs-private
172+
*/
173+
function createFakeEvent(type, bubbles = false, cancelable = true, composed = true) {
174+
return new Event(type, { bubbles, cancelable, composed });
175+
}
176+
/**
177+
* Defines a readonly property on the given event object. Readonly properties on an event object
178+
* are always set as configurable as that matches default readonly properties for DOM event objects.
179+
*/
180+
function defineReadonlyEventProperty(event, propertyName, value) {
181+
Object.defineProperty(event, propertyName, { get: () => value, configurable: true });
182+
}
183+
184+
/**
185+
* Utility to dispatch any event on a Node.
186+
* @docs-private
187+
*/
188+
function dispatchEvent(node, event) {
189+
node.dispatchEvent(event);
190+
return event;
191+
}
192+
/**
193+
* Shorthand to dispatch a fake event on a specified node.
194+
* @docs-private
195+
*/
196+
function dispatchFakeEvent(node, type, bubbles) {
197+
return dispatchEvent(node, createFakeEvent(type, bubbles));
198+
}
199+
/**
200+
* Shorthand to dispatch a keyboard event with a specified key code and
201+
* optional modifiers.
202+
* @docs-private
203+
*/
204+
function dispatchKeyboardEvent(node, type, keyCode, key, modifiers, code) {
205+
return dispatchEvent(node, createKeyboardEvent(type, keyCode, key, modifiers, code));
206+
}
207+
/**
208+
* Shorthand to dispatch a mouse event on the specified coordinates.
209+
* @docs-private
210+
*/
211+
function dispatchMouseEvent(node, type, clientX = 0, clientY = 0, offsetX, offsetY, button, modifiers) {
212+
return dispatchEvent(node, createMouseEvent(type, clientX, clientY, offsetX, offsetY, button, modifiers));
213+
}
214+
/**
215+
* Shorthand to dispatch a pointer event on the specified coordinates.
216+
* @docs-private
217+
*/
218+
function dispatchPointerEvent(node, type, clientX = 0, clientY = 0, offsetX, offsetY, options) {
219+
return dispatchEvent(node, createPointerEvent(type, clientX, clientY, offsetX, offsetY, options));
220+
}
221+
222+
function triggerFocusChange(element, event) {
223+
let eventFired = false;
224+
const handler = () => (eventFired = true);
225+
element.addEventListener(event, handler);
226+
element[event]();
227+
element.removeEventListener(event, handler);
228+
if (!eventFired) {
229+
dispatchFakeEvent(element, event);
230+
}
231+
}
232+
/** @docs-private */
233+
function triggerFocus(element) {
234+
triggerFocusChange(element, 'focus');
235+
}
236+
/** @docs-private */
237+
function triggerBlur(element) {
238+
triggerFocusChange(element, 'blur');
239+
}
240+
241+
/** Input types for which the value can be entered incrementally. */
242+
const incrementalInputTypes = new Set([
243+
'text',
244+
'email',
245+
'hidden',
246+
'password',
247+
'search',
248+
'tel',
249+
'url',
250+
]);
251+
/**
252+
* Manual mapping of some common characters to their `code` in a keyboard event. Non-exhaustive, see
253+
* the tables on MDN for more info: https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode
254+
*/
255+
const charsToCodes = {
256+
' ': 'Space',
257+
'.': 'Period',
258+
',': 'Comma',
259+
'`': 'Backquote',
260+
'-': 'Minus',
261+
'=': 'Equal',
262+
'[': 'BracketLeft',
263+
']': 'BracketRight',
264+
'\\': 'Backslash',
265+
'/': 'Slash',
266+
"'": 'Quote',
267+
'"': 'Quote',
268+
';': 'Semicolon',
269+
};
270+
/**
271+
* Determines the `KeyboardEvent.key` from a character. See #27034 and
272+
* https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
273+
*/
274+
function getKeyboardEventCode(char) {
275+
if (char.length !== 1) {
276+
return '';
277+
}
278+
const charCode = char.charCodeAt(0);
279+
// Key is a letter between a and z, uppercase or lowercase.
280+
if ((charCode >= 97 && charCode <= 122) || (charCode >= 65 && charCode <= 90)) {
281+
return `Key${char.toUpperCase()}`;
282+
}
283+
// Digits from 0 to 9.
284+
if (48 <= charCode && charCode <= 57) {
285+
return `Digit${char}`;
286+
}
287+
return charsToCodes[char] ?? '';
288+
}
289+
/**
290+
* Checks whether the given Element is a text input element.
291+
* @docs-private
292+
*/
293+
function isTextInput(element) {
294+
const nodeName = element.nodeName.toLowerCase();
295+
return nodeName === 'input' || nodeName === 'textarea';
296+
}
297+
function typeInElement(element, ...modifiersAndKeys) {
298+
const first = modifiersAndKeys[0];
299+
let modifiers;
300+
let rest;
301+
if (first !== undefined &&
302+
typeof first !== 'string' &&
303+
first.keyCode === undefined &&
304+
first.key === undefined) {
305+
modifiers = first;
306+
rest = modifiersAndKeys.slice(1);
307+
}
308+
else {
309+
modifiers = {};
310+
rest = modifiersAndKeys;
311+
}
312+
const isInput = isTextInput(element);
313+
const inputType = element.getAttribute('type') || 'text';
314+
const keys = rest
315+
.map(k => typeof k === 'string'
316+
? k.split('').map(c => ({
317+
keyCode: c.toUpperCase().charCodeAt(0),
318+
key: c,
319+
code: getKeyboardEventCode(c),
320+
}))
321+
: [k])
322+
.reduce((arr, k) => arr.concat(k), []);
323+
// Throw an error if no keys have been specified. Calling this function with no
324+
// keys should not result in a focus event being dispatched unexpectedly.
325+
if (keys.length === 0) {
326+
throw getNoKeysSpecifiedError();
327+
}
328+
// We simulate the user typing in a value by incrementally assigning the value below. The problem
329+
// is that for some input types, the browser won't allow for an invalid value to be set via the
330+
// `value` property which will always be the case when going character-by-character. If we detect
331+
// such an input, we have to set the value all at once or listeners to the `input` event (e.g.
332+
// the `ReactiveFormsModule` uses such an approach) won't receive the correct value.
333+
const enterValueIncrementally = inputType === 'number'
334+
? // The value can be set character by character in number inputs if it doesn't have any decimals.
335+
keys.every(key => key.key !== '.' && key.key !== '-' && key.keyCode !== PERIOD)
336+
: incrementalInputTypes.has(inputType);
337+
triggerFocus(element);
338+
// When we aren't entering the value incrementally, assign it all at once ahead
339+
// of time so that any listeners to the key events below will have access to it.
340+
if (!enterValueIncrementally) {
341+
element.value = keys.reduce((value, key) => value + (key.key || ''), '');
342+
}
343+
for (const key of keys) {
344+
dispatchKeyboardEvent(element, 'keydown', key.keyCode, key.key, modifiers, key.code);
345+
dispatchKeyboardEvent(element, 'keypress', key.keyCode, key.key, modifiers, key.code);
346+
if (isInput && key.key && key.key.length === 1) {
347+
if (enterValueIncrementally) {
348+
element.value += key.key;
349+
dispatchFakeEvent(element, 'input');
350+
}
351+
}
352+
dispatchKeyboardEvent(element, 'keyup', key.keyCode, key.key, modifiers, key.code);
353+
}
354+
// Since we weren't dispatching `input` events while sending the keys, we have to do it now.
355+
if (!enterValueIncrementally) {
356+
dispatchFakeEvent(element, 'input');
357+
}
358+
}
359+
/**
360+
* Clears the text in an input or textarea element.
361+
* @docs-private
362+
*/
363+
function clearElement(element) {
364+
triggerFocus(element);
365+
element.value = '';
366+
dispatchFakeEvent(element, 'input');
367+
}
368+
84369
/** Maps `TestKey` constants to the `keyCode` and `key` values used by native browser events. */
85370
const keyMap = {
86371
[TestKey.BACKSPACE]: { keyCode: BACKSPACE, key: 'Backspace', code: 'Backspace' },

fesm2022/testing/testbed.mjs.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)