@expo/build-tools 1.0.193 → 1.0.195
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/builders/common.js +0 -3
- package/dist/builders/common.js.map +1 -1
- package/dist/steps/easFunctions.js +2 -0
- package/dist/steps/easFunctions.js.map +1 -1
- package/dist/steps/functions/internalMaestroTest.d.ts +10 -0
- package/dist/steps/functions/internalMaestroTest.js +385 -0
- package/dist/steps/functions/internalMaestroTest.js.map +1 -0
- package/dist/steps/functions/startAndroidEmulator.js +18 -142
- package/dist/steps/functions/startAndroidEmulator.js.map +1 -1
- package/dist/steps/functions/startIosSimulator.js +35 -72
- package/dist/steps/functions/startIosSimulator.js.map +1 -1
- package/dist/utils/AndroidEmulatorUtils.d.ts +63 -0
- package/dist/utils/AndroidEmulatorUtils.js +260 -0
- package/dist/utils/AndroidEmulatorUtils.js.map +1 -0
- package/dist/utils/IosSimulatorUtils.d.ts +68 -0
- package/dist/utils/IosSimulatorUtils.js +122 -0
- package/dist/utils/IosSimulatorUtils.js.map +1 -0
- package/package.json +6 -4
package/dist/builders/common.js
CHANGED
|
@@ -45,9 +45,6 @@ async function runBuilderWithHooksAsync(ctx, builderAsync) {
|
|
|
45
45
|
err.artifacts = ctx.artifacts;
|
|
46
46
|
throw err;
|
|
47
47
|
}
|
|
48
|
-
if (!ctx.artifacts.APPLICATION_ARCHIVE) {
|
|
49
|
-
throw new Error('Builder must upload application archive');
|
|
50
|
-
}
|
|
51
48
|
return ctx.artifacts;
|
|
52
49
|
}
|
|
53
50
|
exports.runBuilderWithHooksAsync = runBuilderWithHooksAsync;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/builders/common.ts"],"names":[],"mappings":";;;AAAA,uDAA0E;AAG1E,0DAAyE;AACzE,kDAAsE;AACtE,0CAAwD;AAEjD,KAAK,UAAU,wBAAwB,CAC5C,GAAoB,EACpB,YAAqD;IAErD,IAAI,CAAC;QACH,IAAI,YAAY,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;YACxB,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;gBACnE,MAAM,IAAA,wBAAgB,EAAC,GAAG,EAAE,YAAI,CAAC,gBAAgB,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,YAAY,GAAG,KAAK,CAAC;YACrB,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;gBACjE,MAAM,IAAA,wBAAgB,EAAC,GAAG,EAAE,YAAI,CAAC,cAAc,CAAC,CAAC;YACnD,CAAC,CAAC,CAAC;YACH,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;gBACpE,MAAM,IAAA,wBAAgB,EAAC,GAAG,EAAE,YAAI,CAAC,iBAAiB,EAAE;oBAClD,SAAS,EAAE;wBACT,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;qBACxD;iBACF,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,wBAAQ,CAAC,GAAG,EAAE,CAAC;gBACtC,MAAM,IAAA,iDAAgC,EAAC,GAA4B,EAAE;oBACnE,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;gBACpE,MAAM,IAAA,4CAAgC,EAAC,GAAG,EAAE;oBAC1C,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;QAC9B,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"common.js","sourceRoot":"","sources":["../../src/builders/common.ts"],"names":[],"mappings":";;;AAAA,uDAA0E;AAG1E,0DAAyE;AACzE,kDAAsE;AACtE,0CAAwD;AAEjD,KAAK,UAAU,wBAAwB,CAC5C,GAAoB,EACpB,YAAqD;IAErD,IAAI,CAAC;QACH,IAAI,YAAY,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,GAAG,CAAC,CAAC;YACxB,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,qBAAqB,EAAE,KAAK,IAAI,EAAE;gBACnE,MAAM,IAAA,wBAAgB,EAAC,GAAG,EAAE,YAAI,CAAC,gBAAgB,CAAC,CAAC;YACrD,CAAC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,YAAY,GAAG,KAAK,CAAC;YACrB,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,mBAAmB,EAAE,KAAK,IAAI,EAAE;gBACjE,MAAM,IAAA,wBAAgB,EAAC,GAAG,EAAE,YAAI,CAAC,cAAc,CAAC,CAAC;YACnD,CAAC,CAAC,CAAC;YACH,MAAM,GAAG,CAAC;QACZ,CAAC;gBAAS,CAAC;YACT,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;gBACpE,MAAM,IAAA,wBAAgB,EAAC,GAAG,EAAE,YAAI,CAAC,iBAAiB,EAAE;oBAClD,SAAS,EAAE;wBACT,gBAAgB,EAAE,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;qBACxD;iBACF,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;YAEH,IAAI,GAAG,CAAC,GAAG,CAAC,QAAQ,KAAK,wBAAQ,CAAC,GAAG,EAAE,CAAC;gBACtC,MAAM,IAAA,iDAAgC,EAAC,GAA4B,EAAE;oBACnE,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC;YAED,MAAM,GAAG,CAAC,aAAa,CAAC,0BAAU,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;gBACpE,MAAM,IAAA,4CAAgC,EAAC,GAAG,EAAE;oBAC1C,MAAM,EAAE,GAAG,CAAC,MAAM;iBACnB,CAAC,CAAC;YACL,CAAC,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAAC,OAAO,GAAQ,EAAE,CAAC;QAClB,GAAG,CAAC,SAAS,GAAG,GAAG,CAAC,SAAS,CAAC;QAC9B,MAAM,GAAG,CAAC;IACZ,CAAC;IAED,OAAO,GAAG,CAAC,SAAS,CAAC;AACvB,CAAC;AA5CD,4DA4CC","sourcesContent":["import { BuildJob, BuildPhase, Ios, Platform } from '@expo/eas-build-job';\n\nimport { Artifacts, BuildContext } from '../context';\nimport { findAndUploadXcodeBuildLogsAsync } from '../ios/xcodeBuildLogs';\nimport { maybeFindAndUploadBuildArtifacts } from '../utils/artifacts';\nimport { Hook, runHookIfPresent } from '../utils/hooks';\n\nexport async function runBuilderWithHooksAsync<T extends BuildJob>(\n ctx: BuildContext<T>,\n builderAsync: (ctx: BuildContext<T>) => Promise<void>\n): Promise<Artifacts> {\n try {\n let buildSuccess = true;\n try {\n await builderAsync(ctx);\n await ctx.runBuildPhase(BuildPhase.ON_BUILD_SUCCESS_HOOK, async () => {\n await runHookIfPresent(ctx, Hook.ON_BUILD_SUCCESS);\n });\n } catch (err: any) {\n buildSuccess = false;\n await ctx.runBuildPhase(BuildPhase.ON_BUILD_ERROR_HOOK, async () => {\n await runHookIfPresent(ctx, Hook.ON_BUILD_ERROR);\n });\n throw err;\n } finally {\n await ctx.runBuildPhase(BuildPhase.ON_BUILD_COMPLETE_HOOK, async () => {\n await runHookIfPresent(ctx, Hook.ON_BUILD_COMPLETE, {\n extraEnvs: {\n EAS_BUILD_STATUS: buildSuccess ? 'finished' : 'errored',\n },\n });\n });\n\n if (ctx.job.platform === Platform.IOS) {\n await findAndUploadXcodeBuildLogsAsync(ctx as BuildContext<Ios.Job>, {\n logger: ctx.logger,\n });\n }\n\n await ctx.runBuildPhase(BuildPhase.UPLOAD_BUILD_ARTIFACTS, async () => {\n await maybeFindAndUploadBuildArtifacts(ctx, {\n logger: ctx.logger,\n });\n });\n }\n } catch (err: any) {\n err.artifacts = ctx.artifacts;\n throw err;\n }\n\n return ctx.artifacts;\n}\n"]}
|
|
@@ -29,6 +29,7 @@ const createSubmissionEntity_1 = require("./functions/createSubmissionEntity");
|
|
|
29
29
|
const downloadBuild_1 = require("./functions/downloadBuild");
|
|
30
30
|
const repack_1 = require("./functions/repack");
|
|
31
31
|
const downloadArtifact_1 = require("./functions/downloadArtifact");
|
|
32
|
+
const internalMaestroTest_1 = require("./functions/internalMaestroTest");
|
|
32
33
|
function getEasFunctions(ctx) {
|
|
33
34
|
const functions = [
|
|
34
35
|
(0, checkout_1.createCheckoutBuildFunction)(),
|
|
@@ -56,6 +57,7 @@ function getEasFunctions(ctx) {
|
|
|
56
57
|
(0, sendSlackMessage_1.createSendSlackMessageFunction)(),
|
|
57
58
|
(0, calculateEASUpdateRuntimeVersion_1.calculateEASUpdateRuntimeVersionFunction)(),
|
|
58
59
|
(0, createSubmissionEntity_1.createSubmissionEntityFunction)(),
|
|
60
|
+
(0, internalMaestroTest_1.createInternalEasMaestroTestFunction)(ctx),
|
|
59
61
|
];
|
|
60
62
|
if (ctx.hasBuildJob()) {
|
|
61
63
|
functions.push(...[
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"easFunctions.js","sourceRoot":"","sources":["../../src/steps/easFunctions.ts"],"names":[],"mappings":";;;AAIA,+DAA+E;AAC/E,mDAAmE;AACnE,yDAAwE;AACxE,uEAAuF;AACvF,mDAAmE;AACnE,yFAAyG;AACzG,6FAAkG;AAClG,mFAAwF;AACxF,iFAAsF;AACtF,qDAA0D;AAC1D,qGAA0G;AAC1G,iFAAsF;AACtF,yEAA8E;AAC9E,yFAA8F;AAC9F,yDAA8D;AAC9D,2EAA2F;AAC3F,qEAAqF;AACrF,+DAA+E;AAC/E,uIAA0I;AAC1I,yDAAyE;AACzE,mEAA8E;AAC9E,uEAAuF;AACvF,mGAAwG;AACxG,yDAAmE;AACnE,+EAAoF;AACpF,6DAAwE;AACxE,+CAA+D;AAC/D,mEAA8E;
|
|
1
|
+
{"version":3,"file":"easFunctions.js","sourceRoot":"","sources":["../../src/steps/easFunctions.ts"],"names":[],"mappings":";;;AAIA,+DAA+E;AAC/E,mDAAmE;AACnE,yDAAwE;AACxE,uEAAuF;AACvF,mDAAmE;AACnE,yFAAyG;AACzG,6FAAkG;AAClG,mFAAwF;AACxF,iFAAsF;AACtF,qDAA0D;AAC1D,qGAA0G;AAC1G,iFAAsF;AACtF,yEAA8E;AAC9E,yFAA8F;AAC9F,yDAA8D;AAC9D,2EAA2F;AAC3F,qEAAqF;AACrF,+DAA+E;AAC/E,uIAA0I;AAC1I,yDAAyE;AACzE,mEAA8E;AAC9E,uEAAuF;AACvF,mGAAwG;AACxG,yDAAmE;AACnE,+EAAoF;AACpF,6DAAwE;AACxE,+CAA+D;AAC/D,mEAA8E;AAC9E,yEAAuF;AAEvF,SAAgB,eAAe,CAAC,GAAuB;IACrD,MAAM,SAAS,GAAG;QAChB,IAAA,sCAA2B,GAAE;QAC7B,IAAA,iDAA8B,GAAE;QAChC,IAAA,kDAAiC,EAAC,GAAG,CAAC;QACtC,IAAA,2CAA6B,GAAE;QAC/B,IAAA,0DAAqC,GAAE;QACvC,IAAA,sCAA2B,GAAE;QAC7B,IAAA,2CAA2B,GAAE;QAC7B,IAAA,kCAAyB,GAAE;QAE3B,IAAA,qEAAqC,GAAE;QACvC,IAAA,2DAAgC,GAAE;QAClC,IAAA,yDAA+B,GAAE;QACjC,IAAA,sCAAwB,GAAE;QAC1B,IAAA,6BAAiB,GAAE;QACnB,IAAA,6EAAyC,GAAE;QAC3C,IAAA,yDAA+B,GAAE;QACjC,IAAA,iDAA2B,GAAE;QAC7B,IAAA,iEAAmC,GAAE;QACrC,IAAA,iCAAmB,GAAE;QACrB,IAAA,8DAAuC,GAAE;QACzC,IAAA,wDAAoC,GAAE;QACtC,IAAA,kDAAiC,GAAE;QAEnC,IAAA,4CAA8B,GAAE;QAChC,IAAA,iDAA8B,GAAE;QAEhC,IAAA,2EAAwC,GAAE;QAE1C,IAAA,uDAA8B,GAAE;QAEhC,IAAA,0DAAoC,EAAC,GAAG,CAAC;KAC1C,CAAC;IAEF,IAAI,GAAG,CAAC,WAAW,EAAE,EAAE,CAAC;QACtB,SAAS,CAAC,IAAI,CACZ,GAAG;YACD,IAAA,4EAA8C,EAAC,GAAG,CAAC;YACnD,IAAA,0DAAqC,EAAC,GAAG,CAAC;YAC1C,IAAA,6GAAwD,EAAC,GAAG,CAAC;SAC9D,CACF,CAAC;IACJ,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AA9CD,0CA8CC","sourcesContent":["import { BuildFunction } from '@expo/steps';\n\nimport { CustomBuildContext } from '../customBuildContext';\n\nimport { createUploadArtifactBuildFunction } from './functions/uploadArtifact';\nimport { createCheckoutBuildFunction } from './functions/checkout';\nimport { createSetUpNpmrcBuildFunction } from './functions/useNpmToken';\nimport { createInstallNodeModulesBuildFunction } from './functions/installNodeModules';\nimport { createPrebuildBuildFunction } from './functions/prebuild';\nimport { createFindAndUploadBuildArtifactsBuildFunction } from './functions/findAndUploadBuildArtifacts';\nimport { configureEASUpdateIfInstalledFunction } from './functions/configureEASUpdateIfInstalled';\nimport { injectAndroidCredentialsFunction } from './functions/injectAndroidCredentials';\nimport { configureAndroidVersionFunction } from './functions/configureAndroidVersion';\nimport { runGradleFunction } from './functions/runGradle';\nimport { resolveAppleTeamIdFromCredentialsFunction } from './functions/resolveAppleTeamIdFromCredentials';\nimport { configureIosCredentialsFunction } from './functions/configureIosCredentials';\nimport { configureIosVersionFunction } from './functions/configureIosVersion';\nimport { generateGymfileFromTemplateFunction } from './functions/generateGymfileFromTemplate';\nimport { runFastlaneFunction } from './functions/runFastlane';\nimport { createStartAndroidEmulatorBuildFunction } from './functions/startAndroidEmulator';\nimport { createStartIosSimulatorBuildFunction } from './functions/startIosSimulator';\nimport { createInstallMaestroBuildFunction } from './functions/installMaestro';\nimport { createGetCredentialsForBuildTriggeredByGithubIntegration } from './functions/getCredentialsForBuildTriggeredByGitHubIntegration';\nimport { createInstallPodsBuildFunction } from './functions/installPods';\nimport { createSendSlackMessageFunction } from './functions/sendSlackMessage';\nimport { createResolveBuildConfigBuildFunction } from './functions/resolveBuildConfig';\nimport { calculateEASUpdateRuntimeVersionFunction } from './functions/calculateEASUpdateRuntimeVersion';\nimport { eagerBundleBuildFunction } from './functions/eagerBundle';\nimport { createSubmissionEntityFunction } from './functions/createSubmissionEntity';\nimport { createDownloadBuildFunction } from './functions/downloadBuild';\nimport { createRepackBuildFunction } from './functions/repack';\nimport { createDownloadArtifactFunction } from './functions/downloadArtifact';\nimport { createInternalEasMaestroTestFunction } from './functions/internalMaestroTest';\n\nexport function getEasFunctions(ctx: CustomBuildContext): BuildFunction[] {\n const functions = [\n createCheckoutBuildFunction(),\n createDownloadArtifactFunction(),\n createUploadArtifactBuildFunction(ctx),\n createSetUpNpmrcBuildFunction(),\n createInstallNodeModulesBuildFunction(),\n createPrebuildBuildFunction(),\n createDownloadBuildFunction(),\n createRepackBuildFunction(),\n\n configureEASUpdateIfInstalledFunction(),\n injectAndroidCredentialsFunction(),\n configureAndroidVersionFunction(),\n eagerBundleBuildFunction(),\n runGradleFunction(),\n resolveAppleTeamIdFromCredentialsFunction(),\n configureIosCredentialsFunction(),\n configureIosVersionFunction(),\n generateGymfileFromTemplateFunction(),\n runFastlaneFunction(),\n createStartAndroidEmulatorBuildFunction(),\n createStartIosSimulatorBuildFunction(),\n createInstallMaestroBuildFunction(),\n\n createInstallPodsBuildFunction(),\n createSendSlackMessageFunction(),\n\n calculateEASUpdateRuntimeVersionFunction(),\n\n createSubmissionEntityFunction(),\n\n createInternalEasMaestroTestFunction(ctx),\n ];\n\n if (ctx.hasBuildJob()) {\n functions.push(\n ...[\n createFindAndUploadBuildArtifactsBuildFunction(ctx),\n createResolveBuildConfigBuildFunction(ctx),\n createGetCredentialsForBuildTriggeredByGithubIntegration(ctx),\n ]\n );\n }\n\n return functions;\n}\n"]}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BuildFunction } from '@expo/steps';
|
|
2
|
+
import { CustomBuildContext } from '../../customBuildContext';
|
|
3
|
+
export declare function createInternalEasMaestroTestFunction(ctx: CustomBuildContext): BuildFunction;
|
|
4
|
+
export declare function getMaestroTestCommand(params: {
|
|
5
|
+
flow_path: string;
|
|
6
|
+
include_tags: string | undefined;
|
|
7
|
+
exclude_tags: string | undefined;
|
|
8
|
+
output_format: string | undefined;
|
|
9
|
+
output_path: string | undefined;
|
|
10
|
+
}): [command: string, ...args: string[]];
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getMaestroTestCommand = exports.createInternalEasMaestroTestFunction = void 0;
|
|
7
|
+
const node_crypto_1 = require("node:crypto");
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const steps_1 = require("@expo/steps");
|
|
10
|
+
const zod_1 = require("zod");
|
|
11
|
+
const turtle_spawn_1 = __importDefault(require("@expo/turtle-spawn"));
|
|
12
|
+
const logger_1 = require("@expo/logger");
|
|
13
|
+
const results_1 = require("@expo/results");
|
|
14
|
+
const eas_build_job_1 = require("@expo/eas-build-job");
|
|
15
|
+
const IosSimulatorUtils_1 = require("../../utils/IosSimulatorUtils");
|
|
16
|
+
const AndroidEmulatorUtils_1 = require("../../utils/AndroidEmulatorUtils");
|
|
17
|
+
function createInternalEasMaestroTestFunction(ctx) {
|
|
18
|
+
return new steps_1.BuildFunction({
|
|
19
|
+
namespace: 'eas',
|
|
20
|
+
id: '__maestro_test',
|
|
21
|
+
inputProviders: [
|
|
22
|
+
steps_1.BuildStepInput.createProvider({
|
|
23
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
24
|
+
id: 'platform',
|
|
25
|
+
required: true,
|
|
26
|
+
}),
|
|
27
|
+
steps_1.BuildStepInput.createProvider({
|
|
28
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.JSON,
|
|
29
|
+
id: 'flow_paths',
|
|
30
|
+
required: true,
|
|
31
|
+
}),
|
|
32
|
+
steps_1.BuildStepInput.createProvider({
|
|
33
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.NUMBER,
|
|
34
|
+
id: 'retries',
|
|
35
|
+
defaultValue: 1,
|
|
36
|
+
required: false,
|
|
37
|
+
}),
|
|
38
|
+
steps_1.BuildStepInput.createProvider({
|
|
39
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
40
|
+
id: 'include_tags',
|
|
41
|
+
required: false,
|
|
42
|
+
}),
|
|
43
|
+
steps_1.BuildStepInput.createProvider({
|
|
44
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
45
|
+
id: 'exclude_tags',
|
|
46
|
+
required: false,
|
|
47
|
+
}),
|
|
48
|
+
steps_1.BuildStepInput.createProvider({
|
|
49
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.NUMBER,
|
|
50
|
+
id: 'shards',
|
|
51
|
+
defaultValue: 1,
|
|
52
|
+
required: false,
|
|
53
|
+
}),
|
|
54
|
+
steps_1.BuildStepInput.createProvider({
|
|
55
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.STRING,
|
|
56
|
+
id: 'output_format',
|
|
57
|
+
required: false,
|
|
58
|
+
}),
|
|
59
|
+
steps_1.BuildStepInput.createProvider({
|
|
60
|
+
allowedValueTypeName: steps_1.BuildStepInputValueTypeName.BOOLEAN,
|
|
61
|
+
id: 'record_screen',
|
|
62
|
+
defaultValue: false,
|
|
63
|
+
required: false,
|
|
64
|
+
}),
|
|
65
|
+
],
|
|
66
|
+
fn: async (stepCtx, { inputs: _inputs, env }) => {
|
|
67
|
+
console.log('maestroTest', _inputs);
|
|
68
|
+
// inputs come in form of { value: unknown }. Here we parse them into a typed and validated object.
|
|
69
|
+
const { platform, flow_paths, retries, include_tags, exclude_tags, shards, output_format, record_screen, } = zod_1.z
|
|
70
|
+
.object({
|
|
71
|
+
platform: zod_1.z.enum(['ios', 'android']),
|
|
72
|
+
flow_paths: zod_1.z.array(zod_1.z.string()),
|
|
73
|
+
retries: zod_1.z.number().default(1),
|
|
74
|
+
include_tags: zod_1.z.string().optional(),
|
|
75
|
+
exclude_tags: zod_1.z.string().optional(),
|
|
76
|
+
shards: zod_1.z.number().default(1),
|
|
77
|
+
output_format: zod_1.z.string().optional(),
|
|
78
|
+
record_screen: zod_1.z.boolean().default(false),
|
|
79
|
+
})
|
|
80
|
+
.parse(Object.fromEntries(Object.entries(_inputs).map(([key, value]) => [key, value.value])));
|
|
81
|
+
// TODO: Add support for shards. (Shouldn't be too difficult.)
|
|
82
|
+
if (shards > 1) {
|
|
83
|
+
stepCtx.logger.warn('Sharding support has been temporarily disabled. Running tests on a single shard.');
|
|
84
|
+
}
|
|
85
|
+
let sourceDeviceIdentifier;
|
|
86
|
+
switch (platform) {
|
|
87
|
+
case 'ios': {
|
|
88
|
+
const bootedDevices = await IosSimulatorUtils_1.IosSimulatorUtils.getAvailableDevicesAsync({
|
|
89
|
+
env,
|
|
90
|
+
filter: 'booted',
|
|
91
|
+
});
|
|
92
|
+
if (bootedDevices.length === 0) {
|
|
93
|
+
throw new Error('No booted iOS Simulator found.');
|
|
94
|
+
}
|
|
95
|
+
else if (bootedDevices.length > 1) {
|
|
96
|
+
throw new Error('Multiple booted iOS Simulators found.');
|
|
97
|
+
}
|
|
98
|
+
const device = bootedDevices[0];
|
|
99
|
+
stepCtx.logger.info(`Running tests on iOS Simulator: ${device.name}.`);
|
|
100
|
+
stepCtx.logger.info(`Preparing Simulator for tests...`);
|
|
101
|
+
await (0, steps_1.spawnAsync)('xcrun', ['simctl', 'shutdown', device.udid], {
|
|
102
|
+
logger: stepCtx.logger,
|
|
103
|
+
stdio: 'pipe',
|
|
104
|
+
});
|
|
105
|
+
sourceDeviceIdentifier = device.udid;
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
case 'android': {
|
|
109
|
+
const connectedDevices = await AndroidEmulatorUtils_1.AndroidEmulatorUtils.getAttachedDevicesAsync({ env });
|
|
110
|
+
if (connectedDevices.length === 0) {
|
|
111
|
+
throw new Error('No booted Android Emulator found.');
|
|
112
|
+
}
|
|
113
|
+
else if (connectedDevices.length > 1) {
|
|
114
|
+
throw new Error('Multiple booted Android Emulators found.');
|
|
115
|
+
}
|
|
116
|
+
const { serialId } = connectedDevices[0];
|
|
117
|
+
const adbEmuAvdNameResult = await (0, turtle_spawn_1.default)('adb', ['-s', serialId, 'emu', 'avd', 'name'], {
|
|
118
|
+
mode: logger_1.PipeMode.COMBINED,
|
|
119
|
+
env,
|
|
120
|
+
});
|
|
121
|
+
const avdName = adbEmuAvdNameResult.stdout
|
|
122
|
+
.replace(/\r\n/g, '\n')
|
|
123
|
+
.split('\n')[0];
|
|
124
|
+
stepCtx.logger.info(`Running tests on Android Emulator: ${avdName}.`);
|
|
125
|
+
stepCtx.logger.info(`Preparing Emulator for tests...`);
|
|
126
|
+
await (0, steps_1.spawnAsync)('adb', ['-s', serialId, 'emu', 'kill'], {
|
|
127
|
+
logger: stepCtx.logger,
|
|
128
|
+
stdio: 'pipe',
|
|
129
|
+
});
|
|
130
|
+
sourceDeviceIdentifier = avdName;
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
for (const [flowIndex, flowPath] of flow_paths.entries()) {
|
|
135
|
+
for (let retryIndex = 0; retryIndex < retries; retryIndex++) {
|
|
136
|
+
const localDeviceName = `eas-simulator-${flowIndex}-${retryIndex}`;
|
|
137
|
+
// If the test passes, but the recording fails, we don't want to make the test fail,
|
|
138
|
+
// so we return two separate results.
|
|
139
|
+
const { fnResult, recordingResult } = await withCleanDeviceAsync({
|
|
140
|
+
platform,
|
|
141
|
+
sourceDeviceIdentifier,
|
|
142
|
+
localDeviceName,
|
|
143
|
+
env,
|
|
144
|
+
logger: stepCtx.logger,
|
|
145
|
+
fn: async ({ deviceIdentifier }) => {
|
|
146
|
+
return await maybeWithScreenRecordingAsync({
|
|
147
|
+
shouldRecord: record_screen,
|
|
148
|
+
platform,
|
|
149
|
+
deviceIdentifier,
|
|
150
|
+
env,
|
|
151
|
+
logger: stepCtx.logger,
|
|
152
|
+
fn: async () => {
|
|
153
|
+
var _a;
|
|
154
|
+
const [command, ...args] = getMaestroTestCommand({
|
|
155
|
+
flow_path: flowPath,
|
|
156
|
+
include_tags,
|
|
157
|
+
exclude_tags,
|
|
158
|
+
output_format,
|
|
159
|
+
output_path: (_a = getOutputPathForOutputFormat({
|
|
160
|
+
outputFormat: output_format !== null && output_format !== void 0 ? output_format : 'noop',
|
|
161
|
+
env,
|
|
162
|
+
})) !== null && _a !== void 0 ? _a : undefined,
|
|
163
|
+
});
|
|
164
|
+
await (0, steps_1.spawnAsync)(command, args, {
|
|
165
|
+
logger: stepCtx.logger,
|
|
166
|
+
cwd: stepCtx.workingDirectory,
|
|
167
|
+
env,
|
|
168
|
+
stdio: 'pipe',
|
|
169
|
+
});
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
});
|
|
174
|
+
if (recordingResult.ok && recordingResult.value) {
|
|
175
|
+
try {
|
|
176
|
+
await ctx.runtimeApi.uploadArtifact({
|
|
177
|
+
logger: stepCtx.logger,
|
|
178
|
+
artifact: {
|
|
179
|
+
name: `Screen Recording (${flowPath}, retry ${retryIndex})`,
|
|
180
|
+
paths: [recordingResult.value],
|
|
181
|
+
type: eas_build_job_1.GenericArtifactType.OTHER,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
catch (err) {
|
|
186
|
+
stepCtx.logger.warn('Failed to upload screen recording.', err);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (fnResult.ok) {
|
|
190
|
+
stepCtx.logger.info(`Test passed.`);
|
|
191
|
+
// Break out of the retry loop.
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
stepCtx.logger.error(`Failed to run test on device: ${fnResult.reason}`);
|
|
195
|
+
stepCtx.logger.error(`Retrying...`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
},
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
exports.createInternalEasMaestroTestFunction = createInternalEasMaestroTestFunction;
|
|
202
|
+
function getMaestroTestCommand(params) {
|
|
203
|
+
let includeTagsFlag = '';
|
|
204
|
+
if (typeof params.include_tags === 'string') {
|
|
205
|
+
includeTagsFlag = `--include-tags=${params.include_tags}`;
|
|
206
|
+
}
|
|
207
|
+
let excludeTagsFlag = '';
|
|
208
|
+
if (typeof params.exclude_tags === 'string') {
|
|
209
|
+
excludeTagsFlag = `--exclude-tags=${params.exclude_tags}`;
|
|
210
|
+
}
|
|
211
|
+
let outputFormatFlags = [];
|
|
212
|
+
if (params.output_format) {
|
|
213
|
+
outputFormatFlags = [`--format=${params.output_format}`, `--output=${params.output_path}`];
|
|
214
|
+
}
|
|
215
|
+
return [
|
|
216
|
+
'maestro',
|
|
217
|
+
'test',
|
|
218
|
+
includeTagsFlag,
|
|
219
|
+
excludeTagsFlag,
|
|
220
|
+
...outputFormatFlags,
|
|
221
|
+
params.flow_path,
|
|
222
|
+
].flatMap((e) => e || []);
|
|
223
|
+
}
|
|
224
|
+
exports.getMaestroTestCommand = getMaestroTestCommand;
|
|
225
|
+
function getOutputPathForOutputFormat({ outputFormat, env, }) {
|
|
226
|
+
if (outputFormat.toLowerCase() === 'noop') {
|
|
227
|
+
return null;
|
|
228
|
+
}
|
|
229
|
+
let extension;
|
|
230
|
+
switch (outputFormat) {
|
|
231
|
+
case 'junit':
|
|
232
|
+
extension = 'xml';
|
|
233
|
+
break;
|
|
234
|
+
case 'html':
|
|
235
|
+
extension = 'html';
|
|
236
|
+
break;
|
|
237
|
+
default:
|
|
238
|
+
extension = null;
|
|
239
|
+
break;
|
|
240
|
+
}
|
|
241
|
+
return node_path_1.default.join(env.HOME, '.maestro', 'tests', [
|
|
242
|
+
'maestro-',
|
|
243
|
+
outputFormat,
|
|
244
|
+
'-',
|
|
245
|
+
(0, node_crypto_1.randomUUID)(),
|
|
246
|
+
// No . if no extension.
|
|
247
|
+
...(extension ? ['.', extension] : []),
|
|
248
|
+
].join(''));
|
|
249
|
+
}
|
|
250
|
+
async function withCleanDeviceAsync({ platform, sourceDeviceIdentifier, localDeviceName, env, logger, fn, }) {
|
|
251
|
+
// Clone and start the device
|
|
252
|
+
let localDeviceIdentifier;
|
|
253
|
+
switch (platform) {
|
|
254
|
+
case 'ios': {
|
|
255
|
+
logger.info(`Cloning iOS Simulator ${sourceDeviceIdentifier} to ${localDeviceName}...`);
|
|
256
|
+
await IosSimulatorUtils_1.IosSimulatorUtils.cloneAsync({
|
|
257
|
+
sourceDeviceIdentifier: sourceDeviceIdentifier,
|
|
258
|
+
destinationDeviceName: localDeviceName,
|
|
259
|
+
env,
|
|
260
|
+
});
|
|
261
|
+
logger.info(`Starting iOS Simulator ${localDeviceName}...`);
|
|
262
|
+
const { udid } = await IosSimulatorUtils_1.IosSimulatorUtils.startAsync({
|
|
263
|
+
deviceIdentifier: localDeviceName,
|
|
264
|
+
env,
|
|
265
|
+
});
|
|
266
|
+
logger.info(`Waiting for iOS Simulator ${localDeviceName} to be ready...`);
|
|
267
|
+
await IosSimulatorUtils_1.IosSimulatorUtils.waitForReadyAsync({
|
|
268
|
+
udid,
|
|
269
|
+
env,
|
|
270
|
+
});
|
|
271
|
+
localDeviceIdentifier = udid;
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
274
|
+
case 'android': {
|
|
275
|
+
logger.info(`Cloning Android Emulator ${sourceDeviceIdentifier} to ${localDeviceName}...`);
|
|
276
|
+
await AndroidEmulatorUtils_1.AndroidEmulatorUtils.cloneAsync({
|
|
277
|
+
sourceDeviceName: sourceDeviceIdentifier,
|
|
278
|
+
destinationDeviceName: localDeviceName,
|
|
279
|
+
env,
|
|
280
|
+
});
|
|
281
|
+
logger.info(`Starting Android Emulator ${localDeviceName}...`);
|
|
282
|
+
const { serialId } = await AndroidEmulatorUtils_1.AndroidEmulatorUtils.startAsync({
|
|
283
|
+
deviceName: localDeviceName,
|
|
284
|
+
env,
|
|
285
|
+
});
|
|
286
|
+
logger.info(`Waiting for Android Emulator ${localDeviceName} to be ready...`);
|
|
287
|
+
await AndroidEmulatorUtils_1.AndroidEmulatorUtils.waitForReadyAsync({
|
|
288
|
+
serialId,
|
|
289
|
+
env,
|
|
290
|
+
});
|
|
291
|
+
localDeviceIdentifier = serialId;
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
// Run the function
|
|
296
|
+
const fnResult = await (0, results_1.asyncResult)(fn({ deviceIdentifier: localDeviceIdentifier }));
|
|
297
|
+
// Stop the device
|
|
298
|
+
try {
|
|
299
|
+
switch (platform) {
|
|
300
|
+
case 'ios': {
|
|
301
|
+
logger.info(`Cleaning up ${localDeviceName}...`);
|
|
302
|
+
await IosSimulatorUtils_1.IosSimulatorUtils.deleteAsync({
|
|
303
|
+
udid: localDeviceIdentifier,
|
|
304
|
+
env,
|
|
305
|
+
});
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
case 'android': {
|
|
309
|
+
logger.info(`Cleaning up ${localDeviceName}...`);
|
|
310
|
+
await AndroidEmulatorUtils_1.AndroidEmulatorUtils.deleteAsync({
|
|
311
|
+
serialId: localDeviceIdentifier,
|
|
312
|
+
env,
|
|
313
|
+
});
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
catch (err) {
|
|
319
|
+
logger.error(`Error cleaning up device: ${err}`);
|
|
320
|
+
}
|
|
321
|
+
return fnResult.enforceValue();
|
|
322
|
+
}
|
|
323
|
+
/** Runs provided `fn` function, optionally wrapping it with starting and stopping screen recording. */
|
|
324
|
+
async function maybeWithScreenRecordingAsync({ shouldRecord, platform, deviceIdentifier, env, logger, fn, }) {
|
|
325
|
+
if (!shouldRecord) {
|
|
326
|
+
return { fnResult: await (0, results_1.asyncResult)(fn()), recordingResult: (0, results_1.result)(null) };
|
|
327
|
+
}
|
|
328
|
+
let recordingResult;
|
|
329
|
+
// Start screen recording
|
|
330
|
+
logger.info(`Starting screen recording on ${deviceIdentifier}...`);
|
|
331
|
+
switch (platform) {
|
|
332
|
+
case 'ios': {
|
|
333
|
+
recordingResult = await (0, results_1.asyncResult)(IosSimulatorUtils_1.IosSimulatorUtils.startScreenRecordingAsync({
|
|
334
|
+
udid: deviceIdentifier,
|
|
335
|
+
env,
|
|
336
|
+
}));
|
|
337
|
+
break;
|
|
338
|
+
}
|
|
339
|
+
case 'android': {
|
|
340
|
+
recordingResult = await (0, results_1.asyncResult)(AndroidEmulatorUtils_1.AndroidEmulatorUtils.startScreenRecordingAsync({
|
|
341
|
+
serialId: deviceIdentifier,
|
|
342
|
+
env,
|
|
343
|
+
}));
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
if (!recordingResult.ok) {
|
|
348
|
+
logger.warn('Failed to start screen recording.', recordingResult.reason);
|
|
349
|
+
}
|
|
350
|
+
// Run the function
|
|
351
|
+
const fnResult = await (0, results_1.asyncResult)(fn());
|
|
352
|
+
// If recording failed there's nothing to stop, so we return the results
|
|
353
|
+
if (!recordingResult.ok) {
|
|
354
|
+
return { fnResult, recordingResult: (0, results_1.result)(recordingResult.reason) };
|
|
355
|
+
}
|
|
356
|
+
// If recording started, finish it
|
|
357
|
+
try {
|
|
358
|
+
logger.info(`Stopping screen recording on ${deviceIdentifier}...`);
|
|
359
|
+
switch (platform) {
|
|
360
|
+
case 'ios': {
|
|
361
|
+
await IosSimulatorUtils_1.IosSimulatorUtils.stopScreenRecordingAsync({
|
|
362
|
+
recordingSpawn: recordingResult.value.recordingSpawn,
|
|
363
|
+
});
|
|
364
|
+
return {
|
|
365
|
+
fnResult,
|
|
366
|
+
// We know outputPath is defined, because startIosScreenRecording() should have filled it.
|
|
367
|
+
recordingResult: (0, results_1.result)(recordingResult.value.outputPath),
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
case 'android': {
|
|
371
|
+
const { outputPath } = await AndroidEmulatorUtils_1.AndroidEmulatorUtils.stopScreenRecordingAsync({
|
|
372
|
+
serialId: deviceIdentifier,
|
|
373
|
+
recordingSpawn: recordingResult.value.recordingSpawn,
|
|
374
|
+
env,
|
|
375
|
+
});
|
|
376
|
+
return { fnResult, recordingResult: (0, results_1.result)(outputPath) };
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
catch (err) {
|
|
381
|
+
logger.warn('Failed to stop screen recording.', err);
|
|
382
|
+
return { fnResult, recordingResult: (0, results_1.result)(err) };
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
//# sourceMappingURL=internalMaestroTest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internalMaestroTest.js","sourceRoot":"","sources":["../../../src/steps/functions/internalMaestroTest.ts"],"names":[],"mappings":";;;;;;AAAA,6CAAyC;AACzC,0DAA6B;AAE7B,uCAMqB;AACrB,6BAAwB;AACxB,sEAAsE;AACtE,yCAAgD;AAChD,2CAA4D;AAC5D,uDAA0D;AAG1D,qEAIuC;AACvC,2EAI0C;AAE1C,SAAgB,oCAAoC,CAAC,GAAuB;IAC1E,OAAO,IAAI,qBAAa,CAAC;QACvB,SAAS,EAAE,KAAK;QAChB,EAAE,EAAE,gBAAgB;QACpB,cAAc,EAAE;YACd,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,MAAM;gBACxD,EAAE,EAAE,UAAU;gBACd,QAAQ,EAAE,IAAI;aACf,CAAC;YACF,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,IAAI;gBACtD,EAAE,EAAE,YAAY;gBAChB,QAAQ,EAAE,IAAI;aACf,CAAC;YACF,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,MAAM;gBACxD,EAAE,EAAE,SAAS;gBACb,YAAY,EAAE,CAAC;gBACf,QAAQ,EAAE,KAAK;aAChB,CAAC;YACF,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,MAAM;gBACxD,EAAE,EAAE,cAAc;gBAClB,QAAQ,EAAE,KAAK;aAChB,CAAC;YACF,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,MAAM;gBACxD,EAAE,EAAE,cAAc;gBAClB,QAAQ,EAAE,KAAK;aAChB,CAAC;YACF,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,MAAM;gBACxD,EAAE,EAAE,QAAQ;gBACZ,YAAY,EAAE,CAAC;gBACf,QAAQ,EAAE,KAAK;aAChB,CAAC;YACF,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,MAAM;gBACxD,EAAE,EAAE,eAAe;gBACnB,QAAQ,EAAE,KAAK;aAChB,CAAC;YACF,sBAAc,CAAC,cAAc,CAAC;gBAC5B,oBAAoB,EAAE,mCAA2B,CAAC,OAAO;gBACzD,EAAE,EAAE,eAAe;gBACnB,YAAY,EAAE,KAAK;gBACnB,QAAQ,EAAE,KAAK;aAChB,CAAC;SACH;QACD,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE;YAC9C,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;YACpC,mGAAmG;YACnG,MAAM,EACJ,QAAQ,EACR,UAAU,EACV,OAAO,EACP,YAAY,EACZ,YAAY,EACZ,MAAM,EACN,aAAa,EACb,aAAa,GACd,GAAG,OAAC;iBACF,MAAM,CAAC;gBACN,QAAQ,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;gBACpC,UAAU,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;gBAC/B,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC9B,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;gBACnC,YAAY,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;gBACnC,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;gBAC7B,aAAa,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;gBACpC,aAAa,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;aAC1C,CAAC;iBACD,KAAK,CACJ,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CACtF,CAAC;YAEJ,8DAA8D;YAC9D,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,IAAI,CACjB,kFAAkF,CACnF,CAAC;YACJ,CAAC;YAED,IAAI,sBAAmE,CAAC;YAExE,QAAQ,QAAQ,EAAE,CAAC;gBACjB,KAAK,KAAK,CAAC,CAAC,CAAC;oBACX,MAAM,aAAa,GAAG,MAAM,qCAAiB,CAAC,wBAAwB,CAAC;wBACrE,GAAG;wBACH,MAAM,EAAE,QAAQ;qBACjB,CAAC,CAAC;oBACH,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC/B,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;oBACpD,CAAC;yBAAM,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACpC,MAAM,IAAI,KAAK,CAAC,uCAAuC,CAAC,CAAC;oBAC3D,CAAC;oBAED,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC;oBAChC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,mCAAmC,MAAM,CAAC,IAAI,GAAG,CAAC,CAAC;oBAEvE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;oBACxD,MAAM,IAAA,kBAAU,EAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE;wBAC7D,MAAM,EAAE,OAAO,CAAC,MAAM;wBACtB,KAAK,EAAE,MAAM;qBACd,CAAC,CAAC;oBAEH,sBAAsB,GAAG,MAAM,CAAC,IAAI,CAAC;oBACrC,MAAM;gBACR,CAAC;gBACD,KAAK,SAAS,CAAC,CAAC,CAAC;oBACf,MAAM,gBAAgB,GAAG,MAAM,2CAAoB,CAAC,uBAAuB,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC;oBACrF,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAClC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;oBACvD,CAAC;yBAAM,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACvC,MAAM,IAAI,KAAK,CAAC,0CAA0C,CAAC,CAAC;oBAC9D,CAAC;oBAED,MAAM,EAAE,QAAQ,EAAE,GAAG,gBAAgB,CAAC,CAAC,CAAC,CAAC;oBACzC,MAAM,mBAAmB,GAAG,MAAM,IAAA,sBAAK,EAAC,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE;wBACrF,IAAI,EAAE,iBAAQ,CAAC,QAAQ;wBACvB,GAAG;qBACJ,CAAC,CAAC;oBACH,MAAM,OAAO,GAAG,mBAAmB,CAAC,MAAM;yBACvC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC;yBACtB,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAA6B,CAAC;oBAC9C,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,sCAAsC,OAAO,GAAG,CAAC,CAAC;oBAEtE,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;oBACvD,MAAM,IAAA,kBAAU,EAAC,KAAK,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE;wBACvD,MAAM,EAAE,OAAO,CAAC,MAAM;wBACtB,KAAK,EAAE,MAAM;qBACd,CAAC,CAAC;oBAEH,sBAAsB,GAAG,OAAO,CAAC;oBACjC,MAAM;gBACR,CAAC;YACH,CAAC;YAED,KAAK,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,IAAI,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC;gBACzD,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,OAAO,EAAE,UAAU,EAAE,EAAE,CAAC;oBAC5D,MAAM,eAAe,GAAG,iBAAiB,SAAS,IAAI,UAAU,EAEpC,CAAC;oBAE7B,oFAAoF;oBACpF,qCAAqC;oBACrC,MAAM,EAAE,QAAQ,EAAE,eAAe,EAAE,GAAG,MAAM,oBAAoB,CAAC;wBAC/D,QAAQ;wBACR,sBAAsB;wBACtB,eAAe;wBACf,GAAG;wBACH,MAAM,EAAE,OAAO,CAAC,MAAM;wBACtB,EAAE,EAAE,KAAK,EAAE,EAAE,gBAAgB,EAAE,EAAE,EAAE;4BACjC,OAAO,MAAM,6BAA6B,CAAC;gCACzC,YAAY,EAAE,aAAa;gCAC3B,QAAQ;gCACR,gBAAgB;gCAChB,GAAG;gCACH,MAAM,EAAE,OAAO,CAAC,MAAM;gCACtB,EAAE,EAAE,KAAK,IAAI,EAAE;;oCACb,MAAM,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,qBAAqB,CAAC;wCAC/C,SAAS,EAAE,QAAQ;wCACnB,YAAY;wCACZ,YAAY;wCACZ,aAAa;wCACb,WAAW,EACT,MAAA,4BAA4B,CAAC;4CAC3B,YAAY,EAAE,aAAa,aAAb,aAAa,cAAb,aAAa,GAAI,MAAM;4CACrC,GAAG;yCACJ,CAAC,mCAAI,SAAS;qCAClB,CAAC,CAAC;oCAEH,MAAM,IAAA,kBAAU,EAAC,OAAO,EAAE,IAAI,EAAE;wCAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;wCACtB,GAAG,EAAE,OAAO,CAAC,gBAAgB;wCAC7B,GAAG;wCACH,KAAK,EAAE,MAAM;qCACd,CAAC,CAAC;gCACL,CAAC;6BACF,CAAC,CAAC;wBACL,CAAC;qBACF,CAAC,CAAC;oBAEH,IAAI,eAAe,CAAC,EAAE,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC;wBAChD,IAAI,CAAC;4BACH,MAAM,GAAG,CAAC,UAAU,CAAC,cAAc,CAAC;gCAClC,MAAM,EAAE,OAAO,CAAC,MAAM;gCACtB,QAAQ,EAAE;oCACR,IAAI,EAAE,qBAAqB,QAAQ,WAAW,UAAU,GAAG;oCAC3D,KAAK,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC;oCAC9B,IAAI,EAAE,mCAAmB,CAAC,KAAK;iCAChC;6BACF,CAAC,CAAC;wBACL,CAAC;wBAAC,OAAO,GAAG,EAAE,CAAC;4BACb,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;wBACjE,CAAC;oBACH,CAAC;oBAED,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;wBAChB,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;wBACpC,+BAA+B;wBAC/B,MAAM;oBACR,CAAC;oBAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,iCAAiC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;oBACzE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;gBACtC,CAAC;YACH,CAAC;QACH,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAlND,oFAkNC;AAED,SAAgB,qBAAqB,CAAC,MAMrC;IACC,IAAI,eAAe,GAAG,EAAE,CAAC;IACzB,IAAI,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC5C,eAAe,GAAG,kBAAkB,MAAM,CAAC,YAAY,EAAE,CAAC;IAC5D,CAAC;IAED,IAAI,eAAe,GAAG,EAAE,CAAC;IACzB,IAAI,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QAC5C,eAAe,GAAG,kBAAkB,MAAM,CAAC,YAAY,EAAE,CAAC;IAC5D,CAAC;IAED,IAAI,iBAAiB,GAAa,EAAE,CAAC;IACrC,IAAI,MAAM,CAAC,aAAa,EAAE,CAAC;QACzB,iBAAiB,GAAG,CAAC,YAAY,MAAM,CAAC,aAAa,EAAE,EAAE,YAAY,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7F,CAAC;IAED,OAAO;QACL,SAAS;QACT,MAAM;QACN,eAAe;QACf,eAAe;QACf,GAAG,iBAAiB;QACpB,MAAM,CAAC,SAAS;KACjB,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAyC,CAAC;AACpE,CAAC;AA9BD,sDA8BC;AAED,SAAS,4BAA4B,CAAC,EACpC,YAAY,EACZ,GAAG,GAIJ;IACC,IAAI,YAAY,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,IAAI,SAAwB,CAAC;IAC7B,QAAQ,YAAY,EAAE,CAAC;QACrB,KAAK,OAAO;YACV,SAAS,GAAG,KAAK,CAAC;YAClB,MAAM;QACR,KAAK,MAAM;YACT,SAAS,GAAG,MAAM,CAAC;YACnB,MAAM;QACR;YACE,SAAS,GAAG,IAAI,CAAC;YACjB,MAAM;IACV,CAAC;IAED,OAAO,mBAAI,CAAC,IAAI,CACd,GAAG,CAAC,IAAK,EACT,UAAU,EACV,OAAO,EACP;QACE,UAAU;QACV,YAAY;QACZ,GAAG;QACH,IAAA,wBAAU,GAAE;QACZ,wBAAwB;QACxB,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KACvC,CAAC,IAAI,CAAC,EAAE,CAAC,CACX,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAU,EAC3C,QAAQ,EACR,sBAAsB,EACtB,eAAe,EACf,GAAG,EACH,MAAM,EACN,EAAE,GAYH;IACC,6BAA6B;IAE7B,IAAI,qBAA+D,CAAC;IAEpE,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,MAAM,CAAC,IAAI,CAAC,yBAAyB,sBAAsB,OAAO,eAAe,KAAK,CAAC,CAAC;YACxF,MAAM,qCAAiB,CAAC,UAAU,CAAC;gBACjC,sBAAsB,EAAE,sBAA0C;gBAClE,qBAAqB,EAAE,eAAmC;gBAC1D,GAAG;aACJ,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,0BAA0B,eAAe,KAAK,CAAC,CAAC;YAC5D,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,qCAAiB,CAAC,UAAU,CAAC;gBAClD,gBAAgB,EAAE,eAAmC;gBACrD,GAAG;aACJ,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,6BAA6B,eAAe,iBAAiB,CAAC,CAAC;YAC3E,MAAM,qCAAiB,CAAC,iBAAiB,CAAC;gBACxC,IAAI;gBACJ,GAAG;aACJ,CAAC,CAAC;YACH,qBAAqB,GAAG,IAAI,CAAC;YAC7B,MAAM;QACR,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,MAAM,CAAC,IAAI,CAAC,4BAA4B,sBAAsB,OAAO,eAAe,KAAK,CAAC,CAAC;YAC3F,MAAM,2CAAoB,CAAC,UAAU,CAAC;gBACpC,gBAAgB,EAAE,sBAAkD;gBACpE,qBAAqB,EAAE,eAA2C;gBAClE,GAAG;aACJ,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,6BAA6B,eAAe,KAAK,CAAC,CAAC;YAC/D,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,2CAAoB,CAAC,UAAU,CAAC;gBACzD,UAAU,EAAE,eAA2C;gBACvD,GAAG;aACJ,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,gCAAgC,eAAe,iBAAiB,CAAC,CAAC;YAC9E,MAAM,2CAAoB,CAAC,iBAAiB,CAAC;gBAC3C,QAAQ;gBACR,GAAG;aACJ,CAAC,CAAC;YACH,qBAAqB,GAAG,QAAQ,CAAC;YACjC,MAAM;QACR,CAAC;IACH,CAAC;IAED,mBAAmB;IAEnB,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAW,EAAC,EAAE,CAAC,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC;IAEpF,kBAAkB;IAElB,IAAI,CAAC;QACH,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,CAAC,IAAI,CAAC,eAAe,eAAe,KAAK,CAAC,CAAC;gBACjD,MAAM,qCAAiB,CAAC,WAAW,CAAC;oBAClC,IAAI,EAAE,qBAAyC;oBAC/C,GAAG;iBACJ,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,CAAC,IAAI,CAAC,eAAe,eAAe,KAAK,CAAC,CAAC;gBACjD,MAAM,2CAAoB,CAAC,WAAW,CAAC;oBACrC,QAAQ,EAAE,qBAA8C;oBACxD,GAAG;iBACJ,CAAC,CAAC;gBACH,MAAM;YACR,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,KAAK,CAAC,6BAA6B,GAAG,EAAE,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,QAAQ,CAAC,YAAY,EAAE,CAAC;AACjC,CAAC;AAED,uGAAuG;AACvG,KAAK,UAAU,6BAA6B,CAAU,EACpD,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,GAAG,EACH,MAAM,EACN,EAAE,GAUH;IACC,IAAI,CAAC,YAAY,EAAE,CAAC;QAClB,OAAO,EAAE,QAAQ,EAAE,MAAM,IAAA,qBAAW,EAAC,EAAE,EAAE,CAAC,EAAE,eAAe,EAAE,IAAA,gBAAM,EAAC,IAAI,CAAC,EAAE,CAAC;IAC9E,CAAC;IAED,IAAI,eAGF,CAAC;IAEH,yBAAyB;IAEzB,MAAM,CAAC,IAAI,CAAC,gCAAgC,gBAAgB,KAAK,CAAC,CAAC;IAEnE,QAAQ,QAAQ,EAAE,CAAC;QACjB,KAAK,KAAK,CAAC,CAAC,CAAC;YACX,eAAe,GAAG,MAAM,IAAA,qBAAW,EACjC,qCAAiB,CAAC,yBAAyB,CAAC;gBAC1C,IAAI,EAAE,gBAAoC;gBAC1C,GAAG;aACJ,CAAC,CACH,CAAC;YACF,MAAM;QACR,CAAC;QACD,KAAK,SAAS,CAAC,CAAC,CAAC;YACf,eAAe,GAAG,MAAM,IAAA,qBAAW,EACjC,2CAAoB,CAAC,yBAAyB,CAAC;gBAC7C,QAAQ,EAAE,gBAAyC;gBACnD,GAAG;aACJ,CAAC,CACH,CAAC;YACF,MAAM;QACR,CAAC;IACH,CAAC;IAED,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;QACxB,MAAM,CAAC,IAAI,CAAC,mCAAmC,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3E,CAAC;IAED,mBAAmB;IAEnB,MAAM,QAAQ,GAAG,MAAM,IAAA,qBAAW,EAAC,EAAE,EAAE,CAAC,CAAC;IAEzC,wEAAwE;IAExE,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;QACxB,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAA,gBAAM,EAAC,eAAe,CAAC,MAAM,CAAC,EAAE,CAAC;IACvE,CAAC;IAED,kCAAkC;IAElC,IAAI,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,gCAAgC,gBAAgB,KAAK,CAAC,CAAC;QAEnE,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,qCAAiB,CAAC,wBAAwB,CAAC;oBAC/C,cAAc,EAAE,eAAe,CAAC,KAAK,CAAC,cAAc;iBACrD,CAAC,CAAC;gBACH,OAAO;oBACL,QAAQ;oBACR,0FAA0F;oBAC1F,eAAe,EAAE,IAAA,gBAAM,EAAC,eAAe,CAAC,KAAK,CAAC,UAAW,CAAC;iBAC3D,CAAC;YACJ,CAAC;YACD,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,2CAAoB,CAAC,wBAAwB,CAAC;oBACzE,QAAQ,EAAE,gBAAyC;oBACnD,cAAc,EAAE,eAAe,CAAC,KAAK,CAAC,cAAc;oBACpD,GAAG;iBACJ,CAAC,CAAC;gBACH,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAA,gBAAM,EAAC,UAAU,CAAC,EAAE,CAAC;YAC3D,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,kCAAkC,EAAE,GAAG,CAAC,CAAC;QAErD,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,IAAA,gBAAM,EAAC,GAAY,CAAC,EAAE,CAAC;IAC7D,CAAC;AACH,CAAC","sourcesContent":["import { randomUUID } from 'node:crypto';\nimport path from 'node:path';\n\nimport {\n BuildFunction,\n BuildStepEnv,\n BuildStepInput,\n BuildStepInputValueTypeName,\n spawnAsync,\n} from '@expo/steps';\nimport { z } from 'zod';\nimport spawn, { SpawnPromise, SpawnResult } from '@expo/turtle-spawn';\nimport { PipeMode, bunyan } from '@expo/logger';\nimport { Result, asyncResult, result } from '@expo/results';\nimport { GenericArtifactType } from '@expo/eas-build-job';\n\nimport { CustomBuildContext } from '../../customBuildContext';\nimport {\n IosSimulatorName,\n IosSimulatorUtils,\n IosSimulatorUuid,\n} from '../../utils/IosSimulatorUtils';\nimport {\n AndroidDeviceSerialId,\n AndroidEmulatorUtils,\n AndroidVirtualDeviceName,\n} from '../../utils/AndroidEmulatorUtils';\n\nexport function createInternalEasMaestroTestFunction(ctx: CustomBuildContext): BuildFunction {\n return new BuildFunction({\n namespace: 'eas',\n id: '__maestro_test',\n inputProviders: [\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n id: 'platform',\n required: true,\n }),\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.JSON,\n id: 'flow_paths',\n required: true,\n }),\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,\n id: 'retries',\n defaultValue: 1,\n required: false,\n }),\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n id: 'include_tags',\n required: false,\n }),\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n id: 'exclude_tags',\n required: false,\n }),\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.NUMBER,\n id: 'shards',\n defaultValue: 1,\n required: false,\n }),\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.STRING,\n id: 'output_format',\n required: false,\n }),\n BuildStepInput.createProvider({\n allowedValueTypeName: BuildStepInputValueTypeName.BOOLEAN,\n id: 'record_screen',\n defaultValue: false,\n required: false,\n }),\n ],\n fn: async (stepCtx, { inputs: _inputs, env }) => {\n console.log('maestroTest', _inputs);\n // inputs come in form of { value: unknown }. Here we parse them into a typed and validated object.\n const {\n platform,\n flow_paths,\n retries,\n include_tags,\n exclude_tags,\n shards,\n output_format,\n record_screen,\n } = z\n .object({\n platform: z.enum(['ios', 'android']),\n flow_paths: z.array(z.string()),\n retries: z.number().default(1),\n include_tags: z.string().optional(),\n exclude_tags: z.string().optional(),\n shards: z.number().default(1),\n output_format: z.string().optional(),\n record_screen: z.boolean().default(false),\n })\n .parse(\n Object.fromEntries(Object.entries(_inputs).map(([key, value]) => [key, value.value]))\n );\n\n // TODO: Add support for shards. (Shouldn't be too difficult.)\n if (shards > 1) {\n stepCtx.logger.warn(\n 'Sharding support has been temporarily disabled. Running tests on a single shard.'\n );\n }\n\n let sourceDeviceIdentifier: IosSimulatorUuid | AndroidVirtualDeviceName;\n\n switch (platform) {\n case 'ios': {\n const bootedDevices = await IosSimulatorUtils.getAvailableDevicesAsync({\n env,\n filter: 'booted',\n });\n if (bootedDevices.length === 0) {\n throw new Error('No booted iOS Simulator found.');\n } else if (bootedDevices.length > 1) {\n throw new Error('Multiple booted iOS Simulators found.');\n }\n\n const device = bootedDevices[0];\n stepCtx.logger.info(`Running tests on iOS Simulator: ${device.name}.`);\n\n stepCtx.logger.info(`Preparing Simulator for tests...`);\n await spawnAsync('xcrun', ['simctl', 'shutdown', device.udid], {\n logger: stepCtx.logger,\n stdio: 'pipe',\n });\n\n sourceDeviceIdentifier = device.udid;\n break;\n }\n case 'android': {\n const connectedDevices = await AndroidEmulatorUtils.getAttachedDevicesAsync({ env });\n if (connectedDevices.length === 0) {\n throw new Error('No booted Android Emulator found.');\n } else if (connectedDevices.length > 1) {\n throw new Error('Multiple booted Android Emulators found.');\n }\n\n const { serialId } = connectedDevices[0];\n const adbEmuAvdNameResult = await spawn('adb', ['-s', serialId, 'emu', 'avd', 'name'], {\n mode: PipeMode.COMBINED,\n env,\n });\n const avdName = adbEmuAvdNameResult.stdout\n .replace(/\\r\\n/g, '\\n')\n .split('\\n')[0] as AndroidVirtualDeviceName;\n stepCtx.logger.info(`Running tests on Android Emulator: ${avdName}.`);\n\n stepCtx.logger.info(`Preparing Emulator for tests...`);\n await spawnAsync('adb', ['-s', serialId, 'emu', 'kill'], {\n logger: stepCtx.logger,\n stdio: 'pipe',\n });\n\n sourceDeviceIdentifier = avdName;\n break;\n }\n }\n\n for (const [flowIndex, flowPath] of flow_paths.entries()) {\n for (let retryIndex = 0; retryIndex < retries; retryIndex++) {\n const localDeviceName = `eas-simulator-${flowIndex}-${retryIndex}` as\n | IosSimulatorName\n | AndroidVirtualDeviceName;\n\n // If the test passes, but the recording fails, we don't want to make the test fail,\n // so we return two separate results.\n const { fnResult, recordingResult } = await withCleanDeviceAsync({\n platform,\n sourceDeviceIdentifier,\n localDeviceName,\n env,\n logger: stepCtx.logger,\n fn: async ({ deviceIdentifier }) => {\n return await maybeWithScreenRecordingAsync({\n shouldRecord: record_screen,\n platform,\n deviceIdentifier,\n env,\n logger: stepCtx.logger,\n fn: async () => {\n const [command, ...args] = getMaestroTestCommand({\n flow_path: flowPath,\n include_tags,\n exclude_tags,\n output_format,\n output_path:\n getOutputPathForOutputFormat({\n outputFormat: output_format ?? 'noop',\n env,\n }) ?? undefined,\n });\n\n await spawnAsync(command, args, {\n logger: stepCtx.logger,\n cwd: stepCtx.workingDirectory,\n env,\n stdio: 'pipe',\n });\n },\n });\n },\n });\n\n if (recordingResult.ok && recordingResult.value) {\n try {\n await ctx.runtimeApi.uploadArtifact({\n logger: stepCtx.logger,\n artifact: {\n name: `Screen Recording (${flowPath}, retry ${retryIndex})`,\n paths: [recordingResult.value],\n type: GenericArtifactType.OTHER,\n },\n });\n } catch (err) {\n stepCtx.logger.warn('Failed to upload screen recording.', err);\n }\n }\n\n if (fnResult.ok) {\n stepCtx.logger.info(`Test passed.`);\n // Break out of the retry loop.\n break;\n }\n\n stepCtx.logger.error(`Failed to run test on device: ${fnResult.reason}`);\n stepCtx.logger.error(`Retrying...`);\n }\n }\n },\n });\n}\n\nexport function getMaestroTestCommand(params: {\n flow_path: string;\n include_tags: string | undefined;\n exclude_tags: string | undefined;\n output_format: string | undefined;\n output_path: string | undefined;\n}): [command: string, ...args: string[]] {\n let includeTagsFlag = '';\n if (typeof params.include_tags === 'string') {\n includeTagsFlag = `--include-tags=${params.include_tags}`;\n }\n\n let excludeTagsFlag = '';\n if (typeof params.exclude_tags === 'string') {\n excludeTagsFlag = `--exclude-tags=${params.exclude_tags}`;\n }\n\n let outputFormatFlags: string[] = [];\n if (params.output_format) {\n outputFormatFlags = [`--format=${params.output_format}`, `--output=${params.output_path}`];\n }\n\n return [\n 'maestro',\n 'test',\n includeTagsFlag,\n excludeTagsFlag,\n ...outputFormatFlags,\n params.flow_path,\n ].flatMap((e) => e || []) as [command: string, ...args: string[]];\n}\n\nfunction getOutputPathForOutputFormat({\n outputFormat,\n env,\n}: {\n outputFormat: string;\n env: BuildStepEnv;\n}): string | null {\n if (outputFormat.toLowerCase() === 'noop') {\n return null;\n }\n\n let extension: string | null;\n switch (outputFormat) {\n case 'junit':\n extension = 'xml';\n break;\n case 'html':\n extension = 'html';\n break;\n default:\n extension = null;\n break;\n }\n\n return path.join(\n env.HOME!,\n '.maestro',\n 'tests',\n [\n 'maestro-',\n outputFormat,\n '-',\n randomUUID(),\n // No . if no extension.\n ...(extension ? ['.', extension] : []),\n ].join('')\n );\n}\n\nasync function withCleanDeviceAsync<TResult>({\n platform,\n sourceDeviceIdentifier,\n localDeviceName,\n env,\n logger,\n fn,\n}: {\n env: BuildStepEnv;\n logger: bunyan;\n platform: 'ios' | 'android';\n sourceDeviceIdentifier: IosSimulatorUuid | AndroidVirtualDeviceName;\n localDeviceName: IosSimulatorName | AndroidVirtualDeviceName;\n fn: ({\n deviceIdentifier,\n }: {\n deviceIdentifier: IosSimulatorUuid | AndroidDeviceSerialId;\n }) => Promise<TResult>;\n}): Promise<TResult> {\n // Clone and start the device\n\n let localDeviceIdentifier: IosSimulatorUuid | AndroidDeviceSerialId;\n\n switch (platform) {\n case 'ios': {\n logger.info(`Cloning iOS Simulator ${sourceDeviceIdentifier} to ${localDeviceName}...`);\n await IosSimulatorUtils.cloneAsync({\n sourceDeviceIdentifier: sourceDeviceIdentifier as IosSimulatorUuid,\n destinationDeviceName: localDeviceName as IosSimulatorName,\n env,\n });\n logger.info(`Starting iOS Simulator ${localDeviceName}...`);\n const { udid } = await IosSimulatorUtils.startAsync({\n deviceIdentifier: localDeviceName as IosSimulatorName,\n env,\n });\n logger.info(`Waiting for iOS Simulator ${localDeviceName} to be ready...`);\n await IosSimulatorUtils.waitForReadyAsync({\n udid,\n env,\n });\n localDeviceIdentifier = udid;\n break;\n }\n case 'android': {\n logger.info(`Cloning Android Emulator ${sourceDeviceIdentifier} to ${localDeviceName}...`);\n await AndroidEmulatorUtils.cloneAsync({\n sourceDeviceName: sourceDeviceIdentifier as AndroidVirtualDeviceName,\n destinationDeviceName: localDeviceName as AndroidVirtualDeviceName,\n env,\n });\n logger.info(`Starting Android Emulator ${localDeviceName}...`);\n const { serialId } = await AndroidEmulatorUtils.startAsync({\n deviceName: localDeviceName as AndroidVirtualDeviceName,\n env,\n });\n logger.info(`Waiting for Android Emulator ${localDeviceName} to be ready...`);\n await AndroidEmulatorUtils.waitForReadyAsync({\n serialId,\n env,\n });\n localDeviceIdentifier = serialId;\n break;\n }\n }\n\n // Run the function\n\n const fnResult = await asyncResult(fn({ deviceIdentifier: localDeviceIdentifier }));\n\n // Stop the device\n\n try {\n switch (platform) {\n case 'ios': {\n logger.info(`Cleaning up ${localDeviceName}...`);\n await IosSimulatorUtils.deleteAsync({\n udid: localDeviceIdentifier as IosSimulatorUuid,\n env,\n });\n break;\n }\n case 'android': {\n logger.info(`Cleaning up ${localDeviceName}...`);\n await AndroidEmulatorUtils.deleteAsync({\n serialId: localDeviceIdentifier as AndroidDeviceSerialId,\n env,\n });\n break;\n }\n }\n } catch (err) {\n logger.error(`Error cleaning up device: ${err}`);\n }\n\n return fnResult.enforceValue();\n}\n\n/** Runs provided `fn` function, optionally wrapping it with starting and stopping screen recording. */\nasync function maybeWithScreenRecordingAsync<TResult>({\n shouldRecord,\n platform,\n deviceIdentifier,\n env,\n logger,\n fn,\n}: {\n // As weird as it is, it's more convenient to have this function like `maybeWith...`\n // than \"withScreenRecordingAsync\" and `withScreenRecordingAsync(fn)` vs `fn` in the caller.\n shouldRecord: boolean;\n platform: 'ios' | 'android';\n deviceIdentifier: IosSimulatorUuid | AndroidDeviceSerialId;\n env: BuildStepEnv;\n logger: bunyan;\n fn: () => Promise<TResult>;\n}): Promise<{ fnResult: Result<TResult>; recordingResult: Result<string | null> }> {\n if (!shouldRecord) {\n return { fnResult: await asyncResult(fn()), recordingResult: result(null) };\n }\n\n let recordingResult: Result<{\n recordingSpawn: SpawnPromise<SpawnResult>;\n outputPath?: string;\n }>;\n\n // Start screen recording\n\n logger.info(`Starting screen recording on ${deviceIdentifier}...`);\n\n switch (platform) {\n case 'ios': {\n recordingResult = await asyncResult(\n IosSimulatorUtils.startScreenRecordingAsync({\n udid: deviceIdentifier as IosSimulatorUuid,\n env,\n })\n );\n break;\n }\n case 'android': {\n recordingResult = await asyncResult(\n AndroidEmulatorUtils.startScreenRecordingAsync({\n serialId: deviceIdentifier as AndroidDeviceSerialId,\n env,\n })\n );\n break;\n }\n }\n\n if (!recordingResult.ok) {\n logger.warn('Failed to start screen recording.', recordingResult.reason);\n }\n\n // Run the function\n\n const fnResult = await asyncResult(fn());\n\n // If recording failed there's nothing to stop, so we return the results\n\n if (!recordingResult.ok) {\n return { fnResult, recordingResult: result(recordingResult.reason) };\n }\n\n // If recording started, finish it\n\n try {\n logger.info(`Stopping screen recording on ${deviceIdentifier}...`);\n\n switch (platform) {\n case 'ios': {\n await IosSimulatorUtils.stopScreenRecordingAsync({\n recordingSpawn: recordingResult.value.recordingSpawn,\n });\n return {\n fnResult,\n // We know outputPath is defined, because startIosScreenRecording() should have filled it.\n recordingResult: result(recordingResult.value.outputPath!),\n };\n }\n case 'android': {\n const { outputPath } = await AndroidEmulatorUtils.stopScreenRecordingAsync({\n serialId: deviceIdentifier as AndroidDeviceSerialId,\n recordingSpawn: recordingResult.value.recordingSpawn,\n env,\n });\n return { fnResult, recordingResult: result(outputPath) };\n }\n }\n } catch (err) {\n logger.warn('Failed to stop screen recording.', err);\n\n return { fnResult, recordingResult: result(err as Error) };\n }\n}\n"]}
|