Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
push up
  • Loading branch information
Ben.Laskin authored and Ben.Laskin committed Jun 22, 2025
commit dcbce5051b7a254df2089f11b0df338b49126a4e
317 changes: 94 additions & 223 deletions tasks/e2e-installs.sh
Original file line number Diff line number Diff line change
@@ -1,278 +1,149 @@
#!/bin/bash
# Copyright (c) 2015-present, Facebook, Inc.
#
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
# Licensed under the MIT license found in the LICENSE file.

# ******************************************************************************
# This is an end-to-end test intended to run on CI.
# You can also run it locally but it's slow.
# ******************************************************************************
set -euo pipefail
IFS=$'\n\t'

# Start in tasks/ even if run from root directory
cd "$(dirname "$0")"
# ========== Initialization ==========
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
readonly TEMP_APP_PATH="$(mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path')"

# CLI and app temporary locations
# http://unix.stackexchange.com/a/84980
temp_app_path=`mktemp -d 2>/dev/null || mktemp -d -t 'temp_app_path'`

# Load functions for working with local NPM registry (Verdaccio)
cd "$SCRIPT_DIR"
source local-registry.sh

function cleanup {
echo 'Cleaning up.'
cd "$root_path"
rm -rf "$temp_app_path"
# Restore the original NPM and Yarn registry URLs and stop Verdaccio
function cleanup() {
echo "🧹 Cleaning up..."
rm -rf "$TEMP_APP_PATH"
stopLocalRegistry
}

# Error messages are redirected to stderr
function handle_error {
echo "$(basename $0): ERROR! An error was encountered executing line $1." 1>&2;
function on_exit() {
cleanup
echo 'Exiting with error.' 1>&2;
exit 1
echo "🚪 Exiting."
}
trap on_exit EXIT SIGINT SIGTERM ERR

function handle_exit {
cleanup
echo 'Exiting without error.' 1>&2;
exit
}

# Check for the existence of one or more files.
function exists {
for f in $*; do
test -e "$f"
function exists() {
for file in "$@"; do
test -e "$file"
done
}

# Check for accidental dependencies in package.json
function checkDependencies {
if ! awk '/"dependencies": {/{y=1;next}/},/{y=0; next}y' package.json | \
grep -v -q -E '^\s*"(@testing-library\/.+)|web-vitals|(react(-dom|-scripts)?)"'; then
echo "Dependencies are correct"
else
echo "There are extraneous dependencies in package.json"
exit 1
fi
function checkDependencies() {
awk '/"dependencies": {/{y=1;next}/},/{y=0; next}y' package.json |
grep -Ev '^\s*"(@testing-library\/.+|web-vitals|react(-dom|-scripts)?)"' >/dev/null
}

# Check for accidental dependencies in package.json
function checkTypeScriptDependencies {
if ! awk '/"dependencies": {/{y=1;next}/},/{y=0; next}y' package.json | \
grep -v -q -E '^\s*"(@testing-library\/.+)|web-vitals|(@types\/.+)|typescript|(react(-dom|-scripts)?)"'; then
echo "Dependencies are correct"
else
echo "There are extraneous dependencies in package.json"
exit 1
fi
function checkTypeScriptDependencies() {
awk '/"dependencies": {/{y=1;next}/},/{y=0; next}y' package.json |
grep -Ev '^\s*"(@testing-library\/.+|web-vitals|(@types\/.+)|typescript|react(-dom|-scripts)?)"' >/dev/null
}

# Exit the script with a helpful error message when any error is encountered
trap 'set +x; handle_error $LINENO $BASH_COMMAND' ERR

# Cleanup before exit on any termination signal
trap 'set +x; handle_exit' SIGQUIT SIGTERM SIGINT SIGKILL SIGHUP
function createReactAppTest() {
local test_name=$1
local args=$2

# Echo every command being executed
set -x

# Go to root
cd ..
root_path=$PWD
echo "🚀 Running test: $test_name"
local app_path="$TEMP_APP_PATH/$test_name"
cd "$TEMP_APP_PATH"
npx create-react-app "$test_name" $args || true
cd "$app_path"
}

# ******************************************************************************
# First, publish the monorepo.
# ******************************************************************************
function verifyVersionInstalled() {
local version=$1
grep "\"version\": \"$version\"" node_modules/react-scripts*/package.json
}

# Start the local NPM registry
startLocalRegistry "$root_path"/tasks/verdaccio.yaml
function runSmokeTests() {
npm start -- --smoke-test
npm run build
CI=true npm test
}

# Publish the monorepo
# ========== Publish Local Registry ==========
cd "$ROOT_DIR"
startLocalRegistry "$SCRIPT_DIR/verdaccio.yaml"
publishToLocalRegistry

echo "Create React App Version: "
echo "✅ Using Create React App version:"
npx create-react-app --version

# ******************************************************************************
# Test --scripts-version with a distribution tag
# ******************************************************************************
# ========== Tests ==========

cd "$temp_app_path"
npx create-react-app test-app-dist-tag --scripts-version=@latest
cd test-app-dist-tag

# Check corresponding scripts version is installed and no TypeScript or yarn is present by default
exists node_modules/react-scripts
! exists node_modules/typescript
! exists src/index.tsx
! exists yarn.lock
exists src/index.js
# Test: Distribution tag
createReactAppTest test-app-dist-tag "--scripts-version=@latest"
exists node_modules/react-scripts src/index.js
! exists node_modules/typescript src/index.tsx yarn.lock
checkDependencies

# ******************************************************************************
# Test --scripts-version with a version number
# ******************************************************************************

cd "$temp_app_path"
npx create-react-app test-app-version-number --scripts-version=1.0.17
cd test-app-version-number

# Check corresponding scripts version is installed.
exists node_modules/react-scripts
grep '"version": "1.0.17"' node_modules/react-scripts/package.json
# Test: Version number
createReactAppTest test-app-version-number "--scripts-version=1.0.17"
verifyVersionInstalled 1.0.17
checkDependencies

# ******************************************************************************
# Test yarn create
# ******************************************************************************

cd "$temp_app_path"
yarn create react-app test-use-yarn-create --scripts-version=1.0.17
cd test-use-yarn-create

# Check corresponding scripts version is installed.
exists node_modules/react-scripts
# Test: Yarn create
createReactAppTest test-use-yarn-create "--scripts-version=1.0.17"
exists yarn.lock
grep '"version": "1.0.17"' node_modules/react-scripts/package.json
verifyVersionInstalled 1.0.17
checkDependencies

# ******************************************************************************
# Test typescript setup
# ******************************************************************************

cd "$temp_app_path"
npx create-react-app test-app-typescript --template typescript
cd test-app-typescript

# Check corresponding template is installed.
exists node_modules/react-scripts
exists node_modules/typescript
exists src/index.tsx
exists tsconfig.json
exists src/react-app-env.d.ts
# Test: TypeScript template
createReactAppTest test-app-typescript "--template typescript"
exists node_modules/typescript src/index.tsx tsconfig.json src/react-app-env.d.ts
checkTypeScriptDependencies

# Check that the TypeScript template passes smoke tests, build, and normal tests
npm start -- --smoke-test
npm run build
CI=true npm test

# Check eject behaves and works

# Eject...
runSmokeTests
echo yes | npm run eject

# Ensure env file still exists
exists src/react-app-env.d.ts
runSmokeTests

# Check that the TypeScript template passes ejected smoke tests, build, and normal tests
npm start -- --smoke-test
npm run build
CI=true npm test

# ******************************************************************************
# Test --scripts-version with a tarball url
# ******************************************************************************

cd "$temp_app_path"
npx create-react-app test-app-tarball-url --scripts-version=https://registry.npmjs.org/react-scripts/-/react-scripts-1.0.17.tgz
cd test-app-tarball-url

# Check corresponding scripts version is installed.
exists node_modules/react-scripts
grep '"version": "1.0.17"' node_modules/react-scripts/package.json
# Test: Tarball URL
createReactAppTest test-app-tarball-url "--scripts-version=https://registry.npmjs.org/react-scripts/-/react-scripts-1.0.17.tgz"
verifyVersionInstalled 1.0.17
checkDependencies

# ******************************************************************************
# Test --scripts-version with a custom fork of react-scripts
# ******************************************************************************

cd "$temp_app_path"
npx create-react-app test-app-fork --scripts-version=react-scripts-fork
cd test-app-fork

# Check corresponding scripts version is installed.
# Test: Custom fork
createReactAppTest test-app-fork "--scripts-version=react-scripts-fork"
exists node_modules/react-scripts-fork

# ******************************************************************************
# Test project folder is deleted on failing package installation
# ******************************************************************************

cd "$temp_app_path"
# we will install a non-existing package to simulate a failed installation.
npx create-react-app test-app-should-not-exist --scripts-version=`date +%s` || true
# confirm that the project files were deleted
test ! -e test-app-should-not-exist/package.json
test ! -d test-app-should-not-exist/node_modules
# Test: Failing install deletes project folder
cd "$TEMP_APP_PATH"
npx create-react-app test-app-should-not-exist --scripts-version=$(date +%s) || true
! test -e test-app-should-not-exist/package.json
! test -d test-app-should-not-exist/node_modules

# ******************************************************************************
# Test project folder is not deleted when creating app over existing folder
# ******************************************************************************

cd "$temp_app_path"
# Test: Preserve existing folder on failure
mkdir test-app-should-remain
echo '## Hello' > ./test-app-should-remain/README.md
# we will install a non-existing package to simulate a failed installation.
npx create-react-app test-app-should-remain --scripts-version=`date +%s` || true
# confirm the file exist
echo '## Hello' > test-app-should-remain/README.md
npx create-react-app test-app-should-remain --scripts-version=$(date +%s) || true
test -e test-app-should-remain/README.md
# confirm only README.md is the only file in the directory
if [ "$(ls -1 ./test-app-should-remain | wc -l | tr -d '[:space:]')" != "1" ]; then
false
fi

# ******************************************************************************
# Test --scripts-version with a scoped fork tgz of react-scripts
# ******************************************************************************

cd $temp_app_path
curl "https://registry.npmjs.org/@enoah_netzach/react-scripts/-/react-scripts-0.9.0.tgz" -o enoah-scripts-0.9.0.tgz
npx create-react-app test-app-scoped-fork-tgz --scripts-version=$temp_app_path/enoah-scripts-0.9.0.tgz
cd test-app-scoped-fork-tgz
[ "$(ls -1 test-app-should-remain | wc -l)" -eq 1 ]

# Check corresponding scripts version is installed.
# Test: Scoped fork TGZ
cd "$TEMP_APP_PATH"
curl -sSL "https://registry.npmjs.org/@enoah_netzach/react-scripts/-/react-scripts-0.9.0.tgz" -o enoah-scripts-0.9.0.tgz
createReactAppTest test-app-scoped-fork-tgz "--scripts-version=$TEMP_APP_PATH/enoah-scripts-0.9.0.tgz"
exists node_modules/@enoah_netzach/react-scripts

# ******************************************************************************
# Test nested folder path as the project name
# ******************************************************************************

# Testing a path that exists
cd "$temp_app_path"
mkdir test-app-nested-paths-t1
cd test-app-nested-paths-t1
mkdir -p test-app-nested-paths-t1/aa/bb/cc/dd
npx create-react-app test-app-nested-paths-t1/aa/bb/cc/dd
cd test-app-nested-paths-t1/aa/bb/cc/dd
npm start -- --smoke-test

# Testing a path that does not exist
cd "$temp_app_path"
npx create-react-app test-app-nested-paths-t2/aa/bb/cc/dd
cd test-app-nested-paths-t2/aa/bb/cc/dd
npm start -- --smoke-test

# Testing a path that is half exists
cd "$temp_app_path"
mkdir -p test-app-nested-paths-t3/aa
npx create-react-app test-app-nested-paths-t3/aa/bb/cc/dd
cd test-app-nested-paths-t3/aa/bb/cc/dd
npm start -- --smoke-test

# ******************************************************************************
# Test when PnP is enabled
# ******************************************************************************
cd "$temp_app_path"
yarn create react-app test-app-pnp --use-pnp
cd test-app-pnp
# Test: Nested project folder paths
createReactAppTest test-app-nested-paths-t1/aa/bb/cc/dd ""
runSmokeTests
createReactAppTest test-app-nested-paths-t2/aa/bb/cc/dd ""
runSmokeTests
mkdir -p "$TEMP_APP_PATH/test-app-nested-paths-t3/aa"
createReactAppTest test-app-nested-paths-t3/aa/bb/cc/dd ""
runSmokeTests

# Test: Yarn PnP
createReactAppTest test-app-pnp "--use-pnp"
! exists node_modules
exists .pnp.js
# TODO: start and build tasks error with --use-pnp

# TODO: Enable these once PnP supports full smoke testing
# npm start -- --smoke-test
# npm run build

# Cleanup
cleanup
echo "✅ All tests completed."