Skip to content

Commit 20299df

Browse files
chore: Add server status validation (#40)
1 parent 33c3e40 commit 20299df

File tree

2 files changed

+81
-16
lines changed

2 files changed

+81
-16
lines changed

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
"Android",
3232
"iOS"
3333
],
34-
"mainClass": "AppiumFlutterDriver"
34+
"mainClass": "AppiumFlutterDriver",
35+
"flutterServerVersion": ">=0.0.18 <1.0.0"
3536
},
3637
"scripts": {
3738
"format": "prettier --write .",
@@ -63,6 +64,7 @@
6364
"jest": "^29.7.0",
6465
"mocha": "^10.4.0",
6566
"rimraf": "^5.0.7",
67+
"semver": "^7.6.2",
6668
"ts-node": "^10.9.2",
6769
"typescript": "^5.4.5",
6870
"wdio-flutter-by-service": "^1.0.11",

src/utils.ts

Lines changed: 78 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,18 @@ import { JWProxy } from '@appium/base-driver';
55
import type { PortForwardCallback, PortReleaseCallback } from './types';
66
import type { AppiumFlutterDriver } from './driver';
77
import _ from 'lodash';
8+
import type { StringRecord } from '@appium/types';
9+
import { node } from 'appium/support';
10+
import path from 'node:path';
11+
import fs from 'node:fs';
12+
import semver from 'semver';
813

914
const DEVICE_PORT_RANGE = [9000, 9020];
1015
const SYSTEM_PORT_RANGE = [10000, 11000];
16+
const {
17+
appium: { flutterServerVersion: FLUTTER_SERVER_VERSION_REQ },
18+
version: PACKAGE_VERSION,
19+
} = readManifest();
1120

1221
export async function getProxyDriver(
1322
this: AppiumFlutterDriver,
@@ -61,27 +70,16 @@ export async function waitForFlutterServerToBeActive(
6170
): Promise<void> {
6271
await waitForCondition(
6372
async () => {
73+
let response: unknown;
6474
try {
65-
const response: any = await proxy.command('/status', 'GET');
66-
if (!response) {
67-
return false;
68-
}
69-
if (response?.appInfo?.packageName === packageName) {
70-
this.log.info(
71-
`Flutter server version the application is build with ${response.serverVersion}`,
72-
);
73-
return true;
74-
} else {
75-
this.log.error(
76-
`Looking for flutter server with package ${packageName}. But found ${response.appInfo?.packageName}`,
77-
);
78-
}
75+
response = await proxy.command('/status', 'GET');
7976
} catch (err: any) {
8077
this.log.info(
8178
`FlutterServer not reachable on port ${flutterPort}, Retrying..`,
8279
);
8380
return false;
8481
}
82+
return validateServerStatus.bind(this)(response, packageName);
8583
},
8684
{
8785
waitMs: this.opts.flutterServerLaunchTimeout ?? 5000,
@@ -240,8 +238,73 @@ export function attachAppLaunchArguments(
240238
]);
241239

242240
this.log.info(
243-
`iOS platform detected and flutterSystemPort capability is present.
241+
`iOS platform detected and flutterSystemPort capability is present.
244242
So attaching processArguments: ${JSON.stringify(capsToUpdate['appium:processArguments'])}`,
245243
);
246244
}
247245
}
246+
247+
function validateServerStatus(
248+
this: AppiumFlutterDriver,
249+
status: unknown,
250+
packageName: string,
251+
): boolean {
252+
const compatibilityMessage =
253+
`Please check the driver readme to ensure the compatibility ` +
254+
`between the server module integrated into the application under test ` +
255+
`and the current driver version ${PACKAGE_VERSION}.`;
256+
const formattedStatus = _.truncate(JSON.stringify(status), { length: 200 });
257+
const logAndThrow = (errMsg: string) => {
258+
this.log.info(errMsg);
259+
throw new Error(errMsg);
260+
};
261+
if (!_.isPlainObject(status)) {
262+
logAndThrow(
263+
`The server response ${formattedStatus} ` +
264+
`is not a valid object. ${compatibilityMessage}`,
265+
);
266+
}
267+
const statusMap = status as StringRecord;
268+
if (!statusMap.appInfo || !statusMap.appInfo?.packageName) {
269+
logAndThrow(
270+
`The server response ${formattedStatus} ` +
271+
`does not contain a package name. ${compatibilityMessage}`,
272+
);
273+
}
274+
if (statusMap.appInfo.packageName !== packageName) {
275+
logAndThrow(
276+
`The server response ` +
277+
`contains an unexpected package name (${statusMap.appInfo.packageName} != ${packageName}). ` +
278+
`Does this server belong to another app?`,
279+
);
280+
}
281+
if (!statusMap.serverVersion) {
282+
logAndThrow(
283+
`The server response ${formattedStatus} ` +
284+
`does not contain a valid server version. ${compatibilityMessage}`,
285+
);
286+
}
287+
if (!semver.satisfies(statusMap.serverVersion, FLUTTER_SERVER_VERSION_REQ)) {
288+
logAndThrow(
289+
`The server version ${statusMap.serverVersion} does not satisfy the driver ` +
290+
`version requirement '${FLUTTER_SERVER_VERSION_REQ}'. ` +
291+
compatibilityMessage,
292+
);
293+
}
294+
return true;
295+
}
296+
297+
function readManifest(): StringRecord {
298+
return JSON.parse(
299+
fs.readFileSync(
300+
path.join(
301+
node.getModuleRootSync(
302+
'appium-flutter-integration-driver',
303+
__filename,
304+
)!,
305+
'package.json',
306+
),
307+
{ encoding: 'utf8' },
308+
),
309+
);
310+
}

0 commit comments

Comments
 (0)