From 3cb779e8eb1aede0e7041a13da6793483dc0492a Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Mon, 28 Sep 2026 20:29:15 +0530 Subject: [PATCH 1/4] fix(metadata): serve current-run test metadata to per-uuid lookups (LCAM-1282) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit setTestMetadata() is called before the test-run uuid is assigned, so only fallbackMetadata gets populated and metadataByTestRunUuid stays empty. testHubModule reads it back with TestMetadata.get(uuid), which has returned {} since the fallback was removed — so app_lcnc was dropped from the outgoing TestRun event and App LCA test runs never got linked to TestHub. A per-uuid lookup now falls back to the current-run metadata only when no per-uuid metadata has been recorded at all. Once per-uuid tracking is active, an unknown uuid still returns {}, so one test run's metadata can never leak into another. Co-Authored-By: Claude Opus 5 (1M context) --- .changeset/lcam-1282-test-metadata-uuid-fallback.md | 5 +++++ packages/browserstack-service/src/metadata.ts | 8 +++++++- packages/browserstack-service/tests/metadata.test.ts | 9 ++++++--- 3 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 .changeset/lcam-1282-test-metadata-uuid-fallback.md diff --git a/.changeset/lcam-1282-test-metadata-uuid-fallback.md b/.changeset/lcam-1282-test-metadata-uuid-fallback.md new file mode 100644 index 00000000..3aac85c8 --- /dev/null +++ b/.changeset/lcam-1282-test-metadata-uuid-fallback.md @@ -0,0 +1,5 @@ +--- +"@wdio/browserstack-service": patch +--- + +- Fixed custom test metadata set via `BrowserStackSDK.setTestMetadata()` being dropped when the metadata is set before the test-run UUID is assigned. A per-UUID lookup now serves the current-run metadata when no per-UUID metadata has been recorded, while still refusing to leak one test run's metadata into another once per-UUID tracking is active. diff --git a/packages/browserstack-service/src/metadata.ts b/packages/browserstack-service/src/metadata.ts index 1554da6e..96a65e71 100644 --- a/packages/browserstack-service/src/metadata.ts +++ b/packages/browserstack-service/src/metadata.ts @@ -39,7 +39,13 @@ class TestMetadata { } if (testRunUuid) { - return TestMetadata.metadataByTestRunUuid[testRunUuid] || {} + const scopedMetadata = TestMetadata.metadataByTestRunUuid[testRunUuid] + if (scopedMetadata) { + return scopedMetadata + } + if (Object.keys(TestMetadata.metadataByTestRunUuid).length > 0) { + return {} + } } return TestMetadata.fallbackMetadata || {} diff --git a/packages/browserstack-service/tests/metadata.test.ts b/packages/browserstack-service/tests/metadata.test.ts index 2d591676..0a41dee5 100644 --- a/packages/browserstack-service/tests/metadata.test.ts +++ b/packages/browserstack-service/tests/metadata.test.ts @@ -68,11 +68,14 @@ describe('TestMetadata', () => { }) describe('fallback vs per-uuid storage', () => { - it('stores as fallback for the no-uuid (current-run) lookup, but not for unknown uuids', () => { + it('stores as fallback for the no-uuid (current-run) lookup', () => { TestMetadata.set({ identifier: 'run-1' }) expect(TestMetadata.get()).toEqual({ identifier: 'run-1' }) - // A per-uuid lookup must not leak the current-run fallback. - expect(TestMetadata.get('unknown-uuid')).toEqual({}) + }) + + it('serves the fallback to a uuid lookup when the uuid was learned after set()', () => { + TestMetadata.set({ identifier: 'run-1' }) + expect(TestMetadata.get('uuid-assigned-later')).toEqual({ identifier: 'run-1' }) }) it('stores per-uuid when a current test-run uuid is set', () => { From e24ddf0ed7007547d2815694ce638a0fa1db1626 Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Tue, 29 Sep 2026 11:57:19 +0530 Subject: [PATCH 2/4] fix(metadata): restore the current-run fallback verbatim (LCAM-1282) Replaces the guarded variant with the exact restore of the clause removed in aa8898f: metadataByTestRunUuid[testRunUuid] || fallbackMetadata || {} testHubModule calls TestMetadata.reset() after each test completes, and that is what bounds reuse across runs, so the plain restore is sufficient and keeps get(uuid) consistent with the no-arg get(). Tests updated to assert the restored semantics, plus a new case covering that reset() between tests prevents a previous run's metadata being served. Co-Authored-By: Claude Opus 5 (1M context) --- .changeset/lcam-1282-test-metadata-uuid-fallback.md | 2 +- packages/browserstack-service/src/metadata.ts | 8 +------- packages/browserstack-service/tests/metadata.test.ts | 10 +++++++++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/.changeset/lcam-1282-test-metadata-uuid-fallback.md b/.changeset/lcam-1282-test-metadata-uuid-fallback.md index 3aac85c8..eeaa3a30 100644 --- a/.changeset/lcam-1282-test-metadata-uuid-fallback.md +++ b/.changeset/lcam-1282-test-metadata-uuid-fallback.md @@ -2,4 +2,4 @@ "@wdio/browserstack-service": patch --- -- Fixed custom test metadata set via `BrowserStackSDK.setTestMetadata()` being dropped when the metadata is set before the test-run UUID is assigned. A per-UUID lookup now serves the current-run metadata when no per-UUID metadata has been recorded, while still refusing to leak one test run's metadata into another once per-UUID tracking is active. +- Fixed custom test metadata set via `BrowserStackSDK.setTestMetadata()` being dropped when the metadata is set before the test-run UUID is assigned. A per-UUID lookup now falls back to the current-run metadata again, restoring the behaviour that shipped before 8.51.0. diff --git a/packages/browserstack-service/src/metadata.ts b/packages/browserstack-service/src/metadata.ts index 96a65e71..2d6e0c3c 100644 --- a/packages/browserstack-service/src/metadata.ts +++ b/packages/browserstack-service/src/metadata.ts @@ -39,13 +39,7 @@ class TestMetadata { } if (testRunUuid) { - const scopedMetadata = TestMetadata.metadataByTestRunUuid[testRunUuid] - if (scopedMetadata) { - return scopedMetadata - } - if (Object.keys(TestMetadata.metadataByTestRunUuid).length > 0) { - return {} - } + return TestMetadata.metadataByTestRunUuid[testRunUuid] || TestMetadata.fallbackMetadata || {} } return TestMetadata.fallbackMetadata || {} diff --git a/packages/browserstack-service/tests/metadata.test.ts b/packages/browserstack-service/tests/metadata.test.ts index 0a41dee5..a6ad2b6b 100644 --- a/packages/browserstack-service/tests/metadata.test.ts +++ b/packages/browserstack-service/tests/metadata.test.ts @@ -84,9 +84,17 @@ describe('TestMetadata', () => { expect(TestMetadata.get('uuid-1')).toEqual({ identifier: 'run-1' }) }) - it('returns {} for an unknown uuid instead of leaking another run\'s metadata', () => { + it('falls back to the current-run metadata for an unrecognised uuid', () => { TestMetadata.setCurrentTestRunUuid('uuid-1') TestMetadata.set({ identifier: 'run-1' }) + expect(TestMetadata.get('uuid-2')).toEqual({ identifier: 'run-1' }) + }) + + it('does not carry a previous run\'s metadata once reset() has run between tests', () => { + TestMetadata.setCurrentTestRunUuid('uuid-1') + TestMetadata.set({ identifier: 'run-1' }) + TestMetadata.reset() + TestMetadata.setCurrentTestRunUuid('uuid-2') expect(TestMetadata.get('uuid-2')).toEqual({}) }) From 989f9d1c3fde38a909d8efde27f6d07748df4bbd Mon Sep 17 00:00:00 2001 From: Ashish Sharma Date: Tue, 29 Sep 2026 13:53:51 +0530 Subject: [PATCH 3/4] chore(metadata): log metadata store state for future diagnosis (LCAM-1282) The failure this PR fixes was silent end to end: setTestMetadata stored only the fallback, get(uuid) returned {}, and app_lcnc was omitted from the event with nothing logged anywhere. Adds two debug lines, both after the app_lcnc gate so they stay silent for every other SDK consumer: setTestMetadata: identifier=... storedUnderUuid=... store=[...] TestMetadata.get: uuid=... identifier=... store=[...] storedUnderUuid=undefined with store=[] identifies the ordering directly, and identifier=undefined on the get line is the failure signature. Also warns when setTestMetadata is called by a non-app_lcnc central user, which previously returned silently. Co-Authored-By: Claude Opus 5 (1M context) --- packages/browserstack-service/src/metadata.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/browserstack-service/src/metadata.ts b/packages/browserstack-service/src/metadata.ts index 2d6e0c3c..3ce83bb1 100644 --- a/packages/browserstack-service/src/metadata.ts +++ b/packages/browserstack-service/src/metadata.ts @@ -14,6 +14,7 @@ class TestMetadata { static set(metadata: Metadata = {}) { if (!getCentralUser().app_lcnc) { + BStackLogger.warn(`setTestMetadata: ignored, BROWSERSTACK_CENTRAL_USER=${process.env.BROWSERSTACK_CENTRAL_USER}`) return } @@ -31,6 +32,7 @@ class TestMetadata { if (TestMetadata.currentTestRunUuid) { TestMetadata.metadataByTestRunUuid[TestMetadata.currentTestRunUuid] = metadata } + BStackLogger.debug(`setTestMetadata: identifier=${testRunIdentifier} storedUnderUuid=${TestMetadata.currentTestRunUuid} store=[${Object.keys(TestMetadata.metadataByTestRunUuid)}]`) } static get(testRunUuid?: string): Metadata { @@ -39,7 +41,9 @@ class TestMetadata { } if (testRunUuid) { - return TestMetadata.metadataByTestRunUuid[testRunUuid] || TestMetadata.fallbackMetadata || {} + const metadata = TestMetadata.metadataByTestRunUuid[testRunUuid] || TestMetadata.fallbackMetadata || {} + BStackLogger.debug(`TestMetadata.get: uuid=${testRunUuid} identifier=${metadata.identifier} store=[${Object.keys(TestMetadata.metadataByTestRunUuid)}]`) + return metadata } return TestMetadata.fallbackMetadata || {} From 9fc22b231f5d1d70be6b3ec1a7b205e57ae45140 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 29 Sep 2026 09:18:48 +0000 Subject: [PATCH 4/4] chore(changeset): auto-generate from PR template (patch) --- .changeset/pr-243.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/pr-243.md diff --git a/.changeset/pr-243.md b/.changeset/pr-243.md new file mode 100644 index 00000000..0d2a0a70 --- /dev/null +++ b/.changeset/pr-243.md @@ -0,0 +1,5 @@ +--- +"@wdio/browserstack-service": patch +--- + +- Fixed custom test metadata set via `BrowserStackSDK.setTestMetadata()` before the test-run UUID is assigned being dropped for App Low-Code runs.