core-services-sdk 1.3.45 → 1.3.47
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 +247 -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 +185 -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 +2 -0
- package/types/ids/prefixes.d.ts +4 -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 +24 -0
- package/types/instant-messages/message-types.d.ts +62 -0
- package/types/instant-messages/message-unified-mapper.d.ts +356 -0
|
@@ -0,0 +1,185 @@
|
|
|
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 imMessage = { message: { photo: [{}] } }
|
|
27
|
+
expect(isPhoto({ imMessage })).toBe(true)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
it('returns false when media type does not exist', () => {
|
|
31
|
+
const imMessage = { message: { text: 'hi' } }
|
|
32
|
+
expect(isPhoto({ imMessage })).toBe(false)
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('returns false when message is missing', () => {
|
|
36
|
+
expect(isPhoto({ imMessage: {} })).toBe(false)
|
|
37
|
+
expect(isPhoto({ imMessage: 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 imMessage = { type: MESSAGE_TYPE.BUTTON_CLICK }
|
|
46
|
+
expect(isButtonClick({ imMessage })).toBe(true)
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('returns false when type differs', () => {
|
|
50
|
+
const imMessage = { type: MESSAGE_MEDIA_TYPE.TEXT }
|
|
51
|
+
expect(isButtonClick({ imMessage })).toBe(false)
|
|
52
|
+
})
|
|
53
|
+
|
|
54
|
+
it('returns false on missing type', () => {
|
|
55
|
+
const imMessage = {}
|
|
56
|
+
expect(isButtonClick({ imMessage })).toBe(false)
|
|
57
|
+
})
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
describe('isCallbackQuery', () => {
|
|
61
|
+
it('returns true for Telegram callback_query', () => {
|
|
62
|
+
const imMessage = { callback_query: { data: '1' } }
|
|
63
|
+
expect(isCallbackQuery({ imMessage })).toBe(true)
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
it('returns false otherwise', () => {
|
|
67
|
+
expect(isCallbackQuery({ imMessage: {} })).toBe(false)
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
|
|
71
|
+
describe('media helpers', () => {
|
|
72
|
+
it('isItFreeText works', () => {
|
|
73
|
+
expect(isItFreeText({ imMessage: { message: { text: 'hi' } } })).toBe(
|
|
74
|
+
true,
|
|
75
|
+
)
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
it('isItPhoto works', () => {
|
|
79
|
+
expect(isItPhoto({ imMessage: { message: { photo: [{}] } } })).toBe(true)
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('isItVideo works', () => {
|
|
83
|
+
expect(isItVideo({ imMessage: { message: { video: {} } } })).toBe(true)
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
it('isItVoice works', () => {
|
|
87
|
+
expect(isItVoice({ imMessage: { message: { voice: {} } } })).toBe(true)
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('isItDocument works', () => {
|
|
91
|
+
expect(isItDocument({ imMessage: { message: { document: {} } } })).toBe(
|
|
92
|
+
true,
|
|
93
|
+
)
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('isItContact works', () => {
|
|
97
|
+
expect(isItContact({ imMessage: { message: { contact: {} } } })).toBe(
|
|
98
|
+
true,
|
|
99
|
+
)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('isItPoll works', () => {
|
|
103
|
+
expect(isItPoll({ imMessage: { message: { poll: {} } } })).toBe(true)
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
describe('getTelegramMessageType', () => {
|
|
108
|
+
it('detects callback_query → BUTTON_CLICK', () => {
|
|
109
|
+
const imMessage = { callback_query: {} }
|
|
110
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
111
|
+
MESSAGE_TYPE.BUTTON_CLICK,
|
|
112
|
+
)
|
|
113
|
+
})
|
|
114
|
+
|
|
115
|
+
it('detects text', () => {
|
|
116
|
+
const imMessage = { message: { text: 'hello' } }
|
|
117
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
118
|
+
MESSAGE_MEDIA_TYPE.TEXT,
|
|
119
|
+
)
|
|
120
|
+
})
|
|
121
|
+
|
|
122
|
+
it('detects photo', () => {
|
|
123
|
+
const imMessage = { message: { photo: [{}] } }
|
|
124
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
125
|
+
MESSAGE_MEDIA_TYPE.PHOTO,
|
|
126
|
+
)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('detects video', () => {
|
|
130
|
+
const imMessage = { message: { video: {} } }
|
|
131
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
132
|
+
MESSAGE_MEDIA_TYPE.VIDEO,
|
|
133
|
+
)
|
|
134
|
+
})
|
|
135
|
+
|
|
136
|
+
it('detects document', () => {
|
|
137
|
+
const imMessage = { message: { document: {} } }
|
|
138
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
139
|
+
MESSAGE_MEDIA_TYPE.DOCUMENT,
|
|
140
|
+
)
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
it('detects location', () => {
|
|
144
|
+
const imMessage = { message: { location: {} } }
|
|
145
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
146
|
+
MESSAGE_MEDIA_TYPE.LOCATION,
|
|
147
|
+
)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('detects voice', () => {
|
|
151
|
+
const imMessage = { message: { voice: {} } }
|
|
152
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
153
|
+
MESSAGE_MEDIA_TYPE.VOICE,
|
|
154
|
+
)
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
it('detects poll', () => {
|
|
158
|
+
const imMessage = { message: { poll: {} } }
|
|
159
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
160
|
+
MESSAGE_MEDIA_TYPE.POLL,
|
|
161
|
+
)
|
|
162
|
+
})
|
|
163
|
+
|
|
164
|
+
it('detects sticker', () => {
|
|
165
|
+
const imMessage = { message: { sticker: {} } }
|
|
166
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
167
|
+
MESSAGE_MEDIA_TYPE.STICKER,
|
|
168
|
+
)
|
|
169
|
+
})
|
|
170
|
+
|
|
171
|
+
it('detects contact', () => {
|
|
172
|
+
const imMessage = { message: { contact: {} } }
|
|
173
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
174
|
+
MESSAGE_MEDIA_TYPE.CONTACT,
|
|
175
|
+
)
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
it('falls back to UNKNOWN_MESSAGE_TYPE', () => {
|
|
179
|
+
const imMessage = { message: { something_else: 'x' } }
|
|
180
|
+
expect(getTelegramMessageType({ imMessage })).toBe(
|
|
181
|
+
MESSAGE_TYPE.UNKNOWN_MESSAGE_TYPE,
|
|
182
|
+
)
|
|
183
|
+
})
|
|
184
|
+
})
|
|
185
|
+
})
|
|
@@ -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({ imMessage: raw })
|
|
35
|
+
|
|
36
|
+
const unifiedMessage = mapMessageTelegram({
|
|
37
|
+
imMessage: 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({ imMessage: 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({ imMessage: 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({ imMessage: raw })
|
|
34
|
+
|
|
35
|
+
const unifiedMessage = mapMessageWhatsApp({
|
|
36
|
+
imMessage: 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({ imMessage: 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
|
+
}
|