import assertionTemplate from '@dojo/framework/testing/harness/assertionTemplate' ; import * as themeCss from '../../../theme/default/chip-typeahead.m.css' ; import { tsx } from '@dojo/framework/core/vdom' ; import { compareTheme , createHarness , compareResource } from '../../../common/tests/support/test-helpers' ; import Typeahead from '../../../typeahead' ; import { stub } from 'sinon' ; import { ListOption , ListItem } from '../../../list' ; import ChipTypeahead from '../..' ; import * as typeaheadCss from '../../../theme/default/typeahead.m.css' ; import * as chipCss from '../../../theme/default/chip.m.css' ; import Chip from '../../../chip/index' ; const { assert } = intern . getPlugin ( 'chai' ) ; const harness = createHarness ( [ compareTheme , compareResource ] ) ; const { registerSuite } = intern . getInterface ( 'object' ) ; const noop = stub ( ) ; const animalOptions = [ { value : '1' , label : 'Dog' } , { value : '2' , label : 'Cat' } , { value : '3' , label : 'Fish' , disabled : true } ] ; const baseAssertion = assertionTemplate ( ( ) => ( < div key = "root" classes = { [ undefined , null , themeCss . root , null , null , themeCss . noLabel ] } > < Typeahead strict = { undefined } key = "typeahead" theme = { { '@dojo/widgets/typeahead' : typeaheadCss } } itemsInView = { undefined } position = { undefined } name = { undefined } focus = { ( ) => false } itemDisabled = { stub ( ) } disabled = { undefined } resource = { { } as any } onValue = { stub } value = "" onFocus = { stub } onBlur = { stub } variant = { undefined } classes = { { '@dojo/widgets/text-input' : { input : [ themeCss . input ] , wrapper : [ themeCss . wrapper ] , leading : [ themeCss . inputLeading ] , leadingWrapper : [ themeCss . inputLeadingWrapper ] , defaultKind : [ themeCss . defaultKind ] , outlinedKind : [ themeCss . outlinedKind ] , labelWrapper : [ themeCss . inputLabel ] , label : [ themeCss . label , undefined ] , notchedOutline : [ undefined ] } } } kind = { undefined } > { { items : stub as any , leading : [ 'test' ] } } < /Typeahead> < /div>)); const labeledAssertion = assertionTemplate ( ( ) => ( < div key = "root" classes = { [ undefined , null , themeCss . root , null , null , themeCss . hasLabel ] } > < Typeahead strict = { undefined } key = "typeahead" theme = { { '@dojo/widgets/typeahead' : typeaheadCss } } itemsInView = { undefined } position = { undefined } name = { undefined } focus = { ( ) => false } itemDisabled = { stub ( ) } disabled = { undefined } resource = { { } as any } onValue = { stub } value = "" onFocus = { stub } onBlur = { stub } variant = { undefined } classes = { { '@dojo/widgets/text-input' : { input : [ themeCss . input ] , wrapper : [ themeCss . wrapper ] , leading : [ themeCss . inputLeading ] , leadingWrapper : [ themeCss . inputLeadingWrapper ] , defaultKind : [ themeCss . defaultKind ] , outlinedKind : [ themeCss . outlinedKind ] , labelWrapper : [ themeCss . inputLabel ] , label : [ themeCss . label , undefined ] , notchedOutline : [ undefined ] } } } kind = { undefined } > { { items : stub as any , leading : [ 'test' ] , label : 'Label' } } < /Typeahead> < /div>)); const labelActiveAssertion = baseAssertion . setProperty ( '@typeahead' , 'classes' , { '@dojo/widgets/text-input' : { input : [ themeCss . input ] , wrapper : [ themeCss . wrapper ] , leading : [ themeCss . inputLeading ] , leadingWrapper : [ themeCss . inputLeadingWrapper ] , defaultKind : [ themeCss . defaultKind ] , outlinedKind : [ themeCss . outlinedKind ] , labelWrapper : [ themeCss . inputLabel ] , label : [ themeCss . label , themeCss . labelActive ] , notchedOutline : [ undefined ] } } ) ; const hasValueAssertion = labelActiveAssertion . setProperty ( '@root' , 'classes' , [ undefined , null , themeCss . root , themeCss . hasValue , null , themeCss . noLabel ] ) ; const disabledAssertion = hasValueAssertion . setProperty ( '@typeahead' , 'disabled' , true ) . setProperty ( '@root' , 'classes' , [ undefined , themeCss . disabled , themeCss . root , themeCss . hasValue , null , themeCss . noLabel ] ) ; const focusedAssertion = baseAssertion . setProperty ( '@root' , 'classes' , [ undefined , null , themeCss . root , null , themeCss . focused , themeCss . noLabel ] ) ; const bottomAssertion = hasValueAssertion . insertAfter ( '@typeahead' , ( ) => [ < div classes = { themeCss . values } > < Chip theme = { { '@dojo/widgets/chip' : chipCss } } disabled = { undefined } key = "value-2" classes = { { '@dojo/widgets/chip' : { root : [ themeCss . value ] } } } onClose = { stub } variant = { undefined } > { { label : 'Cat' } } < /Chip> < /div> ] ) ; registerSuite ( 'ChipTypeahead' , { tests : { 'renders empty' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } onValue = { noop } > < /ChipTypeahead>)); h . expect ( baseAssertion ) ; } , 'renders with an initial value' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } onValue = { noop } initialValue = { [ '2' ] } > < /ChipTypeahead>)); h . expect ( hasValueAssertion ) ; const chips = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; h . expect ( ( ) => [ < Chip theme = { { '@dojo/widgets/chip' : chipCss } } disabled = { undefined } key = "value-2" classes = { { '@dojo/widgets/chip' : { root : [ themeCss . value ] } } } onClose = { stub } variant = { undefined } > { { label : 'Cat' } } < /Chip> ] , ( ) => chips ) ; assert . isTrue ( chips [ 0 ] . children [ 0 ] . label === 'Cat' ) ; } , 'renders with controlled values' ( ) { const properties = { value : [ '2' ] } ; const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } onValue = { noop } { ... properties } > < /ChipTypeahead>)); h . expect ( hasValueAssertion ) ; let chips = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; h . expect ( ( ) => [ < Chip theme = { { '@dojo/widgets/chip' : chipCss } } disabled = { undefined } key = "value-2" classes = { { '@dojo/widgets/chip' : { root : [ themeCss . value ] } } } onClose = { stub } variant = { undefined } > { { label : 'Cat' } } < /Chip> ] , ( ) => chips ) ; assert . isTrue ( chips [ 0 ] . children [ 0 ] . label === 'Cat' ) ; properties . value = [ '1' ] ; h . expect ( hasValueAssertion ) ; chips = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; h . expect ( ( ) => [ < Chip theme = { { '@dojo/widgets/chip' : chipCss } } disabled = { undefined } key = "value-1" classes = { { '@dojo/widgets/chip' : { root : [ themeCss . value ] } } } onClose = { stub } variant = { undefined } > { { label : 'Dog' } } < /Chip> ] , ( ) => chips ) ; } , 'renders chips with custom renderer' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } onValue = { noop } initialValue = { [ '2' ] } > { { selected : ( _ , label ) => label . toUpperCase ( ) } } < /ChipTypeahead>)); h . expect ( hasValueAssertion ) ; const chips = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; h . expect ( ( ) => [ < Chip theme = { { '@dojo/widgets/chip' : chipCss } } disabled = { undefined } key = "value-2" classes = { { '@dojo/widgets/chip' : { root : [ themeCss . value ] } } } onClose = { stub } variant = { undefined } > { { label : 'Cat' } } < /Chip> ] , ( ) => chips ) ; assert . strictEqual ( chips [ 0 ] . children [ 0 ] . label , 'CAT' ) ; } , 'closing a chip removes the selection' ( ) { const valueStub = stub ( ) ; const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } onValue = { valueStub } initialValue = { [ '1' ] } > { { selected : ( value ) => value . toUpperCase ( ) } } < /ChipTypeahead>)); h . expect ( hasValueAssertion ) ; h . trigger ( '@typeahead' , ( node ) => node . children [ 0 ] . leading [ 0 ] . properties . onClose ) ; assert . isTrue ( valueStub . calledWith ( [ ] ) ) ; h . expect ( baseAssertion ) ; const chips = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; assert . isUndefined ( chips ) ; } , 'selecting a value from the typeahead selects a value' ( ) { const valueStub = stub ( ) ; const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } onValue = { valueStub } > { { selected : ( value ) => value && value . toUpperCase ( ) } } < /ChipTypeahead>)); h . trigger ( '@typeahead' , 'onValue' , { value : '2' , label : 'Cat' } ) ; assert . isTrue ( valueStub . calledWith ( [ { value : '2' , label : 'Cat' } ] ) ) ; h . expect ( hasValueAssertion ) ; const chips = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; h . expect ( ( ) => [ < Chip theme = { { '@dojo/widgets/chip' : chipCss } } disabled = { undefined } key = "value-2" classes = { { '@dojo/widgets/chip' : { root : [ themeCss . value ] } } } onClose = { stub } variant = { undefined } > { { label : 'Cat' } } < /Chip> ] , ( ) => chips ) ; } , 'tracks focus' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } > < /ChipTypeahead>)); h . trigger ( '@typeahead' , 'onFocus' ) ; h . expect ( focusedAssertion ) ; h . trigger ( '@typeahead' , 'onBlur' ) ; h . expect ( baseAssertion ) ; } , 'the default item renderer shows selected items' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } initialValue = { [ '2' ] } > < /ChipTypeahead>)); const itemRenderer = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . items ) ; h . expect ( ( ) => ( < ListItem onSelect = { stub ( ) } onRequestActive = { stub ( ) } widgetId = "" selected = { true } > < div classes = { [ themeCss . item , themeCss . selected ] } > Cat < /div> < /ListItem>), () => itemRenderer({ value: '2', label: 'Cat' }, { onSelect: stub(), onRequestActive: stub(), widgetId: '' })); h . expect ( ( ) => ( < ListItem onSelect = { stub ( ) } onRequestActive = { stub ( ) } widgetId = "" selected = { false } > < div classes = { [ themeCss . item , null ] } > Dog < /div> < /ListItem>), () => itemRenderer({ value: '1', label: 'Dog' }, { onSelect: stub(), onRequestActive: stub(), widgetId: '' })); } , 'uses a custom item renderer' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } initialValue = { [ '2' ] } > { { items : ( item ) => `Item ${ item . label }, selected = ${ item . selected ? 'true' : 'false' }` } } < /ChipTypeahead>)); const itemRenderer = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . items ) ; assert . strictEqual ( itemRenderer ( { value : '2' , label : 'Cat' } ) , 'Item Cat, selected = true' ) ; } , 'can place chips on the bottom instead of inline' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } initialValue = { [ '2' ] } placement = "bottom" > < /ChipTypeahead>)); h . expect ( bottomAssertion ) ; const leading = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; assert . isUndefined ( leading ) ; } , 'renders as disabled' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } initialValue = { [ '2' ] } disabled > < /ChipTypeahead>)); h . expect ( disabledAssertion ) ; const chips = h . trigger ( '@typeahead' , ( node ) => ( ) => node . children [ 0 ] . leading ) ; h . expect ( ( ) => [ < Chip theme = { { '@dojo/widgets/chip' : chipCss } } disabled = { true } key = "value-2" classes = { { '@dojo/widgets/chip' : { root : [ themeCss . value ] } } } onClose = { undefined } variant = { undefined } > { { label : 'Cat' } } < /Chip> ] , ( ) => chips ) ; } , 'renders with labels' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } > { { label : 'Label' } } < /ChipTypeahead>)); h . expect ( labeledAssertion ) ; } , 'disables items that are selected' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } initialValue = { [ '2' ] } > < /ChipTypeahead>)); const disabled = h . trigger ( '@typeahead' , ( node ) => ( ) => node . properties . itemDisabled ) ; assert . isTrue ( disabled ( { value : '2' , label : 'Cat' } ) ) ; assert . isFalse ( disabled ( { value : '1' , label : 'Dog' } ) ) ; } , 'allows duplicate values if duplicates are allowed' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } initialValue = { [ 'cat' ] } duplicates > < /ChipTypeahead>)); const disabled = h . trigger ( '@typeahead' , ( node ) => ( ) => node . properties . itemDisabled ) ; assert . isFalse ( disabled ( { value : '2' , label : 'Cat' } ) ) ; assert . isFalse ( disabled ( { value : '1' , label : 'Dog' } ) ) ; } , 'allows duplicate values if not strict' ( ) { const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } initialValue = { [ 'cat' ] } strict = { false } duplicates > < /ChipTypeahead>)); const disabled = h . trigger ( '@typeahead' , ( node ) => ( ) => node . properties . itemDisabled ) ; assert . isFalse ( disabled ( { value : '2' , label : 'Cat' } ) ) ; assert . isFalse ( disabled ( { value : '1' , label : 'Dog' } ) ) ; } , 'allows free text values if strict is set to false' ( ) { const onValueStub = stub ( ) ; const h = harness ( ( ) => ( < ChipTypeahead resource = { { data : animalOptions , id : 'test' , idKey : 'value' } } onValue = { onValueStub } strict = { false } > < /ChipTypeahead>)); h . trigger ( '@typeahead' , ( node ) => ( ) => { node . properties . onValue ( 'abc' ) ; } ) ; assert . isTrue ( onValueStub . calledWith ( [ 'abc' ] ) ) ; } } } ) ;