create-gramstax 0.8.10 → 0.8.12
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/src/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
"use strict";var W=Object.create;var h=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,O=Object.prototype.hasOwnProperty;var p=(o,e)=>h(o,"name",{value:e,configurable:!0});var V=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of G(e))!O.call(o,a)&&a!==t&&h(o,a,{get:()=>e[a],enumerable:!(n=A(e,a))||n.enumerable});return o};var v=(o,e,t)=>(t=o!=null?W(B(o)):{},V(e||!o||!o.__esModule?h(t,"default",{value:o,enumerable:!0}):t,o));var q=p(()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,"getImportMetaUrl"),f=q();var C=require("logging-pretty"),r=new C.LoggingPretty;var i=v(require("fs"),1),s=v(require("path"),1),E=require("url");var D=require("fs");var g=class o{static{p(this,"FsUt")}static DEFAULT_IGNORED_ENTRIES=new Set([".git",".gitignore",".gitkeep",".DS_Store","Thumbs.db"]);static isDirectoryEffectivelyEmpty(e,t=o.DEFAULT_IGNORED_ENTRIES){return(0,D.readdirSync)(e).filter(c=>!t.has(c)).length===0}static resolvePackageManagerCommand(e,t=process.platform){return t!=="win32"||e==="bun"?e:`${e}.cmd`}static resolveInitialWorkingDirectory(e=process.cwd(),t=process.env.INIT_CWD){return t??e}};var j=require("child_process"),P=v(require("enquirer"),1);var J=(0,E.fileURLToPath)(f),Y=s.dirname(J),_=class{constructor(e,t){this.projectDirectory=e;this.version=t?.version}static{p(this,"Create")}config;version;printBanner(){let e=`
|
|
2
|
+
"use strict";var W=Object.create;var h=Object.defineProperty;var A=Object.getOwnPropertyDescriptor;var G=Object.getOwnPropertyNames;var B=Object.getPrototypeOf,O=Object.prototype.hasOwnProperty;var p=(o,e)=>h(o,"name",{value:e,configurable:!0});var V=(o,e,t,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let a of G(e))!O.call(o,a)&&a!==t&&h(o,a,{get:()=>e[a],enumerable:!(n=A(e,a))||n.enumerable});return o};var v=(o,e,t)=>(t=o!=null?W(B(o)):{},V(e||!o||!o.__esModule?h(t,"default",{value:o,enumerable:!0}):t,o));var q=p(()=>typeof document>"u"?new URL(`file:${__filename}`).href:document.currentScript&&document.currentScript.tagName.toUpperCase()==="SCRIPT"?document.currentScript.src:new URL("main.js",document.baseURI).href,"getImportMetaUrl"),f=q();var C=require("logging-pretty"),r=new C.LoggingPretty;var i=v(require("fs"),1),s=v(require("path"),1),E=require("url");var D=require("fs");var g=class o{static{p(this,"FsUt")}static DEFAULT_IGNORED_ENTRIES=new Set([".git",".gitignore",".gitkeep",".DS_Store","Thumbs.db"]);static isDirectoryEffectivelyEmpty(e,t=o.DEFAULT_IGNORED_ENTRIES){return(0,D.readdirSync)(e).filter(c=>!t.has(c)).length===0}static resolvePackageManagerCommand(e,t=process.platform){return t!=="win32"||e==="bun"?e:`${e}.cmd`}static resolveInitialWorkingDirectory(e=process.cwd(),t=process.env.INIT_CWD){return t??e}};var j=require("child_process"),P=v(require("enquirer"),1);var J=(0,E.fileURLToPath)(f),Y=s.dirname(J),_=class{constructor(e,t){this.projectDirectory=e;this.version=t?.version}projectDirectory;static{p(this,"Create")}config;version;printBanner(){let e=`
|
|
3
3
|
$$$$$$\\ $$\\
|
|
4
4
|
$$ __$$\\ $$ |
|
|
5
5
|
$$ / \\__| $$$$$$\\ $$$$$$\\ $$$$$$\\$$$$\\ $$$$$$$\\ $$$$$$\\ $$$$$$\\ $$\\ $$\\
|
package/dist/src/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var E=Object.defineProperty;var g=(p,e)=>E(p,"name",{value:e,configurable:!0});import{LoggingPretty as N}from"logging-pretty";var r=new N;import*as i from"fs";import*as a from"path";import{fileURLToPath as R}from"url";import{readdirSync as F}from"fs";var m=class p{static{g(this,"FsUt")}static DEFAULT_IGNORED_ENTRIES=new Set([".git",".gitignore",".gitkeep",".DS_Store","Thumbs.db"]);static isDirectoryEffectivelyEmpty(e,t=p.DEFAULT_IGNORED_ENTRIES){return F(e).filter(o=>!t.has(o)).length===0}static resolvePackageManagerCommand(e,t=process.platform){return t!=="win32"||e==="bun"?e:`${e}.cmd`}static resolveInitialWorkingDirectory(e=process.cwd(),t=process.env.INIT_CWD){return t??e}};import{spawn as j}from"child_process";import P from"enquirer";var L=R(import.meta.url),T=a.dirname(L),d=class{constructor(e,t){this.projectDirectory=e;this.version=t?.version}static{g(this,"Create")}config;version;printBanner(){let e=`
|
|
2
|
+
var E=Object.defineProperty;var g=(p,e)=>E(p,"name",{value:e,configurable:!0});import{LoggingPretty as N}from"logging-pretty";var r=new N;import*as i from"fs";import*as a from"path";import{fileURLToPath as R}from"url";import{readdirSync as F}from"fs";var m=class p{static{g(this,"FsUt")}static DEFAULT_IGNORED_ENTRIES=new Set([".git",".gitignore",".gitkeep",".DS_Store","Thumbs.db"]);static isDirectoryEffectivelyEmpty(e,t=p.DEFAULT_IGNORED_ENTRIES){return F(e).filter(o=>!t.has(o)).length===0}static resolvePackageManagerCommand(e,t=process.platform){return t!=="win32"||e==="bun"?e:`${e}.cmd`}static resolveInitialWorkingDirectory(e=process.cwd(),t=process.env.INIT_CWD){return t??e}};import{spawn as j}from"child_process";import P from"enquirer";var L=R(import.meta.url),T=a.dirname(L),d=class{constructor(e,t){this.projectDirectory=e;this.version=t?.version}projectDirectory;static{g(this,"Create")}config;version;printBanner(){let e=`
|
|
3
3
|
$$$$$$\\ $$\\
|
|
4
4
|
$$ __$$\\ $$ |
|
|
5
5
|
$$ / \\__| $$$$$$\\ $$$$$$\\ $$$$$$\\$$$$\\ $$$$$$$\\ $$$$$$\\ $$$$$$\\ $$\\ $$\\
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* E2E Test Flow for Template Bot
|
|
3
|
+
*
|
|
4
|
+
* Setup:
|
|
5
|
+
* 1. MockTelegramServer starts on random port → apiRoot captured
|
|
6
|
+
* 2. BotCore initialized with webhook:http://127.0.0.1:3009/webhook/e2e-template
|
|
7
|
+
* 3. CacheExternal (memory) shared across tests, cleared in beforeEach
|
|
8
|
+
*
|
|
9
|
+
* Test Flow:
|
|
10
|
+
* T1. /start → Welcome message + inline keyboard (Random Number, Sum Number, Help)
|
|
11
|
+
* T2. /start → callback:help → editMessage → Help Message + Back button
|
|
12
|
+
* T3. /start → callback:random-number → editMessage → Random Number + Shake/Back buttons
|
|
13
|
+
* T4. /start → callback:random-number → callback:random-number → editMessage → refreshed number
|
|
14
|
+
* T5. /start → callback:sum-number → text:23 → text:10 → Result Sum: 33 + Home button
|
|
15
|
+
* T6. /start → callback:sum-number → text:not-a-number → re-prompt Input Left Number
|
|
16
|
+
* T7. /start → callback:nonexistent_action → graceful handling (no crash)
|
|
17
|
+
* T8. /start → verify sendMessage request captured in mockServer.requests
|
|
18
|
+
* T9. /start → callback:help → callback:random-number → sequential chain
|
|
19
|
+
* T10. sendPhoto → Route Not Found (no handler for photo)
|
|
20
|
+
* T11. /start with custom user/chat → custom ID propagation verified
|
|
21
|
+
* T12. /start without username → Username Required page (UserGuard blocks)
|
|
22
|
+
* T13. /start → callback:help → callback:random-number → keyboard structure validation (text + callback_data)
|
|
23
|
+
*
|
|
24
|
+
* Cleanup:
|
|
25
|
+
* - botCore.stop() + mockServer.stop() in afterAll
|
|
26
|
+
* - cacheSession.clear() + mockServer.clearRequests() in beforeEach
|
|
27
|
+
*/
|
|
28
|
+
import {join} from "node:path"
|
|
29
|
+
import {BotCore} from "../src/core/bot"
|
|
30
|
+
import {TemplateManager, CacheExternal} from "gramstax"
|
|
31
|
+
import {MockTelegramServer} from "gramstax"
|
|
32
|
+
import {describe, it, expect, beforeAll, afterAll, beforeEach} from "bun:test"
|
|
33
|
+
|
|
34
|
+
let mockServer: MockTelegramServer
|
|
35
|
+
let botCore: BotCore
|
|
36
|
+
let cacheSession: CacheExternal
|
|
37
|
+
|
|
38
|
+
const USER_1 = {
|
|
39
|
+
responseTimeoutMs: undefined, // 9000,
|
|
40
|
+
user: {
|
|
41
|
+
id: 123456789,
|
|
42
|
+
first_name: `Test`,
|
|
43
|
+
last_name: `user`,
|
|
44
|
+
username: `testuser`,
|
|
45
|
+
language_code: `en`,
|
|
46
|
+
is_bot: false
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
beforeAll(async () => {
|
|
51
|
+
mockServer = new MockTelegramServer({log: false})
|
|
52
|
+
await mockServer.start()
|
|
53
|
+
|
|
54
|
+
const templateManager = new TemplateManager({path: [join(import.meta.dir, `../src/pages`)]})
|
|
55
|
+
const cwd = process.cwd()
|
|
56
|
+
process.chdir(join(import.meta.dir, `..`))
|
|
57
|
+
|
|
58
|
+
cacheSession = new CacheExternal(`memory`)
|
|
59
|
+
|
|
60
|
+
botCore = new BotCore({
|
|
61
|
+
deploy: `webhook:http://127.0.0.1:3009/webhook/e2e-template`,
|
|
62
|
+
token: `test-token`,
|
|
63
|
+
log: false,
|
|
64
|
+
templateManager,
|
|
65
|
+
cacheSession,
|
|
66
|
+
botConfig: {client: {apiRoot: mockServer.apiRoot}}
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
process.chdir(cwd)
|
|
70
|
+
|
|
71
|
+
const startedAt = Date.now()
|
|
72
|
+
while (!mockServer.webhookUrl && Date.now() - startedAt < 5000) {
|
|
73
|
+
await new Promise((r) => setTimeout(r, 50))
|
|
74
|
+
}
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
afterAll(async () => {
|
|
78
|
+
await botCore.stop()
|
|
79
|
+
await mockServer.stop()
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
beforeEach(async () => {
|
|
83
|
+
mockServer.clearRequests()
|
|
84
|
+
await cacheSession.clear()
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
describe(`E2E: Template bot via MockTelegramServer (webhook)`, () => {
|
|
88
|
+
it(`responds to /start command with welcome message and navigation buttons`, async () => {
|
|
89
|
+
const responses = await mockServer.sendText(`/start`, USER_1)
|
|
90
|
+
|
|
91
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
92
|
+
const reply = responses[0]!
|
|
93
|
+
expect(reply).toBeDefined()
|
|
94
|
+
expect(reply!.body?.text).toContain(`Welcome to the bot`)
|
|
95
|
+
|
|
96
|
+
const keyboard = reply!.body?.reply_markup?.inline_keyboard
|
|
97
|
+
expect(Array.isArray(keyboard)).toBe(true)
|
|
98
|
+
expect(keyboard.length).toBeGreaterThan(0)
|
|
99
|
+
|
|
100
|
+
const allButtons = keyboard.flat()
|
|
101
|
+
const buttonLabels = allButtons.map((b: any) => b.text)
|
|
102
|
+
expect(buttonLabels).toContain(`🎰 Random Number`)
|
|
103
|
+
expect(buttonLabels).toContain(`➕ Sum Number`)
|
|
104
|
+
expect(buttonLabels).toContain(`🆘 Help`)
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it(`navigates to Help page via callback and shows back button`, async () => {
|
|
108
|
+
await mockServer.sendText(`/start`, USER_1)
|
|
109
|
+
mockServer.clearRequests()
|
|
110
|
+
|
|
111
|
+
const responses = await mockServer.sendCallbackQuery(`help`, USER_1)
|
|
112
|
+
|
|
113
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
114
|
+
const edit = responses[0]!
|
|
115
|
+
expect(edit!.body?.text).toContain(`Help Message`)
|
|
116
|
+
|
|
117
|
+
const keyboard = edit!.body?.reply_markup?.inline_keyboard
|
|
118
|
+
expect(Array.isArray(keyboard)).toBe(true)
|
|
119
|
+
const firstButton = keyboard[0]?.[0]
|
|
120
|
+
expect(firstButton?.text).toContain(`Back`)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it(`navigates to Random Number page via callback and shows generated number`, async () => {
|
|
124
|
+
await mockServer.sendText(`/start`, USER_1)
|
|
125
|
+
mockServer.clearRequests()
|
|
126
|
+
|
|
127
|
+
const responses = await mockServer.sendCallbackQuery(`random-number`, USER_1)
|
|
128
|
+
|
|
129
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
130
|
+
const edit = responses[0]!
|
|
131
|
+
expect(edit!.body?.text).toContain(`Random Number`)
|
|
132
|
+
|
|
133
|
+
const keyboard = edit!.body?.reply_markup?.inline_keyboard
|
|
134
|
+
expect(Array.isArray(keyboard)).toBe(true)
|
|
135
|
+
const allButtons = keyboard.flat()
|
|
136
|
+
const buttonLabels = allButtons.map((b: any) => b.text)
|
|
137
|
+
expect(buttonLabels).toContain(`🎲 Shake`)
|
|
138
|
+
expect(buttonLabels).toContain(`⬅️ Back`)
|
|
139
|
+
})
|
|
140
|
+
|
|
141
|
+
it(`refreshes random number via Shake callback`, async () => {
|
|
142
|
+
await mockServer.sendText(`/start`, USER_1)
|
|
143
|
+
mockServer.clearRequests()
|
|
144
|
+
|
|
145
|
+
await mockServer.sendCallbackQuery(`random-number`, USER_1)
|
|
146
|
+
mockServer.clearRequests()
|
|
147
|
+
|
|
148
|
+
const responses = await mockServer.sendCallbackQuery(`random-number`, USER_1)
|
|
149
|
+
|
|
150
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
151
|
+
const edit = responses[0]!
|
|
152
|
+
expect(edit!.body?.text).toContain(`Random Number`)
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it(`completes Sum Number two-step session flow`, async () => {
|
|
156
|
+
await mockServer.sendText(`/start`, USER_1)
|
|
157
|
+
mockServer.clearRequests()
|
|
158
|
+
|
|
159
|
+
const sumResponses = await mockServer.sendCallbackQuery(`sum-number`, USER_1)
|
|
160
|
+
expect(sumResponses.length).toBeGreaterThan(0)
|
|
161
|
+
expect(sumResponses[0]!.body?.text).toContain(`Input Left Number`)
|
|
162
|
+
|
|
163
|
+
mockServer.clearRequests()
|
|
164
|
+
|
|
165
|
+
const leftResponses = await mockServer.sendText(`23`, USER_1)
|
|
166
|
+
expect(leftResponses.length).toBeGreaterThan(0)
|
|
167
|
+
expect(leftResponses[0]!.body?.text).toContain(`Input Right Number`)
|
|
168
|
+
|
|
169
|
+
mockServer.clearRequests()
|
|
170
|
+
|
|
171
|
+
const resultResponses = await mockServer.sendText(`10`, USER_1)
|
|
172
|
+
expect(resultResponses.length).toBeGreaterThan(0)
|
|
173
|
+
expect(resultResponses[0]!.body?.text).toContain(`Result Sum`)
|
|
174
|
+
expect(resultResponses[0]!.body?.text).toContain(`33`)
|
|
175
|
+
|
|
176
|
+
const keyboard = resultResponses[0]!.body?.reply_markup?.inline_keyboard
|
|
177
|
+
expect(Array.isArray(keyboard)).toBe(true)
|
|
178
|
+
const firstButton = keyboard[0]?.[0]
|
|
179
|
+
expect(firstButton?.text).toContain(`Home`)
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
it(`handles invalid input in Sum Number gracefully`, async () => {
|
|
183
|
+
await mockServer.sendText(`/start`, USER_1)
|
|
184
|
+
mockServer.clearRequests()
|
|
185
|
+
|
|
186
|
+
await mockServer.sendCallbackQuery(`sum-number`, USER_1)
|
|
187
|
+
mockServer.clearRequests()
|
|
188
|
+
|
|
189
|
+
const leftResponses = await mockServer.sendText(`not-a-number`, USER_1)
|
|
190
|
+
expect(leftResponses.length).toBeGreaterThan(0)
|
|
191
|
+
expect(leftResponses[0]!.body?.text).toContain(`Input Left Number`)
|
|
192
|
+
})
|
|
193
|
+
|
|
194
|
+
it(`shows route not found for unrecognized callback`, async () => {
|
|
195
|
+
await mockServer.sendText(`/start`, USER_1)
|
|
196
|
+
mockServer.clearRequests()
|
|
197
|
+
|
|
198
|
+
const responses = await mockServer.sendCallbackQuery(`nonexistent_action_${Math.random()}`, USER_1)
|
|
199
|
+
expect(responses.length).toBeGreaterThanOrEqual(0)
|
|
200
|
+
})
|
|
201
|
+
|
|
202
|
+
it(`captures outbound requests in mockServer.requests`, async () => {
|
|
203
|
+
const responses = await mockServer.sendText(`/start`, USER_1)
|
|
204
|
+
|
|
205
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
206
|
+
const sendMessageReq = mockServer.lastRequest(`sendMessage`)
|
|
207
|
+
expect(sendMessageReq).toBeDefined()
|
|
208
|
+
expect(sendMessageReq?.body?.text).toContain(`Welcome to the bot`)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it(`handles multiple sequential interactions`, async () => {
|
|
212
|
+
const res1 = await mockServer.sendText(`/start`, USER_1)
|
|
213
|
+
expect(res1[0]?.body?.text).toContain(`Welcome to the bot`)
|
|
214
|
+
|
|
215
|
+
mockServer.clearRequests()
|
|
216
|
+
|
|
217
|
+
const res2 = await mockServer.sendCallbackQuery(`help`, USER_1)
|
|
218
|
+
expect(res2[0]?.body?.text).toContain(`Help Message`)
|
|
219
|
+
|
|
220
|
+
mockServer.clearRequests()
|
|
221
|
+
|
|
222
|
+
const res3 = await mockServer.sendCallbackQuery(`random-number`, USER_1)
|
|
223
|
+
expect(res3[0]?.body?.text).toContain(`Random Number`)
|
|
224
|
+
})
|
|
225
|
+
|
|
226
|
+
it(`sendPhoto triggers a response`, async () => {
|
|
227
|
+
const responses = await mockServer.sendPhoto({caption: `test photo`, ...USER_1})
|
|
228
|
+
|
|
229
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
230
|
+
expect(responses[0]?.body?.text).toContain(`Route Not Found`)
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it(`supports custom user and chat options`, async () => {
|
|
234
|
+
const responses = await mockServer.sendText(`/start`, {
|
|
235
|
+
user: {id: 99999, first_name: `CustomUser`, username: `customuser`},
|
|
236
|
+
chat: {id: 88888, type: `private`, first_name: `CustomChat`}
|
|
237
|
+
})
|
|
238
|
+
|
|
239
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
240
|
+
expect(responses[0]?.body?.text).toContain(`Welcome to the bot`)
|
|
241
|
+
|
|
242
|
+
const lastUpdate = mockServer.updates[mockServer.updates.length - 1]
|
|
243
|
+
expect(lastUpdate).toBeDefined()
|
|
244
|
+
const msg = (lastUpdate as any)?.message
|
|
245
|
+
expect(msg?.from?.id).toBe(99999)
|
|
246
|
+
expect(msg?.chat?.id).toBe(88888)
|
|
247
|
+
})
|
|
248
|
+
|
|
249
|
+
it(`blocks user without username and shows username required page`, async () => {
|
|
250
|
+
const responses = await mockServer.sendText(`/start`, {
|
|
251
|
+
user: {id: 77777, first_name: `NoUsername`},
|
|
252
|
+
chat: {id: 77777, type: `private`, first_name: `NoUsername`}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
expect(responses.length).toBeGreaterThan(0)
|
|
256
|
+
const reply = responses[0]!
|
|
257
|
+
expect(reply.body?.text).toContain(`Username Required`)
|
|
258
|
+
expect(reply.body?.text).toContain(`set the username first`)
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
it(`validates inline_keyboard structure for all navigation pages`, async () => {
|
|
262
|
+
const res1 = await mockServer.sendText(`/start`, USER_1)
|
|
263
|
+
expect(Array.isArray(res1[0]?.body?.reply_markup?.inline_keyboard)).toBe(true)
|
|
264
|
+
|
|
265
|
+
mockServer.clearRequests()
|
|
266
|
+
|
|
267
|
+
const res2 = await mockServer.sendCallbackQuery(`help`, USER_1)
|
|
268
|
+
const kb2 = res2[0]?.body?.reply_markup?.inline_keyboard
|
|
269
|
+
expect(Array.isArray(kb2)).toBe(true)
|
|
270
|
+
expect(kb2!.length).toBeGreaterThan(0)
|
|
271
|
+
expect(kb2![0]?.[0]?.text).toBeDefined()
|
|
272
|
+
expect(kb2![0]?.[0]?.callback_data).toBeDefined()
|
|
273
|
+
|
|
274
|
+
mockServer.clearRequests()
|
|
275
|
+
|
|
276
|
+
const res3 = await mockServer.sendCallbackQuery(`random-number`, USER_1)
|
|
277
|
+
const kb3 = res3[0]?.body?.reply_markup?.inline_keyboard
|
|
278
|
+
expect(Array.isArray(kb3)).toBe(true)
|
|
279
|
+
expect(kb3!.length).toBeGreaterThan(0)
|
|
280
|
+
for (const row of kb3!) {
|
|
281
|
+
for (const btn of row) {
|
|
282
|
+
expect(btn?.text).toBeDefined()
|
|
283
|
+
expect(btn?.callback_data).toBeDefined()
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
})
|
|
287
|
+
})
|
|
@@ -32,10 +32,13 @@
|
|
|
32
32
|
"start": "bun src/index.ts",
|
|
33
33
|
"build": "bun build src/index.ts --outdir dist --target bun",
|
|
34
34
|
"lint": "eslint .",
|
|
35
|
-
"lint:fix": "eslint . --fix"
|
|
35
|
+
"lint:fix": "eslint . --fix",
|
|
36
|
+
"test": "bun test test/",
|
|
37
|
+
"test:e2e": "bun test e2e/",
|
|
38
|
+
"test:all": "bun test test/ e2e/"
|
|
36
39
|
},
|
|
37
40
|
"dependencies": {
|
|
38
|
-
"gramstax": "^0.8.
|
|
41
|
+
"gramstax": "^0.8.11",
|
|
39
42
|
"dayjs": "^1.11.13"
|
|
40
43
|
},
|
|
41
44
|
"peerDependencies": {
|
|
File without changes
|