core-services-sdk 1.3.45 → 1.3.46
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/package.json +1 -1
- package/src/ids/generators.js +7 -0
- package/src/ids/prefixes.js +3 -0
- package/src/index.js +1 -0
- package/src/instant-messages/im-platform.js +18 -0
- package/src/instant-messages/index.js +4 -0
- package/src/instant-messages/message-type.js +153 -0
- package/src/instant-messages/message-types.js +127 -0
- package/src/instant-messages/message-unified-mapper.js +251 -0
- package/tests/ids/prefixes.unit.test.js +1 -0
- package/tests/instant-messages/applications.unit.test.js +27 -0
- package/tests/instant-messages/message-type.unit.test.js +193 -0
- package/tests/instant-messages/message-types.unit.test.js +93 -0
- package/tests/instant-messages/message-unified-mapper-telegram.unit.test.js +66 -0
- package/tests/instant-messages/message-unified-mapper-united.unit.test.js +94 -0
- package/tests/instant-messages/message-unified-mapper-whatsapp.unit.test.js +65 -0
- package/tests/instant-messages/mock-messages/telegram/contact.json +27 -0
- package/tests/instant-messages/mock-messages/telegram/document.json +43 -0
- package/tests/instant-messages/mock-messages/telegram/location.json +26 -0
- package/tests/instant-messages/mock-messages/telegram/photo.json +52 -0
- package/tests/instant-messages/mock-messages/telegram/poll.json +45 -0
- package/tests/instant-messages/mock-messages/telegram/text.json +63 -0
- package/tests/instant-messages/mock-messages/telegram/video.json +46 -0
- package/tests/instant-messages/mock-messages/telegram/video_note.json +43 -0
- package/tests/instant-messages/mock-messages/telegram/voice.json +29 -0
- package/tests/instant-messages/mock-messages/whatsapp/audio.json +42 -0
- package/tests/instant-messages/mock-messages/whatsapp/contacts.json +50 -0
- package/tests/instant-messages/mock-messages/whatsapp/document.json +42 -0
- package/tests/instant-messages/mock-messages/whatsapp/image.json +41 -0
- package/tests/instant-messages/mock-messages/whatsapp/location.json +40 -0
- package/tests/instant-messages/mock-messages/whatsapp/reaction.json +40 -0
- package/tests/instant-messages/mock-messages/whatsapp/sticker.json +42 -0
- package/tests/instant-messages/mock-messages/whatsapp/text.json +39 -0
- package/tests/instant-messages/mock-messages/whatsapp/video.json +41 -0
- package/types/ids/generators.d.ts +1 -0
- package/types/ids/prefixes.d.ts +2 -0
- package/types/index.d.ts +1 -0
- package/types/instant-messages/im-platform.d.ts +13 -0
- package/types/instant-messages/index.d.ts +4 -0
- package/types/instant-messages/message-type.d.ts +28 -0
- package/types/instant-messages/message-types.d.ts +62 -0
- package/types/instant-messages/message-unified-mapper.d.ts +380 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
isItPoll,
|
|
4
|
+
isItPhoto,
|
|
5
|
+
isItVideo,
|
|
6
|
+
isItVoice,
|
|
7
|
+
isItContact,
|
|
8
|
+
isItDocument,
|
|
9
|
+
isItFreeText,
|
|
10
|
+
isItMediaType,
|
|
11
|
+
getTelegramMessageType,
|
|
12
|
+
isMessageTypeof,
|
|
13
|
+
isCallbackQuery,
|
|
14
|
+
} from '../../src/instant-messages/message-type.js'
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
MESSAGE_MEDIA_TYPE,
|
|
18
|
+
MESSAGE_TYPE,
|
|
19
|
+
} from '../../src/instant-messages/message-types.js'
|
|
20
|
+
|
|
21
|
+
describe('message-type helpers', () => {
|
|
22
|
+
describe('isItMediaType', () => {
|
|
23
|
+
const isPhoto = isItMediaType(MESSAGE_MEDIA_TYPE.PHOTO)
|
|
24
|
+
|
|
25
|
+
it('returns true when media type exists inside message', () => {
|
|
26
|
+
const originalMessage = { message: { photo: [{}] } }
|
|
27
|
+
expect(isPhoto({ originalMessage })).toBe(true)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('returns false when media type does not exist', () => {
|
|
31
|
+
const originalMessage = { message: { text: 'hi' } }
|
|
32
|
+
expect(isPhoto({ originalMessage })).toBe(false)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('returns false when message is missing', () => {
|
|
36
|
+
expect(isPhoto({ originalMessage: {} })).toBe(false)
|
|
37
|
+
expect(isPhoto({ originalMessage: null })).toBe(false)
|
|
38
|
+
})
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
describe('isMessageTypeof', () => {
|
|
42
|
+
const isButtonClick = isMessageTypeof(MESSAGE_TYPE.BUTTON_CLICK)
|
|
43
|
+
|
|
44
|
+
it('returns true when type matches', () => {
|
|
45
|
+
const originalMessage = { type: MESSAGE_TYPE.BUTTON_CLICK }
|
|
46
|
+
expect(isButtonClick({ originalMessage })).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('returns false when type differs', () => {
|
|
50
|
+
const originalMessage = { type: MESSAGE_MEDIA_TYPE.TEXT }
|
|
51
|
+
expect(isButtonClick({ originalMessage })).toBe(false)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('returns false on missing type', () => {
|
|
55
|
+
const originalMessage = {}
|
|
56
|
+
expect(isButtonClick({ originalMessage })).toBe(false)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('isCallbackQuery', () => {
|
|
61
|
+
it('returns true for Telegram callback_query', () => {
|
|
62
|
+
const originalMessage = { callback_query: { data: '1' } }
|
|
63
|
+
expect(isCallbackQuery({ originalMessage })).toBe(true)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('returns false otherwise', () => {
|
|
67
|
+
expect(isCallbackQuery({ originalMessage: {} })).toBe(false)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
describe('media helpers', () => {
|
|
72
|
+
it('isItFreeText works', () => {
|
|
73
|
+
expect(
|
|
74
|
+
isItFreeText({ originalMessage: { message: { text: 'hi' } } }),
|
|
75
|
+
).toBe(true)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('isItPhoto works', () => {
|
|
79
|
+
expect(isItPhoto({ originalMessage: { message: { photo: [{}] } } })).toBe(
|
|
80
|
+
true,
|
|
81
|
+
)
|
|
82
|
+
})
|
|
83
|
+
|
|
84
|
+
it('isItVideo works', () => {
|
|
85
|
+
expect(isItVideo({ originalMessage: { message: { video: {} } } })).toBe(
|
|
86
|
+
true,
|
|
87
|
+
)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('isItVoice works', () => {
|
|
91
|
+
expect(isItVoice({ originalMessage: { message: { voice: {} } } })).toBe(
|
|
92
|
+
true,
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('isItDocument works', () => {
|
|
97
|
+
expect(
|
|
98
|
+
isItDocument({ originalMessage: { message: { document: {} } } }),
|
|
99
|
+
).toBe(true)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('isItContact works', () => {
|
|
103
|
+
expect(
|
|
104
|
+
isItContact({ originalMessage: { message: { contact: {} } } }),
|
|
105
|
+
).toBe(true)
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('isItPoll works', () => {
|
|
109
|
+
expect(isItPoll({ originalMessage: { message: { poll: {} } } })).toBe(
|
|
110
|
+
true,
|
|
111
|
+
)
|
|
112
|
+
})
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
describe('getTelegramMessageType', () => {
|
|
116
|
+
it('detects callback_query → BUTTON_CLICK', () => {
|
|
117
|
+
const originalMessage = { callback_query: {} }
|
|
118
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
119
|
+
MESSAGE_TYPE.BUTTON_CLICK,
|
|
120
|
+
)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('detects text', () => {
|
|
124
|
+
const originalMessage = { message: { text: 'hello' } }
|
|
125
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
126
|
+
MESSAGE_MEDIA_TYPE.TEXT,
|
|
127
|
+
)
|
|
128
|
+
})
|
|
129
|
+
|
|
130
|
+
it('detects photo', () => {
|
|
131
|
+
const originalMessage = { message: { photo: [{}] } }
|
|
132
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
133
|
+
MESSAGE_MEDIA_TYPE.PHOTO,
|
|
134
|
+
)
|
|
135
|
+
})
|
|
136
|
+
|
|
137
|
+
it('detects video', () => {
|
|
138
|
+
const originalMessage = { message: { video: {} } }
|
|
139
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
140
|
+
MESSAGE_MEDIA_TYPE.VIDEO,
|
|
141
|
+
)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
it('detects document', () => {
|
|
145
|
+
const originalMessage = { message: { document: {} } }
|
|
146
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
147
|
+
MESSAGE_MEDIA_TYPE.DOCUMENT,
|
|
148
|
+
)
|
|
149
|
+
})
|
|
150
|
+
|
|
151
|
+
it('detects location', () => {
|
|
152
|
+
const originalMessage = { message: { location: {} } }
|
|
153
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
154
|
+
MESSAGE_MEDIA_TYPE.LOCATION,
|
|
155
|
+
)
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
it('detects voice', () => {
|
|
159
|
+
const originalMessage = { message: { voice: {} } }
|
|
160
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
161
|
+
MESSAGE_MEDIA_TYPE.VOICE,
|
|
162
|
+
)
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
it('detects poll', () => {
|
|
166
|
+
const originalMessage = { message: { poll: {} } }
|
|
167
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
168
|
+
MESSAGE_MEDIA_TYPE.POLL,
|
|
169
|
+
)
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
it('detects sticker', () => {
|
|
173
|
+
const originalMessage = { message: { sticker: {} } }
|
|
174
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
175
|
+
MESSAGE_MEDIA_TYPE.STICKER,
|
|
176
|
+
)
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
it('detects contact', () => {
|
|
180
|
+
const originalMessage = { message: { contact: {} } }
|
|
181
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
182
|
+
MESSAGE_MEDIA_TYPE.CONTACT,
|
|
183
|
+
)
|
|
184
|
+
})
|
|
185
|
+
|
|
186
|
+
it('falls back to UNKNOWN_MESSAGE_TYPE', () => {
|
|
187
|
+
const originalMessage = { message: { something_else: 'x' } }
|
|
188
|
+
expect(getTelegramMessageType({ originalMessage })).toBe(
|
|
189
|
+
MESSAGE_TYPE.UNKNOWN_MESSAGE_TYPE,
|
|
190
|
+
)
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
})
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import {
|
|
3
|
+
MESSAGE_TYPE,
|
|
4
|
+
MESSAGE_MEDIA_TYPE,
|
|
5
|
+
MESSAGE_MEDIA_TYPE_MAPPER,
|
|
6
|
+
} from '../../src/instant-messages/message-types.js'
|
|
7
|
+
|
|
8
|
+
describe('MESSAGE_MEDIA_TYPE', () => {
|
|
9
|
+
it('should contain all required media type keys', () => {
|
|
10
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('TEXT')
|
|
11
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('POLL')
|
|
12
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('VIDEO')
|
|
13
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('PHOTO')
|
|
14
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('IMAGE')
|
|
15
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('VOICE')
|
|
16
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('AUDIO')
|
|
17
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('STICKER')
|
|
18
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('CONTACT')
|
|
19
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('MESSAGE')
|
|
20
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('REACTION')
|
|
21
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('DOCUMENT')
|
|
22
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('LOCATION')
|
|
23
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('CONTACTS')
|
|
24
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('VIDEO_NOTE')
|
|
25
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('BUTTON_CLICK')
|
|
26
|
+
expect(MESSAGE_MEDIA_TYPE).toHaveProperty('BUTTON_CLICK_MULTIPLE')
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
it('should have correct string values', () => {
|
|
30
|
+
expect(MESSAGE_MEDIA_TYPE.TEXT).toBe('text')
|
|
31
|
+
expect(MESSAGE_MEDIA_TYPE.POLL).toBe('poll')
|
|
32
|
+
expect(MESSAGE_MEDIA_TYPE.VIDEO).toBe('video')
|
|
33
|
+
expect(MESSAGE_MEDIA_TYPE.PHOTO).toBe('photo')
|
|
34
|
+
expect(MESSAGE_MEDIA_TYPE.IMAGE).toBe('image')
|
|
35
|
+
expect(MESSAGE_MEDIA_TYPE.VOICE).toBe('voice')
|
|
36
|
+
expect(MESSAGE_MEDIA_TYPE.AUDIO).toBe('audio')
|
|
37
|
+
expect(MESSAGE_MEDIA_TYPE.STICKER).toBe('sticker')
|
|
38
|
+
expect(MESSAGE_MEDIA_TYPE.CONTACT).toBe('contact')
|
|
39
|
+
expect(MESSAGE_MEDIA_TYPE.MESSAGE).toBe('message')
|
|
40
|
+
expect(MESSAGE_MEDIA_TYPE.REACTION).toBe('reaction')
|
|
41
|
+
expect(MESSAGE_MEDIA_TYPE.DOCUMENT).toBe('document')
|
|
42
|
+
expect(MESSAGE_MEDIA_TYPE.LOCATION).toBe('location')
|
|
43
|
+
expect(MESSAGE_MEDIA_TYPE.CONTACTS).toBe('contacts')
|
|
44
|
+
expect(MESSAGE_MEDIA_TYPE.VIDEO_NOTE).toBe('video_note')
|
|
45
|
+
expect(MESSAGE_MEDIA_TYPE.BUTTON_CLICK).toBe('button_click')
|
|
46
|
+
expect(MESSAGE_MEDIA_TYPE.BUTTON_CLICK_MULTIPLE).toBe(
|
|
47
|
+
'button_click_multiple',
|
|
48
|
+
)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('MESSAGE_TYPE', () => {
|
|
53
|
+
it('should contain all expected keys', () => {
|
|
54
|
+
expect(MESSAGE_TYPE).toHaveProperty('MESSAGE')
|
|
55
|
+
expect(MESSAGE_TYPE).toHaveProperty('BUTTON_CLICK')
|
|
56
|
+
expect(MESSAGE_TYPE).toHaveProperty('BUTTON_CLICK_MULTIPLE')
|
|
57
|
+
expect(MESSAGE_TYPE).toHaveProperty('UNKNOWN_MESSAGE_TYPE')
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
it('should correctly reuse MEDIA_TYPE for interactive types', () => {
|
|
61
|
+
expect(MESSAGE_TYPE.BUTTON_CLICK).toBe('button_click')
|
|
62
|
+
expect(MESSAGE_TYPE.BUTTON_CLICK_MULTIPLE).toBe('button_click_multiple')
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
it('should correctly define fallback unknown type', () => {
|
|
66
|
+
expect(MESSAGE_TYPE.UNKNOWN_MESSAGE_TYPE).toBe('unknown_message_type')
|
|
67
|
+
})
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
describe('MESSAGE_MEDIA_TYPE_MAPPER', () => {
|
|
71
|
+
it('should correctly map Telegram voice → audio', () => {
|
|
72
|
+
expect(MESSAGE_MEDIA_TYPE_MAPPER[MESSAGE_MEDIA_TYPE.VOICE]).toBe(
|
|
73
|
+
MESSAGE_MEDIA_TYPE.AUDIO,
|
|
74
|
+
)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('should correctly map Telegram photo → image', () => {
|
|
78
|
+
expect(MESSAGE_MEDIA_TYPE_MAPPER[MESSAGE_MEDIA_TYPE.PHOTO]).toBe(
|
|
79
|
+
MESSAGE_MEDIA_TYPE.IMAGE,
|
|
80
|
+
)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
it('should correctly map WhatsApp contacts → contact', () => {
|
|
84
|
+
expect(MESSAGE_MEDIA_TYPE_MAPPER[MESSAGE_MEDIA_TYPE.CONTACTS]).toBe(
|
|
85
|
+
MESSAGE_MEDIA_TYPE.CONTACT,
|
|
86
|
+
)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
it('should not map unrelated keys', () => {
|
|
90
|
+
expect(MESSAGE_MEDIA_TYPE_MAPPER[MESSAGE_MEDIA_TYPE.VIDEO]).toBeUndefined()
|
|
91
|
+
expect(MESSAGE_MEDIA_TYPE_MAPPER[MESSAGE_MEDIA_TYPE.TEXT]).toBeUndefined()
|
|
92
|
+
})
|
|
93
|
+
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { readFileSync, readdirSync } from 'fs'
|
|
3
|
+
import { join, extname } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { dirname } from 'path'
|
|
6
|
+
import { mapMessageTelegram } from '../../src/instant-messages/message-unified-mapper.js'
|
|
7
|
+
|
|
8
|
+
import { getTelegramMessageType } from '../../src/instant-messages/message-type.js'
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
MESSAGE_MEDIA_TYPE,
|
|
12
|
+
MESSAGE_MEDIA_TYPE_MAPPER,
|
|
13
|
+
} from '../../src/instant-messages/message-types.js'
|
|
14
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
15
|
+
const __dirname = dirname(__filename)
|
|
16
|
+
|
|
17
|
+
const MOCK_DIR_TELEGRAM = join(__dirname, './mock-messages/telegram')
|
|
18
|
+
|
|
19
|
+
describe('Telegram unified message mapper – all mock samples', () => {
|
|
20
|
+
const files = readdirSync(MOCK_DIR_TELEGRAM).filter(
|
|
21
|
+
(f) => extname(f) === '.json',
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
if (files.length === 0) {
|
|
25
|
+
throw new Error('No Telegram mock message files found in directory.')
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
for (const file of files) {
|
|
29
|
+
const filePath = join(MOCK_DIR_TELEGRAM, file)
|
|
30
|
+
const raw = JSON.parse(readFileSync(filePath, 'utf8'))
|
|
31
|
+
|
|
32
|
+
describe(`Message mock: ${file}`, () => {
|
|
33
|
+
it('should map type correctly', () => {
|
|
34
|
+
const unifiedType = getTelegramMessageType({ originalMessage: raw })
|
|
35
|
+
|
|
36
|
+
const unifiedMessage = mapMessageTelegram({
|
|
37
|
+
originalMessage: raw,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
expect(unifiedMessage).toBeTypeOf('object')
|
|
41
|
+
expect(unifiedType).toBeTypeOf('string')
|
|
42
|
+
|
|
43
|
+
expect(unifiedMessage.type).toBe(
|
|
44
|
+
MESSAGE_MEDIA_TYPE_MAPPER[unifiedType] || unifiedType,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
expect(Object.values(MESSAGE_MEDIA_TYPE)).toContain(unifiedType)
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
it('should include mandatory unified fields', () => {
|
|
51
|
+
const unified = mapMessageTelegram({ originalMessage: raw })
|
|
52
|
+
|
|
53
|
+
expect(unified).toHaveProperty('id')
|
|
54
|
+
expect(unified).toHaveProperty('chatId')
|
|
55
|
+
expect(unified).toHaveProperty('type')
|
|
56
|
+
expect(unified).toHaveProperty('timestamp')
|
|
57
|
+
expect(unified).toHaveProperty('chatter')
|
|
58
|
+
expect(unified).toHaveProperty('imExtraInfo')
|
|
59
|
+
|
|
60
|
+
expect(unified.chatter).toHaveProperty('id')
|
|
61
|
+
expect(unified.chatter).toHaveProperty('name')
|
|
62
|
+
expect(unified.imExtraInfo).toHaveProperty('tmId')
|
|
63
|
+
})
|
|
64
|
+
})
|
|
65
|
+
}
|
|
66
|
+
})
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { readFileSync, readdirSync } from 'fs'
|
|
3
|
+
import { join, extname } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { dirname } from 'path'
|
|
6
|
+
|
|
7
|
+
import { messageUnifiedMapper } from '../../src/instant-messages/message-unified-mapper.js'
|
|
8
|
+
|
|
9
|
+
import { MESSAGE_MEDIA_TYPE } from '../../src/instant-messages/message-types.js'
|
|
10
|
+
import { IM_PLATFORM } from '../../src/instant-messages/im-platform.js'
|
|
11
|
+
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
13
|
+
const __dirname = dirname(__filename)
|
|
14
|
+
|
|
15
|
+
const MOCK_DIR_WHATSAPP = join(__dirname, './mock-messages/whatsapp')
|
|
16
|
+
const MOCK_DIR_TELEGRAM = join(__dirname, './mock-messages/telegram')
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Loads all mock JSON files from directory and returns:
|
|
20
|
+
* [
|
|
21
|
+
* { application: 'whatsapp', file: 'x.json', json: {...} }
|
|
22
|
+
* ]
|
|
23
|
+
*/
|
|
24
|
+
function loadMocks() {
|
|
25
|
+
const list = []
|
|
26
|
+
|
|
27
|
+
const whatsappFiles = readdirSync(MOCK_DIR_WHATSAPP).filter(
|
|
28
|
+
(f) => extname(f) === '.json',
|
|
29
|
+
)
|
|
30
|
+
for (const file of whatsappFiles) {
|
|
31
|
+
const raw = JSON.parse(readFileSync(join(MOCK_DIR_WHATSAPP, file), 'utf8'))
|
|
32
|
+
list.push({
|
|
33
|
+
application: IM_PLATFORM.WHATSAPP,
|
|
34
|
+
file,
|
|
35
|
+
raw,
|
|
36
|
+
})
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const telegramFiles = readdirSync(MOCK_DIR_TELEGRAM).filter(
|
|
40
|
+
(f) => extname(f) === '.json',
|
|
41
|
+
)
|
|
42
|
+
for (const file of telegramFiles) {
|
|
43
|
+
const raw = JSON.parse(readFileSync(join(MOCK_DIR_TELEGRAM, file), 'utf8'))
|
|
44
|
+
list.push({
|
|
45
|
+
application: IM_PLATFORM.TELEGRAM,
|
|
46
|
+
file,
|
|
47
|
+
raw,
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return list
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
describe('Unified message mapper – all platforms, all mock samples', () => {
|
|
55
|
+
const samples = loadMocks()
|
|
56
|
+
|
|
57
|
+
if (samples.length === 0) {
|
|
58
|
+
throw new Error('No mock message files for unified mapper test.')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
for (const sample of samples) {
|
|
62
|
+
const { application, file, raw } = sample
|
|
63
|
+
|
|
64
|
+
describe(`${application} – ${file}`, () => {
|
|
65
|
+
it('should map unified message correctly', () => {
|
|
66
|
+
const mapper = messageUnifiedMapper[application]
|
|
67
|
+
expect(mapper).toBeTypeOf('function')
|
|
68
|
+
|
|
69
|
+
const unified = mapper({ originalMessage: raw })
|
|
70
|
+
|
|
71
|
+
expect(unified).toBeTypeOf('object')
|
|
72
|
+
expect(unified).toHaveProperty('id')
|
|
73
|
+
expect(unified).toHaveProperty('chatId')
|
|
74
|
+
expect(unified).toHaveProperty('type')
|
|
75
|
+
expect(unified).toHaveProperty('timestamp')
|
|
76
|
+
expect(unified).toHaveProperty('chatter')
|
|
77
|
+
expect(unified).toHaveProperty('imExtraInfo')
|
|
78
|
+
|
|
79
|
+
expect(Object.values(MESSAGE_MEDIA_TYPE)).toContain(unified.type)
|
|
80
|
+
|
|
81
|
+
expect(unified.chatter).toHaveProperty('id')
|
|
82
|
+
expect(unified.chatter).toHaveProperty('name')
|
|
83
|
+
|
|
84
|
+
if (application === IM_PLATFORM.WHATSAPP) {
|
|
85
|
+
expect(unified.imExtraInfo).toHaveProperty('wbaid')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (application === IM_PLATFORM.TELEGRAM) {
|
|
89
|
+
expect(unified.imExtraInfo).toHaveProperty('tmId')
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
})
|
|
93
|
+
}
|
|
94
|
+
})
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import { readFileSync, readdirSync } from 'fs'
|
|
3
|
+
import { join, extname } from 'path'
|
|
4
|
+
import { fileURLToPath } from 'url'
|
|
5
|
+
import { dirname } from 'path'
|
|
6
|
+
import {
|
|
7
|
+
getMessageType,
|
|
8
|
+
mapMessageWhatsApp,
|
|
9
|
+
} from '../../src/instant-messages/message-unified-mapper.js'
|
|
10
|
+
|
|
11
|
+
import { MESSAGE_MEDIA_TYPE } from '../../src/instant-messages/message-types.js'
|
|
12
|
+
const __filename = fileURLToPath(import.meta.url)
|
|
13
|
+
const __dirname = dirname(__filename)
|
|
14
|
+
|
|
15
|
+
const MOCK_DIR_WHATSAPP = join(__dirname, './mock-messages/whatsapp')
|
|
16
|
+
|
|
17
|
+
describe('WhatsApp unified message mapper – all mock samples', () => {
|
|
18
|
+
const files = readdirSync(MOCK_DIR_WHATSAPP).filter(
|
|
19
|
+
(f) => extname(f) === '.json',
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
if (files.length === 0) {
|
|
23
|
+
throw new Error('No WhatsApp mock message files found in directory.')
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (const file of files) {
|
|
27
|
+
const filePath = join(MOCK_DIR_WHATSAPP, file)
|
|
28
|
+
const raw = JSON.parse(readFileSync(filePath, 'utf8'))
|
|
29
|
+
|
|
30
|
+
describe(`Message mock: ${file}`, () => {
|
|
31
|
+
it('should map type correctly', () => {
|
|
32
|
+
console.log(file)
|
|
33
|
+
const unifiedType = getMessageType({ originalMessage: raw })
|
|
34
|
+
|
|
35
|
+
const unifiedMessage = mapMessageWhatsApp({
|
|
36
|
+
originalMessage: raw,
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
expect(unifiedMessage).toBeTypeOf('object')
|
|
40
|
+
expect(unifiedType).toBeTypeOf('string')
|
|
41
|
+
|
|
42
|
+
// Type must match mapper result
|
|
43
|
+
expect(unifiedMessage.type).toBe(unifiedType)
|
|
44
|
+
|
|
45
|
+
// All unified types must be supported values
|
|
46
|
+
expect(Object.values(MESSAGE_MEDIA_TYPE)).toContain(unifiedType)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should include mandatory unified fields', () => {
|
|
50
|
+
const unified = mapMessageWhatsApp({ originalMessage: raw })
|
|
51
|
+
|
|
52
|
+
expect(unified).toHaveProperty('id')
|
|
53
|
+
expect(unified).toHaveProperty('chatId')
|
|
54
|
+
expect(unified).toHaveProperty('type')
|
|
55
|
+
expect(unified).toHaveProperty('timestamp')
|
|
56
|
+
expect(unified).toHaveProperty('chatter')
|
|
57
|
+
expect(unified).toHaveProperty('imExtraInfo')
|
|
58
|
+
|
|
59
|
+
expect(unified.chatter).toHaveProperty('id')
|
|
60
|
+
expect(unified.chatter).toHaveProperty('name')
|
|
61
|
+
expect(unified.imExtraInfo).toHaveProperty('wbaid')
|
|
62
|
+
})
|
|
63
|
+
})
|
|
64
|
+
}
|
|
65
|
+
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"update_id": 895013314,
|
|
3
|
+
"message": {
|
|
4
|
+
"message_id": 18,
|
|
5
|
+
"from": {
|
|
6
|
+
"id": 59627707,
|
|
7
|
+
"is_bot": false,
|
|
8
|
+
"first_name": "Haim",
|
|
9
|
+
"last_name": "Rubin",
|
|
10
|
+
"username": "haimrubin",
|
|
11
|
+
"language_code": "en"
|
|
12
|
+
},
|
|
13
|
+
"chat": {
|
|
14
|
+
"id": 59627707,
|
|
15
|
+
"first_name": "Haim",
|
|
16
|
+
"last_name": "Rubin",
|
|
17
|
+
"username": "haimrubin",
|
|
18
|
+
"type": "private"
|
|
19
|
+
},
|
|
20
|
+
"date": 1763789905,
|
|
21
|
+
"contact": {
|
|
22
|
+
"phone_number": "31625129658",
|
|
23
|
+
"first_name": "Ahmad",
|
|
24
|
+
"user_id": 1594286144
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"update_id": 895013311,
|
|
3
|
+
"message": {
|
|
4
|
+
"message_id": 15,
|
|
5
|
+
"from": {
|
|
6
|
+
"id": 59627707,
|
|
7
|
+
"is_bot": false,
|
|
8
|
+
"first_name": "Haim",
|
|
9
|
+
"last_name": "Rubin",
|
|
10
|
+
"username": "haimrubin",
|
|
11
|
+
"language_code": "en"
|
|
12
|
+
},
|
|
13
|
+
"chat": {
|
|
14
|
+
"id": 59627707,
|
|
15
|
+
"first_name": "Haim",
|
|
16
|
+
"last_name": "Rubin",
|
|
17
|
+
"username": "haimrubin",
|
|
18
|
+
"type": "private"
|
|
19
|
+
},
|
|
20
|
+
"date": 1763789772,
|
|
21
|
+
"document": {
|
|
22
|
+
"file_name": "View PDF Statement_2024-12-31.pdf",
|
|
23
|
+
"mime_type": "application/pdf",
|
|
24
|
+
"thumbnail": {
|
|
25
|
+
"file_id": "AAMCBAADGQEAAw9pIUvMD7oscJOFf765U00bgAk_6AACsBkAAn3bmVCXCOv2H3Zr0wEAB20AAzYE",
|
|
26
|
+
"file_unique_id": "AQADsBkAAn3bmVBy",
|
|
27
|
+
"file_size": 13015,
|
|
28
|
+
"width": 247,
|
|
29
|
+
"height": 320
|
|
30
|
+
},
|
|
31
|
+
"thumb": {
|
|
32
|
+
"file_id": "AAMCBAADGQEAAw9pIUvMD7oscJOFf765U00bgAk_6AACsBkAAn3bmVCXCOv2H3Zr0wEAB20AAzYE",
|
|
33
|
+
"file_unique_id": "AQADsBkAAn3bmVBy",
|
|
34
|
+
"file_size": 13015,
|
|
35
|
+
"width": 247,
|
|
36
|
+
"height": 320
|
|
37
|
+
},
|
|
38
|
+
"file_id": "BQACAgQAAxkBAAMPaSFLzA-6LHCThX--uVNNG4AJP-gAArAZAAJ925lQlwjr9h92a9M2BA",
|
|
39
|
+
"file_unique_id": "AgADsBkAAn3bmVA",
|
|
40
|
+
"file_size": 934888
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"update_id": 895013312,
|
|
3
|
+
"message": {
|
|
4
|
+
"message_id": 16,
|
|
5
|
+
"from": {
|
|
6
|
+
"id": 59627707,
|
|
7
|
+
"is_bot": false,
|
|
8
|
+
"first_name": "Haim",
|
|
9
|
+
"last_name": "Rubin",
|
|
10
|
+
"username": "haimrubin",
|
|
11
|
+
"language_code": "en"
|
|
12
|
+
},
|
|
13
|
+
"chat": {
|
|
14
|
+
"id": 59627707,
|
|
15
|
+
"first_name": "Haim",
|
|
16
|
+
"last_name": "Rubin",
|
|
17
|
+
"username": "haimrubin",
|
|
18
|
+
"type": "private"
|
|
19
|
+
},
|
|
20
|
+
"date": 1763789784,
|
|
21
|
+
"location": {
|
|
22
|
+
"latitude": 32.040577,
|
|
23
|
+
"longitude": 34.857177
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"update_id": 895013309,
|
|
3
|
+
"message": {
|
|
4
|
+
"message_id": 13,
|
|
5
|
+
"from": {
|
|
6
|
+
"id": 59627707,
|
|
7
|
+
"is_bot": false,
|
|
8
|
+
"first_name": "Haim",
|
|
9
|
+
"last_name": "Rubin",
|
|
10
|
+
"username": "haimrubin",
|
|
11
|
+
"language_code": "en"
|
|
12
|
+
},
|
|
13
|
+
"chat": {
|
|
14
|
+
"id": 59627707,
|
|
15
|
+
"first_name": "Haim",
|
|
16
|
+
"last_name": "Rubin",
|
|
17
|
+
"username": "haimrubin",
|
|
18
|
+
"type": "private"
|
|
19
|
+
},
|
|
20
|
+
"date": 1763789720,
|
|
21
|
+
"photo": [
|
|
22
|
+
{
|
|
23
|
+
"file_id": "AgACAgQAAxkBAAMNaSFLmGK4vl2nmLRj5OlaSWYcxvMAAgkLaxtNXxFRI0N7hce2i0IBAAMCAANzAAM2BA",
|
|
24
|
+
"file_unique_id": "AQADCQtrG01fEVF4",
|
|
25
|
+
"file_size": 1418,
|
|
26
|
+
"width": 51,
|
|
27
|
+
"height": 90
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"file_id": "AgACAgQAAxkBAAMNaSFLmGK4vl2nmLRj5OlaSWYcxvMAAgkLaxtNXxFRI0N7hce2i0IBAAMCAANtAAM2BA",
|
|
31
|
+
"file_unique_id": "AQADCQtrG01fEVFy",
|
|
32
|
+
"file_size": 19936,
|
|
33
|
+
"width": 180,
|
|
34
|
+
"height": 320
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
"file_id": "AgACAgQAAxkBAAMNaSFLmGK4vl2nmLRj5OlaSWYcxvMAAgkLaxtNXxFRI0N7hce2i0IBAAMCAAN4AAM2BA",
|
|
38
|
+
"file_unique_id": "AQADCQtrG01fEVF9",
|
|
39
|
+
"file_size": 91531,
|
|
40
|
+
"width": 450,
|
|
41
|
+
"height": 800
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"file_id": "AgACAgQAAxkBAAMNaSFLmGK4vl2nmLRj5OlaSWYcxvMAAgkLaxtNXxFRI0N7hce2i0IBAAMCAAN5AAM2BA",
|
|
45
|
+
"file_unique_id": "AQADCQtrG01fEVF-",
|
|
46
|
+
"file_size": 127439,
|
|
47
|
+
"width": 720,
|
|
48
|
+
"height": 1280
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
}
|
|
52
|
+
}
|