Skip to content

Releases: sitespeedio/browsertime

v27.5.0

07 Jun 05:06

Choose a tag to compare

Added

  • Bumped chromedriver and edgedriver to 149 #2487.
  • Updated the Docker image to Chrome 149 / Firefox 151 / Edge 149 #2486 #2488.

Fixed

  • Navigation-script failures now include the URL being tested and the iteration number in the error message, so failure logs and markAsFailure output point at the offending page without cross-referencing the surrounding log lines #2489.

v27.4.1

25 May 13:19

Choose a tag to compare

  • coverage: count dead branches inside executed functions as unused (#2484) aa94b4c

v27.4.0...v27.4.1

v27.4.0

24 May 09:40

Choose a tag to compare

Added

  • JS/CSS coverage collection for Chrome. --chrome.coverage turns it on for every iteration for users who want the data and accept that detailed V8 coverage deoptimizes scripts and will skew their timing metrics. --enableProfileRun also turns coverage on for Chrome alongside the existing trace, so users who want coverage without affecting their timings can lean on the same extra-iteration pattern they already use for tracing — the result is merged back into the main browsertime.json so consumers like sitespeed.io see the data in the same place they read every other metric. Each entry has a per-file breakdown (url, totalBytes, usedBytes, unusedBytes, unusedPercent) #2480.

Fixed

  • HAR post-processing no longer throws when a page has no matching entries. Occasionally a HAR contains a page whose pageref has no entries — typically a navigation that didn't produce any requests, or an extension-injected page. getDocumentRequests and getFinalURL dereferenced shift() / pop() without a guard, and getMainDocumentTimings wrapped its entire per-page loop in a single try/catch so one bad page wiped out the main-document timings for every other page in the same HAR. Downstream this surfaced as a noisy triplet of warnings followed by an empty coach-data payload in sitespeed.io. The three crash points are now guarded and unresolvable pages are skipped #2483.
  • Bumped geckodriver to a version with native ARM-64 support #2482.

v27.3.0

20 May 12:08

Choose a tag to compare

Added

  • browsertime --help is now navigable by topic. The default view shows a short curated list of common options plus the available topic names. browsertime --help <topic> shows just that topic, and browsertime --help-all reproduces the historical full dump for scripts and power users. The old single-screen dump of every option from all 13 topic groups was overwhelming for new users and slow to skim; the topic-filtered view follows the curl/ffmpeg pattern #2467.

Fixed

  • TypeScript types and IntelliSense for navigation scripts are tightened across the script-facing surface. A new BrowsertimeScript type alias lets scripts annotate their default export and get both context and commands typed in one line. The high-level command helpers (navigate, find, getText, fill, hover, press, getTitle, waitForUrl, …) now surface their JSDoc parameter and return types in IntelliSense instead of being typed as Function, and commands.find resolves to a real WebElement so chained calls get completion from selenium-webdriver #2476. context.options, context.result, and context.taskData are typed as Record<string, any> so editors offer completion on context.options. etc. #2478. commands.mouse is now a proper shape (selector typed as string, singleClick's options surface waitForNavigation) instead of an anonymous object literal, and measure.stop / measure.clickAndMeasure / measure.stopAsError return types are explicit (Promise<void> / Promise<unknown>) instead of Promise<any> #2479.
  • How Browsertime publishes its TypeScript types is now safer. scripting.d.ts moved to the repo root next to package.json so it can't be clobbered by a future tsc outDir change, the types condition comes first under exports to match TypeScript's documented resolution rules, and publint runs as part of prepublishOnly so common package.json mistakes fail before a release goes out #2477.
  • Replaced the direct lodash.merge dependency with a small in-tree merge() helper in lib/support/util.js. The helper matches lodash's actual semantics for the cases Browsertime relies on — arrays merged by index, undefined source values skipped unless the key is missing on the target, Date/RegExp/class instances passed by reference, prototype-pollution keys rejected — which finishes the lodash unbundling the same way sitespeed.io did #2468.
  • Bumped dependencies: chrome-har 1.3.1 #2469, chrome-remote-interface and selenium-webdriver #2475, @sitespeed.io/log 2.0 #2471, chromedriver / edgedriver / geckodriver #2472.

v27.2.0

12 May 11:04

Choose a tag to compare

Added

  • Surface the page-level recalculateStyle summary (beforeFCP / beforeLCP element counts + durations) on the first HAR page as _renderBlocking.recalculateStyle. The per-request _renderBlocking map already projected onto each entry stays where it is — the page-level summary is what powers the "Elements that needed recalculate style before FCP" view and was previously only reachable via browsertime.json #2466.

v27.1.0

06 May 14:51

Choose a tag to compare

Added

  • Three new analyses on result.cpu derived from the same Chrome trace.json that's already collected when --cpu is on. scriptCosts produces the per-URL parse / compile / execute / total breakdown that Lighthouse's bootup-time audit shows, sorted by total descending. forcedReflows walks the main-thread task tree for Layout / UpdateLayoutTree events nested inside JS-driven tasks (EventDispatch, FunctionCall, TimerFire, FireAnimationFrame, …) — every match is a synchronous reflow caused by JavaScript reading a layout-triggering property mid-handler, reported with the script that triggered it. nonCompositedAnimations surfaces Animation events whose compositeFailed bitmask is non-zero, returning the unsupported properties (top, box-shadow, filter, …) so consumers can see what to swap for the GPU-friendly equivalent. Each new analysis is wrapped in its own try / catch so a bug in one can't poison the existing categories / events / urls payload

Fixed

  • Replace the unmaintained @sitespeed.io/tracium dependency (extracted from Lighthouse circa 2017, last release 0.3.3) with an in-tree ESM port at lib/chrome/trace/. The algorithm is a 1:1 port; output of computeMainThreadTasks is byte-equivalent for any trace, so existing result.cpu.{categories,events,urls} consumers see no change. Pulling the parser inline lets new analyses ship at Browsertime's release cadence without a second npm publish step in between
  • Modernise the trace-event classifier. The original list only knew about ~30 event names, so on busy 2026-era pages roughly half the trace fell through to "other" — on a sample cnet run that meant 1.3 s of "other" hiding RunTask, v8.run, IntersectionObserverController::computeIntersections, PrePaint, Commit, Layerize, v8.callFunction, V8.DeserializeContext and friends. The expanded list draws from modern Lighthouse + the WebPageTest-derived map in waterfall-tools + direct sampling of real traces, and a new groupForEvent() lookup adds V8.GC* prefix matching so future V8 GC phases auto-classify
  • Bump chrome-har to 1.3.0 to pick up the new _renderBlocking field on each entry, lifting Chrome's CDP renderBlockingStatus (Chrome 108+) so downstream HAR consumers can see which resources blocked first paint without inferring it from the trace.

v27.0.4

05 May 11:31

Choose a tag to compare

Fixed

  • Fix Safari iOS video time scale #2457. This make the video and Safari metric match.

v27.0.3

04 May 09:49

Choose a tag to compare

  • Fix so INP only is calculated on interactions with an id #2456.

v27.0.2

02 May 20:27

Choose a tag to compare

Fixed

  • SPA scripts no longer drop a HAR page when Chrome's soft-navigation PerformanceObserver entry doesn't fire. #2438 gated HAR-page creation on Chrome detecting all three soft-navigation criteria (interaction + URL change + visible paint within a short window), but real SPAs like Grafana sometimes paint too late and Chrome never emits the entry — chrome-har then sees only Network.* events for that measurement and emits zero pages, breaking downstream per-iteration page indexing in sitespeed.io. When the measurement was started without a URL (commands.measure.start(alias) form) and no soft-nav entry was detected, fall back to a synthetic page anchored at the current location.href so each measure.start produces exactly one HAR page.

v27.0.1

02 May 09:12

Choose a tag to compare

Fixed

  • commands.click now falls back to a JavaScript click when the Actions API can't reach the element. Hidden elements have a zero-size bounding box, so the Actions API click that became the default in #2381 silently moved the pointer to (0,0) and clicked nothing instead of triggering the handler. The click command now pre-checks isDisplayed() and uses a JS click when the element isn't displayed, and otherwise catches any Actions API failure and retries with a JS click. Each fallback is logged at info level so it's visible without --verbose. Restores the documented "hide everything before clicking" pattern used by visual-metric scripts #2452.
  • engineDelegate.afterBrowserStopped() is no longer called twice per iteration on the happy path. #2432 added a safety-net cleanup call in the iteration finally block so failure paths still release long-lived helpers, but in the happy path _stopBrowser had already invoked the cleanup, so it ran twice. The visible symptom on Chrome was a spurious ENOENT error from the second cleanUserDataDir (the first call had already removed the directory). It could also double-terminate the iOS simulator's Safari and the ios-capture server. The safety-net now runs only when _stopBrowser didn't already reach the cleanup #2453.
  • cleanUserDataDir cleanup now uses rm(..., { recursive: true, force: true }) so a missing directory is treated as already-cleaned. Defense in depth alongside #2453: if anything in the future double-calls the Chrome cleanup, or if Chrome failed to create the directory in the first place, the cleanup stays quiet instead of logging a spurious ENOENT #2454.