Repository: appium/appium (JavaScript)

Issue:
extension resolution potentially broken when APPIUM_HOME is a relative path
I noticed while testing a plugin that when `APPIUM_HOME=../some/relative/path`, resolution of the extension breaks, because the module resolution begins within the `appium` install itself (`extension-config.js`).  

`APPIUM_HOME` must be converted to an absolute path as soon as it's determined.  That would happen in `env.js` of `@appium/support`.


Discussion:

Patch:
diff --git a/packages/support/lib/env.js b/packages/support/lib/env.js
index 695ba9222ab..35b3e53d2e9 100644
--- a/packages/support/lib/env.js
+++ b/packages/support/lib/env.js
@@ -112,6 +112,8 @@ export const readPackageInDir = _.memoize(
  * - If `APPIUM_HOME` is set in the environment, use that
  * - If we have an `extensions.yaml` in {@linkcode DEFAULT_APPIUM_HOME}, then use that.
  * - If we find a `package.json` in or above `cwd` and {@linkcode shouldUseCwdForAppiumHome} returns `true`, then use the directory containing the `package.json`.
+ *
+ * All returned paths will be absolute.
  */
 export const resolveAppiumHome = _.memoize(
   /**
@@ -119,14 +121,14 @@ export const resolveAppiumHome = _.memoize(
    * @returns {Promise<string>}
    */
   async function _resolveAppiumHome(cwd = process.cwd()) {
-    if (process.env.APPIUM_HOME) {
-      return process.env.APPIUM_HOME;
-    }
-
     if (!path.isAbsolute(cwd)) {
       throw new TypeError('`cwd` parameter must be an absolute path');
     }
 
+    if (process.env.APPIUM_HOME) {
+      return path.resolve(cwd, process.env.APPIUM_HOME);
+    }
+
     /** @type {string|undefined} */
     let currentPkgDir;
 
@@ -136,6 +138,10 @@ export const resolveAppiumHome = _.memoize(
       // if we can't find a `package.json`, use the default
       if (!currentPkgDir) {
         return DEFAULT_APPIUM_HOME;
+      } else {
+        // it's unclear from the contract of `pkgDir` whether or not it can return a relative path,
+        // so let's just be defensive.
+        currentPkgDir = path.resolve(cwd, currentPkgDir);
       }
     } catch {
       // unclear if this can actually happen


Test patch:
diff --git a/packages/support/test/unit/env.spec.js b/packages/support/test/unit/env.spec.js
index bbbf4ce92f7..e7e14741d76 100644
--- a/packages/support/test/unit/env.spec.js
+++ b/packages/support/test/unit/env.spec.js
@@ -70,12 +70,25 @@ describe('env', function () {
     });
 
     describe('when APPIUM_HOME is set in env', function () {
-      beforeEach(function () {
-        process.env.APPIUM_HOME = '/some/path/to/appium';
+      describe('when APPIUM_HOME is absolute', function () {
+        beforeEach(function () {
+          process.env.APPIUM_HOME = '/some/path/to/appium-home';
+        });
+
+        it('should resolve APPIUM_HOME from env', async function () {
+          await expect(env.resolveAppiumHome()).to.eventually.equal(process.env.APPIUM_HOME);
+        });
       });
 
-      it('should resolve APPIUM_HOME from env', async function () {
-        await expect(env.resolveAppiumHome()).to.eventually.equal(process.env.APPIUM_HOME);
+      describe('when APPIUM_HOME is relative', function () {
+        beforeEach(function () {
+          process.env.APPIUM_HOME = 'some/path/to/appium-home';
+        });
+        it('should resolve to an absolute path', async function () {
+          await expect(env.resolveAppiumHome()).to.eventually.equal(
+            path.join(process.cwd(), process.env.APPIUM_HOME)
+          );
+        });
       });
     });