-
Notifications
You must be signed in to change notification settings - Fork 516
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(hits-per-page-selector): New widget to change hitsPerPage
Did a refactoring using Selector instead of IndexSelector for both indexSelector and hitsPerPageSelector. Closes #331
- Loading branch information
Showing
12 changed files
with
347 additions
and
108 deletions.
There are no files selected for viewing
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
var React = require('react'); | ||
|
||
class Selector extends React.Component { | ||
handleChange(event) { | ||
this.props.setValue(event.target.value); | ||
} | ||
|
||
render() { | ||
var {currentValue, options} = this.props; | ||
|
||
var handleChange = this.handleChange.bind(this); | ||
|
||
return ( | ||
<select | ||
className={this.props.cssClasses.root} | ||
onChange={handleChange} | ||
value={currentValue} | ||
> | ||
{options.map((option) => { | ||
return <option className={this.props.cssClasses.item} key={option.value} value={option.value}>{option.label}</option>; | ||
})} | ||
</select> | ||
); | ||
} | ||
} | ||
|
||
Selector.propTypes = { | ||
cssClasses: React.PropTypes.shape({ | ||
root: React.PropTypes.oneOfType([ | ||
React.PropTypes.string, | ||
React.PropTypes.arrayOf(React.PropTypes.string) | ||
]), | ||
item: React.PropTypes.oneOfType([ | ||
React.PropTypes.string, | ||
React.PropTypes.arrayOf(React.PropTypes.string) | ||
]) | ||
}), | ||
currentValue: React.PropTypes.oneOfType([ | ||
React.PropTypes.string, | ||
React.PropTypes.number | ||
]).isRequired, | ||
options: React.PropTypes.arrayOf( | ||
React.PropTypes.shape({ | ||
value: React.PropTypes.oneOfType([ | ||
React.PropTypes.string, | ||
React.PropTypes.number | ||
]).isRequired, | ||
label: React.PropTypes.string.isRequired | ||
}) | ||
).isRequired, | ||
setValue: React.PropTypes.func.isRequired | ||
}; | ||
|
||
module.exports = Selector; |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* eslint-env mocha */ | ||
|
||
import React from 'react'; | ||
import expect from 'expect'; | ||
import TestUtils from 'react-addons-test-utils'; | ||
import Selector from '../Selector'; | ||
|
||
import expectJSX from 'expect-jsx'; | ||
expect.extend(expectJSX); | ||
|
||
describe('Selector', () => { | ||
var renderer; | ||
|
||
beforeEach(() => { | ||
let {createRenderer} = TestUtils; | ||
renderer = createRenderer(); | ||
}); | ||
|
||
|
||
it('should render <Selector/> with strings', () => { | ||
var out = render({ | ||
currentValue: 'index-a', | ||
cssClasses: { | ||
root: 'custom-root', | ||
item: 'custom-item' | ||
}, | ||
options: [{value: 'index-a', label: 'Index A'}, {value: 'index-b', label: 'Index B'}] | ||
}); | ||
expect(out).toEqualJSX( | ||
<select | ||
className="custom-root" | ||
onChange={() => {}} | ||
value="index-a" | ||
> | ||
<option className="custom-item" value="index-a">Index A</option> | ||
<option className="custom-item" value="index-b">Index B</option> | ||
</select> | ||
); | ||
}); | ||
|
||
it('should render <Selector/> with numbers', () => { | ||
var out = render({ | ||
currentValue: 10, | ||
cssClasses: { | ||
root: 'custom-root', | ||
item: 'custom-item' | ||
}, | ||
options: [{value: 10, label: '10 results per page'}, {value: 20, label: '20 results per page'}] | ||
}); | ||
expect(out).toEqualJSX( | ||
<select | ||
className="custom-root" | ||
onChange={() => {}} | ||
value={10} | ||
> | ||
<option className="custom-item" value={10}>10 results per page</option> | ||
<option className="custom-item" value={20}>20 results per page</option> | ||
</select> | ||
); | ||
}); | ||
|
||
function render(props = {}) { | ||
renderer.render(<Selector {...props} />); | ||
return renderer.getRenderOutput(); | ||
} | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
106 changes: 106 additions & 0 deletions
106
widgets/hits-per-page-selector/__tests__/hits-per-page-selector-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
/* eslint-env mocha */ | ||
|
||
import React from 'react'; | ||
import expect from 'expect'; | ||
import sinon from 'sinon'; | ||
import jsdom from 'mocha-jsdom'; | ||
|
||
import expectJSX from 'expect-jsx'; | ||
expect.extend(expectJSX); | ||
|
||
import hitsPerPageSelector from '../hits-per-page-selector'; | ||
import Selector from '../../../components/Selector'; | ||
|
||
describe('hitsPerPageSelector()', () => { | ||
jsdom({useEach: true}); | ||
|
||
var ReactDOM; | ||
var container; | ||
var options; | ||
var cssClasses; | ||
var widget; | ||
var props; | ||
var helper; | ||
var results; | ||
var autoHideContainer; | ||
|
||
beforeEach(() => { | ||
autoHideContainer = sinon.stub().returns(Selector); | ||
ReactDOM = {render: sinon.spy()}; | ||
|
||
hitsPerPageSelector.__Rewire__('ReactDOM', ReactDOM); | ||
hitsPerPageSelector.__Rewire__('autoHideContainer', autoHideContainer); | ||
|
||
container = document.createElement('div'); | ||
options = [ | ||
{value: 10, label: '10 results'}, | ||
{value: 20, label: '20 results'} | ||
]; | ||
cssClasses = { | ||
root: 'custom-root', | ||
item: 'custom-item' | ||
}; | ||
widget = hitsPerPageSelector({container, options, cssClasses}); | ||
helper = { | ||
state: { | ||
hitsPerPage: 20 | ||
}, | ||
setQueryParameter: sinon.spy(), | ||
search: sinon.spy() | ||
}; | ||
results = { | ||
hits: [] | ||
}; | ||
}); | ||
|
||
it('doesn\'t configure anything', () => { | ||
expect(widget.getConfiguration).toEqual(undefined); | ||
}); | ||
|
||
it('calls ReactDOM.render(<Selector props />, container)', () => { | ||
widget.render({helper, results, state: helper.state}); | ||
props = { | ||
cssClasses: { | ||
root: 'ais-hits-per-page-selector custom-root', | ||
item: 'ais-hits-per-page-selector--item custom-item' | ||
}, | ||
currentValue: 20, | ||
hasResults: false, | ||
hideContainerWhenNoResults: false, | ||
options: [ | ||
{value: 10, label: '10 results'}, | ||
{value: 20, label: '20 results'} | ||
], | ||
setValue: () => {} | ||
}; | ||
expect(ReactDOM.render.calledOnce).toBe(true, 'ReactDOM.render called once'); | ||
expect(ReactDOM.render.firstCall.args[0]).toEqualJSX(<Selector {...props} />); | ||
expect(ReactDOM.render.firstCall.args[1]).toEqual(container); | ||
}); | ||
|
||
it('sets the underlying hitsPerPage', () => { | ||
widget.setHitsPerPage(helper, helper.state, 10); | ||
expect(helper.setQueryParameter.calledOnce).toBe(true, 'setQueryParameter called once'); | ||
expect(helper.search.calledOnce).toBe(true, 'search called once'); | ||
}); | ||
|
||
it('should throw if there is no name attribute in a passed object', () => { | ||
options.length = 0; | ||
options.push({label: 'Label without a value'}); | ||
expect(() => { | ||
widget.init(helper.state, helper); | ||
}).toThrow(/No option in `options` with `value: 20`/); | ||
}); | ||
|
||
it('must include the current hitsPerPage at initialization time', () => { | ||
helper.state.hitsPerPage = -1; | ||
expect(() => { | ||
widget.init(helper.state, helper); | ||
}).toThrow(/No option in `options` with `value: -1`/); | ||
}); | ||
|
||
afterEach(() => { | ||
hitsPerPageSelector.__ResetDependency__('ReactDOM'); | ||
hitsPerPageSelector.__ResetDependency__('autoHideContainer'); | ||
}); | ||
}); |
Oops, something went wrong.