diff --git a/.changeset/pr-285.md b/.changeset/pr-285.md new file mode 100644 index 00000000..aecbe5cc --- /dev/null +++ b/.changeset/pr-285.md @@ -0,0 +1,5 @@ +--- +"@wdio/browserstack-service": minor +--- + +- `testManagementOptions` set in the BrowserStack service options is now forwarded in full, so `issues` and `issueTracker` can link Jira issues to the build. The same JSON can be passed with the `BROWSERSTACK_TEST_MANAGEMENT_OPTIONS` environment variable or the `--browserstack.testManagementOptions` CLI argument (Mocha and Cucumber). diff --git a/packages/browserstack-service/src/cli/cliUtils.ts b/packages/browserstack-service/src/cli/cliUtils.ts index 3c6e5c05..5b1454aa 100644 --- a/packages/browserstack-service/src/cli/cliUtils.ts +++ b/packages/browserstack-service/src/cli/cliUtils.ts @@ -116,11 +116,7 @@ export class CLIUtils { ) const observabilityOptions: TestObservabilityOptions = options.testObservabilityOptions || {} - const testManagementOptions: TestManagementOptions = - options.testManagementOptions || {} - const testPlanId = typeof testManagementOptions.testPlanId === 'string' - ? testManagementOptions.testPlanId.trim() - : '' + const testManagementOptions = this.getTestManagementOptions(options.testManagementOptions) const binconfig: Record = { userName: observabilityOptions.user || config.user, accessKey: observabilityOptions.key || config.key, @@ -133,10 +129,8 @@ export class CLIUtils { binconfig.buildName = observabilityOptions.buildName || binconfig.buildName binconfig.projectName = observabilityOptions.projectName || binconfig.projectName binconfig.buildTag = this.getObservabilityBuildTags(observabilityOptions, buildTag) || [] - if (testPlanId.length > 0) { - binconfig.testManagementOptions = { - testPlanId, - } + if (testManagementOptions) { + binconfig.testManagementOptions = testManagementOptions } const caps = Array.isArray(capabilities) ? capabilities : [capabilities] @@ -167,6 +161,22 @@ export class CLIUtils { return JSON.stringify(binconfig) } + /** + * testManagementOptions forwarded to the binary as configured, with testPlanId trimmed and + * dropped when blank; undefined when nothing is left to send. + */ + static getTestManagementOptions(testManagementOptions?: TestManagementOptions): TestManagementOptions | undefined { + if (!testManagementOptions || typeof testManagementOptions !== 'object' || Array.isArray(testManagementOptions)) { + return undefined + } + const { testPlanId, ...otherOptions } = testManagementOptions + const trimmedTestPlanId = typeof testPlanId === 'string' ? testPlanId.trim() : '' + const resolved: TestManagementOptions = trimmedTestPlanId.length > 0 + ? { testPlanId: trimmedTestPlanId, ...otherOptions } + : otherOptions + return Object.keys(resolved).length > 0 ? resolved : undefined + } + static getSdkVersion() { return BSTACK_SERVICE_VERSION } diff --git a/packages/browserstack-service/src/types.ts b/packages/browserstack-service/src/types.ts index e0fd88b4..75a50af2 100644 --- a/packages/browserstack-service/src/types.ts +++ b/packages/browserstack-service/src/types.ts @@ -46,8 +46,32 @@ export interface TestReportingOptions { key?: string } +export interface IssueTrackerOptions { + /** + * Issue tracker the linked issues live in, e.g. 'jira'. + */ + name?: string, + /** + * Base URL of the issue tracker, e.g. 'https://your-domain.atlassian.net'. + */ + host?: string, + [key: string]: unknown +} + export interface TestManagementOptions { + /** + * Test plan to add this run's test cases to. + */ testPlanId?: string, + /** + * Issue keys to link to the build, e.g. ['XYZ-1', 'XYZ-2']. + */ + issues?: string[], + /** + * Issue tracker that `issues` belong to. + */ + issueTracker?: IssueTrackerOptions, + [key: string]: unknown } export interface RunSmartSelectionOptions { @@ -99,8 +123,14 @@ export interface BrowserstackConfig { */ testReportingOptions?: TestReportingOptions; /** - * Set the Test Management related config options under this key. - * Currently supports testPlanId. + * Set the Test Management related config options under this key, e.g. testPlanId, issues + * and issueTracker. + * + * For Mocha and Cucumber runs every key is forwarded to Test Management as is, and the same + * JSON object can also be passed through the BROWSERSTACK_TEST_MANAGEMENT_OPTIONS environment + * variable or the --browserstack.testManagementOptions CLI argument; each top-level key is + * taken from the CLI argument first, then the environment variable, then this option. + * Other runs use testPlanId only. */ testManagementOptions?: TestManagementOptions; /** diff --git a/packages/browserstack-service/tests/cli/cliUtils.test.ts b/packages/browserstack-service/tests/cli/cliUtils.test.ts index aa82167c..bbc371c6 100644 --- a/packages/browserstack-service/tests/cli/cliUtils.test.ts +++ b/packages/browserstack-service/tests/cli/cliUtils.test.ts @@ -199,7 +199,7 @@ describe('CLIUtils', () => { }) }) - it('omits empty testManagementOptions and strips unrelated keys', () => { + it('drops a blank testPlanId and keeps the other testManagementOptions keys', () => { const capabilities = [ { browserName: 'chrome' } ] @@ -218,12 +218,15 @@ describe('CLIUtils', () => { const emptyPlanResult = CLIUtils.getBinConfig(mockConfig, capabilities, emptyPlanOptions) const emptyPlanParsed = JSON.parse(emptyPlanResult) - expect(emptyPlanParsed.testManagementOptions).toBeUndefined() + expect(emptyPlanParsed.testManagementOptions).toEqual({ + ignoredKey: 'ignored' + }) const validPlanResult = CLIUtils.getBinConfig(mockConfig, capabilities, validPlanOptions) const validPlanParsed = JSON.parse(validPlanResult) expect(validPlanParsed.testManagementOptions).toEqual({ - testPlanId: 'tm-plan-456' + testPlanId: 'tm-plan-456', + ignoredKey: 'ignored' }) }) })