The GitHub Actions job "Required Checks" on 
texera.git/gh-readonly-queue/main/pr-7911-54a9a597d87eb63304af77c67ab744da37086d03
 has failed.
Run started by GitHub user aglinxinyuan (triggered by aglinxinyuan).

Head commit for run:
9bb955ccd3082e1a8f43920113f8a82f5266451c / Meng Wang <[email protected]>
test(frontend): cover the agent service's websocket lifecycle and message 
dispatch (#7911)

### What changes were proposed in this PR?

Extends `agent.service.spec.ts` over the WebSocket lifecycle the issue
lists —
connection setup, the `handleWebSocketMessage` dispatch arms, and
teardown — with
15 tests. They live in the existing `websocket lifecycle and events`
block and
reuse its `FakeWebSocket` double; no new harness. Measured locally with
`--coverage`:

| `agent.service.ts` | Before | After |
| --- | --- | --- |
| lines | 301/329 (91.49 %) | **306/329 (93.01 %)** |
| branches | 147/186 (79.03 %) | **160/186 (86.02 %)** |
| functions | 90/103 | **91/103** |

**Connection setup (`startStatePolling`)**

- The `wss:`/`ws:` ternary (411): `window.location` is swapped for one
test with
the `withLocation` helper `virtual-environment.service.spec.ts` already
uses
(jsdom's own is not writable), and the URL the double was constructed
with is
  asserted in full. The `ws:` side was already covered.
- The parse-failure path (424): a payload that is not JSON is logged and
does not
  throw out of the handler; the connection is left intact.
- The `onerror` handler (428-429), previously an uncalled function.
- The close guard (435), both ways: a stale socket that reports an
abnormal close
after being swapped out must not clear the newer connection or flip the
state.

**Message dispatch (`handleWebSocketMessage`)**

- `message.workflowContent` (466) — a snapshot with no workflow content
leaves the
workflow stream and `wsWorkflowActive` alone, so DB polling stays in
charge.
- `message.step` (478) — a step event with no step changes nothing.
- `message.state` (517) — a status event with no state changes nothing.
- The error arm (534) — an event with no `error` falls back to
`"Agent error occurred"`; the explicit-message side was already covered.
- The `default` arm (451/539) — an unrecognised type warns and changes
nothing.

**Teardown**

- `stopStatePolling` (548) both ways, through `deleteAgent`: for a
tracked agent
the socket is closed and `stopPolling$` completes; for an id that was
never
  tracked it is a no-op.
- `activateAgent` (580) — an already-open socket is kept (no second
socket) and a
socket that is no longer `OPEN` is replaced. `deactivateAgent` always
clears the
socket, so the inactive-but-still-connected shape this guard defends
against is
  set up directly on the tracking entry, with a comment saying so.
- `deactivateAgent` (594-606) — both early returns (unknown agent;
already
inactive) and the no-socket side of the close branch, reached the
ordinary way
  by letting a normal close event drop the socket first.

**One arm is not reachable.** The issue asks for a step "that does not"
carry an
id (498). `convertApiReActStep` returns
``id: apiStep.id || `${apiStep.messageId}-${apiStep.stepId || 0}` `` —
the fallback
is a template literal, which always yields a non-empty string, so
`convertedStep.id` is never falsy and `if (convertedStep.id)` cannot
take its else
branch. The test covers the fallback side instead (a step with no id
still
advances HEAD to `m9-0`) and records why the arm stays half-taken. The
remaining
uncovered lines are the state accessors and HTTP failure paths, which
#7908
covers; the two PRs touch disjoint regions of the file.

No production code was changed.

### Any related issues, documentation, discussions?

Closes #7888.

### How was this PR tested?

`ng test --watch=false --include
src/app/workspace/service/agent/agent.service.spec.ts`
— 62 passed (47 before, 15 new), repeated 3× for stability. `yarn
format:ci` clean.
Failure path verified by breaking one assertion in each of the 15 new
tests: 16
failed (the 15 plus one pre-existing test that shares the mutated
assertion),
non-zero exit, then restored to green.

Determinism: every socket event is delivered by invoking the double's
`onmessage`/`onerror`/`onclose` directly — no real socket, no reconnect
timer, and
no new `vi.useFakeTimers()`. `withLocation` restores `window.location`
in a
`finally`, and `vi.restoreAllMocks()` was added to the block's
`afterEach` so the
`console` spies cannot leak into a later test even if an assertion
throws.

### Was this PR authored or co-authored using generative AI tooling?

Generated-by: Claude Code (Opus 4.8 [1M context])

Report URL: https://github.com/apache/texera/actions/runs/32796083992

With regards,
GitHub Actions via GitBox

Reply via email to