diff --git a/package-lock.json b/package-lock.json index 7ab0fa328..02d12b5b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7975,6 +7975,15 @@ "fxparser": "src/cli/cli.js" } }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, "node_modules/fastq": { "version": "1.13.0", "license": "ISC", @@ -18137,6 +18146,7 @@ "bluebird": "3.7.2", "body-parser": "1.20.3", "express": "4.21.2", + "fastest-levenshtein": "1.0.16", "http-status-codes": "2.3.0", "lodash": "4.17.21", "lru-cache": "10.4.3", @@ -19649,6 +19659,7 @@ "bluebird": "3.7.2", "body-parser": "1.20.3", "express": "4.21.2", + "fastest-levenshtein": "1.0.16", "http-status-codes": "2.3.0", "lodash": "4.17.21", "lru-cache": "10.4.3", @@ -25844,6 +25855,11 @@ "strnum": "^1.0.5" } }, + "fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==" + }, "fastq": { "version": "1.13.0", "requires": { diff --git a/packages/base-driver/lib/basedriver/commands/execute.ts b/packages/base-driver/lib/basedriver/commands/execute.ts index e79f19ea3..ab7672455 100644 --- a/packages/base-driver/lib/basedriver/commands/execute.ts +++ b/packages/base-driver/lib/basedriver/commands/execute.ts @@ -10,6 +10,7 @@ import { } from '@appium/types'; import {mixin} from './mixin'; import {BaseDriver} from '../driver'; +import {distance} from 'fastest-levenshtein'; declare module '../driver' { // eslint-disable-next-line @typescript-eslint/no-unused-vars @@ -26,9 +27,33 @@ const ExecuteCommands: IExecuteCommands = { const commandMetadata = {...Driver.executeMethodMap?.[script]}; if (!commandMetadata.command) { const availableScripts = _.keys(Driver.executeMethodMap); + if (_.isEmpty(availableScripts)) { + throw new errors.UnsupportedOperationError( + `Unsupported execute method '${script}'. ` + + `Make sure the installed ${Driver.name} is up-to-date. ` + + `The current driver version does not define any execute methods.` + ); + } + const matchesMap: StringRecord = availableScripts + .map((name) => [distance(script, name), name]) + .reduce((acc, [key, value]) => { + if (key in acc) { + acc[key].push(value); + } else { + acc[key] = [value]; + } + return acc; + }, {}); + const sortedMatches = _.flatten( + _.keys(matchesMap) + .sort((a, b) => parseInt(a, 10) - parseInt(b, 10)) + .map((x) => matchesMap[x]) + ); throw new errors.UnsupportedOperationError( - `Unsupported execute method '${script}'. Available methods ` + - `are: ${availableScripts.join(', ')}` + `Unsupported execute method '${script}', did you mean '${sortedMatches[0]}'? ` + + `Make sure the installed ${Driver.name} is up-to-date. ` + + `Execute methods available in the current driver version are: ` + + sortedMatches.join(', ') ); } const args = validateExecuteMethodParams(protoArgs, commandMetadata.params); diff --git a/packages/base-driver/package.json b/packages/base-driver/package.json index cdd0f714c..d8ad33ed4 100644 --- a/packages/base-driver/package.json +++ b/packages/base-driver/package.json @@ -53,6 +53,7 @@ "bluebird": "3.7.2", "body-parser": "1.20.3", "express": "4.21.2", + "fastest-levenshtein": "1.0.16", "http-status-codes": "2.3.0", "lodash": "4.17.21", "lru-cache": "10.4.3",