import { Component , DebugElement } from '@angular/core' ; import { async , ComponentFixture , fakeAsync , flushMicrotasks , TestBed } from '@angular/core/testing' ; import { FormsModule , NgModel , ReactiveFormsModule } from '@angular/forms' ; import { By } from '@angular/platform-browser' ; import { Platform } from '@angular/cdk/platform' ; import { dispatchFakeEvent , dispatchMouseEvent } from '@angular-mdc/web/testing' ; import { MdcCheckbox , MdcCheckboxModule } from './index' ; describe ( 'MdcCheckbox' , ( ) => { let fixture ; let platform ; beforeEach ( fakeAsync ( ( ) => { platform = { isBrowser : true } ; TestBed . configureTestingModule ( { imports : [ MdcCheckboxModule , FormsModule , ReactiveFormsModule ] , declarations : [ SingleCheckbox , CheckboxWithAriaLabelledby , CheckboxWithAriaLabel , CheckboxWithTabIndex , CheckboxWithFormDirectives , DisabledCheckbox , ] , providers : [ { provide : Platform , useFactory : ( ) => platform } ] } ) ; TestBed . compileComponents ( ) ; } ) ) ; describe ( 'Tests for SSR' , ( ) => { let testDebugElement ; let testInstance ; let testComponent ; beforeEach ( ( ) => { platform = { isBrowser : false } ; fixture = TestBed . createComponent ( SingleCheckbox ) ; fixture . detectChanges ( ) ; testDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; testInstance = testDebugElement . componentInstance ; testComponent = fixture . debugElement . componentInstance ; } ) ; it ( '#should have mdc-checkbox by default' , ( ) => { expect ( testDebugElement . nativeElement . classList ) . toContain ( 'mdc-checkbox' , 'Expected to have mdc-checkbox' ) ; } ) ; } ) ; describe ( 'disabled checkbox' , ( ) => { let testDebugElement ; let testNativeElement ; let testInstance ; let testComponent ; beforeEach ( async ( ( ) => { fixture = TestBed . createComponent ( DisabledCheckbox ) ; fixture . detectChanges ( ) ; testDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; testNativeElement = testDebugElement . nativeElement ; testInstance = testDebugElement . componentInstance ; testComponent = fixture . debugElement . componentInstance ; } ) ) ; it ( '#should be disabled' , ( ) => { fixture . detectChanges ( ) ; expect ( testInstance . _inputElement . nativeElement . disabled ) . toBe ( true ) ; } ) ; } ) ; describe ( 'basic behaviors' , ( ) => { let checkboxDebugElement ; let checkboxNativeElement ; let checkboxInstance ; let testComponent ; let inputElement ; beforeEach ( ( ) => { fixture = TestBed . createComponent ( SingleCheckbox ) ; fixture . detectChanges ( ) ; checkboxDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; checkboxNativeElement = checkboxDebugElement . nativeElement ; checkboxInstance = checkboxDebugElement . componentInstance ; testComponent = fixture . debugElement . componentInstance ; inputElement = checkboxInstance . _inputElement . nativeElement ; } ) ; it ( '#should change native element checked when check programmatically' , ( ) => { expect ( inputElement . checked ) . toBe ( false ) ; checkboxInstance . checked = true ; fixture . detectChanges ( ) ; expect ( inputElement . checked ) . toBe ( true ) ; } ) ; it ( 'handles animationend event' , fakeAsync ( ( ) => { dispatchFakeEvent ( checkboxInstance . elementRef . nativeElement , 'animationend' ) ; } ) ) ; it ( '#should toggle checked state on click' , ( ) => { expect ( checkboxInstance . checked ) . toBe ( false ) ; inputElement . click ( ) ; fixture . detectChanges ( ) ; expect ( checkboxInstance . checked ) . toBe ( true ) ; inputElement . click ( ) ; fixture . detectChanges ( ) ; expect ( checkboxInstance . checked ) . toBe ( false ) ; } ) ; it ( '#should add and remove disabled state' , ( ) => { expect ( checkboxInstance . disabled ) . toBe ( false ) ; expect ( checkboxNativeElement . classList ) . not . toContain ( 'mdc-checkbox--disabled' ) ; expect ( inputElement . tabIndex ) . toBe ( 0 ) ; expect ( inputElement . disabled ) . toBe ( false ) ; testComponent . isDisabled = true ; fixture . detectChanges ( ) ; expect ( checkboxInstance . disabled ) . toBe ( true ) ; expect ( checkboxNativeElement . classList ) . toContain ( 'mdc-checkbox--disabled' ) ; expect ( inputElement . disabled ) . toBe ( true ) ; testComponent . isDisabled = false ; fixture . detectChanges ( ) ; expect ( checkboxInstance . disabled ) . toBe ( false ) ; expect ( checkboxNativeElement . classList ) . not . toContain ( 'mdc-checkbox--disabled' ) ; expect ( inputElement . tabIndex ) . toBe ( 0 ) ; expect ( inputElement . disabled ) . toBe ( false ) ; } ) ; it ( '#should not toggle `checked` state upon interation while disabled' , ( ) => { testComponent . isDisabled = true ; fixture . detectChanges ( ) ; dispatchMouseEvent ( checkboxInstance . _inputElement . nativeElement , 'click' ) ; fixture . detectChanges ( ) ; expect ( checkboxInstance . checked ) . toBe ( false ) ; } ) ; it ( '#should preserve the user-provided id' , ( ) => { expect ( checkboxNativeElement . id ) . toBe ( 'simple-check' ) ; expect ( inputElement . id ) . toBe ( 'simple-check-input' ) ; } ) ; it ( '#should generate a unique id for the checkbox input if no id is set' , ( ) => { testComponent . checkboxId = null ; fixture . detectChanges ( ) ; expect ( checkboxInstance . inputId ) . toMatch ( /mdc-checkbox-\d+/ ) ; expect ( inputElement . id ) . toBe ( checkboxInstance . inputId ) ; } ) ; it ( '#should focus on underlying input element when focus() is called' , ( ) => { expect ( document . activeElement ) . not . toBe ( inputElement ) ; checkboxInstance . focus ( ) ; fixture . detectChanges ( ) ; expect ( document . activeElement ) . toBe ( inputElement ) ; } ) ; it ( '#should not set focus on element when focus() is called and disabled' , ( ) => { checkboxInstance . disabled = true ; fixture . detectChanges ( ) ; checkboxInstance . focus ( ) ; fixture . detectChanges ( ) ; expect ( document . activeElement ) . not . toBe ( inputElement ) ; } ) ; it ( '#should forward the value to input element' , ( ) => { checkboxInstance . checked = true ; fixture . detectChanges ( ) ; expect ( inputElement . checked ) . toBe ( true ) ; } ) ; it ( '#should forward the value to input element' , ( ) => { testComponent . checkboxValue = true ; fixture . detectChanges ( ) ; expect ( inputElement . checked ) . toBe ( true ) ; } ) ; it ( '#should not set indeterminate to true' , ( ) => { testComponent . isDisabled = true ; fixture . detectChanges ( ) ; checkboxInstance . indeterminate = true ; fixture . detectChanges ( ) ; expect ( checkboxInstance . indeterminate ) . toBe ( false ) ; } ) ; it ( '#should not set checked to false' , ( ) => { checkboxInstance . indeterminate = true ; checkboxInstance . indeterminateToChecked = false ; fixture . detectChanges ( ) ; inputElement . click ( ) ; fixture . detectChanges ( ) ; expect ( inputElement . checked ) . toBe ( false ) ; expect ( checkboxInstance . indeterminate ) . toBe ( false ) ; } ) ; it ( '#should set checked to true' , ( ) => { testComponent . indeterminate = true ; fixture . detectChanges ( ) ; checkboxInstance . toggle ( ) ; fixture . detectChanges ( ) ; expect ( inputElement . checked ) . toBe ( true ) ; } ) ; it ( '#should set checked to false' , ( ) => { testComponent . indeterminateToChecked = false ; fixture . detectChanges ( ) ; testComponent . indeterminate = false ; fixture . detectChanges ( ) ; expect ( checkboxInstance . checked ) . toBe ( false ) ; } ) ; it ( '#should set indeterminate to true' , ( ) => { testComponent . indeterminate = true ; fixture . detectChanges ( ) ; expect ( checkboxInstance . indeterminate ) . toBe ( true ) ; } ) ; it ( 'expect disableRipple to be true' , ( ) => { testComponent . disableRipple = true ; fixture . detectChanges ( ) ; expect ( checkboxInstance . disableRipple ) . toBe ( true ) ; } ) ; describe ( 'with provided aria-label' , ( ) => { let checkboxDebugElement ; let checkboxNativeElement ; let inputElement ; it ( 'should use the provided aria-label' , ( ) => { fixture = TestBed . createComponent ( CheckboxWithAriaLabel ) ; checkboxDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; checkboxNativeElement = checkboxDebugElement . nativeElement ; inputElement = < HTMLInputElement > checkboxNativeElement . querySelector ( 'input' ) ; fixture . detectChanges ( ) ; expect ( inputElement . getAttribute ( 'aria-label' ) ) . toBe ( 'Super effective' ) ; } ) ; } ) ; describe ( 'with provided aria-labelledby' , ( ) => { let checkboxDebugElement ; let checkboxNativeElement ; let inputElement ; it ( '#should use the provided aria-labelledby' , ( ) => { fixture = TestBed . createComponent ( CheckboxWithAriaLabelledby ) ; checkboxDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; checkboxNativeElement = checkboxDebugElement . nativeElement ; inputElement = < HTMLInputElement > checkboxNativeElement . querySelector ( 'input' ) ; fixture . detectChanges ( ) ; expect ( inputElement . getAttribute ( 'aria-labelledby' ) ) . toBe ( 'some-id' ) ; } ) ; it ( '#should not assign aria-labelledby if none is provided' , ( ) => { fixture = TestBed . createComponent ( SingleCheckbox ) ; checkboxDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; checkboxNativeElement = checkboxDebugElement . nativeElement ; inputElement = < HTMLInputElement > checkboxNativeElement . querySelector ( 'input' ) ; fixture . detectChanges ( ) ; expect ( inputElement . getAttribute ( 'aria-labelledby' ) ) . toBe ( null ) ; } ) ; } ) ; describe ( 'with provided tabIndex' , ( ) => { let checkboxDebugElement ; let checkboxNativeElement ; let testComponent ; let inputElement ; let labelElement ; beforeEach ( ( ) => { fixture = TestBed . createComponent ( CheckboxWithTabIndex ) ; fixture . detectChanges ( ) ; testComponent = fixture . debugElement . componentInstance ; checkboxDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; checkboxNativeElement = checkboxDebugElement . nativeElement ; inputElement = < HTMLInputElement > checkboxNativeElement . querySelector ( 'input' ) ; labelElement = < HTMLLabelElement > checkboxNativeElement . querySelector ( 'label' ) ; } ) ; it ( '#should preserve any given tabIndex' , ( ) => { expect ( inputElement . tabIndex ) . toBe ( 7 ) ; } ) ; it ( '#should preserve given tabIndex when the checkbox is disabled then enabled' , ( ) => { testComponent . isDisabled = true ; fixture . detectChanges ( ) ; testComponent . customTabIndex = 13 ; fixture . detectChanges ( ) ; testComponent . isDisabled = false ; fixture . detectChanges ( ) ; expect ( inputElement . tabIndex ) . toBe ( 13 ) ; } ) ; } ) ; describe ( 'with ngModel' , ( ) => { let checkboxDebugElement ; let checkboxNativeElement ; let checkboxInstance ; let inputElement ; beforeEach ( ( ) => { fixture = TestBed . createComponent ( CheckboxWithFormDirectives ) ; fixture . detectChanges ( ) ; checkboxDebugElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; checkboxNativeElement = checkboxDebugElement . nativeElement ; checkboxInstance = checkboxDebugElement . componentInstance ; inputElement = < HTMLInputElement > checkboxNativeElement . querySelector ( 'input' ) ; } ) ; it ( '#should be in pristine, untouched, and valid states initially' , fakeAsync ( ( ) => { flushMicrotasks ( ) ; const checkboxElement = fixture . debugElement . query ( By . directive ( MdcCheckbox ) ) ; const ngModel = checkboxElement . injector . get < NgModel > ( NgModel ) ; expect ( ngModel . valid ) . toBe ( true ) ; expect ( ngModel . pristine ) . toBe ( true ) ; expect ( ngModel . touched ) . toBe ( false ) ; } ) ) ; it ( '#should toggle checked state on click' , ( ) => { inputElement . click ( ) ; fixture . detectChanges ( ) ; expect ( checkboxInstance . checked ) . toBe ( true ) ; inputElement . click ( ) ; fixture . detectChanges ( ) ; expect ( checkboxInstance . checked ) . toBe ( false ) ; } ) ; } ) ; } ) ; } ) ; /** Simple component for testing MdcCheckbox. */ @ Component ( { template : `
    <mdc-checkbox
      [id]="checkboxId"
      [(ngModel)]="checkboxValue"
      [checked]="checkboxValue"
      [touch]="touch"
      [indeterminateToChecked]="indeterminateToChecked"
      [indeterminate]="indeterminate"
      [disableRipple]="disableRipple"
      [disabled]="isDisabled">
    </mdc-checkbox>
  ` , } ) class SingleCheckbox { checkboxId : string | null = 'simple-check' ; isDisabled : boolean = false ; indeterminate : boolean ; checkboxValue : boolean = false ; indeterminateToChecked : boolean = true ; disableRipple : boolean ; touch : boolean = false ; } /** Simple test component with an aria-label set. */ @ Component ( { template : `<mdc-checkbox aria-labelledby="some-id"></mdc-checkbox>` } ) class CheckboxWithAriaLabelledby { } /** Simple test component with an aria-label set. */ @ Component ( { template : `<mdc-checkbox aria-label="Super effective"></mdc-checkbox>` } ) class CheckboxWithAriaLabel { } /** Simple test component with tabIndex */ @ Component ( { template : `
    <mdc-checkbox
        [tabIndex]="customTabIndex"
        [disabled]="isDisabled">
    </mdc-checkbox>` , } ) class CheckboxWithTabIndex { customTabIndex : number = 7 ; isDisabled : boolean = false ; } /** Simple component for testing an MdcCheckbox with ngModel in a form. */ @ Component ( { template : `
    <form>
      <mdc-checkbox name="cb" [(ngModel)]="isGood">Be good</mdc-checkbox>
    </form>
  ` , } ) class CheckboxWithFormDirectives { isGood : boolean = false ; } @ Component ( { template : `<mdc-checkbox disabled></mdc-checkbox>` , } ) class DisabledCheckbox { }