Skip to content

Commit 3a454e5

Browse files
add --dry-run option
1 parent 7fe4e11 commit 3a454e5

File tree

8 files changed

+160
-0
lines changed

8 files changed

+160
-0
lines changed

src/cli.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ const espressoCommand = program
126126
'--async',
127127
'Start tests and exit immediately without waiting for results.',
128128
)
129+
.option(
130+
'--dry-run',
131+
'Validate and prepare everything but skip HTTP calls. Shows what would be sent.',
132+
)
129133
// Report options
130134
.option(
131135
'--report <format>',
@@ -193,6 +197,7 @@ const espressoCommand = program
193197
throttleNetwork: args.throttleNetwork,
194198
quiet: args.quiet,
195199
async: args.async,
200+
dryRun: args.dryRun,
196201
report: args.report,
197202
reportOutputDir: args.reportOutputDir,
198203
metadata,
@@ -309,6 +314,10 @@ const maestroCommand = program
309314
'--async',
310315
'Start tests and exit immediately without waiting for results.',
311316
)
317+
.option(
318+
'--dry-run',
319+
'Validate and prepare everything but skip HTTP calls. Shows what would be sent.',
320+
)
312321
// Report options
313322
.option(
314323
'--report <format>',
@@ -411,6 +420,7 @@ const maestroCommand = program
411420
maestroVersion: args.maestroVersion,
412421
quiet: args.quiet,
413422
async: args.async,
423+
dryRun: args.dryRun,
414424
report: args.report,
415425
reportOutputDir: args.reportOutputDir,
416426
realDevice: args.realDevice,
@@ -506,6 +516,10 @@ const xcuitestCommand = program
506516
'--async',
507517
'Start tests and exit immediately without waiting for results.',
508518
)
519+
.option(
520+
'--dry-run',
521+
'Validate and prepare everything but skip HTTP calls. Shows what would be sent.',
522+
)
509523
// Report options
510524
.option(
511525
'--report <format>',
@@ -566,6 +580,7 @@ const xcuitestCommand = program
566580
throttleNetwork: args.throttleNetwork,
567581
quiet: args.quiet,
568582
async: args.async,
583+
dryRun: args.dryRun,
569584
report: args.report,
570585
reportOutputDir: args.reportOutputDir,
571586
metadata,

src/models/espresso_options.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ export default class EspressoOptions {
7878
// Execution mode
7979
private _quiet: boolean;
8080
private _async: boolean;
81+
private _dryRun: boolean;
8182
private _report?: ReportFormat;
8283
private _reportOutputDir?: string;
8384
// Metadata
@@ -109,6 +110,7 @@ export default class EspressoOptions {
109110
throttleNetwork?: ThrottleNetwork | CustomNetworkProfile;
110111
quiet?: boolean;
111112
async?: boolean;
113+
dryRun?: boolean;
112114
report?: ReportFormat;
113115
reportOutputDir?: string;
114116
metadata?: RunMetadata;
@@ -146,6 +148,7 @@ export default class EspressoOptions {
146148
this._throttleNetwork = options?.throttleNetwork;
147149
this._quiet = options?.quiet ?? false;
148150
this._async = options?.async ?? false;
151+
this._dryRun = options?.dryRun ?? false;
149152
this._report = options?.report;
150153
this._reportOutputDir = options?.reportOutputDir;
151154
this._metadata = options?.metadata;
@@ -250,6 +253,10 @@ export default class EspressoOptions {
250253
return this._async;
251254
}
252255

256+
public get dryRun(): boolean {
257+
return this._dryRun;
258+
}
259+
253260
public get report(): ReportFormat | undefined {
254261
return this._report;
255262
}

src/models/maestro_options.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export default class MaestroOptions {
5959
private _maestroVersion?: string;
6060
private _quiet: boolean;
6161
private _async: boolean;
62+
private _dryRun: boolean;
6263
private _report?: ReportFormat;
6364
private _reportOutputDir?: string;
6465
private _realDevice: boolean;
@@ -89,6 +90,7 @@ export default class MaestroOptions {
8990
maestroVersion?: string;
9091
quiet?: boolean;
9192
async?: boolean;
93+
dryRun?: boolean;
9294
report?: ReportFormat;
9395
reportOutputDir?: string;
9496
realDevice?: boolean;
@@ -117,6 +119,7 @@ export default class MaestroOptions {
117119
this._maestroVersion = options?.maestroVersion;
118120
this._quiet = options?.quiet ?? false;
119121
this._async = options?.async ?? false;
122+
this._dryRun = options?.dryRun ?? false;
120123
this._report = options?.report;
121124
this._reportOutputDir = options?.reportOutputDir;
122125
// IPA files can only be tested on real iOS devices, so automatically enable realDevice
@@ -198,6 +201,10 @@ export default class MaestroOptions {
198201
return this._async;
199202
}
200203

204+
public get dryRun(): boolean {
205+
return this._dryRun;
206+
}
207+
201208
public get report(): ReportFormat | undefined {
202209
return this._report;
203210
}

src/models/xcuitest_options.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export default class XCUITestOptions {
6565
// Execution mode
6666
private _quiet: boolean;
6767
private _async: boolean;
68+
private _dryRun: boolean;
6869
private _report?: ReportFormat;
6970
private _reportOutputDir?: string;
7071
// Metadata
@@ -89,6 +90,7 @@ export default class XCUITestOptions {
8990
throttleNetwork?: ThrottleNetwork | CustomNetworkProfile;
9091
quiet?: boolean;
9192
async?: boolean;
93+
dryRun?: boolean;
9294
report?: ReportFormat;
9395
reportOutputDir?: string;
9496
metadata?: RunMetadata;
@@ -119,6 +121,7 @@ export default class XCUITestOptions {
119121
this._throttleNetwork = options?.throttleNetwork;
120122
this._quiet = options?.quiet ?? false;
121123
this._async = options?.async ?? false;
124+
this._dryRun = options?.dryRun ?? false;
122125
this._report = options?.report;
123126
this._reportOutputDir = options?.reportOutputDir;
124127
this._metadata = options?.metadata;
@@ -195,6 +198,10 @@ export default class XCUITestOptions {
195198
return this._async;
196199
}
197200

201+
public get dryRun(): boolean {
202+
return this._dryRun;
203+
}
204+
198205
public get report(): ReportFormat | undefined {
199206
return this._report;
200207
}

src/providers/base_provider.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export interface BaseRunInfo {
3737
export interface BaseProviderOptions {
3838
quiet?: boolean;
3939
reportOutputDir?: string;
40+
dryRun?: boolean;
4041
}
4142

4243
/**
@@ -408,4 +409,28 @@ export default abstract class BaseProvider<
408409
const remainingSeconds = seconds % 60;
409410
return `${minutes}m ${remainingSeconds}s`;
410411
}
412+
413+
/**
414+
* Prints dry-run summary showing what would be sent to the API.
415+
*/
416+
protected printDryRunSummary(sections: {
417+
provider: string;
418+
apiUrl: string;
419+
uploads: { label: string; filePath: string; endpoint: string }[];
420+
runPayload: Record<string, unknown>;
421+
}): void {
422+
logger.info(`[DRY RUN] ${sections.provider}`);
423+
logger.info('');
424+
logger.info('Files to upload:');
425+
for (const upload of sections.uploads) {
426+
logger.info(` ${upload.label}: ${upload.filePath}`);
427+
logger.info(` -> POST ${upload.endpoint}`);
428+
}
429+
logger.info('');
430+
logger.info('Test run payload:');
431+
logger.info(` POST ${sections.apiUrl}/<appId>/run`);
432+
logger.info(JSON.stringify(sections.runPayload, null, 2));
433+
logger.info('');
434+
logger.info('No HTTP requests were made.');
435+
}
411436
}

src/providers/espresso.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,36 @@ export default class Espresso extends BaseProvider<EspressoOptions> {
100100
return { success: false, runs: [] };
101101
}
102102

103+
if (this.options.dryRun) {
104+
const capabilities = this.options.getCapabilities();
105+
const espressoOptions = this.options.getEspressoOptions();
106+
const metadata = this.options.metadata;
107+
108+
this.printDryRunSummary({
109+
provider: 'Espresso',
110+
apiUrl: this.URL,
111+
uploads: [
112+
{
113+
label: 'App',
114+
filePath: this.options.app,
115+
endpoint: `${this.URL}/app`,
116+
},
117+
{
118+
label: 'Test App',
119+
filePath: this.options.testApp,
120+
endpoint: `${this.URL}/<appId>/tests`,
121+
},
122+
],
123+
runPayload: {
124+
capabilities: [capabilities],
125+
...(espressoOptions && { espressoOptions }),
126+
...(metadata && { metadata }),
127+
},
128+
});
129+
130+
return { success: true, runs: [] };
131+
}
132+
103133
try {
104134
// Quick connectivity check before starting uploads
105135
await this.ensureConnectivity();

src/providers/maestro.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,45 @@ export default class Maestro extends BaseProvider<MaestroOptions> {
183183
if (!(await this.validate())) {
184184
return { success: false, runs: [] };
185185
}
186+
187+
if (this.options.dryRun) {
188+
// Detect platform for dry-run output (no network call needed)
189+
if (!this.options.platformName) {
190+
this.detectedPlatform = await this.detectPlatform();
191+
}
192+
193+
const capabilities = this.options.getCapabilities(this.detectedPlatform);
194+
const maestroOptions = this.options.getMaestroOptions();
195+
const metadata = this.options.metadata;
196+
197+
this.printDryRunSummary({
198+
provider: 'Maestro',
199+
apiUrl: this.URL,
200+
uploads: [
201+
{
202+
label: 'App',
203+
filePath: this.options.app,
204+
endpoint: `${this.URL}/app`,
205+
},
206+
{
207+
label: 'Flows',
208+
filePath: this.options.flows.join(', '),
209+
endpoint: `${this.URL}/<appId>/tests`,
210+
},
211+
],
212+
runPayload: {
213+
capabilities: [capabilities],
214+
...(maestroOptions && { maestroOptions }),
215+
...(this.options.shardSplit && {
216+
shardSplit: this.options.shardSplit,
217+
}),
218+
...(metadata && { metadata }),
219+
},
220+
});
221+
222+
return { success: true, runs: [] };
223+
}
224+
186225
try {
187226
// Quick connectivity check before starting uploads
188227
await this.ensureConnectivity();

src/providers/xcuitest.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,36 @@ export default class XCUITest extends BaseProvider<XCUITestOptions> {
100100
return { success: false, runs: [] };
101101
}
102102

103+
if (this.options.dryRun) {
104+
const capabilities = this.options.getCapabilities();
105+
const xcuitestOptions = this.options.getXCUITestOptions();
106+
const metadata = this.options.metadata;
107+
108+
this.printDryRunSummary({
109+
provider: 'XCUITest',
110+
apiUrl: this.URL,
111+
uploads: [
112+
{
113+
label: 'App',
114+
filePath: this.options.app,
115+
endpoint: `${this.URL}/app`,
116+
},
117+
{
118+
label: 'Test App',
119+
filePath: this.options.testApp,
120+
endpoint: `${this.URL}/<appId>/tests`,
121+
},
122+
],
123+
runPayload: {
124+
capabilities: [capabilities],
125+
...(xcuitestOptions && { options: xcuitestOptions }),
126+
...(metadata && { metadata }),
127+
},
128+
});
129+
130+
return { success: true, runs: [] };
131+
}
132+
103133
try {
104134
// Quick connectivity check before starting uploads
105135
await this.ensureConnectivity();

0 commit comments

Comments
 (0)