fix: model replay review cancellation
This commit is contained in:
@@ -109,4 +109,20 @@ describe("demoTimelineReducer", () => {
|
|||||||
expect(restarted.mode).toBe("replay");
|
expect(restarted.mode).toBe("replay");
|
||||||
expect(restarted.appliedCount).toBe(0);
|
expect(restarted.appliedCount).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("cancels review as a terminal non-autoplay phase", () => {
|
||||||
|
const reviewing = {
|
||||||
|
...initialDemoTimelineState,
|
||||||
|
mode: "replay" as const,
|
||||||
|
phase: "review" as const,
|
||||||
|
events: [event(0, "interrupt")],
|
||||||
|
appliedCount: 1,
|
||||||
|
autoplay: false,
|
||||||
|
};
|
||||||
|
const cancelled = demoTimelineReducer(reviewing, { type: "cancel_review" });
|
||||||
|
|
||||||
|
expect(cancelled.phase).toBe("cancelled");
|
||||||
|
expect(cancelled.autoplay).toBe(false);
|
||||||
|
expect(cancelled.appliedCount).toBe(1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export type DemoTimelinePhase =
|
|||||||
| "running"
|
| "running"
|
||||||
| "paused"
|
| "paused"
|
||||||
| "review"
|
| "review"
|
||||||
|
| "cancelled"
|
||||||
| "completed"
|
| "completed"
|
||||||
| "failed";
|
| "failed";
|
||||||
|
|
||||||
@@ -35,6 +36,7 @@ export type DemoTimelineAction =
|
|||||||
| { readonly type: "pause" }
|
| { readonly type: "pause" }
|
||||||
| { readonly type: "play" }
|
| { readonly type: "play" }
|
||||||
| { readonly type: "continue_review" }
|
| { readonly type: "continue_review" }
|
||||||
|
| { readonly type: "cancel_review" }
|
||||||
| { readonly type: "fail"; readonly message: string; readonly event?: DemoEvent }
|
| { readonly type: "fail"; readonly message: string; readonly event?: DemoEvent }
|
||||||
| { readonly type: "restart" }
|
| { readonly type: "restart" }
|
||||||
| {
|
| {
|
||||||
@@ -102,6 +104,10 @@ export const demoTimelineReducer = (
|
|||||||
return state.phase === "review"
|
return state.phase === "review"
|
||||||
? { ...state, phase: "running", autoplay: true }
|
? { ...state, phase: "running", autoplay: true }
|
||||||
: state;
|
: state;
|
||||||
|
case "cancel_review":
|
||||||
|
return state.phase === "review"
|
||||||
|
? { ...state, phase: "cancelled", autoplay: false }
|
||||||
|
: state;
|
||||||
case "fail":
|
case "fail":
|
||||||
return {
|
return {
|
||||||
...state,
|
...state,
|
||||||
|
|||||||
@@ -395,6 +395,23 @@ describe("useDemoTimeline", () => {
|
|||||||
expect(result.current.trace?.frames.length).toBeGreaterThan(0);
|
expect(result.current.trace?.frames.length).toBeGreaterThan(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("replay cancellation stops without consuming submitted branch", async () => {
|
||||||
|
vi.useFakeTimers();
|
||||||
|
const { result } = renderHook(() => useDemoTimeline(null, vi.fn()));
|
||||||
|
act(() => result.current.setMode("replay"));
|
||||||
|
act(() => result.current.start());
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
await act(async () => vi.advanceTimersByTimeAsync(900));
|
||||||
|
}
|
||||||
|
|
||||||
|
await act(async () => result.current.cancelReview("Cancelled."));
|
||||||
|
await act(async () => vi.advanceTimersByTimeAsync(1800));
|
||||||
|
|
||||||
|
expect(result.current.state.phase).toBe("cancelled");
|
||||||
|
expect(result.current.state.events[result.current.state.appliedCount - 1]?.stage).toBe("interrupt");
|
||||||
|
expect(result.current.output).toBeNull();
|
||||||
|
});
|
||||||
|
|
||||||
it("missingDeploymentMessage shows when live mode with null target", () => {
|
it("missingDeploymentMessage shows when live mode with null target", () => {
|
||||||
const { result } = renderHook(() => useDemoTimeline(null, vi.fn()));
|
const { result } = renderHook(() => useDemoTimeline(null, vi.fn()));
|
||||||
expect(result.current.missingDeploymentMessage).toContain("Not connected");
|
expect(result.current.missingDeploymentMessage).toContain("Not connected");
|
||||||
|
|||||||
@@ -292,8 +292,8 @@ export const useDemoTimeline = (
|
|||||||
comment,
|
comment,
|
||||||
outcome: "cancelled",
|
outcome: "cancelled",
|
||||||
};
|
};
|
||||||
dispatch({ type: "continue_review" });
|
dispatch({ type: state.mode === "live" ? "continue_review" : "cancel_review" });
|
||||||
}, []);
|
}, [state.mode]);
|
||||||
|
|
||||||
const restart = useCallback(() => {
|
const restart = useCallback(() => {
|
||||||
resetRuntime();
|
resetRuntime();
|
||||||
|
|||||||
Reference in New Issue
Block a user