@yaebal/test 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +333 -160
- package/lib/api.d.ts +83 -0
- package/lib/api.d.ts.map +1 -0
- package/lib/api.js +186 -0
- package/lib/api.js.map +1 -0
- package/lib/api.test.d.ts +2 -0
- package/lib/api.test.d.ts.map +1 -0
- package/lib/api.test.js +131 -0
- package/lib/api.test.js.map +1 -0
- package/lib/bot-messages.d.ts +42 -0
- package/lib/bot-messages.d.ts.map +1 -0
- package/lib/bot-messages.js +72 -0
- package/lib/bot-messages.js.map +1 -0
- package/lib/chat-actor.d.ts +45 -0
- package/lib/chat-actor.d.ts.map +1 -0
- package/lib/chat-actor.js +72 -0
- package/lib/chat-actor.js.map +1 -0
- package/lib/clock.d.ts +22 -0
- package/lib/clock.d.ts.map +1 -0
- package/lib/clock.js +72 -0
- package/lib/clock.js.map +1 -0
- package/lib/clock.test.d.ts +2 -0
- package/lib/clock.test.d.ts.map +1 -0
- package/lib/clock.test.js +69 -0
- package/lib/clock.test.js.map +1 -0
- package/lib/env.d.ts +100 -0
- package/lib/env.d.ts.map +1 -0
- package/lib/env.js +164 -0
- package/lib/env.js.map +1 -0
- package/lib/env.test.d.ts +2 -0
- package/lib/env.test.d.ts.map +1 -0
- package/lib/env.test.js +302 -0
- package/lib/env.test.js.map +1 -0
- package/lib/fetch.d.ts +3 -0
- package/lib/fetch.d.ts.map +1 -0
- package/lib/fetch.js +12 -0
- package/lib/fetch.js.map +1 -0
- package/lib/index.d.ts +19 -205
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +19 -391
- package/lib/index.js.map +1 -1
- package/lib/internal.d.ts +25 -0
- package/lib/internal.d.ts.map +1 -0
- package/lib/internal.js +19 -0
- package/lib/internal.js.map +1 -0
- package/lib/keyboard.d.ts +15 -0
- package/lib/keyboard.d.ts.map +1 -0
- package/lib/keyboard.js +25 -0
- package/lib/keyboard.js.map +1 -0
- package/lib/keyboard.test.d.ts +2 -0
- package/lib/keyboard.test.d.ts.map +1 -0
- package/lib/keyboard.test.js +31 -0
- package/lib/keyboard.test.js.map +1 -0
- package/lib/normalize.d.ts +10 -0
- package/lib/normalize.d.ts.map +1 -0
- package/lib/normalize.js +27 -0
- package/lib/normalize.js.map +1 -0
- package/lib/reactions.d.ts +3 -0
- package/lib/reactions.d.ts.map +1 -0
- package/lib/reactions.js +17 -0
- package/lib/reactions.js.map +1 -0
- package/lib/updates.d.ts +126 -0
- package/lib/updates.d.ts.map +1 -0
- package/lib/updates.js +200 -0
- package/lib/updates.js.map +1 -0
- package/lib/updates.test.d.ts +2 -0
- package/lib/updates.test.d.ts.map +1 -0
- package/lib/updates.test.js +72 -0
- package/lib/updates.test.js.map +1 -0
- package/lib/user-actor.d.ts +188 -0
- package/lib/user-actor.d.ts.map +1 -0
- package/lib/user-actor.js +465 -0
- package/lib/user-actor.js.map +1 -0
- package/lib/webhook.d.ts +18 -0
- package/lib/webhook.d.ts.map +1 -0
- package/lib/webhook.js +25 -0
- package/lib/webhook.js.map +1 -0
- package/lib/webhook.test.d.ts +2 -0
- package/lib/webhook.test.d.ts.map +1 -0
- package/lib/webhook.test.js +36 -0
- package/lib/webhook.test.js.map +1 -0
- package/package.json +7 -5
- package/src/api.test.ts +180 -0
- package/src/api.ts +289 -0
- package/src/bot-messages.ts +117 -0
- package/src/chat-actor.ts +101 -0
- package/src/clock.test.ts +80 -0
- package/src/clock.ts +118 -0
- package/src/env.test.ts +370 -0
- package/src/env.ts +235 -0
- package/src/fetch.ts +11 -0
- package/src/index.ts +79 -630
- package/src/internal.ts +43 -0
- package/src/keyboard.test.ts +35 -0
- package/src/keyboard.ts +38 -0
- package/src/normalize.ts +34 -0
- package/src/reactions.ts +18 -0
- package/src/updates.test.ts +107 -0
- package/src/updates.ts +354 -0
- package/src/user-actor.ts +702 -0
- package/src/webhook.test.ts +54 -0
- package/src/webhook.ts +48 -0
- package/lib/index.test.d.ts +0 -2
- package/lib/index.test.d.ts.map +0 -1
- package/lib/index.test.js +0 -213
- package/lib/index.test.js.map +0 -1
- package/src/index.test.ts +0 -320
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
import { withFetch } from "./fetch.js";
|
|
4
|
+
import { messageUpdate } from "./updates.js";
|
|
5
|
+
import { collectUpdates, webhookRequest } from "./webhook.js";
|
|
6
|
+
|
|
7
|
+
test("collectUpdates records every update handed to the sink", async () => {
|
|
8
|
+
const { sink, updates } = collectUpdates();
|
|
9
|
+
|
|
10
|
+
await sink.handleUpdate(messageUpdate({ text: "one" }));
|
|
11
|
+
await sink.handleUpdate(messageUpdate({ text: "two" }));
|
|
12
|
+
|
|
13
|
+
assert.equal(updates.length, 2);
|
|
14
|
+
assert.equal(updates[0]?.message?.text, "one");
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("webhookRequest builds a POST carrying the update as JSON, with an optional secret header", async () => {
|
|
18
|
+
const update = messageUpdate({ text: "hi" });
|
|
19
|
+
const req = webhookRequest(update, { secretToken: "s3cret" });
|
|
20
|
+
|
|
21
|
+
assert.equal(req.method, "POST");
|
|
22
|
+
assert.equal(req.headers.get("x-telegram-bot-api-secret-token"), "s3cret");
|
|
23
|
+
assert.deepEqual(await req.json(), update);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("withFetch stubs globalThis.fetch for the duration of fn, then restores it", async () => {
|
|
27
|
+
const realFetch = globalThis.fetch;
|
|
28
|
+
|
|
29
|
+
const result = await withFetch(
|
|
30
|
+
async () => new Response("stubbed"),
|
|
31
|
+
async () => {
|
|
32
|
+
const res = await fetch("https://example.invalid/");
|
|
33
|
+
return res.text();
|
|
34
|
+
},
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
assert.equal(result, "stubbed");
|
|
38
|
+
assert.equal(globalThis.fetch, realFetch);
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
test("withFetch restores the original fetch even if fn throws", async () => {
|
|
42
|
+
const realFetch = globalThis.fetch;
|
|
43
|
+
|
|
44
|
+
await assert.rejects(
|
|
45
|
+
withFetch(
|
|
46
|
+
async () => new Response("x"),
|
|
47
|
+
() => {
|
|
48
|
+
throw new Error("boom");
|
|
49
|
+
},
|
|
50
|
+
),
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
assert.equal(globalThis.fetch, realFetch);
|
|
54
|
+
});
|
package/src/webhook.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { Update, UpdateSink } from "@yaebal/core";
|
|
2
|
+
|
|
3
|
+
/** result of {@link collectUpdates}: an {@link UpdateSink} plus the updates it received, in order. */
|
|
4
|
+
export interface UpdateCollector {
|
|
5
|
+
sink: UpdateSink;
|
|
6
|
+
updates: Update[];
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/** a minimal {@link UpdateSink} (the `{ handleUpdate }` shape `webhookCallback`/runners expect) that just records. */
|
|
10
|
+
export function collectUpdates(): UpdateCollector {
|
|
11
|
+
const updates: Update[] = [];
|
|
12
|
+
|
|
13
|
+
return {
|
|
14
|
+
sink: {
|
|
15
|
+
handleUpdate: async (update) => {
|
|
16
|
+
updates.push(update);
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
updates,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** options for {@link webhookRequest}. */
|
|
24
|
+
export interface WebhookRequestOptions {
|
|
25
|
+
url?: string;
|
|
26
|
+
method?: string;
|
|
27
|
+
secretToken?: string;
|
|
28
|
+
headers?: Record<string, string>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** build a `Request` carrying `update` as JSON, as telegram would POST it to a webhook handler. */
|
|
32
|
+
export function webhookRequest(update: Update, options: WebhookRequestOptions = {}): Request {
|
|
33
|
+
const {
|
|
34
|
+
url = "https://example.invalid/webhook",
|
|
35
|
+
method = "POST",
|
|
36
|
+
secretToken,
|
|
37
|
+
headers = {},
|
|
38
|
+
} = options;
|
|
39
|
+
|
|
40
|
+
const finalHeaders: Record<string, string> = { "content-type": "application/json", ...headers };
|
|
41
|
+
if (secretToken) finalHeaders["x-telegram-bot-api-secret-token"] = secretToken;
|
|
42
|
+
|
|
43
|
+
return new Request(url, {
|
|
44
|
+
method,
|
|
45
|
+
headers: finalHeaders,
|
|
46
|
+
body: method === "GET" || method === "HEAD" ? undefined : JSON.stringify(update),
|
|
47
|
+
});
|
|
48
|
+
}
|
package/lib/index.test.d.ts
DELETED
package/lib/index.test.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
|
package/lib/index.test.js
DELETED
|
@@ -1,213 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { Composer, Context, TelegramError } from "@yaebal/core";
|
|
4
|
-
import { callbackContext, callbackUpdate, channelPostUpdate, chatJoinRequestUpdate, chatMemberUpdate, chosenInlineResultUpdate, collectUpdates, createContext, createUpdate, editedMessageUpdate, findButton, inlineQueryUpdate, messageContext, messageUpdate, mockApi, myChatMemberUpdate, pollAnswerUpdate, pollUpdate, preCheckoutQueryUpdate, runMiddleware, shippingQueryUpdate, webhookRequest, withFetch, } from "./index.js";
|
|
5
|
-
test("mockApi records calls and resolves sensible defaults", async () => {
|
|
6
|
-
const { api, calls } = mockApi();
|
|
7
|
-
const sent = await api.sendMessage({ chat_id: 1, text: "hi" });
|
|
8
|
-
assert.deepEqual(sent, { message_id: 1 });
|
|
9
|
-
const answered = await api.answerCallbackQuery({ callback_query_id: "1" });
|
|
10
|
-
assert.equal(answered, true);
|
|
11
|
-
const viaCall = await api.call("setMyCommands", { commands: [] });
|
|
12
|
-
assert.deepEqual(viaCall, {});
|
|
13
|
-
assert.deepEqual(calls, [
|
|
14
|
-
{ method: "sendMessage", params: { chat_id: 1, text: "hi" } },
|
|
15
|
-
{ method: "answerCallbackQuery", params: { callback_query_id: "1" } },
|
|
16
|
-
{ method: "setMyCommands", params: { commands: [] } },
|
|
17
|
-
]);
|
|
18
|
-
});
|
|
19
|
-
test("mockApi hook registrars are chainable no-ops", () => {
|
|
20
|
-
const { api } = mockApi();
|
|
21
|
-
assert.equal(api.before(() => undefined), api);
|
|
22
|
-
assert.equal(api.after((_m, r) => r), api);
|
|
23
|
-
});
|
|
24
|
-
test("messageUpdate produces a valid message update", () => {
|
|
25
|
-
const update = messageUpdate({ text: "hello", chatId: 42, chatType: "group" });
|
|
26
|
-
assert.ok(update.update_id > 0);
|
|
27
|
-
assert.equal(update.message?.text, "hello");
|
|
28
|
-
assert.equal(update.message?.chat.id, 42);
|
|
29
|
-
assert.equal(update.message?.chat.type, "group");
|
|
30
|
-
assert.equal(update.message?.from?.id, 42);
|
|
31
|
-
});
|
|
32
|
-
test("callbackUpdate produces a valid callback_query update", () => {
|
|
33
|
-
const update = callbackUpdate({ data: "click", chatId: 7, fromId: 9 });
|
|
34
|
-
assert.equal(update.callback_query?.data, "click");
|
|
35
|
-
assert.equal(update.callback_query?.from.id, 9);
|
|
36
|
-
assert.equal(update.callback_query?.message?.chat.id, 7);
|
|
37
|
-
});
|
|
38
|
-
test("createUpdate fills a fresh update_id", () => {
|
|
39
|
-
const a = createUpdate();
|
|
40
|
-
const b = createUpdate();
|
|
41
|
-
assert.notEqual(a.update_id, b.update_id);
|
|
42
|
-
});
|
|
43
|
-
test("createContext yields a Context whose getters work", () => {
|
|
44
|
-
const ctx = createContext(messageUpdate({ text: "yo", chatId: 5 }));
|
|
45
|
-
assert.ok(ctx instanceof Context);
|
|
46
|
-
assert.equal(ctx.updateType, "message");
|
|
47
|
-
assert.equal(ctx.text, "yo");
|
|
48
|
-
assert.equal(ctx.chat?.id, 5);
|
|
49
|
-
});
|
|
50
|
-
test("createContext detects callback_query updates", () => {
|
|
51
|
-
const ctx = createContext(callbackUpdate({ data: "x" }));
|
|
52
|
-
assert.equal(ctx.updateType, "callback_query");
|
|
53
|
-
assert.equal(ctx.callbackQuery?.data, "x");
|
|
54
|
-
});
|
|
55
|
-
test("a handler calling ctx.reply records a sendMessage call", async () => {
|
|
56
|
-
const { api, calls } = mockApi();
|
|
57
|
-
const composer = new Composer().on("message:text", (ctx) => ctx.reply("pong"));
|
|
58
|
-
await runMiddleware(composer, createContext(messageUpdate({ text: "ping", chatId: 3 }), api));
|
|
59
|
-
assert.equal(calls.length, 1);
|
|
60
|
-
const call = calls[0];
|
|
61
|
-
assert.equal(call?.method, "sendMessage");
|
|
62
|
-
assert.equal(call?.params?.chat_id, 3);
|
|
63
|
-
assert.equal(call?.params?.text, "pong");
|
|
64
|
-
assert.deepEqual(call?.params?.reply_parameters, { message_id: 1 });
|
|
65
|
-
});
|
|
66
|
-
test("mockApi auto-increments message_id across send* calls", async () => {
|
|
67
|
-
const { api } = mockApi();
|
|
68
|
-
const first = await api.sendMessage({ chat_id: 1, text: "a" });
|
|
69
|
-
const second = await api.sendMessage({ chat_id: 1, text: "b" });
|
|
70
|
-
assert.deepEqual(first, { message_id: 1 });
|
|
71
|
-
assert.deepEqual(second, { message_id: 2 });
|
|
72
|
-
});
|
|
73
|
-
test("mockApi results: static override replaces the built-in default", async () => {
|
|
74
|
-
const { api } = mockApi({ results: { sendMessage: { message_id: 99 } } });
|
|
75
|
-
assert.deepEqual(await api.sendMessage({ chat_id: 1 }), { message_id: 99 });
|
|
76
|
-
});
|
|
77
|
-
test("mockApi results: an Error value makes the call throw", async () => {
|
|
78
|
-
const { api } = mockApi({
|
|
79
|
-
results: { sendMessage: new TelegramError("sendMessage", 400, "Bad Request") },
|
|
80
|
-
});
|
|
81
|
-
await assert.rejects(api.sendMessage({ chat_id: 1 }), TelegramError);
|
|
82
|
-
});
|
|
83
|
-
test("mockApi results: a function sees params and a running attempt count", async () => {
|
|
84
|
-
const { api } = mockApi({
|
|
85
|
-
results: {
|
|
86
|
-
sendMessage: (params, attempt) => attempt <= 2
|
|
87
|
-
? new TelegramError("sendMessage", 429, "retry after 0")
|
|
88
|
-
: { message_id: 1, echo: params?.text },
|
|
89
|
-
},
|
|
90
|
-
});
|
|
91
|
-
api.onError((_m, _e, attempt) => (attempt <= 2 ? { retry: true } : undefined));
|
|
92
|
-
const result = await api.sendMessage({ chat_id: 1, text: "hi" });
|
|
93
|
-
assert.deepEqual(result, { message_id: 1, echo: "hi" });
|
|
94
|
-
});
|
|
95
|
-
test("mockApi.setResult overrides after creation; reset() clears calls and counters", async () => {
|
|
96
|
-
const { api, calls, setResult, reset } = mockApi();
|
|
97
|
-
await api.sendMessage({ chat_id: 1 });
|
|
98
|
-
setResult("sendMessage", { message_id: 42 });
|
|
99
|
-
assert.deepEqual(await api.sendMessage({ chat_id: 1 }), { message_id: 42 });
|
|
100
|
-
assert.equal(calls.length, 2);
|
|
101
|
-
reset();
|
|
102
|
-
assert.equal(calls.length, 0);
|
|
103
|
-
assert.deepEqual(await api.sendMessage({ chat_id: 1 }), { message_id: 42 });
|
|
104
|
-
});
|
|
105
|
-
test("mockApi.lastCall and callsTo filter recorded calls", async () => {
|
|
106
|
-
const { api, lastCall, callsTo } = mockApi();
|
|
107
|
-
await api.sendMessage({ chat_id: 1, text: "a" });
|
|
108
|
-
await api.answerCallbackQuery({ callback_query_id: "1" });
|
|
109
|
-
await api.sendMessage({ chat_id: 1, text: "b" });
|
|
110
|
-
assert.equal(lastCall()?.method, "sendMessage");
|
|
111
|
-
assert.equal(lastCall("answerCallbackQuery")?.method, "answerCallbackQuery");
|
|
112
|
-
assert.equal(lastCall("sendMessage")?.params?.text, "b");
|
|
113
|
-
assert.equal(callsTo("sendMessage").length, 2);
|
|
114
|
-
});
|
|
115
|
-
test("mockApi hooks actually run: before rewrites params, after rewrites result", async () => {
|
|
116
|
-
const { api } = mockApi();
|
|
117
|
-
api.before((_method, params) => ({ ...params, injected: true }));
|
|
118
|
-
api.after((_method, _params, result) => ({ ...result, tagged: true }));
|
|
119
|
-
const result = await api.sendMessage({ chat_id: 1 });
|
|
120
|
-
assert.deepEqual(result, { message_id: 1, tagged: true });
|
|
121
|
-
});
|
|
122
|
-
test("channelPostUpdate / editedMessageUpdate build the right update key", () => {
|
|
123
|
-
assert.equal(channelPostUpdate({ text: "hi" }).channel_post?.text, "hi");
|
|
124
|
-
assert.equal(channelPostUpdate().channel_post?.chat.type, "channel");
|
|
125
|
-
assert.equal(editedMessageUpdate({ text: "hi" }).edited_message?.text, "hi");
|
|
126
|
-
});
|
|
127
|
-
test("inlineQueryUpdate / chosenInlineResultUpdate build their payloads", () => {
|
|
128
|
-
const iq = inlineQueryUpdate({ query: "cats", fromId: 5 });
|
|
129
|
-
assert.equal(iq.inline_query?.query, "cats");
|
|
130
|
-
assert.equal(iq.inline_query?.from.id, 5);
|
|
131
|
-
const cir = chosenInlineResultUpdate({ resultId: "r1", query: "cats" });
|
|
132
|
-
assert.equal(cir.chosen_inline_result?.result_id, "r1");
|
|
133
|
-
});
|
|
134
|
-
test("shippingQueryUpdate / preCheckoutQueryUpdate build valid payloads", () => {
|
|
135
|
-
const sq = shippingQueryUpdate({ shippingAddress: { city: "Berlin" } });
|
|
136
|
-
assert.equal(sq.shipping_query?.shipping_address.city, "Berlin");
|
|
137
|
-
const pcq = preCheckoutQueryUpdate({ currency: "EUR", totalAmount: 500 });
|
|
138
|
-
assert.equal(pcq.pre_checkout_query?.currency, "EUR");
|
|
139
|
-
assert.equal(pcq.pre_checkout_query?.total_amount, 500);
|
|
140
|
-
});
|
|
141
|
-
test("pollUpdate / pollAnswerUpdate build valid payloads", () => {
|
|
142
|
-
const poll = pollUpdate({ question: "?", options: ["a", "b", "c"] });
|
|
143
|
-
assert.equal(poll.poll?.options.length, 3);
|
|
144
|
-
assert.equal(poll.poll?.options[1]?.text, "b");
|
|
145
|
-
const answer = pollAnswerUpdate({ optionIds: [1] });
|
|
146
|
-
assert.deepEqual(answer.poll_answer?.option_ids, [1]);
|
|
147
|
-
});
|
|
148
|
-
test("myChatMemberUpdate / chatMemberUpdate / chatJoinRequestUpdate build valid payloads", () => {
|
|
149
|
-
const my = myChatMemberUpdate({ oldStatus: "left", newStatus: "member" });
|
|
150
|
-
assert.equal(my.my_chat_member?.old_chat_member.status, "left");
|
|
151
|
-
assert.equal(my.my_chat_member?.new_chat_member.status, "member");
|
|
152
|
-
const other = chatMemberUpdate({ userId: 7 });
|
|
153
|
-
assert.equal(other.chat_member?.new_chat_member.user.id, 7);
|
|
154
|
-
const join = chatJoinRequestUpdate({ chatId: 3, fromId: 4, bio: "hi" });
|
|
155
|
-
assert.equal(join.chat_join_request?.chat.id, 3);
|
|
156
|
-
assert.equal(join.chat_join_request?.bio, "hi");
|
|
157
|
-
});
|
|
158
|
-
test("messageContext / callbackContext build a Context in one call", () => {
|
|
159
|
-
const ctx = messageContext({ text: "hi", chatId: 9 });
|
|
160
|
-
assert.equal(ctx.text, "hi");
|
|
161
|
-
assert.equal(ctx.chat?.id, 9);
|
|
162
|
-
const cbCtx = callbackContext({ data: "x" });
|
|
163
|
-
assert.equal(cbCtx.callbackQuery?.data, "x");
|
|
164
|
-
});
|
|
165
|
-
test("findButton locates a button by text and reports its position", () => {
|
|
166
|
-
const markup = {
|
|
167
|
-
inline_keyboard: [
|
|
168
|
-
[{ text: "a", callback_data: "a" }],
|
|
169
|
-
[
|
|
170
|
-
{ text: "b", callback_data: "b" },
|
|
171
|
-
{ text: "Next", callback_data: "page:2" },
|
|
172
|
-
],
|
|
173
|
-
],
|
|
174
|
-
};
|
|
175
|
-
const found = findButton(markup, "Next");
|
|
176
|
-
assert.equal(found?.callback_data, "page:2");
|
|
177
|
-
assert.equal(found?.row, 1);
|
|
178
|
-
assert.equal(found?.col, 1);
|
|
179
|
-
assert.equal(findButton(markup, /^n/i)?.text, "Next");
|
|
180
|
-
assert.equal(findButton(markup, "missing"), undefined);
|
|
181
|
-
assert.equal(findButton(undefined, "missing"), undefined);
|
|
182
|
-
});
|
|
183
|
-
test("collectUpdates records every update handed to the sink", async () => {
|
|
184
|
-
const { sink, updates } = collectUpdates();
|
|
185
|
-
await sink.handleUpdate(messageUpdate({ text: "one" }));
|
|
186
|
-
await sink.handleUpdate(messageUpdate({ text: "two" }));
|
|
187
|
-
assert.equal(updates.length, 2);
|
|
188
|
-
assert.equal(updates[0]?.message?.text, "one");
|
|
189
|
-
});
|
|
190
|
-
test("webhookRequest builds a POST carrying the update as JSON, with an optional secret header", async () => {
|
|
191
|
-
const update = messageUpdate({ text: "hi" });
|
|
192
|
-
const req = webhookRequest(update, { secretToken: "s3cret" });
|
|
193
|
-
assert.equal(req.method, "POST");
|
|
194
|
-
assert.equal(req.headers.get("x-telegram-bot-api-secret-token"), "s3cret");
|
|
195
|
-
assert.deepEqual(await req.json(), update);
|
|
196
|
-
});
|
|
197
|
-
test("withFetch stubs globalThis.fetch for the duration of fn, then restores it", async () => {
|
|
198
|
-
const realFetch = globalThis.fetch;
|
|
199
|
-
const result = await withFetch(async () => new Response("stubbed"), async () => {
|
|
200
|
-
const res = await fetch("https://example.invalid/");
|
|
201
|
-
return res.text();
|
|
202
|
-
});
|
|
203
|
-
assert.equal(result, "stubbed");
|
|
204
|
-
assert.equal(globalThis.fetch, realFetch);
|
|
205
|
-
});
|
|
206
|
-
test("withFetch restores the original fetch even if fn throws", async () => {
|
|
207
|
-
const realFetch = globalThis.fetch;
|
|
208
|
-
await assert.rejects(withFetch(async () => new Response("x"), () => {
|
|
209
|
-
throw new Error("boom");
|
|
210
|
-
}));
|
|
211
|
-
assert.equal(globalThis.fetch, realFetch);
|
|
212
|
-
});
|
|
213
|
-
//# sourceMappingURL=index.test.js.map
|
package/lib/index.test.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.test.js","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":"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"}
|
package/src/index.test.ts
DELETED
|
@@ -1,320 +0,0 @@
|
|
|
1
|
-
import assert from "node:assert/strict";
|
|
2
|
-
import test from "node:test";
|
|
3
|
-
import { Composer, Context, TelegramError } from "@yaebal/core";
|
|
4
|
-
import {
|
|
5
|
-
callbackContext,
|
|
6
|
-
callbackUpdate,
|
|
7
|
-
channelPostUpdate,
|
|
8
|
-
chatJoinRequestUpdate,
|
|
9
|
-
chatMemberUpdate,
|
|
10
|
-
chosenInlineResultUpdate,
|
|
11
|
-
collectUpdates,
|
|
12
|
-
createContext,
|
|
13
|
-
createUpdate,
|
|
14
|
-
editedMessageUpdate,
|
|
15
|
-
findButton,
|
|
16
|
-
inlineQueryUpdate,
|
|
17
|
-
messageContext,
|
|
18
|
-
messageUpdate,
|
|
19
|
-
mockApi,
|
|
20
|
-
myChatMemberUpdate,
|
|
21
|
-
pollAnswerUpdate,
|
|
22
|
-
pollUpdate,
|
|
23
|
-
preCheckoutQueryUpdate,
|
|
24
|
-
runMiddleware,
|
|
25
|
-
shippingQueryUpdate,
|
|
26
|
-
webhookRequest,
|
|
27
|
-
withFetch,
|
|
28
|
-
} from "./index.js";
|
|
29
|
-
|
|
30
|
-
test("mockApi records calls and resolves sensible defaults", async () => {
|
|
31
|
-
const { api, calls } = mockApi();
|
|
32
|
-
|
|
33
|
-
const sent = await api.sendMessage({ chat_id: 1, text: "hi" });
|
|
34
|
-
assert.deepEqual(sent, { message_id: 1 });
|
|
35
|
-
|
|
36
|
-
const answered = await api.answerCallbackQuery({ callback_query_id: "1" });
|
|
37
|
-
assert.equal(answered, true);
|
|
38
|
-
|
|
39
|
-
const viaCall = await api.call("setMyCommands", { commands: [] });
|
|
40
|
-
assert.deepEqual(viaCall, {});
|
|
41
|
-
|
|
42
|
-
assert.deepEqual(calls, [
|
|
43
|
-
{ method: "sendMessage", params: { chat_id: 1, text: "hi" } },
|
|
44
|
-
{ method: "answerCallbackQuery", params: { callback_query_id: "1" } },
|
|
45
|
-
{ method: "setMyCommands", params: { commands: [] } },
|
|
46
|
-
]);
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test("mockApi hook registrars are chainable no-ops", () => {
|
|
50
|
-
const { api } = mockApi();
|
|
51
|
-
assert.equal(
|
|
52
|
-
api.before(() => undefined),
|
|
53
|
-
api,
|
|
54
|
-
);
|
|
55
|
-
assert.equal(
|
|
56
|
-
api.after((_m, r) => r),
|
|
57
|
-
api,
|
|
58
|
-
);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test("messageUpdate produces a valid message update", () => {
|
|
62
|
-
const update = messageUpdate({ text: "hello", chatId: 42, chatType: "group" });
|
|
63
|
-
|
|
64
|
-
assert.ok(update.update_id > 0);
|
|
65
|
-
|
|
66
|
-
assert.equal(update.message?.text, "hello");
|
|
67
|
-
assert.equal(update.message?.chat.id, 42);
|
|
68
|
-
assert.equal(update.message?.chat.type, "group");
|
|
69
|
-
assert.equal(update.message?.from?.id, 42);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("callbackUpdate produces a valid callback_query update", () => {
|
|
73
|
-
const update = callbackUpdate({ data: "click", chatId: 7, fromId: 9 });
|
|
74
|
-
|
|
75
|
-
assert.equal(update.callback_query?.data, "click");
|
|
76
|
-
assert.equal(update.callback_query?.from.id, 9);
|
|
77
|
-
assert.equal(update.callback_query?.message?.chat.id, 7);
|
|
78
|
-
});
|
|
79
|
-
|
|
80
|
-
test("createUpdate fills a fresh update_id", () => {
|
|
81
|
-
const a = createUpdate();
|
|
82
|
-
const b = createUpdate();
|
|
83
|
-
|
|
84
|
-
assert.notEqual(a.update_id, b.update_id);
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
test("createContext yields a Context whose getters work", () => {
|
|
88
|
-
const ctx = createContext(messageUpdate({ text: "yo", chatId: 5 }));
|
|
89
|
-
|
|
90
|
-
assert.ok(ctx instanceof Context);
|
|
91
|
-
|
|
92
|
-
assert.equal(ctx.updateType, "message");
|
|
93
|
-
assert.equal(ctx.text, "yo");
|
|
94
|
-
assert.equal(ctx.chat?.id, 5);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
test("createContext detects callback_query updates", () => {
|
|
98
|
-
const ctx = createContext(callbackUpdate({ data: "x" }));
|
|
99
|
-
|
|
100
|
-
assert.equal(ctx.updateType, "callback_query");
|
|
101
|
-
assert.equal(ctx.callbackQuery?.data, "x");
|
|
102
|
-
});
|
|
103
|
-
|
|
104
|
-
test("a handler calling ctx.reply records a sendMessage call", async () => {
|
|
105
|
-
const { api, calls } = mockApi();
|
|
106
|
-
|
|
107
|
-
const composer = new Composer().on("message:text", (ctx) => ctx.reply("pong"));
|
|
108
|
-
await runMiddleware(composer, createContext(messageUpdate({ text: "ping", chatId: 3 }), api));
|
|
109
|
-
|
|
110
|
-
assert.equal(calls.length, 1);
|
|
111
|
-
|
|
112
|
-
const call = calls[0];
|
|
113
|
-
assert.equal(call?.method, "sendMessage");
|
|
114
|
-
assert.equal(call?.params?.chat_id, 3);
|
|
115
|
-
assert.equal(call?.params?.text, "pong");
|
|
116
|
-
|
|
117
|
-
assert.deepEqual(call?.params?.reply_parameters, { message_id: 1 });
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("mockApi auto-increments message_id across send* calls", async () => {
|
|
121
|
-
const { api } = mockApi();
|
|
122
|
-
|
|
123
|
-
const first = await api.sendMessage({ chat_id: 1, text: "a" });
|
|
124
|
-
const second = await api.sendMessage({ chat_id: 1, text: "b" });
|
|
125
|
-
|
|
126
|
-
assert.deepEqual(first, { message_id: 1 });
|
|
127
|
-
assert.deepEqual(second, { message_id: 2 });
|
|
128
|
-
});
|
|
129
|
-
|
|
130
|
-
test("mockApi results: static override replaces the built-in default", async () => {
|
|
131
|
-
const { api } = mockApi({ results: { sendMessage: { message_id: 99 } } });
|
|
132
|
-
|
|
133
|
-
assert.deepEqual(await api.sendMessage({ chat_id: 1 }), { message_id: 99 });
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
test("mockApi results: an Error value makes the call throw", async () => {
|
|
137
|
-
const { api } = mockApi({
|
|
138
|
-
results: { sendMessage: new TelegramError("sendMessage", 400, "Bad Request") },
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
await assert.rejects(api.sendMessage({ chat_id: 1 }), TelegramError);
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test("mockApi results: a function sees params and a running attempt count", async () => {
|
|
145
|
-
const { api } = mockApi({
|
|
146
|
-
results: {
|
|
147
|
-
sendMessage: (params: Record<string, unknown> | undefined, attempt: number) =>
|
|
148
|
-
attempt <= 2
|
|
149
|
-
? new TelegramError("sendMessage", 429, "retry after 0")
|
|
150
|
-
: { message_id: 1, echo: params?.text },
|
|
151
|
-
},
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
api.onError((_m, _e, attempt) => (attempt <= 2 ? { retry: true } : undefined));
|
|
155
|
-
|
|
156
|
-
const result = await api.sendMessage({ chat_id: 1, text: "hi" });
|
|
157
|
-
assert.deepEqual(result, { message_id: 1, echo: "hi" });
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
test("mockApi.setResult overrides after creation; reset() clears calls and counters", async () => {
|
|
161
|
-
const { api, calls, setResult, reset } = mockApi();
|
|
162
|
-
|
|
163
|
-
await api.sendMessage({ chat_id: 1 });
|
|
164
|
-
setResult("sendMessage", { message_id: 42 });
|
|
165
|
-
assert.deepEqual(await api.sendMessage({ chat_id: 1 }), { message_id: 42 });
|
|
166
|
-
assert.equal(calls.length, 2);
|
|
167
|
-
|
|
168
|
-
reset();
|
|
169
|
-
assert.equal(calls.length, 0);
|
|
170
|
-
assert.deepEqual(await api.sendMessage({ chat_id: 1 }), { message_id: 42 });
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
test("mockApi.lastCall and callsTo filter recorded calls", async () => {
|
|
174
|
-
const { api, lastCall, callsTo } = mockApi();
|
|
175
|
-
|
|
176
|
-
await api.sendMessage({ chat_id: 1, text: "a" });
|
|
177
|
-
await api.answerCallbackQuery({ callback_query_id: "1" });
|
|
178
|
-
await api.sendMessage({ chat_id: 1, text: "b" });
|
|
179
|
-
|
|
180
|
-
assert.equal(lastCall()?.method, "sendMessage");
|
|
181
|
-
assert.equal(lastCall("answerCallbackQuery")?.method, "answerCallbackQuery");
|
|
182
|
-
assert.equal(lastCall("sendMessage")?.params?.text, "b");
|
|
183
|
-
assert.equal(callsTo("sendMessage").length, 2);
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
test("mockApi hooks actually run: before rewrites params, after rewrites result", async () => {
|
|
187
|
-
const { api } = mockApi();
|
|
188
|
-
|
|
189
|
-
api.before((_method, params) => ({ ...params, injected: true }));
|
|
190
|
-
api.after((_method, _params, result) => ({ ...(result as object), tagged: true }));
|
|
191
|
-
|
|
192
|
-
const result = await api.sendMessage({ chat_id: 1 });
|
|
193
|
-
|
|
194
|
-
assert.deepEqual(result, { message_id: 1, tagged: true });
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
test("channelPostUpdate / editedMessageUpdate build the right update key", () => {
|
|
198
|
-
assert.equal(channelPostUpdate({ text: "hi" }).channel_post?.text, "hi");
|
|
199
|
-
assert.equal(channelPostUpdate().channel_post?.chat.type, "channel");
|
|
200
|
-
assert.equal(editedMessageUpdate({ text: "hi" }).edited_message?.text, "hi");
|
|
201
|
-
});
|
|
202
|
-
|
|
203
|
-
test("inlineQueryUpdate / chosenInlineResultUpdate build their payloads", () => {
|
|
204
|
-
const iq = inlineQueryUpdate({ query: "cats", fromId: 5 });
|
|
205
|
-
assert.equal(iq.inline_query?.query, "cats");
|
|
206
|
-
assert.equal(iq.inline_query?.from.id, 5);
|
|
207
|
-
|
|
208
|
-
const cir = chosenInlineResultUpdate({ resultId: "r1", query: "cats" });
|
|
209
|
-
assert.equal(cir.chosen_inline_result?.result_id, "r1");
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
test("shippingQueryUpdate / preCheckoutQueryUpdate build valid payloads", () => {
|
|
213
|
-
const sq = shippingQueryUpdate({ shippingAddress: { city: "Berlin" } });
|
|
214
|
-
assert.equal(sq.shipping_query?.shipping_address.city, "Berlin");
|
|
215
|
-
|
|
216
|
-
const pcq = preCheckoutQueryUpdate({ currency: "EUR", totalAmount: 500 });
|
|
217
|
-
assert.equal(pcq.pre_checkout_query?.currency, "EUR");
|
|
218
|
-
assert.equal(pcq.pre_checkout_query?.total_amount, 500);
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
test("pollUpdate / pollAnswerUpdate build valid payloads", () => {
|
|
222
|
-
const poll = pollUpdate({ question: "?", options: ["a", "b", "c"] });
|
|
223
|
-
assert.equal(poll.poll?.options.length, 3);
|
|
224
|
-
assert.equal(poll.poll?.options[1]?.text, "b");
|
|
225
|
-
|
|
226
|
-
const answer = pollAnswerUpdate({ optionIds: [1] });
|
|
227
|
-
assert.deepEqual(answer.poll_answer?.option_ids, [1]);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
test("myChatMemberUpdate / chatMemberUpdate / chatJoinRequestUpdate build valid payloads", () => {
|
|
231
|
-
const my = myChatMemberUpdate({ oldStatus: "left", newStatus: "member" });
|
|
232
|
-
assert.equal(my.my_chat_member?.old_chat_member.status, "left");
|
|
233
|
-
assert.equal(my.my_chat_member?.new_chat_member.status, "member");
|
|
234
|
-
|
|
235
|
-
const other = chatMemberUpdate({ userId: 7 });
|
|
236
|
-
assert.equal(other.chat_member?.new_chat_member.user.id, 7);
|
|
237
|
-
|
|
238
|
-
const join = chatJoinRequestUpdate({ chatId: 3, fromId: 4, bio: "hi" });
|
|
239
|
-
assert.equal(join.chat_join_request?.chat.id, 3);
|
|
240
|
-
assert.equal(join.chat_join_request?.bio, "hi");
|
|
241
|
-
});
|
|
242
|
-
|
|
243
|
-
test("messageContext / callbackContext build a Context in one call", () => {
|
|
244
|
-
const ctx = messageContext({ text: "hi", chatId: 9 });
|
|
245
|
-
assert.equal(ctx.text, "hi");
|
|
246
|
-
assert.equal(ctx.chat?.id, 9);
|
|
247
|
-
|
|
248
|
-
const cbCtx = callbackContext({ data: "x" });
|
|
249
|
-
assert.equal(cbCtx.callbackQuery?.data, "x");
|
|
250
|
-
});
|
|
251
|
-
|
|
252
|
-
test("findButton locates a button by text and reports its position", () => {
|
|
253
|
-
const markup = {
|
|
254
|
-
inline_keyboard: [
|
|
255
|
-
[{ text: "a", callback_data: "a" }],
|
|
256
|
-
[
|
|
257
|
-
{ text: "b", callback_data: "b" },
|
|
258
|
-
{ text: "Next", callback_data: "page:2" },
|
|
259
|
-
],
|
|
260
|
-
],
|
|
261
|
-
};
|
|
262
|
-
|
|
263
|
-
const found = findButton(markup, "Next");
|
|
264
|
-
assert.equal(found?.callback_data, "page:2");
|
|
265
|
-
assert.equal(found?.row, 1);
|
|
266
|
-
assert.equal(found?.col, 1);
|
|
267
|
-
|
|
268
|
-
assert.equal(findButton(markup, /^n/i)?.text, "Next");
|
|
269
|
-
assert.equal(findButton(markup, "missing"), undefined);
|
|
270
|
-
assert.equal(findButton(undefined, "missing"), undefined);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
test("collectUpdates records every update handed to the sink", async () => {
|
|
274
|
-
const { sink, updates } = collectUpdates();
|
|
275
|
-
|
|
276
|
-
await sink.handleUpdate(messageUpdate({ text: "one" }));
|
|
277
|
-
await sink.handleUpdate(messageUpdate({ text: "two" }));
|
|
278
|
-
|
|
279
|
-
assert.equal(updates.length, 2);
|
|
280
|
-
assert.equal(updates[0]?.message?.text, "one");
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
test("webhookRequest builds a POST carrying the update as JSON, with an optional secret header", async () => {
|
|
284
|
-
const update = messageUpdate({ text: "hi" });
|
|
285
|
-
const req = webhookRequest(update, { secretToken: "s3cret" });
|
|
286
|
-
|
|
287
|
-
assert.equal(req.method, "POST");
|
|
288
|
-
assert.equal(req.headers.get("x-telegram-bot-api-secret-token"), "s3cret");
|
|
289
|
-
assert.deepEqual(await req.json(), update);
|
|
290
|
-
});
|
|
291
|
-
|
|
292
|
-
test("withFetch stubs globalThis.fetch for the duration of fn, then restores it", async () => {
|
|
293
|
-
const realFetch = globalThis.fetch;
|
|
294
|
-
|
|
295
|
-
const result = await withFetch(
|
|
296
|
-
async () => new Response("stubbed"),
|
|
297
|
-
async () => {
|
|
298
|
-
const res = await fetch("https://example.invalid/");
|
|
299
|
-
return res.text();
|
|
300
|
-
},
|
|
301
|
-
);
|
|
302
|
-
|
|
303
|
-
assert.equal(result, "stubbed");
|
|
304
|
-
assert.equal(globalThis.fetch, realFetch);
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
test("withFetch restores the original fetch even if fn throws", async () => {
|
|
308
|
-
const realFetch = globalThis.fetch;
|
|
309
|
-
|
|
310
|
-
await assert.rejects(
|
|
311
|
-
withFetch(
|
|
312
|
-
async () => new Response("x"),
|
|
313
|
-
() => {
|
|
314
|
-
throw new Error("boom");
|
|
315
|
-
},
|
|
316
|
-
),
|
|
317
|
-
);
|
|
318
|
-
|
|
319
|
-
assert.equal(globalThis.fetch, realFetch);
|
|
320
|
-
});
|