Skip to content

Commit 817bddf

Browse files
committed
perf(cdk/testing): Improve performance of clicking in unit tests.
This PR changes the semantics of `TestElement.click()` when called with no arguments. Rather than guarantee clicking the center of the element, the location of the click will be up to the particular `HarnessEnvironment`. This allows the `TestbedHarnessEnvironment` to skip the expensive and often unnecessary calculation to determine the center of the element. To replace the old behavior of `TestElement.click()`, the PR adds a new signature, `TestElement.click('center')` that can be used to click the center of the element. Calling `TestElement.click(x, y)` to click a point relative to the top left of the element remains uncahnged. I tested the performance gain of these changes by running a unit test to click 1000 buttons. Prior to this change it took 3000.2ms, with this change it took 1842.1ms (38.6% improvement).
1 parent 4f1238f commit 817bddf

File tree

4 files changed

+31
-13
lines changed

4 files changed

+31
-13
lines changed

src/cdk/testing/protractor/protractor-element.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ export class ProtractorElement implements TestElement {
8080
return this.element.clear();
8181
}
8282

83-
async click(...args: number[]): Promise<void> {
83+
async click(...args: ['center'] | [number, number]): Promise<void> {
8484
// Omitting the offset argument to mouseMove results in clicking the center.
8585
// This is the default behavior we want, so we use an empty array of offsetArgs if no args are
8686
// passed to this method.
87-
const offsetArgs = args.length ? [{x: args[0], y: args[1]}] : [];
87+
const offsetArgs = args.length == 2 ? [{x: args[0], y: args[1]}] : [];
8888

8989
await browser.actions()
9090
.mouseMove(await this.element.getWebElement(), ...offsetArgs)

src/cdk/testing/test-element.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,9 +67,16 @@ export interface TestElement {
6767
/** Clear the element's input (for input and textarea elements only). */
6868
clear(): Promise<void>;
6969

70-
/** Click the element at the element's center. */
70+
/**
71+
* Click the element at the default location for the current environment. If you need to guarantee
72+
* the element is clicked at a specific location, consider using `click('center')` or
73+
* `click(x, y)` instead.
74+
*/
7175
click(): Promise<void>;
7276

77+
/** Click the element at the element's center. */
78+
click(location: 'center'): Promise<void>;
79+
7380
/**
7481
* Click the element at the specified coordinates relative to the top-left of the element.
7582
* @param relativeX Coordinate within the element, along the X-axis at which to click.

src/cdk/testing/testbed/unit-test-element.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -78,15 +78,19 @@ export class UnitTestElement implements TestElement {
7878
await this._stabilize();
7979
}
8080

81-
async click(...args: number[]): Promise<void> {
82-
const {left, top, width, height} = await this.getDimensions();
83-
const relativeX = args.length ? args[0] : width / 2;
84-
const relativeY = args.length ? args[1] : height / 2;
85-
86-
// Round the computed click position as decimal pixels are not
87-
// supported by mouse events and could lead to unexpected results.
88-
const clientX = Math.round(left + relativeX);
89-
const clientY = Math.round(top + relativeY);
81+
async click(...args: ['center'] | [number, number]): Promise<void> {
82+
let clientX: number | undefined = undefined;
83+
let clientY: number | undefined = undefined;
84+
if (args.length) {
85+
const {left, top, width, height} = await this.getDimensions();
86+
const relativeX = args[0] === 'center' ? width / 2 : args[0];
87+
const relativeY = args[0] === 'center' ? height / 2 : args[1];
88+
89+
// Round the computed click position as decimal pixels are not
90+
// supported by mouse events and could lead to unexpected results.
91+
clientX = Math.round(left + relativeX);
92+
clientY = Math.round(top + relativeY);
93+
}
9094

9195
this._dispatchPointerEventIfSupported('pointerdown', clientX, clientY);
9296
dispatchMouseEvent(this.element, 'mousedown', clientX, clientY);

src/cdk/testing/tests/cross-environment.spec.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -322,7 +322,14 @@ export function crossEnvironmentSpecs(
322322
it('should be able to click at a specific position within an element', async () => {
323323
const clickTest = await harness.clickTest();
324324
const clickTestResult = await harness.clickTestResult();
325-
await clickTest.click(50, 50);
325+
await clickTest.click(10, 10);
326+
expect(await clickTestResult.text()).toBe('10-10');
327+
});
328+
329+
it('should be able to click the center of an element', async () => {
330+
const clickTest = await harness.clickTest();
331+
const clickTestResult = await harness.clickTestResult();
332+
await clickTest.click('center');
326333
expect(await clickTestResult.text()).toBe('50-50');
327334
});
328335

0 commit comments

Comments
 (0)