Skip to content

LTS: populate duration_in_ms + attach per-step meta.steps on Nightwatch TestRunFinished - #60

Merged
shubhamkd merged 3 commits into
nightwatchjs:mainfrom
MihirR-BS:lts-nightwatch-step-insights
Jul 30, 2026
Merged

LTS: populate duration_in_ms + attach per-step meta.steps on Nightwatch TestRunFinished#60
shubhamkd merged 3 commits into
nightwatchjs:mainfrom
MihirR-BS:lts-nightwatch-step-insights

Conversation

@MihirR-BS

Copy link
Copy Markdown
Contributor

Summary

Two LTS-only reporting improvements to the Nightwatch main-path (sendTestRunEvent), both gated on helper.isLoadTestingSession() so non-LTS Automate customers see byte-identical uploads.

1. Populate duration_in_ms (regression fix — commit 389d6a8)

Main-path Nightwatch TestRunFinished never carried duration_in_ms (cucumber / hook / skipped paths do). Downstream is a straight passthrough (observability-pipeline EventProcessorService L874 + L1325 in buildBtcerForLts), so BTCER.duration ended up NULL on every LTS Nightwatch row — every duration-derived Tests-tab metric (min/avg/p50/p75/p90/p95/p99/max) rendered as 0.

Fix: compute duration from the envelope timestamps that sendTestRunEvent already assigns for the TestRunFinished branch (finished_at - started_at).

2. Attach per-step data to meta.steps (new capability — commit c976a0b)

Enables the Step Insights feature for LTS Nightwatch builds. The LCNC compiler wraps every recorded step in a bstackStep(idx, text, id, async fn) helper that captures per-step timings and pushes {id, text, keyword, duration, started_at, finished_at, result, failure} to globalThis.__bstack_steps. This change lets the plugin surface that buffer to Testhub so the mv_btcer_step_metrics_v5 MV fans it out into btcer_step_metrics_v5 — the table the Step Insights /cross-build-step-metrics endpoint aggregates on across builds.

Two touch points:

  • nightwatch/globals.js: reset globalThis.__bstack_steps on every TestRunStarted so retries, reruns, and per-VU iterations get clean buffers.
  • src/testObservability.js: on TestRunFinished, attach the buffer to testData.meta.steps. Non-destructive merge — preserves whatever meta fields (e.g. configuration_id) the LT pipeline had already written.

Verification

duration_in_ms

Patched plugin + local Selenium jar + real Chrome + BROWSERSTACK_LTS_SESSION_ID set → TestRunFinished payload carries duration_in_ms = 145 (matches the timestamp delta). Contract check with LTS env off → duration_in_ms absent from payload.

meta.steps (end-to-end against real Testhub)

  • Ran a sample LCNC-style Nightwatch spec (6 bstackStep-wrapped steps) through local chromedriver with BROWSERSTACK_LTS_SESSION_ID=local-e2e-4 set.
  • Build creation succeeded, TestRunFinished payload carried test_run.meta.steps as a 6-entry array.
  • ClickHouse build_test_case_execution_results_v5 row landed with meta.steps present (length(JSONExtractArrayRaw(meta,'steps')) = 6).
  • MV mv_btcer_step_metrics_v5 fanned out 6 rows into btcer_step_metrics_v5 with correct step_text, step_result, step_duration (846, 597, 118, 72, 47, 24 ms), step_started_at, step_finished_at.

Sample build in Automate: 98w1ld2w7qqihu9mnw1brpgnv582oezqktrkpxcf.

Retries / re-runs

  • Each Nightwatch retry attempt fires its own TestRunStarted → reset zeros the array → fresh steps per attempt.
  • Each attempt gets its own BTCER row via a distinct uuid.
  • sendTestRunEvent captures the array reference synchronously at handler start, before any subsequent reset can happen.
  • Parallel BLU pods run in separate Node processes → separate globalThis → no cross-pollination.

Test plan

  • Unit tests added to test/src/test-observability/sendTestRunEvent.js:
    • duration_in_ms populated on LTS runs
    • duration_in_ms unset on non-LTS runs
    • meta.steps attached on LTS runs when buffer populated
    • meta.steps omitted on non-LTS runs even when buffer populated
    • meta.steps omitted on LTS runs when buffer empty/missing
  • Local end-to-end mimic against real Testhub — see Verification section.
  • Paired LCNC compiler PR: browserstack/lcnc-backend#5068

🤖 Generated with Claude Code

MihirR-BS and others added 2 commits July 24, 2026 06:02
Main-path (non-cucumber, non-hook, non-skipped) Nightwatch
TestRunFinished never carried duration_in_ms. Downstream is a straight
passthrough (observability-pipeline EventProcessorService line 874 + 1325
in buildBtcerForLts), so BTCER.duration ended up NULL on every LTS
Nightwatch row — and every duration-derived Tests-tab metric
(min/avg/p50/p75/p90/p95/p99/max) rendered as 0.

Fix gated on helper.isLoadTestingSession() so non-LTS emits stay
byte-identical. Duration computed from the envelope timestamps
(finished_at - started_at) that sendTestRunEvent already assigns for the
TestRunFinished branch.

Verified end-to-end: patched plugin + local Selenium jar + real Chrome
+ BROWSERSTACK_LTS_SESSION_ID set → TestRunFinished payload carries
duration_in_ms = 145 (matches the timestamp delta). Contract check
with LTS env off → duration_in_ms absent from payload. Two unit tests
added to sendTestRunEvent.spec cover both paths.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The LCNC compiler emits each recorded step wrapped in a bstackStep()
helper that captures per-step timings and pushes them to
globalThis.__bstack_steps. This change lets the plugin surface that
buffer to Testhub so the mv_btcer_step_metrics_v5 MV can fan it out
into btcer_step_metrics_v5 — the table Step Insights aggregates on
across builds.

Two touch points, both gated on helper.isLoadTestingSession() (same
gate as the duration_in_ms fix, so non-LTS Automate customers see
byte-identical uploads):
- nightwatch/globals.js: reset globalThis.__bstack_steps on every
  TestRunStarted so retries and per-VU iterations get clean buffers.
- src/testObservability.js: attach the buffer to testData.meta.steps
  on TestRunFinished. Non-destructive merge — preserves whatever meta
  fields (e.g. configuration_id) the LT pipeline had already written.

Verified end-to-end against real Testhub:
- Compiled a sample LCNC-style Nightwatch spec (tests/lcnc_mimic_test.js
  in local mimic) with 6 bstackStep-wrapped steps.
- Ran through local chromedriver with BROWSERSTACK_LTS_SESSION_ID set
  → build creation succeeded, TestRunFinished payload carried
    test_run.meta.steps as a 6-entry array.
- ClickHouse: build_test_case_execution_results_v5 row landed with
  meta.steps present, mv_btcer_step_metrics_v5 fanned out 6 rows into
  btcer_step_metrics_v5 with correct step_text, step_result and
  step_duration values (846, 597, 118, 72, 47, 24 ms).

Three unit tests added to sendTestRunEvent.spec cover: attach on LTS,
omit on non-LTS, and empty/missing buffer.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@MihirR-BS
MihirR-BS marked this pull request as ready for review July 29, 2026 22:57
The repo's eslint config doesn't declare es2020 env, so globalThis
trips no-undef. `global` is Node's builtin and works in every
runtime this plugin actually ships to. Also splits the one-line
if-block so the `semi` rule's omitLastInOneLineBlock stops flagging
the assignment's own terminator.
@shubhamkd
shubhamkd merged commit 0a63cb3 into nightwatchjs:main Jul 30, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants