feat(support): Move module root detection utility into support package
MODIFY
packages/appium/lib/main.js
packages/appium/lib/main.js
@@ -172,7 +172,7 @@ function areServerCommandArgs(args) {
async function init(args) {
const appiumHome = args?.appiumHome ?? (await resolveAppiumHome());
- await adjustNodePath();
+ adjustNodePath();
const {driverConfig, pluginConfig} = await loadExtensions(appiumHome);

MODIFY
packages/appium/lib/utils.js
packages/appium/lib/utils.js
@@ -2,7 +2,7 @@ import _ from 'lodash';
import logger from './logger';
import {processCapabilities, PROTOCOLS} from '@appium/base-driver';
import {inspect as dump} from 'util';
-import {fs} from '@appium/support';
+import {node} from '@appium/support';
import path from 'path';
const W3C_APPIUM_PREFIX = 'appium';
@@ -216,28 +216,14 @@ function getPackageVersion(pkgName) {
* so drivers and plugins could load their peer dependencies.
* Read https://nodejs.org/api/modules.html#loading-from-the-global-folders
* for more details.
- * @returns {Promise<void>}
+ * @returns {void}
*/
-async function adjustNodePath() {
- const pathParts = path.resolve(...(__filename.split(path.sep)))
- .split(path.sep)
- .map((x) => x === '' ? path.sep : x);
- let nodeModulesRoot = null;
- for (let pathItemIdx = pathParts.length - 1; pathItemIdx > 0; --pathItemIdx) {
- const manifestPath = path.join(...(pathParts.slice(0, pathItemIdx)), 'package.json');
- if (!await fs.exists(manifestPath)) {
- continue;
- }
- try {
- if (JSON.parse(await fs.readFile(manifestPath, 'utf8')).name === 'appium') {
- nodeModulesRoot = path.join(...(pathParts.slice(0, pathItemIdx - 1)));
- break;
- }
- } catch (ign) {}
- }
- if (!nodeModulesRoot) {
+function adjustNodePath() {
+ const selfRoot = node.getModuleRootSync('appium', __filename);
+ if (!selfRoot || path.dirname(selfRoot).length >= selfRoot.length) {
return;
}
+ const nodeModulesRoot = path.dirname(selfRoot);
const refreshRequirePaths = () => {
try {

MODIFY
packages/appium/test/unit/utils.spec.js
packages/appium/test/unit/utils.spec.js
@@ -271,7 +271,7 @@ describe('utils', function () {
});
it('should adjust NODE_PATH', async function () {
- await adjustNodePath();
+ adjustNodePath();
(await fs.exists(process.env.NODE_PATH)).should.be.true;
});
});

MODIFY
packages/support/lib/node.js
packages/support/lib/node.js
@@ -3,6 +3,7 @@ import log from './logger';
import _ from 'lodash';
import {exec} from 'teen_process';
import path from 'path';
+import _fs from 'fs';
import {v4 as uuidV4} from 'uuid';
const ECMA_SIZES = Object.freeze({
@@ -200,4 +201,30 @@ function deepFreeze(object) {
return Object.freeze(object);
}
-export {requirePackage, getObjectSize, getObjectId, deepFreeze};
+/**
+ * Tries to synchronously detect the absolute path to the folder
+ * where the given `moduleName` is located.
+ *
+ * @param {string} moduleName The name of the module as it is written in package.json
+ * @param {string} filePath Full path to any of files that `moduleName` contains. Use
+ * `__filename` to find the root of the module where this helper is called.
+ * @returns {string?} Full path to the module root
+ */
+function getModuleRootSync (moduleName, filePath) {
+ let currentDir = path.dirname(path.resolve(filePath));
+ let isAtFsRoot = false;
+ while (!isAtFsRoot) {
+ const manifestPath = path.join(currentDir, 'package.json');
+ try {
+ if (_fs.existsSync(manifestPath) &&
+ JSON.parse(_fs.readFileSync(manifestPath, 'utf8')).name === moduleName) {
+ return currentDir;
+ }
+ } catch (ign) {}
+ currentDir = path.dirname(currentDir);
+ isAtFsRoot = currentDir.length <= path.dirname(currentDir).length;
+ }
+ return null;
+}
+
+export {requirePackage, getObjectSize, getObjectId, deepFreeze, getModuleRootSync};

MODIFY
packages/support/test/unit/node.spec.js
packages/support/test/unit/node.spec.js
import {should} from 'chai';
import {node} from '../../lib';
+import path from 'path';
+import _ from 'lodash';
describe('node utilities', function () {
describe('getObjectSize', function () {
@@ -22,6 +24,16 @@ describe('node utilities', function () {
});
});
+ describe('getModuleRootSync', function () {
+ it('should be able to find current module\'s root', function () {
+ path.resolve(__dirname).should.contain(node.getModuleRootSync('@appium/support', __filename));
+ });
+
+ it('should return null if no root is found', function () {
+ _.isNull(node.getModuleRootSync('yolo', __filename)).should.be.true;
+ });
+ });
+
describe('getObjectId', function () {
it('should be able to calculate object identifiers', function () {
const obj1 = {};

feat(support): Move module root detection utility into support package (#17427)