@@ -228,6 +228,41 @@ describe("TwitchClientManager", () => {
|
228 | 228 | ); |
229 | 229 | }); |
230 | 230 | |
| 231 | +it("rejects and does not cache a client when addUserForToken fails (83853)", async () => { |
| 232 | +const refreshingAccount: TwitchAccountConfig = { |
| 233 | + ...testAccount, |
| 234 | +clientSecret: "test-client-secret", |
| 235 | +refreshToken: "test-refresh-token", |
| 236 | +expiresIn: 3600, |
| 237 | +obtainmentTimestamp: 1_700_000_000_000, |
| 238 | +}; |
| 239 | +mockAddUserForToken.mockRejectedValueOnce(new Error("token bind failed")); |
| 240 | + |
| 241 | +await expect(manager.getClient(refreshingAccount)).rejects.toThrow("token bind failed"); |
| 242 | + |
| 243 | +// The broken auth provider must not be cached as a usable client; |
| 244 | +// otherwise later sends fail with an opaque error instead of failing fast. |
| 245 | +const key = manager.getAccountKey(refreshingAccount); |
| 246 | +expect((manager as any).clients.has(key)).toBe(false); |
| 247 | +}); |
| 248 | + |
| 249 | +it("retries client creation after an earlier addUserForToken failure (83853)", async () => { |
| 250 | +const refreshingAccount: TwitchAccountConfig = { |
| 251 | + ...testAccount, |
| 252 | +clientSecret: "test-client-secret", |
| 253 | +refreshToken: "test-refresh-token", |
| 254 | +expiresIn: 3600, |
| 255 | +obtainmentTimestamp: 1_700_000_000_000, |
| 256 | +}; |
| 257 | +mockAddUserForToken.mockRejectedValueOnce(new Error("token bind failed")); |
| 258 | + |
| 259 | +await expect(manager.getClient(refreshingAccount)).rejects.toThrow("token bind failed"); |
| 260 | +// No broken client was cached, so a second call re-attempts the bind. |
| 261 | +await manager.getClient(refreshingAccount); |
| 262 | + |
| 263 | +expect(mockAddUserForToken).toHaveBeenCalledTimes(2); |
| 264 | +}); |
| 265 | + |
231 | 266 | it("should throw error when clientId is missing", async () => { |
232 | 267 | const accountWithoutClientId: TwitchAccountConfig = { |
233 | 268 | ...testAccount, |
|