* fix(telegram): handle Grammy HttpError network failures (#3815) Grammy wraps fetch errors in an .error property (not .cause). Added .error traversal to collectErrorCandidates in network-errors.ts. Registered scoped unhandled rejection handler in monitorTelegramProvider to catch network errors that escape the polling loop (e.g., from setMyCommands during bot setup). Handler is unregistered when the provider stops. * fix(telegram): address review feedback for Grammy HttpError handling - Gate .error traversal on HttpError name to avoid widening search graph - Use runtime logger instead of console.warn for consistency - Add isGrammyHttpError check to scope unhandled rejection handler - Consolidate isNetworkRelatedError into isRecoverableTelegramNetworkError - Add 'timeout' to recoverable message snippets for full coverage
This commit is contained in:
@@ -39,4 +39,43 @@ describe("isRecoverableTelegramNetworkError", () => {
|
||||
it("returns false for unrelated errors", () => {
|
||||
expect(isRecoverableTelegramNetworkError(new Error("invalid token"))).toBe(false);
|
||||
});
|
||||
|
||||
// Grammy HttpError tests (issue #3815)
|
||||
// Grammy wraps fetch errors in .error property, not .cause
|
||||
describe("Grammy HttpError", () => {
|
||||
class MockHttpError extends Error {
|
||||
constructor(
|
||||
message: string,
|
||||
public readonly error: unknown,
|
||||
) {
|
||||
super(message);
|
||||
this.name = "HttpError";
|
||||
}
|
||||
}
|
||||
|
||||
it("detects network error wrapped in HttpError", () => {
|
||||
const fetchError = new TypeError("fetch failed");
|
||||
const httpError = new MockHttpError(
|
||||
"Network request for 'setMyCommands' failed!",
|
||||
fetchError,
|
||||
);
|
||||
|
||||
expect(isRecoverableTelegramNetworkError(httpError)).toBe(true);
|
||||
});
|
||||
|
||||
it("detects network error with cause wrapped in HttpError", () => {
|
||||
const cause = Object.assign(new Error("socket hang up"), { code: "ECONNRESET" });
|
||||
const fetchError = Object.assign(new TypeError("fetch failed"), { cause });
|
||||
const httpError = new MockHttpError("Network request for 'getUpdates' failed!", fetchError);
|
||||
|
||||
expect(isRecoverableTelegramNetworkError(httpError)).toBe(true);
|
||||
});
|
||||
|
||||
it("returns false for non-network errors wrapped in HttpError", () => {
|
||||
const authError = new Error("Unauthorized: bot token is invalid");
|
||||
const httpError = new MockHttpError("Bad Request: invalid token", authError);
|
||||
|
||||
expect(isRecoverableTelegramNetworkError(httpError)).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user