@devicecloud.dev/dcd 4.4.3 → 4.4.5

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
@@ -1,5 +1,11 @@
1
1
  # devicecloud.dev CLI
2
2
 
3
+ > **Notice:** This CLI is being replaced by a new standalone repository at
4
+ > [moropo-com/cli](https://github.com/moropo-com/cli). Active development,
5
+ > releases, and new features (including `dcd login`) live there. The version
6
+ > in this directory is retained for historical reference and will be removed
7
+ > once the migration is complete.
8
+
3
9
  ---
4
10
 
5
11
  One line swap out for Maestro Cloud
@@ -172,6 +172,14 @@ class Cloud extends core_1.Command {
172
172
  this.error(`Maestro version ${resolvedMaestroVersion} is no longer supported. ` +
173
173
  `Please upgrade to a newer version. See: https://docs.devicecloud.dev/configuration/maestro-versions`);
174
174
  }
175
+ const DEPRECATED_MAESTRO_VERSIONS = ['1.39.1', '2.4.0'];
176
+ if (DEPRECATED_MAESTRO_VERSIONS.includes(resolvedMaestroVersion)) {
177
+ this.log(`\n${styling_1.dividers.light}\n` +
178
+ `${styling_1.colors.warning('⚠')} ${styling_1.colors.bold('Deprecation Warning')}\n` +
179
+ styling_1.colors.dim(` Maestro version ${resolvedMaestroVersion} is deprecated and will be removed in a future release.\n`) +
180
+ styling_1.colors.dim(` Please upgrade to a newer version. See: `) + styling_1.colors.info('https://docs.devicecloud.dev/configuration/maestro-versions') + `\n` +
181
+ `${styling_1.dividers.light}\n`);
182
+ }
175
183
  if (retry && retry > 2) {
176
184
  this.log(styling_1.colors.warning('⚠') + ' ' + styling_1.colors.dim("Retries are now free of charge but limited to 2. If your test is still failing after 2 retries, please ask for help on Discord."));
177
185
  flags.retry = 2;
@@ -49,6 +49,6 @@ exports.deviceFlags = {
49
49
  }),
50
50
  'disable-animations': core_1.Flags.boolean({
51
51
  default: false,
52
- description: '[Android only] Disable device animations during test execution. This reduces CPU load and may improve test reliability on resource-constrained runners.',
52
+ description: 'Disable device animations during test execution. On Android, disables system animation scales. On iOS, enables Reduce Motion. Reduces CPU load and may improve test reliability.',
53
53
  }),
54
54
  };
@@ -14,6 +14,14 @@ interface IWorkspaceConfig {
14
14
  includeTags?: null | string[];
15
15
  local?: ILocal | null;
16
16
  notifications?: INotificationsConfig;
17
+ platform?: {
18
+ android?: {
19
+ disableAnimations?: boolean;
20
+ };
21
+ ios?: {
22
+ disableAnimations?: boolean;
23
+ };
24
+ };
17
25
  }
18
26
  /** Local execution configuration */
19
27
  interface ILocal {
@@ -92,9 +92,10 @@ function extractDeviceCloudOverrides(config) {
92
92
  /**
93
93
  * Generate execution plan for a single flow file
94
94
  * @param normalizedInput - Normalized path to the flow file
95
+ * @param configFile - Optional custom config file path
95
96
  * @returns Execution plan for the single file with dependencies
96
97
  */
97
- async function planSingleFile(normalizedInput) {
98
+ async function planSingleFile(normalizedInput, configFile) {
98
99
  if (normalizedInput.endsWith('config.yaml') ||
99
100
  normalizedInput.endsWith('config.yml')) {
100
101
  throw new Error('If using config.yaml, pass the workspace folder path, not the config file or a custom path via --config');
@@ -106,6 +107,14 @@ async function planSingleFile(normalizedInput) {
106
107
  flowMetadata[normalizedInput] = config;
107
108
  flowOverrides[normalizedInput] = extractDeviceCloudOverrides(config);
108
109
  }
110
+ let workspaceConfig;
111
+ if (configFile) {
112
+ const configFilePath = path.resolve(process.cwd(), configFile);
113
+ if (!fs.existsSync(configFilePath)) {
114
+ throw new Error(`Config file does not exist: ${configFilePath}`);
115
+ }
116
+ workspaceConfig = (0, execution_plan_utils_1.readYamlFileAsJson)(configFilePath);
117
+ }
109
118
  const checkedDependancies = await checkDependencies(normalizedInput);
110
119
  return {
111
120
  flowMetadata,
@@ -113,6 +122,7 @@ async function planSingleFile(normalizedInput) {
113
122
  flowsToRun: [normalizedInput],
114
123
  referencedFiles: [...new Set(checkedDependancies)],
115
124
  totalFlowFiles: 1,
125
+ workspaceConfig,
116
126
  };
117
127
  }
118
128
  /**
@@ -211,7 +221,7 @@ async function plan(options) {
211
221
  throw new Error(`Flow path does not exist: ${path.resolve(normalizedInput)}`);
212
222
  }
213
223
  if (fs.lstatSync(normalizedInput).isFile()) {
214
- return planSingleFile(normalizedInput);
224
+ return planSingleFile(normalizedInput, configFile);
215
225
  }
216
226
  let unfilteredFlowFiles = await (0, execution_plan_utils_1.readDirectory)(normalizedInput, execution_plan_utils_1.isFlowFile);
217
227
  if (unfilteredFlowFiles.length === 0) {
@@ -67,6 +67,11 @@ class TestSubmissionService {
67
67
  testFormData.set('env', JSON.stringify(envObject));
68
68
  // Note: googlePlay is now included in configPayload below instead of as a separate field
69
69
  // to work around a FormData parsing issue in the API
70
+ const targetPlatform = iOSDevice || iOSVersion ? 'ios' : 'android';
71
+ const configYamlDisableAnimations = targetPlatform === 'ios'
72
+ ? Boolean(workspaceConfig?.platform?.ios?.disableAnimations)
73
+ : Boolean(workspaceConfig?.platform?.android?.disableAnimations);
74
+ const effectiveDisableAnimations = disableAnimations || configYamlDisableAnimations;
70
75
  const configPayload = {
71
76
  allExcludeTags,
72
77
  allIncludeTags,
@@ -83,7 +88,7 @@ class TestSubmissionService {
83
88
  report,
84
89
  showCrosshairs,
85
90
  maestroChromeOnboarding,
86
- disableAnimations,
91
+ disableAnimations: effectiveDisableAnimations,
87
92
  version: cliVersion,
88
93
  };
89
94
  testFormData.set('config', JSON.stringify(configPayload));
@@ -14,7 +14,6 @@ export declare enum EiOSDevices {
14
14
  'iphone-16-pro-max' = "iphone-16-pro-max"
15
15
  }
16
16
  export declare enum EAndroidDevices {
17
- 'generic-tablet' = "generic-tablet",
18
17
  'pixel-6' = "pixel-6",
19
18
  'pixel-6-pro' = "pixel-6-pro",
20
19
  'pixel-7' = "pixel-7",
@@ -19,7 +19,6 @@ var EiOSDevices;
19
19
  })(EiOSDevices || (exports.EiOSDevices = EiOSDevices = {}));
20
20
  var EAndroidDevices;
21
21
  (function (EAndroidDevices) {
22
- EAndroidDevices["generic-tablet"] = "generic-tablet";
23
22
  EAndroidDevices["pixel-6"] = "pixel-6";
24
23
  EAndroidDevices["pixel-6-pro"] = "pixel-6-pro";
25
24
  EAndroidDevices["pixel-7"] = "pixel-7";