From d3eca0f3b86ef779620ea5091a64f72c42f1df66 Mon Sep 17 00:00:00 2001 From: hujing Date: Sun, 24 May 2026 13:19:52 +0800 Subject: [PATCH 1/2] Add BATS test setup --- .travis.yml | 8 ++++++++ Makefile | 5 +++++ README.md | 10 ++++++++++ test/node-reinstall.bats | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+) create mode 100644 .travis.yml create mode 100644 test/node-reinstall.bats diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..274ccec --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: bash + +install: + - git clone --depth 1 https://github.com/bats-core/bats-core.git /tmp/bats-core + - export PATH="/tmp/bats-core/bin:$PATH" + +script: + - make test diff --git a/Makefile b/Makefile index 3b5077a..774dc7f 100644 --- a/Makefile +++ b/Makefile @@ -2,12 +2,17 @@ BIN ?= node-reinstall PREFIX ?= /usr/local USAGE ?= $$(./node-reinstall -h | grep "Usage:") +.PHONY: install uninstall test readme + install: cp node-reinstall $(PREFIX)/bin/$(BIN) uninstall: rm -f $(PREFIX)/bin/$(BIN) +test: + bats test + readme: perl -pi -w -e "s/Usage:.*/$(USAGE)/" README.md sed '/Commands/,$$ d' README.md > changes.md diff --git a/README.md b/README.md index 93ebe77..abcb8fb 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,16 @@ With `node-reinstall` in your [$PATH](http://en.wikipedia.org/wiki/PATH_%28varia node-reinstall ``` +## Tests + +Run the BATS test suite with: + +``` +make test +``` + +The tests cover safe command-line paths that exit before any destructive reinstall operations run. + ## Usage diff --git a/test/node-reinstall.bats b/test/node-reinstall.bats new file mode 100644 index 0000000..6b1dceb --- /dev/null +++ b/test/node-reinstall.bats @@ -0,0 +1,35 @@ +#!/usr/bin/env bats + +setup() { + export SCRIPT="$BATS_TEST_DIRNAME/../node-reinstall" +} + +@test "script has valid bash syntax" { + run bash -n "$SCRIPT" + + [ "$status" -eq 0 ] +} + +@test "--help prints usage and exits before privileged operations" { + run "$SCRIPT" --help + + [ "$status" -eq 0 ] + [[ "$output" == *"Usage:"* ]] + [[ "$output" == *"--nvm-latest"* ]] + [[ "$output" != *"sudo"* ]] +} + +@test "-v prints the package version" { + run "$SCRIPT" -v + + [ "$status" -eq 0 ] + [ "$output" = "0.0.17" ] +} + +@test "unknown options fail with usage output" { + run "$SCRIPT" --not-a-real-option + + [ "$status" -eq 1 ] + [[ "$output" == *"Unknown option"* ]] + [[ "$output" == *"Usage:"* ]] +} From f4b609b00d98838f3810df5084a0de6e1e9eebf6 Mon Sep 17 00:00:00 2001 From: hujing Date: Mon, 25 May 2026 09:26:54 +0800 Subject: [PATCH 2/2] Expand BATS coverage --- .github/workflows/test.yml | 20 ++++++++ README.md | 2 +- test/node-reinstall.bats | 98 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 119 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/test.yml diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..a58d400 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,20 @@ +name: Tests + +on: + push: + pull_request: + +jobs: + bats: + strategy: + matrix: + os: [ubuntu-latest, macos-latest] + runs-on: ${{ matrix.os }} + steps: + - uses: actions/checkout@v4 + - name: Install bats-core + run: | + git clone --depth 1 https://github.com/bats-core/bats-core.git /tmp/bats-core + echo "/tmp/bats-core/bin" >> "$GITHUB_PATH" + - name: Run tests + run: make test diff --git a/README.md b/README.md index abcb8fb..211c8ef 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ Run the BATS test suite with: make test ``` -The tests cover safe command-line paths that exit before any destructive reinstall operations run. +The tests cover safe command-line paths that exit before any destructive reinstall operations run, plus stubbed reinstall flows that run against temporary `HOME` and `PREFIX` paths. ## Usage diff --git a/test/node-reinstall.bats b/test/node-reinstall.bats index 6b1dceb..48f5ce9 100644 --- a/test/node-reinstall.bats +++ b/test/node-reinstall.bats @@ -2,6 +2,70 @@ setup() { export SCRIPT="$BATS_TEST_DIRNAME/../node-reinstall" + export TEST_ROOT="$BATS_TEST_TMPDIR/node-reinstall" + export HOME="$TEST_ROOT/home" + export PREFIX="$TEST_ROOT/prefix" + export STUB_BIN="$TEST_ROOT/bin" + export STUB_LOG="$TEST_ROOT/commands.log" + + mkdir -p "$HOME" "$PREFIX/bin" "$STUB_BIN" + export PATH="$STUB_BIN:/usr/bin:/bin:$PREFIX/bin" +} + +make_stub() { + local name="$1" + local body="$2" + + printf '#!/usr/bin/env bash\n%s\n' "$body" > "$STUB_BIN/$name" + chmod +x "$STUB_BIN/$name" +} + +stub_sudo() { + make_stub sudo 'echo "sudo $*" >> "$STUB_LOG"; exit 0' +} + +stub_curl_for_nvm() { + make_stub curl ' +echo "curl $*" >> "$STUB_LOG" +for arg in "$@"; do + if [[ "$arg" == "-o" ]]; then + write_next=1 + continue + fi + if [[ -n "${write_next:-}" ]]; then + printf "%s\n" "#!/usr/bin/env bash" "echo \"nave \$*\" >> \"\$STUB_LOG\"" > "$arg" + chmod +x "$arg" + exit 0 + fi +done +case "$*" in + *releases/latest*) printf "%s\n" "{\"tag_name\":\"v0.40.3\"}" ;; + *) printf "%s\n" "# nvm install script stub" ;; +esac +' +} + +stub_nvm() { + make_stub nvm 'echo "nvm $*" >> "$STUB_LOG"; exit 0' +} + +stub_absent_node() { + make_stub node 'exit 127' +} + +stub_installed_node() { + make_stub node 'printf "%s\n" "v16.20.2"' +} + +stub_npm_with_globals() { + make_stub npm ' +echo "npm $*" >> "$STUB_LOG" +if [[ "$*" == "-g list --depth 0 --parseable" ]]; then + printf "%s\n" "/usr/local/lib" "/usr/local/lib/npm" "/usr/local/lib/eslint" "/usr/local/lib/prettier" + exit 0 +fi +exit 0 +' } @test "script has valid bash syntax" { @@ -33,3 +97,37 @@ setup() { [[ "$output" == *"Unknown option"* ]] [[ "$output" == *"Usage:"* ]] } + +@test "--force --nvm installs the default version when node and npm are absent" { + stub_sudo + stub_curl_for_nvm + stub_nvm + stub_absent_node + + run "$SCRIPT" --force --nvm + + [ "$status" -eq 0 ] + [[ "$output" == *"Installing Node, npm."* ]] + [[ "$output" == *"node-reinstall is done."* ]] + grep -q "sudo -v" "$STUB_LOG" + grep -q "nvm install 5" "$STUB_LOG" + grep -q "nvm alias default 5" "$STUB_LOG" +} + +@test "--force --nave uses the requested node version without prompting" { + stub_sudo + stub_curl_for_nvm + stub_installed_node + stub_npm_with_globals + + run "$SCRIPT" --force --nave 18.20.4 + + [ "$status" -eq 0 ] + [[ "$output" == *"Found Node.js version v16.20.2 already installed."* ]] + [[ "$output" == *"Completely reinstalling Node, npm."* ]] + [[ "$output" == *"Reinstalling your global npm modules:"* ]] + grep -q "sudo -v" "$STUB_LOG" + grep -q "curl .*nave.sh.* -o $PREFIX/bin/nave" "$STUB_LOG" + grep -q "nave usemain 18.20.4" "$STUB_LOG" + grep -q "npm install --global eslint prettier" "$STUB_LOG" +}