@yaebal/test 0.0.1 → 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.
Files changed (107) hide show
  1. package/README.md +400 -15
  2. package/lib/api.d.ts +83 -0
  3. package/lib/api.d.ts.map +1 -0
  4. package/lib/api.js +186 -0
  5. package/lib/api.js.map +1 -0
  6. package/lib/api.test.d.ts +2 -0
  7. package/lib/api.test.d.ts.map +1 -0
  8. package/lib/api.test.js +131 -0
  9. package/lib/api.test.js.map +1 -0
  10. package/lib/bot-messages.d.ts +42 -0
  11. package/lib/bot-messages.d.ts.map +1 -0
  12. package/lib/bot-messages.js +72 -0
  13. package/lib/bot-messages.js.map +1 -0
  14. package/lib/chat-actor.d.ts +45 -0
  15. package/lib/chat-actor.d.ts.map +1 -0
  16. package/lib/chat-actor.js +72 -0
  17. package/lib/chat-actor.js.map +1 -0
  18. package/lib/clock.d.ts +22 -0
  19. package/lib/clock.d.ts.map +1 -0
  20. package/lib/clock.js +72 -0
  21. package/lib/clock.js.map +1 -0
  22. package/lib/clock.test.d.ts +2 -0
  23. package/lib/clock.test.d.ts.map +1 -0
  24. package/lib/clock.test.js +69 -0
  25. package/lib/clock.test.js.map +1 -0
  26. package/lib/env.d.ts +100 -0
  27. package/lib/env.d.ts.map +1 -0
  28. package/lib/env.js +164 -0
  29. package/lib/env.js.map +1 -0
  30. package/lib/env.test.d.ts +2 -0
  31. package/lib/env.test.d.ts.map +1 -0
  32. package/lib/env.test.js +302 -0
  33. package/lib/env.test.js.map +1 -0
  34. package/lib/fetch.d.ts +3 -0
  35. package/lib/fetch.d.ts.map +1 -0
  36. package/lib/fetch.js +12 -0
  37. package/lib/fetch.js.map +1 -0
  38. package/lib/index.d.ts +19 -52
  39. package/lib/index.d.ts.map +1 -1
  40. package/lib/index.js +19 -115
  41. package/lib/index.js.map +1 -1
  42. package/lib/internal.d.ts +25 -0
  43. package/lib/internal.d.ts.map +1 -0
  44. package/lib/internal.js +19 -0
  45. package/lib/internal.js.map +1 -0
  46. package/lib/keyboard.d.ts +15 -0
  47. package/lib/keyboard.d.ts.map +1 -0
  48. package/lib/keyboard.js +25 -0
  49. package/lib/keyboard.js.map +1 -0
  50. package/lib/keyboard.test.d.ts +2 -0
  51. package/lib/keyboard.test.d.ts.map +1 -0
  52. package/lib/keyboard.test.js +31 -0
  53. package/lib/keyboard.test.js.map +1 -0
  54. package/lib/normalize.d.ts +10 -0
  55. package/lib/normalize.d.ts.map +1 -0
  56. package/lib/normalize.js +27 -0
  57. package/lib/normalize.js.map +1 -0
  58. package/lib/reactions.d.ts +3 -0
  59. package/lib/reactions.d.ts.map +1 -0
  60. package/lib/reactions.js +17 -0
  61. package/lib/reactions.js.map +1 -0
  62. package/lib/updates.d.ts +126 -0
  63. package/lib/updates.d.ts.map +1 -0
  64. package/lib/updates.js +200 -0
  65. package/lib/updates.js.map +1 -0
  66. package/lib/updates.test.d.ts +2 -0
  67. package/lib/updates.test.d.ts.map +1 -0
  68. package/lib/updates.test.js +72 -0
  69. package/lib/updates.test.js.map +1 -0
  70. package/lib/user-actor.d.ts +188 -0
  71. package/lib/user-actor.d.ts.map +1 -0
  72. package/lib/user-actor.js +465 -0
  73. package/lib/user-actor.js.map +1 -0
  74. package/lib/webhook.d.ts +18 -0
  75. package/lib/webhook.d.ts.map +1 -0
  76. package/lib/webhook.js +25 -0
  77. package/lib/webhook.js.map +1 -0
  78. package/lib/webhook.test.d.ts +2 -0
  79. package/lib/webhook.test.d.ts.map +1 -0
  80. package/lib/webhook.test.js +36 -0
  81. package/lib/webhook.test.js.map +1 -0
  82. package/package.json +7 -5
  83. package/src/api.test.ts +180 -0
  84. package/src/api.ts +289 -0
  85. package/src/bot-messages.ts +117 -0
  86. package/src/chat-actor.ts +101 -0
  87. package/src/clock.test.ts +80 -0
  88. package/src/clock.ts +118 -0
  89. package/src/env.test.ts +370 -0
  90. package/src/env.ts +235 -0
  91. package/src/fetch.ts +11 -0
  92. package/src/index.ts +79 -169
  93. package/src/internal.ts +43 -0
  94. package/src/keyboard.test.ts +35 -0
  95. package/src/keyboard.ts +38 -0
  96. package/src/normalize.ts +34 -0
  97. package/src/reactions.ts +18 -0
  98. package/src/updates.test.ts +107 -0
  99. package/src/updates.ts +354 -0
  100. package/src/user-actor.ts +702 -0
  101. package/src/webhook.test.ts +54 -0
  102. package/src/webhook.ts +48 -0
  103. package/lib/index.test.d.ts +0 -2
  104. package/lib/index.test.d.ts.map +0 -1
  105. package/lib/index.test.js +0 -66
  106. package/lib/index.test.js.map +0 -1
  107. package/src/index.test.ts +0 -101
@@ -0,0 +1,302 @@
1
+ import assert from "node:assert/strict";
2
+ import test from "node:test";
3
+ import { bold, Composer, format } from "@yaebal/core";
4
+ import { apiError } from "./api.js";
5
+ import { createTestEnv } from "./env.js";
6
+ test("createUser().sendMessage dispatches a message update and records the bot's reply", async () => {
7
+ const bot = new Composer().on("message:text", (ctx) => ctx.reply("pong"));
8
+ const env = createTestEnv(bot);
9
+ const user = env.createUser({ firstName: "Linia" });
10
+ await user.sendMessage("ping");
11
+ assert.equal(env.apiCalls.length, 1);
12
+ assert.equal(env.lastApiCall()?.method, "sendMessage");
13
+ assert.equal(env.lastApiCall("sendMessage")?.params?.text, "pong");
14
+ assert.equal(env.lastApiCall()?.params?.chat_id, user.pmChat.id);
15
+ });
16
+ test("sendMessage(chat, text) sends into a group; .in(chat) scopes the same way", async () => {
17
+ const bot = new Composer().on("message:text", (ctx) => ctx.reply("hi group"));
18
+ const env = createTestEnv(bot);
19
+ const user = env.createUser();
20
+ const group = env.createChat({ type: "group", title: "devs" });
21
+ await user.sendMessage(group, "hello");
22
+ assert.equal(env.lastApiCall("sendMessage")?.params?.chat_id, group.id);
23
+ env.clearApiCalls();
24
+ await user.in(group).sendMessage("hello again");
25
+ assert.equal(env.lastApiCall("sendMessage")?.params?.chat_id, group.id);
26
+ });
27
+ test("sendMessage accepts a format() result — entities are auto-extracted (rich integration)", async () => {
28
+ let entityType;
29
+ const bot = new Composer().on("message:text", (ctx) => {
30
+ entityType = ctx.message?.entities?.[0]?.type;
31
+ });
32
+ const env = createTestEnv(bot);
33
+ const user = env.createUser();
34
+ await user.sendMessage(format `Check out ${bold("this")}`);
35
+ assert.equal(entityType, "bold");
36
+ });
37
+ test("sendCommand attaches a bot_command entity and parses args via Composer.command", async () => {
38
+ let captured;
39
+ const bot = new Composer().command("start", (ctx) => {
40
+ captured = { command: ctx.command, args: ctx.args };
41
+ });
42
+ const env = createTestEnv(bot);
43
+ const user = env.createUser();
44
+ await user.sendCommand("start", "ref42");
45
+ assert.deepEqual(captured, { command: "start", args: ["ref42"] });
46
+ });
47
+ test("sendReply sets reply_to_message and targets the same chat", async () => {
48
+ const bot = new Composer();
49
+ const env = createTestEnv(bot);
50
+ const user = env.createUser();
51
+ const group = env.createChat({ type: "group" });
52
+ const original = await user.sendMessage(group, "hello");
53
+ const reply = await user.sendReply(original, "nice to meet you");
54
+ assert.equal(reply.reply_to_message?.message_id, original.message_id);
55
+ assert.equal(reply.chat.id, group.id);
56
+ });
57
+ test("media shortcuts attach a plausible attachment with auto file ids, caption entities, and spoiler", async () => {
58
+ const bot = new Composer();
59
+ const env = createTestEnv(bot);
60
+ const user = env.createUser();
61
+ const photo = await user.sendPhoto({ caption: format `nice ${bold("shot")}`, spoiler: true });
62
+ assert.ok(photo.photo?.length);
63
+ assert.ok(photo.photo?.[0]?.file_id);
64
+ assert.equal(photo.caption, "nice shot");
65
+ assert.equal(photo.caption_entities?.[0]?.type, "bold");
66
+ assert.equal(photo.has_media_spoiler, true);
67
+ const sticker = await user.sendSticker({ emoji: "🔥" });
68
+ assert.equal(sticker.sticker?.type, "regular");
69
+ assert.equal(sticker.sticker?.emoji, "🔥");
70
+ });
71
+ test("sendMediaGroup dispatches one message per item, all sharing media_group_id", async () => {
72
+ const groupIds = [];
73
+ const bot = new Composer().on("message", (ctx) => {
74
+ if (ctx.message?.media_group_id)
75
+ groupIds.push(ctx.message.media_group_id);
76
+ });
77
+ const env = createTestEnv(bot);
78
+ const user = env.createUser();
79
+ const group = env.createChat({ type: "group" });
80
+ const [m1, m2] = await user.sendMediaGroup(group, [
81
+ { photo: [{ file_id: "f1", file_unique_id: "u1", width: 100, height: 100 }] },
82
+ { photo: [{ file_id: "f2", file_unique_id: "u2", width: 100, height: 100 }] },
83
+ ]);
84
+ assert.equal(groupIds.length, 2);
85
+ assert.equal(m1?.media_group_id, m2?.media_group_id);
86
+ });
87
+ test("click() dispatches a callback_query the bot's callbackQuery() handler sees", async () => {
88
+ let seenData;
89
+ const bot = new Composer().callbackQuery("vote:up", (ctx) => {
90
+ seenData = ctx.callbackQuery.data;
91
+ });
92
+ const env = createTestEnv(bot);
93
+ const user = env.createUser();
94
+ await user.click("vote:up");
95
+ assert.equal(seenData, "vote:up");
96
+ });
97
+ test("lastBotMessage() stays in sync with editMessageText/editMessageReplyMarkup, even on an earlier reference", async () => {
98
+ const bot = new Composer()
99
+ .on("message:text", (ctx) => ctx.send("Pick:", {
100
+ reply_markup: { inline_keyboard: [[{ text: "Next", callback_data: "next" }]] },
101
+ }))
102
+ .callbackQuery("next", async (ctx) => {
103
+ const msg = ctx.callbackQuery.message;
104
+ await ctx.api.call("editMessageText", {
105
+ chat_id: msg.chat.id,
106
+ message_id: msg.message_id,
107
+ text: "Done!",
108
+ });
109
+ await ctx.api.call("editMessageReplyMarkup", {
110
+ chat_id: msg.chat.id,
111
+ message_id: msg.message_id,
112
+ reply_markup: { inline_keyboard: [[{ text: "Restart", callback_data: "restart" }]] },
113
+ });
114
+ });
115
+ const env = createTestEnv(bot);
116
+ const user = env.createUser();
117
+ await user.sendMessage("hi");
118
+ const bubble = env.lastBotMessage();
119
+ assert.ok(bubble);
120
+ assert.ok(bubble.reply_markup);
121
+ await user.on(bubble).clickByText("Next");
122
+ assert.equal(env.lastBotMessage(), bubble); // same reference
123
+ assert.equal(bubble.text, "Done!");
124
+ assert.equal((bubble.reply_markup?.inline_keyboard)[0]?.length, 1);
125
+ await user.on(bubble).clickByText("Restart");
126
+ });
127
+ test("lastBotMessage() query filters: chat, withReplyMarkup, where", async () => {
128
+ const bot = new Composer().on("message:text", (ctx) => {
129
+ if (ctx.text === "plain")
130
+ return ctx.reply("no markup");
131
+ return ctx.reply("with markup", {
132
+ reply_markup: { inline_keyboard: [[{ text: "x", callback_data: "x" }]] },
133
+ });
134
+ });
135
+ const env = createTestEnv(bot);
136
+ const user = env.createUser();
137
+ const group = env.createChat({ type: "group" });
138
+ await user.sendMessage("plain");
139
+ await user.sendMessage(group, "keyboard");
140
+ assert.equal(env.lastBotMessage({ chat: user.pmChat })?.text, "no markup");
141
+ assert.equal(env.lastBotMessage({ withReplyMarkup: true })?.chat.id, group.id);
142
+ assert.equal(env.lastBotMessage({
143
+ where: (call) => call.method === "sendMessage" && call.params?.chat_id === group.id,
144
+ })?.text, "with markup");
145
+ });
146
+ test("react() infers old_reaction from this user's last reaction on the message", async () => {
147
+ const seen = [];
148
+ const bot = new Composer().on("message_reaction", (ctx) => {
149
+ const r = ctx.update.message_reaction;
150
+ if (!r)
151
+ return;
152
+ seen.push({
153
+ old: r.old_reaction.map((x) => ("emoji" in x ? x.emoji : "")),
154
+ new: r.new_reaction.map((x) => ("emoji" in x ? x.emoji : "")),
155
+ });
156
+ });
157
+ const env = createTestEnv(bot);
158
+ const user = env.createUser();
159
+ const msg = await user.sendMessage("nice bot");
160
+ await user.react("👍", msg);
161
+ await user.react("❤", msg);
162
+ await user.react([], msg);
163
+ assert.deepEqual(seen[0], { old: [], new: ["👍"] });
164
+ assert.deepEqual(seen[1], { old: ["👍"], new: ["❤"] });
165
+ assert.deepEqual(seen[2], { old: ["❤"], new: [] });
166
+ });
167
+ test("join()/leave() track chat.members and dispatch chat_member + a service message", async () => {
168
+ const serviceMessages = [];
169
+ const bot = new Composer().on("message", (ctx) => {
170
+ if (ctx.message?.new_chat_members)
171
+ serviceMessages.push("joined");
172
+ if (ctx.message?.left_chat_member)
173
+ serviceMessages.push("left");
174
+ });
175
+ const env = createTestEnv(bot);
176
+ const user = env.createUser();
177
+ const group = env.createChat({ type: "group" });
178
+ await user.join(group);
179
+ assert.equal(group.members.has(user), true);
180
+ assert.equal(group.membershipOf(user)?.status, "member");
181
+ assert.deepEqual(serviceMessages, ["joined"]);
182
+ await user.leave(group);
183
+ assert.equal(group.members.has(user), false);
184
+ assert.equal(group.membershipOf(user)?.status, "left");
185
+ assert.deepEqual(serviceMessages, ["joined", "left"]);
186
+ });
187
+ test("sendInlineQuery / chooseInlineResult dispatch their updates", async () => {
188
+ let query;
189
+ let chosen;
190
+ const bot = new Composer()
191
+ .on("inline_query", (ctx) => {
192
+ query = ctx.update.inline_query?.query;
193
+ })
194
+ .on("chosen_inline_result", (ctx) => {
195
+ chosen = ctx.update.chosen_inline_result?.result_id;
196
+ });
197
+ const env = createTestEnv(bot);
198
+ const user = env.createUser();
199
+ const group = env.createChat({ type: "group" });
200
+ await user.sendInlineQuery("cats", group);
201
+ await user.chooseInlineResult("r1", "cats");
202
+ assert.equal(query, "cats");
203
+ assert.equal(chosen, "r1");
204
+ });
205
+ test("sendSuccessfulPayment throws unless the bot answered pre_checkout_query with ok: true", async () => {
206
+ const notHandling = createTestEnv(new Composer());
207
+ await assert.rejects(notHandling.createUser().sendSuccessfulPayment({ invoice_payload: "x" }), /never answered the pre_checkout_query/);
208
+ const rejecting = createTestEnv(new Composer().on("pre_checkout_query", async (ctx) => {
209
+ await ctx.api.call("answerPreCheckoutQuery", {
210
+ pre_checkout_query_id: ctx.update.pre_checkout_query?.id,
211
+ ok: false,
212
+ });
213
+ }));
214
+ await assert.rejects(rejecting.createUser().sendSuccessfulPayment({ invoice_payload: "x" }));
215
+ let paid;
216
+ const accepting = createTestEnv(new Composer()
217
+ .on("pre_checkout_query", async (ctx) => {
218
+ await ctx.api.call("answerPreCheckoutQuery", {
219
+ pre_checkout_query_id: ctx.update.pre_checkout_query?.id,
220
+ ok: true,
221
+ });
222
+ })
223
+ .on("message", (ctx) => {
224
+ paid = ctx.message?.successful_payment?.invoice_payload;
225
+ }));
226
+ await accepting.createUser().sendSuccessfulPayment({ invoice_payload: "sub_monthly" });
227
+ assert.equal(paid, "sub_monthly");
228
+ });
229
+ test("onApi/apiError let a test simulate a Telegram failure the bot must handle", async () => {
230
+ const bot = new Composer().on("message:text", async (ctx) => {
231
+ try {
232
+ await ctx.reply("hi");
233
+ }
234
+ catch {
235
+ // swallow — this bot doesn't retry, just shouldn't crash the test
236
+ }
237
+ });
238
+ const env = createTestEnv(bot);
239
+ env.onApi("sendMessage", apiError(403, "Forbidden: bot was blocked by the user"));
240
+ await env.createUser().sendMessage("hi");
241
+ assert.equal(env.lastApiCall("sendMessage")?.error instanceof Error, true);
242
+ });
243
+ test("strictDispatch throws when no handler consumes the update", async () => {
244
+ const env = createTestEnv(new Composer(), { strictDispatch: true });
245
+ await assert.rejects(env.createUser().sendMessage("hi"), /no handler consumed/);
246
+ });
247
+ test("advanceTime() lets code under test skip a real setTimeout wait", async () => {
248
+ let resumed = false;
249
+ const bot = new Composer().on("message", () => {
250
+ setTimeout(() => {
251
+ resumed = true;
252
+ }, 5000);
253
+ });
254
+ const env = createTestEnv(bot);
255
+ env.useFakeTimers(); // arm before the handler schedules its setTimeout
256
+ await env.createUser().sendMessage("hi");
257
+ assert.equal(resumed, false);
258
+ await env.advanceTime(5000);
259
+ assert.equal(resumed, true);
260
+ env.shutdown();
261
+ });
262
+ test("chat.post() emits an anonymous channel_post and throws on non-channel chats", async () => {
263
+ let fromIsUndefined = false;
264
+ const bot = new Composer().on("channel_post", (ctx) => {
265
+ fromIsUndefined = ctx.update.channel_post?.from === undefined;
266
+ });
267
+ const env = createTestEnv(bot);
268
+ const channel = env.createChat({ type: "channel", title: "News" });
269
+ const group = env.createChat({ type: "group" });
270
+ await channel.post("breaking news");
271
+ assert.equal(fromIsUndefined, true);
272
+ await assert.rejects(group.post("nope"), /only channel chats can post/);
273
+ });
274
+ test("onPostDispatch hooks run after each dispatched update, in registration order", async () => {
275
+ const order = [];
276
+ const env = createTestEnv(new Composer());
277
+ env.onPostDispatch(() => {
278
+ order.push("first");
279
+ });
280
+ env.onPostDispatch(() => {
281
+ order.push("second");
282
+ });
283
+ await env.createUser().sendMessage("hi");
284
+ assert.deepEqual(order, ["first", "second"]);
285
+ });
286
+ test("packs: setup(env) runs at construction time and can seed api overrides", () => {
287
+ let ran = false;
288
+ const env = createTestEnv(new Composer(), {
289
+ packs: [
290
+ {
291
+ name: "probe",
292
+ setup(e) {
293
+ ran = true;
294
+ e.onApi("getMe", { id: 99, is_bot: true, first_name: "probe" });
295
+ },
296
+ },
297
+ ],
298
+ });
299
+ assert.equal(ran, true);
300
+ return env.api.getMe().then((me) => assert.equal(me.id, 99));
301
+ });
302
+ //# sourceMappingURL=env.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.test.js","sourceRoot":"","sources":["../src/env.test.ts"],"names":[],"mappings":"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"}
package/lib/fetch.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /** stub `globalThis.fetch` for the duration of `fn`, restoring the original afterwards (even on throw). */
2
+ export declare function withFetch<T>(handler: typeof fetch, fn: () => T | Promise<T>): Promise<T>;
3
+ //# sourceMappingURL=fetch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.d.ts","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,wBAAsB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAS9F"}
package/lib/fetch.js ADDED
@@ -0,0 +1,12 @@
1
+ /** stub `globalThis.fetch` for the duration of `fn`, restoring the original afterwards (even on throw). */
2
+ export async function withFetch(handler, fn) {
3
+ const realFetch = globalThis.fetch;
4
+ globalThis.fetch = handler;
5
+ try {
6
+ return await fn();
7
+ }
8
+ finally {
9
+ globalThis.fetch = realFetch;
10
+ }
11
+ }
12
+ //# sourceMappingURL=fetch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch.js","sourceRoot":"","sources":["../src/fetch.ts"],"names":[],"mappings":"AAAA,2GAA2G;AAC3G,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,OAAqB,EAAE,EAAwB;IACjF,MAAM,SAAS,GAAG,UAAU,CAAC,KAAK,CAAC;IACnC,UAAU,CAAC,KAAK,GAAG,OAAO,CAAC;IAE3B,IAAI,CAAC;QACJ,OAAO,MAAM,EAAE,EAAE,CAAC;IACnB,CAAC;YAAS,CAAC;QACV,UAAU,CAAC,KAAK,GAAG,SAAS,CAAC;IAC9B,CAAC;AACF,CAAC"}
package/lib/index.d.ts CHANGED
@@ -1,56 +1,23 @@
1
1
  /**
2
- * @yaebal/test — testing utilities for yaebal bots.
2
+ * @yaebal/test — an actor-driven test framework for yaebal bots, with zero dependency on any
3
+ * test runner or assertion library. Works with `node:test`, vitest, bun:test, jest, ava —
4
+ * anything that can `await` a promise and call `assert`.
3
5
  *
4
- * every plugin test used to hand-build fake updates and a mock api. this package
5
- * extracts that boilerplate: {@link mockApi} records every call, the `*Update`
6
- * factories produce real {@link Update} shapes, and {@link createContext} wraps
7
- * one in a core {@link Context}.
8
- */
9
- import { type Api, type Composer, Context, type Message, type Update, type UpdateName } from "@yaebal/core";
10
- /** a single recorded api call: the method name and the params it was given. */
11
- export interface RecordedCall {
12
- method: string;
13
- params: Record<string, unknown> | undefined;
14
- }
15
- /** result of {@link mockApi}: the fake `api` plus the array it records into. */
16
- export interface MockApi {
17
- api: Api;
18
- calls: RecordedCall[];
19
- }
20
- /**
21
- * a fake {@link Api} whose every method records `{ method, params }` into `calls`
22
- * and resolves to a sensible default (`{ message_id: 1 }` for `send*`, `true` for
23
- * `answerCallbackQuery`, `{}` otherwise). hook registrars (`before`/`after`/
24
- * `onError`) are no-ops that return the api for chaining.
25
- */
26
- export declare function mockApi(): MockApi;
27
- /** build an {@link Update} from a partial, filling in a fresh `update_id`. */
28
- export declare function createUpdate(partial?: Partial<Update>): Update;
29
- /** options for {@link messageUpdate}. */
30
- export interface MessageUpdateOptions {
31
- text?: string;
32
- chatId?: number;
33
- fromId?: number;
34
- chatType?: "private" | "group" | "supergroup" | "channel";
35
- }
36
- /** build a message {@link Update}. */
37
- export declare function messageUpdate(options?: MessageUpdateOptions): Update;
38
- /** options for {@link callbackUpdate}. */
39
- export interface CallbackUpdateOptions {
40
- data?: string;
41
- chatId?: number;
42
- fromId?: number;
43
- }
44
- /** build a callback_query {@link Update}. */
45
- export declare function callbackUpdate(options?: CallbackUpdateOptions): Update;
46
- /** infer which payload key an update carries; defaults to `"message"`. */
47
- export declare function detectUpdateType(update: Update): UpdateName;
48
- /**
49
- * wrap an {@link Update} in a core {@link Context}. the api defaults to a fresh
50
- * {@link mockApi}; pass `updateType` to override the auto-detected one.
6
+ * {@link createTestEnv} wraps your bot and hands you {@link UserActor}/{@link ChatActor} actors
7
+ * that send it real updates messages, commands, media, reactions, button clicks, joins,
8
+ * payments the way real Telegram users would. every outgoing api call is intercepted and
9
+ * recorded (no real HTTP), with sensible auto-stubs, `onApi`/`apiError` overrides for the rest,
10
+ * a virtual clock for TTL/retry tests, and satellite-plugin test packs.
11
+ *
12
+ * fixture builders ({@link messageUpdate} & co.), {@link webhookRequest}/{@link collectUpdates},
13
+ * and {@link withFetch} remain as the escape hatch beneath the actor api — reach for them when
14
+ * you need a raw update shape or full control.
51
15
  */
52
- export declare function createContext(update: Update, api?: Api, updateType?: UpdateName): Context;
53
- /** run a composer's middleware against a context. resolves when the chain settles. */
54
- export declare function runMiddleware<C extends Context>(composer: Composer<C>, ctx: C): Promise<void>;
55
- export type { Message };
16
+ export { type MockApi, type MockApiOptions, mockApi } from "./api.js";
17
+ export { type ApiErrorSentinel, apiError, type BotMessage, ChatActor, type ChatMembership, type ChatType, type CreateChatOptions, createTestEnv, installTestClock, isApiErrorSentinel, type LastBotMessageQuery, type MediaOptions, type MessageOptions, type MockResult, type OnApiOptions, type RecordedCall, TestApiError, type TestClock, TestEnv, type TestEnvOptions, type TestPack, UserActor, UserInChatScope, UserOnMessageScope, } from "./env.js";
18
+ export { withFetch } from "./fetch.js";
19
+ export { type FoundButton, findButton } from "./keyboard.js";
20
+ export { toPlain } from "./normalize.js";
21
+ export { type BuildUserOptions, buildUser, type CallbackUpdateOptions, type ChatJoinRequestUpdateOptions, type ChatMemberUpdateOptions, type ChosenInlineResultUpdateOptions, callbackUpdate, channelPostUpdate, chatJoinRequestUpdate, chatMemberUpdate, chosenInlineResultUpdate, createUpdate, detectUpdateType, editedChannelPostUpdate, editedMessageUpdate, type InlineQueryUpdateOptions, inlineQueryUpdate, type MessageUpdateOptions, messageUpdate, myChatMemberUpdate, type PollAnswerUpdateOptions, type PollUpdateOptions, type PreCheckoutQueryUpdateOptions, pollAnswerUpdate, pollUpdate, preCheckoutQueryUpdate, type ShippingQueryUpdateOptions, shippingQueryUpdate, } from "./updates.js";
22
+ export { collectUpdates, type UpdateCollector, type WebhookRequestOptions, webhookRequest, } from "./webhook.js";
56
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACN,KAAK,GAAG,EACR,KAAK,QAAQ,EACb,OAAO,EACP,KAAK,OAAO,EAEZ,KAAK,MAAM,EACX,KAAK,UAAU,EACf,MAAM,cAAc,CAAC;AAEtB,+EAA+E;AAC/E,MAAM,WAAW,YAAY;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;CAC5C;AAED,gFAAgF;AAChF,MAAM,WAAW,OAAO;IACvB,GAAG,EAAE,GAAG,CAAC;IACT,KAAK,EAAE,YAAY,EAAE,CAAC;CACtB;AAcD;;;;;GAKG;AACH,wBAAgB,OAAO,IAAI,OAAO,CA4BjC;AAID,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,OAAO,GAAE,OAAO,CAAC,MAAM,CAAM,GAAG,MAAM,CAElE;AAED,yCAAyC;AACzC,MAAM,WAAW,oBAAoB;IACpC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,SAAS,GAAG,OAAO,GAAG,YAAY,GAAG,SAAS,CAAC;CAC1D;AAED,sCAAsC;AACtC,wBAAgB,aAAa,CAAC,OAAO,GAAE,oBAAyB,GAAG,MAAM,CAYxE;AAED,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,CAAC,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAgB1E;AAED,0EAA0E;AAC1E,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAY3D;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,EAAE,UAAU,GAAG,OAAO,CAMzF;AAID,sFAAsF;AACtF,wBAAsB,aAAa,CAAC,CAAC,SAAS,OAAO,EACpD,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC,EACrB,GAAG,EAAE,CAAC,GACJ,OAAO,CAAC,IAAI,CAAC,CAEf;AAED,YAAY,EAAE,OAAO,EAAE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,cAAc,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EACN,KAAK,gBAAgB,EACrB,QAAQ,EACR,KAAK,UAAU,EACf,SAAS,EACT,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,iBAAiB,EACtB,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,YAAY,EACZ,KAAK,SAAS,EACd,OAAO,EACP,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,SAAS,EACT,eAAe,EACf,kBAAkB,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAE,KAAK,WAAW,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EACN,KAAK,gBAAgB,EACrB,SAAS,EACT,KAAK,qBAAqB,EAC1B,KAAK,4BAA4B,EACjC,KAAK,uBAAuB,EAC5B,KAAK,+BAA+B,EACpC,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EACnB,KAAK,wBAAwB,EAC7B,iBAAiB,EACjB,KAAK,oBAAoB,EACzB,aAAa,EACb,kBAAkB,EAClB,KAAK,uBAAuB,EAC5B,KAAK,iBAAiB,EACtB,KAAK,6BAA6B,EAClC,gBAAgB,EAChB,UAAU,EACV,sBAAsB,EACtB,KAAK,0BAA0B,EAC/B,mBAAmB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,cAAc,EACd,KAAK,eAAe,EACpB,KAAK,qBAAqB,EAC1B,cAAc,GACd,MAAM,cAAc,CAAC"}
package/lib/index.js CHANGED
@@ -1,119 +1,23 @@
1
1
  /**
2
- * @yaebal/test — testing utilities for yaebal bots.
2
+ * @yaebal/test — an actor-driven test framework for yaebal bots, with zero dependency on any
3
+ * test runner or assertion library. Works with `node:test`, vitest, bun:test, jest, ava —
4
+ * anything that can `await` a promise and call `assert`.
3
5
  *
4
- * every plugin test used to hand-build fake updates and a mock api. this package
5
- * extracts that boilerplate: {@link mockApi} records every call, the `*Update`
6
- * factories produce real {@link Update} shapes, and {@link createContext} wraps
7
- * one in a core {@link Context}.
8
- */
9
- import { Context, } from "@yaebal/core";
10
- /** default results for known methods; everything else resolves to `{}`. */
11
- function defaultResult(method) {
12
- if (method.startsWith("send") || method === "copyMessage" || method === "forwardMessage") {
13
- return { message_id: 1 };
14
- }
15
- if (method === "answerCallbackQuery")
16
- return true;
17
- if (method === "getMe")
18
- return { id: 1, is_bot: true, first_name: "bot", username: "bot" };
19
- return {};
20
- }
21
- /**
22
- * a fake {@link Api} whose every method records `{ method, params }` into `calls`
23
- * and resolves to a sensible default (`{ message_id: 1 }` for `send*`, `true` for
24
- * `answerCallbackQuery`, `{}` otherwise). hook registrars (`before`/`after`/
25
- * `onError`) are no-ops that return the api for chaining.
26
- */
27
- export function mockApi() {
28
- const calls = [];
29
- const record = (method, params) => {
30
- calls.push({ method, params });
31
- return Promise.resolve(defaultResult(method));
32
- };
33
- const registrar = {
34
- call: (method, params) => record(method, params),
35
- fileUrl: (filePath) => `https://example.invalid/file/${filePath}`,
36
- before: () => api,
37
- after: () => api,
38
- onError: () => api,
39
- };
40
- const api = new Proxy(registrar, {
41
- get(obj, prop) {
42
- if (prop in obj)
43
- return obj[prop];
44
- const method = (params) => record(prop, params);
45
- obj[prop] = method;
46
- return method;
47
- },
48
- });
49
- return { api, calls };
50
- }
51
- let updateIdCounter = 0;
52
- /** build an {@link Update} from a partial, filling in a fresh `update_id`. */
53
- export function createUpdate(partial = {}) {
54
- return { update_id: ++updateIdCounter, ...partial };
55
- }
56
- /** build a message {@link Update}. */
57
- export function messageUpdate(options = {}) {
58
- const { text = "", chatId = 1, fromId = chatId, chatType = "private" } = options;
59
- return createUpdate({
60
- message: {
61
- message_id: 1,
62
- date: 0,
63
- chat: { id: chatId, type: chatType },
64
- from: { id: fromId, is_bot: false, first_name: "u" },
65
- text,
66
- },
67
- });
68
- }
69
- /** build a callback_query {@link Update}. */
70
- export function callbackUpdate(options = {}) {
71
- const { data = "", chatId = 1, fromId = chatId } = options;
72
- return createUpdate({
73
- callback_query: {
74
- id: "1",
75
- chat_instance: "0",
76
- from: { id: fromId, is_bot: false, first_name: "u" },
77
- message: {
78
- message_id: 1,
79
- date: 0,
80
- chat: { id: chatId, type: "private" },
81
- },
82
- data,
83
- },
84
- });
85
- }
86
- /** infer which payload key an update carries; defaults to `"message"`. */
87
- export function detectUpdateType(update) {
88
- if (update.message)
89
- return "message";
90
- if (update.edited_message)
91
- return "edited_message";
92
- if (update.channel_post)
93
- return "channel_post";
94
- if (update.callback_query)
95
- return "callback_query";
96
- const bag = update;
97
- for (const key of Object.keys(bag)) {
98
- if (key !== "update_id" && bag[key] !== undefined)
99
- return key;
100
- }
101
- return "message";
102
- }
103
- /**
104
- * wrap an {@link Update} in a core {@link Context}. the api defaults to a fresh
105
- * {@link mockApi}; pass `updateType` to override the auto-detected one.
6
+ * {@link createTestEnv} wraps your bot and hands you {@link UserActor}/{@link ChatActor} actors
7
+ * that send it real updates messages, commands, media, reactions, button clicks, joins,
8
+ * payments the way real Telegram users would. every outgoing api call is intercepted and
9
+ * recorded (no real HTTP), with sensible auto-stubs, `onApi`/`apiError` overrides for the rest,
10
+ * a virtual clock for TTL/retry tests, and satellite-plugin test packs.
11
+ *
12
+ * fixture builders ({@link messageUpdate} & co.), {@link webhookRequest}/{@link collectUpdates},
13
+ * and {@link withFetch} remain as the escape hatch beneath the actor api — reach for them when
14
+ * you need a raw update shape or full control.
106
15
  */
107
- export function createContext(update, api, updateType) {
108
- return new Context({
109
- api: api ?? mockApi().api,
110
- update,
111
- updateType: updateType ?? detectUpdateType(update),
112
- });
113
- }
114
- const noop = async () => { };
115
- /** run a composer's middleware against a context. resolves when the chain settles. */
116
- export async function runMiddleware(composer, ctx) {
117
- await composer.toMiddleware()(ctx, noop);
118
- }
16
+ export { mockApi } from "./api.js";
17
+ export { apiError, ChatActor, createTestEnv, installTestClock, isApiErrorSentinel, TestApiError, TestEnv, UserActor, UserInChatScope, UserOnMessageScope, } from "./env.js";
18
+ export { withFetch } from "./fetch.js";
19
+ export { findButton } from "./keyboard.js";
20
+ export { toPlain } from "./normalize.js";
21
+ export { buildUser, callbackUpdate, channelPostUpdate, chatJoinRequestUpdate, chatMemberUpdate, chosenInlineResultUpdate, createUpdate, detectUpdateType, editedChannelPostUpdate, editedMessageUpdate, inlineQueryUpdate, messageUpdate, myChatMemberUpdate, pollAnswerUpdate, pollUpdate, preCheckoutQueryUpdate, shippingQueryUpdate, } from "./updates.js";
22
+ export { collectUpdates, webhookRequest, } from "./webhook.js";
119
23
  //# sourceMappingURL=index.js.map
package/lib/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAqC,OAAO,EAAE,MAAM,UAAU,CAAC;AACtE,OAAO,EAEN,QAAQ,EAER,SAAS,EAIT,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAOlB,YAAY,EAEZ,OAAO,EAGP,SAAS,EACT,eAAe,EACf,kBAAkB,GAClB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,OAAO,EAAoB,UAAU,EAAE,MAAM,eAAe,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AACzC,OAAO,EAEN,SAAS,EAKT,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,EACxB,YAAY,EACZ,gBAAgB,EAChB,uBAAuB,EACvB,mBAAmB,EAEnB,iBAAiB,EAEjB,aAAa,EACb,kBAAkB,EAIlB,gBAAgB,EAChB,UAAU,EACV,sBAAsB,EAEtB,mBAAmB,GACnB,MAAM,cAAc,CAAC;AACtB,OAAO,EACN,cAAc,EAGd,cAAc,GACd,MAAM,cAAc,CAAC"}
@@ -0,0 +1,25 @@
1
+ import type { FormatResult, MessageEntity, Update } from "@yaebal/core";
2
+ /**
3
+ * the sliver of {@link TestEnv} actors need — kept as a separate interface (rather than a
4
+ * circular import of the class) so `chat-actor.ts`/`user-actor.ts` don't depend on `env.ts`.
5
+ */
6
+ export interface ActorHost {
7
+ dispatch(update: Update): Promise<void>;
8
+ nextMessageId(): number;
9
+ now(): number;
10
+ /** did the bot answer `answerPreCheckoutQuery` for `preCheckoutQueryId` with `ok: true`? */
11
+ answeredPreCheckoutQuery(preCheckoutQueryId: string): boolean;
12
+ }
13
+ /** text an actor method accepts: a plain string, or a `format`/`fmt` result carrying entities. */
14
+ export type SendText = string | FormatResult;
15
+ /** resolve a `SendText` into `{ text, entities }`, merging in any `extraEntities`. */
16
+ export declare function resolveSendText(text: SendText, extraEntities?: MessageEntity[]): {
17
+ text: string;
18
+ entities: MessageEntity[];
19
+ };
20
+ /** a fake `{ file_id, file_unique_id }` pair — good enough for tests, never a real download. */
21
+ export declare function fakeFile(prefix: string): {
22
+ file_id: string;
23
+ file_unique_id: string;
24
+ };
25
+ //# sourceMappingURL=internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAExE;;;GAGG;AACH,MAAM,WAAW,SAAS;IACzB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,aAAa,IAAI,MAAM,CAAC;IACxB,GAAG,IAAI,MAAM,CAAC;IACd,4FAA4F;IAC5F,wBAAwB,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9D;AAED,kGAAkG;AAClG,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,YAAY,CAAC;AAY7C,sFAAsF;AACtF,wBAAgB,eAAe,CAC9B,IAAI,EAAE,QAAQ,EACd,aAAa,GAAE,aAAa,EAAO,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,aAAa,EAAE,CAAA;CAAE,CAG7C;AAID,gGAAgG;AAChG,wBAAgB,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,CAAA;CAAE,CAGpF"}