gpt-driver-node 1.0.1 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +55 -90
- package/dist/index.d.cts +38 -31
- package/dist/index.mjs +55 -90
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -160,6 +160,14 @@ const SavableTestStoreSchema = zod.z.object({
|
|
|
160
160
|
steps: zod.z.array(SavableStepSchema),
|
|
161
161
|
params: zod.z.record(zod.z.string(), zod.z.string()).optional()
|
|
162
162
|
});
|
|
163
|
+
const VariablesSchema = zod.z.record(zod.z.string(), zod.z.string()).optional().default({});
|
|
164
|
+
const ConfigSchema = zod.z.object({
|
|
165
|
+
testDir: zod.z.string(),
|
|
166
|
+
driver: zod.z.string(),
|
|
167
|
+
port: zod.z.number(),
|
|
168
|
+
apiKey: zod.z.string(),
|
|
169
|
+
variables: VariablesSchema
|
|
170
|
+
});
|
|
163
171
|
|
|
164
172
|
const CACHE_SERVER_URL = "https://cache.mobileboost.io";
|
|
165
173
|
const GPT_DRIVER_BASE_URL = "https://api.mobileboost.io";
|
|
@@ -604,7 +612,6 @@ class GptDriver {
|
|
|
604
612
|
});
|
|
605
613
|
}
|
|
606
614
|
apiKey;
|
|
607
|
-
organisationId;
|
|
608
615
|
gptDriverSessionId;
|
|
609
616
|
gptDriverBaseUrl;
|
|
610
617
|
appiumSessionConfig;
|
|
@@ -616,6 +623,8 @@ class GptDriver {
|
|
|
616
623
|
buildId;
|
|
617
624
|
testId;
|
|
618
625
|
step_number = 1;
|
|
626
|
+
organisationId;
|
|
627
|
+
configFilePath;
|
|
619
628
|
// Smart loop state - maintains action history across steps for context
|
|
620
629
|
globalActionHistory = [];
|
|
621
630
|
/**
|
|
@@ -640,11 +649,12 @@ class GptDriver {
|
|
|
640
649
|
constructor(config) {
|
|
641
650
|
this.testId = config.testId;
|
|
642
651
|
this.apiKey = config.apiKey;
|
|
643
|
-
this.organisationId = config.organisationId;
|
|
644
652
|
this.buildId = config.buildId;
|
|
645
653
|
this.useGptDriverCloud = config.useGptDriverCloud;
|
|
646
654
|
this.gptDriverBaseUrl = GPT_DRIVER_BASE_URL;
|
|
647
655
|
this.cachingMode = config.cachingMode ?? "NONE";
|
|
656
|
+
this.organisationId = config.organisationId;
|
|
657
|
+
this.configFilePath = config.configFilePath;
|
|
648
658
|
if (config.useGptDriverCloud) {
|
|
649
659
|
if (config.serverConfig.device?.platform == null) {
|
|
650
660
|
throw new Error("Platform is missing. Please specify the platform when using GPTDriver Cloud.");
|
|
@@ -1005,86 +1015,12 @@ class GptDriver {
|
|
|
1005
1015
|
await this.gptHandler(command);
|
|
1006
1016
|
}
|
|
1007
1017
|
}
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
* If an `appiumHandler` is provided, it will be invoked with the WebDriver instance to perform
|
|
1015
|
-
* the command-specific operations. After executing the handler, the executed commands get logged
|
|
1016
|
-
* on the GPTDriver servers. If the handler execution fails or no handler is provided, the command
|
|
1017
|
-
* gets executed by the GPTDriver using natural language processing.
|
|
1018
|
-
*
|
|
1019
|
-
* @param {Object} params - The execution parameters
|
|
1020
|
-
* @param {string} params.command - The natural language command to be executed by the GPTDriver.
|
|
1021
|
-
* Examples: "Click the login button", "Enter 'test@example.com' in the email field"
|
|
1022
|
-
* @param {AppiumHandler} [params.appiumHandler] - An optional function that processes Appium-specific commands.
|
|
1023
|
-
* If provided, this handler is executed instead of calling
|
|
1024
|
-
* the GPTDriver API. Useful for performance optimization when
|
|
1025
|
-
* you know the exact Appium commands to execute.
|
|
1026
|
-
* @param {CachingMode} [params.cachingMode] - Controls how the GPTDriver caches this command execution.
|
|
1027
|
-
* If not specified, uses the global caching mode set in the constructor.
|
|
1028
|
-
* Options:
|
|
1029
|
-
* - "NONE"
|
|
1030
|
-
* - "FULL_SCREEN"
|
|
1031
|
-
* - "INTERACTION_REGION"
|
|
1032
|
-
* @param {boolean} [params.useSmartLoop] - If true, uses the smart loop execution (Cache -> AI -> Execute -> Populate)
|
|
1033
|
-
* which optimizes execution by checking cache first and populating it after.
|
|
1034
|
-
* Default: false (uses legacy gptHandler)
|
|
1035
|
-
*
|
|
1036
|
-
* @returns {Promise<void>} A promise that resolves when the command execution is complete.
|
|
1037
|
-
*
|
|
1038
|
-
* @throws {Error} If an error occurs during the execution of the Appium handler or while processing
|
|
1039
|
-
* the command by the GPTDriver.
|
|
1040
|
-
*
|
|
1041
|
-
* @example
|
|
1042
|
-
* // Basic usage with natural language (no caching)
|
|
1043
|
-
* await driver.aiExecute({
|
|
1044
|
-
* command: "Click the submit button"
|
|
1045
|
-
* });
|
|
1046
|
-
*
|
|
1047
|
-
* @example
|
|
1048
|
-
* // Full screen caching for repetitive navigation on similar screens
|
|
1049
|
-
* await driver.aiExecute({
|
|
1050
|
-
* command: "Navigate to the settings page",
|
|
1051
|
-
* cachingMode: "FULL_SCREEN"
|
|
1052
|
-
* });
|
|
1053
|
-
*
|
|
1054
|
-
* @example
|
|
1055
|
-
* // Interaction region caching for repeated actions on the same button
|
|
1056
|
-
* await driver.aiExecute({
|
|
1057
|
-
* command: "Click the login button",
|
|
1058
|
-
* cachingMode: "INTERACTION_REGION"
|
|
1059
|
-
* });
|
|
1060
|
-
*
|
|
1061
|
-
* @example
|
|
1062
|
-
* // With custom Appium handler as fallback
|
|
1063
|
-
* await driver.aiExecute({
|
|
1064
|
-
* command: "Click the login button",
|
|
1065
|
-
* appiumHandler: async (driver) => {
|
|
1066
|
-
* const loginBtn = await driver.$('~loginButton');
|
|
1067
|
-
* await loginBtn.click();
|
|
1068
|
-
* },
|
|
1069
|
-
* cachingMode: "INTERACTION_REGION"
|
|
1070
|
-
* });
|
|
1071
|
-
*
|
|
1072
|
-
* @example
|
|
1073
|
-
* // Force fresh execution for dynamic content
|
|
1074
|
-
* await driver.aiExecute({
|
|
1075
|
-
* command: "Verify the current timestamp",
|
|
1076
|
-
* cachingMode: "NONE"
|
|
1077
|
-
* });
|
|
1078
|
-
*
|
|
1079
|
-
* @example
|
|
1080
|
-
* // Using smart loop for optimized caching
|
|
1081
|
-
* await driver.aiExecute({
|
|
1082
|
-
* command: "Click the login button",
|
|
1083
|
-
* useSmartLoop: true,
|
|
1084
|
-
* cachingMode: "FULL_SCREEN"
|
|
1085
|
-
* });
|
|
1086
|
-
*/
|
|
1087
|
-
async aiExecute({ command, appiumHandler, cachingMode, useSmartLoop = false }) {
|
|
1018
|
+
async aiExecute(commandOrOptions, options) {
|
|
1019
|
+
const command = typeof commandOrOptions === "string" ? commandOrOptions : commandOrOptions.command;
|
|
1020
|
+
const opts = typeof commandOrOptions === "string" ? options : commandOrOptions;
|
|
1021
|
+
const appiumHandler = opts?.appiumHandler;
|
|
1022
|
+
const cachingMode = opts?.cachingMode;
|
|
1023
|
+
const useSmartLoop = opts?.useSmartLoop ?? false;
|
|
1088
1024
|
if (!this.appiumSessionStarted) {
|
|
1089
1025
|
await this.startSession();
|
|
1090
1026
|
}
|
|
@@ -1337,9 +1273,42 @@ class GptDriver {
|
|
|
1337
1273
|
*/
|
|
1338
1274
|
async executeFlow(filePath, options) {
|
|
1339
1275
|
const useSmartLoop = options?.useSmartLoop ?? false;
|
|
1276
|
+
const configFilePath = this.configFilePath;
|
|
1277
|
+
let baseDir;
|
|
1278
|
+
let absolutePath;
|
|
1279
|
+
if (configFilePath) {
|
|
1280
|
+
let raw2;
|
|
1281
|
+
try {
|
|
1282
|
+
raw2 = await node_fs.promises.readFile(configFilePath, "utf-8");
|
|
1283
|
+
} catch (e) {
|
|
1284
|
+
const msg = `Failed to read file at ${configFilePath}: ${e?.message ?? e}`;
|
|
1285
|
+
globalLogger.error(msg);
|
|
1286
|
+
throw new Error(msg);
|
|
1287
|
+
}
|
|
1288
|
+
let json2;
|
|
1289
|
+
try {
|
|
1290
|
+
json2 = JSON.parse(raw2);
|
|
1291
|
+
} catch (e) {
|
|
1292
|
+
const msg = `Invalid JSON in flow file ${configFilePath}: ${e?.message ?? e}`;
|
|
1293
|
+
globalLogger.error(msg);
|
|
1294
|
+
throw new Error(msg);
|
|
1295
|
+
}
|
|
1296
|
+
const parsedConfigFile = ConfigSchema.parse(json2);
|
|
1297
|
+
if (path.isAbsolute(parsedConfigFile.testDir)) {
|
|
1298
|
+
baseDir = parsedConfigFile.testDir;
|
|
1299
|
+
} else {
|
|
1300
|
+
baseDir = path.resolve(path.dirname(configFilePath), parsedConfigFile.testDir);
|
|
1301
|
+
}
|
|
1302
|
+
absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(baseDir, filePath);
|
|
1303
|
+
} else {
|
|
1304
|
+
if (useSmartLoop) {
|
|
1305
|
+
throw new Error("Config file is required when using SmartLoop, please provide the path in the constructor");
|
|
1306
|
+
} else {
|
|
1307
|
+
absolutePath = path.resolve(filePath);
|
|
1308
|
+
baseDir = path.dirname(absolutePath);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1340
1311
|
globalLogger.info(`Loading flow from file: ${filePath}`);
|
|
1341
|
-
const absolutePath = path.resolve(filePath);
|
|
1342
|
-
const baseDir = path.dirname(absolutePath);
|
|
1343
1312
|
let raw;
|
|
1344
1313
|
try {
|
|
1345
1314
|
raw = await node_fs.promises.readFile(absolutePath, "utf-8");
|
|
@@ -1578,10 +1547,7 @@ ${issues}`);
|
|
|
1578
1547
|
for (const appiumCommand of executeResponse.commands) {
|
|
1579
1548
|
await this.executeCommand(appiumCommand);
|
|
1580
1549
|
}
|
|
1581
|
-
|
|
1582
|
-
globalLogger.debug("Command still in progress, waiting...");
|
|
1583
|
-
await delay(1500);
|
|
1584
|
-
}
|
|
1550
|
+
await delay(1500);
|
|
1585
1551
|
}
|
|
1586
1552
|
this.step_number = this.step_number + 1;
|
|
1587
1553
|
globalLogger.info("Command execution completed successfully");
|
|
@@ -1594,8 +1560,7 @@ ${issues}`);
|
|
|
1594
1560
|
async executeCommand(command) {
|
|
1595
1561
|
const firstAction = command.data?.actions?.at(0);
|
|
1596
1562
|
if (firstAction?.type === "pause" && firstAction.duration != null) {
|
|
1597
|
-
|
|
1598
|
-
await delay(firstAction * 1e3);
|
|
1563
|
+
await delay(firstAction.duration * 1e3);
|
|
1599
1564
|
} else if (!this.useGptDriverCloud) {
|
|
1600
1565
|
const parsedUrl = new URL(command.url);
|
|
1601
1566
|
parsedUrl.protocol = this.appiumSessionConfig.serverUrl.protocol;
|
package/dist/index.d.cts
CHANGED
|
@@ -14,7 +14,6 @@ interface ServerSessionInitConfig {
|
|
|
14
14
|
interface GptDriverConfig {
|
|
15
15
|
testId?: string;
|
|
16
16
|
apiKey: string;
|
|
17
|
-
organisationId?: string;
|
|
18
17
|
driver?: WebDriver | Browser;
|
|
19
18
|
serverConfig: {
|
|
20
19
|
device?: ServerSessionInitConfig;
|
|
@@ -23,6 +22,8 @@ interface GptDriverConfig {
|
|
|
23
22
|
useGptDriverCloud?: boolean;
|
|
24
23
|
buildId?: string;
|
|
25
24
|
cachingMode?: CachingMode;
|
|
25
|
+
organisationId?: string;
|
|
26
|
+
configFilePath?: string;
|
|
26
27
|
}
|
|
27
28
|
/**
|
|
28
29
|
* Parameters for opening a deep link url in the Appium session.
|
|
@@ -386,7 +387,6 @@ type SavableTestStore = z.infer<typeof SavableTestStoreSchema>;
|
|
|
386
387
|
declare class GptDriver {
|
|
387
388
|
private interpolateTemplate;
|
|
388
389
|
private apiKey;
|
|
389
|
-
private organisationId?;
|
|
390
390
|
private gptDriverSessionId?;
|
|
391
391
|
private gptDriverBaseUrl;
|
|
392
392
|
private appiumSessionConfig?;
|
|
@@ -398,6 +398,8 @@ declare class GptDriver {
|
|
|
398
398
|
private buildId?;
|
|
399
399
|
private testId?;
|
|
400
400
|
private step_number;
|
|
401
|
+
private organisationId?;
|
|
402
|
+
private configFilePath?;
|
|
401
403
|
private globalActionHistory;
|
|
402
404
|
/**
|
|
403
405
|
* Creates an instance of the GptDriver class.
|
|
@@ -495,22 +497,26 @@ declare class GptDriver {
|
|
|
495
497
|
* on the GPTDriver servers. If the handler execution fails or no handler is provided, the command
|
|
496
498
|
* gets executed by the GPTDriver using natural language processing.
|
|
497
499
|
*
|
|
498
|
-
* @param {Object}
|
|
499
|
-
* @param {string}
|
|
500
|
-
*
|
|
501
|
-
* @param {AppiumHandler} [
|
|
500
|
+
* @param {string | Object} commandOrOptions - Either a command string or an options object
|
|
501
|
+
* @param {string} commandOrOptions.command - The natural language command to be executed by the GPTDriver.
|
|
502
|
+
* Examples: "Click the login button", "Enter 'test@example.com' in the email field"
|
|
503
|
+
* @param {AppiumHandler} [commandOrOptions.appiumHandler] - An optional function that processes Appium-specific commands.
|
|
504
|
+
* @param {CachingMode} [commandOrOptions.cachingMode] - Controls how the GPTDriver caches this command execution.
|
|
505
|
+
* @param {boolean} [commandOrOptions.useSmartLoop] - If true, uses the smart loop execution. Default: false
|
|
506
|
+
* @param {Object} [options] - Additional options when first parameter is a command string
|
|
507
|
+
* @param {AppiumHandler} [options.appiumHandler] - An optional function that processes Appium-specific commands.
|
|
502
508
|
* If provided, this handler is executed instead of calling
|
|
503
509
|
* the GPTDriver API. Useful for performance optimization when
|
|
504
510
|
* you know the exact Appium commands to execute.
|
|
505
|
-
* @param {CachingMode} [
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
*
|
|
511
|
-
* @param {boolean} [
|
|
512
|
-
*
|
|
513
|
-
*
|
|
511
|
+
* @param {CachingMode} [options.cachingMode] - Controls how the GPTDriver caches this command execution.
|
|
512
|
+
* If not specified, uses the global caching mode set in the constructor.
|
|
513
|
+
* Options:
|
|
514
|
+
* - "NONE"
|
|
515
|
+
* - "FULL_SCREEN"
|
|
516
|
+
* - "INTERACTION_REGION"
|
|
517
|
+
* @param {boolean} [options.useSmartLoop] - If true, uses the smart loop execution (Cache -> AI -> Execute -> Populate)
|
|
518
|
+
* which optimizes execution by checking cache first and populating it after.
|
|
519
|
+
* Default: false (uses legacy gptHandler)
|
|
514
520
|
*
|
|
515
521
|
* @returns {Promise<void>} A promise that resolves when the command execution is complete.
|
|
516
522
|
*
|
|
@@ -518,27 +524,30 @@ declare class GptDriver {
|
|
|
518
524
|
* the command by the GPTDriver.
|
|
519
525
|
*
|
|
520
526
|
* @example
|
|
521
|
-
* // Basic usage with
|
|
527
|
+
* // Basic usage with command string
|
|
528
|
+
* await driver.aiExecute("Click the submit button");
|
|
529
|
+
*
|
|
530
|
+
* @example
|
|
531
|
+
* // Basic usage with options object
|
|
522
532
|
* await driver.aiExecute({
|
|
523
533
|
* command: "Click the submit button"
|
|
524
534
|
* });
|
|
525
535
|
*
|
|
526
536
|
* @example
|
|
527
|
-
* //
|
|
528
|
-
* await driver.aiExecute({
|
|
529
|
-
* command: "Navigate to the settings page",
|
|
537
|
+
* // Command string with options
|
|
538
|
+
* await driver.aiExecute("Navigate to settings", {
|
|
530
539
|
* cachingMode: "FULL_SCREEN"
|
|
531
540
|
* });
|
|
532
541
|
*
|
|
533
542
|
* @example
|
|
534
|
-
* //
|
|
543
|
+
* // Full screen caching using options object
|
|
535
544
|
* await driver.aiExecute({
|
|
536
|
-
* command: "
|
|
537
|
-
* cachingMode: "
|
|
545
|
+
* command: "Navigate to the settings page",
|
|
546
|
+
* cachingMode: "FULL_SCREEN"
|
|
538
547
|
* });
|
|
539
548
|
*
|
|
540
549
|
* @example
|
|
541
|
-
* // With custom Appium handler
|
|
550
|
+
* // With custom Appium handler
|
|
542
551
|
* await driver.aiExecute({
|
|
543
552
|
* command: "Click the login button",
|
|
544
553
|
* appiumHandler: async (driver) => {
|
|
@@ -549,13 +558,6 @@ declare class GptDriver {
|
|
|
549
558
|
* });
|
|
550
559
|
*
|
|
551
560
|
* @example
|
|
552
|
-
* // Force fresh execution for dynamic content
|
|
553
|
-
* await driver.aiExecute({
|
|
554
|
-
* command: "Verify the current timestamp",
|
|
555
|
-
* cachingMode: "NONE"
|
|
556
|
-
* });
|
|
557
|
-
*
|
|
558
|
-
* @example
|
|
559
561
|
* // Using smart loop for optimized caching
|
|
560
562
|
* await driver.aiExecute({
|
|
561
563
|
* command: "Click the login button",
|
|
@@ -563,12 +565,17 @@ declare class GptDriver {
|
|
|
563
565
|
* cachingMode: "FULL_SCREEN"
|
|
564
566
|
* });
|
|
565
567
|
*/
|
|
566
|
-
aiExecute(
|
|
568
|
+
aiExecute(options: {
|
|
567
569
|
command: string;
|
|
568
570
|
appiumHandler?: AppiumHandler;
|
|
569
571
|
cachingMode?: CachingMode;
|
|
570
572
|
useSmartLoop?: boolean;
|
|
571
573
|
}): Promise<void>;
|
|
574
|
+
aiExecute(command: string, options?: {
|
|
575
|
+
appiumHandler?: AppiumHandler;
|
|
576
|
+
cachingMode?: CachingMode;
|
|
577
|
+
useSmartLoop?: boolean;
|
|
578
|
+
}): Promise<void>;
|
|
572
579
|
/**
|
|
573
580
|
* Asserts a single condition using the GPTDriver.
|
|
574
581
|
*
|
package/dist/index.mjs
CHANGED
|
@@ -158,6 +158,14 @@ const SavableTestStoreSchema = z.object({
|
|
|
158
158
|
steps: z.array(SavableStepSchema),
|
|
159
159
|
params: z.record(z.string(), z.string()).optional()
|
|
160
160
|
});
|
|
161
|
+
const VariablesSchema = z.record(z.string(), z.string()).optional().default({});
|
|
162
|
+
const ConfigSchema = z.object({
|
|
163
|
+
testDir: z.string(),
|
|
164
|
+
driver: z.string(),
|
|
165
|
+
port: z.number(),
|
|
166
|
+
apiKey: z.string(),
|
|
167
|
+
variables: VariablesSchema
|
|
168
|
+
});
|
|
161
169
|
|
|
162
170
|
const CACHE_SERVER_URL = "https://cache.mobileboost.io";
|
|
163
171
|
const GPT_DRIVER_BASE_URL = "https://api.mobileboost.io";
|
|
@@ -602,7 +610,6 @@ class GptDriver {
|
|
|
602
610
|
});
|
|
603
611
|
}
|
|
604
612
|
apiKey;
|
|
605
|
-
organisationId;
|
|
606
613
|
gptDriverSessionId;
|
|
607
614
|
gptDriverBaseUrl;
|
|
608
615
|
appiumSessionConfig;
|
|
@@ -614,6 +621,8 @@ class GptDriver {
|
|
|
614
621
|
buildId;
|
|
615
622
|
testId;
|
|
616
623
|
step_number = 1;
|
|
624
|
+
organisationId;
|
|
625
|
+
configFilePath;
|
|
617
626
|
// Smart loop state - maintains action history across steps for context
|
|
618
627
|
globalActionHistory = [];
|
|
619
628
|
/**
|
|
@@ -638,11 +647,12 @@ class GptDriver {
|
|
|
638
647
|
constructor(config) {
|
|
639
648
|
this.testId = config.testId;
|
|
640
649
|
this.apiKey = config.apiKey;
|
|
641
|
-
this.organisationId = config.organisationId;
|
|
642
650
|
this.buildId = config.buildId;
|
|
643
651
|
this.useGptDriverCloud = config.useGptDriverCloud;
|
|
644
652
|
this.gptDriverBaseUrl = GPT_DRIVER_BASE_URL;
|
|
645
653
|
this.cachingMode = config.cachingMode ?? "NONE";
|
|
654
|
+
this.organisationId = config.organisationId;
|
|
655
|
+
this.configFilePath = config.configFilePath;
|
|
646
656
|
if (config.useGptDriverCloud) {
|
|
647
657
|
if (config.serverConfig.device?.platform == null) {
|
|
648
658
|
throw new Error("Platform is missing. Please specify the platform when using GPTDriver Cloud.");
|
|
@@ -1003,86 +1013,12 @@ class GptDriver {
|
|
|
1003
1013
|
await this.gptHandler(command);
|
|
1004
1014
|
}
|
|
1005
1015
|
}
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
* If an `appiumHandler` is provided, it will be invoked with the WebDriver instance to perform
|
|
1013
|
-
* the command-specific operations. After executing the handler, the executed commands get logged
|
|
1014
|
-
* on the GPTDriver servers. If the handler execution fails or no handler is provided, the command
|
|
1015
|
-
* gets executed by the GPTDriver using natural language processing.
|
|
1016
|
-
*
|
|
1017
|
-
* @param {Object} params - The execution parameters
|
|
1018
|
-
* @param {string} params.command - The natural language command to be executed by the GPTDriver.
|
|
1019
|
-
* Examples: "Click the login button", "Enter 'test@example.com' in the email field"
|
|
1020
|
-
* @param {AppiumHandler} [params.appiumHandler] - An optional function that processes Appium-specific commands.
|
|
1021
|
-
* If provided, this handler is executed instead of calling
|
|
1022
|
-
* the GPTDriver API. Useful for performance optimization when
|
|
1023
|
-
* you know the exact Appium commands to execute.
|
|
1024
|
-
* @param {CachingMode} [params.cachingMode] - Controls how the GPTDriver caches this command execution.
|
|
1025
|
-
* If not specified, uses the global caching mode set in the constructor.
|
|
1026
|
-
* Options:
|
|
1027
|
-
* - "NONE"
|
|
1028
|
-
* - "FULL_SCREEN"
|
|
1029
|
-
* - "INTERACTION_REGION"
|
|
1030
|
-
* @param {boolean} [params.useSmartLoop] - If true, uses the smart loop execution (Cache -> AI -> Execute -> Populate)
|
|
1031
|
-
* which optimizes execution by checking cache first and populating it after.
|
|
1032
|
-
* Default: false (uses legacy gptHandler)
|
|
1033
|
-
*
|
|
1034
|
-
* @returns {Promise<void>} A promise that resolves when the command execution is complete.
|
|
1035
|
-
*
|
|
1036
|
-
* @throws {Error} If an error occurs during the execution of the Appium handler or while processing
|
|
1037
|
-
* the command by the GPTDriver.
|
|
1038
|
-
*
|
|
1039
|
-
* @example
|
|
1040
|
-
* // Basic usage with natural language (no caching)
|
|
1041
|
-
* await driver.aiExecute({
|
|
1042
|
-
* command: "Click the submit button"
|
|
1043
|
-
* });
|
|
1044
|
-
*
|
|
1045
|
-
* @example
|
|
1046
|
-
* // Full screen caching for repetitive navigation on similar screens
|
|
1047
|
-
* await driver.aiExecute({
|
|
1048
|
-
* command: "Navigate to the settings page",
|
|
1049
|
-
* cachingMode: "FULL_SCREEN"
|
|
1050
|
-
* });
|
|
1051
|
-
*
|
|
1052
|
-
* @example
|
|
1053
|
-
* // Interaction region caching for repeated actions on the same button
|
|
1054
|
-
* await driver.aiExecute({
|
|
1055
|
-
* command: "Click the login button",
|
|
1056
|
-
* cachingMode: "INTERACTION_REGION"
|
|
1057
|
-
* });
|
|
1058
|
-
*
|
|
1059
|
-
* @example
|
|
1060
|
-
* // With custom Appium handler as fallback
|
|
1061
|
-
* await driver.aiExecute({
|
|
1062
|
-
* command: "Click the login button",
|
|
1063
|
-
* appiumHandler: async (driver) => {
|
|
1064
|
-
* const loginBtn = await driver.$('~loginButton');
|
|
1065
|
-
* await loginBtn.click();
|
|
1066
|
-
* },
|
|
1067
|
-
* cachingMode: "INTERACTION_REGION"
|
|
1068
|
-
* });
|
|
1069
|
-
*
|
|
1070
|
-
* @example
|
|
1071
|
-
* // Force fresh execution for dynamic content
|
|
1072
|
-
* await driver.aiExecute({
|
|
1073
|
-
* command: "Verify the current timestamp",
|
|
1074
|
-
* cachingMode: "NONE"
|
|
1075
|
-
* });
|
|
1076
|
-
*
|
|
1077
|
-
* @example
|
|
1078
|
-
* // Using smart loop for optimized caching
|
|
1079
|
-
* await driver.aiExecute({
|
|
1080
|
-
* command: "Click the login button",
|
|
1081
|
-
* useSmartLoop: true,
|
|
1082
|
-
* cachingMode: "FULL_SCREEN"
|
|
1083
|
-
* });
|
|
1084
|
-
*/
|
|
1085
|
-
async aiExecute({ command, appiumHandler, cachingMode, useSmartLoop = false }) {
|
|
1016
|
+
async aiExecute(commandOrOptions, options) {
|
|
1017
|
+
const command = typeof commandOrOptions === "string" ? commandOrOptions : commandOrOptions.command;
|
|
1018
|
+
const opts = typeof commandOrOptions === "string" ? options : commandOrOptions;
|
|
1019
|
+
const appiumHandler = opts?.appiumHandler;
|
|
1020
|
+
const cachingMode = opts?.cachingMode;
|
|
1021
|
+
const useSmartLoop = opts?.useSmartLoop ?? false;
|
|
1086
1022
|
if (!this.appiumSessionStarted) {
|
|
1087
1023
|
await this.startSession();
|
|
1088
1024
|
}
|
|
@@ -1335,9 +1271,42 @@ class GptDriver {
|
|
|
1335
1271
|
*/
|
|
1336
1272
|
async executeFlow(filePath, options) {
|
|
1337
1273
|
const useSmartLoop = options?.useSmartLoop ?? false;
|
|
1274
|
+
const configFilePath = this.configFilePath;
|
|
1275
|
+
let baseDir;
|
|
1276
|
+
let absolutePath;
|
|
1277
|
+
if (configFilePath) {
|
|
1278
|
+
let raw2;
|
|
1279
|
+
try {
|
|
1280
|
+
raw2 = await promises.readFile(configFilePath, "utf-8");
|
|
1281
|
+
} catch (e) {
|
|
1282
|
+
const msg = `Failed to read file at ${configFilePath}: ${e?.message ?? e}`;
|
|
1283
|
+
globalLogger.error(msg);
|
|
1284
|
+
throw new Error(msg);
|
|
1285
|
+
}
|
|
1286
|
+
let json2;
|
|
1287
|
+
try {
|
|
1288
|
+
json2 = JSON.parse(raw2);
|
|
1289
|
+
} catch (e) {
|
|
1290
|
+
const msg = `Invalid JSON in flow file ${configFilePath}: ${e?.message ?? e}`;
|
|
1291
|
+
globalLogger.error(msg);
|
|
1292
|
+
throw new Error(msg);
|
|
1293
|
+
}
|
|
1294
|
+
const parsedConfigFile = ConfigSchema.parse(json2);
|
|
1295
|
+
if (path.isAbsolute(parsedConfigFile.testDir)) {
|
|
1296
|
+
baseDir = parsedConfigFile.testDir;
|
|
1297
|
+
} else {
|
|
1298
|
+
baseDir = path.resolve(path.dirname(configFilePath), parsedConfigFile.testDir);
|
|
1299
|
+
}
|
|
1300
|
+
absolutePath = path.isAbsolute(filePath) ? filePath : path.resolve(baseDir, filePath);
|
|
1301
|
+
} else {
|
|
1302
|
+
if (useSmartLoop) {
|
|
1303
|
+
throw new Error("Config file is required when using SmartLoop, please provide the path in the constructor");
|
|
1304
|
+
} else {
|
|
1305
|
+
absolutePath = path.resolve(filePath);
|
|
1306
|
+
baseDir = path.dirname(absolutePath);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1338
1309
|
globalLogger.info(`Loading flow from file: ${filePath}`);
|
|
1339
|
-
const absolutePath = path.resolve(filePath);
|
|
1340
|
-
const baseDir = path.dirname(absolutePath);
|
|
1341
1310
|
let raw;
|
|
1342
1311
|
try {
|
|
1343
1312
|
raw = await promises.readFile(absolutePath, "utf-8");
|
|
@@ -1576,10 +1545,7 @@ ${issues}`);
|
|
|
1576
1545
|
for (const appiumCommand of executeResponse.commands) {
|
|
1577
1546
|
await this.executeCommand(appiumCommand);
|
|
1578
1547
|
}
|
|
1579
|
-
|
|
1580
|
-
globalLogger.debug("Command still in progress, waiting...");
|
|
1581
|
-
await delay(1500);
|
|
1582
|
-
}
|
|
1548
|
+
await delay(1500);
|
|
1583
1549
|
}
|
|
1584
1550
|
this.step_number = this.step_number + 1;
|
|
1585
1551
|
globalLogger.info("Command execution completed successfully");
|
|
@@ -1592,8 +1558,7 @@ ${issues}`);
|
|
|
1592
1558
|
async executeCommand(command) {
|
|
1593
1559
|
const firstAction = command.data?.actions?.at(0);
|
|
1594
1560
|
if (firstAction?.type === "pause" && firstAction.duration != null) {
|
|
1595
|
-
|
|
1596
|
-
await delay(firstAction * 1e3);
|
|
1561
|
+
await delay(firstAction.duration * 1e3);
|
|
1597
1562
|
} else if (!this.useGptDriverCloud) {
|
|
1598
1563
|
const parsedUrl = new URL(command.url);
|
|
1599
1564
|
parsedUrl.protocol = this.appiumSessionConfig.serverUrl.protocol;
|