Bug 1419828 - Remove devtools references to React.addons.TestUtils r?nchevobbe draft
authorMichael Ratcliffe <mratcliffe@mozilla.com>
Fri, 24 Nov 2017 18:25:52 +0000
changeset 705039 469cc3f7693f19ed33504362249ebe5da76eba97
parent 705033 40b464eb6b31e66294aba0fd13b8a938f25d573d
child 742238 e00959a23eaf6bb20270b8bfe4b18dd2aa877cbc
push id91335
push userbmo:mratcliffe@mozilla.com
push dateWed, 29 Nov 2017 10:51:56 +0000
reviewersnchevobbe
bugs1419828
milestone59.0a1
Bug 1419828 - Remove devtools references to React.addons.TestUtils r?nchevobbe Changes: - Added testUtils to React DOMs Proxy MonkeyPatch. - Removed TestUtils where it is not needed. - Added syntax identifiers to Markdown fences just because VSCode can do syntax highlighting in the markdown itself when you do that. - In our require-helper.js files I have had to keep the name "react-addons-test-utils." This is because Enzyme uses the require paths to choose which adapters are needed (none are... yet)... we will need to use "react-addons-test-utils" instead of "react-dom/test-utils" as the path until we upgrade to React 16+. MozReview-Commit-ID: H1tgzfp0MXl
devtools/client/netmonitor/test/require-helper.js
devtools/client/responsive.html/test/browser/browser_device_custom.js
devtools/client/responsive.html/test/browser/browser_device_custom_remove.js
devtools/client/responsive.html/test/browser/head.js
devtools/client/shared/components/test/mochitest/head.js
devtools/client/shared/components/test/mochitest/test_tabs_accessibility.html
devtools/client/shared/components/test/mochitest/test_tree_05.html
devtools/client/shared/components/test/mochitest/test_tree_06.html
devtools/client/shared/components/test/mochitest/test_tree_08.html
devtools/client/shared/components/test/mochitest/test_tree_09.html
devtools/client/shared/components/test/mochitest/test_tree_10.html
devtools/client/shared/components/test/mochitest/test_tree_11.html
devtools/client/shared/vendor/REACT_UPGRADING.md
devtools/client/shared/vendor/react-dom-dev.js
devtools/client/shared/vendor/react-dom.js
devtools/client/webconsole/new-console-output/test/helpers.js
devtools/client/webconsole/new-console-output/test/require-helper.js
--- a/devtools/client/netmonitor/test/require-helper.js
+++ b/devtools/client/netmonitor/test/require-helper.js
@@ -7,18 +7,22 @@ const requireHacker = require("require-h
 
 requireHacker.global_hook("default", path => {
   switch (path) {
     // For Enzyme
     case "react-dom":
       return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React`;
     case "react-dom/server":
       return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React`;
+    // TODO: Enzyme uses the require paths to choose which adapters are
+    // needed... we need to use react-addons-test-utils instead of
+    // react-dom/test-utils as the path until we upgrade to React 16+
+    // https://bugzil.la/1416824
     case "react-addons-test-utils":
-      return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React.addons.TestUtils`;
+      return `const ReactDOM = require('devtools/client/shared/vendor/react-dom'); module.exports = ReactDOM.TestUtils`;
     // Use react-dev. This would be handled by browserLoader in Firefox.
     case "react":
     case "devtools/client/shared/vendor/react":
       return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React`;
     // For Rep's use of AMD
     case "devtools/client/shared/vendor/react.default":
       return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React`;
   }
--- a/devtools/client/responsive.html/test/browser/browser_device_custom.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_custom.js
@@ -24,31 +24,29 @@ const unicodeDevice = {
 };
 
 const TEST_URL = "data:text/html;charset=utf-8,";
 const Types = require("devtools/client/responsive.html/types");
 
 addRDMTask(TEST_URL, function* ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
-  let React = toolWindow.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
 
   // Wait until the viewport has been added and the device list has been loaded
   yield waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form, check that defaults match the viewport");
   let adderShow = document.querySelector("#device-adder-show");
-  Simulate.click(adderShow);
+  adderShow.click();
   testDeviceAdder(ui, {
     name: "Custom Device",
     width: 320,
     height: 480,
     pixelRatio: window.devicePixelRatio,
     userAgent: navigator.userAgent,
     touch: false,
   });
@@ -57,97 +55,93 @@ addRDMTask(TEST_URL, function* ({ ui }) 
   yield addDeviceInModal(ui, device);
 
   info("Verify device defaults to enabled in modal");
   let deviceCb = [...document.querySelectorAll(".device-input-checkbox")].find(cb => {
     return cb.value == device.name;
   });
   ok(deviceCb, "Custom device checkbox added to modal");
   ok(deviceCb.checked, "Custom device enabled");
-  Simulate.click(submitButton);
+  submitButton.click();
 
   info("Look for custom device in device selector");
   let selectorOption = [...deviceSelector.options].find(opt => opt.value == device.name);
   ok(selectorOption, "Custom device option added to device selector");
 });
 
 addRDMTask(TEST_URL, function* ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
-  let React = toolWindow.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
 
   // Wait until the viewport has been added and the device list has been loaded
   yield waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   info("Select existing device from the selector");
   yield selectDevice(ui, "Test Device");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form, check that defaults are based on selected device");
   let adderShow = document.querySelector("#device-adder-show");
-  Simulate.click(adderShow);
+  adderShow.click();
   testDeviceAdder(ui, Object.assign({}, device, {
     name: "Test Device (Custom)",
   }));
 
   info("Remove previously added custom device");
   let deviceRemoveButton = document.querySelector(".device-remove-button");
   let removed = Promise.all([
     waitUntilState(store, state => state.devices.custom.length == 0),
     once(ui, "device-association-removed")
   ]);
-  Simulate.click(deviceRemoveButton);
+  deviceRemoveButton.click();
   yield removed;
-  Simulate.click(submitButton);
+  submitButton.click();
 
   info("Ensure custom device was removed from device selector");
   yield waitUntilState(store, state => state.viewports[0].device == "");
   is(deviceSelector.value, "", "Device selector reset to no device");
   let selectorOption = [...deviceSelector.options].find(opt => opt.value == device.name);
   ok(!selectorOption, "Custom device option removed from device selector");
 
   info("Ensure device properties like UA have been reset");
   yield testUserAgent(ui, navigator.userAgent);
 });
 
 addRDMTask(TEST_URL, function* ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
-  let React = toolWindow.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
 
   // Wait until the viewport has been added and the device list has been loaded
   yield waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form");
   let adderShow = document.querySelector("#device-adder-show");
-  Simulate.click(adderShow);
+  adderShow.click();
 
   info("Fill out device adder form by setting details to unicode device and save");
   yield addDeviceInModal(ui, unicodeDevice);
 
   info("Verify unicode device defaults to enabled in modal");
   let deviceCb = [...document.querySelectorAll(".device-input-checkbox")].find(cb => {
     return cb.value == unicodeDevice.name;
   });
   ok(deviceCb, "Custom unicode device checkbox added to modal");
   ok(deviceCb.checked, "Custom unicode device enabled");
-  Simulate.click(submitButton);
+  submitButton.click();
 
   info("Look for custom unicode device in device selector");
   let selectorOption = [...deviceSelector.options].find(opt =>
     opt.value == unicodeDevice.name);
   ok(selectorOption, "Custom unicode device option added to device selector");
 });
 
 addRDMTask(TEST_URL, function* ({ ui }) {
--- a/devtools/client/responsive.html/test/browser/browser_device_custom_remove.js
+++ b/devtools/client/responsive.html/test/browser/browser_device_custom_remove.js
@@ -22,70 +22,68 @@ const device1 = Object.assign({}, device
 
 const device2 = Object.assign({}, device, {
   name: "Test Device 2",
 });
 
 addRDMTask(TEST_URL, function* ({ ui }) {
   let { toolWindow } = ui;
   let { store, document } = toolWindow;
-  let React = toolWindow.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
 
   info("Verify that remove buttons affect the correct device");
 
   // Wait until the viewport has been added and the device list has been loaded
   yield waitUntilState(store, state => state.viewports.length == 1
     && state.devices.listState == Types.deviceListState.LOADED);
 
   let deviceSelector = document.querySelector(".viewport-device-selector");
   let submitButton = document.querySelector("#device-submit-button");
 
   openDeviceModal(ui);
 
   info("Reveal device adder form");
   let adderShow = document.querySelector("#device-adder-show");
-  Simulate.click(adderShow);
+  adderShow.click();
 
   info("Add test device 1");
   yield addDeviceInModal(ui, device1);
 
   info("Reveal device adder form");
   adderShow = document.querySelector("#device-adder-show");
-  Simulate.click(adderShow);
+  adderShow.click();
 
   info("Add test device 2");
   yield addDeviceInModal(ui, device2);
 
   info("Verify all custom devices default to enabled in modal");
   let deviceCbs =
     [...document.querySelectorAll(".device-type-custom .device-input-checkbox")];
   is(deviceCbs.length, 2, "Both devices have a checkbox in modal");
   for (let cb of deviceCbs) {
     ok(cb.checked, "Custom device enabled");
   }
-  Simulate.click(submitButton);
+  submitButton.click();
 
   info("Look for device 1 in device selector");
   let deviceOption1 = [...deviceSelector.options].find(opt => opt.value == device1.name);
   ok(deviceOption1, "Test device 1 option added to device selector");
 
   info("Look for device 2 in device selector");
   let deviceOption2 = [...deviceSelector.options].find(opt => opt.value == device2.name);
   ok(deviceOption2, "Test device 2 option added to device selector");
 
   openDeviceModal(ui);
 
   info("Remove device 2");
   let deviceRemoveButtons = [...document.querySelectorAll(".device-remove-button")];
   is(deviceRemoveButtons.length, 2, "Both devices have a remove button in modal");
   let removed = waitUntilState(store, state => state.devices.custom.length == 1);
-  Simulate.click(deviceRemoveButtons[1]);
+  deviceRemoveButtons[1].click();
   yield removed;
-  Simulate.click(submitButton);
+  submitButton.click();
 
   info("Ensure device 1 is still in device selector");
   deviceOption1 = [...deviceSelector.options].find(opt => opt.value == device1.name);
   ok(deviceOption1, "Test device 1 option exists");
 
   info("Ensure device 2 is no longer in device selector");
   deviceOption2 = [...deviceSelector.options].find(opt => opt.value == device2.name);
   ok(!deviceOption2, "Test device 2 option removed");
--- a/devtools/client/responsive.html/test/browser/head.js
+++ b/devtools/client/responsive.html/test/browser/head.js
@@ -180,18 +180,18 @@ function getElRect(selector, win) {
   return el.getBoundingClientRect();
 }
 
 /**
  * Drag an element identified by 'selector' by [x,y] amount. Returns
  * the rect of the dragged element as it was before drag.
  */
 function dragElementBy(selector, x, y, win) {
-  let React = win.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
+  let ReactDOM = win.require("devtools/client/shared/vendor/react-dom");
+  let { Simulate } = ReactDOM.TestUtils;
   let rect = getElRect(selector, win);
   let startPoint = {
     clientX: Math.floor(rect.left + rect.width / 2),
     clientY: Math.floor(rect.top + rect.height / 2),
   };
   let endPoint = [ startPoint.clientX + x, startPoint.clientY + y ];
 
   let elem = win.document.querySelector(selector);
@@ -217,36 +217,36 @@ function* testViewportResize(ui, selecto
   is(endRect.left - startRect.left, expectedHandleMove[0],
     `The x move of ${selector} is as expected`);
   is(endRect.top - startRect.top, expectedHandleMove[1],
     `The y move of ${selector} is as expected`);
 }
 
 function openDeviceModal({ toolWindow }) {
   let { document } = toolWindow;
-  let React = toolWindow.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
+  let ReactDOM = toolWindow.require("devtools/client/shared/vendor/react-dom");
+  let { Simulate } = ReactDOM.TestUtils;
   let select = document.querySelector(".viewport-device-selector");
   let modal = document.querySelector("#device-modal-wrapper");
 
   info("Checking initial device modal state");
   ok(modal.classList.contains("closed") && !modal.classList.contains("opened"),
     "The device modal is closed by default.");
 
   info("Opening device modal through device selector.");
   select.value = OPEN_DEVICE_MODAL_VALUE;
   Simulate.change(select);
   ok(modal.classList.contains("opened") && !modal.classList.contains("closed"),
     "The device modal is displayed.");
 }
 
 function changeSelectValue({ toolWindow }, selector, value) {
   let { document } = toolWindow;
-  let React = toolWindow.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
+  let ReactDOM = toolWindow.require("devtools/client/shared/vendor/react-dom");
+  let { Simulate } = ReactDOM.TestUtils;
 
   info(`Selecting ${value} in ${selector}.`);
 
   let select = document.querySelector(selector);
   isnot(select, null, `selector "${selector}" should match an existing element.`);
 
   let option = [...select.options].find(o => o.value === String(value));
   isnot(option, undefined, `value "${value}" should match an existing option.`);
@@ -378,20 +378,19 @@ function* testUserAgent(ui, expected) {
   is(ua, expected, `UA should be set to ${expected}`);
 }
 
 /**
  * Assuming the device modal is open and the device adder form is shown, this helper
  * function adds `device` via the form, saves it, and waits for it to appear in the store.
  */
 function addDeviceInModal(ui, device) {
-  let { toolWindow } = ui;
+  let ReactDOM = ui.toolWindow.require("devtools/client/shared/vendor/react-dom");
+  let { Simulate } = ReactDOM.TestUtils;
   let { store, document } = ui.toolWindow;
-  let React = toolWindow.require("devtools/client/shared/vendor/react");
-  let { Simulate } = React.addons.TestUtils;
 
   let nameInput = document.querySelector("#device-adder-name input");
   let [ widthInput, heightInput ] = document.querySelectorAll("#device-adder-size input");
   let pixelRatioInput = document.querySelector("#device-adder-pixel-ratio input");
   let userAgentInput = document.querySelector("#device-adder-user-agent input");
   let touchInput = document.querySelector("#device-adder-touch input");
 
   nameInput.value = device.name;
--- a/devtools/client/shared/components/test/mochitest/head.js
+++ b/devtools/client/shared/components/test/mochitest/head.js
@@ -26,17 +26,17 @@ flags.testing = true;
 var { require: browserRequire } = BrowserLoader({
   baseURI: "resource://devtools/client/shared/",
   window
 });
 
 let React = browserRequire("devtools/client/shared/vendor/react");
 let ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
 let dom = browserRequire("devtools/client/shared/vendor/react-dom-factories");
-var TestUtils = React.addons.TestUtils;
+let TestUtils = ReactDOM.TestUtils;
 
 var EXAMPLE_URL = "http://example.com/browser/browser/devtools/shared/test/";
 
 function forceRender(comp) {
   return setState(comp, {})
     .then(() => setState(comp, {}));
 }
 
--- a/devtools/client/shared/components/test/mochitest/test_tabs_accessibility.html
+++ b/devtools/client/shared/components/test/mochitest/test_tabs_accessibility.html
@@ -14,20 +14,20 @@ Test tabs accessibility.
 </head>
 <body>
 <pre id="test">
 <script src="head.js" type="application/javascript"></script>
 <script type="application/javascript">
 window.onload = Task.async(function* () {
   try {
     const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
-    const React = browserRequire("devtools/client/shared/vendor/react");
-    const { Simulate } = React.addons.TestUtils;
-    const InspectorTabPanel = React.createFactory(browserRequire("devtools/client/inspector/components/InspectorTabPanel"));
-    const Tabbar = React.createFactory(browserRequire("devtools/client/shared/components/tabs/TabBar"));
+    const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
+    const InspectorTabPanel = createFactory(browserRequire("devtools/client/inspector/components/InspectorTabPanel"));
+    const Tabbar =
+      createFactory(browserRequire("devtools/client/shared/components/tabs/TabBar"));
     const tabbar = Tabbar();
     const tabbarReact = ReactDOM.render(tabbar, window.document.body);
     const tabbarEl = ReactDOM.findDOMNode(tabbarReact);
 
     // Setup for InspectorTabPanel
     const tabpanels = document.createElement("div");
     tabpanels.id = "tabpanels";
     document.body.appendChild(tabpanels);
--- a/devtools/client/shared/components/test/mochitest/test_tree_05.html
+++ b/devtools/client/shared/components/test/mochitest/test_tree_05.html
@@ -15,19 +15,18 @@ Test focusing with the Tree component.
 <body>
 <pre id="test">
 <script src="head.js" type="application/javascript"></script>
 <script type="application/javascript">
 
 window.onload = Task.async(function* () {
   try {
     const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
-    const React = browserRequire("devtools/client/shared/vendor/react");
-    const { Simulate } = React.addons.TestUtils;
-    const Tree = React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
+    const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
+    const Tree = createFactory(browserRequire("devtools/client/shared/components/Tree"));
 
     function renderTree(props) {
       const treeProps = Object.assign({},
         TEST_TREE_INTERFACE,
         { onFocus: x => renderTree({ focused: x }) },
         props
       );
       return ReactDOM.render(Tree(treeProps), window.document.body);
@@ -55,17 +54,17 @@ window.onload = Task.async(function* () 
       "-D:false",
       "--J:false",
       "M:false",
       "-N:false",
       "--O:false",
     ], "G should be focused");
 
     // Click the first tree node
-    Simulate.click(document.querySelector(".tree-node"));
+    document.querySelector(".tree-node").click();
     yield forceRender(tree);
 
     isRenderedTree(document.body.textContent, [
       "A:true",
       "-B:false",
       "--E:false",
       "---K:false",
       "---L:false",
--- a/devtools/client/shared/components/test/mochitest/test_tree_06.html
+++ b/devtools/client/shared/components/test/mochitest/test_tree_06.html
@@ -14,19 +14,19 @@ Test keyboard navigation with the Tree c
 </head>
 <body>
 <pre id="test">
 <script src="head.js" type="application/javascript"></script>
 <script type="application/javascript">
 window.onload = Task.async(function* () {
   try {
     const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
-    const React = browserRequire("devtools/client/shared/vendor/react");
-    const { Simulate } = React.addons.TestUtils;
-    const Tree = React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
+    const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
+    const { Simulate } = ReactDOM.TestUtils;
+    const Tree = createFactory(browserRequire("devtools/client/shared/components/Tree"));
 
     function renderTree(props) {
       const treeProps = Object.assign({},
         TEST_TREE_INTERFACE,
         { onFocus: x => renderTree({ focused: x }) },
         props
       );
       return ReactDOM.render(Tree(treeProps), window.document.body);
--- a/devtools/client/shared/components/test/mochitest/test_tree_08.html
+++ b/devtools/client/shared/components/test/mochitest/test_tree_08.html
@@ -16,19 +16,18 @@ other inputs.
 </head>
 <body>
 <pre id="test">
 <script src="head.js" type="application/javascript"></script>
 <script type="application/javascript">
 window.onload = Task.async(function* () {
   try {
     const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
-    const React = browserRequire("devtools/client/shared/vendor/react");
-    const { Simulate } = React.addons.TestUtils;
-    const Tree = React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
+    const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
+    const Tree = createFactory(browserRequire("devtools/client/shared/components/Tree"));
 
     function renderTree(props) {
       const treeProps = Object.assign({},
         TEST_TREE_INTERFACE,
         { onFocus: x => renderTree({ focused: x }) },
         props
       );
       return ReactDOM.render(Tree(treeProps), window.document.body);
@@ -37,17 +36,17 @@ window.onload = Task.async(function* () 
     const tree = renderTree();
 
     const input = document.createElement("input");
     document.body.appendChild(input);
 
     input.focus();
     is(document.activeElement, input, "The text input should be focused.");
 
-    Simulate.click(document.querySelector(".tree-node"));
+    document.querySelector(".tree-node").click();
     yield forceRender(tree);
 
     isnot(document.activeElement, input,
           "The input should have had it's focus stolen by clicking on a tree item.");
   } catch(e) {
     ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
   } finally {
     SimpleTest.finish();
--- a/devtools/client/shared/components/test/mochitest/test_tree_09.html
+++ b/devtools/client/shared/components/test/mochitest/test_tree_09.html
@@ -15,19 +15,19 @@ Test that when an item in the Tree compo
 </head>
 <body>
 <pre id="test">
 <script src="head.js" type="application/javascript"></script>
 <script type="application/javascript">
 window.onload = Task.async(function* () {
   try {
     const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
-    const React = browserRequire("devtools/client/shared/vendor/react");
-    const { Simulate } = React.addons.TestUtils;
-    const Tree = React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
+    const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
+    const { Simulate } = ReactDOM.TestUtils;
+    const Tree = createFactory(browserRequire("devtools/client/shared/components/Tree"));
 
     let numberOfExpands = 0;
     let lastExpandedItem = null;
 
     let numberOfCollapses = 0;
     let lastCollapsedItem = null;
 
     function renderTree(props) {
--- a/devtools/client/shared/components/test/mochitest/test_tree_10.html
+++ b/devtools/client/shared/components/test/mochitest/test_tree_10.html
@@ -15,19 +15,18 @@ Test that when an item in the Tree compo
 </head>
 <body>
 <pre id="test">
 <script src="head.js" type="application/javascript"></script>
 <script type="application/javascript">
 window.onload = Task.async(function* () {
   try {
     const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
-    const React = browserRequire("devtools/client/shared/vendor/react");
-    const { Simulate } = React.addons.TestUtils;
-    const Tree = React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
+    const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
+    const Tree = createFactory(browserRequire("devtools/client/shared/components/Tree"));
 
     function renderTree(props) {
       const treeProps = Object.assign({},
         TEST_TREE_INTERFACE,
         { autoExpandDepth: 1 },
         props
       );
       return ReactDOM.render(Tree(treeProps), window.document.body);
--- a/devtools/client/shared/components/test/mochitest/test_tree_11.html
+++ b/devtools/client/shared/components/test/mochitest/test_tree_11.html
@@ -26,19 +26,19 @@ Test that when an item in the Tree compo
 </head>
 <body>
 <pre id="test">
 <script src="head.js" type="application/javascript"></script>
 <script type="application/javascript">
 window.onload = Task.async(function* () {
   try {
     const ReactDOM = browserRequire("devtools/client/shared/vendor/react-dom");
-    const React = browserRequire("devtools/client/shared/vendor/react");
-    const { Simulate } = React.addons.TestUtils;
-    const Tree = React.createFactory(browserRequire("devtools/client/shared/components/Tree"));
+    const { createFactory } = browserRequire("devtools/client/shared/vendor/react");
+    const { Simulate } = ReactDOM.TestUtils;
+    const Tree = createFactory(browserRequire("devtools/client/shared/components/Tree"));
 
     TEST_TREE.expanded = new Set("ABCDEFGHIJKLMNO".split(""));
 
     function renderTree(props) {
       const treeProps = Object.assign({},
         TEST_TREE_INTERFACE,
         {
           itemHeight: 10,
--- a/devtools/client/shared/vendor/REACT_UPGRADING.md
+++ b/devtools/client/shared/vendor/REACT_UPGRADING.md
@@ -5,113 +5,113 @@
 # Upgrading React
 
 ## Introduction
 
 We use a version of React that has a few minor tweaks. We want to use an un-minified production version anyway, and because of all of this you need to build React yourself to upgrade it for devtools.
 
 ## Getting the Source
 
-```
+```bash
 git clone https://github.com/facebook/react.git
 cd react
 git checkout v15.6.1 # or the version you are targetting
 ```
 
 ## Building
 
-```
+```bash
 npm install
 grunt build
 ```
 
 If you did not receive any errors go to the section entitled "[Patching (XUL Workarounds)](#patching-xul-workarounds)."
 
 If you receive the following error:
 
 > Current npm version is not supported for development,
 > expected "x.x.x." to satisfy "2.x || 3.x || 4.x"
 
 Your npm version is too recent. `"2.x || 3.x || 4.x"` is a hint that the React project only supports npm versions 2.x, 3.x and 4.x. To fix this let's start by removing all of your node versions:
 
-```
+```bash
 # If you use ubuntu
 sudo apt-get remove --purge nodejs
 # If you use homebrew
 brew uninstall node
 # If yu use macports
 sudo port uninstall nodejs
 # If you use nvm
 LINK="https://github.com/creationix/nvm/issues/298"
 xdg-open $LINK || open $LINK
 ```
 
 You will need to setup a node version manager. These instructions cover "n" but many people prefer to use "nvm". If you choose to use nvm them you will need to set it up yourself.
 
 Run the n-install script and it will set "n" it up for you:
 
-```
+```bash
 curl -L -o /tmp/n-install-script https://git.io/n-install
 bash /tmp/n-install-script -y
 exec $SHELL # To re-initialize the PATH variable
 ```
 
 To match node versions with npm versions see:
 <https://nodejs.org/en/download/releases/>
 
 The latest 4.x version of npm is installed with node 7.10.1 so install that version using `sudo n 7.10.1`.
 
 Running `node --version` should now show v7.10.1 and `npm --version` should show 4.2.0.
 
 Now try again:
 
-```
+```bash
 npm install
 grunt build
 ```
 
 ## Patching
 
 ### Patching build/react-with-addons.js
 
 - Open `build/react-with-addons.js`. Search for all `document.createElement` calls and replace them with `document.createElementNS('http://www.w3.org/1999/xhtml', ...)`.
 
   **Note**: some code may be `ownerDocument.createElement` so don't do a blind search/replace. At the time of writing there was only 1 place to change.
 
 - If you are editing the production version then change this:
 
-  ```
+  ```js
   if ("production" !== 'production') {
     exports.getReactPerf = function () {
       return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactPerf;
     };
 
     exports.getReactTestUtils = function () {
       return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactTestUtils;
     };
   }
   ```
 
   To this:
 
-  ```
+  ```js
   if ("production" !== 'production') {
     exports.getReactPerf = function () {
       return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactPerf;
     };
   }
 
   exports.getReactTestUtils = function () {
     return getReactDOM().__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactTestUtils;
   };
   ```
 
 - If you are editing the production version then change this:
 
-  ```
+  ```js
   if ("production" !== 'production') {
     // For the UMD build we get these lazily from the global since they're tied
     // to the DOM renderer and it hasn't loaded yet.
     Object.defineProperty(React.addons, 'Perf', {
       enumerable: true,
       get: function () {
         return ReactAddonsDOMDependencies.getReactPerf();
       }
@@ -121,17 +121,17 @@ grunt build
       get: function () {
         return ReactAddonsDOMDependencies.getReactTestUtils();
       }
     });
   }
   ```
 
   To this:
-  ```
+  ```js
   if ("production" !== 'production') {
     // For the UMD build we get these lazily from the global since they're tied
     // to the DOM renderer and it hasn't loaded yet.
     Object.defineProperty(React.addons, 'Perf', {
       enumerable: true,
       get: function () {
         return ReactAddonsDOMDependencies.getReactPerf();
       }
@@ -151,53 +151,53 @@ grunt build
 - Open `build/react-dom.js` and replace all of the document.createElement calls as you did for `build/react-with-addons.js`.
 
 - Change `require('react')` near the top of the file to `require('devtools/client/shared/vendor/react')`.
 
 - About four lines below that require there is a `define(['react'], f);`. Change this to the full path e.g.`define(['devtools/client/shared/vendor/react'], f);`
 
 - If you are editing the production version then change this:
 
-  ```
+  ```js
   if ("production" !== 'production') {
     ReactDOMUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
       // ReactPerf and ReactTestUtils currently only work with the DOM renderer
       // so we expose them from here, but only in DEV mode.
       ReactPerf: _dereq_(71),
       ReactTestUtils: _dereq_(80)
     };
   }
   ```
 
   Into this:
 
-  ```
+  ```js
   if ("production" !== 'production') {
     ReactDOMUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
       // ReactPerf and ReactTestUtils currently only work with the DOM renderer
       // so we expose them from here, but only in DEV mode.
       ReactPerf: _dereq_(71)
     };
   }
   ReactDOMUMDEntry.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED = {
     ReactTestUtils: _dereq_(80)
   }
   ```
 
 To have React's event system working correctly in certain XUL situations, ReactDOM must be monkey patched with a fix. This fix is currently applied in devtools/client/shared/vendor/react-dom.js. When upgrading, copy and paste the existing block of code into the new file in the same location. It is delimited by a header and footer, and then the monkeyPatchReactDOM() needs to be applied to the returned value.
 
 e.g. Turn this:
 
-```
+```js
 module.exports = ReactDOM;
 ```
 
 Into this:
 
-```
+```js
 //--------------------------------------------------------------------------------------
 // START MONKEY PATCH
 /**
   * This section contains a monkey patch for React DOM, so that it functions correctly in
   * certain XUL situations. React centralizes events to specific DOM nodes by only
   * binding a single listener to the document of the page. It then captures these events,
   * and then uses a SyntheticEvent system to dispatch these throughout the page.
   *
@@ -222,19 +222,26 @@ function monkeyPatchReactDOM(ReactDOM) {
   // Proxied method calls might need to be bound, but do this lazily with caching.
   const lazyFunctionBinding = functionLazyBinder();
 
   // Create a proxy, but the render property is not writable on the ReactDOM object, so
   // a direct proxy will fail with an error. Instead, create a proxy on a a blank object.
   // Pass on getting and setting behaviors.
   return new Proxy({}, {
     get: (target, name) => {
-      return name === "render"
-        ? reactDomRender
-        : lazyFunctionBinding(ReactDOM, name);
+      switch (name) {
+        case "render":
+          return reactDomRender;
+        case "TestUtils":
+          // Bind ReactTestUtils and return it when a request is made for
+          // ReactDOM.TestUtils.
+          let ReactInternals = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+          return lazyFunctionBinding(ReactInternals, "ReactTestUtils");
+      }
+      return lazyFunctionBinding(ReactDOM, name);
     },
     set: (target, name, value) => {
       ReactDOM[name] = value;
       return true;
     }
   });
 };
 
@@ -363,28 +370,28 @@ module.exports = monkeyPatchReactDOM(Rea
 - Change `require('react')` near the top of the file to `require('devtools/client/shared/vendor/react')`.
 
 - About four lines below that require there is a `define(['react'], f);`. Change this to the full path e.g.`define(['devtools/client/shared/vendor/react'], f);`
 
 ### Copy the Files Across
 
 - Now we need to copy `react-with-addons.js`, `react-dom.js` and `react-dom-server.js` into our repo (note the destination filenames all have -dev added e.g. `react-dev.js`, these are part of the dev version):
 
-  ```
+  ```bash
   cp build/react-with-addons.js
      <gecko-dev>/devtools/client/shared/vendor/react-dev.js
   cp build/react-dom.js
      <gecko-dev>/devtools/client/shared/vendor/react-dom-dev.js
   cp build/react-dom-server.js
      <gecko-dev>/devtools/client/shared/vendor/react-dom-server-dev.js
   ```
 
 ### Generate a Production Build
 
-```
+```bash
 NODE_ENV=production grunt build
 
 # Or if using the fish shell:
 
 env NODE_ENV=production grunt build
 ```
 
 ### More Patching
@@ -392,16 +399,16 @@ env NODE_ENV=production grunt build
 Unfortunately, you will need to repeat the following sections **(See note below)**:
 
 - [Patching build/react-with-addons.js](#patching-buildreact-with-addonsjs)
 - [Patching build/react-dom.js](#patching-buildreact-domjs)
 - [Patching build/react-dom-server.js](#patching-buildreact-dom-serverjs)
 
 **NOTE**: This time you need to save the files with their original filenames so the commands in the "Copy the Files Across" section become:
 
-  ```
+  ```bash
   cp build/react-with-addons.js
      <gecko-dev>/devtools/client/shared/vendor/react.js
   cp build/react-dom.js
      <gecko-dev>/devtools/client/shared/vendor/react-dom.js
   cp build/react-dom-server.js
      <gecko-dev>/devtools/client/shared/vendor/react-dom-server.js
   ```
--- a/devtools/client/shared/vendor/react-dom-dev.js
+++ b/devtools/client/shared/vendor/react-dom-dev.js
@@ -5498,19 +5498,26 @@ if ("development" !== 'production') {
     // Proxied method calls might need to be bound, but do this lazily with caching.
     const lazyFunctionBinding = functionLazyBinder();
 
     // Create a proxy, but the render property is not writable on the ReactDOM object, so
     // a direct proxy will fail with an error. Instead, create a proxy on a a blank object.
     // Pass on getting and setting behaviors.
     return new Proxy({}, {
       get: (target, name) => {
-        return name === "render"
-          ? reactDomRender
-          : lazyFunctionBinding(ReactDOM, name);
+        switch (name) {
+          case "render":
+            return reactDomRender;
+          case "TestUtils":
+            // Bind ReactTestUtils and return it when a request is made for
+            // ReactDOM.TestUtils.
+            let ReactInternals = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+            return lazyFunctionBinding(ReactInternals, "ReactTestUtils");
+        }
+        return lazyFunctionBinding(ReactDOM, name);
       },
       set: (target, name, value) => {
         ReactDOM[name] = value;
         return true;
       }
     });
   };
 
--- a/devtools/client/shared/vendor/react-dom.js
+++ b/devtools/client/shared/vendor/react-dom.js
@@ -5498,19 +5498,26 @@ if ("production" !== 'production') {
     // Proxied method calls might need to be bound, but do this lazily with caching.
     const lazyFunctionBinding = functionLazyBinder();
 
     // Create a proxy, but the render property is not writable on the ReactDOM object, so
     // a direct proxy will fail with an error. Instead, create a proxy on a a blank object.
     // Pass on getting and setting behaviors.
     return new Proxy({}, {
       get: (target, name) => {
-        return name === "render"
-          ? reactDomRender
-          : lazyFunctionBinding(ReactDOM, name);
+        switch (name) {
+          case "render":
+            return reactDomRender;
+          case "TestUtils":
+            // Bind ReactTestUtils and return it when a request is made for
+            // ReactDOM.TestUtils.
+            let ReactInternals = ReactDOM.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED;
+            return lazyFunctionBinding(ReactInternals, "ReactTestUtils");
+        }
+        return lazyFunctionBinding(ReactDOM, name);
       },
       set: (target, name, value) => {
         ReactDOM[name] = value;
         return true;
       }
     });
   };
 
--- a/devtools/client/webconsole/new-console-output/test/helpers.js
+++ b/devtools/client/webconsole/new-console-output/test/helpers.js
@@ -2,17 +2,17 @@
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 "use strict";
 
 let ReactDOM = require("devtools/client/shared/vendor/react-dom");
 let React = require("devtools/client/shared/vendor/react");
 const dom = require("devtools/client/shared/vendor/react-dom-factories");
 const { createElement } = React;
-var TestUtils = React.addons.TestUtils;
+const TestUtils = ReactDOM.TestUtils;
 
 const actions = require("devtools/client/webconsole/new-console-output/actions/index");
 const { configureStore } = require("devtools/client/webconsole/new-console-output/store");
 const { IdGenerator } = require("devtools/client/webconsole/new-console-output/utils/id-generator");
 const { stubPackets } = require("devtools/client/webconsole/new-console-output/test/fixtures/stubs/index");
 const {
   getAllMessagesById,
 } = require("devtools/client/webconsole/new-console-output/selectors/messages");
--- a/devtools/client/webconsole/new-console-output/test/require-helper.js
+++ b/devtools/client/webconsole/new-console-output/test/require-helper.js
@@ -6,18 +6,22 @@ const requireHacker = require("require-h
 
 requireHacker.global_hook("default", path => {
   switch (path) {
     // For Enzyme
     case "react-dom":
       return `const ReactDOM = require('devtools/client/shared/vendor/react-dom'); module.exports = ReactDOM`;
     case "react-dom/server":
       return `const ReactDOMServer = require('devtools/client/shared/vendor/react-dom-server'); module.exports = ReactDOMServer`;
+    // TODO: Enzyme uses the require paths to choose which adapters are
+    // needed... we need to use react-addons-test-utils instead of
+    // react-dom/test-utils as the path until we upgrade to React 16+
+    // https://bugzil.la/1416824
     case "react-addons-test-utils":
-      return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React.addons.TestUtils`;
+      return `const ReactDOM = require('devtools/client/shared/vendor/react-dom'); module.exports = ReactDOM.TestUtils`;
     case "react-redux":
       return `const ReactRedux = require('devtools/client/shared/vendor/react-redux'); module.exports = ReactRedux`;
     // Use react-dev. This would be handled by browserLoader in Firefox.
     case "react":
     case "devtools/client/shared/vendor/react":
       return `const React = require('devtools/client/shared/vendor/react-dev'); module.exports = React`;
     // For Rep's use of AMD
     case "devtools/client/shared/vendor/react.default":