UNPKG

ipsos-components

Version:

Material Design components for Angular

1,326 lines (1,011 loc) 59.7 kB
import {BidiModule} from '@angular/cdk/bidi'; import { BACKSPACE, DOWN_ARROW, END, HOME, LEFT_ARROW, PAGE_DOWN, PAGE_UP, RIGHT_ARROW, UP_ARROW, } from '@angular/cdk/keycodes'; import {dispatchFakeEvent, dispatchKeyboardEvent, dispatchMouseEvent} from '@angular/cdk/testing'; import {Component, DebugElement, ViewChild} from '@angular/core'; import {async, ComponentFixture, TestBed} from '@angular/core/testing'; import {FormControl, FormsModule, ReactiveFormsModule} from '@angular/forms'; import {By, HAMMER_GESTURE_CONFIG} from '@angular/platform-browser'; import {MatSlider, MatSliderModule} from './index'; import {TestGestureConfig} from './test-gesture-config'; describe('MatSlider without forms', () => { let gestureConfig: TestGestureConfig; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [MatSliderModule, ReactiveFormsModule, FormsModule, BidiModule], declarations: [ StandardSlider, DisabledSlider, SliderWithMinAndMax, SliderWithValue, SliderWithStep, SliderWithAutoTickInterval, SliderWithSetTickInterval, SliderWithThumbLabel, SliderWithOneWayBinding, SliderWithValueSmallerThanMin, SliderWithValueGreaterThanMax, SliderWithChangeHandler, SliderWithDirAndInvert, SliderWithTabIndexBinding, SliderWithNativeTabindexAttr, VerticalSlider, ], providers: [ {provide: HAMMER_GESTURE_CONFIG, useFactory: () => { gestureConfig = new TestGestureConfig(); return gestureConfig; }} ], }); TestBed.compileComponents(); })); describe('standard slider', () => { let fixture: ComponentFixture<StandardSlider>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let trackFillElement: HTMLElement; let sliderWrapperElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(StandardSlider); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.componentInstance; trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); }); it('should set the default values', () => { expect(sliderInstance.value).toBe(0); expect(sliderInstance.min).toBe(0); expect(sliderInstance.max).toBe(100); }); it('should update the value on a click', () => { expect(sliderInstance.value).toBe(0); dispatchClickEventSequence(sliderNativeElement, 0.19); expect(sliderInstance.value).toBe(19); }); it('should update the value on a slide', () => { expect(sliderInstance.value).toBe(0); dispatchSlideEventSequence(sliderNativeElement, 0, 0.89, gestureConfig); expect(sliderInstance.value).toBe(89); }); it('should set the value as min when sliding before the track', () => { expect(sliderInstance.value).toBe(0); dispatchSlideEventSequence(sliderNativeElement, 0, -1.33, gestureConfig); expect(sliderInstance.value).toBe(0); }); it('should set the value as max when sliding past the track', () => { expect(sliderInstance.value).toBe(0); dispatchSlideEventSequence(sliderNativeElement, 0, 1.75, gestureConfig); expect(sliderInstance.value).toBe(100); }); it('should update the track fill on click', () => { expect(trackFillElement.style.transform).toContain('scaleX(0)'); dispatchClickEventSequence(sliderNativeElement, 0.39); fixture.detectChanges(); expect(trackFillElement.style.transform).toContain('scaleX(0.39)'); }); it('should update the track fill on slide', () => { expect(trackFillElement.style.transform).toContain('scaleX(0)'); dispatchSlideEventSequence(sliderNativeElement, 0, 0.86, gestureConfig); fixture.detectChanges(); expect(trackFillElement.style.transform).toContain('scaleX(0.86)'); }); it('should add and remove the mat-slider-sliding class when sliding', () => { expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding'); dispatchSlideStartEvent(sliderNativeElement, 0, gestureConfig); fixture.detectChanges(); expect(sliderNativeElement.classList).toContain('mat-slider-sliding'); dispatchSlideEndEvent(sliderNativeElement, 0.34, gestureConfig); fixture.detectChanges(); expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding'); }); it('should not change value without emitting a change event', () => { const onChangeSpy = jasmine.createSpy('slider onChange'); sliderInstance.change.subscribe(onChangeSpy); sliderInstance.value = 50; fixture.detectChanges(); dispatchSlideStartEvent(sliderNativeElement, 0, gestureConfig); fixture.detectChanges(); dispatchSlideEvent(sliderNativeElement, 10, gestureConfig); fixture.detectChanges(); // In some situations, HammerJS will fire a second "slidestart" event because the user // holds the thumb and drags it around. This would mean that the `_valueOnSlideStart` // value will be updated to the actual end value. Causing the slider to think that the value // didn't change at all. dispatchSlideStartEvent(sliderNativeElement, 10, gestureConfig); fixture.detectChanges(); dispatchSlideEndEvent(sliderNativeElement, 10, gestureConfig); fixture.detectChanges(); expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding'); expect(onChangeSpy).toHaveBeenCalledTimes(1); }); it('should reset active state upon blur', () => { sliderInstance._isActive = true; dispatchFakeEvent(sliderNativeElement, 'blur'); fixture.detectChanges(); expect(sliderInstance._isActive).toBe(false); }); it('should reset thumb gap when blurred on min value', () => { sliderInstance._isActive = true; sliderInstance.value = 0; fixture.detectChanges(); expect(sliderInstance._thumbGap).toBe(10); dispatchFakeEvent(sliderNativeElement, 'blur'); fixture.detectChanges(); expect(sliderInstance._thumbGap).toBe(7); }); it('should have thumb gap when at min value', () => { expect(trackFillElement.style.transform).toContain('translateX(-7px)'); }); it('should not have thumb gap when not at min value', () => { dispatchClickEventSequence(sliderNativeElement, 1); fixture.detectChanges(); // Some browsers use '0' and some use '0px', so leave off the closing paren. expect(trackFillElement.style.transform).toContain('translateX(0'); }); it('should have aria-orientation horizontal', () => { expect(sliderNativeElement.getAttribute('aria-orientation')).toEqual('horizontal'); }); }); describe('disabled slider', () => { let fixture: ComponentFixture<StandardSlider>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderWrapperElement: HTMLElement; let sliderInstance: MatSlider; let trackFillElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(DisabledSlider); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); sliderInstance = sliderDebugElement.componentInstance; trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); }); it('should be disabled', () => { expect(sliderInstance.disabled).toBeTruthy(); }); it('should not change the value on click when disabled', () => { expect(sliderInstance.value).toBe(0); dispatchClickEventSequence(sliderNativeElement, 0.63); expect(sliderInstance.value).toBe(0); }); it('should not change the value on slide when disabled', () => { expect(sliderInstance.value).toBe(0); dispatchSlideEventSequence(sliderNativeElement, 0, 0.5, gestureConfig); expect(sliderInstance.value).toBe(0); }); it('should not add the mat-slider-active class on click when disabled', () => { expect(sliderNativeElement.classList).not.toContain('mat-slider-active'); dispatchClickEventSequence(sliderNativeElement, 0.43); fixture.detectChanges(); expect(sliderNativeElement.classList).not.toContain('mat-slider-active'); }); it('should not add the mat-slider-sliding class on slide when disabled', () => { expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding'); dispatchSlideStartEvent(sliderNativeElement, 0.46, gestureConfig); fixture.detectChanges(); expect(sliderNativeElement.classList).not.toContain('mat-slider-sliding'); }); it ('should leave thumb gap', () => { expect(trackFillElement.style.transform).toContain('translateX(-7px)'); }); it('should disable tabbing to the slider', () => { expect(sliderNativeElement.tabIndex).toBe(-1); }); }); describe('slider with set min and max', () => { let fixture: ComponentFixture<SliderWithMinAndMax>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let trackFillElement: HTMLElement; let ticksContainerElement: HTMLElement; let ticksElement: HTMLElement; let testComponent: SliderWithMinAndMax; beforeEach(() => { fixture = TestBed.createComponent(SliderWithMinAndMax); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); testComponent = fixture.debugElement.componentInstance; sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); ticksContainerElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-ticks-container'); ticksElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-ticks'); }); it('should set the default values from the attributes', () => { expect(sliderInstance.value).toBe(4); expect(sliderInstance.min).toBe(4); expect(sliderInstance.max).toBe(6); }); it('should set the correct value on click', () => { dispatchClickEventSequence(sliderNativeElement, 0.09); fixture.detectChanges(); // Computed by multiplying the difference between the min and the max by the percentage from // the click and adding that to the minimum. let value = Math.round(4 + (0.09 * (6 - 4))); expect(sliderInstance.value).toBe(value); }); it('should set the correct value on slide', () => { dispatchSlideEventSequence(sliderNativeElement, 0, 0.62, gestureConfig); fixture.detectChanges(); // Computed by multiplying the difference between the min and the max by the percentage from // the click and adding that to the minimum. let value = Math.round(4 + (0.62 * (6 - 4))); expect(sliderInstance.value).toBe(value); }); it('should snap the fill to the nearest value on click', () => { dispatchClickEventSequence(sliderNativeElement, 0.68); fixture.detectChanges(); // The closest snap is halfway on the slider. expect(trackFillElement.style.transform).toContain('scaleX(0.5)'); }); it('should snap the fill to the nearest value on slide', () => { dispatchSlideEventSequence(sliderNativeElement, 0, 0.74, gestureConfig); fixture.detectChanges(); // The closest snap is at the halfway point on the slider. expect(trackFillElement.style.transform).toContain('scaleX(0.5)'); }); it('should adjust fill and ticks on mouse enter when min changes', () => { testComponent.min = -2; fixture.detectChanges(); dispatchMouseenterEvent(sliderNativeElement); fixture.detectChanges(); expect(trackFillElement.style.transform).toContain('scaleX(0.75)'); expect(ticksElement.style.backgroundSize).toBe('75% 2px'); // Make sure it cuts off the last half tick interval. expect(ticksElement.style.transform).toContain('translateX(37.5%)'); expect(ticksContainerElement.style.transform).toBe('translateX(-37.5%)'); }); it('should adjust fill and ticks on mouse enter when max changes', () => { testComponent.min = -2; fixture.detectChanges(); testComponent.max = 10; fixture.detectChanges(); dispatchMouseenterEvent(sliderNativeElement); fixture.detectChanges(); expect(trackFillElement.style.transform).toContain('scaleX(0.5)'); expect(ticksElement.style.backgroundSize).toBe('50% 2px'); // Make sure it cuts off the last half tick interval. expect(ticksElement.style.transform).toContain('translateX(25%)'); expect(ticksContainerElement.style.transform).toBe('translateX(-25%)'); }); }); describe('slider with set value', () => { let fixture: ComponentFixture<SliderWithValue>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(SliderWithValue); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); }); it('should set the default value from the attribute', () => { expect(sliderInstance.value).toBe(26); }); it('should set the correct value on click', () => { dispatchClickEventSequence(sliderNativeElement, 0.92); fixture.detectChanges(); // On a slider with default max and min the value should be approximately equal to the // percentage clicked. This should be the case regardless of what the original set value was. expect(sliderInstance.value).toBe(92); }); it('should set the correct value on slide', () => { dispatchSlideEventSequence(sliderNativeElement, 0, 0.32, gestureConfig); fixture.detectChanges(); expect(sliderInstance.value).toBe(32); }); }); describe('slider with set step', () => { let fixture: ComponentFixture<SliderWithStep>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let trackFillElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(SliderWithStep); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); }); it('should set the correct step value on click', () => { expect(sliderInstance.value).toBe(0); dispatchClickEventSequence(sliderNativeElement, 0.13); fixture.detectChanges(); expect(sliderInstance.value).toBe(25); }); it('should snap the fill to a step on click', () => { dispatchClickEventSequence(sliderNativeElement, 0.66); fixture.detectChanges(); // The closest step is at 75% of the slider. expect(trackFillElement.style.transform).toContain('scaleX(0.75)'); }); it('should set the correct step value on slide', () => { dispatchSlideEventSequence(sliderNativeElement, 0, 0.07, gestureConfig); fixture.detectChanges(); expect(sliderInstance.value).toBe(0); }); it('should snap the thumb and fill to a step on slide', () => { dispatchSlideEventSequence(sliderNativeElement, 0, 0.88, gestureConfig); fixture.detectChanges(); // The closest snap is at the end of the slider. expect(trackFillElement.style.transform).toContain('scaleX(1)'); }); it('should round the value inside the label based on the provided step', () => { let testStep = (step: number, expected: string) => { fixture.componentInstance.step = step; fixture.detectChanges(); dispatchSlideEventSequence(sliderNativeElement, 0, 0.333333, gestureConfig); expect(sliderDebugElement.componentInstance.displayValue.toString()).toBe(expected); }; testStep(1, '33'); testStep(0.1, '33.3'); testStep(0.01, '33.33'); testStep(0.001, '33.333'); }); it('should not add decimals to the value if it is a whole number', () => { fixture.componentInstance.step = 0.1; fixture.detectChanges(); dispatchSlideEventSequence(sliderNativeElement, 0, 1, gestureConfig); expect(sliderDebugElement.componentInstance.displayValue).toBe(100); }); }); describe('slider with auto ticks', () => { let fixture: ComponentFixture<SliderWithAutoTickInterval>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let ticksContainerElement: HTMLElement; let ticksElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(SliderWithAutoTickInterval); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; ticksContainerElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-ticks-container'); ticksElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-ticks'); }); it('should set the correct tick separation on mouse enter', () => { dispatchMouseenterEvent(sliderNativeElement); fixture.detectChanges(); // Ticks should be 30px apart (therefore 30% for a 100px long slider). expect(ticksElement.style.backgroundSize).toBe('30% 2px'); // Make sure it cuts off the last half tick interval. expect(ticksElement.style.transform).toContain('translateX(15%)'); expect(ticksContainerElement.style.transform).toBe('translateX(-15%)'); }); }); describe('slider with set tick interval', () => { let fixture: ComponentFixture<SliderWithSetTickInterval>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let ticksContainerElement: HTMLElement; let ticksElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(SliderWithSetTickInterval); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; ticksContainerElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-ticks-container'); ticksElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-ticks'); }); it('should set the correct tick separation on mouse enter', () => { dispatchMouseenterEvent(sliderNativeElement); fixture.detectChanges(); // Ticks should be every 18 values (tickInterval of 6 * step size of 3). On a slider 100px // long with 100 values, this is 18%. expect(ticksElement.style.backgroundSize).toBe('18% 2px'); // Make sure it cuts off the last half tick interval. expect(ticksElement.style.transform).toContain('translateX(9%)'); expect(ticksContainerElement.style.transform).toBe('translateX(-9%)'); }); it('should be able to reset the tick interval after it has been set', () => { expect(sliderNativeElement.classList) .toContain('mat-slider-has-ticks', 'Expected element to have ticks initially.'); fixture.componentInstance.tickInterval = 0; fixture.detectChanges(); expect(sliderNativeElement.classList) .not.toContain('mat-slider-has-ticks', 'Expected element not to have ticks after reset.'); }); }); describe('slider with thumb label', () => { let fixture: ComponentFixture<SliderWithThumbLabel>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let thumbLabelTextElement: Element; beforeEach(() => { fixture = TestBed.createComponent(SliderWithThumbLabel); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.componentInstance; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); thumbLabelTextElement = sliderNativeElement.querySelector('.mat-slider-thumb-label-text')!; }); it('should add the thumb label class to the slider container', () => { expect(sliderNativeElement.classList).toContain('mat-slider-thumb-label-showing'); }); it('should update the thumb label text on click', () => { expect(thumbLabelTextElement.textContent).toBe('0'); dispatchClickEventSequence(sliderNativeElement, 0.13); fixture.detectChanges(); // The thumb label text is set to the slider's value. These should always be the same. expect(thumbLabelTextElement.textContent).toBe('13'); }); it('should update the thumb label text on slide', () => { expect(thumbLabelTextElement.textContent).toBe('0'); dispatchSlideEventSequence(sliderNativeElement, 0, 0.56, gestureConfig); fixture.detectChanges(); // The thumb label text is set to the slider's value. These should always be the same. expect(thumbLabelTextElement.textContent).toBe(`${sliderInstance.value}`); }); }); describe('slider with value property binding', () => { let fixture: ComponentFixture<SliderWithOneWayBinding>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let testComponent: SliderWithOneWayBinding; let trackFillElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(SliderWithOneWayBinding); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); }); it('should initialize based on bound value', () => { expect(sliderInstance.value).toBe(50); expect(trackFillElement.style.transform).toContain('scaleX(0.5)'); }); it('should update when bound value changes', () => { testComponent.val = 75; fixture.detectChanges(); expect(sliderInstance.value).toBe(75); expect(trackFillElement.style.transform).toContain('scaleX(0.75)'); }); }); describe('slider with set min and max and a value smaller than min', () => { let fixture: ComponentFixture<SliderWithValueSmallerThanMin>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let trackFillElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(SliderWithValueSmallerThanMin); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.componentInstance; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); }); it('should set the value smaller than the min value', () => { expect(sliderInstance.value).toBe(3); expect(sliderInstance.min).toBe(4); expect(sliderInstance.max).toBe(6); }); it('should set the fill to the min value', () => { expect(trackFillElement.style.transform).toContain('scaleX(0)'); }); }); describe('slider with set min and max and a value greater than max', () => { let fixture: ComponentFixture<SliderWithValueSmallerThanMin>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let trackFillElement: HTMLElement; beforeEach(() => { fixture = TestBed.createComponent(SliderWithValueGreaterThanMax); fixture.detectChanges(); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.componentInstance; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); }); it('should set the value greater than the max value', () => { expect(sliderInstance.value).toBe(7); expect(sliderInstance.min).toBe(4); expect(sliderInstance.max).toBe(6); }); it('should set the fill to the max value', () => { expect(trackFillElement.style.transform).toContain('scaleX(1)'); }); }); describe('slider with change handler', () => { let fixture: ComponentFixture<SliderWithChangeHandler>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderWrapperElement: HTMLElement; let testComponent: SliderWithChangeHandler; beforeEach(() => { fixture = TestBed.createComponent(SliderWithChangeHandler); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; spyOn(testComponent, 'onChange'); spyOn(testComponent, 'onInput'); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); }); it('should emit change on click', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchClickEventSequence(sliderNativeElement, 0.2); fixture.detectChanges(); expect(testComponent.onChange).toHaveBeenCalledTimes(1); }); it('should emit change on slide', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchSlideEventSequence(sliderNativeElement, 0, 0.4, gestureConfig); fixture.detectChanges(); expect(testComponent.onChange).toHaveBeenCalledTimes(1); }); it('should not emit multiple changes for same value', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchClickEventSequence(sliderNativeElement, 0.6); dispatchSlideEventSequence(sliderNativeElement, 0.6, 0.6, gestureConfig); fixture.detectChanges(); expect(testComponent.onChange).toHaveBeenCalledTimes(1); }); it('should dispatch events when changing back to previously emitted value after ' + 'programmatically setting value', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); expect(testComponent.onInput).not.toHaveBeenCalled(); dispatchClickEventSequence(sliderNativeElement, 0.2); fixture.detectChanges(); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(testComponent.onInput).toHaveBeenCalledTimes(1); testComponent.slider.value = 0; fixture.detectChanges(); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(testComponent.onInput).toHaveBeenCalledTimes(1); dispatchClickEventSequence(sliderNativeElement, 0.2); fixture.detectChanges(); expect(testComponent.onChange).toHaveBeenCalledTimes(2); expect(testComponent.onInput).toHaveBeenCalledTimes(2); }); }); describe('slider with input event', () => { let fixture: ComponentFixture<SliderWithChangeHandler>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderWrapperElement: HTMLElement; let testComponent: SliderWithChangeHandler; beforeEach(() => { fixture = TestBed.createComponent(SliderWithChangeHandler); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; spyOn(testComponent, 'onInput'); spyOn(testComponent, 'onChange'); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); }); it('should emit an input event while sliding', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchMouseenterEvent(sliderNativeElement); dispatchSlideEvent(sliderNativeElement, 0.5, gestureConfig); dispatchSlideEvent(sliderNativeElement, 1, gestureConfig); dispatchSlideEndEvent(sliderNativeElement, 1, gestureConfig); fixture.detectChanges(); // The input event should fire twice, because the slider changed two times. expect(testComponent.onInput).toHaveBeenCalledTimes(2); expect(testComponent.onChange).toHaveBeenCalledTimes(1); }); it('should emit an input event when clicking', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchClickEventSequence(sliderNativeElement, 0.75); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single click. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); }); }); describe('keyboard support', () => { let fixture: ComponentFixture<SliderWithChangeHandler>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderWrapperElement: HTMLElement; let testComponent: SliderWithChangeHandler; let sliderInstance: MatSlider; beforeEach(() => { fixture = TestBed.createComponent(SliderWithChangeHandler); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; spyOn(testComponent, 'onInput'); spyOn(testComponent, 'onChange'); sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); }); it('should increment slider by 1 on up arrow pressed', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', UP_ARROW); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(1); }); it('should increment slider by 1 on right arrow pressed', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(1); }); it('should decrement slider by 1 on down arrow pressed', () => { sliderInstance.value = 100; expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', DOWN_ARROW); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(99); }); it('should decrement slider by 1 on left arrow pressed', () => { sliderInstance.value = 100; expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(99); }); it('should increment slider by 10 on page up pressed', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', PAGE_UP); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(10); }); it('should decrement slider by 10 on page down pressed', () => { sliderInstance.value = 100; expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', PAGE_DOWN); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(90); }); it('should set slider to max on end pressed', () => { expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', END); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(100); }); it('should set slider to min on home pressed', () => { sliderInstance.value = 100; expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', HOME); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).toHaveBeenCalledTimes(1); expect(testComponent.onChange).toHaveBeenCalledTimes(1); expect(sliderInstance.value).toBe(0); }); it(`should take not action for presses of keys it doesn't care about`, () => { sliderInstance.value = 50; expect(testComponent.onChange).not.toHaveBeenCalled(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', BACKSPACE); fixture.detectChanges(); // The `onInput` event should be emitted once due to a single keyboard press. expect(testComponent.onInput).not.toHaveBeenCalled(); expect(testComponent.onChange).not.toHaveBeenCalled(); expect(sliderInstance.value).toBe(50); }); }); describe('slider with direction and invert', () => { let fixture: ComponentFixture<SliderWithDirAndInvert>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderWrapperElement: HTMLElement; let sliderInstance: MatSlider; let testComponent: SliderWithDirAndInvert; beforeEach(() => { fixture = TestBed.createComponent(SliderWithDirAndInvert); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderNativeElement = sliderDebugElement.nativeElement; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); }); it('works in inverted mode', () => { testComponent.invert = true; fixture.detectChanges(); dispatchClickEventSequence(sliderNativeElement, 0.3); fixture.detectChanges(); expect(sliderInstance.value).toBe(70); }); it('works in RTL languages', () => { testComponent.dir = 'rtl'; fixture.detectChanges(); dispatchClickEventSequence(sliderNativeElement, 0.3); fixture.detectChanges(); expect(sliderInstance.value).toBe(70); }); it('works in RTL languages in inverted mode', () => { testComponent.dir = 'rtl'; testComponent.invert = true; fixture.detectChanges(); dispatchClickEventSequence(sliderNativeElement, 0.3); fixture.detectChanges(); expect(sliderInstance.value).toBe(30); }); it('should re-render slider with updated style upon directionality change', () => { testComponent.dir = 'rtl'; fixture.detectChanges(); let initialTrackFillStyles = sliderInstance._trackFillStyles; let initialTicksContainerStyles = sliderInstance._ticksContainerStyles; let initialTicksStyles = sliderInstance._ticksStyles; let initialThumbContainerStyles = sliderInstance._thumbContainerStyles; testComponent.dir = 'ltr'; fixture.detectChanges(); expect(initialTrackFillStyles).not.toEqual(sliderInstance._trackFillStyles); expect(initialTicksContainerStyles).not.toEqual(sliderInstance._ticksContainerStyles); expect(initialTicksStyles).not.toEqual(sliderInstance._ticksStyles); expect(initialThumbContainerStyles).not.toEqual(sliderInstance._thumbContainerStyles); }); it('should increment inverted slider by 1 on right arrow pressed', () => { testComponent.invert = true; fixture.detectChanges(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW); fixture.detectChanges(); expect(sliderInstance.value).toBe(1); }); it('should decrement inverted slider by 1 on left arrow pressed', () => { testComponent.invert = true; sliderInstance.value = 100; fixture.detectChanges(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW); fixture.detectChanges(); expect(sliderInstance.value).toBe(99); }); it('should decrement RTL slider by 1 on right arrow pressed', () => { testComponent.dir = 'rtl'; sliderInstance.value = 100; fixture.detectChanges(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW); fixture.detectChanges(); expect(sliderInstance.value).toBe(99); }); it('should increment RTL slider by 1 on left arrow pressed', () => { testComponent.dir = 'rtl'; fixture.detectChanges(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW); fixture.detectChanges(); expect(sliderInstance.value).toBe(1); }); it('should decrement inverted RTL slider by 1 on right arrow pressed', () => { testComponent.dir = 'rtl'; testComponent.invert = true; sliderInstance.value = 100; fixture.detectChanges(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', RIGHT_ARROW); fixture.detectChanges(); expect(sliderInstance.value).toBe(99); }); it('should increment inverted RTL slider by 1 on left arrow pressed', () => { testComponent.dir = 'rtl'; testComponent.invert = true; fixture.detectChanges(); dispatchKeyboardEvent(sliderNativeElement, 'keydown', LEFT_ARROW); fixture.detectChanges(); expect(sliderInstance.value).toBe(1); }); it('should hide last tick when inverted and at min value', () => { testComponent.invert = true; fixture.detectChanges(); expect(sliderNativeElement.classList.contains('mat-slider-hide-last-tick')) .toBe(true, 'last tick should be hidden'); }); }); describe('vertical slider', () => { let fixture: ComponentFixture<VerticalSlider>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderWrapperElement: HTMLElement; let trackFillElement: HTMLElement; let sliderInstance: MatSlider; let testComponent: VerticalSlider; beforeEach(() => { fixture = TestBed.createComponent(VerticalSlider); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderNativeElement = sliderDebugElement.nativeElement; sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); trackFillElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-track-fill'); }); it('updates value on click', () => { dispatchClickEventSequence(sliderNativeElement, 0.3); fixture.detectChanges(); expect(sliderInstance.value).toBe(70); }); it('updates value on click in inverted mode', () => { testComponent.invert = true; fixture.detectChanges(); dispatchClickEventSequence(sliderNativeElement, 0.3); fixture.detectChanges(); expect(sliderInstance.value).toBe(30); }); it('should update the track fill on click', () => { expect(trackFillElement.style.transform).toContain('scaleY(0)'); dispatchClickEventSequence(sliderNativeElement, 0.39); fixture.detectChanges(); expect(trackFillElement.style.transform).toContain('scaleY(0.61)'); }); it('should update the track fill on click in inverted mode', () => { testComponent.invert = true; fixture.detectChanges(); expect(trackFillElement.style.transform).toContain('scaleY(0)'); dispatchClickEventSequence(sliderNativeElement, 0.39); fixture.detectChanges(); expect(trackFillElement.style.transform).toContain('scaleY(0.39)'); }); it('should have aria-orientation vertical', () => { expect(sliderNativeElement.getAttribute('aria-orientation')).toEqual('vertical'); }); }); describe('tabindex', () => { it('should allow setting the tabIndex through binding', () => { const fixture = TestBed.createComponent(SliderWithTabIndexBinding); fixture.detectChanges(); const slider = fixture.debugElement.query(By.directive(MatSlider)).componentInstance; expect(slider.tabIndex).toBe(0, 'Expected the tabIndex to be set to 0 by default.'); fixture.componentInstance.tabIndex = 3; fixture.detectChanges(); expect(slider.tabIndex).toBe(3, 'Expected the tabIndex to have been changed.'); }); it('should detect the native tabindex attribute', () => { const fixture = TestBed.createComponent(SliderWithNativeTabindexAttr); fixture.detectChanges(); const slider = fixture.debugElement.query(By.directive(MatSlider)).componentInstance; expect(slider.tabIndex) .toBe(5, 'Expected the tabIndex to be set to the value of the native attribute.'); }); }); }); describe('MatSlider with forms module', () => { let gestureConfig: TestGestureConfig; beforeEach(async(() => { TestBed.configureTestingModule({ imports: [MatSliderModule, ReactiveFormsModule, FormsModule, BidiModule], declarations: [ SliderWithFormControl, SliderWithNgModel, ], providers: [ {provide: HAMMER_GESTURE_CONFIG, useFactory: () => { gestureConfig = new TestGestureConfig(); return gestureConfig; }} ], }); TestBed.compileComponents(); })); describe('slider with ngModel', () => { let fixture: ComponentFixture<SliderWithNgModel>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let testComponent: SliderWithNgModel; beforeEach(() => { fixture = TestBed.createComponent(SliderWithNgModel); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); }); it('should update the model on click', () => { expect(testComponent.val).toBe(0); dispatchClickEventSequence(sliderNativeElement, 0.76); fixture.detectChanges(); expect(testComponent.val).toBe(76); }); it('should update the model on slide', () => { expect(testComponent.val).toBe(0); dispatchSlideEventSequence(sliderNativeElement, 0, 0.19, gestureConfig); fixture.detectChanges(); expect(testComponent.val).toBe(19); }); it('should update the model on keydown', () => { expect(testComponent.val).toBe(0); dispatchKeyboardEvent(sliderNativeElement, 'keydown', UP_ARROW); fixture.detectChanges(); expect(testComponent.val).toBe(1); }); }); describe('slider as a custom form control', () => { let fixture: ComponentFixture<SliderWithFormControl>; let sliderDebugElement: DebugElement; let sliderNativeElement: HTMLElement; let sliderInstance: MatSlider; let sliderWrapperElement: HTMLElement; let testComponent: SliderWithFormControl; beforeEach(() => { fixture = TestBed.createComponent(SliderWithFormControl); fixture.detectChanges(); testComponent = fixture.debugElement.componentInstance; sliderDebugElement = fixture.debugElement.query(By.directive(MatSlider)); sliderNativeElement = sliderDebugElement.nativeElement; sliderInstance = sliderDebugElement.injector.get<MatSlider>(MatSlider); sliderWrapperElement = <HTMLElement>sliderNativeElement.querySelector('.mat-slider-wrapper'); }); it('should not update the control when the value is updated', () => { expect(testComponent.control.value).toBe(0); sliderInstance.value = 11; fixture.detectChanges(); expect(testComponent.control.value).toBe(0); }); it('should update the control on click', () => { expect(testComponent.control.value).toBe(0); dispatchClickEventSequence(sliderNativeElement, 0.76); fixture.detectChanges(); expect(testComponent.control.value).toBe(76); }); it('should update the control on slide', () => { expect(testComponent.control.value).toBe(0); dispatchSlideEventSequence(sliderNativeElement, 0, 0.19, gestureConfig); fixture.detectChanges(); expect(testComponent.control.value).toBe(19); }); it('should update the value when the control is set', () => { expect(sliderInstance.value).toBe(0); testComponent.control.setValue(7); fixture.detectChanges(); expect(sliderInstance.value).toBe(7); }); it('should update the disabled state when control is disabled', (