@@ -38,7 +38,6 @@ describe('MdSlider', () => {
3838 let sliderDimensions : ClientRect ;
3939 let thumbElement : HTMLElement ;
4040 let thumbDimensions : ClientRect ;
41- let thumbWidth : number ;
4241
4342 beforeEach ( async ( ( ) => {
4443 builder . createAsync ( StandardSlider ) . then ( f => {
@@ -56,8 +55,6 @@ describe('MdSlider', () => {
5655
5756 thumbElement = < HTMLElement > sliderNativeElement . querySelector ( '.md-slider-thumb-position' ) ;
5857 thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
59- thumbWidth =
60- sliderNativeElement . querySelector ( '.md-slider-thumb' ) . getBoundingClientRect ( ) . width ;
6158 } ) ;
6259 } ) ) ;
6360
@@ -71,16 +68,14 @@ describe('MdSlider', () => {
7168 expect ( sliderInstance . value ) . toBe ( 0 ) ;
7269 dispatchClickEvent ( sliderTrackElement , 0.19 ) ;
7370 // The expected value is 19 from: percentage * difference of max and min.
74- let difference = Math . abs ( sliderInstance . value - 19 ) ;
75- expect ( difference ) . toBeLessThan ( 1 ) ;
71+ expect ( sliderInstance . value ) . toBe ( 19 ) ;
7672 } ) ;
7773
7874 it ( 'should update the value on a drag' , ( ) => {
7975 expect ( sliderInstance . value ) . toBe ( 0 ) ;
8076 dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.89 , gestureConfig ) ;
8177 // The expected value is 89 from: percentage * difference of max and min.
82- let difference = Math . abs ( sliderInstance . value - 89 ) ;
83- expect ( difference ) . toBeLessThan ( 1 ) ;
78+ expect ( sliderInstance . value ) . toBe ( 89 ) ;
8479 } ) ;
8580
8681 it ( 'should set the value as min when dragging before the track' , ( ) => {
@@ -100,40 +95,49 @@ describe('MdSlider', () => {
10095 dispatchClickEvent ( sliderTrackElement , 0.39 ) ;
10196
10297 trackFillDimensions = trackFillElement . getBoundingClientRect ( ) ;
103- // The fill should be close to the slider's width * the percentage from the click.
104- let difference = Math . abs ( trackFillDimensions . width - ( sliderDimensions . width * 0.39 ) ) ;
105- expect ( difference ) . toBeLessThan ( 1 ) ;
98+ thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
99+
100+ // The thumb and track fill positions are relative to the viewport, so to get the thumb's
101+ // offset relative to the track, subtract the offset on the track fill.
102+ let thumbPosition = thumbDimensions . left - trackFillDimensions . left ;
103+ // The track fill width should be equal to the thumb's position.
104+ expect ( Math . round ( trackFillDimensions . width ) ) . toBe ( Math . round ( thumbPosition ) ) ;
106105 } ) ;
107106
108107 it ( 'should update the thumb position on click' , ( ) => {
109- expect ( thumbDimensions . left ) . toBe ( sliderDimensions . left - ( thumbWidth / 2 ) ) ;
110- dispatchClickEvent ( sliderTrackElement , 0.16 ) ;
108+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . left ) ;
109+ // 50% is used here because the click event that is dispatched truncates the position and so
110+ // a value had to be used that would not be truncated.
111+ dispatchClickEvent ( sliderTrackElement , 0.5 ) ;
111112
112113 thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
113- // The thumb's offset is expected to be equal to the slider's offset + 0.16 * the slider's
114- // width - half the thumb width (to center the thumb).
115- let offset = sliderDimensions . left + ( sliderDimensions . width * 0.16 ) - ( thumbWidth / 2 ) ;
116- let difference = Math . abs ( thumbDimensions . left - offset ) ;
117- expect ( difference ) . toBeLessThan ( 1 ) ;
114+ // The thumb position should be at 50% of the slider's width + the offset of the slider.
115+ // Both the thumb and the slider are affected by this offset.
116+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . width * 0.5 + sliderDimensions . left ) ;
118117 } ) ;
119118
120119 it ( 'should update the track fill on drag' , ( ) => {
121120 expect ( trackFillDimensions . width ) . toBe ( 0 ) ;
122121 dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.86 , gestureConfig ) ;
123122
124123 trackFillDimensions = trackFillElement . getBoundingClientRect ( ) ;
125- let difference = Math . abs ( trackFillDimensions . width - ( sliderDimensions . width * 0.86 ) ) ;
126- expect ( difference ) . toBeLessThan ( 1 ) ;
124+ thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
125+
126+ // The thumb and track fill positions are relative to the viewport, so to get the thumb's
127+ // offset relative to the track, subtract the offset on the track fill.
128+ let thumbPosition = thumbDimensions . left - trackFillDimensions . left ;
129+ // The track fill width should be equal to the thumb's position.
130+ expect ( Math . round ( trackFillDimensions . width ) ) . toBe ( Math . round ( thumbPosition ) ) ;
127131 } ) ;
128132
129133 it ( 'should update the thumb position on drag' , ( ) => {
130- expect ( thumbDimensions . left ) . toBe ( sliderDimensions . left - ( thumbWidth / 2 ) ) ;
131- dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.27 , gestureConfig ) ;
134+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . left ) ;
135+ // The drag event also truncates the position passed in, so 50% is used here as well to
136+ // ensure the ability to calculate the expected position.
137+ dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.5 , gestureConfig ) ;
132138
133139 thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
134- let offset = sliderDimensions . left + ( sliderDimensions . width * 0.27 ) - ( thumbWidth / 2 ) ;
135- let difference = Math . abs ( thumbDimensions . left - offset ) ;
136- expect ( difference ) . toBeLessThan ( 1 ) ;
140+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . width * 0.5 + sliderDimensions . left ) ;
137141 } ) ;
138142
139143 it ( 'should add the md-slider-active class on click' , ( ) => {
@@ -237,6 +241,9 @@ describe('MdSlider', () => {
237241 let sliderNativeElement : HTMLElement ;
238242 let sliderInstance : MdSlider ;
239243 let sliderTrackElement : HTMLElement ;
244+ let sliderDimensions : ClientRect ;
245+ let trackFillElement : HTMLElement ;
246+ let thumbElement : HTMLElement ;
240247
241248 beforeEach ( async ( ( ) => {
242249 builder . createAsync ( SliderWithMinAndMax ) . then ( f => {
@@ -247,31 +254,62 @@ describe('MdSlider', () => {
247254 sliderNativeElement = sliderDebugElement . nativeElement ;
248255 sliderInstance = sliderDebugElement . injector . get ( MdSlider ) ;
249256 sliderTrackElement = < HTMLElement > sliderNativeElement . querySelector ( '.md-slider-track' ) ;
257+ sliderDimensions = sliderTrackElement . getBoundingClientRect ( ) ;
258+ trackFillElement = < HTMLElement > sliderNativeElement . querySelector ( '.md-slider-track-fill' ) ;
259+ thumbElement = < HTMLElement > sliderNativeElement . querySelector ( '.md-slider-thumb-position' ) ;
250260 } ) ;
251261 } ) ) ;
252262
253263 it ( 'should set the default values from the attributes' , ( ) => {
254- expect ( sliderInstance . value ) . toBe ( 5 ) ;
255- expect ( sliderInstance . min ) . toBe ( 5 ) ;
256- expect ( sliderInstance . max ) . toBe ( 15 ) ;
264+ expect ( sliderInstance . value ) . toBe ( 4 ) ;
265+ expect ( sliderInstance . min ) . toBe ( 4 ) ;
266+ expect ( sliderInstance . max ) . toBe ( 6 ) ;
257267 } ) ;
258268
259269 it ( 'should set the correct value on click' , ( ) => {
260270 dispatchClickEvent ( sliderTrackElement , 0.09 ) ;
261271 // Computed by multiplying the difference between the min and the max by the percentage from
262272 // the click and adding that to the minimum.
263- let value = 5 + ( 0.09 * ( 15 - 5 ) ) ;
264- let difference = Math . abs ( sliderInstance . value - value ) ;
265- expect ( difference ) . toBeLessThan ( 1 ) ;
273+ let value = Math . round ( 4 + ( 0.09 * ( 6 - 4 ) ) ) ;
274+ expect ( sliderInstance . value ) . toBe ( value ) ;
266275 } ) ;
267276
268277 it ( 'should set the correct value on drag' , ( ) => {
269278 dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.62 , gestureConfig ) ;
270279 // Computed by multiplying the difference between the min and the max by the percentage from
271280 // the click and adding that to the minimum.
272- let value = 5 + ( 0.62 * ( 15 - 5 ) ) ;
273- let difference = Math . abs ( sliderInstance . value - value ) ;
274- expect ( difference ) . toBeLessThan ( 1 ) ;
281+ let value = Math . round ( 4 + ( 0.62 * ( 6 - 4 ) ) ) ;
282+ expect ( sliderInstance . value ) . toBe ( value ) ;
283+ } ) ;
284+
285+ it ( 'should snap the thumb and fill to the nearest value on click' , ( ) => {
286+ dispatchClickEvent ( sliderTrackElement , 0.68 ) ;
287+ fixture . detectChanges ( ) ;
288+
289+ let trackFillDimensions = trackFillElement . getBoundingClientRect ( ) ;
290+ let thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
291+ let thumbPosition = thumbDimensions . left - trackFillDimensions . left ;
292+
293+ // The closest snap is halfway on the slider.
294+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . width * 0.5 + sliderDimensions . left ) ;
295+ expect ( Math . round ( trackFillDimensions . width ) ) . toBe ( Math . round ( thumbPosition ) ) ;
296+ } ) ;
297+
298+ it ( 'should snap the thumb and fill to the nearest value on drag' , ( ) => {
299+ dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.74 , gestureConfig ) ;
300+ fixture . detectChanges ( ) ;
301+
302+ dispatchDragEndEvent ( sliderNativeElement , 0.74 , gestureConfig ) ;
303+ fixture . detectChanges ( ) ;
304+
305+ let trackFillDimensions = trackFillElement . getBoundingClientRect ( ) ;
306+ let thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
307+ let thumbPosition = thumbDimensions . left - trackFillDimensions . left ;
308+
309+ // The closest snap is at the halfway point on the slider.
310+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . left + sliderDimensions . width * 0.5 ) ;
311+ expect ( Math . round ( trackFillDimensions . width ) ) . toBe ( Math . round ( thumbPosition ) ) ;
312+
275313 } ) ;
276314 } ) ;
277315
@@ -302,16 +340,85 @@ describe('MdSlider', () => {
302340 dispatchClickEvent ( sliderTrackElement , 0.92 ) ;
303341 // On a slider with default max and min the value should be approximately equal to the
304342 // percentage clicked. This should be the case regardless of what the original set value was.
305- let value = 92 ;
306- let difference = Math . abs ( sliderInstance . value - value ) ;
307- expect ( difference ) . toBeLessThan ( 1 ) ;
343+ expect ( sliderInstance . value ) . toBe ( 92 ) ;
308344 } ) ;
309345
310346 it ( 'should set the correct value on drag' , ( ) => {
311347 dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.32 , gestureConfig ) ;
312348 expect ( sliderInstance . value ) . toBe ( 32 ) ;
313349 } ) ;
314350 } ) ;
351+
352+ describe ( 'slider with set step' , ( ) => {
353+ let fixture : ComponentFixture < SliderWithStep > ;
354+ let sliderDebugElement : DebugElement ;
355+ let sliderNativeElement : HTMLElement ;
356+ let sliderInstance : MdSlider ;
357+ let sliderTrackElement : HTMLElement ;
358+ let sliderDimensions : ClientRect ;
359+ let trackFillElement : HTMLElement ;
360+ let thumbElement : HTMLElement ;
361+
362+ beforeEach ( async ( ( ) => {
363+ builder . createAsync ( SliderWithStep ) . then ( f => {
364+ fixture = f ;
365+ fixture . detectChanges ( ) ;
366+
367+ sliderDebugElement = fixture . debugElement . query ( By . directive ( MdSlider ) ) ;
368+ sliderNativeElement = sliderDebugElement . nativeElement ;
369+ sliderInstance = sliderDebugElement . injector . get ( MdSlider ) ;
370+ sliderTrackElement = < HTMLElement > sliderNativeElement . querySelector ( '.md-slider-track' ) ;
371+ sliderDimensions = sliderTrackElement . getBoundingClientRect ( ) ;
372+ trackFillElement = < HTMLElement > sliderNativeElement . querySelector ( '.md-slider-track-fill' ) ;
373+ thumbElement = < HTMLElement > sliderNativeElement . querySelector ( '.md-slider-thumb-position' ) ;
374+ } ) ;
375+ } ) ) ;
376+
377+ it ( 'should set the correct step value on click' , ( ) => {
378+ expect ( sliderInstance . value ) . toBe ( 0 ) ;
379+
380+ dispatchClickEvent ( sliderTrackElement , 0.13 ) ;
381+ fixture . detectChanges ( ) ;
382+
383+ expect ( sliderInstance . value ) . toBe ( 25 ) ;
384+ } ) ;
385+
386+ it ( 'should snap the thumb and fill to a step on click' , ( ) => {
387+ dispatchClickEvent ( sliderNativeElement , 0.66 ) ;
388+ fixture . detectChanges ( ) ;
389+
390+ let trackFillDimensions = trackFillElement . getBoundingClientRect ( ) ;
391+ let thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
392+ let thumbPosition = thumbDimensions . left - trackFillDimensions . left ;
393+
394+ // The closest step is at 75% of the slider.
395+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . width * 0.75 + sliderDimensions . left ) ;
396+ expect ( Math . round ( trackFillDimensions . width ) ) . toBe ( Math . round ( thumbPosition ) ) ;
397+ } ) ;
398+
399+ it ( 'should set the correct step value on drag' , ( ) => {
400+ dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.07 , gestureConfig ) ;
401+ fixture . detectChanges ( ) ;
402+
403+ expect ( sliderInstance . value ) . toBe ( 0 ) ;
404+ } ) ;
405+
406+ it ( 'should snap the thumb and fill to a step on drag' , ( ) => {
407+ dispatchDragEvent ( sliderTrackElement , sliderNativeElement , 0 , 0.88 , gestureConfig ) ;
408+ fixture . detectChanges ( ) ;
409+
410+ dispatchDragEndEvent ( sliderNativeElement , 0.88 , gestureConfig ) ;
411+ fixture . detectChanges ( ) ;
412+
413+ let trackFillDimensions = trackFillElement . getBoundingClientRect ( ) ;
414+ let thumbDimensions = thumbElement . getBoundingClientRect ( ) ;
415+ let thumbPosition = thumbDimensions . left - trackFillDimensions . left ;
416+
417+ // The closest snap is at the end of the slider.
418+ expect ( thumbDimensions . left ) . toBe ( sliderDimensions . width + sliderDimensions . left ) ;
419+ expect ( Math . round ( trackFillDimensions . width ) ) . toBe ( Math . round ( thumbPosition ) ) ;
420+ } ) ;
421+ } ) ;
315422} ) ;
316423
317424// The transition has to be removed in order to test the updated positions without setTimeout.
@@ -335,7 +442,13 @@ class DisabledSlider { }
335442
336443@Component ( {
337444 directives : [ MD_SLIDER_DIRECTIVES ] ,
338- template : `<md-slider min="5" max="15"></md-slider>`
445+ template : `<md-slider min="4" max="6"></md-slider>` ,
446+ styles : [ `
447+ .md-slider-track-fill, .md-slider-thumb-position {
448+ transition: none !important;
449+ }
450+ ` ] ,
451+ encapsulation : ViewEncapsulation . None
339452} )
340453class SliderWithMinAndMax { }
341454
@@ -345,8 +458,21 @@ class SliderWithMinAndMax { }
345458} )
346459class SliderWithValue { }
347460
461+ @Component ( {
462+ directives : [ MD_SLIDER_DIRECTIVES ] ,
463+ template : `<md-slider step="25"></md-slider>` ,
464+ styles : [ `
465+ .md-slider-track-fill, .md-slider-thumb-position {
466+ transition: none !important;
467+ }
468+ ` ] ,
469+ encapsulation : ViewEncapsulation . None
470+ } )
471+ class SliderWithStep { }
472+
348473/**
349474 * Dispatches a click event from an element.
475+ * Note: The mouse event truncates the position for the click.
350476 * @param element The element from which the event will be dispatched.
351477 * @param percentage The percentage of the slider where the click should occur. Used to find the
352478 * physical location of the click.
0 commit comments