Layers BrowserStack on top of the local Playwright e2e suites:
- browserstack.yml (Windows Chrome, macOS Firefox, iPad/iPhone WebKit,
Galaxy S23) driven by the BrowserStack Node SDK and Local tunnel
- :browserstack package scripts and the gated E2E (BrowserStack) CI job
(runs on manual dispatch or the e2e-browserstack PR label)
- tunnel/iOS-WebKit resilience in the specs (bs-local.com host, single
shared mobile context, dynamic-import + CDP "Internal error" skips)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds Playwright end-to-end tests covering three targets:
- the demo build
- a new lightweight test app exercising several scenarios (theming,
admin/non-admin sidebar, panel navigation, more-info dialog)
- the component gallery
Includes the gulp/rspack build infra for the test app and an "E2E Tests"
GitHub Actions workflow that builds each target once, shares it via
artifacts, and runs the suites on Chromium and mobile Chrome. Browser
install is cached and retried to avoid intermittent download stalls.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Preserve unchanged entity display entries across registry updates
* Compare all display fields (integration reload can change source-defined ones)
* Use a generic preserveUnchangedRecord helper with deepEqual
* Add deterministic fixtures and characterization tests for chart data processing
* Extract statistics chart data processing into a pure function
* Extract state history line chart data processing into a pure function
* Add benchmark suite for chart data processing
* Add chart data optimization playbook
* Point agent instructions at the chart optimization playbook
A config flow field guarded by vol.In([1, 5, 6]) sends numeric option
values, but the underlying select returns the chosen value as a string, and
ha-form-select forwarded that string unchanged. On submit the backend
validated "1" against [1, 5, 6] and rejected it as an invalid selection.
Map the selected value back to its original option in ha-form-select so the
source type is retained. String options are unaffected. The mapping is
extracted into matchSelectOptionValue and covered by unit tests.
getEntities builds the item list over every entity each time an entity
picker, the quick bar, or a target picker opens. On a large installation
that list construction did avoidable per-entity work:
- the include/exclude entity and domain filters used Array.includes,
a linear scan per entity (O(entities x filter));
- computeRTL was recomputed for every entity although it only depends on
the language and translation metadata;
- domainToName (a localize lookup) was called for every entity even though
domains repeat heavily across entities.
Use Sets for the filters, hoist computeRTL out of the map, and cache the
domain name per domain. This speeds up opening pickers on large installs.
Behavior is unchanged. Add tests for getEntities, which had none.
computeCssVariable built its nested var() fallback chain with
props.reverse(), which reverses the caller's array in place. Every current
caller passes a freshly built array so there is no visible corruption
today, but mutating an input parameter is a latent trap: a shared,
memoized, or frozen array would produce wrong output or throw.
Use reduceRight to build the same chain from last to first without
mutating or copying the array. Output is unchanged. Add tests for
computeCssVariable (including a no-mutation guarantee) and computeCssValue,
which previously had no coverage.
When createLogMessage received an error whose stack stacktrace-js could
not parse (for example a DOMException such as "AbortError: Transition was
skipped"), fromError threw "Cannot parse given Error object". That throw
escaped createLogMessage, so the global unhandledrejection handler logged
"Failure writing unhandled promise rejection to system log" and the
original error was never recorded.
Wrap the stacktrace extraction in a try/catch and fall back to the raw
error stack (or the provided stack fallback) so the logger stays robust
and still records the original error.
formatNumberToParts, the engine behind formatNumber, built a new
Intl.NumberFormat on every call. It is invoked for essentially every
numeric state render, and constructing an Intl.NumberFormat is
comparatively expensive.
Cache the formatters in a Map keyed by (locale, options). Unlike the
single-entry memoizeOne used for the date formatters, the number format
options are derived per value, so a multi-entry cache is needed to avoid
thrashing. The number of distinct combinations is small and bounded in
practice. Output is unchanged.
When the async Clipboard API is unavailable or rejects, copyToClipboard
falls back to a hidden textarea and execCommand. It appended that textarea
to deepActiveElement()?.getRootNode(). When the deepest active element
lives in the light DOM, getRootNode() returns the Document node, and
appending an element to a Document throws HierarchyRequestError (only the
single documentElement is allowed), so the fallback copy silently failed.
Append to document.body when the resolved root is a Document. Shadow roots
and elements keep holding the textarea directly, preserving execCommand
behavior inside dialogs that trap focus.
* Render echarts tooltips with Lit templates
Replace raw HTML string interpolation in echarts tooltip formatters with Lit templates so user-controlled fields (entity friendly_name, device names, node labels) are auto-escaped instead of relying on per-string filterXSS. ha-chart-base now wraps any function tooltip.formatter into a stable per-formatter container and handles Lit TemplateResult / nothing / null returns; the public HaECOption type lets charts express Lit-returning formatters without per-callsite casts.
* Simplify
* Refactor _getSeries
* Small fix
* Fix merge mistake
* Marker component and wrapper test
* Update dependency echarts to v6.1.0
* Fix axis-proxy patch for echarts 6.1.0 AxisProxy internals
ECharts 6.1.0 uses hostedBy() and _window.value instead of direct model
comparison and _valueWindow. Update the boundaryFilter patch and contract
tests so CI passes with the dependency bump.
Co-authored-by: Cursor <cursoragent@cursor.com>
---------
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Petar Petrov <MindFreeze@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
* first rough draft of Z-Wave credential mangement
* separate user and credentials, error handling, dialog tweaks
* align with upstream API changes, improve error handling
* align more with Matter, use lock entity for services
* remove get_credential_status service
* address review feedback, clarify user types
* user_index -> user_id, fix some pending states
* address review feedback
* clean up unused code, strongly type credential types
* Clear -> Delete, drop icons
* Simplify flow to 1 PIN/Password credential per user
* cleanup, comments, etc.
* address review feedback
* do not show existing credential data
* fix lint errors after branch update
* ignore non-enterable credential types when editing user
* Don't round bar chart end time for hourly periods
If we do this, it causes the last hour of the energy dashboard bar charts to be cut off. This went unnoticed previously because they were placed at times of xx:00, while now they are times of xx:30.
* Round to 30minute for hourly bars rather than leaving unrounded
This better matches the axes with line charts by cutting off padding into the next day, whilst leaving mid-point bars visible.
* Update tests to account for new behaviour
* Add apps navigation group with ingress add-on panels
Add an "Apps" section to the navigation picker that shows all add-ons
with ingress support. Uses the /ingress/panels supervisor endpoint via
a cached collection to fetch add-on titles and icons in a single call.
https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj
* Fix no-shadow lint error for panels variable
Rename subscribe callback parameter from `panels` to `data` to avoid
shadowing the outer `panels` variable in _loadNavigationItems.
https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj
* Use subscribeOne helper for ingress panels collection
Replace hand-rolled Promise/subscribe/unsub pattern with the existing
subscribeOne utility for cleaner one-shot collection consumption.
https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj
* Add explicit type parameter to subscribeOne call
TypeScript cannot infer the generic type through the collection
subscribe chain, resulting in unknown type for panel entries.
https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj
* Add subscribeOneCollection helper for collection one-shot reads
Add a new subscribeOneCollection utility that takes a collection
directly instead of requiring the (conn, onChange) function pattern.
Use it in the navigation picker for cleaner ingress panel fetching.
https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj
* Use Collection type instead of custom Subscribable interface
https://claude.ai/code/session_01F8dUzfSWj8ZwDByVZ45BNj
* Add ingress panel support to subscribeNavigationPathInfo
* Use app panel variable
* Add tests
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Paul Bottein <paul.bottein@gmail.com>
* Cleaned up experience when no pin support is possible to provide better messaging.
* Improvements to messaging depending on lock features
* Added documentation links
* Added prettier format