Skip to content

Commit 17d55b2

Browse files
committed
fix(material-experimental/mdc-slider): fix ios unit test bug
* use touch events instead of pointer events when testing on ios. pointerdown, pointerup, and pointermove are not supported on ios.
1 parent 10035f1 commit 17d55b2

File tree

3 files changed

+76
-27
lines changed

3 files changed

+76
-27
lines changed

src/cdk/testing/testbed/fake-events/dispatch-events.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export function dispatchPointerEvent(node: Node, type: string, clientX = 0, clie
6565
* Shorthand to dispatch a touch event on the specified coordinates.
6666
* @docs-private
6767
*/
68-
export function dispatchTouchEvent(node: Node, type: string, x = 0, y = 0) {
69-
return dispatchEvent(node, createTouchEvent(type, x, y));
68+
export function dispatchTouchEvent(node: Node, type: string, pageX = 0, pageY = 0, clientX = 0,
69+
clientY = 0) {
70+
return dispatchEvent(node, createTouchEvent(type, pageX, pageY, clientX, clientY));
7071
}

src/cdk/testing/testbed/fake-events/event-objects.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,11 @@ export function createPointerEvent(type: string, clientX = 0, clientY = 0,
7979
* Creates a browser TouchEvent with the specified pointer coordinates.
8080
* @docs-private
8181
*/
82-
export function createTouchEvent(type: string, pageX = 0, pageY = 0) {
82+
export function createTouchEvent(type: string, pageX = 0, pageY = 0, clientX = 0, clientY = 0) {
8383
// In favor of creating events that work for most of the browsers, the event is created
8484
// as a basic UI Event. The necessary details for the event will be set manually.
8585
const event = document.createEvent('UIEvent');
86-
const touchDetails = {pageX, pageY};
86+
const touchDetails = {pageX, pageY, clientX, clientY};
8787

8888
// TS3.6 removes the initUIEvent method and suggests porting to "new UIEvent()".
8989
(event as any).initUIEvent(type, true, true, window, 0);

src/material-experimental/mdc-slider/slider.spec.ts

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

9-
import {dispatchMouseEvent, dispatchPointerEvent} from '@angular/cdk/testing/private';
9+
import {Platform} from '@angular/cdk/platform';
10+
import {
11+
dispatchMouseEvent,
12+
dispatchPointerEvent,
13+
dispatchTouchEvent,
14+
} from '@angular/cdk/testing/private';
1015
import {Component, DebugElement, Type} from '@angular/core';
1116
import {ComponentFixture, fakeAsync, TestBed, tick, waitForAsync} from '@angular/core/testing';
1217
import {By} from '@angular/platform-browser';
@@ -15,7 +20,10 @@ import {MatSliderModule} from './module';
1520
import {MatSlider, MatSliderThumb, MatSliderVisualThumb} from './slider';
1621

1722
describe('MDC-based MatSlider' , () => {
23+
let platform: Platform;
24+
1825
beforeAll(() => {
26+
platform = TestBed.inject(Platform);
1927
// Mock #setPointerCapture as it throws errors on pointerdown without a real pointerId.
2028
spyOn(Element.prototype, 'setPointerCapture');
2129
});
@@ -49,28 +57,28 @@ describe('MDC-based MatSlider' , () => {
4957
});
5058

5159
it('should update the value on mousedown', () => {
52-
setValueByClick(sliderInstance, 19);
60+
setValueByClick(sliderInstance, 19, platform.IOS);
5361
expect(inputInstance.value).toBe(19);
5462
});
5563

5664
it('should update the value on a slide', () => {
57-
slideToValue(sliderInstance, 77);
65+
slideToValue(sliderInstance, 77, Thumb.END, platform.IOS);
5866
expect(inputInstance.value).toBe(77);
5967
});
6068

6169
it('should set the value as min when sliding before the track', () => {
62-
slideToValue(sliderInstance, -1);
70+
slideToValue(sliderInstance, -1, Thumb.END, platform.IOS);
6371
expect(inputInstance.value).toBe(0);
6472
});
6573

6674
it('should set the value as max when sliding past the track', () => {
67-
slideToValue(sliderInstance, 101);
75+
slideToValue(sliderInstance, 101, Thumb.END, platform.IOS);
6876
expect(inputInstance.value).toBe(100);
6977
});
7078

7179
it('should focus the slider input when clicking on the slider', () => {
7280
expect(document.activeElement).not.toBe(inputInstance._hostElement);
73-
setValueByClick(sliderInstance, 0);
81+
setValueByClick(sliderInstance, 0, platform.IOS);
7482
expect(document.activeElement).toBe(inputInstance._hostElement);
7583
});
7684
});
@@ -99,46 +107,46 @@ describe('MDC-based MatSlider' , () => {
99107
});
100108

101109
it('should update the start value on a slide', () => {
102-
slideToValue(sliderInstance, 19, Thumb.START);
110+
slideToValue(sliderInstance, 19, Thumb.START, platform.IOS);
103111
expect(startInputInstance.value).toBe(19);
104112
});
105113

106114
it('should update the end value on a slide', () => {
107-
slideToValue(sliderInstance, 27, Thumb.END);
115+
slideToValue(sliderInstance, 27, Thumb.END, platform.IOS);
108116
expect(endInputInstance.value).toBe(27);
109117
});
110118

111119
it('should update the start value on mousedown behind the start thumb', () => {
112120
sliderInstance._setValue(19, Thumb.START);
113-
setValueByClick(sliderInstance, 12);
121+
setValueByClick(sliderInstance, 12, platform.IOS);
114122
expect(startInputInstance.value).toBe(12);
115123
});
116124

117125
it('should update the end value on mousedown in front of the end thumb', () => {
118126
sliderInstance._setValue(27, Thumb.END);
119-
setValueByClick(sliderInstance, 55);
127+
setValueByClick(sliderInstance, 55, platform.IOS);
120128
expect(endInputInstance.value).toBe(55);
121129
});
122130

123131
it('should set the start value as min when sliding before the track', () => {
124-
slideToValue(sliderInstance, -1, Thumb.START);
132+
slideToValue(sliderInstance, -1, Thumb.START, platform.IOS);
125133
expect(startInputInstance.value).toBe(0);
126134
});
127135

128136
it('should set the end value as max when sliding past the track', () => {
129-
slideToValue(sliderInstance, 101, Thumb.START);
137+
slideToValue(sliderInstance, 101, Thumb.START, platform.IOS);
130138
expect(startInputInstance.value).toBe(100);
131139
});
132140

133141
it('should not let the start thumb slide past the end thumb', () => {
134142
sliderInstance._setValue(50, Thumb.END);
135-
slideToValue(sliderInstance, 75, Thumb.START);
143+
slideToValue(sliderInstance, 75, Thumb.START, platform.IOS);
136144
expect(startInputInstance.value).toBe(50);
137145
});
138146

139147
it('should not let the end thumb slide before the start thumb', () => {
140148
sliderInstance._setValue(50, Thumb.START);
141-
slideToValue(sliderInstance, 25, Thumb.END);
149+
slideToValue(sliderInstance, 25, Thumb.END, platform.IOS);
142150
expect(startInputInstance.value).toBe(50);
143151
});
144152
});
@@ -182,11 +190,15 @@ describe('MDC-based MatSlider' , () => {
182190
}
183191

184192
function pointerdown() {
185-
dispatchPointerEvent(thumbElement, 'pointerdown', thumbX, thumbY);
193+
dispatchPointerOrTouchEvent(
194+
thumbElement, PointerEventType.POINTER_DOWN, thumbX, thumbY, platform.IOS
195+
);
186196
}
187197

188198
function pointerup() {
189-
dispatchPointerEvent(thumbElement, 'pointerup', thumbX, thumbY);
199+
dispatchPointerOrTouchEvent(
200+
thumbElement, PointerEventType.POINTER_UP, thumbX, thumbY, platform.IOS
201+
);
190202
}
191203

192204
it('should show the hover ripple on mouseenter', fakeAsync(() => {
@@ -289,8 +301,22 @@ class StandardSlider {}
289301
})
290302
class StandardRangeSlider {}
291303

304+
/** The pointer event types used by the MDC Slider. */
305+
const enum PointerEventType {
306+
POINTER_DOWN = 'pointerdown',
307+
POINTER_UP = 'pointerup',
308+
POINTER_MOVE = 'pointermove',
309+
}
310+
311+
/** The touch event types used by the MDC Slider. */
312+
const enum TouchEventType {
313+
TOUCH_START = 'touchstart',
314+
TOUCH_END = 'touchend',
315+
TOUCH_MOVE = 'touchmove',
316+
}
317+
292318
/** Clicks on the MatSlider at the coordinates corresponding to the given value. */
293-
function setValueByClick(slider: MatSlider, value: number) {
319+
function setValueByClick(slider: MatSlider, value: number, isIOS: boolean) {
294320
const {min, max} = slider;
295321
const percent = (value - min) / (max - min);
296322

@@ -299,12 +325,12 @@ function setValueByClick(slider: MatSlider, value: number) {
299325
const x = left + (width * percent);
300326
const y = top + (height / 2);
301327

302-
dispatchPointerEvent(sliderElement, 'pointerdown', x, y);
303-
dispatchPointerEvent(sliderElement, 'pointerup', x, y);
328+
dispatchPointerOrTouchEvent(sliderElement, PointerEventType.POINTER_DOWN, x, y, isIOS);
329+
dispatchPointerOrTouchEvent(sliderElement, PointerEventType.POINTER_UP, x, y, isIOS);
304330
}
305331

306332
/** Slides the MatSlider's thumb to the given value. */
307-
function slideToValue(slider: MatSlider, value: number, thumbPosition: Thumb = Thumb.END) {
333+
function slideToValue(slider: MatSlider, value: number, thumbPosition: Thumb, isIOS: boolean) {
308334
const {min, max} = slider;
309335
const percent = (value - min) / (max - min);
310336

@@ -320,7 +346,29 @@ function slideToValue(slider: MatSlider, value: number, thumbPosition: Thumb = T
320346
const endX = sliderDimensions.left + (sliderDimensions.width * percent);
321347
const endY = sliderDimensions.top + (sliderDimensions.height / 2);
322348

323-
dispatchPointerEvent(sliderElement, 'pointerdown', startX, startY);
324-
dispatchPointerEvent(sliderElement, 'pointermove', endX, endY);
325-
dispatchPointerEvent(sliderElement, 'pointerup', endX, endY);
349+
dispatchPointerOrTouchEvent(sliderElement, PointerEventType.POINTER_DOWN, startX, startY, isIOS);
350+
dispatchPointerOrTouchEvent(sliderElement, PointerEventType.POINTER_MOVE, endX, endY, isIOS);
351+
dispatchPointerOrTouchEvent(sliderElement, PointerEventType.POINTER_UP, endX, endY, isIOS);
352+
}
353+
354+
/** Dispatch a pointerdown or pointerup event if supported, otherwise dispatch the touch event. */
355+
function dispatchPointerOrTouchEvent(
356+
node: Node, type: PointerEventType, x: number, y: number, isIOS: boolean) {
357+
if (isIOS) {
358+
dispatchTouchEvent(node, pointerEventTypeToTouchEventType(type), x, y, x, y);
359+
} else {
360+
dispatchPointerEvent(node, type, x, y);
361+
}
362+
}
363+
364+
/** Returns the touch event equivalent of the given pointer event. */
365+
function pointerEventTypeToTouchEventType(pointerEventType: PointerEventType) {
366+
switch (pointerEventType) {
367+
case PointerEventType.POINTER_DOWN:
368+
return TouchEventType.TOUCH_START;
369+
case PointerEventType.POINTER_UP:
370+
return TouchEventType.TOUCH_END;
371+
case PointerEventType.POINTER_MOVE:
372+
return TouchEventType.TOUCH_MOVE;
373+
}
326374
}

0 commit comments

Comments
 (0)