lim 0.21.3 → 0.22.0

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/README.md CHANGED
@@ -309,6 +309,23 @@ lim ios sync ./MyApp.app --watch --launch-mode RelaunchIfRunning
309
309
  lim ios sync ./MyApp.app --basis-cache-dir ./.limsync-cache
310
310
  ```
311
311
 
312
+ #### Maestro (iOS only)
313
+
314
+ Run the locally installed [Maestro](https://docs.maestro.dev) CLI against a remote
315
+ Limrun simulator. The command installs and launches the Maestro XCTest runner on
316
+ the instance when needed, then wires `maestro test` to it transparently.
317
+
318
+ ```bash
319
+ lim ios maestro test flow.yaml
320
+ lim ios maestro test flows/
321
+
322
+ # Extra maestro flags go after --
323
+ lim ios maestro -- test flow.yaml --include-tags smoke --test-output-dir artifacts
324
+
325
+ # Creating the instance with the runner preinstalled skips the install step
326
+ lim ios create --install-asset appstore/maestro-ios-runner-2.5.1.tar.gz
327
+ ```
328
+
312
329
  ---
313
330
 
314
331
  ### Android
@@ -0,0 +1,18 @@
1
+ import { BaseCommand } from '../../base-command';
2
+ export default class IosMaestro extends BaseCommand {
3
+ static summary: string;
4
+ static description: string;
5
+ static examples: string[];
6
+ static strict: boolean;
7
+ static args: {};
8
+ static flags: {
9
+ id: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
10
+ 'api-key': import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
11
+ json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
12
+ quiet: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
13
+ create: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
14
+ workspace: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
+ };
16
+ run(): Promise<void>;
17
+ }
18
+ //# sourceMappingURL=maestro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maestro.d.ts","sourceRoot":"","sources":["../../../src/commands/ios/maestro.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAIjD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,WAAW;IACjD,MAAM,CAAC,OAAO,SAAsD;IACpE,MAAM,CAAC,WAAW,SAI2F;IAC7G,MAAM,CAAC,QAAQ,WAIb;IAEF,MAAM,CAAC,MAAM,UAAS;IAEtB,MAAM,CAAC,IAAI,KAAM;IAEjB,MAAM,CAAC,KAAK;;;;;;;MAKV;IAEI,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA8F3B"}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const node_child_process_1 = require("node:child_process");
4
+ const core_1 = require("@oclif/core");
5
+ const api_1 = require("@limrun/api");
6
+ const base_command_1 = require("../../base-command");
7
+ const instance_client_factory_1 = require("../../lib/instance-client-factory");
8
+ const maestro_1 = require("../../lib/maestro");
9
+ class IosMaestro extends base_command_1.BaseCommand {
10
+ async run() {
11
+ const parsed = await this.parse(IosMaestro);
12
+ const flags = parsed.flags;
13
+ const rawArgs = parsed.argv ?? [];
14
+ this.setParsedFlags(flags);
15
+ await this.withAuth(async () => {
16
+ if (rawArgs[0] !== 'test') {
17
+ this.error('Provide a maestro test invocation, for example `lim ios maestro test flow.yaml`. ' +
18
+ 'Only the `test` subcommand is supported.');
19
+ }
20
+ const passthroughArgs = rawArgs.slice(1);
21
+ for (const arg of passthroughArgs) {
22
+ const flagName = arg.split('=')[0];
23
+ if (flagName && maestro_1.INJECTED_MAESTRO_FLAGS.includes(flagName)) {
24
+ this.error(`${flagName} is set by lim automatically, remove it from the maestro arguments.`);
25
+ }
26
+ }
27
+ const resolvedInstance = this.resolveIosInstance(flags.id);
28
+ const id = resolvedInstance.id;
29
+ let { targetHttpPortUrlPrefix, token } = resolvedInstance;
30
+ if (!targetHttpPortUrlPrefix || !token) {
31
+ const instance = await this.client.iosInstances.get(id);
32
+ targetHttpPortUrlPrefix = instance.status.targetHttpPortUrlPrefix;
33
+ token = instance.status.token;
34
+ // Forward the fresh endpoints so getIosInstanceClient connects directly
35
+ // instead of fetching the instance a second time.
36
+ resolvedInstance.apiUrl = instance.status.apiUrl;
37
+ resolvedInstance.token = token;
38
+ }
39
+ if (!targetHttpPortUrlPrefix || !token) {
40
+ this.error(`Instance ${id} does not expose the HTTP port URL required for Maestro.`);
41
+ }
42
+ const runnerUrl = targetHttpPortUrlPrefix + String(api_1.MAESTRO_RUNNER_PORT);
43
+ // A responding runner proves it is installed, so the common path skips
44
+ // the listApps round trip entirely.
45
+ const [{ client, disconnect }, runnerRunning] = await Promise.all([
46
+ (0, instance_client_factory_1.getIosInstanceClient)(this.client, resolvedInstance),
47
+ (0, api_1.isMaestroRunnerRunning)(runnerUrl, token),
48
+ ]);
49
+ try {
50
+ if (!runnerRunning) {
51
+ const apps = await client.listApps();
52
+ if (!apps.some((app) => app.bundleId === api_1.MAESTRO_RUNNER_BUNDLE_ID)) {
53
+ this.info('Installing the Maestro runner on the instance...');
54
+ const assets = await this.client.assets.list({
55
+ nameFilter: maestro_1.MAESTRO_RUNNER_ASSET_NAME,
56
+ includeAppStore: true,
57
+ includeDownloadUrl: true,
58
+ });
59
+ const runnerAsset = assets.find((asset) => asset.name === maestro_1.MAESTRO_RUNNER_ASSET_NAME);
60
+ if (!runnerAsset?.signedDownloadUrl) {
61
+ this.error(`Maestro runner asset ${maestro_1.MAESTRO_RUNNER_ASSET_NAME} is not available.`);
62
+ }
63
+ await client.installApp(runnerAsset.signedDownloadUrl);
64
+ }
65
+ this.info('Launching the Maestro runner...');
66
+ const launch = await client
67
+ .simctl(['launch', '--terminate-running-process', 'booted', api_1.MAESTRO_RUNNER_BUNDLE_ID])
68
+ .wait();
69
+ if (launch.code !== 0) {
70
+ this.error(`Failed to launch the Maestro runner (exit code ${launch.code}): ${launch.stderr}`);
71
+ }
72
+ if (!(await (0, api_1.waitForMaestroRunner)(runnerUrl, token))) {
73
+ this.error('The Maestro runner did not become ready in time.');
74
+ }
75
+ }
76
+ const run = await (0, api_1.prepareMaestroRun)(client, { runnerUrl });
77
+ this.info(`Running maestro ${run.maestroVersion} against ${id}...`);
78
+ const exitCode = await new Promise((resolve, reject) => {
79
+ const proc = (0, node_child_process_1.spawn)('maestro', ['test', ...run.args, ...passthroughArgs], {
80
+ ...api_1.maestroSpawnOptions,
81
+ env: { ...process.env, ...run.env },
82
+ stdio: 'inherit',
83
+ });
84
+ proc.once('error', reject);
85
+ // Maestro already reported to the inherited stdio; a signal death
86
+ // simply becomes a nonzero exit.
87
+ proc.once('close', (code, signal) => resolve(signal ? 1 : code ?? 1));
88
+ });
89
+ if (exitCode !== 0) {
90
+ this.exit(exitCode);
91
+ }
92
+ }
93
+ finally {
94
+ disconnect();
95
+ }
96
+ });
97
+ }
98
+ }
99
+ IosMaestro.summary = 'Run Maestro flows against a running iOS instance';
100
+ IosMaestro.description = 'Run the locally installed Maestro CLI against a remote Limrun iOS simulator. ' +
101
+ 'Ensures the Maestro XCTest runner is installed and running on the instance, then wires ' +
102
+ 'the local `maestro test` invocation to it transparently. Pass Maestro arguments after `--`. ' +
103
+ `Creating the instance with \`--install-asset ${maestro_1.MAESTRO_RUNNER_ASSET_NAME}\` skips the install step here.`;
104
+ IosMaestro.examples = [
105
+ '<%= config.bin %> ios maestro test flow.yaml',
106
+ '<%= config.bin %> ios maestro test flows/',
107
+ '<%= config.bin %> ios maestro -- test flow.yaml --include-tags smoke --test-output-dir artifacts',
108
+ ];
109
+ IosMaestro.strict = false;
110
+ IosMaestro.args = {};
111
+ IosMaestro.flags = {
112
+ ...base_command_1.BaseCommand.baseFlags,
113
+ id: core_1.Flags.string({
114
+ description: 'iOS instance ID to target. Defaults to the last created iOS instance.',
115
+ }),
116
+ };
117
+ exports.default = IosMaestro;
118
+ //# sourceMappingURL=maestro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maestro.js","sourceRoot":"","sources":["../../../src/commands/ios/maestro.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare const MAESTRO_RUNNER_ASSET_NAME = "appstore/maestro-ios-runner-2.5.1.tar.gz";
2
+ export declare const INJECTED_MAESTRO_FLAGS: string[];
3
+ //# sourceMappingURL=maestro.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maestro.d.ts","sourceRoot":"","sources":["../../src/lib/maestro.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,yBAAyB,6CAA6C,CAAC;AAIpF,eAAO,MAAM,sBAAsB,UAOlC,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.INJECTED_MAESTRO_FLAGS = exports.MAESTRO_RUNNER_ASSET_NAME = void 0;
4
+ // The patched runner has proven version-agnostic so far: Maestro CLI 2.7.0
5
+ // drives this 2.5.1-built runner including the newer endpoints (swipeV2,
6
+ // isScreenStatic, setOrientation). Bump only when a CLI release actually
7
+ // requires a newer runner.
8
+ exports.MAESTRO_RUNNER_ASSET_NAME = 'appstore/maestro-ios-runner-2.5.1.tar.gz';
9
+ // Flags `lim ios maestro` injects itself; user-provided duplicates would make
10
+ // maestro's picocli parser fail with a confusing error.
11
+ exports.INJECTED_MAESTRO_FLAGS = [
12
+ '--platform',
13
+ '-p',
14
+ '--device',
15
+ '--udid',
16
+ '--no-reinstall-driver',
17
+ '--driver-host-port',
18
+ ];
19
+ //# sourceMappingURL=maestro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maestro.js","sourceRoot":"","sources":["../../src/lib/maestro.ts"],"names":[],"mappings":";;;AAAA,2EAA2E;AAC3E,yEAAyE;AACzE,yEAAyE;AACzE,2BAA2B;AACd,QAAA,yBAAyB,GAAG,0CAA0C,CAAC;AAEpF,8EAA8E;AAC9E,wDAAwD;AAC3C,QAAA,sBAAsB,GAAG;IACpC,YAAY;IACZ,IAAI;IACJ,UAAU;IACV,QAAQ;IACR,uBAAuB;IACvB,oBAAoB;CACrB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lim",
3
- "version": "0.21.3",
3
+ "version": "0.22.0",
4
4
  "description": "Use remote XCode, Gradle, iOS Simulator, Android Emulator and more to build and test apps from Linux, Windows or macOS.",
5
5
  "bin": {
6
6
  "lim": "./bin/run.js"
@@ -25,7 +25,7 @@
25
25
  "test": "jest"
26
26
  },
27
27
  "dependencies": {
28
- "@limrun/api": "0.45.2",
28
+ "@limrun/api": "0.45.3",
29
29
  "@oclif/core": "^4",
30
30
  "cli-progress": "^3.12.0",
31
31
  "cli-table3": "^0.6.5",