Skip to content

Commit c8b798c

Browse files
add groups cli argument
1 parent 436fd95 commit c8b798c

5 files changed

Lines changed: 68 additions & 0 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ testingbot maestro <app> <flows...> [options]
110110
|--------|-------------|
111111
| `--name <name>` | Test name for dashboard identification |
112112
| `--build <build>` | Build identifier for grouping test runs |
113+
| `--groups <names>` | Tag the test session with one or more groups (comma-separated). Groups appear on the test in the TestingBot dashboard |
113114
| `--include-tags <tags>` | Only run flows with these tags (comma-separated) |
114115
| `--exclude-tags <tags>` | Exclude flows with these tags (comma-separated) |
115116
| `-e, --env <KEY=VALUE>` | Environment variable for flows (can be repeated) |
@@ -172,6 +173,9 @@ testingbot maestro app.apk ./flows --device "Pixel 8" --deviceVersion "14"
172173
# Android app on real device with tags
173174
testingbot maestro app.apk ./flows --device "Samsung Galaxy S24" --real-device --include-tags "smoke,regression"
174175

176+
# Tag the test session with groups (visible in the dashboard)
177+
testingbot maestro app.apk ./flows --groups "smoke,critical"
178+
175179
# With environment variables
176180
testingbot maestro app.apk ./flows -e API_URL=https://staging.example.com -e API_KEY=secret
177181

src/cli.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,11 @@ program
285285
)
286286
// Test metadata
287287
.option('--name <name>', 'Name for this Maestro run.')
288+
.option(
289+
'--groups <names>',
290+
'Tag the test session with one or more groups (comma-separated).',
291+
(val) => val.split(',').map((g) => g.trim()).filter((g) => g.length > 0),
292+
)
288293
// Network and geo
289294
.option(
290295
'--throttle-network <speed>',
@@ -479,6 +484,7 @@ program
479484
shardSplit: args.shardSplit,
480485
debug: args.debug,
481486
configFile: args.config,
487+
groups: args.groups,
482488
metadata,
483489
});
484490
if (args.debug) {

src/models/maestro_options.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ export interface MaestroCapabilities {
3131
'testingbot.geoCountryCode'?: string;
3232
tunnelIdentifier?: string;
3333
realDevice?: string;
34+
groups?: string[];
3435
}
3536

3637
export interface MaestroRunOptions {
@@ -75,6 +76,7 @@ export default class MaestroOptions {
7576
private _shardSplit?: number;
7677
private _debug: boolean;
7778
private _configFile?: string;
79+
private _groups?: string[];
7880
// Metadata
7981
private _metadata?: RunMetadata;
8082

@@ -109,6 +111,7 @@ export default class MaestroOptions {
109111
shardSplit?: number;
110112
debug?: boolean;
111113
configFile?: string;
114+
groups?: string[];
112115
metadata?: RunMetadata;
113116
},
114117
) {
@@ -147,6 +150,7 @@ export default class MaestroOptions {
147150
this._shardSplit = options?.shardSplit;
148151
this._debug = options?.debug ?? false;
149152
this._configFile = options?.configFile;
153+
this._groups = options?.groups;
150154
this._metadata = options?.metadata;
151155
}
152156

@@ -270,6 +274,10 @@ export default class MaestroOptions {
270274
return this._metadata;
271275
}
272276

277+
public get groups(): string[] | undefined {
278+
return this._groups;
279+
}
280+
273281
public getMaestroOptions(): MaestroRunOptions | undefined {
274282
const opts: MaestroRunOptions = {};
275283

@@ -323,6 +331,7 @@ export default class MaestroOptions {
323331
caps['testingbot.geoCountryCode'] = this._geoCountryCode;
324332
if (this._tunnelIdentifier) caps.tunnelIdentifier = this._tunnelIdentifier;
325333
if (this._realDevice) caps.realDevice = 'true';
334+
if (this._groups && this._groups.length > 0) caps.groups = this._groups;
326335

327336
return caps;
328337
}

tests/cli.test.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,27 @@ describe('TestingBotCTL CLI', () => {
364364
expect(opts.excludeTags).toEqual(['flaky']);
365365
});
366366

367+
test('maestro command should accept --groups (parsed into array, surfaces in capabilities)', async () => {
368+
mockGetCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
369+
370+
await program.parseAsync([
371+
'node',
372+
'cli',
373+
'maestro',
374+
'app.apk',
375+
'./flows',
376+
'--device',
377+
'device-1',
378+
'--groups',
379+
'smoke, critical , ,regression',
380+
]);
381+
382+
expect(mockMaestroRun).toHaveBeenCalledTimes(1);
383+
const opts = lastConstructorOptions<{ groups?: string[] }>(Maestro);
384+
// Empty entries from "a, ,b" and surrounding whitespace are stripped.
385+
expect(opts.groups).toEqual(['smoke', 'critical', 'regression']);
386+
});
387+
367388
test('maestro command should work without --device (optional)', async () => {
368389
mockGetCredentials.mockResolvedValue({ apiKey: 'test-api-key' });
369390

tests/models/maestro_options.test.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ describe('MaestroOptions', () => {
3636
geoCountryCode: 'DE',
3737
env: { API_URL: 'https://api.example.com', API_KEY: 'secret' },
3838
maestroVersion: '2.0.10',
39+
groups: ['smoke', 'critical'],
3940
quiet: true,
4041
async: true,
4142
});
@@ -58,6 +59,7 @@ describe('MaestroOptions', () => {
5859
API_KEY: 'secret',
5960
});
6061
expect(options.maestroVersion).toBe('2.0.10');
62+
expect(options.groups).toEqual(['smoke', 'critical']);
6163
expect(options.quiet).toBe(true);
6264
expect(options.async).toBe(true);
6365
});
@@ -232,6 +234,32 @@ describe('MaestroOptions', () => {
232234
expect(caps.tunnelIdentifier).toBe('my-tunnel');
233235
});
234236

237+
it('should include groups in capabilities when set', () => {
238+
const options = new MaestroOptions('app.apk', './flows', 'Pixel 6', {
239+
platformName: 'Android',
240+
groups: ['smoke', 'critical'],
241+
});
242+
const caps = options.getCapabilities();
243+
expect(caps.groups).toEqual(['smoke', 'critical']);
244+
});
245+
246+
it('should omit groups from capabilities when not set', () => {
247+
const options = new MaestroOptions('app.apk', './flows', 'Pixel 6', {
248+
platformName: 'Android',
249+
});
250+
const caps = options.getCapabilities();
251+
expect(caps).not.toHaveProperty('groups');
252+
});
253+
254+
it('should omit groups from capabilities when empty array', () => {
255+
const options = new MaestroOptions('app.apk', './flows', 'Pixel 6', {
256+
platformName: 'Android',
257+
groups: [],
258+
});
259+
const caps = options.getCapabilities();
260+
expect(caps).not.toHaveProperty('groups');
261+
});
262+
235263
it('should not include includeTags and excludeTags in capabilities', () => {
236264
const options = new MaestroOptions('app.apk', './flows', 'Pixel 8', {
237265
includeTags: ['smoke', 'regression'],

0 commit comments

Comments
 (0)