@devicecloud.dev/dcd 0.0.1-alpha.6 → 0.0.1-alpha.7

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.
@@ -12,12 +12,15 @@ export default class Cloud extends Command {
12
12
  apiUrl: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
13
13
  appBinaryId: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
14
14
  appFile: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
15
- async: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
15
+ arm64: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
16
+ async: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
16
17
  env: import("@oclif/core/lib/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
17
18
  excludeTags: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
18
19
  flows: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
+ googlePlay: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
19
21
  iOSVersion: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
20
22
  includeTags: import("@oclif/core/lib/interfaces").OptionFlag<string[], import("@oclif/core/lib/interfaces").CustomOptions>;
23
+ orientation: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
21
24
  };
22
25
  run(): Promise<void>;
23
26
  }
@@ -98,7 +98,7 @@ class Cloud extends core_1.Command {
98
98
  static flags = {
99
99
  androidApiLevel: core_1.Flags.integer({
100
100
  aliases: ['android-api-level'],
101
- description: 'Android API level to run your flow against',
101
+ description: '[Android only] Android API level to run your flow against',
102
102
  options: ['32', '33', '34'],
103
103
  }),
104
104
  apiKey: core_1.Flags.string({ aliases: ['api-key'], description: 'API key' }),
@@ -116,9 +116,14 @@ class Cloud extends core_1.Command {
116
116
  aliases: ['app-file'],
117
117
  description: 'App binary to run your flows against',
118
118
  }),
119
- async: core_1.Flags.boolean({
120
- default: true,
119
+ arm64: core_1.Flags.boolean({
120
+ default: false,
121
+ description: '[Android only] Run your flow against arm64 devices',
122
+ }),
123
+ async: core_1.Flags.string({
124
+ default: 'true',
121
125
  description: 'Wait for the results of the run',
126
+ options: ['true', 'false'],
122
127
  }),
123
128
  env: core_1.Flags.file({
124
129
  char: 'e',
@@ -135,9 +140,14 @@ class Cloud extends core_1.Command {
135
140
  flows: core_1.Flags.string({
136
141
  description: 'The path to the flow file or folder containing your flows',
137
142
  }),
143
+ googlePlay: core_1.Flags.boolean({
144
+ aliases: ['google-play'],
145
+ default: false,
146
+ description: '[Android only] Run your flow against Google Play devices',
147
+ }),
138
148
  iOSVersion: core_1.Flags.string({
139
149
  aliases: ['ios-version'],
140
- description: 'iOS version to run your flow against',
150
+ description: '[iOS only] iOS version to run your flow against',
141
151
  options: ['16.4', '17.2'],
142
152
  }),
143
153
  includeTags: core_1.Flags.string({
@@ -147,10 +157,18 @@ class Cloud extends core_1.Command {
147
157
  multiple: true,
148
158
  parse: (input) => input.split(','),
149
159
  }),
160
+ orientation: core_1.Flags.string({
161
+ description: '[Android only] The orientation of the device to run your flow against in degrees',
162
+ options: ['0', '90', '180', '270'],
163
+ }),
150
164
  };
151
165
  async run() {
152
166
  const { args, flags } = await this.parse(Cloud);
153
- const { apiKey, apiUrl, appBinaryId, appFile, async, env, excludeTags, flows, includeTags, ...rest } = flags;
167
+ const { apiKey, apiUrl, appBinaryId, appFile, arm64, async, env, excludeTags, flows, googlePlay, includeTags, ...rest } = flags;
168
+ if (arm64) {
169
+ (0, cli_ux_1.info)('Contact hello@devicecloud.dev to enquire about arm64 devices');
170
+ (0, cli_ux_1.exit)();
171
+ }
154
172
  const { firstFile, secondFile } = args;
155
173
  let finalBinaryId = appBinaryId;
156
174
  const finalAppFile = appFile ?? firstFile;
@@ -160,25 +178,40 @@ class Cloud extends core_1.Command {
160
178
  throw new Error('You cannot provide both an appBinaryId and a binary file');
161
179
  }
162
180
  flowFile = flows ?? firstFile;
163
- // this.log(
164
- // `you want to run the flow(s) ${flowFile} against the binary with id ${appBinaryId} with the following flags: ${JSON.stringify(
165
- // flags,
166
- // )}`,
167
- // );
168
181
  }
169
- else {
182
+ if (!flowFile) {
183
+ throw new Error('You must provide a flow file');
184
+ }
185
+ const testFileNames = [];
186
+ if (!flowFile?.endsWith('.yaml') &&
187
+ !flowFile?.endsWith('.yml') &&
188
+ !flowFile?.endsWith('/')) {
189
+ flowFile += '/';
190
+ }
191
+ try {
192
+ const executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat());
193
+ for (const file of executionPlan.flowsToRun) {
194
+ testFileNames.push(file);
195
+ }
196
+ for (const file of executionPlan.sequence?.flows ?? []) {
197
+ // todo: handle continueOnFailure and other sequence properties
198
+ testFileNames.push(file);
199
+ }
200
+ }
201
+ catch (error) {
202
+ console.error(error);
203
+ }
204
+ if (!appBinaryId) {
170
205
  if (!(flowFile && finalAppFile)) {
171
206
  throw new Error('You must provide a flow file and an app binary id');
172
207
  }
173
208
  if (!finalAppFile.endsWith('.apk') && !finalAppFile.endsWith('.zip')) {
174
209
  throw new Error('App file must be a .apk or .zip file');
175
210
  }
176
- this.log(`you want to run the flow(s) ${flowFile} against the app ${finalAppFile} with the following flags: ${JSON.stringify(flags)}`);
177
- }
178
- if (!flowFile) {
179
- throw new Error('You must provide a flow file');
211
+ this.log(`you want to run the flow(s) ${flowFile} against the app ${finalAppFile} with the following flags: ${JSON.stringify(flags)}\n`);
180
212
  }
181
213
  if (!finalBinaryId) {
214
+ core_1.ux.action.start('Uploading binary', 'Initializing', { stdout: true });
182
215
  const binaryFormData = new FormData();
183
216
  const binaryBlob = new Blob([await (0, promises_1.readFile)(finalAppFile)], {
184
217
  type: mimeTypeLookupByExtension[finalAppFile.split('.').pop()],
@@ -188,34 +221,13 @@ class Cloud extends core_1.Command {
188
221
  body: binaryFormData,
189
222
  headers: { 'x-app-api-key': apiKey },
190
223
  };
224
+ core_1.ux.action.status = `Uploading`;
191
225
  const { binaryId, message } = await typeSafePost(apiUrl, '/uploads/binary', options);
192
226
  if (!binaryId)
193
227
  throw new Error(message);
194
- this.log(message);
228
+ core_1.ux.action.stop(`\nBinary uploaded with id: ${binaryId}`);
195
229
  finalBinaryId = binaryId;
196
230
  }
197
- const testFileNames = [];
198
- let flowFileDirectory = flowFile;
199
- if (!flowFile?.endsWith('.yaml') && !flowFile?.endsWith('.yml')) {
200
- try {
201
- const executionPlan = await (0, plan_1.plan)(flowFile, includeTags.flat(), excludeTags.flat());
202
- for (const file of executionPlan.flowsToRun) {
203
- testFileNames.push(file);
204
- }
205
- for (const file of executionPlan.sequence?.flows ?? []) {
206
- // todo: handle continueOnFailure and other sequence properties
207
- testFileNames.push(file);
208
- }
209
- }
210
- catch (error) {
211
- console.error(error);
212
- }
213
- }
214
- else {
215
- // we are working with a single file
216
- flowFileDirectory = flowFile.split('/').slice(0, -1).join('/');
217
- testFileNames.push(flowFile.split('/').pop());
218
- }
219
231
  const testFormData = new FormData();
220
232
  // eslint-disable-next-line unicorn/no-array-reduce
221
233
  const envObject = (env ?? []).reduce((acc, cur) => {
@@ -223,8 +235,8 @@ class Cloud extends core_1.Command {
223
235
  acc[key] = value;
224
236
  return acc;
225
237
  }, {});
226
- const buffer = flowFileDirectory?.length
227
- ? await compressDir(flowFileDirectory)
238
+ const buffer = testFileNames?.length > 1
239
+ ? await compressDir(flowFile.split('/').slice(0, -1).join('/'))
228
240
  : await compressFile(flowFile);
229
241
  const blob = new Blob([buffer], {
230
242
  type: mimeTypeLookupByExtension.zip,
@@ -233,6 +245,7 @@ class Cloud extends core_1.Command {
233
245
  testFormData.set('appBinaryId', finalBinaryId);
234
246
  testFormData.set('testFileNames', JSON.stringify(testFileNames));
235
247
  testFormData.set('env', JSON.stringify(envObject));
248
+ testFormData.set('googlePlay', googlePlay ? 'true' : 'false');
236
249
  for (const [key, value] of Object.entries(rest)) {
237
250
  if (value) {
238
251
  testFormData.set(key, value);
@@ -250,37 +263,37 @@ class Cloud extends core_1.Command {
250
263
  .join(', ')}\n`);
251
264
  (0, cli_ux_1.info)('Run triggered, you can access the results at:');
252
265
  (0, cli_ux_1.info)(`https://console.devicecloud.dev/results/${results[0].test_upload_id}/${results[0].id}/\n`);
253
- if (!async) {
254
- (0, cli_ux_1.info)('completed');
266
+ if (async === 'false') {
267
+ (0, cli_ux_1.info)('Not waiting for results as async flag is set to false');
255
268
  (0, cli_ux_1.exit)(0);
256
269
  }
257
- if (async) {
258
- // poll for the run status every 5 seconds
259
- core_1.ux.action.start('Waiting for results', 'Initializing', { stdout: true });
260
- (0, cli_ux_1.info)(' ');
261
- const intervalId = setInterval(async () => {
262
- const { results: updatedResults } = await typeSafeGet(apiUrl, `/results/${results[0].test_upload_id}`, {
263
- headers: { 'x-app-api-key': apiKey },
264
- });
265
- if (!updatedResults) {
266
- clearInterval(intervalId);
267
- (0, errors_1.error)('No results found');
268
- }
269
- core_1.ux.action.status = `\nStatus | Test
270
+ // poll for the run status every 5 seconds
271
+ core_1.ux.action.start('Waiting for results', 'Initializing', { stdout: true });
272
+ (0, cli_ux_1.info)('You can safely close this terminal and the tests will continue\n');
273
+ const intervalId = setInterval(async () => {
274
+ const { results: updatedResults } = await typeSafeGet(apiUrl, `/results/${results[0].test_upload_id}`, {
275
+ headers: { 'x-app-api-key': apiKey },
276
+ });
277
+ if (!updatedResults) {
278
+ clearInterval(intervalId);
279
+ (0, errors_1.error)('No results found');
280
+ }
281
+ core_1.ux.action.status = `\nStatus | Test
270
282
  ────────── ─────────── `;
271
- for (const { status, test_file_name: test } of updatedResults) {
272
- core_1.ux.action.status += `\n${status.padEnd(10, ' ')} | ${test}`;
273
- }
274
- if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
275
- (0, cli_ux_1.info)('\nRun completed\n');
276
- (0, cli_ux_1.table)(updatedResults, {
277
- status: { get: (row) => row.status },
278
- test: { get: (row) => row.test_file_name },
279
- }, { printLine: this.log.bind(this) });
280
- clearInterval(intervalId);
281
- }
282
- }, 5000);
283
- }
283
+ for (const { status, test_file_name: test } of updatedResults) {
284
+ core_1.ux.action.status += `\n${status.padEnd(10, ' ')} | ${test}`;
285
+ }
286
+ if (updatedResults.every((result) => !['PENDING', 'RUNNING'].includes(result.status))) {
287
+ core_1.ux.action.stop('completed');
288
+ (0, cli_ux_1.info)('\n');
289
+ (0, cli_ux_1.table)(updatedResults, {
290
+ status: { get: (row) => row.status },
291
+ test: { get: (row) => row.test_file_name },
292
+ }, { printLine: this.log.bind(this) });
293
+ (0, cli_ux_1.info)('\n');
294
+ clearInterval(intervalId);
295
+ }
296
+ }, 5000);
284
297
  }
285
298
  }
286
299
  exports.default = Cloud;
@@ -23,7 +23,7 @@
23
23
  "aliases": [
24
24
  "android-api-level"
25
25
  ],
26
- "description": "Android API level to run your flow against",
26
+ "description": "[Android only] Android API level to run your flow against",
27
27
  "name": "androidApiLevel",
28
28
  "hasDynamicHelp": false,
29
29
  "multiple": false,
@@ -76,11 +76,23 @@
76
76
  "multiple": false,
77
77
  "type": "option"
78
78
  },
79
+ "arm64": {
80
+ "description": "[Android only] Run your flow against arm64 devices",
81
+ "name": "arm64",
82
+ "allowNo": false,
83
+ "type": "boolean"
84
+ },
79
85
  "async": {
80
86
  "description": "Wait for the results of the run",
81
87
  "name": "async",
82
- "allowNo": false,
83
- "type": "boolean"
88
+ "default": "true",
89
+ "hasDynamicHelp": false,
90
+ "multiple": false,
91
+ "options": [
92
+ "true",
93
+ "false"
94
+ ],
95
+ "type": "option"
84
96
  },
85
97
  "env": {
86
98
  "char": "e",
@@ -108,11 +120,20 @@
108
120
  "multiple": false,
109
121
  "type": "option"
110
122
  },
123
+ "googlePlay": {
124
+ "aliases": [
125
+ "google-play"
126
+ ],
127
+ "description": "[Android only] Run your flow against Google Play devices",
128
+ "name": "googlePlay",
129
+ "allowNo": false,
130
+ "type": "boolean"
131
+ },
111
132
  "iOSVersion": {
112
133
  "aliases": [
113
134
  "ios-version"
114
135
  ],
115
- "description": "iOS version to run your flow against",
136
+ "description": "[iOS only] iOS version to run your flow against",
116
137
  "name": "iOSVersion",
117
138
  "hasDynamicHelp": false,
118
139
  "multiple": false,
@@ -132,6 +153,19 @@
132
153
  "hasDynamicHelp": false,
133
154
  "multiple": true,
134
155
  "type": "option"
156
+ },
157
+ "orientation": {
158
+ "description": "[Android only] The orientation of the device to run your flow against in degrees",
159
+ "name": "orientation",
160
+ "hasDynamicHelp": false,
161
+ "multiple": false,
162
+ "options": [
163
+ "0",
164
+ "90",
165
+ "180",
166
+ "270"
167
+ ],
168
+ "type": "option"
135
169
  }
136
170
  },
137
171
  "hasDynamicHelp": false,
@@ -150,5 +184,5 @@
150
184
  ]
151
185
  }
152
186
  },
153
- "version": "0.0.1-alpha.6"
187
+ "version": "0.0.1-alpha.7"
154
188
  }
package/package.json CHANGED
@@ -74,7 +74,7 @@
74
74
  "test": "mocha --forbid-only \"test/**/*.test.ts\"",
75
75
  "version": "oclif readme && git add README.md"
76
76
  },
77
- "version": "0.0.1-alpha.6",
77
+ "version": "0.0.1-alpha.7",
78
78
  "bugs": {
79
79
  "url": "https://discord.gg/GzZBHcUJ"
80
80
  },