Skip to content

Commit

Permalink
feat(cdk/testing/testbed): emit pointer events for test element click
Browse files Browse the repository at this point in the history
Currently, test elements for the testbed harness environment only
emit `mousedown` and `mouseup` events when a click is simulated.

Authors of components technically could already rely on the
more convenient pointer events. To handle this, we also emit
pointer events similar to what actual browsers do.
  • Loading branch information
devversion authored and jelbourn committed Apr 29, 2020
1 parent 666417d commit 9cd1891
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/cdk/testing/testbed/fake-events/dispatch-events.ts
Expand Up @@ -11,6 +11,7 @@ import {
createFakeEvent,
createKeyboardEvent,
createMouseEvent,
createPointerEvent,
createTouchEvent,
} from './event-objects';

Expand Down Expand Up @@ -49,6 +50,15 @@ export function dispatchMouseEvent(node: Node, type: string, clientX = 0, client
return dispatchEvent(node, createMouseEvent(type, clientX, clientY));
}

/**
* Shorthand to dispatch a pointer event on the specified coordinates.
* @docs-private
*/
export function dispatchPointerEvent(node: Node, type: string, clientX = 0, clientY = 0,
options?: PointerEventInit): PointerEvent {
return dispatchEvent(node, createPointerEvent(type, clientX, clientY, options)) as PointerEvent;
}

/**
* Shorthand to dispatch a touch event on the specified coordinates.
* @docs-private
Expand Down
22 changes: 22 additions & 0 deletions src/cdk/testing/testbed/fake-events/event-objects.ts
Expand Up @@ -52,6 +52,28 @@ export function createMouseEvent(type: string, clientX = 0, clientY = 0, button
return event;
}

/**
* Creates a browser `PointerEvent` with the specified options. Pointer events
* by default will appear as if they are the primary pointer of their type.
* https://www.w3.org/TR/pointerevents2/#dom-pointerevent-isprimary.
*
* For example, if pointer events for a multi-touch interaction are created, the non-primary
* pointer touches would need to be represented by non-primary pointer events.
*
* @docs-private
*/
export function createPointerEvent(type: string, clientX = 0, clientY = 0,
options: PointerEventInit = {isPrimary: true}) {
return new PointerEvent(type, {
bubbles: true,
cancelable: true,
view: window,
clientX,
clientY,
...options,
});
}

/**
* Creates a browser TouchEvent with the specified pointer coordinates.
* @docs-private
Expand Down
15 changes: 15 additions & 0 deletions src/cdk/testing/testbed/unit-test-element.ts
Expand Up @@ -11,6 +11,7 @@ import {ElementDimensions, ModifierKeys, TestElement, TestKey} from '@angular/cd
import {
clearElement,
dispatchMouseEvent,
dispatchPointerEvent,
isTextInput,
triggerBlur,
triggerFocus,
Expand Down Expand Up @@ -77,9 +78,23 @@ export class UnitTestElement implements TestElement {
// supported by mouse events and could lead to unexpected results.
const clientX = Math.round(left + relativeX);
const clientY = Math.round(top + relativeY);

// The latest versions of all browsers we support have the new `PointerEvent` API.
// Though since we capture the two most recent versions of these browsers, we also
// need to support Safari 12 at time of writing. Safari 12 does not have support for this,
// so we need to conditionally create and dispatch these events based on feature detection.
const emitPointerEvents = window.PointerEvent !== undefined;

if (emitPointerEvents) {
dispatchPointerEvent(this.element, 'pointerdown', clientX, clientY);
}
dispatchMouseEvent(this.element, 'mousedown', clientX, clientY);
if (emitPointerEvents) {
dispatchMouseEvent(this.element, 'pointerup', clientX, clientY);
}
dispatchMouseEvent(this.element, 'mouseup', clientX, clientY);
dispatchMouseEvent(this.element, 'click', clientX, clientY);

await this._stabilize();
}

Expand Down

0 comments on commit 9cd1891

Please sign in to comment.