diff --git a/bin/JSON.sh b/bin/JSON.sh
new file mode 120000
index 0000000..f3a245b
--- /dev/null
+++ b/bin/JSON.sh
@@ -0,0 +1 @@
+../node_modules/JSON.sh/JSON.sh
\ No newline at end of file
diff --git a/bin/nodenv-package-json b/bin/nodenv-package-json
new file mode 120000
index 0000000..777cd74
--- /dev/null
+++ b/bin/nodenv-package-json
@@ -0,0 +1 @@
+../libexec/nodenv-package-json
\ No newline at end of file
diff --git a/bin/plugin_root b/bin/plugin_root
deleted file mode 100755
index d76a072..0000000
--- a/bin/plugin_root
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/bash
-#
-# Writes the full path to the root of this plugin to standard out.
-# Use to source or run files in libexec/
-#
-# Adapted from:
-# http://www.ostricher.com/2014/10/the-right-way-to-get-the-directory-of-a-bash-script/
-# http://stackoverflow.com/a/12694189/407845
-src="${BASH_SOURCE[0]}"
-
-# while $src is a symlink, resolve it
-while [ -h "$src" ]; do
- dir="${src%/*}"
- src="$( readlink "$src" )"
-
- # If $src was a relative symlink (so no "/" as prefix),
- # need to resolve it relative to the symlink base directory
- [[ $src != /* ]] && src="$dir/$src"
-done
-dir="${src%/*}"
-
-if [ -d "$dir" ]; then
- echo "$dir/.."
-else
- echo "$PWD/.."
-fi
diff --git a/bin/semver.sh b/bin/semver.sh
new file mode 120000
index 0000000..0bde939
--- /dev/null
+++ b/bin/semver.sh
@@ -0,0 +1 @@
+../node_modules/sh-semver/semver.sh
\ No newline at end of file
diff --git a/etc/nodenv.d/version-name/package-json-engine.bash b/etc/nodenv.d/version-name/package-json-engine.bash
index f443ada..a2b09e9 100644
--- a/etc/nodenv.d/version-name/package-json-engine.bash
+++ b/etc/nodenv.d/version-name/package-json-engine.bash
@@ -1,11 +1,10 @@
-#!/bin/bash
-
-# shellcheck source=libexec/nodenv-package-json-engine
-source "$(plugin_root)/libexec/nodenv-package-json-engine"
+if [ -n "$(nodenv-sh-shell 2>/dev/null)" ] ||
+ [ -n "$(nodenv-local 2>/dev/null)" ]; then
+ return
+fi
-if ! NODENV_PACKAGE_JSON_VERSION=$(get_version_respecting_precedence); then
- echo "package-json-engine: version satisfying \`$(get_expression_respecting_precedence)' not installed" >&2
- exit 1
-elif [ -n "$NODENV_PACKAGE_JSON_VERSION" ]; then
- export NODENV_VERSION="${NODENV_PACKAGE_JSON_VERSION}"
+if NODENV_PACKAGE_JSON_VERSION=$(nodenv-package-json 2>/dev/null) &&
+ [ -n "$NODENV_PACKAGE_JSON_VERSION" ]; then
+ # shellcheck disable=2034
+ NODENV_VERSION=$NODENV_PACKAGE_JSON_VERSION
fi
diff --git a/etc/nodenv.d/version-origin/package-json-engine.bash b/etc/nodenv.d/version-origin/package-json-engine.bash
index 97c0afd..3d0cd88 100644
--- a/etc/nodenv.d/version-origin/package-json-engine.bash
+++ b/etc/nodenv.d/version-origin/package-json-engine.bash
@@ -1,9 +1,33 @@
-#!/bin/bash
+if [ -n "$(nodenv-sh-shell 2>/dev/null)" ] ||
+ [ -n "$(nodenv-local 2>/dev/null)" ]; then
+ return
+fi
+
+READLINK=$(type -p greadlink readlink | head -1)
+[ -n "$READLINK" ] || return 1
+
+abs_dirname() {
+ local cwd="$PWD"
+ local path="$1"
+
+ while [ -n "$path" ]; do
+ cd "${path%/*}" || return 1
+ local name="${path##*/}"
+ path="$($READLINK "$name" || true)"
+ done
+
+ pwd
+ cd "$cwd" || return 1
+}
+
+bin_path="$(abs_dirname "${BASH_SOURCE[0]}")/../../../libexec"
-# shellcheck source=libexec/nodenv-package-json-engine
-source "$(plugin_root)/libexec/nodenv-package-json-engine"
+[ -d "$bin_path" ] || return 1
-ENGINES_EXPRESSION=$(get_expression_respecting_precedence);
-if [ -n "$ENGINES_EXPRESSION" ]; then
- export NODENV_VERSION_ORIGIN="package-json-engine matching $ENGINES_EXPRESSION"
+if NODENV_PACKAGE_JSON_VERSION=$(nodenv-package-json 2>/dev/null) &&
+ [ -n "$NODENV_PACKAGE_JSON_VERSION" ]; then
+ NODENV_PACKAGE_JSON_FILE=$("$bin_path/nodenv-package-json-file")
+ NODENV_PACKAGE_JSON_SPEC=$("$bin_path/nodenv-package-json-file-read" "$NODENV_PACKAGE_JSON_FILE")
+ # shellcheck disable=2034
+ NODENV_VERSION_ORIGIN="satisfying \`$NODENV_PACKAGE_JSON_SPEC' from $NODENV_PACKAGE_JSON_FILE#engines.node"
fi
diff --git a/libexec/nodenv-package-json b/libexec/nodenv-package-json
new file mode 100755
index 0000000..ad72c3b
--- /dev/null
+++ b/libexec/nodenv-package-json
@@ -0,0 +1,77 @@
+#!/usr/bin/env bash
+#
+# Usage: nodenv package-json
+# Summary: Show the local application-specific Node version from package.json
+#
+# Shows the highest-installed node version satisfying package.json#engines.
+#
+
+set -e
+[ -n "$NODENV_DEBUG" ] && set -x
+
+abort() {
+ echo "package-json-engine: $1" >&2
+ exit 1
+}
+
+READLINK=$(type -p greadlink readlink | head -1)
+[ -n "$READLINK" ] || abort "cannot find readlink - are you missing GNU coreutils?"
+
+abs_dirname() {
+ local cwd="$PWD"
+ local path="$1"
+
+ while [ -n "$path" ]; do
+ cd "${path%/*}"
+ local name="${path##*/}"
+ path="$($READLINK "$name" || true)"
+ done
+
+ pwd
+ cd "$cwd"
+}
+
+bin_path="$(abs_dirname "$0")"
+
+matching_version() {
+ local version_spec=$1
+ local -a installed_versions
+ while IFS= read -r v; do
+ installed_versions+=( "$v" )
+ done < <(nodenv versions --bare --skip-aliases | grep -e '^[[:digit:]]')
+
+ local fast_guess
+ fast_guess=$(semver.sh -r "$version_spec" "${installed_versions[@]:${#installed_versions[@]}-1}" | tail -n 1)
+
+ # Most #engine version specs just specify a baseline version,
+ # which means most likely, the highest installed version will satisfy
+ # This does a first pass with just that single version in hopes it satisfies.
+ # If so, we can avoid the cost of sh-semver sorting and validating across
+ # all the installed versions.
+ if [ -n "$fast_guess" ]; then
+ echo "$fast_guess"
+ return 0
+ fi
+
+ local match
+ match=$(semver.sh -r "$version_spec" "${installed_versions[@]}" | tail -n 1)
+
+ if [ -n "$match" ]; then
+ echo "$match"
+ else
+ return 1
+ fi
+}
+
+
+if ! NODENV_PACKAGE_JSON_FILE="$("$bin_path/nodenv-package-json-file")"; then
+ abort "no package.json found for this directory"
+fi
+
+if ! version_spec="$("$bin_path/nodenv-package-json-file-read" "$NODENV_PACKAGE_JSON_FILE")"; then
+ abort "no engine version configured for this package"
+fi
+
+if ! matching_version "$version_spec"; then
+ abort "no version found satisfying \`$version_spec'"
+fi
diff --git a/libexec/nodenv-package-json-engine b/libexec/nodenv-package-json-engine
deleted file mode 100755
index 58f8db0..0000000
--- a/libexec/nodenv-package-json-engine
+++ /dev/null
@@ -1,97 +0,0 @@
-#!/bin/bash
-#
-# If a custom Node version is not already defined, we look
-# for a Node version semver expressing in the current tree's package.json.
-# If we find a fixed version, we print it out. If we find a range we
-# test the installed versions against that range and print the
-# greatest matching version.
-
-# Vendored scripts:
-JSON_SH="$(plugin_root)/node_modules/JSON.sh/JSON.sh"
-SEMVER="$(plugin_root)/node_modules/sh-semver/semver.sh"
-
-# Exits non-zero if this plugin should yield precedence
-# Gives precedence to local and shell versions.
-# Takes precedence over global version.
-package_json_has_precedence() {
- if [[ ( -z "$(nodenv local 2>/dev/null)" )
- && ( -z "$(nodenv sh-shell 2>/dev/null)" ) ]]; then
- return;
- else
- return 1;
- fi
-}
-
-find_package_json_path() {
- local package_json root="$1"
- while [ -n "$root" ]; do
- package_json="$root/package.json"
-
- if [ -r "$package_json" ] && [ -f "$package_json" ]; then
- echo "$package_json"
- return
- fi
- root="${root%/*}"
- done
-}
-
-extract_version_from_package_json() {
- package_json_path="$1"
- version_regex='\["engines","node"\][[:space:]]*"([^"]*)"'
- # -b -n gives minimal output - see https://github.com/dominictarr/JSON.sh#options
- [[ $("$JSON_SH" -b -n < "$package_json_path" 2>/dev/null) =~ $version_regex ]]
- echo "${BASH_REMATCH[1]}"
-}
-
-find_installed_version_matching_expression() {
- version_expression="$1"
- local -a installed_versions
- while IFS= read -r v; do
- installed_versions+=( "$v" )
- done < <(nodenv versions --bare --skip-aliases | grep -e '^[[:digit:]]')
-
- local fast_guess
- fast_guess=$("$SEMVER" -r "$version_expression" "${installed_versions[@]:${#installed_versions[@]}-1}" | tail -n 1)
-
- # Most #engine version specs just specify a baseline version,
- # which means most likely, the highest installed version will satisfy
- # This does a first pass with just that single version in hopes it satisfies.
- # If so, we can avoid the cost of sh-semver sorting and validating across
- # all the installed versions.
- if [ -n "$fast_guess" ]; then
- echo "$fast_guess"
- return
- fi
-
- "$SEMVER" -r "$version_expression" "${installed_versions[@]}" | tail -n 1
-}
-
-get_version_respecting_precedence() {
- if ! package_json_has_precedence; then return; fi
-
- package_json_path=$(find_package_json_path "$PWD")
- if [ ! -e "$package_json_path" ]; then return; fi
-
- version_expression=$(
- extract_version_from_package_json "$package_json_path"
- )
- if [ -z "$version_expression" ]; then return; fi
-
- version=$(
- find_installed_version_matching_expression "$version_expression"
- )
- if [ -z "$version" ]; then return 1; fi
- echo "$version"
-}
-
-get_expression_respecting_precedence() {
- if ! package_json_has_precedence; then return; fi
-
- package_json_path=$(find_package_json_path "$PWD")
- if [ ! -e "$package_json_path" ]; then return; fi
-
- version_expression=$(
- extract_version_from_package_json "$package_json_path"
- )
- echo "$version_expression"
-}
diff --git a/libexec/nodenv-package-json-file b/libexec/nodenv-package-json-file
new file mode 100755
index 0000000..2c0e2be
--- /dev/null
+++ b/libexec/nodenv-package-json-file
@@ -0,0 +1,37 @@
+#!/usr/bin/env bash
+#
+# Usage: package-file [
]
+# Summary: Detect the package.json that sets the current nodenv version
+# Options:
+# Directory from which to find package.json
+# [default: ${NODENV_DIR:-PWD}]
+
+set -e
+[ -n "$NODENV_DEBUG" ] && set -x
+
+target_dir="$1"
+
+find_package_json() {
+ local package_json root="$1"
+ while ! [[ "$root" =~ ^//[^/]*$ ]]; do
+ package_json="$root/package.json"
+
+ if [ -f "$package_json" ] &&
+ [ -r "$package_json" ] &&
+ [ -s "$package_json" ]; then
+ echo "$package_json"
+ return 0
+ fi
+ [ -n "$root" ] || break
+ root="${root%/*}"
+ done
+ return 1
+}
+
+if [ -n "$target_dir" ]; then
+ find_package_json "$target_dir"
+else
+ find_package_json "$NODENV_DIR" || {
+ [ "$NODENV_DIR" != "$PWD" ] && find_package_json "$PWD"
+ }
+fi
diff --git a/libexec/nodenv-package-json-file-read b/libexec/nodenv-package-json-file-read
new file mode 100755
index 0000000..ddc39ba
--- /dev/null
+++ b/libexec/nodenv-package-json-file-read
@@ -0,0 +1,26 @@
+#!/usr/bin/env bash
+# Usage: nodenv package-json-file-read
+#
+# Summary: Show the engines version-spec from package.json
+# Options:
+# Package.json file to read from
+#
+
+set -e
+[ -n "$NODENV_DEBUG" ] && set -x
+
+PACKAGE_JSON_FILE=$1
+
+[ -f "$PACKAGE_JSON_FILE" ] || exit 1
+
+extract_expression() {
+ local version_regex='\["engines","node"\][[:space:]]*"([^"]*)"'
+ # -b -n gives minimal output - see https://github.com/dominictarr/JSON.sh#options
+ if [[ $(JSON.sh -b -n 2>/dev/null) =~ $version_regex ]]; then
+ echo "${BASH_REMATCH[1]}"
+ else
+ return 1
+ fi
+}
+
+extract_expression < "$PACKAGE_JSON_FILE"
diff --git a/package.json b/package.json
index de3f77b..5c2aa8a 100644
--- a/package.json
+++ b/package.json
@@ -15,6 +15,7 @@
"bugs": {
"url": "https://github.com/nodenv/nodenv-package-json-engine/issues"
},
+ "bin": "libexec/nodenv-package-json",
"directories": {
"bin": "bin",
"test": "test"
@@ -25,7 +26,7 @@
"libexec"
],
"scripts": {
- "lint": "git ls-files bin etc libexec test/*.bash | xargs shellcheck",
+ "lint": "git ls-files etc libexec test/*.bash | xargs shellcheck",
"test": "bats ${CI:+--tap} test",
"posttest": "npm run lint",
"postversion": "npm publish",
diff --git a/test/nodenv-package-json-engine.bats b/test/nodenv-package-json-engine.bats
deleted file mode 100755
index 47d91d8..0000000
--- a/test/nodenv-package-json-engine.bats
+++ /dev/null
@@ -1,149 +0,0 @@
-#!/usr/bin/env bats
-
-load test_helper
-
-@test 'Recognizes simple node version specified in package.json engines' {
- in_package_for_engine 4.2.1
-
- run nodenv version
- assert_success
- assert_output '4.2.1 (set by package-json-engine matching 4.2.1)'
-}
-
-@test 'Prefers the greatest installed version matching a range' {
- in_package_for_engine '^4.0.0'
-
- run nodenv version
- assert_success
- assert_output '4.2.1 (set by package-json-engine matching ^4.0.0)'
-}
-
-@test 'Ignores non-matching installed versions' {
- in_package_for_engine '^1.0.0'
-
- run nodenv version
- # note the command completes successfully
- assert_success
- assert_output - <<-MSG
-package-json-engine: version satisfying \`^1.0.0' not installed
- (set by package-json-engine matching ^1.0.0)
-MSG
-}
-
-@test 'Prefers nodenv-local over package.json' {
- in_package_for_engine 4.2.1
- nodenv local 5.0.0
-
- run nodenv version
- assert_success
- assert_output "5.0.0 (set by $PWD/.node-version)"
-}
-
-@test 'Prefers nodenv-shell over package.json' {
- in_package_for_engine 4.2.1
-
- NODENV_VERSION=5.0.0 run nodenv version
- assert_success
- assert_output "5.0.0 (set by NODENV_VERSION environment variable)"
-}
-
-@test 'Prefers package.json over nodenv-global' {
- in_package_for_engine 4.2.1
- nodenv global 5.0.0
-
- run nodenv version-name
- assert_success
- assert_output '4.2.1'
-}
-
-@test 'Is not confused by nodenv-shell shadowing nodenv-global' {
- in_package_for_engine 4.2.1
- nodenv global 5.0.0
-
- NODENV_VERSION=5.0.0 run nodenv version
- assert_success
- assert_output "5.0.0 (set by NODENV_VERSION environment variable)"
-}
-
-@test 'Does not match arbitrary "node" key in package.json' {
- in_package_with_babel_env
-
- run nodenv version-name
-
- assert_success
- assert_output 'system'
-}
-
-@test 'Handles missing package.json' {
- in_example_package
-
- run nodenv version-name
-
- assert_success
- assert_output 'system'
-}
-
-@test 'Does not fail with unreadable package.json' {
- in_example_package
- touch package.json
- chmod -r package.json
-
- run nodenv version-name
-
- assert_success
- assert_output 'system'
-}
-
-@test 'Does not fail with non-file package.json' {
- in_example_package
- mkdir package.json
-
- run nodenv version-name
-
- assert_success
- assert_output 'system'
-}
-
-@test 'Does not fail with empty or malformed package.json' {
- in_example_package
-
- # empty
- touch package.json
- run nodenv version-name
- assert_success
- assert_output 'system'
-
- # non json
- echo "foo" > package.json
- run nodenv version-name
- assert_success
- assert_output 'system'
-
- # malformed
- echo "{" > package.json
- run nodenv version-name
- assert_success
- assert_output 'system'
-}
-
-@test 'Handles multiple occurrences of "node" key' {
- in_example_package
- cat << JSON > package.json
-{
- "engines": {
- "node": "4.2.1"
- },
- "presets": [
- ["env", {
- "targets": {
- "node": "current"
- }
- }]
- ]
-}
-JSON
-
- run nodenv version-name
- assert_success
- assert_output '4.2.1'
-}
diff --git a/test/package-json-file-read.bats b/test/package-json-file-read.bats
new file mode 100755
index 0000000..cef6a8e
--- /dev/null
+++ b/test/package-json-file-read.bats
@@ -0,0 +1,78 @@
+#!/usr/bin/env bats
+
+load test_helper
+
+read="$BATS_TEST_DIRNAME/../libexec/nodenv-package-json-file-read"
+
+@test 'Prints the version spec from engines.node' {
+ in_example_package
+ echo '{ "engines": { "node": ">= 8" } }' > package.json
+
+ run $read package.json
+
+ assert_success
+ assert_output '>= 8'
+}
+
+@test 'Does not match arbitrary "node" key in package.json' {
+ in_example_package
+ cat << JSON > package.json
+{
+ "presets": [
+ ["env", {
+ "targets": {
+ "node": "current"
+ }
+ }]
+ ]
+}
+JSON
+
+ run $read package.json
+
+ assert_failure
+ refute_output
+}
+
+@test 'Errors with non-JSON file' {
+ in_example_package
+ echo "foo" > package.json
+
+ run $read package.json
+
+ assert_failure
+ refute_output
+}
+
+@test 'Errors with malformed JSON file' {
+ in_example_package
+ echo "{" > package.json
+
+ run $read package.json
+
+ assert_failure
+ refute_output
+}
+
+@test 'Prints the right "node" key' {
+ in_example_package
+ cat << JSON > package.json
+{
+ "engines": {
+ "node": "4.2.1"
+ },
+ "presets": [
+ ["env", {
+ "targets": {
+ "node": "current"
+ }
+ }]
+ ]
+}
+JSON
+
+ run $read package.json
+
+ assert_success
+ assert_output '4.2.1'
+}
diff --git a/test/package-json-file.bats b/test/package-json-file.bats
new file mode 100755
index 0000000..b215a42
--- /dev/null
+++ b/test/package-json-file.bats
@@ -0,0 +1,86 @@
+#!/usr/bin/env bats
+
+load test_helper
+
+nodenv_package_json_file="$BATS_TEST_DIRNAME/../libexec/nodenv-package-json-file"
+
+@test 'Looks in provided directory' {
+ in_example_package
+ cd ..
+
+ run "$nodenv_package_json_file" "$EXAMPLE_PACKAGE_DIR"
+
+ assert_success
+ assert_output "$EXAMPLE_PACKAGE_DIR/package.json"
+}
+
+@test 'Looks in NODENV_DIR by default' {
+ in_example_package
+ cd ..
+
+ NODENV_DIR="$EXAMPLE_PACKAGE_DIR" run "$nodenv_package_json_file"
+
+ assert_success
+ assert_output "$EXAMPLE_PACKAGE_DIR/package.json"
+}
+
+@test 'Falls back to PWD' {
+ in_example_package
+
+ run "$nodenv_package_json_file"
+
+ assert_success
+ assert_output "$EXAMPLE_PACKAGE_DIR/package.json"
+}
+
+@test 'Works up the directory hierarchy' {
+ in_example_package
+ mkdir -p "sub/dir"
+ cd "sub/dir"
+
+ run "$nodenv_package_json_file"
+
+ assert_success
+ assert_output "$EXAMPLE_PACKAGE_DIR/package.json"
+}
+
+@test 'Exits non-zero when missing package.json' {
+ in_example_package
+ rm package.json
+
+ run "$nodenv_package_json_file"
+
+ assert_failure
+ refute_output
+}
+
+@test 'Treats non-readable same as missing' {
+ in_example_package
+ chmod -r package.json
+
+ run "$nodenv_package_json_file"
+
+ assert_failure
+ refute_output
+}
+
+@test 'Treats non-file same as missing' {
+ in_example_package
+ rm package.json
+ mkdir package.json
+
+ run "$nodenv_package_json_file"
+
+ assert_failure
+ refute_output
+}
+
+@test 'Treats empty same as missing' {
+ in_example_package
+ > package.json
+
+ run "$nodenv_package_json_file"
+
+ assert_failure
+ refute_output
+}
diff --git a/test/package-json.bats b/test/package-json.bats
new file mode 100755
index 0000000..d0d41ec
--- /dev/null
+++ b/test/package-json.bats
@@ -0,0 +1,27 @@
+#!/usr/bin/env bats
+
+load test_helper
+
+@test 'Recognizes simple node version specified in package.json engines' {
+ in_package_for_engine 4.2.1
+
+ run nodenv package-json
+ assert_success
+ assert_output '4.2.1'
+}
+
+@test 'Prefers the greatest installed version matching a range' {
+ in_package_for_engine '^4.0.0'
+
+ run nodenv package-json
+ assert_success
+ assert_output '4.2.1'
+}
+
+@test 'Ignores non-matching installed versions' {
+ in_package_for_engine '^1.0.0'
+
+ run nodenv package-json
+ assert_failure
+ assert_output "package-json-engine: no version found satisfying \`^1.0.0'"
+}
diff --git a/test/test_helper.bash b/test/test_helper.bash
index 474907f..a0bfc1f 100644
--- a/test/test_helper.bash
+++ b/test/test_helper.bash
@@ -5,11 +5,11 @@ load '../node_modules/bats-assert/load'
setup() {
# common nodenv setup
- unset NODENV_VERSION
+ unset NODENV_VERSION NODENV_DIR NODENV_HOOK_PATH
local node_modules_bin=$BATS_TEST_DIRNAME/../node_modules/.bin
- export PATH="$node_modules_bin:/usr/bin:/bin:/usr/sbin:/sbin"
+ export PATH="$BATS_TEST_DIRNAME/../bin:$node_modules_bin:/usr/bin:/bin:/usr/sbin:/sbin"
export NODENV_ROOT="$BATS_TEST_DIRNAME/fixtures/nodenv_root"
@@ -27,6 +27,7 @@ teardown() {
in_example_package() {
cd "$EXAMPLE_PACKAGE_DIR" || return 1
+ echo '{}' > package.json
}
in_package_for_engine() {
@@ -39,18 +40,3 @@ in_package_for_engine() {
}
JSON
}
-
-in_package_with_babel_env() {
- in_example_package
- cat << JSON > package.json
-{
- "presets": [
- ["env", {
- "targets": {
- "node": "current"
- }
- }]
- ]
-}
-JSON
-}
diff --git a/test/version-name-hook.bats b/test/version-name-hook.bats
new file mode 100755
index 0000000..c98c86b
--- /dev/null
+++ b/test/version-name-hook.bats
@@ -0,0 +1,38 @@
+#!/usr/bin/env bats
+
+load test_helper
+
+@test 'Prefers nodenv-shell over package.json' {
+ in_package_for_engine 4.2.1
+
+ NODENV_VERSION=5.0.0 run nodenv version-name
+ assert_success
+ assert_output '5.0.0'
+}
+
+@test 'Prefers nodenv-local over package.json' {
+ in_package_for_engine 4.2.1
+ nodenv local 5.0.0
+
+ run nodenv version-name
+ assert_success
+ assert_output '5.0.0'
+}
+
+@test 'Prefers package.json over nodenv-global' {
+ in_package_for_engine 4.2.1
+ nodenv global 5.0.0
+
+ run nodenv version-name
+ assert_success
+ assert_output '4.2.1'
+}
+
+@test 'Mutes error output from nodenv-package' {
+ in_example_package
+
+ run nodenv version-name
+
+ assert_success
+ assert_output 'system'
+}
diff --git a/test/version-origin-hook.bats b/test/version-origin-hook.bats
new file mode 100755
index 0000000..5fdba2e
--- /dev/null
+++ b/test/version-origin-hook.bats
@@ -0,0 +1,38 @@
+#!/usr/bin/env bats
+
+load test_helper
+
+@test 'Prefers nodenv-shell over package.json' {
+ in_package_for_engine 4.2.1
+
+ NODENV_VERSION=5.0.0 run nodenv version-origin
+ assert_success
+ assert_output 'NODENV_VERSION environment variable'
+}
+
+@test 'Prefers nodenv-local over package.json' {
+ in_package_for_engine 4.2.1
+ nodenv local 5.0.0
+
+ run nodenv version-origin
+ assert_success
+ assert_output "$PWD/.node-version"
+}
+
+@test 'Prefers package.json over nodenv-global' {
+ in_package_for_engine '>= 4'
+ nodenv global 5.0.0
+
+ run nodenv version-origin
+ assert_success
+ assert_output "satisfying \`>= 4' from $PWD/package.json#engines.node"
+}
+
+@test 'Mutes error output from nodenv-package' {
+ in_example_package
+
+ run nodenv version-origin
+
+ assert_success
+ assert_output "$NODENV_ROOT/version"
+}