test(node): cover Endpoint.getStateOf() overloads on server endpoints#3685
Merged
test(node): cover Endpoint.getStateOf() overloads on server endpoints#3685
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds missing runtime and compile-time coverage for Endpoint.getStateOf() overloads, focusing on server endpoints via MockServerNode and augmenting existing type-helper tests to validate overload return types.
Changes:
- Add server-endpoint integration tests covering all
getStateOf()overloads and key error cases. - Add type-level assertions for
getStateOf()overload return types (including@ts-expect-errorfor invalid keys).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| packages/node/test/endpoint/EndpointGetTypesTest.ts | Adds compile-time checks for Endpoint.getStateOf() overload return types. |
| packages/node/test/endpoint/EndpointGetServerTest.ts | Adds runtime integration tests for getStateOf() behavior/selector overloads and error conditions on a server endpoint. |
Comment on lines
+139
to
+141
| const _stateOfKeys = _ep.getStateOf(_fakeBeh, ["value"] as const); | ||
| const _checkKeysAwait: Awaited<typeof _stateOfKeys> = {} as { readonly value?: number }; | ||
| void _checkKeysAwait; |
Adds runtime + type-level coverage for `Endpoint.getStateOf()`, which
previously had no integration tests beyond a single error case in
`ClientGroupTest`.
Server-side runtime tests (`EndpointGetServerTest.ts`) exercise all
three overloads against `MockServerNode` + `BasicInformationServer`:
- `(B)` and `(B, true)` return full behavior state.
- `(B, K[])` returns the requested attributes only; empty list returns `{}`.
- `(string, string[])` resolves the string-id fallback overload.
- Unknown behavior id throws `EndpointBehaviorNotPresentError`.
- Unknown attribute on the string overload throws `AttributeNotPresentError`.
Client-side runtime tests (`EndpointGetClientTest.ts`) mirror the server
suite using `MockSite` + `BasicInformationClient` (the client-cluster
behavior, not the server variant) plus a regression test calling
`peer.getStateOf(OperationalCredentialsClient, ['fabrics'])` directly on
the typed peer reference. Without the source change below, the latter
fails to compile because dynamically-added behaviors (added by
`ClientStructure` post-commissioning) are not in `ClientNode.RootEndpoint`'s
static behavior map. Reproduces the user-reported error:
Argument of type 'OperationalCredentialsClientConstructor' is not
assignable to parameter of type 'BehaviorOf<RootEndpoint>'.
The fix loosens the typed `getStateOf` overload constraints in
`Endpoint.ts` from `B extends BehaviorOf<T>` to `B extends Behavior.Type`.
The runtime check at line 385 still throws `EndpointBehaviorNotPresentError`
for behaviors not present on the endpoint, so safety is unchanged: callers
who pass a `Behavior.Type` not actually supported by the endpoint receive
the same runtime error as the string-id overload (which never had a
compile-time existence check). Return type tightening via
`Behavior.StateOf<B>` is preserved.
Type-level tests (`EndpointGetTypesTest.ts`) assert each overload's
return shape:
- `getStateOf(B)` / `getStateOf(B, true)` → `Promise<Behavior.StateOf<B>>`.
- `getStateOf(B, K[])` → `Promise<{ readonly [P in K]?: Behavior.StateOf<B>[P] }>`,
including a `@ts-expect-error` for unknown keys.
- `getStateOf(string, string[])` accepts arbitrary string keys.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
a03ece7 to
3fc2c5d
Compare
Verifies the `fabricFilter` option threads through `Endpoint.get()` to the protocol Read on the client path (Endpoint.ts:1069). Server-side reads hardcode `fabricFilter: false` (Endpoint.ts:1120) and ignore the option, so this test covers only the plumbing on the client side: passing `fabricFilter: false` must not throw and must still return a usable slice. Coverage gaps still open (out of scope for this PR): - Client partial-state-on-failure (`EndpointReadFailedError` carrying failed paths + partial slice). The endpoint pre-validates requested attribute names against the cluster's supported elements at `Endpoint.ts:1042` and rejects unknowns with `AttributeNotPresentError` before reaching the protocol read. ClientStructure mirrors the device's supported attribute set on the peer, so the client peer rejects on the same path. Triggering `EndpointReadFailedError` end-to-end requires a protocol-level mock that injects per-attribute `attr-status` failures, which is not yet available in the node test infrastructure. - Server per-attribute mid-read failure has the same root cause and is blocked on the same mock infrastructure. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Address Copilot review on PR #3685: - The previous `_checkKeysAwait` assignment was one-sided: it only checked that `{ readonly value?: number }` was assignable to `Awaited<typeof _stateOfKeys>`, so an extra optional property creeping into the return type would have slipped through. Switch to the bidirectional `_AssertEqual` helper already used elsewhere in this file so the test fails on either-direction drift. - The comment above the dead-code block claimed it was wrapped in `if (false)`, but the actual guard is `(false as boolean) === true`. Rewrite the comment to match the code and explain why the cast is required (it defeats TypeScript's constant-condition unreachable- code check that a literal `if (false)` would trigger). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
packages/node/src/endpoint/Endpoint.ts:368
- Changing the typed
getStateOf()overloads fromB extends BehaviorOf<T>toB extends Behavior.Typeweakens compile-time enforcement that the behavior is actually part of the endpoint’s static behavior map. Since unsupported behavior types will now compile but throwEndpointBehaviorNotPresentErrorat runtime, the typed overloads should document this (or consider keeping the narrowerBehaviorOf<T>overloads alongside a broader overload for dynamically-added client behaviors).
getStateOf<B extends Behavior.Type>(
type: B,
selector?: true,
options?: Endpoint.GetOptions,
): Promise<Behavior.StateOf<B>>;
getStateOf<B extends Behavior.Type, K extends keyof Behavior.StateOf<B>>(
type: B,
selector: readonly K[],
options?: Endpoint.GetOptions,
): Promise<{ readonly [P in K]?: Behavior.StateOf<B>[P] }>;
Address Copilot review on PR #3685: comment in `EndpointGetClientTest` referenced `Endpoint.ts:1069` / `Endpoint.ts:1120`, which rot as the file changes. Replace with stable method-name references (`Endpoint.#performRead` client branch / server branch). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds runtime + type-level coverage for
Endpoint.getStateOf(), which previously had no integration tests beyond a single error case inClientGroupTest. Surfaced during follow-up review of #3683.Runtime tests (
EndpointGetServerTest.ts)Exercise all three overloads against
MockServerNode+BasicInformationServer:(B)and(B, true)→ full behavior state.(B, K[])→ only the requested attributes; empty list returns{}.(string, string[])→ string-id fallback overload.EndpointBehaviorNotPresentError.AttributeNotPresentError.Type-level tests (
EndpointGetTypesTest.ts)Assert each overload's return shape:
getStateOf(B)/getStateOf(B, true)→Promise<Behavior.StateOf<B>>.getStateOf(B, K[])→Promise<{ readonly [P in K]?: Behavior.StateOf<B>[P] }>, including a@ts-expect-errorfor unknown keys.getStateOf(string, string[])accepts arbitrary string keys.The type-only block lives behind
if ((false as boolean) === true)so the runtime never executes against the phantom endpoint instance.Coverage gaps still open (out of scope for this PR)
getStateOf()integration (heavier mock-site setup).EndpointReadFailedErrorpartial-state-on-failure contract end-to-end.GetOptions.fabricFilterpathway.🤖 Generated with Claude Code