gpt-driver-node 1.0.0-alpha.1 → 1.0.0-alpha.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 ADDED
@@ -0,0 +1,154 @@
1
+ 'use strict';
2
+
3
+ var axios = require('axios');
4
+ var webdriverio = require('webdriverio');
5
+ var sharp = require('sharp');
6
+
7
+ const delay = async (milliseconds) => {
8
+ await new Promise((resolve) => setTimeout(resolve, milliseconds));
9
+ };
10
+ const getScreenshot = async (driver, deviceSize) => {
11
+ let screenshot = await driver.takeScreenshot();
12
+ if (driver.capabilities.platformName === "iOS") {
13
+ const imageBuffer = Buffer.from(screenshot, "base64");
14
+ const transformedImage = await sharp(imageBuffer).resize(deviceSize.width, deviceSize.height).toBuffer();
15
+ screenshot = transformedImage.toString("base64");
16
+ }
17
+ return screenshot;
18
+ };
19
+ const delayIfNeeded = async (lastResponseTime) => {
20
+ if (lastResponseTime == null) {
21
+ return;
22
+ }
23
+ const currentTime = Date.now();
24
+ const difference = currentTime - lastResponseTime;
25
+ if (difference < 1500) {
26
+ await delay(difference);
27
+ }
28
+ };
29
+
30
+ class GptDriver {
31
+ apiKey;
32
+ baseUrl;
33
+ driver;
34
+ deviceConfig;
35
+ firestoreSessionId;
36
+ deviceSize;
37
+ lastCommandExecutionTime;
38
+ constructor(config) {
39
+ this.apiKey = config.apiKey;
40
+ this.baseUrl = "https://api.mobileboost.io";
41
+ if (config.driver !== void 0) {
42
+ this.driver = config.driver;
43
+ } else if (config.deviceConfig !== void 0) {
44
+ this.deviceConfig = config.deviceConfig;
45
+ } else {
46
+ throw new Error("Either provide an appium driver or a deviceConfig object");
47
+ }
48
+ }
49
+ async startSession() {
50
+ if (this.driver == void 0 && this.deviceConfig != void 0) {
51
+ const capabilities = {
52
+ platformName: this.deviceConfig.platform,
53
+ "appium:automationName": this.deviceConfig.platform === "Android" ? "UiAutomator2" : "XCUITest",
54
+ "appium:deviceName": this.deviceConfig.deviceName
55
+ };
56
+ const wdOpts = {
57
+ hostname: process.env.APPIUM_HOST || "localhost",
58
+ port: process.env.APPIUM_PORT != null ? parseInt(process.env.APPIUM_PORT, 10) : 4723,
59
+ logLevel: "info",
60
+ capabilities
61
+ };
62
+ this.driver = await webdriverio.remote(wdOpts);
63
+ }
64
+ const driver = this.driver;
65
+ const response = await axios.post(
66
+ `${this.baseUrl}/sessions/create`,
67
+ {
68
+ api_key: this.apiKey,
69
+ appium_session_id: driver.sessionId,
70
+ device_config: {
71
+ // @ts-ignore
72
+ platform: driver.capabilities.platformName,
73
+ // @ts-ignore
74
+ device: driver.capabilities.deviceName,
75
+ // @ts-ignore
76
+ os: driver.capabilities.platformVersion
77
+ }
78
+ }
79
+ );
80
+ const rect = await driver.getWindowRect();
81
+ this.deviceSize = { width: rect.width, height: rect.height };
82
+ this.firestoreSessionId = response.data.sessionId;
83
+ }
84
+ async stopSession({ status }) {
85
+ await axios.post(
86
+ `${this.baseUrl}/sessions/${this.firestoreSessionId}/stop`,
87
+ {
88
+ api_key: this.apiKey,
89
+ status
90
+ }
91
+ );
92
+ this.firestoreSessionId = void 0;
93
+ }
94
+ async execute(command, appiumHandler) {
95
+ const driver = this.driver;
96
+ if (appiumHandler != null) {
97
+ try {
98
+ await appiumHandler(driver);
99
+ } catch (e) {
100
+ await this.gptHandler(command);
101
+ }
102
+ } else {
103
+ await this.gptHandler(command);
104
+ }
105
+ }
106
+ async gptHandler(command) {
107
+ const driver = this.driver;
108
+ try {
109
+ let conditionSucceeded = false;
110
+ while (!conditionSucceeded) {
111
+ await delayIfNeeded(this.lastCommandExecutionTime);
112
+ const screenshot = await getScreenshot(driver, this.deviceSize);
113
+ const response = await axios.request(
114
+ {
115
+ url: `${this.baseUrl}/sessions/${this.firestoreSessionId}/execute`,
116
+ method: "POST",
117
+ data: {
118
+ api_key: this.apiKey,
119
+ command,
120
+ base64_screenshot: screenshot
121
+ }
122
+ }
123
+ );
124
+ const executeStatus = response.data.status;
125
+ if (executeStatus === "failed") {
126
+ throw new Error("Execution failed");
127
+ }
128
+ conditionSucceeded = executeStatus !== "inProgress";
129
+ const executeResponse = response.data;
130
+ for (const command2 of executeResponse.commands) {
131
+ await this.executeCommand(command2);
132
+ }
133
+ this.lastCommandExecutionTime = Date.now();
134
+ }
135
+ } catch (e) {
136
+ await this.stopSession({ status: "failed" });
137
+ throw e;
138
+ }
139
+ }
140
+ async executeCommand(command) {
141
+ const firstAction = command.data.actions?.at(0);
142
+ if (firstAction?.type === "pause" && firstAction.duration != null) {
143
+ await delay(firstAction * 1e3);
144
+ } else {
145
+ await axios.request({
146
+ url: command.url,
147
+ method: command.method,
148
+ data: command.data
149
+ });
150
+ }
151
+ }
152
+ }
153
+
154
+ module.exports = GptDriver;
@@ -0,0 +1,37 @@
1
+ interface AppiumHandler {
2
+ (driver: WebdriverIO.Browser): Promise<any>;
3
+ }
4
+ interface DeviceConfig {
5
+ platform: "iOS" | "Android";
6
+ deviceName?: string;
7
+ platformVersion?: string;
8
+ }
9
+ interface GptDriverConfig {
10
+ apiKey: string;
11
+ driver?: WebdriverIO.Browser;
12
+ deviceConfig?: DeviceConfig;
13
+ }
14
+ interface DeviceSize {
15
+ width: number;
16
+ height: number;
17
+ }
18
+
19
+ declare class GptDriver {
20
+ apiKey: string;
21
+ baseUrl: string;
22
+ driver?: WebdriverIO.Browser;
23
+ deviceConfig?: DeviceConfig;
24
+ firestoreSessionId?: string;
25
+ deviceSize?: DeviceSize;
26
+ lastCommandExecutionTime?: number;
27
+ constructor(config: GptDriverConfig);
28
+ startSession(): Promise<void>;
29
+ stopSession({ status }: {
30
+ status: "failed" | "success";
31
+ }): Promise<void>;
32
+ execute(command: string, appiumHandler?: AppiumHandler): Promise<void>;
33
+ private gptHandler;
34
+ private executeCommand;
35
+ }
36
+
37
+ export { GptDriver as default };
package/dist/index.mjs ADDED
@@ -0,0 +1,152 @@
1
+ import axios from 'axios';
2
+ import { remote } from 'webdriverio';
3
+ import sharp from 'sharp';
4
+
5
+ const delay = async (milliseconds) => {
6
+ await new Promise((resolve) => setTimeout(resolve, milliseconds));
7
+ };
8
+ const getScreenshot = async (driver, deviceSize) => {
9
+ let screenshot = await driver.takeScreenshot();
10
+ if (driver.capabilities.platformName === "iOS") {
11
+ const imageBuffer = Buffer.from(screenshot, "base64");
12
+ const transformedImage = await sharp(imageBuffer).resize(deviceSize.width, deviceSize.height).toBuffer();
13
+ screenshot = transformedImage.toString("base64");
14
+ }
15
+ return screenshot;
16
+ };
17
+ const delayIfNeeded = async (lastResponseTime) => {
18
+ if (lastResponseTime == null) {
19
+ return;
20
+ }
21
+ const currentTime = Date.now();
22
+ const difference = currentTime - lastResponseTime;
23
+ if (difference < 1500) {
24
+ await delay(difference);
25
+ }
26
+ };
27
+
28
+ class GptDriver {
29
+ apiKey;
30
+ baseUrl;
31
+ driver;
32
+ deviceConfig;
33
+ firestoreSessionId;
34
+ deviceSize;
35
+ lastCommandExecutionTime;
36
+ constructor(config) {
37
+ this.apiKey = config.apiKey;
38
+ this.baseUrl = "https://api.mobileboost.io";
39
+ if (config.driver !== void 0) {
40
+ this.driver = config.driver;
41
+ } else if (config.deviceConfig !== void 0) {
42
+ this.deviceConfig = config.deviceConfig;
43
+ } else {
44
+ throw new Error("Either provide an appium driver or a deviceConfig object");
45
+ }
46
+ }
47
+ async startSession() {
48
+ if (this.driver == void 0 && this.deviceConfig != void 0) {
49
+ const capabilities = {
50
+ platformName: this.deviceConfig.platform,
51
+ "appium:automationName": this.deviceConfig.platform === "Android" ? "UiAutomator2" : "XCUITest",
52
+ "appium:deviceName": this.deviceConfig.deviceName
53
+ };
54
+ const wdOpts = {
55
+ hostname: process.env.APPIUM_HOST || "localhost",
56
+ port: process.env.APPIUM_PORT != null ? parseInt(process.env.APPIUM_PORT, 10) : 4723,
57
+ logLevel: "info",
58
+ capabilities
59
+ };
60
+ this.driver = await remote(wdOpts);
61
+ }
62
+ const driver = this.driver;
63
+ const response = await axios.post(
64
+ `${this.baseUrl}/sessions/create`,
65
+ {
66
+ api_key: this.apiKey,
67
+ appium_session_id: driver.sessionId,
68
+ device_config: {
69
+ // @ts-ignore
70
+ platform: driver.capabilities.platformName,
71
+ // @ts-ignore
72
+ device: driver.capabilities.deviceName,
73
+ // @ts-ignore
74
+ os: driver.capabilities.platformVersion
75
+ }
76
+ }
77
+ );
78
+ const rect = await driver.getWindowRect();
79
+ this.deviceSize = { width: rect.width, height: rect.height };
80
+ this.firestoreSessionId = response.data.sessionId;
81
+ }
82
+ async stopSession({ status }) {
83
+ await axios.post(
84
+ `${this.baseUrl}/sessions/${this.firestoreSessionId}/stop`,
85
+ {
86
+ api_key: this.apiKey,
87
+ status
88
+ }
89
+ );
90
+ this.firestoreSessionId = void 0;
91
+ }
92
+ async execute(command, appiumHandler) {
93
+ const driver = this.driver;
94
+ if (appiumHandler != null) {
95
+ try {
96
+ await appiumHandler(driver);
97
+ } catch (e) {
98
+ await this.gptHandler(command);
99
+ }
100
+ } else {
101
+ await this.gptHandler(command);
102
+ }
103
+ }
104
+ async gptHandler(command) {
105
+ const driver = this.driver;
106
+ try {
107
+ let conditionSucceeded = false;
108
+ while (!conditionSucceeded) {
109
+ await delayIfNeeded(this.lastCommandExecutionTime);
110
+ const screenshot = await getScreenshot(driver, this.deviceSize);
111
+ const response = await axios.request(
112
+ {
113
+ url: `${this.baseUrl}/sessions/${this.firestoreSessionId}/execute`,
114
+ method: "POST",
115
+ data: {
116
+ api_key: this.apiKey,
117
+ command,
118
+ base64_screenshot: screenshot
119
+ }
120
+ }
121
+ );
122
+ const executeStatus = response.data.status;
123
+ if (executeStatus === "failed") {
124
+ throw new Error("Execution failed");
125
+ }
126
+ conditionSucceeded = executeStatus !== "inProgress";
127
+ const executeResponse = response.data;
128
+ for (const command2 of executeResponse.commands) {
129
+ await this.executeCommand(command2);
130
+ }
131
+ this.lastCommandExecutionTime = Date.now();
132
+ }
133
+ } catch (e) {
134
+ await this.stopSession({ status: "failed" });
135
+ throw e;
136
+ }
137
+ }
138
+ async executeCommand(command) {
139
+ const firstAction = command.data.actions?.at(0);
140
+ if (firstAction?.type === "pause" && firstAction.duration != null) {
141
+ await delay(firstAction * 1e3);
142
+ } else {
143
+ await axios.request({
144
+ url: command.url,
145
+ method: command.method,
146
+ data: command.data
147
+ });
148
+ }
149
+ }
150
+ }
151
+
152
+ export { GptDriver as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gpt-driver-node",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0-alpha.2",
4
4
  "main": "./dist/index.cjs",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.cts",
@@ -15,7 +15,6 @@
15
15
  "license": "CC BY-NC-SA 4.0",
16
16
  "description": "Test your mobile apps with the AI native GPT Driver (docs.mobileboost.io).",
17
17
  "dependencies": {
18
- "appium-xcuitest-driver": "^7.24.14",
19
18
  "axios": "^1.7.3",
20
19
  "sharp": "^0.33.4",
21
20
  "webdriverio": "^8.40.0"
package/tsconfig.json CHANGED
@@ -3,7 +3,8 @@
3
3
  "target": "ESNext",
4
4
  "module": "ESNext",
5
5
  "strict": true,
6
- // "esModuleInterop": true,
6
+ "outDir": "./dist",
7
+ "esModuleInterop": true,
7
8
  "declaration": true,
8
9
  "moduleResolution": "node",
9
10
  "isolatedModules": true,
package/src/helpers.ts DELETED
@@ -1,31 +0,0 @@
1
- import sharp from "sharp";
2
-
3
- const delay = async (milliseconds: number): Promise<void> => {
4
- await new Promise((resolve) => setTimeout(resolve, milliseconds));
5
- };
6
-
7
-
8
- const getScreenshot = async (driver: WebdriverIO.Browser, deviceSize: DeviceSize) => {
9
- let screenshot = await driver.takeScreenshot();
10
- if (driver.capabilities.platformName === "iOS") {
11
- const imageBuffer = Buffer.from(screenshot, 'base64');
12
- const transformedImage = await sharp(imageBuffer).resize(deviceSize.width, deviceSize.height).toBuffer()
13
- screenshot = transformedImage.toString('base64')
14
- }
15
-
16
- return screenshot;
17
- }
18
-
19
- const delayIfNeeded = async (lastResponseTime?: number) => {
20
- if (lastResponseTime == null) {
21
- return;
22
- }
23
- const currentTime = Date.now();
24
- const difference = currentTime - lastResponseTime;
25
-
26
- if (difference < 1500) {
27
- await delay(difference);
28
- }
29
- }
30
-
31
- export {delay, getScreenshot, delayIfNeeded}
package/src/index.ts DELETED
@@ -1,151 +0,0 @@
1
- import axios from "axios";
2
- import {remote, RemoteOptions} from 'webdriverio'
3
- import {delay, delayIfNeeded, getScreenshot} from "./helpers";
4
- import {AppiumHandler, Command, DeviceConfig, DeviceSize, ExecuteResponse, GptDriverConfig} from "./types";
5
-
6
- class GptDriver {
7
- apiKey: string;
8
- baseUrl: string;
9
- driver?: WebdriverIO.Browser;
10
- deviceConfig?: DeviceConfig;
11
- firestoreSessionId?: string;
12
- deviceSize?: DeviceSize;
13
- lastCommandExecutionTime?: number;
14
-
15
- constructor(config: GptDriverConfig) {
16
- this.apiKey = config.apiKey;
17
- this.baseUrl = "https://api.mobileboost.io";
18
-
19
- if (config.driver !== undefined) {
20
- this.driver = config.driver
21
- } else if (config.deviceConfig !== undefined) {
22
- this.deviceConfig = config.deviceConfig;
23
- } else {
24
- throw new Error("Either provide an appium driver or a deviceConfig object")
25
- }
26
- }
27
-
28
- async startSession() {
29
- if (this.driver == undefined && this.deviceConfig != undefined) {
30
- const capabilities = {
31
- platformName: this.deviceConfig.platform,
32
- 'appium:automationName': this.deviceConfig.platform === "Android" ? 'UiAutomator2' : "XCUITest",
33
- 'appium:deviceName': this.deviceConfig.deviceName,
34
- };
35
-
36
- const wdOpts: RemoteOptions = {
37
- hostname: process.env.APPIUM_HOST || 'localhost',
38
- port: process.env.APPIUM_PORT != null ? parseInt(process.env.APPIUM_PORT, 10) : 4723,
39
- logLevel: 'info',
40
- capabilities: capabilities,
41
- };
42
-
43
- this.driver = await remote(wdOpts);
44
- }
45
-
46
-
47
- const driver = this.driver!;
48
-
49
- const response = await axios.post(
50
- `${this.baseUrl}/sessions/create`,
51
- {
52
- api_key: this.apiKey,
53
- appium_session_id: driver.sessionId,
54
- device_config: {
55
- // @ts-ignore
56
- platform: driver.capabilities.platformName,
57
- // @ts-ignore
58
- device: driver.capabilities.deviceName,
59
- // @ts-ignore
60
- os: driver.capabilities.platformVersion
61
- },
62
- },
63
- )
64
- const rect = await driver.getWindowRect();
65
- this.deviceSize = {width: rect.width, height: rect.height}
66
-
67
- this.firestoreSessionId = response.data.sessionId;
68
-
69
- }
70
-
71
- async stopSession({status}: { status: "failed" | "success" }) {
72
- await axios.post(
73
- `${this.baseUrl}/sessions/${this.firestoreSessionId}/stop`,
74
- {
75
- api_key: this.apiKey,
76
- status,
77
- },
78
- )
79
-
80
- this.firestoreSessionId = undefined;
81
- }
82
-
83
- async execute(command: string, appiumHandler?: AppiumHandler) {
84
- const driver = this.driver!;
85
-
86
- if (appiumHandler != null) {
87
- try {
88
- await appiumHandler(driver);
89
- } catch (e) {
90
- await this.gptHandler(command)
91
- }
92
- } else {
93
- await this.gptHandler(command)
94
- }
95
- }
96
-
97
- private async gptHandler(command: string) {
98
- const driver = this.driver!;
99
-
100
- try {
101
- let conditionSucceeded = false;
102
-
103
- while (!conditionSucceeded) {
104
- await delayIfNeeded(this.lastCommandExecutionTime);
105
- const screenshot = await getScreenshot(driver, this.deviceSize!)
106
-
107
- const response = await axios.request({
108
- url: `${this.baseUrl}/sessions/${this.firestoreSessionId}/execute`,
109
- method: "POST",
110
- data: {
111
- api_key: this.apiKey,
112
- command,
113
- base64_screenshot: screenshot,
114
- },
115
- }
116
- )
117
- const executeStatus = response.data.status;
118
- if (executeStatus === "failed") {
119
- throw new Error("Execution failed");
120
- }
121
-
122
- conditionSucceeded = executeStatus !== "inProgress";
123
- const executeResponse: ExecuteResponse = response.data;
124
- for (const command of executeResponse.commands) {
125
- await this.executeCommand(command)
126
- }
127
- this.lastCommandExecutionTime = Date.now();
128
- }
129
- } catch (e) {
130
- await this.stopSession({status: "failed"})
131
- throw e;
132
- }
133
-
134
- }
135
-
136
- private async executeCommand(command: Command) {
137
- const firstAction = command.data.actions?.at(0);
138
- if (firstAction?.type === "pause" && firstAction.duration != null) {
139
- await delay(firstAction * 1000)
140
- } else {
141
- await axios.request({
142
- url: command.url,
143
- method: command.method,
144
- data: command.data
145
- })
146
- }
147
-
148
- }
149
- }
150
-
151
- export default GptDriver;
package/src/types.ts DELETED
@@ -1,33 +0,0 @@
1
- interface ExecuteResponse {
2
- commands: Command[]
3
- status: "inProgress" | "success" | "failed"
4
- }
5
-
6
- interface Command {
7
- method: 'GET' | 'DELETE' | 'POST';
8
- url: string;
9
- data: any;
10
- }
11
-
12
- interface AppiumHandler {
13
- (driver: WebdriverIO.Browser): Promise<any>;
14
- }
15
-
16
- interface DeviceConfig {
17
- platform: "iOS" | "Android";
18
- deviceName?: string;
19
- platformVersion?: string;
20
- }
21
-
22
- interface GptDriverConfig {
23
- apiKey: string;
24
- driver?: WebdriverIO.Browser;
25
- deviceConfig?: DeviceConfig;
26
- }
27
-
28
- interface DeviceSize {
29
- width: number,
30
- height: number
31
- }
32
-
33
- export type {ExecuteResponse, Command, AppiumHandler, DeviceConfig, GptDriverConfig, DeviceSize}