Some code rename and reorg + basic tests
authorymh <ymh.work@gmail.com>
Tue, 23 May 2017 13:15:34 +0200
changeset 3 3b5d37d84cfe
parent 2 b52921a63e77
child 4 885a20cde527
Some code rename and reorg + basic tests
client/package.json
client/src/App.test.js
client/src/__tests__/App.test.js
client/src/actions/__tests__/notesActions.test.js
client/src/actions/action-types.js
client/src/actions/notes-actions.js
client/src/actions/notesActions.js
client/src/components/NotesContainer.js
client/src/components/__tests__/Note.test.js
client/src/components/__tests__/NoteInput.test.js
client/src/components/__tests__/NotesContainer.test.js
client/src/components/__tests__/NotesList.test.js
client/src/constants/actionTypes.js
client/src/index.js
client/src/reducers/__tests__/notesReducer.test.js
client/src/reducers/index.js
client/src/reducers/notes-reducer.js
client/src/reducers/notesReducer.js
client/src/store/configure-store.js
client/src/store/configureStore.js
client/src/store/noteRecord.js
client/yarn.lock
--- a/client/package.json	Mon May 22 17:59:19 2017 +0200
+++ b/client/package.json	Tue May 23 13:15:34 2017 +0200
@@ -2,6 +2,7 @@
   "name": "client",
   "version": "0.1.0",
   "private": true,
+  "homepage": ".",
   "dependencies": {
     "bootstrap-sass": "^3.3.7",
     "immutable": "^3.8.1",
@@ -14,9 +15,11 @@
     "uuid": "^3.0.1"
   },
   "devDependencies": {
+    "enzyme": "^2.8.2",
     "node-sass-chokidar": "^0.0.1",
     "npm-run-all": "^4.0.2",
-    "react-scripts": "1.0.2"
+    "react-scripts": "1.0.2",
+    "react-test-renderer": "^15.5.4"
   },
   "scripts": {
     "build-css": "node-sass-chokidar --include-path ./src --include-path ./node_modules --include-path ./node_modules/bootstrap-sass/assets/stylesheets src/ -o src/",
--- a/client/src/App.test.js	Mon May 22 17:59:19 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,17 +0,0 @@
-import React from 'react';
-import ReactDOM from 'react-dom';
-import App from './App';
-import {Provider} from 'react-redux';
-
-import configureStore from './store/configure-store';
-
-const store = configureStore();
-
-it('renders without crashing', () => {
-  const div = document.createElement('div');
-  ReactDOM.render(
-    <Provider store={store}>
-      <App />
-    </Provider>,
-    div);
-});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/__tests__/App.test.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,17 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import {Provider} from 'react-redux';
+
+import App from '../App';
+import configureStore from '../store/configureStore';
+
+const store = configureStore();
+
+it('renders without crashing', () => {
+  const div = document.createElement('div');
+  ReactDOM.render(
+    <Provider store={store}>
+      <App />
+    </Provider>,
+    div);
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/actions/__tests__/notesActions.test.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,22 @@
+// cf. http://redux.js.org/docs/recipes/WritingTests.html
+
+import * as actions from '../notesActions'
+import * as types from '../../constants/actionTypes'
+
+describe('actions', () => {
+
+  it('should create an action to add a note', () => {
+    const text = 'test note'
+    const expectedAction = {
+      type: types.ADD_NOTE,
+      note: {
+          id: expect.stringMatching(/[a-z0-9]{8}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{4}-[a-z0-9]{12}/),
+          text: text
+      }
+    }
+
+    const receivedAction = actions.addNote(text);
+    expect(receivedAction).toMatchObject(expectedAction);
+
+  })
+})
\ No newline at end of file
--- a/client/src/actions/action-types.js	Mon May 22 17:59:19 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-export const ADD_NOTE = 'ADD_NOTE';
\ No newline at end of file
--- a/client/src/actions/notes-actions.js	Mon May 22 17:59:19 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-import * as types from './action-types';
-
-import uuidV1 from 'uuid/v1';
-
-export const addNote = (noteText) => {
-  return {
-    type: types.ADD_NOTE,
-    note: {
-      id: uuidV1(),
-      text: noteText
-    }
-  };
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/actions/notesActions.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,13 @@
+import uuidV1 from 'uuid/v1';
+
+import * as types from '../constants/actionTypes';
+
+export const addNote = (noteText) => {
+  return {
+    type: types.ADD_NOTE,
+    note: {
+      id: uuidV1(),
+      text: noteText
+    }
+  };
+}
--- a/client/src/components/NotesContainer.js	Mon May 22 17:59:19 2017 +0200
+++ b/client/src/components/NotesContainer.js	Tue May 23 13:15:34 2017 +0200
@@ -7,7 +7,7 @@
 
 import { Grid, Row, Col} from 'react-bootstrap';
 
-import * as notesActions from '../actions/notes-actions';
+import * as notesActions from '../actions/notesActions';
 import NotesList from './NotesList';
 import NoteInput from './NoteInput';
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/__tests__/Note.test.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,39 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import Note from '../Note';
+
+
+const setup = propOverrides => {
+  const props = Object.assign({
+      note: {
+          id: 'abc',
+          text: 'test text'
+      }
+  }, propOverrides);
+
+  const wrapper = shallow(<Note {...props} />);
+
+  return {
+    props,
+    wrapper,
+  }
+}
+
+describe('Notes container Component', () => {
+  test('render', () => {
+    const { wrapper } = setup()
+    expect(wrapper.exists()).toBe(true)
+  });
+
+  test('contains note text', () => {
+    const { wrapper } = setup();
+    expect(wrapper.text()).toBe('test text');
+  });
+
+  test('contains note id', () => {
+    const { wrapper } = setup();
+    expect(wrapper.first().prop('id')).toBe('note-abc');
+  });
+
+
+});
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/__tests__/NoteInput.test.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,40 @@
+import React from 'react';
+import { shallow, mount } from 'enzyme';
+import NoteInput from '../NoteInput';
+
+const setup = (propOverrides, doMount=false) => {
+  const props = Object.assign({
+      addNote: jest.fn()
+  }, propOverrides);
+
+  const renderFn = doMount?mount:shallow; 
+  const wrapper = renderFn(<NoteInput {...props} />);
+
+  return {
+    props,
+    wrapper,
+  }
+};
+
+describe('Notes container Component', () => {
+  test('render', () => {
+    const { wrapper } = setup();
+    expect(wrapper.exists()).toBe(true)
+  });
+
+  test('click button', () => {
+      const { props, wrapper } = setup({}, true);
+      wrapper.find('button').simulate('click');
+      expect(props.addNote.mock.calls.length).toBe(1);
+  });
+
+  test('note value on clickbutton', () => {
+      const { props, wrapper } = setup({}, true);
+      wrapper.find('textarea').simulate('change', {target: {value: 'note text'}});
+      wrapper.find('button').simulate('click');
+      expect(props.addNote.mock.calls.length).toBe(1);
+      expect(props.addNote.mock.calls[0]).toEqual(['note text']);
+  });
+
+});
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/__tests__/NotesContainer.test.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,40 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import NotesContainer from '../NotesContainer';
+import {createStore} from 'redux';
+import Immutable from 'immutable';
+
+const initialState = Immutable.Map({
+    notes: Immutable.List([])
+});
+
+
+const setup = propOverrides => {
+  const props = Object.assign({
+    store: createStore((state) => { return state; }, initialState)
+  }, propOverrides);
+
+  const wrapper = shallow(<NotesContainer {...props} />).dive();
+
+  return {
+    props,
+    wrapper,
+  }
+}
+
+describe('Notes container Component', () => {
+  test('render', () => {
+    const { wrapper } = setup()
+    expect(wrapper.exists()).toBe(true)
+  });
+
+  test('contains notes list', () => {
+    const { wrapper } = setup();
+    expect(wrapper.find('NotesList').exists()).toBe(true);
+  });
+
+  test('contains note input', () => {
+    const { wrapper } = setup();
+    expect(wrapper.find('NoteInput').exists()).toBe(true);
+  });
+});
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/components/__tests__/NotesList.test.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,58 @@
+import React from 'react';
+import { shallow } from 'enzyme';
+import NotesList from '../NotesList';
+import Immutable from 'immutable';
+
+const setup = propOverrides => {
+  const props = Object.assign({
+      notes: Immutable.List([{
+          id: 'note1',
+          text: 'test text 1'
+        },
+        {
+          id: 'note2',
+          text: 'test text 2'
+        },
+        {
+          id: 'note3',
+          text: 'test text 3'
+        }])
+  }, propOverrides);
+
+  const wrapper = shallow(<NotesList {...props} />);
+
+  return {
+    props,
+    wrapper,
+  }
+};
+
+describe('Notes container Component', () => {
+  test('render', () => {
+    const { wrapper } = setup();
+    expect(wrapper.exists()).toBe(true)
+  });
+
+  test('test note nb', () => {
+    const { wrapper } = setup();
+    expect(wrapper.find('Note').getNodes()).toHaveLength(3);
+  });
+
+  test('test node key', () => {
+    const { wrapper } = setup();
+    wrapper.find('li').forEach((node, i) => {
+      expect(node.key()).toBe('note'+(i+1));
+    });
+  });
+
+  test('test node note', () => {
+    const { wrapper } = setup();
+    wrapper.find('Note').forEach((node, i) => {
+      const {note} = node.props();
+      expect(note.id).toBe('note'+(i+1));
+      expect(note.text).toBe('test text '+(i+1));
+    });
+  });
+
+});
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/constants/actionTypes.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,1 @@
+export const ADD_NOTE = 'ADD_NOTE';
\ No newline at end of file
--- a/client/src/index.js	Mon May 22 17:59:19 2017 +0200
+++ b/client/src/index.js	Tue May 23 13:15:34 2017 +0200
@@ -1,10 +1,11 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
+import {Provider} from 'react-redux';
+
 import App from './App';
-import registerServiceWorker from './registerServiceWorker';
 import './index.css';
-import {Provider} from 'react-redux';
-import configureStore from './store/configure-store';
+import registerServiceWorker from './registerServiceWorker';
+import configureStore from './store/configureStore';
 
 const store = configureStore();
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/reducers/__tests__/notesReducer.test.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,94 @@
+// cf http://redux.js.org/docs/recipes/WritingTests.html
+
+import Immutable from 'immutable';
+
+import uuidV1 from 'uuid/v1';
+
+import reducer from '../notesReducer'
+import * as types from '../../constants/ActionTypes'
+import noteRecord from '../../store/noteRecord';
+
+describe('note reducer', () => {
+  it('should return the initial state', () => {
+    expect(
+      reducer(undefined, {})
+    ).toEqual(Immutable.List([]))
+  });
+
+  it('should handle ADD_NOTE', () => {
+
+    const newId = uuidV1();
+    expect(
+      reducer(Immutable.List([]), {
+        type: types.ADD_NOTE,
+        note: {
+          id: newId,
+          text: 'Run the tests'
+        }
+      })
+    ).toEqual(
+      Immutable.List([
+        new noteRecord({
+          id: newId,
+          text: 'Run the tests',
+        })
+      ])
+    );
+
+    const initialStore = Immutable.List([
+        new noteRecord({
+          id: uuidV1(),
+          text: 'origial note',
+        })
+    ]);
+    expect(
+      reducer(initialStore, {
+        type: types.ADD_NOTE,
+        note: {
+          id: newId,
+          text: 'Run the tests'
+        }
+      })
+    ).toEqual(
+      initialStore.push(
+        new noteRecord({
+          id: newId,
+          text: 'Run the tests',
+        })
+      )
+    );
+
+  });
+
+
+
+});
+
+//     expect(
+//       reducer(
+//         [
+//           {
+//             text: 'Use Redux',
+//             completed: false,
+//             id: 0
+//           }
+//         ],
+//         {
+//           type: types.ADD_TODO,
+//           text: 'Run the tests'
+//         }
+//       )
+//     ).toEqual(
+//       [
+//         {
+//           text: 'Run the tests',
+//           completed: false,
+//           id: 1
+//         },
+//         {
+//           text: 'Use Redux',
+//           completed: false,
+//           id: 0
+//         }
+//       ]
+//     )
--- a/client/src/reducers/index.js	Mon May 22 17:59:19 2017 +0200
+++ b/client/src/reducers/index.js	Tue May 23 13:15:34 2017 +0200
@@ -1,6 +1,7 @@
-import notes from './notes-reducer';
 import {combineReducers} from 'redux-immutable';
 
+import notes from './notesReducer';
+
 const rootReducer = combineReducers({
   notes
 });
--- a/client/src/reducers/notes-reducer.js	Mon May 22 17:59:19 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,13 +0,0 @@
-import * as types from '../actions/action-types';
-import Immutable from 'immutable';
-
-const noteRecord = Immutable.Record({id:'', text: ''});
-
-export default (state = Immutable.List([]), action) => {
-  switch (action.type) {
-    case types.ADD_NOTE:
-      return state.push(new noteRecord(action.note));
-    default:
-      return state;
-  }
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/reducers/notesReducer.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,14 @@
+import Immutable from 'immutable';
+
+import * as types from '../constants/actionTypes';
+import noteRecord from '../store/noteRecord';
+
+
+export default (state = Immutable.List([]), action) => {
+  switch (action.type) {
+    case types.ADD_NOTE:
+      return state.push(new noteRecord(action.note));
+    default:
+      return state;
+  }
+};
--- a/client/src/store/configure-store.js	Mon May 22 17:59:19 2017 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,11 +0,0 @@
-import rootReducer from '../reducers';
-import {createStore} from 'redux';
-import Immutable from 'immutable';
-
-const storeInitialState = Immutable.Map({
-    notes: Immutable.List([])
-});
-
-export default (initialState = storeInitialState) => {
-  return createStore(rootReducer, initialState);
-};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/store/configureStore.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,11 @@
+import rootReducer from '../reducers';
+import {createStore} from 'redux';
+import Immutable from 'immutable';
+
+const storeInitialState = Immutable.Map({
+    notes: Immutable.List([])
+});
+
+export default (initialState = storeInitialState) => {
+  return createStore(rootReducer, initialState);
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/client/src/store/noteRecord.js	Tue May 23 13:15:34 2017 +0200
@@ -0,0 +1,3 @@
+import Immutable from 'immutable';
+
+export default Immutable.Record({id:'', text: ''});
\ No newline at end of file
--- a/client/yarn.lock	Mon May 22 17:59:19 2017 +0200
+++ b/client/yarn.lock	Tue May 23 13:15:34 2017 +0200
@@ -1232,6 +1232,27 @@
     strip-ansi "^3.0.0"
     supports-color "^2.0.0"
 
+cheerio@^0.22.0:
+  version "0.22.0"
+  resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.22.0.tgz#a9baa860a3f9b595a6b81b1a86873121ed3a269e"
+  dependencies:
+    css-select "~1.2.0"
+    dom-serializer "~0.1.0"
+    entities "~1.1.1"
+    htmlparser2 "^3.9.1"
+    lodash.assignin "^4.0.9"
+    lodash.bind "^4.1.4"
+    lodash.defaults "^4.0.1"
+    lodash.filter "^4.4.0"
+    lodash.flatten "^4.2.0"
+    lodash.foreach "^4.3.0"
+    lodash.map "^4.4.0"
+    lodash.merge "^4.4.0"
+    lodash.pick "^4.2.1"
+    lodash.reduce "^4.4.0"
+    lodash.reject "^4.4.0"
+    lodash.some "^4.4.0"
+
 chokidar@^1.4.3, chokidar@^1.6.0, chokidar@^1.6.1:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
@@ -1602,7 +1623,7 @@
     postcss-value-parser "^3.3.0"
     source-list-map "^0.1.7"
 
-css-select@^1.1.0:
+css-select@^1.1.0, css-select@~1.2.0:
   version "1.2.0"
   resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
   dependencies:
@@ -1839,7 +1860,7 @@
   version "3.2.1"
   resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.2.1.tgz#3203e07fed217bd1f424b019735582fc37b2825a"
 
-dom-serializer@0:
+dom-serializer@0, dom-serializer@~0.1.0:
   version "0.1.0"
   resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
   dependencies:
@@ -1856,7 +1877,7 @@
   version "1.1.7"
   resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc"
 
-domelementtype@1:
+domelementtype@1, domelementtype@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2"
 
@@ -1870,13 +1891,19 @@
   dependencies:
     domelementtype "1"
 
+domhandler@^2.3.0:
+  version "2.4.1"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259"
+  dependencies:
+    domelementtype "1"
+
 domutils@1.1:
   version "1.1.6"
   resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485"
   dependencies:
     domelementtype "1"
 
-domutils@1.5.1:
+domutils@1.5.1, domutils@^1.5.1:
   version "1.5.1"
   resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
   dependencies:
@@ -1956,10 +1983,25 @@
     object-assign "^4.0.1"
     tapable "^0.2.5"
 
-entities@~1.1.1:
+entities@^1.1.1, entities@~1.1.1:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
 
+enzyme@^2.8.2:
+  version "2.8.2"
+  resolved "https://registry.yarnpkg.com/enzyme/-/enzyme-2.8.2.tgz#6c8bcb05012abc4aa4bc3213fb23780b9b5b1714"
+  dependencies:
+    cheerio "^0.22.0"
+    function.prototype.name "^1.0.0"
+    is-subset "^0.1.1"
+    lodash "^4.17.2"
+    object-is "^1.0.1"
+    object.assign "^4.0.4"
+    object.entries "^1.0.3"
+    object.values "^1.0.3"
+    prop-types "^15.5.4"
+    uuid "^2.0.3"
+
 "errno@>=0.1.1 <0.2.0-0", errno@^0.1.3:
   version "0.1.4"
   resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d"
@@ -1972,7 +2014,7 @@
   dependencies:
     is-arrayish "^0.2.1"
 
-es-abstract@^1.4.3, es-abstract@^1.7.0:
+es-abstract@^1.4.3, es-abstract@^1.6.1, es-abstract@^1.7.0:
   version "1.7.0"
   resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.7.0.tgz#dfade774e01bfcd97f96180298c449c8623fb94c"
   dependencies:
@@ -2588,6 +2630,14 @@
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771"
 
+function.prototype.name@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.0.0.tgz#5f523ca64e491a5f95aba80cc1e391080a14482e"
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.0"
+    is-callable "^1.1.2"
+
 gauge@~2.7.3:
   version "2.7.4"
   resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
@@ -2860,6 +2910,17 @@
     pretty-error "^2.0.2"
     toposort "^1.0.0"
 
+htmlparser2@^3.9.1:
+  version "3.9.2"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338"
+  dependencies:
+    domelementtype "^1.3.0"
+    domhandler "^2.3.0"
+    domutils "^1.5.1"
+    entities "^1.1.1"
+    inherits "^2.0.1"
+    readable-stream "^2.0.2"
+
 htmlparser2@~3.3.0:
   version "3.3.0"
   resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe"
@@ -3057,7 +3118,7 @@
   dependencies:
     builtin-modules "^1.0.0"
 
-is-callable@^1.1.1, is-callable@^1.1.3:
+is-callable@^1.1.1, is-callable@^1.1.2, is-callable@^1.1.3:
   version "1.1.3"
   resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2"
 
@@ -3208,6 +3269,10 @@
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
 
+is-subset@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-subset/-/is-subset-0.1.1.tgz#8a59117d932de1de00f245fcdd39ce43f1e939a6"
+
 is-svg@^2.0.0:
   version "2.1.0"
   resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9"
@@ -3769,6 +3834,14 @@
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
 
+lodash.assignin@^4.0.9:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/lodash.assignin/-/lodash.assignin-4.2.0.tgz#ba8df5fb841eb0a3e8044232b0e263a8dc6a28a2"
+
+lodash.bind@^4.1.4:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/lodash.bind/-/lodash.bind-4.2.1.tgz#7ae3017e939622ac31b7d7d7dcb1b34db1690d35"
+
 lodash.camelcase@^4.3.0:
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
@@ -3781,18 +3854,54 @@
   version "4.5.2"
   resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5"
 
-lodash.defaults@^4.2.0:
+lodash.defaults@^4.0.1, lodash.defaults@^4.2.0:
   version "4.2.0"
   resolved "https://registry.yarnpkg.com/lodash.defaults/-/lodash.defaults-4.2.0.tgz#d09178716ffea4dde9e5fb7b37f6f0802274580c"
 
+lodash.filter@^4.4.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.filter/-/lodash.filter-4.6.0.tgz#668b1d4981603ae1cc5a6fa760143e480b4c4ace"
+
+lodash.flatten@^4.2.0:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f"
+
+lodash.foreach@^4.3.0:
+  version "4.5.0"
+  resolved "https://registry.yarnpkg.com/lodash.foreach/-/lodash.foreach-4.5.0.tgz#1a6a35eace401280c7f06dddec35165ab27e3e53"
+
+lodash.map@^4.4.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.map/-/lodash.map-4.6.0.tgz#771ec7839e3473d9c4cde28b19394c3562f4f6d3"
+
 lodash.memoize@^4.1.2:
   version "4.1.2"
   resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
 
+lodash.merge@^4.4.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5"
+
 lodash.mergewith@^4.6.0:
   version "4.6.0"
   resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55"
 
+lodash.pick@^4.2.1:
+  version "4.4.0"
+  resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3"
+
+lodash.reduce@^4.4.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.reduce/-/lodash.reduce-4.6.0.tgz#f1ab6b839299ad48f784abbf476596f03b914d3b"
+
+lodash.reject@^4.4.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.reject/-/lodash.reject-4.6.0.tgz#80d6492dc1470864bbf583533b651f42a9f52415"
+
+lodash.some@^4.4.0:
+  version "4.6.0"
+  resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d"
+
 lodash.template@^4.4.0:
   version "4.4.0"
   resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.4.0.tgz#e73a0385c8355591746e020b99679c690e68fba0"
@@ -4243,10 +4352,31 @@
   version "1.1.8"
   resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.8.tgz#28a659cf987d96a4dabe7860289f3b5326c4a03c"
 
-object-keys@^1.0.8:
+object-is@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.0.1.tgz#0aa60ec9989a0b3ed795cf4d06f62cf1ad6539b6"
+
+object-keys@^1.0.10, object-keys@^1.0.8:
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
 
+object.assign@^4.0.4:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.0.4.tgz#b1c9cc044ef1b9fe63606fc141abbb32e14730cc"
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.0"
+    object-keys "^1.0.10"
+
+object.entries@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f"
+  dependencies:
+    define-properties "^1.1.2"
+    es-abstract "^1.6.1"
+    function-bind "^1.1.0"
+    has "^1.0.1"
+
 object.omit@^2.0.0:
   version "2.0.1"
   resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa"
@@ -4254,6 +4384,15 @@
     for-own "^0.1.4"
     is-extendable "^0.1.1"
 
+object.values@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.0.4.tgz#e524da09b4f66ff05df457546ec72ac99f13069a"
+  dependencies:
+    define-properties "^1.1.2"
+    es-abstract "^1.6.1"
+    function-bind "^1.1.0"
+    has "^1.0.1"
+
 obuf@^1.0.0, obuf@^1.1.0:
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e"
@@ -4856,7 +4995,7 @@
   dependencies:
     asap "~2.0.3"
 
-prop-types@^15.5.10, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7:
+prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@~15.5.7:
   version "15.5.10"
   resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154"
   dependencies:
@@ -5087,6 +5226,13 @@
   optionalDependencies:
     fsevents "1.0.17"
 
+react-test-renderer@^15.5.4:
+  version "15.5.4"
+  resolved "https://registry.yarnpkg.com/react-test-renderer/-/react-test-renderer-15.5.4.tgz#d4ebb23f613d685ea8f5390109c2d20fbf7c83bc"
+  dependencies:
+    fbjs "^0.8.9"
+    object-assign "^4.1.0"
+
 react@^15.5.4:
   version "15.5.4"
   resolved "https://registry.yarnpkg.com/react/-/react-15.5.4.tgz#fa83eb01506ab237cdc1c8c3b1cea8de012bf047"
@@ -6185,7 +6331,7 @@
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8"
 
-uuid@^2.0.1, uuid@^2.0.2:
+uuid@^2.0.1, uuid@^2.0.2, uuid@^2.0.3:
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-2.0.3.tgz#67e2e863797215530dff318e5bf9dcebfd47b21a"