Skip to content

Commit 0a16e04

Browse files
devversionmmalerba
authored andcommitted
feat(material-experimental): add test harness for slider (#16688)
Resolves COMP-191.
1 parent a6d1445 commit 0a16e04

File tree

16 files changed

+490
-14
lines changed

16 files changed

+490
-14
lines changed

.github/CODEOWNERS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@
100100
# Note to implementer: please repossess
101101
/src/material-experimental/mdc-radio/** @mmalerba
102102
/src/material-experimental/mdc-slide-toggle/** @crisbeto
103+
# Note to implementer: please repossess
104+
/src/material-experimental/mdc-slider/** @devversion
103105
/src/material-experimental/mdc-tabs/** @crisbeto
104106
/src/material-experimental/mdc-sidenav/** @crisbeto
105107
/src/material-experimental/mdc-theming/** @mmalerba
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
/**
10+
* Dimensions for element size and its position relative to the viewport.
11+
*/
12+
export interface ElementDimensions {
13+
top: number;
14+
left: number;
15+
width: number;
16+
height: number;
17+
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
import {ModifierKeys} from '@angular/cdk/testing';
1010
import {browser, ElementFinder, Key} from 'protractor';
11+
import {ElementDimensions} from '../element-dimensions';
1112
import {TestElement, TestKey} from '../test-element';
1213

1314
/** Maps the `TestKey` constants to Protractor's `Key` constants. */
@@ -74,8 +75,11 @@ export class ProtractorElement implements TestElement {
7475
return this.element.clear();
7576
}
7677

77-
async click(): Promise<void> {
78-
return this.element.click();
78+
async click(relativeX = 0, relativeY = 0): Promise<void> {
79+
await browser.actions()
80+
.mouseMove(await this.element.getWebElement(), {x: relativeX, y: relativeY})
81+
.click()
82+
.perform();
7983
}
8084

8185
async focus(): Promise<void> {
@@ -126,4 +130,10 @@ export class ProtractorElement implements TestElement {
126130
const classes = (await this.getAttribute('class')) || '';
127131
return new Set(classes.split(/\s+/).filter(c => c)).has(name);
128132
}
133+
134+
async getDimensions(): Promise<ElementDimensions> {
135+
const {width, height} = await this.element.getSize();
136+
const {x: left, y: top} = await this.element.getLocation();
137+
return {width, height, left, top};
138+
}
129139
}

src/cdk-experimental/testing/test-element.ts

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
/** Keyboard keys that do not result in input characters. */
109
import {ModifierKeys} from '@angular/cdk/testing';
10+
import {ElementDimensions} from './element-dimensions';
1111

1212
/** An enum of non-text keys that can be used with the `sendKeys` method. */
1313
// NOTE: This is a separate enum from `@angular/cdk/keycodes` because we don't necessarily want to
@@ -59,8 +59,12 @@ export interface TestElement {
5959
/** Clear the element's input (for input elements only). */
6060
clear(): Promise<void>;
6161

62-
/** Click the element. */
63-
click(): Promise<void>;
62+
/**
63+
* Click the element.
64+
* @param relativeX Coordinate within the element, along the X-axis at which to click.
65+
* @param relativeY Coordinate within the element, along the Y-axis at which to click.
66+
*/
67+
click(relativeX?: number, relativeY?: number): Promise<void>;
6468

6569
/** Focus the element. */
6670
focus(): Promise<void>;
@@ -94,4 +98,7 @@ export interface TestElement {
9498

9599
/** Checks whether the element has the given class. */
96100
hasClass(name: string): Promise<boolean>;
101+
102+
/** Gets the dimensions of the element. */
103+
getDimensions(): Promise<ElementDimensions>;
97104
}

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import {
1717
typeInElement
1818
} from '@angular/cdk/testing';
1919
import {TestElement, TestKey} from '../test-element';
20+
import {ElementDimensions} from '../element-dimensions';
2021

2122
/** Maps `TestKey` constants to the `keyCode` and `key` values used by native browser events. */
2223
const keyMap = {
@@ -71,9 +72,16 @@ export class UnitTestElement implements TestElement {
7172
await this._stabilize();
7273
}
7374

74-
async click(): Promise<void> {
75+
async click(relativeX = 0, relativeY = 0): Promise<void> {
7576
await this._stabilize();
76-
dispatchMouseEvent(this.element, 'click');
77+
const {left, top} = this.element.getBoundingClientRect();
78+
// Round the computed click position as decimal pixels are not
79+
// supported by mouse events and could lead to unexpected results.
80+
const clientX = Math.round(left + relativeX);
81+
const clientY = Math.round(top + relativeY);
82+
dispatchMouseEvent(this.element, 'mousedown', clientX, clientY);
83+
dispatchMouseEvent(this.element, 'mouseup', clientX, clientY);
84+
dispatchMouseEvent(this.element, 'click', clientX, clientY);
7785
await this._stabilize();
7886
}
7987

@@ -126,4 +134,9 @@ export class UnitTestElement implements TestElement {
126134
await this._stabilize();
127135
return this.element.classList.contains(name);
128136
}
137+
138+
async getDimensions(): Promise<ElementDimensions> {
139+
await this._stabilize();
140+
return this.element.getBoundingClientRect();
141+
}
129142
}

src/cdk-experimental/testing/tests/harnesses/main-component-harness.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ export class MainComponentHarness extends ComponentHarness {
2626
readonly allLabels = this.locatorForAll('label');
2727
readonly allLists = this.locatorForAll(SubComponentHarness);
2828
readonly memo = this.locatorFor('textarea');
29+
readonly clickTest = this.locatorFor('.click-test');
30+
readonly clickTestResult = this.locatorFor('.click-test-result');
2931
// Allow null for element
3032
readonly nullItem = this.locatorForOptional('wrong locator');
3133
// Allow null for component harness
@@ -36,7 +38,7 @@ export class MainComponentHarness extends ComponentHarness {
3638
readonly errorGlobalEl = this.documentRootLocatorFactory().locatorFor('wrong locator');
3739
readonly nullGlobalEl = this.documentRootLocatorFactory().locatorForOptional('wrong locator');
3840

39-
readonly optionalDiv = this.locatorForOptional('div');
41+
readonly optionalUsername = this.locatorForOptional('#username');
4042
readonly optionalSubComponent = this.locatorForOptional(SubComponentHarness);
4143
readonly errorSubComponent = this.locatorFor(WrongComponentHarness);
4244

src/cdk-experimental/testing/tests/protractor.e2e.spec.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ describe('ProtractorHarnessEnvironment', () => {
8787
});
8888

8989
it('should locate an optional element based on CSS selector', async () => {
90-
const present = await harness.optionalDiv();
90+
const present = await harness.optionalUsername();
9191
const missing = await harness.nullItem();
9292
expect(present).not.toBeNull();
9393
expect(await present!.text()).toBe('Hello Yi from Angular 2!');
@@ -192,6 +192,13 @@ describe('ProtractorHarnessEnvironment', () => {
192192
expect(await counter.text()).toBe('3');
193193
});
194194

195+
it('should be able to click at a specific position within an element', async () => {
196+
const clickTest = await harness.clickTest();
197+
const clickTestResult = await harness.clickTestResult();
198+
await clickTest.click(50, 50);
199+
expect(await clickTestResult.text()).toBe('50-50');
200+
});
201+
195202
it('should be able to send key', async () => {
196203
const input = await harness.input();
197204
const value = await harness.value();
@@ -208,6 +215,11 @@ describe('ProtractorHarnessEnvironment', () => {
208215
.toBe(await browser.driver.switchTo().activeElement().getAttribute('id'));
209216
});
210217

218+
it('should be able to retrieve dimensions', async () => {
219+
const dimensions = await (await harness.title()).getDimensions();
220+
expect(dimensions).toEqual(jasmine.objectContaining({height: 100, width: 200}));
221+
});
222+
211223
it('should be able to hover', async () => {
212224
const host = await harness.host();
213225
let classAttr = await host.getAttribute('class');
@@ -229,7 +241,7 @@ describe('ProtractorHarnessEnvironment', () => {
229241

230242
it('should be able to getCssValue', async () => {
231243
const title = await harness.title();
232-
expect(await title.getCssValue('height')).toBe('50px');
244+
expect(await title.getCssValue('height')).toBe('100px');
233245
});
234246

235247
it('should focus and blur element', async () => {

src/cdk-experimental/testing/tests/test-main-component.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
<h1 style="height: 50px">Main Component</h1>
1+
<div class="click-test" (click)="onClick($event)"
2+
style="width: 100px; height: 100px; background: grey"
3+
#clickTestElement>
4+
</div>
5+
<div class="click-test-result">{{relativeX}}-{{relativeY}}</div>
6+
<h1 style="height: 100px; width: 200px;">Main Component</h1>
27
<div id="username">Hello {{username}} from Angular 2!</div>
38
<div class="counters">
49
<button (click)="click()">Up</button><br>

src/cdk-experimental/testing/tests/test-main-component.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ import {
1111
ChangeDetectionStrategy,
1212
ChangeDetectorRef,
1313
Component,
14+
ElementRef,
15+
ViewChild,
1416
ViewEncapsulation
1517
} from '@angular/core';
1618

@@ -37,6 +39,10 @@ export class TestMainComponent {
3739
testMethods: string[];
3840
_isHovering: boolean;
3941
specialKey = '';
42+
relativeX = 0;
43+
relativeY = 0;
44+
45+
@ViewChild('clickTestElement', {static: false}) clickTestElement: ElementRef<HTMLElement>;
4046

4147
onMouseOver() {
4248
this._isHovering = true;
@@ -75,4 +81,10 @@ export class TestMainComponent {
7581
this.specialKey = 'alt-j';
7682
}
7783
}
84+
85+
onClick(event: MouseEvent) {
86+
const {top, left} = this.clickTestElement.nativeElement.getBoundingClientRect();
87+
this.relativeX = Math.round(event.clientX - left);
88+
this.relativeY = Math.round(event.clientY - top);
89+
}
7890
}

src/cdk-experimental/testing/tests/testbed.spec.ts

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ describe('TestbedHarnessEnvironment', () => {
103103
});
104104

105105
it('should locate an optional element based on CSS selector', async () => {
106-
const present = await harness.optionalDiv();
106+
const present = await harness.optionalUsername();
107107
const missing = await harness.nullItem();
108108
expect(present).not.toBeNull();
109109
expect(await present!.text()).toBe('Hello Yi from Angular 2!');
@@ -212,6 +212,13 @@ describe('TestbedHarnessEnvironment', () => {
212212
expect(await counter.text()).toBe('3');
213213
});
214214

215+
it('should be able to click at a specific position within an element', async () => {
216+
const clickTest = await harness.clickTest();
217+
const clickTestResult = await harness.clickTestResult();
218+
await clickTest.click(50, 50);
219+
expect(await clickTestResult.text()).toBe('50-50');
220+
});
221+
215222
it('should be able to send key', async () => {
216223
const input = await harness.input();
217224
const value = await harness.value();
@@ -227,6 +234,11 @@ describe('TestbedHarnessEnvironment', () => {
227234
expect(await input.getAttribute('id')).toBe(document.activeElement!.id);
228235
});
229236

237+
it('should be able to retrieve dimensions', async () => {
238+
const dimensions = await (await harness.title()).getDimensions();
239+
expect(dimensions).toEqual(jasmine.objectContaining({height: 100, width: 200}));
240+
});
241+
230242
it('should be able to hover', async () => {
231243
const host = await harness.host();
232244
let classAttr = await host.getAttribute('class');
@@ -248,7 +260,7 @@ describe('TestbedHarnessEnvironment', () => {
248260

249261
it('should be able to getCssValue', async () => {
250262
const title = await harness.title();
251-
expect(await title.getCssValue('height')).toBe('50px');
263+
expect(await title.getCssValue('height')).toBe('100px');
252264
});
253265

254266
it('should focus and blur element', async () => {
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package(default_visibility = ["//visibility:public"])
2+
3+
load("//tools:defaults.bzl", "ng_test_library", "ng_web_test_suite", "ts_library")
4+
5+
ts_library(
6+
name = "harness",
7+
srcs = glob(
8+
["**/*.ts"],
9+
exclude = ["**/*.spec.ts"],
10+
),
11+
deps = [
12+
"//src/cdk-experimental/testing",
13+
"//src/cdk/coercion",
14+
],
15+
)
16+
17+
ng_test_library(
18+
name = "harness_tests",
19+
srcs = glob(["**/*.spec.ts"]),
20+
deps = [
21+
":harness",
22+
"//src/cdk-experimental/testing",
23+
"//src/cdk-experimental/testing/testbed",
24+
"//src/material/slider",
25+
],
26+
)
27+
28+
ng_web_test_suite(
29+
name = "tests",
30+
deps = [":harness_tests"],
31+
)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
export type SliderHarnessFilters = {
10+
id?: string;
11+
};

0 commit comments

Comments
 (0)