Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/pr-131.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@wdio/browserstack-service": patch
---

- Fixed App Automate and Automate session names staying on the static `sessionName` capability instead of the test title, for suites that reload the session between tests or whose run ends before the WebdriverIO `after` hook.
42 changes: 39 additions & 3 deletions packages/browserstack-service/src/cli/modules/automateModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ interface TestResult {

interface SessionData {
lastTestName: string
appliedName?: string // last name successfully PUT for this session, for de-duping
testResults: Map<string, TestResult> // testName -> TestResult
}

Expand Down Expand Up @@ -95,6 +96,42 @@ export default class AutomateModule extends BaseModule {
}

TestFramework.setState(instace, TestFrameworkConstants.KEY_AUTOMATE_SESSION_NAME, name)

// SDK-7270: name the session NOW, while it is still the live session, instead of
// relying solely on the onAfterExecute sweep at worker teardown. Sessions are closed
// as soon as the suite reloads them (`browser.reloadSession()` per test), and a worker
// that never reaches `after()` — interrupted run, hard exit, crash — never fires
// onAfterExecute at all, leaving every session on the creation-time `sessionName`
// capability. Restores the pre-9.27 behaviour, where the rename was issued per test.
await this.flushSessionName(sessionId)
}

/**
* PUT the session's current name if it has not already been applied.
* De-duped via `appliedName` so the onAfterExecute sweep does not re-send it.
*/
private async flushSessionName(sessionId: string): Promise<void> {
const testContextOptions = this.config.testContextOptions as TestContextOptions
if (testContextOptions.skipSessionName) {
return
}

if (!sessionId) {
return
}

const sessionData = this.sessionMap.get(sessionId)
if (!sessionData || !sessionData.lastTestName || sessionData.appliedName === sessionData.lastTestName) {
return
}

const name = sessionData.lastTestName
await this.markSessionName(sessionId, name, {
user: this.config.userName as string,
key: this.config.accessKey as string
})
sessionData.appliedName = name
this.sessionMap.set(sessionId, sessionData)
}

async onAfterTest(args: Record<string, unknown>) {
Expand Down Expand Up @@ -180,9 +217,8 @@ export default class AutomateModule extends BaseModule {
}
}

if (!testContextOptions.skipSessionName) {
await this.markSessionName(sessionId, sessionData.lastTestName, { user: userName, key: accessKey })
}
// Final sweep — a no-op for sessions already named per-test in onBeforeTest.
await this.flushSessionName(sessionId)

if (!testContextOptions.skipSessionStatus) {
await this.markSessionStatus(sessionId, sessionStatus, failureReason, { user: userName, key: accessKey })
Expand Down
Loading