From cc86585a7039056c0f3caee4d5402237dff2bc2e Mon Sep 17 00:00:00 2001 From: YASH JAIN Date: Thu, 30 Jul 2026 11:28:58 +0530 Subject: [PATCH] fix(rerun): normalise BROWSERSTACK_RERUN_TESTS spec list so only failed specs re-run [SDK-7124] obs-api sends the failed-spec list comma+space separated ("a.ts, b.ts"). setUserSpecs assigned it to run_settings.specs verbatim, unlike the other spec sources which run it through fixCommaSeparatedString. sanitizeSpecsPattern then built "{a.ts, b.ts}" whose space-prefixed brace alternatives never match, so the failed-spec filter collapsed and the whole suite re-ran. Same space-sensitivity in the local runCypressTestsLocally path (cypress --spec). Normalise in both places. Co-Authored-By: Claude Opus 4.8 --- bin/helpers/utils.js | 5 ++++- bin/testObservability/helper/helper.js | 5 ++++- test/unit/bin/helpers/utils.js | 27 ++++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/bin/helpers/utils.js b/bin/helpers/utils.js index b8d134c0..a356a5b8 100644 --- a/bin/helpers/utils.js +++ b/bin/helpers/utils.js @@ -495,7 +495,10 @@ exports.setNodeVersion = (bsConfig, args) => { // command line args takes precedence over config exports.setUserSpecs = (bsConfig, args) => { if(o11yHelpers.isBrowserstackInfra() && o11yHelpers.isTestObservabilitySession() && o11yHelpers.shouldReRunObservabilityTests()) { - bsConfig.run_settings.specs = process.env.BROWSERSTACK_RERUN_TESTS; + // BROWSERSTACK_RERUN_TESTS arrives comma+space separated (e.g. "a.ts, b.ts"); normalise + // like the other spec sources below, else sanitizeSpecsPattern builds "{a.ts, b.ts}" whose + // space-prefixed brace alternatives never match and the failed-spec filter collapses. + bsConfig.run_settings.specs = this.fixCommaSeparatedString(process.env.BROWSERSTACK_RERUN_TESTS); return; } diff --git a/bin/testObservability/helper/helper.js b/bin/testObservability/helper/helper.js index 49d625a1..68ab7367 100644 --- a/bin/testObservability/helper/helper.js +++ b/bin/testObservability/helper/helper.js @@ -879,7 +879,10 @@ const getReRunSpecs = (rawArgs) => { } } if(startIdx != -1) rawArgs.splice(startIdx, numEle + 1); - finalArgs = [...rawArgs, '--spec', process.env.BROWSERSTACK_RERUN_TESTS]; + // Normalise the comma+space separated rerun list ("a.ts, b.ts") to comma-only before + // handing it to cypress --spec; a leading space makes cypress miss every spec but the first. + const reRunSpecs = process.env.BROWSERSTACK_RERUN_TESTS.split(",").map(spec => spec.trim()).filter(Boolean).join(","); + finalArgs = [...rawArgs, '--spec', reRunSpecs]; } return finalArgs.filter(item => item !== '--disable-test-observability' && item !== '--disable-browserstack-automation'); } diff --git a/test/unit/bin/helpers/utils.js b/test/unit/bin/helpers/utils.js index 07f3d57e..2705d770 100644 --- a/test/unit/bin/helpers/utils.js +++ b/test/unit/bin/helpers/utils.js @@ -699,6 +699,33 @@ describe('utils', () => { expect(bsConfig.run_settings.specs).to.be.eq('spec1,spec2'); }); + context('when re-running observability failed tests (BROWSERSTACK_RERUN_TESTS)', () => { + let rerunStubs = []; + beforeEach(() => { + rerunStubs.push(sinon.stub(o11yHelpers, 'isBrowserstackInfra').returns(true)); + rerunStubs.push(sinon.stub(o11yHelpers, 'isTestObservabilitySession').returns(true)); + rerunStubs.push(sinon.stub(o11yHelpers, 'shouldReRunObservabilityTests').returns(true)); + }); + afterEach(() => { + rerunStubs.forEach((s) => s.restore()); + rerunStubs = []; + delete process.env.BROWSERSTACK_RERUN_TESTS; + }); + + it('normalises the comma+space separated rerun spec list to comma-only (SDK-7124)', () => { + process.env.BROWSERSTACK_RERUN_TESTS = + 'FO-E2E-05.ts, FO-E2E-02.ts, FO-E2E-06.ts, FO-E2E-07.ts, FO-E2E-03.ts'; + let bsConfig = { run_settings: { specs: ['some/other/spec.js'] } }; + + utils.setUserSpecs(bsConfig, { specs: null }); + + expect(bsConfig.run_settings.specs).to.be.eq( + 'FO-E2E-05.ts,FO-E2E-02.ts,FO-E2E-06.ts,FO-E2E-07.ts,FO-E2E-03.ts' + ); + expect(bsConfig.run_settings.specs).to.not.contain(' '); + }); + }); + it('does not set the specs list if no specs key specified', () => { let bsConfig = { run_settings: {},