From fddde2a837ac0317d80f4ee8ab9b4cad1eec5df9 Mon Sep 17 00:00:00 2001 From: Harshit Date: Thu, 10 Sep 2026 00:54:07 +0530 Subject: [PATCH 1/2] fix(SDK-4165): keep buildIdentifier when BROWSERSTACK_BUILD_NAME is set MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _handleBuildIdentifier skipped buildIdentifier resolution whenever BROWSERSTACK_BUILD_NAME was set, even though a buildName was available. The skip also deleted buildIdentifier from the capabilities only — this ._buildIdentifier kept the unresolved '#${BUILD_NUMBER}' template, which onPrepare forwards to TestHub as build_identifier. Consequence: successive runs sharing a build name were never disambiguated, so their sessions collapsed into a single build. The guard now keys solely on the absence of a buildName, which is what its own warning always claimed and what the binary's handleBuildIdentifier already does (its BROWSERSTACK_BUILD_NAME skip is commented out). The skip path additionally clears _buildIdentifier so the raw template is never reported as a value. Co-Authored-By: Claude Opus 5 (1M context) --- packages/browserstack-service/src/launcher.ts | 5 ++- .../tests/launcher.test.ts | 35 ++++++++++++++++++- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packages/browserstack-service/src/launcher.ts b/packages/browserstack-service/src/launcher.ts index 390e4e8..5f327bd 100644 --- a/packages/browserstack-service/src/launcher.ts +++ b/packages/browserstack-service/src/launcher.ts @@ -1154,8 +1154,11 @@ export default class BrowserstackLauncherService implements Services.ServiceInst return } - if ((!this._buildName || process.env.BROWSERSTACK_BUILD_NAME) && this._buildIdentifier) { + if (!this._buildName) { this._updateCaps(capabilities, 'buildIdentifier') + // drop it here too: the raw '${BUILD_NUMBER}'/'${DATE_TIME}' template is never a + // usable value, and onPrepare forwards this field to TestHub as build_identifier + this._buildIdentifier = undefined BStackLogger.warn('Skipping buildIdentifier as buildName is not passed.') return } diff --git a/packages/browserstack-service/tests/launcher.test.ts b/packages/browserstack-service/tests/launcher.test.ts index 292cae4..4cf314e 100644 --- a/packages/browserstack-service/tests/launcher.test.ts +++ b/packages/browserstack-service/tests/launcher.test.ts @@ -1329,7 +1329,7 @@ describe('_handleBuildIdentifier', () => { expect(caps[0]).toMatchObject(updatedcaps[0]) }) - it('should delete buildIdentifier if BROWSERSTACK_BUILD_NAME is defined as env var', async() => { + it('should delete buildIdentifier if buildName is absent from caps even when BROWSERSTACK_BUILD_NAME is set', async() => { process.env.BROWSERSTACK_BUILD_NAME = 'browserstack wdio build' const caps: any = [{ 'bstack:options': { @@ -1348,6 +1348,39 @@ describe('_handleBuildIdentifier', () => { delete process.env.BROWSERSTACK_BUILD_NAME }) + it('should still resolve buildIdentifier when buildName is in caps and BROWSERSTACK_BUILD_NAME is set', async() => { + process.env.BROWSERSTACK_BUILD_NAME = 'browserstack wdio build' + const caps: any = [{ + 'bstack:options': { + buildName: 'browserstack wdio build', + buildIdentifier: '#${BUILD_NUMBER}' + } + }] + const service = new BrowserstackLauncher(options as any, caps, config) + + vi.spyOn(utils, 'getCiInfo').mockReturnValueOnce(null) + vi.spyOn(service, '_getLocalBuildNumber').mockReturnValueOnce('3') + vi.spyOn(service, '_updateLocalBuildCache').mockImplementation(() => {}) + service._handleBuildIdentifier(caps) + + expect(caps[0]['bstack:options']?.buildIdentifier).toEqual('#3') + delete process.env.BROWSERSTACK_BUILD_NAME + }) + + it('should not retain an unresolved buildIdentifier template when the identifier is skipped', async() => { + const caps: any = [{ + 'bstack:options': { + buildIdentifier: '#${BUILD_NUMBER}' + } + }] + const service = new BrowserstackLauncher(options as any, caps, config) + + service._handleBuildIdentifier(caps) + + // onPrepare forwards this to TestHub as build_identifier; the raw template must not leak + expect(service._buildIdentifier).toBeUndefined() + }) + it('should not evaluate buildIdentifier if buildIdentifier is not present in the caps', async() => { const caps: any = [{}] const updatedcaps: any = [{ 'browserstack.wdioService': pkg.version }] From ce459fd7cd0d310ac233559b6cce01f6a221e16b Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 9 Sep 2026 19:25:22 +0000 Subject: [PATCH 2/2] chore(changeset): auto-generate from PR template (patch) --- .changeset/pr-192.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/pr-192.md diff --git a/.changeset/pr-192.md b/.changeset/pr-192.md new file mode 100644 index 0000000..387b643 --- /dev/null +++ b/.changeset/pr-192.md @@ -0,0 +1,5 @@ +--- +"@wdio/browserstack-service": patch +--- + +- Fixed `buildIdentifier` being ignored when the `BROWSERSTACK_BUILD_NAME` environment variable is set. Successive runs that share a build name are now reported as separate builds (`my-build #1`, `my-build #2`) instead of merging into one.