diff --git a/appveyor.yml b/appveyor.yml
index e00da39436c34befa483e9223488efc2723eb838..ffe48fc85857410c2c307573961a68290dc4b9dd 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -2,11 +2,11 @@ image: Visual Studio 2017
 
 environment:
   matrix:
-    - nodejs_version: 7
+    - nodejs_version: 8
       test_suite: "simple"
-    - nodejs_version: 7
+    - nodejs_version: 8
       test_suite: "installs"
-    - nodejs_version: 7
+    - nodejs_version: 8
       test_suite: "kitchensink"
     - nodejs_version: 6
       test_suite: "simple"
diff --git a/tasks/e2e-kitchensink.sh b/tasks/e2e-kitchensink.sh
index 3d29e8a6f3ca3aed57f32e1179d3b3cd598f00b2..c1167c1dedf53ed4a93895a054d1b3e872d55a64 100755
--- a/tasks/e2e-kitchensink.sh
+++ b/tasks/e2e-kitchensink.sh
@@ -44,6 +44,31 @@ function create_react_app {
   node "$temp_cli_path"/node_modules/create-react-app/index.js "$@"
 }
 
+function install_package {
+  local pkg=$(basename $1)
+
+  # Clean target (for safety)
+  rm -rf node_modules/$pkg/
+  rm -rf node_modules/**/$pkg/
+
+  # Copy package into node_modules/ ignoring installed deps
+  # rsync -a ${1%/} node_modules/ --exclude node_modules
+  cp -R ${1%/} node_modules/
+  rm -rf node_modules/$pkg/node_modules/
+
+  # Install `dependencies`
+  cd node_modules/$pkg/
+  if [ "$USE_YARN" = "yes" ]
+  then
+    yarn install --production
+  else
+    npm install --only=production
+  fi
+  # Remove our packages to ensure side-by-side versions are used (which we link)
+  rm -rf node_modules/{babel-preset-react-app,eslint-config-react-app,react-dev-utils,react-error-overlay,react-scripts}
+  cd ../..
+}
+
 # Check for the existence of one or more files.
 function exists {
   for f in $*; do
@@ -162,13 +187,13 @@ npm install test-integrity@^2.0.1
 cd "$temp_app_path/test-kitchensink"
 
 # Link to our preset
-npm link "$root_path"/packages/babel-preset-react-app
+install_package "$root_path"/packages/babel-preset-react-app
 # Link to error overlay package because now it's a dependency
 # of react-dev-utils and not react-scripts
-npm link "$root_path"/packages/react-error-overlay
+install_package "$root_path"/packages/react-error-overlay
 
 # Link to test module
-npm link "$temp_module_path/node_modules/test-integrity"
+install_package "$temp_module_path/node_modules/test-integrity"
 
 # Test the build
 REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \
@@ -219,23 +244,25 @@ E2E_FILE=./build/index.html \
 # Finally, let's check that everything still works after ejecting.
 # ******************************************************************************
 
-# Unlink our preset
-npm unlink "$root_path"/packages/babel-preset-react-app
-# Unlink error overlay
-npm unlink "$root_path"/packages/react-error-overlay
-
 # Eject...
 echo yes | npm run eject
 
+# Ensure Yarn is ran after eject; at the time of this commit, we don't run Yarn
+# after ejecting. Soon, we may only skip Yarn on Windows. Let's try to remove
+# this in the near future.
+if hash yarnpkg 2>/dev/null
+then
+  yarn install --check-files
+fi
+
 # ...but still link to the local packages
-npm link "$root_path"/packages/babel-preset-react-app
-npm link "$root_path"/packages/eslint-config-react-app
-npm link "$root_path"/packages/react-error-overlay
-npm link "$root_path"/packages/react-dev-utils
-npm link "$root_path"/packages/react-scripts
+install_package "$root_path"/packages/babel-preset-react-app
+install_package "$root_path"/packages/eslint-config-react-app
+install_package "$root_path"/packages/react-error-overlay
+install_package "$root_path"/packages/react-dev-utils
 
 # Link to test module
-npm link "$temp_module_path/node_modules/test-integrity"
+install_package "$temp_module_path/node_modules/test-integrity"
 
 # Test the build
 REACT_APP_SHELL_ENV_MESSAGE=fromtheshell \
diff --git a/tasks/e2e-simple.sh b/tasks/e2e-simple.sh
index 2c9709546a04689464a7b1174ee8695bd9577373..867b6dc95030298858167a7c10f69a9b31e5e33b 100755
--- a/tasks/e2e-simple.sh
+++ b/tasks/e2e-simple.sh
@@ -43,6 +43,31 @@ function create_react_app {
   node "$temp_cli_path"/node_modules/create-react-app/index.js "$@"
 }
 
+function install_package {
+  local pkg=$(basename $1)
+
+  # Clean target (for safety)
+  rm -rf node_modules/$pkg/
+  rm -rf node_modules/**/$pkg/
+
+  # Copy package into node_modules/ ignoring installed deps
+  # rsync -a ${1%/} node_modules/ --exclude node_modules
+  cp -R ${1%/} node_modules/
+  rm -rf node_modules/$pkg/node_modules/
+
+  # Install `dependencies`
+  cd node_modules/$pkg/
+  if [ "$USE_YARN" = "yes" ]
+  then
+    yarn install --production
+  else
+    npm install --only=production
+  fi
+  # Remove our packages to ensure side-by-side versions are used (which we link)
+  rm -rf node_modules/{babel-preset-react-app,eslint-config-react-app,react-dev-utils,react-error-overlay,react-scripts}
+  cd ../..
+}
+
 # Check for the existence of one or more files.
 function exists {
   for f in $*; do
@@ -306,11 +331,18 @@ verify_module_scope
 # Eject...
 echo yes | npm run eject
 
+# Ensure Yarn is ran after eject; at the time of this commit, we don't run Yarn
+# after ejecting. Soon, we may only skip Yarn on Windows. Let's try to remove
+# this in the near future.
+if hash yarnpkg 2>/dev/null
+then
+  yarnpkg install --check-files
+fi
+
 # ...but still link to the local packages
-npm link "$root_path"/packages/babel-preset-react-app
-npm link "$root_path"/packages/eslint-config-react-app
-npm link "$root_path"/packages/react-dev-utils
-npm link "$root_path"/packages/react-scripts
+install_package "$root_path"/packages/babel-preset-react-app
+install_package "$root_path"/packages/eslint-config-react-app
+install_package "$root_path"/packages/react-dev-utils
 
 # Test the build
 npm run build