You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by be...@apache.org on 2016/02/01 18:40:21 UTC

[2/6] fauxton commit: updated refs/heads/master to e6450a0

removing react 14 warnings


Project: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/commit/e6450a0d
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/tree/e6450a0d
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/diff/e6450a0d

Branch: refs/heads/master
Commit: e6450a0d0c9710d79e96bc924c447b8cb12f01b8
Parents: cab6fc2
Author: Ben Keen <be...@gmail.com>
Authored: Tue Jan 19 10:33:45 2016 -0800
Committer: Ben Keen <be...@gmail.com>
Committed: Mon Feb 1 08:39:35 2016 -0800

----------------------------------------------------------------------
 app/addons/activetasks/components.react.jsx     | 34 ++++++------
 .../tests/activetasks.componentsSpec.react.jsx  | 13 ++---
 app/addons/auth/components.react.jsx            | 13 ++---
 .../auth/test/auth.componentsSpec.react.jsx     | 31 +++++------
 app/addons/cluster/tests/clusterSpec.react.jsx  | 10 ++--
 .../compaction/tests/componentsSpec.react.jsx   | 15 +++---
 .../components/react-components.react.jsx       | 25 +++++----
 .../tests/apiBarControllerSpec.react.jsx        | 31 +++++------
 .../components/tests/beautifySpec.react.jsx     | 14 ++---
 .../tests/codeEditorPanelSpec.react.jsx         | 13 ++---
 .../components/tests/codeEditorSpec.react.jsx   |  7 +--
 .../tests/confirmButtonSpec.react.jsx           | 12 ++---
 app/addons/components/tests/docSpec.react.jsx   | 32 ++++++------
 .../tests/headerTogglebuttonSpec.react.jsx      | 10 ++--
 .../tests/paddedBorderedBoxSpec.react.jsx       | 10 ++--
 .../tests/stringEditModalSpec.react.jsx         | 55 +++-----------------
 .../components/tests/styledSelectSpec.react.jsx | 10 ++--
 .../components/tests/zenModeSpec.react.jsx      | 17 +++---
 app/addons/cors/tests/componentsSpec.react.jsx  | 55 ++++++++++----------
 app/addons/databases/components.react.jsx       | 27 +++++-----
 .../databases/tests/componentsSpec.react.jsx    | 31 +++++------
 .../documents/changes/components.react.jsx      | 19 ++++---
 .../tests/changes.componentsSpec.react.jsx      | 53 ++++++++++---------
 .../documents/doc-editor/components.react.jsx   |  5 +-
 .../tests/doc-editor.componentsSpec.react.jsx   | 55 +++++++++-----------
 app/addons/documents/helpers.js                 |  6 ++-
 .../tests/viewIndex.componentsSpec.react.jsx    | 23 ++++----
 .../index-results.components.react.jsx          |  2 +-
 .../index-results.componentsSpec.react.jsx      | 40 +++++++-------
 .../mango/tests/mango.componentsSpec.react.jsx  | 25 +++++----
 .../tests/pagination.componentSpec.react.jsx    | 14 ++---
 .../queryoptions/queryoptions.react.jsx         | 11 ++--
 .../tests/queryoptions.componentsSpec.react.jsx | 21 ++++----
 app/addons/documents/sidebar/sidebar.react.jsx  | 10 ++--
 .../tests/sidebar.componentsSpec.react.jsx      | 11 ++--
 app/addons/documents/tests/helpersSpec.js       | 31 +++++++++++
 app/addons/fauxton/components.react.jsx         | 11 ++--
 .../fauxton/navigation/components.react.jsx     |  5 +-
 .../navigation/tests/componentsSpec.react.jsx   | 13 ++---
 .../notifications/notifications.react.jsx       | 11 ++--
 .../tests/componentsSpec.react.jsx              | 43 +++++++--------
 .../fauxton/tests/componentsSpec.react.jsx      | 25 ++++-----
 .../permissions/tests/componentsSpec.react.jsx  | 25 ++++-----
 .../setup/tests/setupComponentsSpec.react.jsx   | 21 ++++----
 .../tests/componentsSpec.react.jsx              | 21 ++++----
 app/config.js                                   |  1 +
 app/core/routeObject.js                         |  7 +--
 app/core/tests/routeObjectSpec.js               | 11 ++--
 48 files changed, 504 insertions(+), 481 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/activetasks/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/components.react.jsx b/app/addons/activetasks/components.react.jsx
index 7e65399..b8d294c 100644
--- a/app/addons/activetasks/components.react.jsx
+++ b/app/addons/activetasks/components.react.jsx
@@ -14,12 +14,13 @@ define([
   'app',
   'api',
   'react',
+  'react-dom',
   'addons/activetasks/stores',
   'addons/activetasks/resources',
   'addons/activetasks/actions',
   'addons/components/react-components.react',
   'addons/fauxton/components.react'
-], function (app, FauxtonAPI, React, Stores, Resources, Actions, Components, ComponentsReact) {
+], function (app, FauxtonAPI, React, ReactDOM, Stores, Resources, Actions, Components, ComponentsReact) {
 
   var activeTasksStore = Stores.activeTasksStore;
   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
@@ -263,21 +264,20 @@ define([
       var th_class = 'header-field ' + this.props.headerName;
 
       return (
-        <input
-          type="radio"
-          name="header-field"
-          id={this.props.headerName}
-          value={this.props.headerName}
-          className="header-field radio"
-          onChange={this.onTableHeaderClick}>
-          <td className={th_class + " tableheader"} value={this.props.headerName}>
-            <label
-              className="header-field label-text active-tasks-header noselect"
-              htmlFor={this.props.headerName}>
-              {this.props.displayName} {arrow}
-            </label>
-          </td>
-        </input>
+        <td className={th_class + " tableheader"} value={this.props.headerName}>
+          <input
+            type="radio"
+            name="header-field"
+            id={this.props.headerName}
+            value={this.props.headerName}
+            className="header-field radio"
+            onChange={this.onTableHeaderClick} />
+          <label
+            className="header-field label-text active-tasks-header noselect"
+            htmlFor={this.props.headerName}>
+            {this.props.displayName} {arrow}
+          </label>
+        </td>
       );
     }
   });
@@ -396,7 +396,7 @@ define([
       e.preventDefault();
       this.refs.view_source_sequence_btn.toggle(function (shown) {
         if (shown) {
-          React.findDOMNode(this.refs.view_source_sequence_btn).focus();
+          ReactDOM.findDOMNode(this.refs.view_source_sequence_btn).focus();
         }
       }.bind(this));
     },

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx b/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
index 6db8f66..6ad4413 100644
--- a/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
+++ b/app/addons/activetasks/tests/activetasks.componentsSpec.react.jsx
@@ -16,9 +16,10 @@ define([
   'addons/activetasks/stores',
   'addons/activetasks/tests/fakeActiveTaskResponse',
   'react',
+  'react-dom',
   'addons/activetasks/actions',
   'testUtils'
-], function (FauxtonAPI, ActiveTasks, Components, Stores, fakedResponse, React, Actions, utils) {
+], function (FauxtonAPI, ActiveTasks, Components, Stores, fakedResponse, React, ReactDOM, Actions, utils) {
   var assert = utils.assert;
   var restore = utils.restore;
   var TestUtils = React.addons.TestUtils;
@@ -39,7 +40,7 @@ define([
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(pollingWidgetDiv);
+        ReactDOM.unmountComponentAtNode(pollingWidgetDiv);
         restore(Actions.changePollingInterval);
       });
 
@@ -67,7 +68,7 @@ define([
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(tableDiv);
+        ReactDOM.unmountComponentAtNode(tableDiv);
         restore(window.confirm);
       });
 
@@ -88,7 +89,7 @@ define([
         it('should trigger change to radio buttons', function () {
           _.each(radioIDs, function (radioID) {
             spy = sinon.spy(Actions, 'switchTab');
-            TestUtils.Simulate.change($(table.getDOMNode()).find('#' + radioID)[0]);
+            TestUtils.Simulate.change($(ReactDOM.findDOMNode(table)).find('#' + radioID)[0]);
             assert.ok(spy.calledOnce);
             spy.restore();
           });
@@ -96,7 +97,7 @@ define([
 
         it('should trigger change to search term', function () {
           spy = sinon.spy(Actions, 'setSearchTerm');
-          TestUtils.Simulate.change($(table.getDOMNode()).find('.searchbox')[0], {target: {value: 'searching'}});
+          TestUtils.Simulate.change($(ReactDOM.findDOMNode(table)).find('.searchbox')[0], {target: {value: 'searching'}});
           assert.ok(spy.calledOnce);
         });
       });
@@ -118,7 +119,7 @@ define([
         it('should trigger change to which header to sort by', function () {
           _.each(headerNames, function (header) {
             spy = sinon.spy(Actions, 'sortByColumnHeader');
-            TestUtils.Simulate.change($(table.getDOMNode()).find('#' + header)[0]);
+            TestUtils.Simulate.change($(ReactDOM.findDOMNode(table)).find('#' + header)[0]);
             assert.ok(spy.calledOnce);
             spy.restore();
           });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/auth/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/auth/components.react.jsx b/app/addons/auth/components.react.jsx
index d4d1abb..448c7c0 100644
--- a/app/addons/auth/components.react.jsx
+++ b/app/addons/auth/components.react.jsx
@@ -14,9 +14,10 @@ define([
   'app',
   'api',
   'react',
+  'react-dom',
   'addons/auth/stores',
   'addons/auth/actions'
-], function (app, FauxtonAPI, React, AuthStores, AuthActions) {
+], function (app, FauxtonAPI, React, ReactDOM, AuthStores, AuthActions) {
 
   var changePasswordStore = AuthStores.changePasswordStore;
   var createAdminStore = AuthStores.createAdminStore;
@@ -64,8 +65,8 @@ define([
       if (this.state.username !== '' || this.state.password !== '') {
         return false;
       }
-      var username = (this.props.testBlankUsername) ? this.props.testBlankUsername : React.findDOMNode(this.refs.username).value;
-      var password = (this.props.testBlankPassword) ? this.props.testBlankPassword : React.findDOMNode(this.refs.password).value;
+      var username = (this.props.testBlankUsername) ? this.props.testBlankUsername : ReactDOM.findDOMNode(this.refs.username).value;
+      var password = (this.props.testBlankPassword) ? this.props.testBlankPassword : ReactDOM.findDOMNode(this.refs.password).value;
       this.setState({ username: username, password: password }); // doesn't set immediately, hence separate login() call
       this.login(username, password);
 
@@ -77,7 +78,7 @@ define([
     },
 
     componentDidMount: function () {
-      React.findDOMNode(this.refs.username).focus();
+      ReactDOM.findDOMNode(this.refs.username).focus();
     },
 
     render: function () {
@@ -128,7 +129,7 @@ define([
     },
 
     componentDidMount: function () {
-      React.findDOMNode(this.refs.password).focus();
+      ReactDOM.findDOMNode(this.refs.password).focus();
       changePasswordStore.on('change', this.onChange, this);
     },
 
@@ -203,7 +204,7 @@ define([
     },
 
     componentDidMount: function () {
-      React.findDOMNode(this.refs.username).focus();
+      ReactDOM.findDOMNode(this.refs.username).focus();
       createAdminStore.on('change', this.onChange, this);
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/auth/test/auth.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/auth/test/auth.componentsSpec.react.jsx b/app/addons/auth/test/auth.componentsSpec.react.jsx
index 5113147..f8315bb 100644
--- a/app/addons/auth/test/auth.componentsSpec.react.jsx
+++ b/app/addons/auth/test/auth.componentsSpec.react.jsx
@@ -12,11 +12,12 @@
 define([
   'api',
   'react',
+  'react-dom',
   'testUtils',
   'addons/auth/components.react',
   'addons/auth/stores',
   'addons/auth/actions'
-], function (FauxtonAPI, React, utils, Components, Stores, Actions) {
+], function (FauxtonAPI, React, ReactDOM, utils, Components, Stores, Actions) {
   var assert = utils.assert;
 
   var TestUtils = React.addons.TestUtils;
@@ -34,14 +35,14 @@ define([
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
         createAdminSidebarStore.reset();
         Actions.login.restore();
       });
 
       it('should trigger login event when form submitted', function () {
         loginForm = TestUtils.renderIntoDocument(<Components.LoginForm />, container);
-        TestUtils.Simulate.submit($(loginForm.getDOMNode()).find('#login')[0]);
+        TestUtils.Simulate.submit($(ReactDOM.findDOMNode(loginForm)).find('#login')[0]);
         assert.ok(stub.calledOnce);
       });
 
@@ -55,7 +56,7 @@ define([
             testBlankPassword={password}
           />, container);
 
-        TestUtils.Simulate.submit($(loginForm.getDOMNode()).find('#login')[0]);
+        TestUtils.Simulate.submit($(ReactDOM.findDOMNode(loginForm)).find('#login')[0]);
         assert.ok(stub.calledOnce);
 
         // confirm Actions.login() received the values that weren't in the DOM
@@ -75,24 +76,24 @@ define([
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
       });
 
       it('should call action to update password on field change', function () {
         var spy = sinon.spy(Actions, 'updateChangePasswordField');
-        TestUtils.Simulate.change($(changePasswordForm.getDOMNode()).find('#password')[0], { target: { value: 'bobsyouruncle' }});
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(changePasswordForm)).find('#password')[0], { target: { value: 'bobsyouruncle' }});
         assert.ok(spy.calledOnce);
       });
 
       it('should call action to update password confirm on field change', function () {
         var spy = sinon.spy(Actions, 'updateChangePasswordConfirmField');
-        TestUtils.Simulate.change($(changePasswordForm.getDOMNode()).find('#password-confirm')[0], { target: { value: 'hotdiggity' }});
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(changePasswordForm)).find('#password-confirm')[0], { target: { value: 'hotdiggity' }});
         assert.ok(spy.calledOnce);
       });
 
       it('should call action to submit form', function () {
         var stub = sinon.stub(Actions, 'changePassword', function () {});
-        TestUtils.Simulate.submit($(changePasswordForm.getDOMNode()).find('#change-password')[0]);
+        TestUtils.Simulate.submit($(ReactDOM.findDOMNode(changePasswordForm)).find('#change-password')[0]);
         assert.ok(stub.calledOnce);
       });
     });
@@ -106,18 +107,18 @@ define([
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
       });
 
       it('should call action to update username on field change', function () {
         var spy = sinon.spy(Actions, 'updateCreateAdminUsername');
-        TestUtils.Simulate.change($(createAdminForm.getDOMNode()).find('#username')[0], { target: { value: 'catsmeow' }});
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(createAdminForm)).find('#username')[0], { target: { value: 'catsmeow' }});
         assert.ok(spy.calledOnce);
       });
 
       it('should call action to update password confirm on field change', function () {
         var spy = sinon.spy(Actions, 'updateCreateAdminPassword');
-        TestUtils.Simulate.change($(createAdminForm.getDOMNode()).find('#password')[0], { target: { value: 'topnotch' }});
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(createAdminForm)).find('#password')[0], { target: { value: 'topnotch' }});
         assert.ok(spy.calledOnce);
       });
     });
@@ -132,16 +133,16 @@ define([
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
       });
 
       it('confirm the default selected nav item is the change pwd page', function () {
-        assert.equal($(createAdminSidebar.getDOMNode()).find('.active').find('a').attr('href'), '#changePassword');
+        assert.equal($(ReactDOM.findDOMNode(createAdminSidebar)).find('.active').find('a').attr('href'), '#changePassword');
       });
 
       it('confirm clicking a sidebar nav item selects it in the DOM', function () {
-        TestUtils.Simulate.click($(createAdminSidebar.getDOMNode()).find('li[data-page="addAdmin"]').find('a')[0]);
-        assert.equal($(createAdminSidebar.getDOMNode()).find('.active').find('a').attr('href'), '#addAdmin');
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(createAdminSidebar)).find('li[data-page="addAdmin"]').find('a')[0]);
+        assert.equal($(ReactDOM.findDOMNode(createAdminSidebar)).find('.active').find('a').attr('href'), '#addAdmin');
       });
     });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/cluster/tests/clusterSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/cluster/tests/clusterSpec.react.jsx b/app/addons/cluster/tests/clusterSpec.react.jsx
index 9a6c3b5..08e3625 100644
--- a/app/addons/cluster/tests/clusterSpec.react.jsx
+++ b/app/addons/cluster/tests/clusterSpec.react.jsx
@@ -14,10 +14,10 @@ define([
   'addons/cluster/cluster.react',
   'addons/cluster/cluster.actions',
   'addons/cluster/cluster.stores',
-
   'testUtils',
-  'react'
-], function (FauxtonAPI, ClusterComponent, ClusterActions, ClusterStores, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ClusterComponent, ClusterActions, ClusterStores, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -47,11 +47,11 @@ define([
 
     afterEach(function () {
       ClusterStores.nodesStore.reset();
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('renders the amount of nodes', function () {
-      assert.ok(/6 nodes/.test($(controller.getDOMNode()).text()), 'finds 6 nodes');
+      assert.ok(/6 nodes/.test($(ReactDOM.findDOMNode(controller)).text()), 'finds 6 nodes');
     });
   });
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/compaction/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/compaction/tests/componentsSpec.react.jsx b/app/addons/compaction/tests/componentsSpec.react.jsx
index 5c6a18a..08fb02e 100644
--- a/app/addons/compaction/tests/componentsSpec.react.jsx
+++ b/app/addons/compaction/tests/componentsSpec.react.jsx
@@ -14,8 +14,9 @@ define([
   'addons/compaction/components.react',
   'addons/compaction/actions',
   'testUtils',
-  "react"
-], function (FauxtonAPI, Views, Actions, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, Views, Actions, utils, React, ReactDOM) {
   FauxtonAPI.router = new FauxtonAPI.Router([]);
 
   var assert = utils.assert;
@@ -37,7 +38,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('triggers compact database action', function () {
@@ -69,11 +70,11 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('calls cleanupView on button click', function () {
-      var el = $(cleanupViewEl.getDOMNode()).find('button')[0];
+      var el = $(ReactDOM.findDOMNode(cleanupViewEl)).find('button')[0];
       TestUtils.Simulate.click(el, {});
 
       assert.ok(spy.calledOnce);
@@ -95,11 +96,11 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('calls compact database on button click', function () {
-      var el = $(compactViewEl.getDOMNode()).find('button')[0];
+      var el = $(ReactDOM.findDOMNode(compactViewEl)).find('button')[0];
       TestUtils.Simulate.click(el, {});
 
       assert.ok(spy.calledOnce);

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/react-components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/react-components.react.jsx b/app/addons/components/react-components.react.jsx
index a471637..606d50b 100644
--- a/app/addons/components/react-components.react.jsx
+++ b/app/addons/components/react-components.react.jsx
@@ -14,14 +14,16 @@ define([
   'app',
   'api',
   'react',
+  'react-dom',
   'addons/components/stores',
   'addons/fauxton/components.react',
+  'addons/documents/helpers',
   'ace/ace',
   'plugins/beautify',
   'libs/react-bootstrap'
 ],
 
-function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper, ReactBootstrap) {
+function (app, FauxtonAPI, React, ReactDOM, Stores, FauxtonComponents, Helpers, ace, beautifyHelper, ReactBootstrap) {
 
   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
   var componentStore = Stores.componentStore;
@@ -450,7 +452,7 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
     },
 
     setupAce: function (props, shouldUpdateCode) {
-      this.editor = ace.edit(React.findDOMNode(this.refs.ace));
+      this.editor = ace.edit(ReactDOM.findDOMNode(this.refs.ace));
 
       // suppresses an Ace editor error
       this.editor.$blockScrolling = Infinity;
@@ -770,14 +772,14 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
       }
       var val = '';
       if (!prevProps.visible && this.props.visible) {
-        val = JSON.parse('"' + this.props.value + '"'); // this ensures newlines are converted
+        val = Helpers.parseJSON(this.props.value);
       }
 
       this.initEditor(val);
     },
 
     initEditor: function (val) {
-      this.editor = ace.edit(React.findDOMNode(this.refs.stringEditor));
+      this.editor = ace.edit(ReactDOM.findDOMNode(this.refs.stringEditor));
       this.editor.$blockScrolling = Infinity; // suppresses an Ace editor error
       this.editor.setShowPrintMargin(false);
       this.editor.setOption('highlightActiveLine', true);
@@ -857,8 +859,8 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
     },
 
     componentDidMount: function () {
-      $(React.findDOMNode(this.refs.exit)).tooltip({ placement: 'left' });
-      $(React.findDOMNode(this.refs.theme)).tooltip({ placement: 'left' });
+      $(ReactDOM.findDOMNode(this.refs.exit)).tooltip({ placement: 'left' });
+      $(ReactDOM.findDOMNode(this.refs.theme)).tooltip({ placement: 'left' });
     },
 
     exitZenMode: function () {
@@ -1194,7 +1196,8 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
 
     render: function () {
       return (
-        <ReactCSSTransitionGroup transitionName="tray" transitionAppear={true} component="div">
+        <ReactCSSTransitionGroup transitionName="tray" transitionAppear={true} component="div" transitionAppearTimeout={500}
+          transitionEnterTimeout={500} transitionLeaveTimeout={300}>
           {this.getChildren()}
         </ReactCSSTransitionGroup>
       );
@@ -1246,7 +1249,7 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
 
     renderChildren: function () {
       return React.Children.map(this.props.children, function (child, key) {
-        return React.addons.cloneWithProps(child, {
+        return React.cloneElement(child, {
           trayVisible: this.state.trayVisible,
           selected: this.state.trayVisible,
           toggleCallback: this.toggleTray,
@@ -1265,7 +1268,7 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
 
     closeIfOpen: function (e) {
       if (!this.state.trayVisible) { return; }
-      var trayEl = $(React.findDOMNode(this));
+      var trayEl = $(ReactDOM.findDOMNode(this));
 
       if (!trayEl.is(e.target) && trayEl.has(e.target).length === 0) {
         this.toggleTray();
@@ -1385,11 +1388,11 @@ function (app, FauxtonAPI, React, Stores, FauxtonComponents, ace, beautifyHelper
     ApiBarController: ApiBarController,
 
     renderMenuDropDown: function (el, opts) {
-      React.render(<MenuDropDown icon="fonticon-cog" links={opts.links} />, el);
+      ReactDOM.render(<MenuDropDown icon="fonticon-cog" links={opts.links} />, el);
     },
 
     removeMenuDropDown: function (el) {
-      React.unmountComponentAtNode(el);
+      ReactDOM.unmountComponentAtNode(el);
     },
   };
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/apiBarControllerSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/apiBarControllerSpec.react.jsx b/app/addons/components/tests/apiBarControllerSpec.react.jsx
index 3f516d8..4ca4b5d 100644
--- a/app/addons/components/tests/apiBarControllerSpec.react.jsx
+++ b/app/addons/components/tests/apiBarControllerSpec.react.jsx
@@ -15,8 +15,9 @@ define([
   'addons/components/stores',
   'addons/components/react-components.react',
   'testUtils',
-  'react'
-], function (FauxtonAPI, Actions, Stores, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, Actions, Stores, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -32,7 +33,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
       componentStore.reset();
     });
 
@@ -83,16 +84,16 @@ define([
       var el = TestUtils.renderIntoDocument(<ApiBarController />, container);
       Actions.updateAPIBar({ visible: true, endpoint: 'http://link.com', docURL: 'http://doc.com' });
 
-      TestUtils.Simulate.click($(el.getDOMNode()).find('.control-toggle-api-url')[0]);
-      assert.equal($(el.getDOMNode()).find('.help-link').length, 1);
+      TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.control-toggle-api-url')[0]);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.help-link').length, 1);
     });
 
     it('Confirm doc link icon doesn\'t appear with no docURL', function () {
       var el = TestUtils.renderIntoDocument(<ApiBarController />, container);
       Actions.updateAPIBar({ visible: true, endpoint: 'http://link.com', docURL: null });
 
-      TestUtils.Simulate.click($(el.getDOMNode()).find('.control-toggle-api-url')[0]);
-      assert.equal($(el.getDOMNode()).find('.help-link').length, 0);
+      TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.control-toggle-api-url')[0]);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.help-link').length, 0);
     });
 
     it('Confirm endpoint appears in markup', function () {
@@ -100,8 +101,8 @@ define([
       var link = 'http://booyah.ca';
       Actions.updateAPIBar({ visible: true, endpoint: link, docURL: null });
 
-      TestUtils.Simulate.click($(el.getDOMNode()).find('.control-toggle-api-url')[0]);
-      assert.equal($(el.getDOMNode()).find('.text-field-to-copy').val(), link);
+      TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.control-toggle-api-url')[0]);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.text-field-to-copy').val(), link);
     });
 
     it('Confirm endpoint is updated in markup', function () {
@@ -109,12 +110,12 @@ define([
       var link = 'http://booyah.ca';
       Actions.updateAPIBar({ visible: true, endpoint: link, docURL: null });
 
-      TestUtils.Simulate.click($(el.getDOMNode()).find('.control-toggle-api-url')[0]);
-      assert.equal($(el.getDOMNode()).find('.text-field-to-copy').val(), link);
+      TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.control-toggle-api-url')[0]);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.text-field-to-copy').val(), link);
 
       var newLink = 'http://chickensarenoisy.com';
       Actions.updateAPIBar({ endpoint: newLink });
-      assert.equal($(el.getDOMNode()).find('.text-field-to-copy').val(), newLink);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.text-field-to-copy').val(), newLink);
     });
 
     it('Confirm doc URL is updated in markup after a change', function () {
@@ -122,12 +123,12 @@ define([
       var docLink = 'http://mydoc.org';
       Actions.updateAPIBar({ visible: true, endpoint: 'http://whatever.com', docURL: docLink });
 
-      TestUtils.Simulate.click($(el.getDOMNode()).find('.control-toggle-api-url')[0]);
-      assert.equal($(el.getDOMNode()).find('.help-link').attr('href'), docLink);
+      TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.control-toggle-api-url')[0]);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.help-link').attr('href'), docLink);
 
       var newDocLink = 'http://newawesomedoclink.xxx';
       Actions.updateAPIBar({ docURL: newDocLink });
-      assert.equal($(el.getDOMNode()).find('.help-link').attr('href'), newDocLink);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.help-link').attr('href'), newDocLink);
     });
 
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/beautifySpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/beautifySpec.react.jsx b/app/addons/components/tests/beautifySpec.react.jsx
index 92260cb..17d106d 100644
--- a/app/addons/components/tests/beautifySpec.react.jsx
+++ b/app/addons/components/tests/beautifySpec.react.jsx
@@ -12,10 +12,10 @@
 define([
   'api',
   'addons/components/react-components.react',
-
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -28,7 +28,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('should be empty for multi-lined code', function () {
@@ -37,13 +37,13 @@ define([
         <ReactComponents.Beautify code={correctCode}/>,
         container
       );
-      assert.ok(_.isNull(beautifyEl.getDOMNode()));
+      assert.ok(_.isNull(ReactDOM.findDOMNode(beautifyEl)));
     });
 
     it('should have button to beautify for single line code', function () {
       var badCode = 'function () { console.log("hello"); }';
       beautifyEl = TestUtils.renderIntoDocument(<ReactComponents.Beautify code={badCode}/>, container);
-      assert.ok($(beautifyEl.getDOMNode()).hasClass('beautify'));
+      assert.ok($(ReactDOM.findDOMNode(beautifyEl)).hasClass('beautify'));
     });
 
     it('on click beautifies code', function () {
@@ -61,7 +61,7 @@ define([
           noOfLines={1}/>,
         container
       );
-      TestUtils.Simulate.click(beautifyEl.getDOMNode());
+      TestUtils.Simulate.click(ReactDOM.findDOMNode(beautifyEl));
       assert.equal(fixedCode, correctCode);
 
     });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/codeEditorPanelSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/codeEditorPanelSpec.react.jsx b/app/addons/components/tests/codeEditorPanelSpec.react.jsx
index a2a1dcd..98252b5 100644
--- a/app/addons/components/tests/codeEditorPanelSpec.react.jsx
+++ b/app/addons/components/tests/codeEditorPanelSpec.react.jsx
@@ -13,8 +13,9 @@ define([
   'api',
   'addons/components/react-components.react',
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -30,7 +31,7 @@ define([
           <ReactComponents.CodeEditorPanel defaultCode={code} />,
           container
         );
-        assert.equal($(codeEditorEl.getDOMNode()).find('.icon-question-sign').length, 0);
+        assert.equal($(ReactDOM.findDOMNode(codeEditorEl)).find('.icon-question-sign').length, 0);
       });
       it('hidden by default', function () {
         var container = document.createElement('div');
@@ -38,7 +39,7 @@ define([
           <ReactComponents.CodeEditorPanel defaultCode={code} docLink="http://link.com" />,
           container
         );
-        assert.equal($(codeEditorEl.getDOMNode()).find('.icon-question-sign').length, 1);
+        assert.equal($(ReactDOM.findDOMNode(codeEditorEl)).find('.icon-question-sign').length, 1);
       });
     });
 
@@ -49,7 +50,7 @@ define([
           <ReactComponents.CodeEditorPanel defaultCode={code} />,
           container
         );
-        assert.equal($(codeEditorEl.getDOMNode()).find('.zen-editor-icon').length, 1);
+        assert.equal($(ReactDOM.findDOMNode(codeEditorEl)).find('.zen-editor-icon').length, 1);
       });
 
       it('omits zen mode if explicitly turned off', function () {
@@ -58,7 +59,7 @@ define([
           <ReactComponents.CodeEditor defaultCode={code} allowZenMode={false} />,
           container
         );
-        assert.equal($(codeEditorEl.getDOMNode()).find('.zen-editor-icon').length, 0);
+        assert.equal($(ReactDOM.findDOMNode(codeEditorEl)).find('.zen-editor-icon').length, 0);
       });
     });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/codeEditorSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/codeEditorSpec.react.jsx b/app/addons/components/tests/codeEditorSpec.react.jsx
index ee3dbd5..3ba5ce7 100644
--- a/app/addons/components/tests/codeEditorSpec.react.jsx
+++ b/app/addons/components/tests/codeEditorSpec.react.jsx
@@ -13,8 +13,9 @@ define([
   'api',
   'addons/components/react-components.react',
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -39,7 +40,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     describe('Tracking edits', function () {

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/confirmButtonSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/confirmButtonSpec.react.jsx b/app/addons/components/tests/confirmButtonSpec.react.jsx
index d4d428a..d650c59 100644
--- a/app/addons/components/tests/confirmButtonSpec.react.jsx
+++ b/app/addons/components/tests/confirmButtonSpec.react.jsx
@@ -12,10 +12,10 @@
 define([
   'api',
   'addons/components/react-components.react',
-
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -27,7 +27,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('should render text properties', function () {
@@ -35,7 +35,7 @@ define([
         <ReactComponents.ConfirmButton text="Click here to render Rocko Artischocko" />,
         container
       );
-      assert.equal($(button.getDOMNode()).text(), 'Click here to render Rocko Artischocko');
+      assert.equal($(ReactDOM.findDOMNode(button)).text(), 'Click here to render Rocko Artischocko');
     });
 
     it('should use onClick handler if provided', function () {
@@ -46,7 +46,7 @@ define([
         container
       );
 
-      React.addons.TestUtils.Simulate.click(button.getDOMNode());
+      React.addons.TestUtils.Simulate.click(ReactDOM.findDOMNode(button));
       assert.ok(spy.calledOnce);
     });
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/docSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/docSpec.react.jsx b/app/addons/components/tests/docSpec.react.jsx
index a931019..a013cb0 100644
--- a/app/addons/components/tests/docSpec.react.jsx
+++ b/app/addons/components/tests/docSpec.react.jsx
@@ -12,10 +12,10 @@
 define([
   'api',
   'addons/components/react-components.react',
-
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -28,7 +28,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('hosts child elements', function () {
@@ -38,7 +38,7 @@ define([
         </ReactComponents.Document>,
         container
       );
-      assert.ok($(el.getDOMNode()).find('.foo-children').length);
+      assert.ok($(ReactDOM.findDOMNode(el)).find('.foo-children').length);
     });
 
     it('does not require child elements', function () {
@@ -46,7 +46,7 @@ define([
         <ReactComponents.Document />,
         container
       );
-      assert.notOk($(el.getDOMNode()).find('.doc-edit-symbol').length);
+      assert.notOk($(ReactDOM.findDOMNode(el)).find('.doc-edit-symbol').length);
     });
 
     it('you can check it', function () {
@@ -54,7 +54,7 @@ define([
         <ReactComponents.Document isDeletable={true} checked={true} docIdentifier="foo" />,
         container
       );
-      assert.equal($(el.getDOMNode()).find('input[type="checkbox"]').attr('checked'), 'checked');
+      assert.equal($(ReactDOM.findDOMNode(el)).find('input[type="checkbox"]').attr('checked'), 'checked');
     });
 
     it('you can uncheck it', function () {
@@ -62,7 +62,7 @@ define([
         <ReactComponents.Document isDeletable={true} docIdentifier="foo" />,
         container
       );
-      assert.equal($(el.getDOMNode()).find('input[type="checkbox"]').attr('checked'), undefined);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('input[type="checkbox"]').attr('checked'), undefined);
     });
 
     it('it calls an onchange callback', function () {
@@ -72,7 +72,7 @@ define([
         <ReactComponents.Document doc={{id: "foo"}} isDeletable={true} docChecked={spy} docIdentifier="foo" />,
         container
       );
-      var testEl = $(el.getDOMNode()).find('input[type="checkbox"]')[0];
+      var testEl = $(ReactDOM.findDOMNode(el)).find('input[type="checkbox"]')[0];
       React.addons.TestUtils.Simulate.change(testEl, {target: {value: 'Hello, world'}});
       assert.ok(spy.calledOnce);
     });
@@ -84,7 +84,7 @@ define([
         <ReactComponents.Document isDeletable={true} onDoubleClick={spy} docIdentifier="foo" />,
         container
       );
-      React.addons.TestUtils.Simulate.doubleClick(el.getDOMNode());
+      React.addons.TestUtils.Simulate.doubleClick(ReactDOM.findDOMNode(el));
       assert.ok(spy.calledOnce);
     });
 
@@ -95,8 +95,8 @@ define([
         <ReactComponents.Document isDeletable={false} onDoubleClick={spy} docIdentifier="foo" />,
         container
       );
-      assert.notOk($(el.getDOMNode()).find('input[type="checkbox"]').length);
-      assert.ok($(el.getDOMNode()).find('.checkbox-dummy').length);
+      assert.notOk($(ReactDOM.findDOMNode(el)).find('input[type="checkbox"]').length);
+      assert.ok($(ReactDOM.findDOMNode(el)).find('.checkbox-dummy').length);
     });
 
     it('contains a doc-data element when there\'s doc content', function () {
@@ -104,7 +104,7 @@ define([
         <ReactComponents.Document isDeletable={true} checked={true} docIdentifier="foo" docContent='{ "content": true }' />,
         container
       );
-      assert.equal(1, $(el.getDOMNode()).find('.doc-data').length);
+      assert.equal(1, $(ReactDOM.findDOMNode(el)).find('.doc-data').length);
     });
 
     it('doesn\'t contain a doc-data element when there\'s no doc content', function () {
@@ -112,7 +112,7 @@ define([
         <ReactComponents.Document isDeletable={true} checked={true} docIdentifier="foo" docContent='' />,
         container
       );
-      assert.equal(0, $(el.getDOMNode()).find('.doc-data').length);
+      assert.equal(0, $(ReactDOM.findDOMNode(el)).find('.doc-data').length);
     });
 
     it('allows empty headers', function () {
@@ -120,7 +120,7 @@ define([
         <ReactComponents.Document header={null} isDeletable={true} checked={true} docIdentifier="foo" docContent='' />,
         container
       );
-      assert.equal('', $(el.getDOMNode()).find('.header-doc-id').text());
+      assert.equal('', $(ReactDOM.findDOMNode(el)).find('.header-doc-id').text());
     });
 
     it('allows supports headers with "', function () {
@@ -128,7 +128,7 @@ define([
         <ReactComponents.Document header="foo" isDeletable={true} checked={true} docIdentifier="foo" docContent='' />,
         container
       );
-      assert.equal('"foo"', $(el.getDOMNode()).find('.header-doc-id').text());
+      assert.equal('"foo"', $(ReactDOM.findDOMNode(el)).find('.header-doc-id').text());
     });
   });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/headerTogglebuttonSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/headerTogglebuttonSpec.react.jsx b/app/addons/components/tests/headerTogglebuttonSpec.react.jsx
index 14523f3..6ce0776 100644
--- a/app/addons/components/tests/headerTogglebuttonSpec.react.jsx
+++ b/app/addons/components/tests/headerTogglebuttonSpec.react.jsx
@@ -12,10 +12,10 @@
 define([
   'api',
   'addons/components/react-components.react',
-
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -30,11 +30,11 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('should call the passed callback', function () {
-      TestUtils.Simulate.click(toggleEl.getDOMNode());
+      TestUtils.Simulate.click(ReactDOM.findDOMNode(toggleEl));
       assert.ok(toggleCallback.calledOnce);
     });
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/paddedBorderedBoxSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/paddedBorderedBoxSpec.react.jsx b/app/addons/components/tests/paddedBorderedBoxSpec.react.jsx
index b262bc3..a0e2866 100644
--- a/app/addons/components/tests/paddedBorderedBoxSpec.react.jsx
+++ b/app/addons/components/tests/paddedBorderedBoxSpec.react.jsx
@@ -12,10 +12,10 @@
 define([
   'api',
   'addons/components/react-components.react',
-
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -28,7 +28,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('hosts child elements', function () {
@@ -38,7 +38,7 @@ define([
         </ReactComponents.PaddedBorderedBox>,
         container
       );
-      assert.ok($(el.getDOMNode()).find('.foo-children').length);
+      assert.ok($(ReactDOM.findDOMNode(el)).find('.foo-children').length);
     });
   });
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/stringEditModalSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/stringEditModalSpec.react.jsx b/app/addons/components/tests/stringEditModalSpec.react.jsx
index bc1fd71..188581c 100644
--- a/app/addons/components/tests/stringEditModalSpec.react.jsx
+++ b/app/addons/components/tests/stringEditModalSpec.react.jsx
@@ -14,8 +14,9 @@ define([
   'addons/components/react-components.react',
   'libs/react-bootstrap',
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, ReactBootstrap, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, ReactBootstrap, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -31,34 +32,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
-    });
-
-    describe('event methods called', function () {
-      it('onClose called by top (x)', function () {
-        var spy = sinon.spy();
-        el = TestUtils.renderIntoDocument(
-          <ReactComponents.StringEditModal visible={true} onClose={spy} onSave={stub} />,
-          container
-        );
-        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
-        var modalEl = React.findDOMNode(modal.refs.modal);
-
-        TestUtils.Simulate.click($(modalEl).find('.close')[0]);
-        assert.ok(spy.calledOnce);
-      });
-
-      it('onClose called by cancel button', function () {
-        var spy = sinon.spy();
-        el = TestUtils.renderIntoDocument(
-          <ReactComponents.StringEditModal visible={true} onClose={spy} onSave={stub} />,
-          container
-        );
-        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
-        var modalEl = React.findDOMNode(modal.refs.modal);
-        TestUtils.Simulate.click($(modalEl).find('.cancel-button')[0]);
-        assert.ok(spy.calledOnce);
-      });
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     describe('onSave', function () {
@@ -69,28 +43,11 @@ define([
           <ReactComponents.StringEditModal visible={true} onClose={stub} onSave={spy} value={string} />,
           container
         );
-        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
-        var modalEl = React.findDOMNode(modal.refs.modal);
-
-        TestUtils.Simulate.click($(modalEl).find('#string-edit-save-btn')[0]);
+        TestUtils.Simulate.click($('body').find('#string-edit-save-btn')[0]);
         assert.ok(spy.calledOnce);
         assert.ok(spy.calledWith(string));
       });
-
-      it('replaces "\\n" with actual newlines', function () {
-        var spy = sinon.spy();
-        var string = 'I am a string\\nwith\\nlinebreaks\\nin\\nit';
-        el = TestUtils.renderIntoDocument(
-          <ReactComponents.StringEditModal visible={true} onSave={spy} value={string} />,
-          container
-        );
-
-        var modal = TestUtils.findRenderedComponentWithType(el, Modal);
-        var modalEl = React.findDOMNode(modal.refs.modal);
-
-        TestUtils.Simulate.click($(modalEl).find('#string-edit-save-btn')[0]);
-        assert.ok(spy.calledOnce);
-      });
     });
   });
+
 });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/styledSelectSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/styledSelectSpec.react.jsx b/app/addons/components/tests/styledSelectSpec.react.jsx
index 7a3328a..94e0028 100644
--- a/app/addons/components/tests/styledSelectSpec.react.jsx
+++ b/app/addons/components/tests/styledSelectSpec.react.jsx
@@ -12,10 +12,10 @@
 define([
   'api',
   'addons/components/react-components.react',
-
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -44,11 +44,11 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('calls the callback on select', function () {
-      TestUtils.Simulate.change($(selectorEl.getDOMNode()).find('#new-ddoc')[0], {
+      TestUtils.Simulate.change($(ReactDOM.findDOMNode(selectorEl)).find('#new-ddoc')[0], {
         target: {
           value: 'new'
         }

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/components/tests/zenModeSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/components/tests/zenModeSpec.react.jsx b/app/addons/components/tests/zenModeSpec.react.jsx
index ec742d4..7895454 100644
--- a/app/addons/components/tests/zenModeSpec.react.jsx
+++ b/app/addons/components/tests/zenModeSpec.react.jsx
@@ -13,8 +13,9 @@ define([
   'api',
   'addons/components/react-components.react',
   'testUtils',
-  'react'
-], function (FauxtonAPI, ReactComponents, utils, React) {
+  'react',
+  'react-dom'
+], function (FauxtonAPI, ReactComponents, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -33,26 +34,26 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
       window.localStorage.removeItem('zenTheme');
     });
 
     describe('Toggle theme', function () {
       it('defaults to dark theme', function () {
-        assert.ok($(el.getDOMNode()).hasClass('zen-theme-dark'));
+        assert.ok($(ReactDOM.findDOMNode(el)).hasClass('zen-theme-dark'));
       });
 
       it('switch to light theme on click', function () {
-        TestUtils.Simulate.click($(el.getDOMNode()).find('.js-toggle-theme')[0]);
-        assert.ok($(el.getDOMNode()).hasClass('zen-theme-light'));
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.js-toggle-theme')[0]);
+        assert.ok($(ReactDOM.findDOMNode(el)).hasClass('zen-theme-light'));
         // reset
-        TestUtils.Simulate.click($(el.getDOMNode()).find('.js-toggle-theme')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.js-toggle-theme')[0]);
       });
     });
 
     describe('Closing zen mode', function () {
       it('method called', function () {
-        TestUtils.Simulate.click($(el.getDOMNode()).find('.js-exit-zen-mode')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(el)).find('.js-exit-zen-mode')[0]);
         assert.ok(spy.calledOnce);
       });
     });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/cors/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/cors/tests/componentsSpec.react.jsx b/app/addons/cors/tests/componentsSpec.react.jsx
index 7bd5762..dd76ff3 100644
--- a/app/addons/cors/tests/componentsSpec.react.jsx
+++ b/app/addons/cors/tests/componentsSpec.react.jsx
@@ -16,8 +16,9 @@ define([
   'addons/cors/resources',
   'addons/cors/stores',
   'testUtils',
-  "react"
-], function (FauxtonAPI, Views, Actions, Resources, Stores, utils, React) {
+  "react",
+  'react-dom'
+], function (FauxtonAPI, Views, Actions, Resources, Stores, utils, React, ReactDOM) {
 
   FauxtonAPI.router = new FauxtonAPI.Router([]);
   var assert = utils.assert;
@@ -45,7 +46,7 @@ define([
         utils.restore(Actions.toggleLoadingBarsToEnabled);
         utils.restore(corsEl.save);
 
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
         window.confirm.restore && window.confirm.restore();
       });
 
@@ -92,13 +93,13 @@ define([
 
       it('shows loading bars', function () {
         Actions.toggleLoadingBarsToEnabled(true);
-        assert.equal($(corsEl.getDOMNode()).find('.loading-lines').length, 1);
+        assert.equal($(ReactDOM.findDOMNode(corsEl)).find('.loading-lines').length, 1);
       });
 
       it('hides loading bars', function () {
         Actions.toggleLoadingBarsToEnabled(false);
 
-        assert.equal($(corsEl.getDOMNode()).find('.loading-lines').length, 0);
+        assert.equal($(ReactDOM.findDOMNode(corsEl)).find('.loading-lines').length, 0);
       });
     });
 
@@ -115,26 +116,26 @@ define([
       afterEach(function () {
         utils.restore(Resources.validateCORSDomain);
         utils.restore(FauxtonAPI.addNotification);
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
       });
 
       it('calls validates each domain', function () {
         var spy = sinon.spy(Resources, 'validateCORSDomain');
-        TestUtils.Simulate.change($(inputEl.getDOMNode()).find('input')[0], {target: {value: newOrigin}});
-        TestUtils.Simulate.click($(inputEl.getDOMNode()).find('.btn')[0]);
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(inputEl)).find('input')[0], {target: {value: newOrigin}});
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(inputEl)).find('.btn')[0]);
         assert.ok(spy.calledWith(newOrigin));
       });
 
       it('calls addOrigin on add click with valid domain', function () {
-        TestUtils.Simulate.change($(inputEl.getDOMNode()).find('input')[0], {target: {value: newOrigin}});
-        TestUtils.Simulate.click($(inputEl.getDOMNode()).find('.btn')[0]);
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(inputEl)).find('input')[0], {target: {value: newOrigin}});
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(inputEl)).find('.btn')[0]);
         assert.ok(addOrigin.calledWith(newOrigin));
       });
 
       it('shows notification if origin is not valid', function () {
         var spy = sinon.spy(FauxtonAPI, 'addNotification');
-        TestUtils.Simulate.change($(inputEl.getDOMNode()).find('input')[0], {target: {value: 'badOrigin'}});
-        TestUtils.Simulate.click($(inputEl.getDOMNode()).find('.btn')[0]);
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(inputEl)).find('input')[0], {target: {value: 'badOrigin'}});
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(inputEl)).find('.btn')[0]);
         assert.ok(spy.calledOnce);
       });
     });
@@ -149,11 +150,11 @@ define([
       });
 
       afterEach(function () {
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
       });
 
       it('calls change Origin on all origins selected', function () {
-        TestUtils.Simulate.change($(originEl.getDOMNode()).find('input[value="all"]')[0]);
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(originEl)).find('input[value="all"]')[0]);
         assert.ok(changeOrigin.calledWith(true));
       });
 
@@ -165,7 +166,7 @@ define([
         //1. render radio buttons with 'all origins'
         originEl = TestUtils.renderIntoDocument(<Views.Origins corsEnabled={true} isAllOrigins={true} originChange={changeOrigin}/>, container);
         //2. switch back to 'select origins'
-        TestUtils.Simulate.change($(originEl.getDOMNode()).find('input[value="selected"]')[0]);
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(originEl)).find('input[value="selected"]')[0]);
         assert.ok(changeOrigin.calledWith(false));
       });
     });
@@ -185,14 +186,14 @@ define([
       afterEach(function () {
         window.confirm.restore && window.confirm.restore();
         Actions.deleteOrigin.restore && Actions.deleteOrigin.restore();
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
       });
 
       it('should confirm on delete', function () {
         var stub = sinon.stub(window, 'confirm');
         stub.returns(true);
 
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.fonticon-trash')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.fonticon-trash')[0]);
         assert.ok(stub.calledOnce);
       });
 
@@ -210,43 +211,43 @@ define([
       it('should deleteOrigin on confirm true', function () {
         var stub = sinon.stub(window, 'confirm');
         stub.returns(true);
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.fonticon-trash')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.fonticon-trash')[0]);
         assert.ok(deleteOrigin.calledWith(origin));
       });
 
       it('should not deleteOrigin on confirm false', function () {
         var stub = sinon.stub(window, 'confirm');
         stub.returns(false);
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.fonticon-trash')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.fonticon-trash')[0]);
         assert.notOk(deleteOrigin.calledOnce);
       });
 
       it('should change origin to input on edit click', function () {
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.fonticon-pencil')[0]);
-        assert.ok($(originTableEl.getDOMNode()).find('input').length === 1);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.fonticon-pencil')[0]);
+        assert.ok($(ReactDOM.findDOMNode(originTableEl)).find('input').length === 1);
       });
 
       it('should update origin on update clicked', function () {
         var updatedOrigin = 'https://updated-origin.com';
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.fonticon-pencil')[0]);
-        TestUtils.Simulate.change($(originTableEl.getDOMNode()).find('input')[0], {
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.fonticon-pencil')[0]);
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(originTableEl)).find('input')[0], {
           target: {
             value: updatedOrigin
           }
         });
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.btn')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.btn')[0]);
         assert.ok(updateOrigin.calledWith(updatedOrigin));
       });
 
       it('should not update origin on update clicked with bad origin', function () {
         var updatedOrigin = 'updated-origin';
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.fonticon-pencil')[0]);
-        TestUtils.Simulate.change($(originTableEl.getDOMNode()).find('input')[0], {
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.fonticon-pencil')[0]);
+        TestUtils.Simulate.change($(ReactDOM.findDOMNode(originTableEl)).find('input')[0], {
           target: {
             value: updatedOrigin
           }
         });
-        TestUtils.Simulate.click($(originTableEl.getDOMNode()).find('.btn')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(originTableEl)).find('.btn')[0]);
         assert.notOk(updateOrigin.calledOnce);
       });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/databases/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/databases/components.react.jsx b/app/addons/databases/components.react.jsx
index 98e85be..05e4b45 100644
--- a/app/addons/databases/components.react.jsx
+++ b/app/addons/databases/components.react.jsx
@@ -14,13 +14,14 @@ define([
   'app',
   'api',
   'react',
+  'react-dom',
   'addons/components/react-components.react',
   'addons/fauxton/components.react',
   'addons/databases/stores',
   'addons/databases/resources',
   'addons/databases/actions',
   'helpers'
-], function (app, FauxtonAPI, React, Components, ComponentsReact, Stores, Resources, Actions, Helpers) {
+], function (app, FauxtonAPI, React, ReactDOM, Components, ComponentsReact, Stores, Resources, Actions, Helpers) {
 
   var ToggleHeaderButton = Components.ToggleHeaderButton;
   var databasesStore = Stores.databasesStore;
@@ -89,12 +90,14 @@ define([
         <div className="view">
           <table className="databases table table-striped">
             <thead>
-              <th>Name</th>
-              <th>Size</th>
-              <th># of Docs</th>
-              <th>Update Seq</th>
-              {this.getExtensionColumns()}
-              <th>Actions</th>
+              <tr>
+                <th>Name</th>
+                <th>Size</th>
+                <th># of Docs</th>
+                <th>Update Seq</th>
+                {this.getExtensionColumns()}
+                <th>Actions</th>
+              </tr>
             </thead>
             <tbody>
             {rows}
@@ -170,7 +173,7 @@ define([
   var GraveyardInfo = React.createClass({
 
     componentDidMount: function () {
-      $(React.findDOMNode(this.refs.myself)).tooltip();
+      $(ReactDOM.findDOMNode(this.refs.myself)).tooltip();
     },
 
     render: function () {
@@ -204,7 +207,7 @@ define([
 
       this.refs.newDbTray.toggle(function (shown) {
         if (shown) {
-          React.findDOMNode(this.refs.newDbName).focus();
+          ReactDOM.findDOMNode(this.refs.newDbName).focus();
         }
       }.bind(this));
     },
@@ -222,7 +225,7 @@ define([
     },
 
     onAddDatabase: function () {
-      var databaseName = React.findDOMNode(this.refs.newDbName).value;
+      var databaseName = ReactDOM.findDOMNode(this.refs.newDbName).value;
       Actions.createNewDatabase(databaseName);
     },
 
@@ -265,7 +268,7 @@ define([
     },
 
     componentDidUpdate: function () {
-      $(React.findDOMNode(this.refs.searchDbName)).typeahead({
+      $(ReactDOM.findDOMNode(this.refs.searchDbName)).typeahead({
         source: this.state.databaseNames,
         updater: function (item) {
           this.jumpToDb(item);
@@ -282,7 +285,7 @@ define([
     },
 
     jumpToDb: function (databaseName) {
-      databaseName = databaseName || React.findDOMNode(this.refs.searchDbName).value;
+      databaseName = databaseName || ReactDOM.findDOMNode(this.refs.searchDbName).value;
       Actions.jumpToDatabase(databaseName);
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/databases/tests/componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/databases/tests/componentsSpec.react.jsx b/app/addons/databases/tests/componentsSpec.react.jsx
index 2669b46..f57c5c2 100644
--- a/app/addons/databases/tests/componentsSpec.react.jsx
+++ b/app/addons/databases/tests/componentsSpec.react.jsx
@@ -16,8 +16,9 @@ define([
   'addons/databases/actiontypes',
   'addons/databases/stores',
   'testUtils',
-  "react"
-], function (FauxtonAPI, Views, Actions, ActionTypes, Stores, utils, React) {
+  "react",
+  'react-dom'
+], function (FauxtonAPI, Views, Actions, ActionTypes, Stores, utils, React, ReactDOM) {
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -85,12 +86,12 @@ define([
         ];
       };
       container = document.createElement('div');
-      dbEl = React.render(React.createElement(Views.DatabasesController, {}), container);
+      dbEl = ReactDOM.render(React.createElement(Views.DatabasesController, {}), container);
     });
 
     afterEach(function () {
       Stores.databasesStore.getCollection = oldGetCollection;
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('renders base data of DBs', function () {
@@ -118,12 +119,12 @@ define([
         passedDbName = dbName;
       };
       container = document.createElement('div');
-      addEl = React.render(React.createElement(Views.AddDatabaseWidget, {}), container);
+      addEl = ReactDOM.render(React.createElement(Views.AddDatabaseWidget, {}), container);
     });
 
     afterEach(function () {
       Actions.createNewDatabase = oldCreateNewDatabase;
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it("Creates a database with given name", function () {
@@ -160,14 +161,14 @@ define([
         return ["db1", "db2"];
       };
       container = document.createElement('div');
-      jumpEl = React.render(React.createElement(Views.JumpToDatabaseWidget, {}), container);
+      jumpEl = ReactDOM.render(React.createElement(Views.JumpToDatabaseWidget, {}), container);
     });
 
     afterEach(function () {
       $ = old$;
       Actions.jumpToDatabase = oldJumpToDatabase;
       Stores.databasesStore.getDatabaseNames = oldGetDatabaseNames;
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it("Jumps to a database with given name", function () {
@@ -217,14 +218,14 @@ define([
     it('uses custom URL prefix on the navigation if passed through props', function () {
       var container = document.createElement('div');
       var pagination = TestUtils.renderIntoDocument(<Views.DatabasePagination linkPath="_custom_path" />, container);
-      var links = $(pagination.getDOMNode()).find('a');
+      var links = $(ReactDOM.findDOMNode(pagination)).find('a');
 
       assert.equal(links.length, 3, 'pagination contains links');
       links.each(function () {
         assert.include(this.href, '_custom_path', 'link contains custom path');
       });
 
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
   });
 
@@ -236,7 +237,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('adds multiple extra columns if extended', function () {
@@ -255,7 +256,7 @@ define([
       FauxtonAPI.registerExtension('DatabaseTable:head', ColHeader3);
 
       var table = TestUtils.renderIntoDocument(<Views.DatabaseTable loading={false} body={[]} />, container);
-      var cols = $(table.getDOMNode()).find('th');
+      var cols = $(ReactDOM.findDOMNode(table)).find('th');
 
       // (default # of rows is 5)
       assert.equal(cols.length, 8, 'extra columns show up');
@@ -280,7 +281,7 @@ define([
       };
 
       var databaseRow = TestUtils.renderIntoDocument(<Views.DatabaseTable body={[row]} />, container);
-      var links = $(databaseRow.getDOMNode()).find('td');
+      var links = $(ReactDOM.findDOMNode(databaseRow)).find('td');
 
       // (default # of rows is 5)
       assert.equal(links.length, 6, 'extra column shows up');
@@ -301,7 +302,7 @@ define([
       };
 
       var databaseRow = TestUtils.renderIntoDocument(<Views.DatabaseTable body={[row]} />, container);
-      assert.equal($(databaseRow.getDOMNode()).find('.database-load-fail').length, 1);
+      assert.equal($(ReactDOM.findDOMNode(databaseRow)).find('.database-load-fail').length, 1);
     });
 
     it('shows no error if row marked as loaded', function () {
@@ -316,7 +317,7 @@ define([
 
       var databaseRow = TestUtils.renderIntoDocument(<Views.DatabaseTable body={[row]} />, container);
 
-      assert.equal($(databaseRow.getDOMNode()).find('.database-load-fail').length, 0);
+      assert.equal($(ReactDOM.findDOMNode(databaseRow)).find('.database-load-fail').length, 0);
     });
 
   });

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/documents/changes/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/changes/components.react.jsx b/app/addons/documents/changes/components.react.jsx
index 9d8ed98..9ba2b57 100644
--- a/app/addons/documents/changes/components.react.jsx
+++ b/app/addons/documents/changes/components.react.jsx
@@ -14,13 +14,14 @@ define([
   'app',
   'api',
   'react',
+  'react-dom',
   'addons/documents/changes/actions',
   'addons/documents/changes/stores',
   'addons/fauxton/components.react',
   'addons/components/react-components.react',
 
   'plugins/prettify'
-], function (app, FauxtonAPI, React, Actions, Stores, Components, ReactComponents) {
+], function (app, FauxtonAPI, React, ReactDOM, Actions, Stores, Components, ReactComponents) {
 
   var changesStore = Stores.changesStore;
   var ReactCSSTransitionGroup = React.addons.CSSTransitionGroup;
@@ -64,7 +65,8 @@ define([
       return (
         <div className="changes-header-section">
           <ChangesHeaderTab onToggle={this.toggleFilterSection} />
-          <ReactCSSTransitionGroup transitionName="toggle-changes-filter" component="div" className="changes-tab-content">
+          <ReactCSSTransitionGroup transitionName="toggle-changes-filter" component="div" className="changes-tab-content"
+             transitionEnterTimeout={500} transitionLeaveTimeout={300}>
             {tabContent}
           </ReactCSSTransitionGroup>
         </div>
@@ -211,7 +213,7 @@ define([
     },
 
     focusFilterField: function () {
-      React.findDOMNode(this.refs.addItem).focus();
+      ReactDOM.findDOMNode(this.refs.addItem).focus();
     },
 
     onChangeFilter: function (e) {
@@ -248,7 +250,7 @@ define([
   var FilterTooltip = React.createClass({
     componentDidMount: function () {
       if (this.props.tooltip) {
-        $(React.findDOMNode(this.refs.tooltip)).tooltip();
+        $(ReactDOM.findDOMNode(this.refs.tooltip)).tooltip();
       }
     },
 
@@ -383,7 +385,8 @@ define([
               </div>
             </div>
 
-            <ReactCSSTransitionGroup transitionName="toggle-changes-code" component="div" className="changesCodeSectionWrapper">
+            <ReactCSSTransitionGroup transitionName="toggle-changes-code" component="div" className="changesCodeSectionWrapper"
+              transitionEnterTimeout={500} transitionLeaveTimeout={300}>
               {this.getChangesCode()}
             </ReactCSSTransitionGroup>
 
@@ -416,13 +419,13 @@ define([
 
   return {
     renderHeader: function (el) {
-      React.render(<ChangesHeaderController />, el);
+      ReactDOM.render(<ChangesHeaderController />, el);
     },
     renderChanges: function (el) {
-      React.render(<ChangesController />, el);
+      ReactDOM.render(<ChangesController />, el);
     },
     remove: function (el) {
-      React.unmountComponentAtNode(el);
+      ReactDOM.unmountComponentAtNode(el);
     },
 
     ChangesHeaderController: ChangesHeaderController,

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/documents/changes/tests/changes.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/changes/tests/changes.componentsSpec.react.jsx b/app/addons/documents/changes/tests/changes.componentsSpec.react.jsx
index 7a3e444..c5f5e62 100644
--- a/app/addons/documents/changes/tests/changes.componentsSpec.react.jsx
+++ b/app/addons/documents/changes/tests/changes.componentsSpec.react.jsx
@@ -14,11 +14,12 @@ define([
   'app',
   'api',
   'react',
+  'react-dom',
   'addons/documents/changes/components.react',
   'addons/documents/changes/stores',
   'addons/documents/changes/actions',
   'testUtils'
-], function (app, FauxtonAPI, React, Changes, Stores, Actions, utils) {
+], function (app, FauxtonAPI, React, ReactDOM, Changes, Stores, Actions, utils) {
   FauxtonAPI.router = new FauxtonAPI.Router([]);
 
   var assert = utils.assert;
@@ -47,12 +48,12 @@ define([
       afterEach(function () {
         spy.restore();
         Stores.changesStore.reset();
-        React.unmountComponentAtNode(container);
+        ReactDOM.unmountComponentAtNode(container);
       });
 
       // similar as previous, except it confirms that the action gets fired, not the custom toggle func
       it('calls toggleTabVisibility action on selecting a tab', function () {
-        TestUtils.Simulate.click($(tab.getDOMNode()).find('a')[0]);
+        TestUtils.Simulate.click($(ReactDOM.findDOMNode(tab)).find('a')[0]);
         assert.ok(spy.calledOnce);
       });
     });
@@ -69,11 +70,11 @@ define([
 
     afterEach(function () {
       Stores.changesStore.reset();
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('should call toggle function on clicking tab', function () {
-      TestUtils.Simulate.click($(tab.getDOMNode()).find('a')[0]);
+      TestUtils.Simulate.click($(ReactDOM.findDOMNode(tab)).find('a')[0]);
       assert.ok(toggleTabVisibility.calledOnce);
     });
   });
@@ -89,11 +90,11 @@ define([
 
     afterEach(function () {
       Stores.changesStore.reset();
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('should add filter markup', function () {
-      var $el = $(changesFilterEl.getDOMNode()),
+      var $el = $(ReactDOM.findDOMNode(changesFilterEl)),
           submitBtn = $el.find('[type="submit"]')[0],
           addItemField = $el.find('.js-changes-filter-field')[0];
 
@@ -109,7 +110,7 @@ define([
     });
 
     it('should call addFilter action on click', function () {
-      var $el = $(changesFilterEl.getDOMNode()),
+      var $el = $(ReactDOM.findDOMNode(changesFilterEl)),
         submitBtn = $el.find('[type="submit"]')[0],
         addItemField = $el.find('.js-changes-filter-field')[0];
 
@@ -123,7 +124,7 @@ define([
     });
 
     it('should remove filter markup', function () {
-      var $el = $(changesFilterEl.getDOMNode()),
+      var $el = $(ReactDOM.findDOMNode(changesFilterEl)),
         submitBtn = $el.find('[type="submit"]')[0],
         addItemField = $el.find('.js-changes-filter-field')[0];
 
@@ -143,7 +144,7 @@ define([
     });
 
     it('should call removeFilter action on click', function () {
-      var $el = $(changesFilterEl.getDOMNode()),
+      var $el = $(ReactDOM.findDOMNode(changesFilterEl)),
         submitBtn = $el.find('[type="submit"]')[0],
         addItemField = $el.find('.js-changes-filter-field')[0];
 
@@ -158,7 +159,7 @@ define([
     });
 
     it('should not add empty filters', function () {
-      var $el = $(changesFilterEl.getDOMNode()),
+      var $el = $(ReactDOM.findDOMNode(changesFilterEl)),
         submitBtn = $el.find('[type="submit"]')[0],
         addItemField = $el.find('.js-changes-filter-field')[0];
 
@@ -170,11 +171,11 @@ define([
     });
 
     it('should not add tooltips by default', function () {
-      assert.equal(0, $(changesFilterEl.getDOMNode()).find('.js-remove-filter').length);
+      assert.equal(0, $(ReactDOM.findDOMNode(changesFilterEl)).find('.js-remove-filter').length);
     });
 
     it('should not add the same filter twice', function () {
-      var $el = $(changesFilterEl.getDOMNode()),
+      var $el = $(ReactDOM.findDOMNode(changesFilterEl)),
           submitBtn = $el.find('[type="submit"]')[0],
           addItemField = $el.find('.js-changes-filter-field')[0];
 
@@ -213,16 +214,16 @@ define([
       container2 = document.createElement('div');
       Actions.initChanges({ databaseName: 'testDatabase' });
       headerEl  = TestUtils.renderIntoDocument(<Changes.ChangesHeaderController />, container);
-      $headerEl = $(headerEl.getDOMNode());
+      $headerEl = $(ReactDOM.findDOMNode(headerEl));
       changesEl = TestUtils.renderIntoDocument(<Changes.ChangesController />, container2);
-      $changesEl = $(changesEl.getDOMNode());
+      $changesEl = $(ReactDOM.findDOMNode(changesEl));
       Actions.updateChanges(changesResponse);
     });
 
     afterEach(function () {
       Stores.changesStore.reset();
-      React.unmountComponentAtNode(container);
-      React.unmountComponentAtNode(container2);
+      ReactDOM.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container2);
     });
 
 
@@ -320,16 +321,16 @@ define([
 
     afterEach(function () {
       Stores.changesStore.reset();
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('should truncate the number of results with very large # of changes', function () {
       // check there's no more than maxChanges results
-      assert.equal(maxChanges, $(changesEl.getDOMNode()).find('.change-box').length);
+      assert.equal(maxChanges, $(ReactDOM.findDOMNode(changesEl)).find('.change-box').length);
     });
 
     it('should show a message if the results are truncated', function () {
-      assert.equal(1, $(changesEl.getDOMNode()).find('.changes-result-limit').length);
+      assert.equal(1, $(ReactDOM.findDOMNode(changesEl)).find('.changes-result-limit').length);
     });
 
   });
@@ -349,7 +350,7 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
 
@@ -357,23 +358,23 @@ define([
       var changeRow = TestUtils.renderIntoDocument(<Changes.ChangeRow change={change} databaseName="testDatabase" />, container);
 
       // confirm it's hidden by default
-      assert.equal(0, $(changeRow.getDOMNode()).find('.prettyprint').length);
+      assert.equal(0, $(ReactDOM.findDOMNode(changeRow)).find('.prettyprint').length);
 
       // confirm clicking it shows the element
-      TestUtils.Simulate.click($(changeRow.getDOMNode()).find('button.btn')[0]);
-      assert.equal(1, $(changeRow.getDOMNode()).find('.prettyprint').length);
+      TestUtils.Simulate.click($(ReactDOM.findDOMNode(changeRow)).find('button.btn')[0]);
+      assert.equal(1, $(ReactDOM.findDOMNode(changeRow)).find('.prettyprint').length);
     });
 
     it('deleted docs should not be clickable', function () {
       change.deleted = true;
       var changeRow = TestUtils.renderIntoDocument(<Changes.ChangeRow change={change} databaseName="testDatabase" />, container);
-      assert.equal(0, $(changeRow.getDOMNode()).find('a.js-doc-link').length);
+      assert.equal(0, $(ReactDOM.findDOMNode(changeRow)).find('a.js-doc-link').length);
     });
 
     it('non-deleted docs should be clickable', function () {
       change.deleted = false;
       var changeRow = TestUtils.renderIntoDocument(<Changes.ChangeRow change={change} databaseName="testDatabase" />, container);
-      assert.equal(1, $(changeRow.getDOMNode()).find('a.js-doc-link').length);
+      assert.equal(1, $(ReactDOM.findDOMNode(changeRow)).find('a.js-doc-link').length);
     });
   });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/documents/doc-editor/components.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/doc-editor/components.react.jsx b/app/addons/documents/doc-editor/components.react.jsx
index 6e1e051..56ed8d3 100644
--- a/app/addons/documents/doc-editor/components.react.jsx
+++ b/app/addons/documents/doc-editor/components.react.jsx
@@ -2,13 +2,14 @@ define([
   'api',
   'app',
   'react',
+  'react-dom',
   'addons/documents/doc-editor/actions',
   'addons/documents/doc-editor/stores',
   'addons/fauxton/components.react',
   'addons/components/react-components.react',
   'libs/react-bootstrap',
   'helpers'
-], function (FauxtonAPI, app, React, Actions, Stores, FauxtonComponents, GeneralComponents, ReactBootstrap, Helpers) {
+], function (FauxtonAPI, app, React, ReactDOM, Actions, Stores, FauxtonComponents, GeneralComponents, ReactBootstrap, Helpers) {
 
   var store = Stores.docEditorStore;
   var Modal = ReactBootstrap.Modal;
@@ -290,7 +291,7 @@ define([
       Actions.uploadAttachment({
         doc: this.props.doc,
         rev: this.props.doc.get('_rev'),
-        files: $(React.findDOMNode(this.refs.attachments))[0].files
+        files: $(ReactDOM.findDOMNode(this.refs.attachments))[0].files
       });
     },
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
----------------------------------------------------------------------
diff --git a/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx b/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
index cdbc192..124d101 100644
--- a/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
+++ b/app/addons/documents/doc-editor/tests/doc-editor.componentsSpec.react.jsx
@@ -14,6 +14,7 @@ define([
   'app',
   'api',
   'react',
+  'react-dom',
   'addons/documents/resources',
   'addons/documents/doc-editor/components.react',
   'addons/documents/doc-editor/stores',
@@ -22,12 +23,10 @@ define([
   'addons/databases/base',
   'testUtils',
   'libs/react-bootstrap'
-], function (app, FauxtonAPI, React, Documents, Components, Stores, Actions, ActionTypes, Databases, utils,
+], function (app, FauxtonAPI, React, ReactDOM, Documents, Components, Stores, Actions, ActionTypes, Databases, utils,
   ReactBoostrap) {
 
   FauxtonAPI.router = new FauxtonAPI.Router([]);
-  var Modal = ReactBoostrap.Modal;
-
 
   var assert = utils.assert;
   var TestUtils = React.addons.TestUtils;
@@ -71,12 +70,12 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('loading indicator appears on load', function () {
       var el = TestUtils.renderIntoDocument(<Components.DocEditorController />, container);
-      assert.equal($(el.getDOMNode()).find('.loading-lines').length, 1);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.loading-lines').length, 1);
     });
 
     it('new docs do not show the button row', function () {
@@ -90,10 +89,10 @@ define([
         }
       });
 
-      assert.equal($(el.getDOMNode()).find('.loading-lines').length, 0);
-      assert.equal($(el.getDOMNode()).find('.icon-circle-arrow-up').length, 0);
-      assert.equal($(el.getDOMNode()).find('.icon-repeat').length, 0);
-      assert.equal($(el.getDOMNode()).find('.icon-trash').length, 0);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.loading-lines').length, 0);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.icon-circle-arrow-up').length, 0);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.icon-repeat').length, 0);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.icon-trash').length, 0);
     });
 
     it('view attachments button does not appear with no attachments', function () {
@@ -106,7 +105,7 @@ define([
           doc: doc
         }
       });
-      assert.equal($(el.getDOMNode()).find('.view-attachments-section').length, 0);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.view-attachments-section').length, 0);
     });
 
     it('view attachments button shows up when the doc has attachments', function () {
@@ -119,7 +118,7 @@ define([
           doc: doc
         }
       });
-      assert.equal($(el.getDOMNode()).find('.view-attachments-section').length, 1);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.view-attachments-section').length, 1);
     });
 
     it('view attachments dropdown contains right number of docs', function () {
@@ -132,7 +131,7 @@ define([
           doc: doc
         }
       });
-      assert.equal($(el.getDOMNode()).find('.view-attachments-section .dropdown-menu li').length, 2);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.view-attachments-section .dropdown-menu li').length, 2);
     });
 
     it('view attachments dropdown contains correct urls', function () {
@@ -146,13 +145,12 @@ define([
         }
       });
 
-      var attachmentNode = $(el.getDOMNode()).find('.view-attachments-section .dropdown-menu li')[0];
+      var attachmentNode = $(ReactDOM.findDOMNode(el)).find('.view-attachments-section .dropdown-menu li')[0];
       var attachmentURLactual = $(attachmentNode).find('a').attr('href');
 
       assert.equal(attachmentURLactual, "../../id/_design/test-doc/one.png");
     });
 
-
     it('setting deleteDocModal=true in store shows modal', function () {
       var el = TestUtils.renderIntoDocument(<Components.DocEditorController database={database} />, container);
       var doc = new Documents.Doc(docWithAttachmentsJSON, { database: database });
@@ -163,14 +161,14 @@ define([
         }
       });
 
-      // this is unfortunate, but I can't find a better way to do it. Refs won't work for bootstrap modals because
-      // they add the modal to the page at the top level outside the component. There are 3 modals in the
-      // component: the upload modal, clone modal, delete doc modal. We locate it by index
-      var modals = TestUtils.scryRenderedComponentsWithType(el, Modal);
+      // uber-kludgy, but the delete doc modal is a generic dialog used multiple times, so this test first checks
+      // no modal is open, then confirms the open modal contains the delete dialog message
+      assert.equal($('body').find('.confirmation-modal').length, 0);
 
-      assert.equal(React.findDOMNode(modals[2].refs.modal), null);
       Actions.showDeleteDocModal();
-      assert.notEqual(React.findDOMNode(modals[2].refs.modal), null);
+
+      var modalContent = $('body').find('.confirmation-modal .modal-body p')[0];
+      assert.ok(/Are you sure you want to delete this document\?/.test(modalContent.innerHTML));
     });
 
     it('setting uploadDocModal=true in store shows modal', function () {
@@ -182,11 +180,10 @@ define([
           doc: doc
         }
       });
-      var modals = TestUtils.scryRenderedComponentsWithType(el, Modal);
 
-      assert.equal(React.findDOMNode(modals[1].refs.modal), null);
+      assert.equal($('body').find('.upload-file-modal').length, 0);
       Actions.showUploadModal();
-      assert.notEqual(React.findDOMNode(modals[1].refs.modal), null);
+      assert.notEqual($('body').find('.upload-file-modal').length, 0);
     });
   });
 
@@ -200,17 +197,17 @@ define([
     });
 
     afterEach(function () {
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
 
     it('does not show up when loading', function () {
       var el = TestUtils.renderIntoDocument(<Components.AttachmentsPanelButton isLoading={true} doc={doc} />, container);
-      assert.equal($(el.getDOMNode()).find('.panel-button').length, 0);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.panel-button').length, 0);
     });
 
     it('shows up after loading', function () {
       var el = TestUtils.renderIntoDocument(<Components.AttachmentsPanelButton isLoading={false} doc={doc} />, container);
-      assert.equal($(el.getDOMNode()).find('.panel-button').length, 1);
+      assert.equal($(ReactDOM.findDOMNode(el)).find('.panel-button').length, 1);
     });
   });
 
@@ -231,12 +228,12 @@ define([
 
       var container = document.createElement('div');
       var el = TestUtils.renderIntoDocument(<Components.DocEditorController database={database} />, container);
-      assert.isTrue(/Oh\sno\sshe\sdi'n't!/.test(el.getDOMNode().outerHTML));
+      assert.isTrue(/Oh\sno\sshe\sdi'n't!/.test(ReactDOM.findDOMNode(el).outerHTML));
 
       // confirm the database name was also included
-      assert.equal($(el.getDOMNode()).find("#testDatabaseName").html(), database.id);
+      assert.equal($(ReactDOM.findDOMNode(el)).find("#testDatabaseName").html(), database.id);
 
-      React.unmountComponentAtNode(container);
+      ReactDOM.unmountComponentAtNode(container);
     });
   });
 

http://git-wip-us.apache.org/repos/asf/couchdb-fauxton/blob/e6450a0d/app/addons/documents/helpers.js
----------------------------------------------------------------------
diff --git a/app/addons/documents/helpers.js b/app/addons/documents/helpers.js
index 17d774c..81be185 100644
--- a/app/addons/documents/helpers.js
+++ b/app/addons/documents/helpers.js
@@ -16,7 +16,6 @@ define([
 ], function (app, FauxtonAPI) {
 
 
-
   function getPreviousPageForDoc (database, wasCloned) {
     var previousPage = database.url('index'), // default to the current database's all_docs page
         lastPages = FauxtonAPI.router.lastPages;
@@ -81,12 +80,15 @@ define([
     };
   }
 
+  function parseJSON (str) {
+    return JSON.parse('"' + str + '"');   // this ensures newlines are converted
+  }
 
   return {
     getPreviousPageForDoc: getPreviousPageForDoc,
     getPreviousPage: getPreviousPage,
     getSeqNum: getSeqNum,
     getNewButtonLinks: getNewButtonLinks,
-
+    parseJSON: parseJSON
   };
 });