Skip to content

Commit

Permalink
Adding finishing touches on unit tests for V1 - adding maxTags option…
Browse files Browse the repository at this point in the history
…s - changing name of allowDupes to uniqueTags - changing name of events to be prefixed with 'on' - adding test task to the build process - refacotring SCSS into multip[le files based on core and components - now destructuring properties in methods in tags component - changing name of delimiters to addKeys.
  • Loading branch information
jfusco committed Jul 30, 2016
1 parent 27b9a95 commit d5fb544
Show file tree
Hide file tree
Showing 21 changed files with 488 additions and 336 deletions.
8 changes: 2 additions & 6 deletions .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
"brace-style": [2, "1tbs", {
"allowSingleLine": true
}],
"object-curly-spacing": [2, "never", {
"object-curly-spacing": [2, "always", {
"objectsInObjects": true,
"arraysInObjects": true
}],
Expand Down Expand Up @@ -78,10 +78,6 @@
}]
},
"globals": {
"console": true,
"alert": true,
"document": true,
"window": true,
"WeakMap": true
"console": true
}
}
61 changes: 31 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class Application extends Component{
<Tags
initialTags={this.state.tags}
placeholder="Add a tag"
change={this.onTagsChange} />
onChange={this.onTagsChange} />
</div>
);
}
Expand All @@ -57,14 +57,14 @@ render(<Application />, document.getElementById('application'));
#### Options
* **[`initialTags`](#initialTags)**
* **[`placeholder`](#placeholder)**
* **[`delimiters`](#delimiters)**
* **[`change`](#change)**
* **[`added`](#added)**
* **[`removed`](#removed)**
* **[`addKeys`](#addKeys)**
* **[`onChange`](#onChange)**
* **[`onAdded`](#onAdded)**
* **[`onRemoved`](#onRemoved)**
* **[`maxTags`](#maxTags)**
* **[`readOnly`](#readOnly)**
* **[`removeTagWithDeleteKey`](#removeTagWithDeleteKey)**
* **[`removeTagIcon`](#removeTagIcon)**
* **[`allowDupes`](#allowDupes)**
* **[`uniqueTags`](#allowDupes)**
* **[`id`](#id)**

<a name="initialTags"></a>
Expand All @@ -83,46 +83,53 @@ A `string` used as placeholder text in the tags input field
<Tags placeholder="Add a tag" />
```

<a name="delimiters"></a>
##### delimiters ~ optional ~ default `[13, 9, 32]`
<a name="addKeys"></a>
##### addKeys ~ optional ~ default `[13, 9, 32]`
An `array` of keyCodes used to tell the tags component which delimiter to use to add a tag

[Here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) is more info and a list of keyCodes
```js
<Tags delimiters={[13, 9, 32, 188]} />
<Tags addKeys={[13, 9, 32, 188]} />
```

<a name="change"></a>
##### change ~ optional
<a name="onChange"></a>
##### onChange ~ optional
A `function` fired anytime there is a change - returns the new `array` of tags
```js
onTagsChange(tags){
console.log(`new tags: ${tags}`);
}

<Tags change={this.onTagsChange} />
<Tags onChange={this.onTagsChange} />
```

<a name="added"></a>
##### added ~ optional
<a name="onAdded"></a>
##### onAdded ~ optional
A `function` fired when a new tag is added - returns a `string` of the new tag
```js
onTagAdded(tag){
console.log(`new tag: ${tags}`);
}

<Tags added={this.onTagAdded} />
<Tags onAdded={this.onTagAdded} />
```

<a name="removed"></a>
##### removed ~ optional
<a name="onRemoved"></a>
##### onRemoved ~ optional
A `function` fired when a new tag is deleted - returns a `string` of the tag that was deleted
```js
onTagRemoved(tag){
console.log(`deleted tag: ${tag}`);
}

<Tags removed={this.onTagRemoved} />
<Tags onRemoved={this.onTagRemoved} />
```

<a name="maxTags"></a>
##### maxTags ~ optional ~ default `-1` (infinite)
An `integer` representing the maximum number of tags that are allowed to be added
```js
<Tags maxTags={10} />
```

<a name="readOnly"></a>
Expand All @@ -132,13 +139,6 @@ A `boolean` that sets the tag component to read only mode. No adding or removing
<Tags readOnly={true} />
```

<a name="removeTagWithDeleteKey"></a>
##### removeTagWithDeleteKey ~ optional ~ default `true`
A `boolean` that allows tags to be removed with the delete key when the input field is empty
```js
<Tags removeTagWithDeleteKey={true} />
```

<a name="removeTagIcon"></a>
##### removeTagIcon ~ optional ~ default `"x"`
The `element` to be used for the delete icon
Expand All @@ -152,11 +152,12 @@ const removeIcon = () => {
<Tags removeTagsIcon={removeIcon()} />
```

<a name="allowDupes"></a>
##### allowDupes ~ optional ~ default `false`
A `boolean` that allows tags to be added more than once
<a name="uniqueTags"></a>
##### uniqueTags ~ optional ~ default `false`
A `boolean` that allows the same tag to be added more than once
```js
<Tags allowDupes={false} />
//-- Only allow unique tags to be added
<Tags uniqueTags={true} />
```

<a name="id"></a>
Expand Down
4 changes: 2 additions & 2 deletions __tests__/Tag-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,15 @@ describe('Tag - "removeTagIcon"', () => {
});
});

describe('Tag - "removeTag"', () => {
describe('Tag - "onRemoveTag"', () => {
it('should be called when clicking the remove icon', () => {
const onRemoveClick = jest.genMockFunction();

const tag = renderIntoDocument(
<div>
<Tag
name={TAG_NAME}
removeTag={onRemoveClick} />
onRemoveTag={onRemoveClick} />
</div>
);

Expand Down
79 changes: 64 additions & 15 deletions __tests__/Tags-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,18 @@ describe('Tags', () => {
});

it('should render custom placeholder if provided', () => {
expect(tags.props.children[1].type).toBe('input');
expect(tags.props.children[1].props.placeholder).toBe('Custom placeholder text');
const input = tags.props.children[1];

expect(input.type).toBe('input');
expect(input.props.placeholder).toBe('Custom placeholder text');
});
});

it('should set aria-label', () => {
const input = tags.props.children[1];

expect(input.props['aria-label']).toBe('Custom placeholder text');
});
});

describe('Tags - "initialTags"', () => {
it('should render tags (shallow render)', () => {
Expand Down Expand Up @@ -109,7 +116,7 @@ describe('Tags - "readOnly"', () => {
});


describe('Tags - "delimiters"', () => {
describe('Tags - "addKeys"', () => {
let tags,
input,
tagContainer;
Expand All @@ -118,7 +125,7 @@ describe('Tags - "delimiters"', () => {
tags = renderIntoDocument(
<Tags
initialTags={TEST_TAGS}
delimiters={[13, 9, 32, 188]} />
addKeys={[13, 9, 32, 188]} />
);

const renderedDOM = findDOMNode(tags);
Expand Down Expand Up @@ -177,14 +184,16 @@ describe('Tags - events', () => {
const onTagAdded = jest.genMockFunction();
const onTagRemoved = jest.genMockFunction();
const onTagsChanged = jest.genMockFunction();
const onTagsInputChange = jest.genMockFunction();

beforeEach(() => {
tags = renderIntoDocument(
<Tags
initialTags={TEST_TAGS}
added={onTagAdded}
removed={onTagRemoved}
change={onTagsChanged} />
onAdded={onTagAdded}
onRemoved={onTagRemoved}
onChange={onTagsChanged}
onInputChange={onTagsInputChange} />
);

const renderedDOM = findDOMNode(tags);
Expand All @@ -206,11 +215,11 @@ describe('Tags - events', () => {
Simulate.keyDown(input, {key: 'Enter', keyCode: 13, which: 13});
});

it('should call the "added" event and return the new tag', () => {
it('should call the "onAdded" event and return the new tag', () => {
expect(onTagAdded).toBeCalledWith(TEST_TAGS[0]);
});

it('should call the "changed" event and return the new tags list as an array', () => {
it('should call the "onChange" event and return the new tags list as an array', () => {
const newArray = TEST_TAGS.concat('foo');

expect(onTagsChanged).toBeCalledWith(newArray);
Expand All @@ -225,14 +234,26 @@ describe('Tags - events', () => {
Simulate.keyDown(input, {key: 'Delete', keyCode: 8, which: 8});
});

it('should call the "removed" event and return the tag that was removed', () => {
it('should call the "onRemoved" event and return the tag that was removed', () => {
expect(onTagRemoved).toBeCalledWith(TEST_TAGS[1]);
});

it('should call the "changed" event and return the new tags list as an array', () => {
it('should call the "onChange" event and return the new tags list as an array', () => {
expect(onTagsChanged).toBeCalledWith([TEST_TAGS[0]]);
});
});

describe('when typing in the input field', () => {
it('should call the "inputChange" and return the word as you\'re typing', () => {
Simulate.change(input, {
target: {
value: 'a'
}
});

expect(onTagsInputChange).toBeCalledWith('a');
});
});
});

describe('Tags - removing', () => {
Expand Down Expand Up @@ -293,11 +314,12 @@ describe('Tags - removing', () => {
});
});

describe('Tags - "allowDupes"', () => {
describe('Tags - "uniqueTags"', () => {
it('should allow duplicate tags to be created', () => {
const tags = renderIntoDocument(
<Tags
initialTags={TEST_TAGS} />
initialTags={TEST_TAGS}
uniqueTags={false} />
);

const renderedDOM = findDOMNode(tags);
Expand All @@ -318,7 +340,7 @@ describe('Tags - "allowDupes"', () => {
const tags = renderIntoDocument(
<Tags
initialTags={TEST_TAGS}
allowDupes={false} />
uniqueTags={true} />
);

const renderedDOM = findDOMNode(tags);
Expand All @@ -333,3 +355,30 @@ describe('Tags - "allowDupes"', () => {
expect(tagContainer.children.length).toBe(2);
});
});

describe('Tags - "maxTags"', () => {
describe('when maxTags is set to 3', () => {
it('should allow no more than 3 tags to be added', () => {
const tags = renderIntoDocument(
<Tags
initialTags={TEST_TAGS}
maxTags={3} />
);

const renderedDOM = findDOMNode(tags);
const input = renderedDOM.getElementsByTagName('input')[0];
const tagContainer = renderedDOM.querySelector('.tags-container');

input.value = TEST_TAGS[0];

Simulate.change(input);
Simulate.keyDown(input, {key: 'Enter', keyCode: 13, which: 13});

input.value = TEST_TAGS[0];

Simulate.keyDown(input, {key: 'Enter', keyCode: 13, which: 13});

expect(tagContainer.children.length).toBe(3);
});
});
});
4 changes: 2 additions & 2 deletions dist-components/Tag.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var Tag = function Tag(props) {
var onRemoveClick = function onRemoveClick(e) {
e.preventDefault();

props.removeTag();
props.onRemoveTag(e);
};

var removeIcon = !props.readOnly ? _react2.default.createElement(
Expand All @@ -36,7 +36,7 @@ exports.default = Tag;

Tag.propTypes = {
name: _react2.default.PropTypes.string.isRequired,
removeTag: _react2.default.PropTypes.func,
onRemoveTag: _react2.default.PropTypes.func,
selectedTag: _react2.default.PropTypes.bool,
readOnly: _react2.default.PropTypes.bool,
removeTagIcon: _react2.default.PropTypes.oneOfType([_react2.default.PropTypes.string, _react2.default.PropTypes.element])
Expand Down
Loading

0 comments on commit d5fb544

Please sign in to comment.