|
1 | | -import { fireEvent, render, screen } from "@testing-library/react" |
| 1 | +import { act, fireEvent, render, screen } from "@testing-library/react" |
2 | 2 |
|
3 | 3 | import { |
4 | 4 | type OrganizationAllowList, |
@@ -99,6 +99,8 @@ describe("IOIntelligence", () => { |
99 | 99 |
|
100 | 100 | beforeEach(() => vi.clearAllMocks()) |
101 | 101 |
|
| 102 | + afterEach(() => vi.useRealTimers()) |
| 103 | + |
102 | 104 | it("renders the secret key input, CTA, and dynamic model picker", () => { |
103 | 105 | renderComponent({ ioIntelligenceApiKey: "stored" }) |
104 | 106 |
|
@@ -129,25 +131,51 @@ describe("IOIntelligence", () => { |
129 | 131 | expect(setApiConfigurationField).toHaveBeenCalledWith("ioIntelligenceApiKey", "new-secret") |
130 | 132 | }) |
131 | 133 |
|
132 | | - it("refreshes models with the unsaved cached key whenever it changes", () => { |
| 134 | + it("refreshes models with the unsaved cached key 250ms after it stops changing", () => { |
| 135 | + vi.useFakeTimers() |
| 136 | + const rerenderWithKey = (rerender: ReturnType<typeof render>["rerender"], ioIntelligenceApiKey: string) => |
| 137 | + rerender( |
| 138 | + <IOIntelligence |
| 139 | + apiConfiguration={{ ioIntelligenceApiKey }} |
| 140 | + setApiConfigurationField={setApiConfigurationField} |
| 141 | + routerModels={{ ...routerModels, "io-intelligence": {} }} |
| 142 | + organizationAllowList={organizationAllowList} |
| 143 | + />, |
| 144 | + ) |
| 145 | + |
133 | 146 | const { rerender } = renderComponent({ ioIntelligenceApiKey: "first-key" }) |
| 147 | + |
| 148 | + act(() => vi.advanceTimersByTime(249)) |
| 149 | + expect(postMessageMock).not.toHaveBeenCalled() |
| 150 | + act(() => vi.advanceTimersByTime(1)) |
| 151 | + expect(postMessageMock).toHaveBeenCalledTimes(1) |
134 | 152 | expect(postMessageMock).toHaveBeenLastCalledWith({ |
135 | 153 | type: RouterModelsMessageType.requestRouterModels, |
136 | 154 | values: { provider: providerIdentifiers.ioIntelligence, ioIntelligenceApiKey: "first-key" }, |
137 | 155 | }) |
138 | 156 |
|
139 | | - rerender( |
140 | | - <IOIntelligence |
141 | | - apiConfiguration={{ ioIntelligenceApiKey: "unsaved-key" }} |
142 | | - setApiConfigurationField={setApiConfigurationField} |
143 | | - routerModels={{ ...routerModels, "io-intelligence": {} }} |
144 | | - organizationAllowList={organizationAllowList} |
145 | | - />, |
146 | | - ) |
| 157 | + // Each edit restarts the timer, so intermediate values never reach the host. |
| 158 | + rerenderWithKey(rerender, "unsaved-") |
| 159 | + act(() => vi.advanceTimersByTime(200)) |
| 160 | + rerenderWithKey(rerender, "unsaved-key") |
| 161 | + act(() => vi.advanceTimersByTime(249)) |
| 162 | + expect(postMessageMock).toHaveBeenCalledTimes(1) |
147 | 163 |
|
| 164 | + act(() => vi.advanceTimersByTime(1)) |
| 165 | + expect(postMessageMock).toHaveBeenCalledTimes(2) |
148 | 166 | expect(postMessageMock).toHaveBeenLastCalledWith({ |
149 | 167 | type: RouterModelsMessageType.requestRouterModels, |
150 | 168 | values: { provider: providerIdentifiers.ioIntelligence, ioIntelligenceApiKey: "unsaved-key" }, |
151 | 169 | }) |
152 | 170 | }) |
| 171 | + |
| 172 | + it("drops a pending model refresh when it unmounts", () => { |
| 173 | + vi.useFakeTimers() |
| 174 | + const { unmount } = renderComponent({ ioIntelligenceApiKey: "first-key" }) |
| 175 | + |
| 176 | + unmount() |
| 177 | + act(() => vi.advanceTimersByTime(250)) |
| 178 | + |
| 179 | + expect(postMessageMock).not.toHaveBeenCalled() |
| 180 | + }) |
153 | 181 | }) |
0 commit comments