@mks2508/telegram-message-builder 0.2.0 → 0.3.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/dist/index.cjs +1057 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1022 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/builder/builder.d.ts +55 -0
- package/src/builder/builder.d.ts.map +1 -1
- package/src/builder/builder.ts +145 -10
- package/src/builder/index.d.ts +2 -1
- package/src/builder/index.d.ts.map +1 -1
- package/src/builder/index.ts +2 -1
- package/src/builder/media.d.ts +352 -0
- package/src/builder/media.d.ts.map +1 -0
- package/src/builder/media.test.ts +664 -0
- package/src/builder/media.ts +484 -0
- package/src/builder.test.ts +465 -0
- package/src/escaping.test.ts +2 -2
- package/src/formatters/index.d.ts +47 -0
- package/src/formatters/index.d.ts.map +1 -1
- package/src/formatters/index.ts +92 -1
- package/src/formatters/markdown.d.ts +179 -0
- package/src/formatters/markdown.d.ts.map +1 -0
- package/src/formatters/markdown.test.ts +417 -0
- package/src/formatters/markdown.ts +220 -0
- package/src/formatters/markdownv2.d.ts +184 -0
- package/src/formatters/markdownv2.d.ts.map +1 -0
- package/src/formatters/markdownv2.ts +235 -0
- package/src/formatters.test.ts +17 -7
- package/src/index.d.ts +2 -0
- package/src/index.d.ts.map +1 -1
- package/src/index.ts +12 -0
- package/src/integration.test.ts +523 -0
- package/src/media-integration.test.ts +384 -0
- package/src/types/index.d.ts +1 -0
- package/src/types/index.d.ts.map +1 -1
- package/src/types/index.ts +1 -0
- package/src/types/media.types.d.ts +158 -0
- package/src/types/media.types.d.ts.map +1 -0
- package/src/types/media.types.ts +178 -0
- package/src/types.test.ts +539 -0
- package/src/utils/index.d.ts +1 -1
- package/src/utils/index.ts +0 -5
package/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,YAAY,EACV,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,WAAW,CAAC;AAC1B,YAAY,EACV,SAAS,EACT,UAAU,EACV,QAAQ,EACR,eAAe,EACf,WAAW,EACX,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,qBAAqB,EACrB,qBAAqB,EACrB,oBAAoB,EACpB,eAAe,EACf,iBAAiB,GAClB,MAAM,wBAAwB,CAAC;AAChC,YAAY,EACV,WAAW,EACX,SAAS,EACT,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,aAAa,EACb,aAAa,GACd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAC;AACnD,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,WAAW,CAAC"}
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,18 @@ export type {
|
|
|
17
17
|
IKeyboardButton,
|
|
18
18
|
IForceReplyMarkup,
|
|
19
19
|
} from "./types/keyboard.types";
|
|
20
|
+
export type {
|
|
21
|
+
MediaSource,
|
|
22
|
+
MediaType,
|
|
23
|
+
IMediaCommonOptions,
|
|
24
|
+
IMediaBuildResult,
|
|
25
|
+
IPhotoOptions,
|
|
26
|
+
IVideoOptions,
|
|
27
|
+
IDocumentOptions,
|
|
28
|
+
IAudioOptions,
|
|
29
|
+
IVoiceOptions,
|
|
30
|
+
} from "./types/media.types";
|
|
20
31
|
export { fmt } from "./formatters";
|
|
21
32
|
export { TelegramMessageBuilder } from "./builder";
|
|
22
33
|
export { TelegramKeyboardBuilder } from "./keyboard";
|
|
34
|
+
export { TelegramMediaBuilder } from "./builder";
|
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
import { describe, it, expect } from "bun:test";
|
|
2
|
+
import { TelegramMessageBuilder } from "./builder";
|
|
3
|
+
import { TelegramKeyboardBuilder } from "./keyboard";
|
|
4
|
+
import * as fmt from "../src";
|
|
5
|
+
|
|
6
|
+
describe("Integration Tests", () => {
|
|
7
|
+
describe("Message + Keyboard Combination", () => {
|
|
8
|
+
it("should build message with inline keyboard", () => {
|
|
9
|
+
const message = TelegramMessageBuilder.text()
|
|
10
|
+
.title("Choose an option")
|
|
11
|
+
.newline()
|
|
12
|
+
.line("Options", "Available below", { italic: true })
|
|
13
|
+
.build();
|
|
14
|
+
|
|
15
|
+
const keyboard = TelegramKeyboardBuilder.inline()
|
|
16
|
+
.urlButton("Visit Website", "https://example.com")
|
|
17
|
+
.row()
|
|
18
|
+
.callbackButton("Option 1", "opt_1")
|
|
19
|
+
.callbackButton("Option 2", "opt_2")
|
|
20
|
+
.buildMarkup();
|
|
21
|
+
|
|
22
|
+
expect(message.text).toContain("<b>Choose an option</b>");
|
|
23
|
+
expect(message.text).toContain("Options: <i>Available below</i>");
|
|
24
|
+
expect(keyboard.inline_keyboard).toBeDefined();
|
|
25
|
+
expect(keyboard.inline_keyboard?.length).toBeGreaterThan(0);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should build message with reply keyboard", () => {
|
|
29
|
+
const message = TelegramMessageBuilder.text()
|
|
30
|
+
.title("Menu")
|
|
31
|
+
.line("Please select an option", "", {})
|
|
32
|
+
.build();
|
|
33
|
+
|
|
34
|
+
const keyboard = TelegramKeyboardBuilder.reply()
|
|
35
|
+
.textButton("Option 1")
|
|
36
|
+
.row()
|
|
37
|
+
.textButton("Option 2")
|
|
38
|
+
.textButton("Option 3")
|
|
39
|
+
.buildReplyMarkup();
|
|
40
|
+
|
|
41
|
+
expect(message.text).toContain("<b>Menu</b>");
|
|
42
|
+
expect(keyboard.keyboard).toBeDefined();
|
|
43
|
+
expect(keyboard.keyboard?.length).toBe(2);
|
|
44
|
+
expect(keyboard.keyboard?.[1]?.length).toBe(2);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
describe("Complex Real-World Messages", () => {
|
|
49
|
+
it("should build user profile message (HTML)", () => {
|
|
50
|
+
const message = TelegramMessageBuilder.text()
|
|
51
|
+
.title("👤 User Profile")
|
|
52
|
+
.newline()
|
|
53
|
+
.section("Personal Information")
|
|
54
|
+
.line("Name", "John Doe", { bold: true })
|
|
55
|
+
.line("Age", "30", { code: true })
|
|
56
|
+
.line("Status", "Active", { italic: true })
|
|
57
|
+
.line("Level", "Premium", { underline: true })
|
|
58
|
+
.newline()
|
|
59
|
+
.section("Statistics")
|
|
60
|
+
.line("Messages", "1,234")
|
|
61
|
+
.line("Score", "9,876")
|
|
62
|
+
.separator()
|
|
63
|
+
.codeBlock(
|
|
64
|
+
"const user = {\n name: 'John Doe',\n level: 'Premium'\n};",
|
|
65
|
+
"javascript",
|
|
66
|
+
)
|
|
67
|
+
.newline()
|
|
68
|
+
.listItem("✅ Verified")
|
|
69
|
+
.listItem("⭐ Premium Member")
|
|
70
|
+
.listItem("🏆 Top Contributor")
|
|
71
|
+
.newline()
|
|
72
|
+
.link("View Full Profile", "https://example.com/user/123")
|
|
73
|
+
.mention(123456, "John Doe")
|
|
74
|
+
.build();
|
|
75
|
+
|
|
76
|
+
expect(message.text).toContain("<b>👤 User Profile</b>");
|
|
77
|
+
expect(message.text).toContain("<u>Personal Information</u>");
|
|
78
|
+
expect(message.text).toContain("Name: <b>John Doe</b>");
|
|
79
|
+
expect(message.text).toContain("Age: <code>30</code>");
|
|
80
|
+
expect(message.text).toContain("Status: <i>Active</i>");
|
|
81
|
+
expect(message.text).toContain("Level: <u>Premium</u>");
|
|
82
|
+
expect(message.text).toContain("---");
|
|
83
|
+
expect(message.text).toContain("language-javascript");
|
|
84
|
+
expect(message.text).toContain("• ✅ Verified");
|
|
85
|
+
expect(message.text).toContain("View Full Profile");
|
|
86
|
+
expect(message.text).toContain("tg://user?id=123456");
|
|
87
|
+
expect(message.parse_mode).toBe("html");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("should build same message in Markdown mode", () => {
|
|
91
|
+
const message = TelegramMessageBuilder.text()
|
|
92
|
+
.setParseMode("markdown")
|
|
93
|
+
.title("👤 User Profile")
|
|
94
|
+
.newline()
|
|
95
|
+
.section("Personal Information")
|
|
96
|
+
.line("Name", "John Doe", { bold: true })
|
|
97
|
+
.line("Status", "Active", { italic: true })
|
|
98
|
+
.build();
|
|
99
|
+
|
|
100
|
+
expect(message.text).toContain("*👤 User Profile*");
|
|
101
|
+
expect(message.text).toContain("Name: *John Doe*");
|
|
102
|
+
expect(message.text).toContain("Status: _Active_");
|
|
103
|
+
expect(message.parse_mode).toBe("markdown");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it("should build same message in MarkdownV2 mode", () => {
|
|
107
|
+
const message = TelegramMessageBuilder.text()
|
|
108
|
+
.setParseMode("markdownv2")
|
|
109
|
+
.title("👤 User Profile")
|
|
110
|
+
.newline()
|
|
111
|
+
.section("Personal Information")
|
|
112
|
+
.line("Name", "John Doe", { bold: true })
|
|
113
|
+
.line("Status", "Active", { italic: true })
|
|
114
|
+
.line("Level", "Premium", { underline: true })
|
|
115
|
+
.build();
|
|
116
|
+
|
|
117
|
+
expect(message.text).toContain("*👤 User Profile*");
|
|
118
|
+
expect(message.text).toContain("Name: *John Doe*");
|
|
119
|
+
expect(message.text).toContain("Status: _Active_");
|
|
120
|
+
expect(message.text).toContain("Level: __Premium__");
|
|
121
|
+
expect(message.parse_mode).toBe("markdownv2");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("should build product listing message", () => {
|
|
125
|
+
const message = TelegramMessageBuilder.text()
|
|
126
|
+
.title("🛒 Product List")
|
|
127
|
+
.newline()
|
|
128
|
+
.section("Featured Products")
|
|
129
|
+
.listItem("Product A - $10")
|
|
130
|
+
.listItem("Product B - $20")
|
|
131
|
+
.listItem("Product C - $30")
|
|
132
|
+
.newline()
|
|
133
|
+
.section("Special Offers")
|
|
134
|
+
.line("Discount", "20% OFF", { bold: true })
|
|
135
|
+
.line("Code", "SAVE20", { code: true })
|
|
136
|
+
.separator()
|
|
137
|
+
.link("Shop Now", "https://example.com/shop")
|
|
138
|
+
.hashtag("deals")
|
|
139
|
+
.hashtag("sale")
|
|
140
|
+
.setOption("disable_web_page_preview", true)
|
|
141
|
+
.build();
|
|
142
|
+
|
|
143
|
+
expect(message.text).toContain("<b>🛒 Product List</b>");
|
|
144
|
+
expect(message.text).toContain("• Product A - $10");
|
|
145
|
+
expect(message.text).toContain("Discount: <b>20% OFF</b>");
|
|
146
|
+
expect(message.text).toContain("Code: <code>SAVE20</code>");
|
|
147
|
+
expect(message.text).toContain("Shop Now");
|
|
148
|
+
expect(message.text).toContain("#deals");
|
|
149
|
+
expect(message.text).toContain("#sale");
|
|
150
|
+
expect(message.disable_web_page_preview).toBe(true);
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("should build error message", () => {
|
|
154
|
+
const message = TelegramMessageBuilder.text()
|
|
155
|
+
.title("❌ Error Occurred")
|
|
156
|
+
.newline()
|
|
157
|
+
.line("Code", "ERR_500", { code: true })
|
|
158
|
+
.line("Message", "Internal server error", { bold: true })
|
|
159
|
+
.newline()
|
|
160
|
+
.section("Details")
|
|
161
|
+
.codeBlock("Error: Database connection failed\nat connect (db.js:42)")
|
|
162
|
+
.newline()
|
|
163
|
+
.line("Support", "@support", { italic: true })
|
|
164
|
+
.mention(123456, "Support Team")
|
|
165
|
+
.build();
|
|
166
|
+
|
|
167
|
+
expect(message.text).toContain("<b>❌ Error Occurred</b>");
|
|
168
|
+
expect(message.text).toContain("Code: <code>ERR_500</code>");
|
|
169
|
+
expect(message.text).toContain("Message: <b>Internal server error</b>");
|
|
170
|
+
expect(message.text).toContain(
|
|
171
|
+
"<pre><code>Error: Database connection failed",
|
|
172
|
+
);
|
|
173
|
+
expect(message.text).toContain("@support");
|
|
174
|
+
expect(message.text).toContain("tg://user?id=123456");
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("should build notification message", () => {
|
|
178
|
+
const message = TelegramMessageBuilder.text()
|
|
179
|
+
.title("🔔 New Notification")
|
|
180
|
+
.newline()
|
|
181
|
+
.line("Type", "System Update", { bold: true })
|
|
182
|
+
.line("Time", "2024-01-10 12:00", { code: true })
|
|
183
|
+
.newline()
|
|
184
|
+
.section("Message")
|
|
185
|
+
.text("A new update is available. Please update to the latest version.")
|
|
186
|
+
.newline()
|
|
187
|
+
.separator()
|
|
188
|
+
.link("Update Now", "https://example.com/update")
|
|
189
|
+
.link("Release Notes", "https://example.com/release-notes")
|
|
190
|
+
.setOptions({
|
|
191
|
+
disable_notification: false,
|
|
192
|
+
protect_content: true,
|
|
193
|
+
})
|
|
194
|
+
.build();
|
|
195
|
+
|
|
196
|
+
expect(message.text).toContain("<b>🔔 New Notification</b>");
|
|
197
|
+
expect(message.text).toContain("Type: <b>System Update</b>");
|
|
198
|
+
expect(message.text).toContain("Time: <code>2024-01-10 12:00</code>");
|
|
199
|
+
expect(message.text).toContain("A new update is available");
|
|
200
|
+
expect(message.text).toContain("Update Now");
|
|
201
|
+
expect(message.text).toContain("Release Notes");
|
|
202
|
+
expect(message.protect_content).toBe(true);
|
|
203
|
+
expect(message.disable_notification).toBe(false);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
describe("Cross-Mode Message Consistency", () => {
|
|
208
|
+
it("should produce equivalent messages in all three modes", () => {
|
|
209
|
+
const htmlMessage = TelegramMessageBuilder.text()
|
|
210
|
+
.setParseMode("html")
|
|
211
|
+
.title("Welcome")
|
|
212
|
+
.line("Status", "Active", { bold: true })
|
|
213
|
+
.link("Click here", "https://example.com")
|
|
214
|
+
.build();
|
|
215
|
+
|
|
216
|
+
const mdMessage = TelegramMessageBuilder.text()
|
|
217
|
+
.setParseMode("markdown")
|
|
218
|
+
.title("Welcome")
|
|
219
|
+
.line("Status", "Active", { bold: true })
|
|
220
|
+
.link("Click here", "https://example.com")
|
|
221
|
+
.build();
|
|
222
|
+
|
|
223
|
+
const mdv2Message = TelegramMessageBuilder.text()
|
|
224
|
+
.setParseMode("markdownv2")
|
|
225
|
+
.title("Welcome")
|
|
226
|
+
.line("Status", "Active", { bold: true })
|
|
227
|
+
.link("Click here", "https://example.com")
|
|
228
|
+
.build();
|
|
229
|
+
|
|
230
|
+
// HTML mode
|
|
231
|
+
expect(htmlMessage.parse_mode).toBe("html");
|
|
232
|
+
expect(htmlMessage.text).toContain("<b>Welcome</b>");
|
|
233
|
+
expect(htmlMessage.text).toContain("Status: <b>Active</b>");
|
|
234
|
+
expect(htmlMessage.text).toContain(
|
|
235
|
+
'<a href="https://example.com">Click here</a>',
|
|
236
|
+
);
|
|
237
|
+
|
|
238
|
+
// Markdown mode
|
|
239
|
+
expect(mdMessage.parse_mode).toBe("markdown");
|
|
240
|
+
expect(mdMessage.text).toContain("*Welcome*");
|
|
241
|
+
expect(mdMessage.text).toContain("Status: *Active*");
|
|
242
|
+
expect(mdMessage.text).toContain("[Click here](https://example.com)");
|
|
243
|
+
|
|
244
|
+
// MarkdownV2 mode
|
|
245
|
+
expect(mdv2Message.parse_mode).toBe("markdownv2");
|
|
246
|
+
expect(mdv2Message.text).toContain("*Welcome*");
|
|
247
|
+
expect(mdv2Message.text).toContain("Status: *Active*");
|
|
248
|
+
expect(mdv2Message.text).toContain("[Click here](https://example.com)");
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
describe("Formatter Integration", () => {
|
|
253
|
+
it("should combine fmt helpers with builder", () => {
|
|
254
|
+
const customPart = `${fmt.bold("Custom")} ${fmt.italic("Part")}`;
|
|
255
|
+
|
|
256
|
+
const message = TelegramMessageBuilder.text()
|
|
257
|
+
.title("Main Title")
|
|
258
|
+
.newline()
|
|
259
|
+
.text(customPart)
|
|
260
|
+
.build();
|
|
261
|
+
|
|
262
|
+
expect(message.text).toContain("<b>Main Title</b>");
|
|
263
|
+
// Note: text() escapes HTML, so the customPart will be escaped
|
|
264
|
+
expect(message.text).toContain("<b>Custom</b>");
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it("should use raw() to preserve formatting in builder", () => {
|
|
268
|
+
// The title() method wraps its content, so raw() doesn't help here
|
|
269
|
+
// Instead, use bold() directly on the text without title()
|
|
270
|
+
const message = TelegramMessageBuilder.text()
|
|
271
|
+
.text(fmt.raw(fmt.bold("Main")))
|
|
272
|
+
.build();
|
|
273
|
+
|
|
274
|
+
// text() also escapes, so this will escape the bold tags
|
|
275
|
+
// This is the expected behavior - raw() is for combining formatters, not bypassing escaping in builder methods
|
|
276
|
+
expect(message.text).toContain("<b>Main</b>");
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("should escape properly in all formatters", () => {
|
|
280
|
+
const message = TelegramMessageBuilder.text()
|
|
281
|
+
.title("<script>alert('xss')</script>")
|
|
282
|
+
.line("Key", "<b>Value</b>", { bold: true })
|
|
283
|
+
.codeBlock("<code>alert('xss')</code>")
|
|
284
|
+
.link("Click", "https://example.com?x=1&y=2")
|
|
285
|
+
.build();
|
|
286
|
+
|
|
287
|
+
expect(message.text).toContain("<script>");
|
|
288
|
+
expect(message.text).toContain("<b>Value</b>");
|
|
289
|
+
expect(message.text).toContain("<code>");
|
|
290
|
+
expect(message.text).toContain("&");
|
|
291
|
+
});
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
describe("Special Characters and Unicode", () => {
|
|
295
|
+
it("should handle emoji in all modes", () => {
|
|
296
|
+
const html = TelegramMessageBuilder.text()
|
|
297
|
+
.title("🎉 Success!")
|
|
298
|
+
.listItem("✅ Step 1")
|
|
299
|
+
.listItem("✅ Step 2")
|
|
300
|
+
.listItem("🏆 Complete!")
|
|
301
|
+
.build();
|
|
302
|
+
|
|
303
|
+
expect(html.text).toContain("🎉");
|
|
304
|
+
expect(html.text).toContain("✅");
|
|
305
|
+
expect(html.text).toContain("🏆");
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("should handle special characters in MarkdownV2", () => {
|
|
309
|
+
const message = TelegramMessageBuilder.text()
|
|
310
|
+
.setParseMode("markdownv2")
|
|
311
|
+
.title("Test")
|
|
312
|
+
.text("Text with * and _ and ~")
|
|
313
|
+
.build();
|
|
314
|
+
|
|
315
|
+
// text() should escape special characters in MDv2 mode
|
|
316
|
+
expect(message.text).toContain("\\*");
|
|
317
|
+
expect(message.text).toContain("\\_");
|
|
318
|
+
expect(message.text).toContain("\\~");
|
|
319
|
+
});
|
|
320
|
+
|
|
321
|
+
it("should handle RTL languages (Arabic, Hebrew)", () => {
|
|
322
|
+
const message = TelegramMessageBuilder.text()
|
|
323
|
+
.title("مرحبا")
|
|
324
|
+
.line("اسم", "محمد", { bold: true })
|
|
325
|
+
.line("משהו", "משהו", { italic: true })
|
|
326
|
+
.build();
|
|
327
|
+
|
|
328
|
+
expect(message.text).toContain("مرحبا");
|
|
329
|
+
expect(message.text).toContain("محمد");
|
|
330
|
+
expect(message.text).toContain("משהו");
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
it("should handle CJK languages (Chinese, Japanese, Korean)", () => {
|
|
334
|
+
const message = TelegramMessageBuilder.text()
|
|
335
|
+
.title("标题")
|
|
336
|
+
.line("名前", "名前", { bold: true })
|
|
337
|
+
.line("이름", "이름", { code: true })
|
|
338
|
+
.build();
|
|
339
|
+
|
|
340
|
+
expect(message.text).toContain("标题");
|
|
341
|
+
expect(message.text).toContain("名前");
|
|
342
|
+
expect(message.text).toContain("이름");
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
describe("Performance and Edge Cases", () => {
|
|
347
|
+
it("should handle very long messages", () => {
|
|
348
|
+
const longText = "a".repeat(4000);
|
|
349
|
+
|
|
350
|
+
const message = TelegramMessageBuilder.text()
|
|
351
|
+
.title("Long Message")
|
|
352
|
+
.text(longText)
|
|
353
|
+
.build();
|
|
354
|
+
|
|
355
|
+
expect(message.text.length).toBeGreaterThan(4000);
|
|
356
|
+
expect(message.text).toContain("<b>Long Message</b>");
|
|
357
|
+
expect(message.text).toContain(longText);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("should handle empty builder", () => {
|
|
361
|
+
const message = TelegramMessageBuilder.text().build();
|
|
362
|
+
expect(message.text).toBe("");
|
|
363
|
+
expect(message.parse_mode).toBe("html");
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("should handle message with only newlines", () => {
|
|
367
|
+
const message = TelegramMessageBuilder.text().newline(5).build();
|
|
368
|
+
|
|
369
|
+
expect(message.text).toContain("\n\n");
|
|
370
|
+
});
|
|
371
|
+
|
|
372
|
+
it("should handle multiple consecutive separators", () => {
|
|
373
|
+
const message = TelegramMessageBuilder.text()
|
|
374
|
+
.separator()
|
|
375
|
+
.separator()
|
|
376
|
+
.separator()
|
|
377
|
+
.build();
|
|
378
|
+
|
|
379
|
+
const count = (message.text.match(/---/g) || []).length;
|
|
380
|
+
expect(count).toBe(3);
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it("should handle all formatter types in single message", () => {
|
|
384
|
+
const message = TelegramMessageBuilder.text()
|
|
385
|
+
.title("Title")
|
|
386
|
+
.section("Section")
|
|
387
|
+
.line("A", "B", { bold: true })
|
|
388
|
+
.line("C", "D", { italic: true })
|
|
389
|
+
.line("E", "F", { code: true })
|
|
390
|
+
.line("G", "H", { underline: true })
|
|
391
|
+
.codeBlock("code")
|
|
392
|
+
.listItem("item")
|
|
393
|
+
.newline()
|
|
394
|
+
.separator()
|
|
395
|
+
.text("text")
|
|
396
|
+
.link("L", "https://example.com")
|
|
397
|
+
.mention(123, "User")
|
|
398
|
+
.hashtag("tag")
|
|
399
|
+
.setOption("opt", 1)
|
|
400
|
+
.build();
|
|
401
|
+
|
|
402
|
+
expect(message.text).toContain("<b>Title</b>");
|
|
403
|
+
expect(message.text).toContain("<u>Section</u>");
|
|
404
|
+
expect(message.text).toContain("A: <b>B</b>");
|
|
405
|
+
expect(message.text).toContain("C: <i>D</i>");
|
|
406
|
+
expect(message.text).toContain("E: <code>F</code>");
|
|
407
|
+
expect(message.text).toContain("G: <u>H</u>");
|
|
408
|
+
expect(message.text).toContain("<pre><code>code</code></pre>");
|
|
409
|
+
expect(message.text).toContain("• item");
|
|
410
|
+
expect(message.text).toContain("---");
|
|
411
|
+
expect(message.text).toContain("L");
|
|
412
|
+
expect(message.text).toContain("tg://user?id=123");
|
|
413
|
+
expect(message.text).toContain("#tag");
|
|
414
|
+
expect(message.opt).toBe(1);
|
|
415
|
+
});
|
|
416
|
+
});
|
|
417
|
+
|
|
418
|
+
describe("Real-World Use Cases", () => {
|
|
419
|
+
it("should build bot welcome message", () => {
|
|
420
|
+
const message = TelegramMessageBuilder.text()
|
|
421
|
+
.title("🤖 Welcome to ExampleBot")
|
|
422
|
+
.newline()
|
|
423
|
+
.section("Available Commands")
|
|
424
|
+
.listItem("/start - Start the bot")
|
|
425
|
+
.listItem("/help - Show help")
|
|
426
|
+
.listItem("/settings - Configure settings")
|
|
427
|
+
.newline()
|
|
428
|
+
.section("Quick Links")
|
|
429
|
+
.link("🌐 Website", "https://example.com")
|
|
430
|
+
.link("📖 Documentation", "https://docs.example.com")
|
|
431
|
+
.link("💬 Support", "https://t.me/support")
|
|
432
|
+
.newline()
|
|
433
|
+
.text("Use the buttons below or type a command to get started.")
|
|
434
|
+
.hashtag("ExampleBot")
|
|
435
|
+
.hashtag("Telegram")
|
|
436
|
+
.build();
|
|
437
|
+
|
|
438
|
+
expect(message.text).toContain("🤖 Welcome to ExampleBot");
|
|
439
|
+
expect(message.text).toContain("/start");
|
|
440
|
+
expect(message.text).toContain("Website");
|
|
441
|
+
expect(message.text).toContain("#ExampleBot");
|
|
442
|
+
});
|
|
443
|
+
|
|
444
|
+
it("should build order confirmation message", () => {
|
|
445
|
+
const orderId = "ORD-2024-001";
|
|
446
|
+
const items = "Item 1 x1, Item 2 x2";
|
|
447
|
+
const total = "$45.00";
|
|
448
|
+
|
|
449
|
+
const message = TelegramMessageBuilder.text()
|
|
450
|
+
.title("📦 Order Confirmation")
|
|
451
|
+
.newline()
|
|
452
|
+
.section("Order Details")
|
|
453
|
+
.line("Order ID", orderId, { code: true })
|
|
454
|
+
.line("Date", "2024-01-10", { code: true })
|
|
455
|
+
.newline()
|
|
456
|
+
.section("Items")
|
|
457
|
+
.text(items)
|
|
458
|
+
.newline()
|
|
459
|
+
.section("Payment")
|
|
460
|
+
.line("Total", total, { bold: true })
|
|
461
|
+
.line("Method", "Credit Card", { italic: true })
|
|
462
|
+
.separator()
|
|
463
|
+
.text("Thank you for your purchase! 🎉")
|
|
464
|
+
.newline()
|
|
465
|
+
.link("Track Order", "https://example.com/track/ORD-2024-001")
|
|
466
|
+
.mention(123456, "Support Team")
|
|
467
|
+
.setOptions({
|
|
468
|
+
disable_web_page_preview: true,
|
|
469
|
+
})
|
|
470
|
+
.build();
|
|
471
|
+
|
|
472
|
+
expect(message.text).toContain("📦 Order Confirmation");
|
|
473
|
+
expect(message.text).toContain("Order ID: <code>ORD-2024-001</code>");
|
|
474
|
+
expect(message.text).toContain("Total: <b>$45.00</b>");
|
|
475
|
+
expect(message.text).toContain("Thank you for your purchase!");
|
|
476
|
+
expect(message.text).toContain("Track Order");
|
|
477
|
+
});
|
|
478
|
+
|
|
479
|
+
it("should build analytics report message", () => {
|
|
480
|
+
const message = TelegramMessageBuilder.text()
|
|
481
|
+
.title("📊 Weekly Analytics Report")
|
|
482
|
+
.newline()
|
|
483
|
+
.section("Overview")
|
|
484
|
+
.line("Period", "Jan 1 - Jan 7, 2024", { code: true })
|
|
485
|
+
.line("Total Users", "1,234", { bold: true })
|
|
486
|
+
.line("Active Users", "987", { bold: true })
|
|
487
|
+
.line("Growth", "+15.3%", { italic: true })
|
|
488
|
+
.newline()
|
|
489
|
+
.section("Top Metrics")
|
|
490
|
+
.listItem("Messages sent: 45,678")
|
|
491
|
+
.listItem("Commands used: 12,345")
|
|
492
|
+
.listItem("Errors: 23")
|
|
493
|
+
.newline()
|
|
494
|
+
.codeBlock(
|
|
495
|
+
`{
|
|
496
|
+
"users": {
|
|
497
|
+
"new": 123,
|
|
498
|
+
"returning": 864,
|
|
499
|
+
"churned": 12
|
|
500
|
+
},
|
|
501
|
+
"engagement": {
|
|
502
|
+
"avg_session": "5m 32s",
|
|
503
|
+
"retention": "78.5%"
|
|
504
|
+
}
|
|
505
|
+
}`,
|
|
506
|
+
"json",
|
|
507
|
+
)
|
|
508
|
+
.newline()
|
|
509
|
+
.link("View Full Report", "https://analytics.example.com")
|
|
510
|
+
.hashtag("analytics")
|
|
511
|
+
.hashtag("report")
|
|
512
|
+
.build();
|
|
513
|
+
|
|
514
|
+
expect(message.text).toContain("📊 Weekly Analytics Report");
|
|
515
|
+
expect(message.text).toContain("Total Users: <b>1,234</b>");
|
|
516
|
+
expect(message.text).toContain("Growth: <i>+15.3%</i>");
|
|
517
|
+
expect(message.text).toContain("Messages sent: 45,678");
|
|
518
|
+
expect(message.text).toContain(""users":"); // HTML escaped quotes
|
|
519
|
+
expect(message.text).toContain("View Full Report");
|
|
520
|
+
expect(message.text).toContain("#analytics");
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
});
|