react-widgets
Version:
An à la carte set of polished, extensible, and accessible inputs built for React
374 lines (264 loc) • 13.3 kB
JSX
require('../vendor/phantomjs-shim')
import { findDOMNode } from 'react-dom';
var React = require('react/addons');
var Select = require('../src/Multiselect.jsx')
, TagList = require('../src/MultiselectTagList.jsx');
var TestUtils = React.addons.TestUtils
, render = TestUtils.renderIntoDocument
, findTag = TestUtils.findRenderedDOMComponentWithTag
, findClass = TestUtils.findRenderedDOMComponentWithClass
, findType = TestUtils.findRenderedComponentWithType
, trigger = TestUtils.Simulate;
$.fn.myText = function(){
return this.contents().filter(function(){ return this.nodeType === 3; })[0].nodeValue
}
describe('Multiselect', function(){
var dataList = [
{ label: 'jimmy', id: 0 },
{ label: 'sally', id: 1 },
{ label: 'pat', id: 2 }
];
it('should set initial values', function(){
var select = render(<Select value={['hello']} onChange={()=>{}} />)
, tags = findDOMNode(findType(select, TagList));
expect($(tags).find('li:first-child > span').myText()).to.be('hello');
})
it('should respect textField and valueFields', function(){
var select = render(<Select defaultValue={[0]} data={dataList} textField='label' valueField='id' />)
, tags = findDOMNode(findType(select, TagList));
expect( $(tags).find('li:first-child > span').myText() ).to.be('jimmy');
})
it('should start closed', function(done){
var select = render(<Select defaultValue={[0]} data={dataList} textField='label' valueField='id' />);
var popup = findType(select, require('../src/Popup.jsx'));
expect(select._values.open).to.not.be(true)
expect(findDOMNode(select).className).to.not.match(/\brw-open\b/)
expect(findClass(select, 'rw-input').getAttribute('aria-expanded')).to.be('false')
setTimeout(function(){
expect($(findDOMNode(popup)).css('display')).to.be('none')
done()
}, 0)
})
it('should open when focused', function(done){
var select = render(<Select defaultValue={['jimmy']} data={dataList} duration={0}/>);
var popup = findType(select, require('../src/Popup.jsx'))
trigger.focus(findDOMNode(select))
setTimeout(function() {
expect(select._values.open).to.be(true)
expect(findDOMNode(select).className).to.match(/\brw-open\b/)
expect(findClass(select, 'rw-input').getAttribute('aria-expanded')).to.be('true')
expect(popup.props.open).to.be(true)
done()
})
})
it('should set id on list', function(){
var instance = render(<Select />)
, list = findTag(instance, 'ul');
expect(list.hasAttribute('id')).to.be(true);
})
it('should remove tag when clicked', function(){
var del = sinon.spy()
, tags = findDOMNode(render(
<TagList value={[dataList[0], dataList[1]]} data={dataList} textField='label' valueField='id' onDelete={del}/>));
expect($(tags).children().length).to.be(2)
trigger.click(tags.children[1].children[1]) // click button
expect(del.calledOnce).to.be(true)
expect(del.calledWith(dataList[1])).to.be(true)
})
it('should change value when tag is clicked', function(){
var change = sinon.spy()
, select = render(<Select onChange={change} value={[dataList[0], dataList[1]]} data={dataList} textField='label' valueField='id' />)
, tags = findDOMNode(findType(select, TagList))
expect($(tags).children().length).to.be(2)
trigger.click(tags.children[1].children[1]) // click button
expect(change.calledOnce).to.be(true)
expect(change.args[0][0]).to.eql([ dataList[0] ])
})
it('should trigger focus/blur events', function(done){
var blur = sinon.spy()
, focus = sinon.spy()
, select = render(<Select onBlur={blur} onFocus={focus}/>);
expect(focus.calledOnce).to.be(false)
expect(blur.calledOnce).to.be(false)
trigger.focus(findDOMNode(select))
setTimeout(() => {
expect(focus.calledOnce).to.be(true)
trigger.blur(findDOMNode(select))
setTimeout(() => {
expect(blur.calledOnce).to.be(true)
done()
})
})
})
it('should trigger key events', function(){
var kp = sinon.spy(), kd = sinon.spy(), ku = sinon.spy()
, select = render(<Select onKeyPress={kp} onKeyUp={ku} onKeyDown={kd}/>)
, input = findDOMNode(findType(select, require('../src/MultiselectInput.jsx')));
trigger.keyPress(input)
trigger.keyDown(input)
trigger.keyUp(input)
expect(kp.calledOnce).to.be(true)
expect(kd.calledOnce).to.be(true)
expect(ku.calledOnce).to.be(true)
})
it('should do nothing when disabled', function(done){
var select = render(<Select defaultValue={['jimmy']} data={dataList} duration={0} disabled={true}/>)
, input = findDOMNode(findType(select, require('../src/MultiselectInput.jsx')))
, tags = findDOMNode(findType(select, TagList));
expect( input.hasAttribute('disabled')).to.be(true);
expect( input.getAttribute('aria-disabled')).to.be('true');
//expect( input.getAttribute('disabled')).to.be('');
trigger.click(findClass(select, 'rw-tag-btn'))
setTimeout(function() {
expect(select._values.open).to.not.be(true)
expect(tags.children.length).to.be(1)
expect(findDOMNode(select).className).to.not.match(/\brw-state-focus\b/)
done()
}, 0)
})
it('should disable only certain tags', function(done){
var select = render(<Select defaultValue={[0, 1]} data={dataList} disabled={[1]} textField='label' valueField='id'/>)
, tags = findDOMNode(findType(select, TagList));
expect(tags.children.length).to.be(2)
expect(tags.children[1].className).to.match(/\brw-state-disabled\b/);
trigger.click(tags.children[1].children[1]) // click button
setTimeout(function() {
expect(tags.children.length).to.be(2)
done()
}, 0)
})
it('should do nothing when readonly', function(done){
var select = render(<Select defaultValue={['jimmy']} data={dataList} duration={0} readOnly={true}/>)
, input = findDOMNode(findType(select, require('../src/MultiselectInput.jsx')))
, tags = findDOMNode(findType(select, TagList));
expect( input.hasAttribute('readonly')).to.be(true);
expect( input.getAttribute('aria-readonly')).to.be('true');
trigger.click(findClass(select, 'rw-tag-btn'))
setTimeout(function() {
expect(select._values.open).to.not.be(true)
expect(tags.children.length).to.be(1)
done()
}, 0)
})
it('should readonly only certain tags', function(done){
var select = render(<Select defaultValue={[0, 1]} data={dataList} readOnly={[1]} textField='label' valueField='id'/>)
, tags = findDOMNode(findType(select, TagList));
expect(tags.children.length).to.be(2)
expect(tags.children[1].className).to.match(/\brw-state-readonly\b/);
trigger.click(tags.children[1].children[1]) // click button
setTimeout(function() {
expect(tags.children.length).to.be(2)
done()
})
})
it('should call Select handler', function(done){
var change = sinon.spy(), onSelect = sinon.spy()
, instance = render(<Select value={[dataList[1]]} data={dataList} onChange={change} onSelect={onSelect}/>)
findDOMNode(instance).focus()
let list = findClass(instance, 'rw-list');
setTimeout(function(){
trigger.click(list.children[0])
expect(onSelect.calledOnce).to.be(true)
expect(change.calledAfter(onSelect)).to.be(true)
onSelect.reset()
change.reset()
trigger.keyDown(findDOMNode(instance), { key: 'ArrowDown'}) //move to different value so change fires
trigger.keyDown(findDOMNode(instance), { key: 'Enter'})
expect(onSelect.calledOnce).to.be(true)
expect(change.calledAfter(onSelect)).to.be(true)
done()
})
})
it('should clear SearchTerm when uncontrolled', function(){
var select = render(<Select data={dataList} defaultSearchTerm='ji' open textField='label' valueField='id' onToggle={()=>{}}/>);
var input = findType(select, Select.ControlledComponent)
expect(input.props.searchTerm).to.be('ji')
trigger.keyDown(findDOMNode(select), { key: 'Enter'})
expect(input.props.searchTerm).to.be('')
})
it('should not clear SearchTerm when controlled', function(){
var select = render(<Select searchTerm="jim" data={dataList} onSearch={()=>{}}/>);
var input = findTag(select, 'input')
trigger.keyDown(findDOMNode(select), { key: 'Enter'})
expect(input.value).to.be('jim')
})
it('should show create tag correctly', function(){
var select = render(<Select searchTerm="custom tag" onCreate={()=>{}} data={dataList} onSearch={()=>{}}/>);
expect(function err() {
findClass(select, 'rw-multiselect-create-tag') }).to.not.throwException()
select = render(<Select onCreate={()=>{}} data={dataList} onSearch={()=>{}}/>)
expect(function err() {
findClass(select, 'rw-multiselect-create-tag') }).to.throwException()
select = render(<Select searchTerm="custom tag" data={dataList} onSearch={()=>{}}/>)
expect(function err() {
findClass(select, 'rw-multiselect-create-tag') }).to.throwException()
select = render(<Select searchTerm="asfasfas tag" data={dataList} onSearch={()=>{}}/>)
expect(function err() {
findClass(select, 'rw-multiselect-create-tag') }).to.throwException()
})
it('should call onCreate', function(){
var create = sinon.spy()
, select = render(<Select
open={true}
searchTerm="custom tag"
data={dataList}
onCreate={create}
onSearch={()=>{}} onToggle={()=>{}}/>)
, createLi = findClass(select, 'rw-multiselect-create-tag').children[0];
trigger.click(createLi)
expect(create.calledOnce).to.ok()
expect(create.calledWith('custom tag')).to.ok()
// only option is create
create.reset()
trigger.keyDown(findDOMNode(select), { key: 'Enter'})
expect(create.calledOnce).to.ok()
expect(create.calledWith('custom tag')).to.ok()
// other values have focus
select = render(<Select open={true} searchTerm="custom tag" data={['custom tag time']} onCreate={create} onSearch={()=>{}} onToggle={()=>{}}/>)
create.reset()
trigger.keyDown(findDOMNode(select), { key: 'Enter'})
expect(create.called).to.be(false)
trigger.keyDown(findDOMNode(select), { key: 'Enter', ctrlKey: true })
expect(create.calledOnce).to.ok()
expect(create.calledWith('custom tag')).to.ok()
})
it('should change values on key down', function(){
var change = sinon.spy()
, select = render(<Select value={[0, 1, 2]} data={dataList} textField='label' valueField='id' onChange={change}/>)
, tags = findDOMNode(findType(select, TagList))
, list = findClass(select, 'rw-list');
trigger.keyDown(findDOMNode(select), { key: 'ArrowLeft'})
expect(tags.children[2].className).to.match(/\brw-state-focus\b/)
expect(tags.children[1].className).to.not.match(/\brw-state-focus\b/)
trigger.keyDown(findDOMNode(select), { key: 'ArrowLeft'})
expect(tags.children[1].className).to.match(/\brw-state-focus\b/)
expect(tags.children[2].className).to.not.match(/\brw-state-focus\b/)
trigger.keyDown(findDOMNode(select), { key: 'ArrowRight'})
expect(tags.children[2].className).to.match(/\brw-state-focus\b/)
expect(tags.children[1].className).to.not.match(/\brw-state-focus\b/)
trigger.keyDown(findDOMNode(select), { key: 'Home'})
expect(tags.children[0].className).to.match(/\brw-state-focus\b/)
expect(tags.children[1].className).to.not.match(/\brw-state-focus\b/)
trigger.keyDown(findDOMNode(select), { key: 'Delete'})
expect(change.calledOnce).to.be(true)
expect(change.args[0][0]).to.eql(dataList.slice(1, 3))
change.reset()
trigger.keyDown(findDOMNode(select), { key: 'End'})
expect(tags.children[2].className).to.match(/\brw-state-focus\b/)
expect(tags.children[1].className).to.not.match(/\brw-state-focus\b/)
trigger.keyDown(findDOMNode(select), { key: 'Backspace'})
expect(change.calledOnce).to.be(true)
expect(change.args[0][0]).to.eql(dataList.slice(0, 2))
change.reset()
trigger.keyDown(findDOMNode(select), { key: 'ArrowDown'})
expect(select._values.open).to.be(true)
select = render(<Select open value={[]} onToggle={()=>{}} data={dataList} textField='label' valueField='id' onChange={change}/>)
list = findClass(select, 'rw-list')
trigger.keyDown(findDOMNode(select), { key: 'ArrowDown'})
expect(list.children[1].className).to.match(/\brw-state-focus\b/)
trigger.keyDown(findDOMNode(select), { key: 'End'})
expect(list.children[2].className).to.match(/\brw-state-focus\b/)
trigger.keyDown(findDOMNode(select), { key: 'Home'})
expect(list.children[0].className).to.match(/\brw-state-focus\b/)
})
})