Skip to content

Commit 7a5537e

Browse files
steipetehansraj316
andcommitted
test(channels): consolidate progress draft error coverage
Co-authored-by: Hansraj Singh Thakur <[email protected]>
1 parent bf5b077 commit 7a5537e

4 files changed

Lines changed: 11 additions & 82 deletions

File tree

src/channels/progress-draft-compositor.test.ts

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -163,9 +163,8 @@ describe("createChannelProgressDraftCompositor", () => {
163163
vi.useFakeTimers();
164164
const warn = vi.spyOn(console, "warn").mockImplementation(() => {});
165165
try {
166-
// The compositor builds the gate without an onStartError, so the failure must be
167-
// observed by the gate's default boundary reporter rather than silently dropped.
168-
const update = vi.fn().mockRejectedValue(new Error("send failed"));
166+
const error = new Error("send failed");
167+
const update = vi.fn().mockRejectedValue(error);
169168
const progress = createChannelProgressDraftCompositor({
170169
entry: { streaming: { mode: "progress", progress: { label: "Shelling" } } },
171170
mode: "progress",
@@ -174,16 +173,14 @@ describe("createChannelProgressDraftCompositor", () => {
174173
update,
175174
});
176175

177-
// A single work event schedules the delayed start timer (no startImmediately).
178176
await progress.pushToolProgress("🛠️ Exec");
179177
expect(warn).not.toHaveBeenCalled();
180178

181-
// Firing the timer runs onStart -> render -> update(), which rejects.
182179
await vi.advanceTimersByTimeAsync(DEFAULT_PROGRESS_DRAFT_INITIAL_DELAY_MS);
183180

184181
expect(update).toHaveBeenCalled();
185182
expect(warn).toHaveBeenCalledWith(
186-
expect.stringContaining("channel progress draft failed to start"),
183+
"[progress-draft] channel progress draft failed to start: Error: send failed",
187184
);
188185
} finally {
189186
vi.useRealTimers();

src/channels/streaming.test.ts

Lines changed: 0 additions & 62 deletions
This file was deleted.

src/channels/streaming.ts

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -553,12 +553,7 @@ export function createChannelProgressDraftGate(params: {
553553
onStart: () => void | Promise<void>;
554554
/** Delay before first work event starts a draft; second work event starts immediately. */
555555
initialDelayMs?: number;
556-
/**
557-
* Observes a timer-fired startup rejection. The explicit start/noteWork/startNow
558-
* paths re-throw to their awaiting caller, but the timer path has no awaiter. When a
559-
* caller does not supply this, the gate logs a warning at the helper boundary so the
560-
* failure is never silently dropped regardless of which channel built the gate.
561-
*/
556+
/** Reports timer-fired startup failures, which have no awaiting caller. */
562557
onStartError?: (error: unknown) => void;
563558
/** Timer implementation, injectable for tests. */
564559
setTimeoutFn?: typeof setTimeout;
@@ -568,10 +563,7 @@ export function createChannelProgressDraftGate(params: {
568563
const initialDelayMs = params.initialDelayMs ?? DEFAULT_PROGRESS_DRAFT_INITIAL_DELAY_MS;
569564
const setTimeoutFn = params.setTimeoutFn ?? setTimeout;
570565
const clearTimeoutFn = params.clearTimeoutFn ?? clearTimeout;
571-
// Boundary default: callers that do not pass onStartError still get an observable
572-
// warning for a swallowed timer-fired start failure instead of a silent drop. Use a
573-
// lightweight console.warn (matching sibling typing.ts) rather than a structured
574-
// logger import, so this SDK-exposed module does not widen its static import surface.
566+
// Timer starts have no awaiting caller, so preserve observability at this SDK boundary.
575567
const reportStartError =
576568
params.onStartError ??
577569
((error: unknown) => {
@@ -628,8 +620,7 @@ export function createChannelProgressDraftGate(params: {
628620
}
629621
timer = setTimeoutFn(() => {
630622
timer = undefined;
631-
// Timer start has no awaiter; route the rejection to the (defaulted) reporter so
632-
// it is observed rather than silently dropped.
623+
// Explicit starts rethrow to callers; timer starts must report at the boundary.
633624
void start().catch((error: unknown) => {
634625
reportStartError(error);
635626
});

src/plugin-sdk/channel-streaming.test.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -611,17 +611,20 @@ describe("channel-streaming", () => {
611611

612612
it("does not report started when delayed progress startup rejects", async () => {
613613
vi.useFakeTimers();
614+
const error = new Error("draft unavailable");
614615
const onStart = vi
615616
.fn<() => Promise<void>>()
616-
.mockRejectedValueOnce(new Error("draft unavailable"))
617+
.mockRejectedValueOnce(error)
617618
.mockResolvedValueOnce(undefined);
618-
const gate = createChannelProgressDraftGate({ onStart });
619+
const onStartError = vi.fn();
620+
const gate = createChannelProgressDraftGate({ onStart, onStartError });
619621

620622
await expect(gate.noteWork()).resolves.toBe(false);
621623
await vi.advanceTimersByTimeAsync(5_000);
622624

623625
expect(onStart).toHaveBeenCalledTimes(1);
624626
expect(gate.hasStarted).toBe(false);
627+
expect(onStartError).toHaveBeenCalledWith(error);
625628

626629
await expect(gate.noteWork()).resolves.toBe(true);
627630

0 commit comments

Comments
 (0)