@flashphoner/sfusdk 1.0.40 → 1.0.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/docTemplate/README.md +1 -1
- package/package.json +6 -3
- package/src/examples/player/player.js +3 -0
- package/src/examples/two-way-streaming/two-way-streaming.js +88 -59
- package/src/sdk/constants.js +28 -2
- package/src/sdk/logger.js +16 -0
- package/src/sdk/room.js +280 -128
- package/src/sdk/sfu-extended.js +341 -11
- package/src/sdk/sfu.js +30 -1
- package/src/sdk/ws.js +4 -0
- package/src/tests/assets/1.jpeg +0 -0
- package/src/tests/lib/rtcaudiosourcesinewave.js +109 -0
- package/src/tests/lib/rtcvideosourcewrapper.js +28 -0
- package/src/tests/sdk/room.test.js +229 -0
- package/src/tests/sdk/sfu-extended.test.js +122 -8
- package/src/tests/sdk/sfu-extended.test.js_ +265 -0
- package/src/tests/util.js +48 -0
- package/src/sdk/messaging.js +0 -59
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
const wrtc = require("wrtc");
|
|
2
|
+
const RTCAudioSourceSineWave = require("../lib/rtcaudiosourcesinewave");
|
|
3
|
+
const RTCVideoSourceWrapper = require("../lib/rtcvideosourcewrapper");
|
|
4
|
+
const sfu = require("../../sdk/sfu-extended");
|
|
5
|
+
const constants = require("../../sdk/constants");
|
|
6
|
+
const {waitForTracks, waitForPeerConnectionStableState, waitForPeerConnectionState} = require("../util");
|
|
7
|
+
|
|
8
|
+
// Jest default timeout
|
|
9
|
+
const JEST_TIMEOUT = 20000;
|
|
10
|
+
|
|
11
|
+
const SERVER = "ws://127.0.0.1:8080";
|
|
12
|
+
const USER_BOB = "bob@flashphoner.com";
|
|
13
|
+
const BOB_NICKNAME = "bob";
|
|
14
|
+
const USER_ALICE = "alice@flashphoner.com";
|
|
15
|
+
const ALICE_NICKNAME = "alice";
|
|
16
|
+
const PASSWD = "123456";
|
|
17
|
+
|
|
18
|
+
const ROOM_NAME = "TEST_ROOM";
|
|
19
|
+
const PIN = "1234";
|
|
20
|
+
const USE_WAITING_ROOM = true;
|
|
21
|
+
|
|
22
|
+
let sfu2;
|
|
23
|
+
|
|
24
|
+
jest.setTimeout(JEST_TIMEOUT);
|
|
25
|
+
jest.isolateModules(() => {
|
|
26
|
+
sfu2 = require("../../sdk/sfu-extended");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
function stopAfterTimeout(done) {
|
|
30
|
+
console.log("Test ended");
|
|
31
|
+
setTimeout(done, 5000);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
beforeAll(async () => {
|
|
35
|
+
await sfu.connect({
|
|
36
|
+
url: SERVER,
|
|
37
|
+
username: USER_BOB,
|
|
38
|
+
password: PASSWD
|
|
39
|
+
});
|
|
40
|
+
await sfu2.connect({
|
|
41
|
+
url: SERVER,
|
|
42
|
+
username: USER_ALICE,
|
|
43
|
+
password: PASSWD
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
afterAll(async () => {
|
|
48
|
+
await sfu2.disconnect();
|
|
49
|
+
await sfu.disconnect();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("room", () => {
|
|
53
|
+
it("should create new room", async () => {
|
|
54
|
+
const room = sfu.room({
|
|
55
|
+
name: ROOM_NAME,
|
|
56
|
+
pin: PIN,
|
|
57
|
+
pc: new wrtc.RTCPeerConnection()
|
|
58
|
+
});
|
|
59
|
+
const ret = await room.createRoom();
|
|
60
|
+
expect(ret).toBeTruthy();
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("should join the room", async () => {
|
|
64
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
65
|
+
const ret = await room.join();
|
|
66
|
+
expect(ret).toBeTruthy();
|
|
67
|
+
await waitForPeerConnectionStableState(room.pc());
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it("should configure waiting room", async () => {
|
|
71
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
72
|
+
await room.configureWaitingRoom(USE_WAITING_ROOM);
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
describe("second participant", () => {
|
|
76
|
+
it("should be successfully authorized and joined to the room", async (done) => {
|
|
77
|
+
console.log("should be successfully authorized and joined to the room");
|
|
78
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
79
|
+
const waitingListHandler = async (event) => {
|
|
80
|
+
if (event.users && event.users.length !== 0) {
|
|
81
|
+
const users = event.users;
|
|
82
|
+
for (const waitingUser of users) {
|
|
83
|
+
const info = await room.subscribeToWaitingParticipant(waitingUser.nickname);
|
|
84
|
+
expect(info).toBeTruthy();
|
|
85
|
+
expect(Array.isArray(info.info)).toBeTruthy();
|
|
86
|
+
expect(info.info.length).toEqual(1);
|
|
87
|
+
await waitForTracks(room.pc(), info.info);
|
|
88
|
+
await room.unsubscribeFromWaitingParticipant(waitingUser.nickname);
|
|
89
|
+
await room.authorizeWaitingList(waitingUser.id, true);
|
|
90
|
+
await waitForPeerConnectionStableState(room.pc());
|
|
91
|
+
}
|
|
92
|
+
room.off(sfu.constants.SFU_ROOM_EVENT.WAITING_LIST, waitingListHandler);
|
|
93
|
+
done();
|
|
94
|
+
}
|
|
95
|
+
};
|
|
96
|
+
room.on(sfu.constants.SFU_ROOM_EVENT.WAITING_LIST, waitingListHandler);
|
|
97
|
+
const room2 = sfu2.room({
|
|
98
|
+
name: ROOM_NAME,
|
|
99
|
+
pin: PIN,
|
|
100
|
+
pc: new wrtc.RTCPeerConnection()
|
|
101
|
+
});
|
|
102
|
+
// Audio track
|
|
103
|
+
const aSource = new RTCAudioSourceSineWave();
|
|
104
|
+
const aTrack = aSource.createTrack();
|
|
105
|
+
const aSender = room2.pc().addTrack(aTrack);
|
|
106
|
+
|
|
107
|
+
const ret = await room2.join({});
|
|
108
|
+
expect(ret).toBeTruthy();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("should set new role for the second participant", async () => {
|
|
112
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
113
|
+
await room.assignRole(ALICE_NICKNAME, sfu.constants.SFU_PARTICIPANT_ROLE.ADMIN);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it("should be able to send message", async () => {
|
|
117
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
118
|
+
await room.sendMessage("should be able to send message");
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it("should be able to send message more then 16384 characters long", async () => {
|
|
122
|
+
const messageLength = 20000;
|
|
123
|
+
const letter = "a";
|
|
124
|
+
let msg = "";
|
|
125
|
+
for (let i = 0; i < messageLength; i++) {
|
|
126
|
+
msg += letter;
|
|
127
|
+
}
|
|
128
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
129
|
+
await room.sendMessage(msg);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("should receive message", async (done) => {
|
|
133
|
+
const msg = "should receive message";
|
|
134
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
135
|
+
const room2 = sfu2.getRoom({name: ROOM_NAME});
|
|
136
|
+
const messageHandler = (message) => {
|
|
137
|
+
expect(message).toBeTruthy();
|
|
138
|
+
expect(message.message).toEqual(msg);
|
|
139
|
+
room2.off(sfu.constants.SFU_ROOM_EVENT.MESSAGE, messageHandler);
|
|
140
|
+
done();
|
|
141
|
+
}
|
|
142
|
+
room2.on(sfu.constants.SFU_ROOM_EVENT.MESSAGE, messageHandler);
|
|
143
|
+
room.sendMessage(msg);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("should receive message more then 16384 characters long", async (done) => {
|
|
147
|
+
const messageLength = 20000;
|
|
148
|
+
const letter = "a";
|
|
149
|
+
let msg = "";
|
|
150
|
+
for (let i = 0; i < messageLength; i++) {
|
|
151
|
+
msg += letter;
|
|
152
|
+
}
|
|
153
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
154
|
+
const room2 = sfu2.getRoom({name: ROOM_NAME});
|
|
155
|
+
const messageHandler = (message) => {
|
|
156
|
+
expect(message).toBeTruthy();
|
|
157
|
+
expect(message.message).toEqual(msg);
|
|
158
|
+
room.off(sfu.constants.SFU_ROOM_EVENT.MESSAGE, messageHandler);
|
|
159
|
+
done();
|
|
160
|
+
}
|
|
161
|
+
room.on(sfu.constants.SFU_ROOM_EVENT.MESSAGE, messageHandler);
|
|
162
|
+
room2.sendMessage(msg);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it("should leave the room", async () => {
|
|
166
|
+
const room2 = sfu2.getRoom({name: ROOM_NAME});
|
|
167
|
+
await room2.leaveRoom();
|
|
168
|
+
await waitForPeerConnectionState(room2.pc(), "closed");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("the owner should be able to move it to the waiting room", async (done) => {
|
|
172
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
173
|
+
room.on(sfu.constants.SFU_ROOM_EVENT.JOINED, async (participant) => {
|
|
174
|
+
await room.moveToWaitingRoom(participant.name);
|
|
175
|
+
done();
|
|
176
|
+
});
|
|
177
|
+
await room.configureWaitingRoom(false);
|
|
178
|
+
const room2 = sfu2.room({
|
|
179
|
+
name: ROOM_NAME,
|
|
180
|
+
pin: PIN,
|
|
181
|
+
pc: new wrtc.RTCPeerConnection()
|
|
182
|
+
});
|
|
183
|
+
await room2.join({});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it("should update room state", async () => {
|
|
188
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
189
|
+
// Audio track
|
|
190
|
+
const aSource = new RTCAudioSourceSineWave();
|
|
191
|
+
const aTrack = aSource.createTrack();
|
|
192
|
+
const aSender = room.pc().addTrack(aTrack);
|
|
193
|
+
// Video track
|
|
194
|
+
const vSource = new RTCVideoSourceWrapper();
|
|
195
|
+
const vTrack = vSource.createTrack();
|
|
196
|
+
const vSender = room.pc().addTrack(vTrack);
|
|
197
|
+
|
|
198
|
+
await room.updateState({});
|
|
199
|
+
await waitForPeerConnectionStableState(room.pc());
|
|
200
|
+
aTrack.stop();
|
|
201
|
+
aSource.close();
|
|
202
|
+
vTrack.stop();
|
|
203
|
+
room.pc().removeTrack(aSender);
|
|
204
|
+
room.pc().removeTrack(vSender);
|
|
205
|
+
await room.updateState();
|
|
206
|
+
await waitForPeerConnectionStableState(room.pc());
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("should leave room", async () => {
|
|
210
|
+
const room = sfu.getRoom({name: ROOM_NAME});
|
|
211
|
+
const ret = await room.leaveRoom();
|
|
212
|
+
expect(ret).toBeTruthy();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("should destroy room", async (done) => {
|
|
216
|
+
const room = sfu.room({
|
|
217
|
+
name: ROOM_NAME,
|
|
218
|
+
pin: PIN,
|
|
219
|
+
pc: new wrtc.RTCPeerConnection()
|
|
220
|
+
});
|
|
221
|
+
room.on(constants.SFU_ROOM_EVENT.EVICTED, () => {
|
|
222
|
+
expect(sfu.getRoom({name: ROOM_NAME})).toBeFalsy();
|
|
223
|
+
done();
|
|
224
|
+
});
|
|
225
|
+
await room.createRoom();
|
|
226
|
+
await room.join();
|
|
227
|
+
await room.destroyRoom();
|
|
228
|
+
});
|
|
229
|
+
});
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
1
3
|
const sfu = require("../../sdk/sfu-extended");
|
|
2
4
|
const constants = require("../../sdk/constants");
|
|
3
5
|
|
|
@@ -5,6 +7,8 @@ const SERVER = "ws://127.0.0.1:8080";
|
|
|
5
7
|
const USER = "bob@flashphoner.com";
|
|
6
8
|
const PASSWD = "123456";
|
|
7
9
|
const CHAT_ID = "test-chat-id";
|
|
10
|
+
const CHANNEL_ID = "test-channel-id";
|
|
11
|
+
const CHANNEL_NAME = "test-channel";
|
|
8
12
|
const CHAT_NAME = "test-chat";
|
|
9
13
|
const CHAT_NAME2 = "test-chat2";
|
|
10
14
|
const USER2 = "alice@flashphoner.com";
|
|
@@ -14,6 +18,11 @@ const MEMBERS = [
|
|
|
14
18
|
"alice@flashphoner.com",
|
|
15
19
|
"kiri@flashphoner.com"
|
|
16
20
|
];
|
|
21
|
+
const FILE = "../assets/1.jpeg";
|
|
22
|
+
|
|
23
|
+
jest.isolateModules(() => {
|
|
24
|
+
sfu2 = require("../../sdk/sfu-extended");
|
|
25
|
+
});
|
|
17
26
|
|
|
18
27
|
beforeAll( async () => {
|
|
19
28
|
await sfu.connect({
|
|
@@ -27,10 +36,16 @@ beforeAll( async () => {
|
|
|
27
36
|
await sfu.deleteChat({id: value.id});
|
|
28
37
|
});
|
|
29
38
|
}
|
|
39
|
+
await sfu2.connect({
|
|
40
|
+
url: SERVER,
|
|
41
|
+
username: USER2,
|
|
42
|
+
password: PASSWD
|
|
43
|
+
});
|
|
30
44
|
});
|
|
31
45
|
|
|
32
|
-
afterAll(() => {
|
|
33
|
-
|
|
46
|
+
afterAll(async () => {
|
|
47
|
+
await sfu.disconnect();
|
|
48
|
+
await sfu2.disconnect();
|
|
34
49
|
});
|
|
35
50
|
|
|
36
51
|
|
|
@@ -61,6 +76,36 @@ describe("chat", () => {
|
|
|
61
76
|
name: CHAT_NAME
|
|
62
77
|
});
|
|
63
78
|
});
|
|
79
|
+
describe("channels", () => {
|
|
80
|
+
test("should create new channel", () => {
|
|
81
|
+
return sfu.createChat({
|
|
82
|
+
id: CHANNEL_ID,
|
|
83
|
+
name: CHANNEL_NAME,
|
|
84
|
+
members: [USER2],
|
|
85
|
+
channel: true,
|
|
86
|
+
channelType: "PUBLIC",
|
|
87
|
+
channelSendPolicy: "ADMIN_AND_LIST",
|
|
88
|
+
sendPermissionList: [USER2]
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
test("should load public channels", async () => {
|
|
92
|
+
const channels = await sfu.getPublicChannels();
|
|
93
|
+
expect(channels).toBeTruthy();
|
|
94
|
+
expect(channels).toHaveProperty(CHANNEL_ID);
|
|
95
|
+
});
|
|
96
|
+
test("channel should appear in loaded chats", async () => {
|
|
97
|
+
const chats = await sfu.getUserChats();
|
|
98
|
+
expect(chats).toBeTruthy();
|
|
99
|
+
expect(chats).toHaveProperty(CHANNEL_ID);
|
|
100
|
+
});
|
|
101
|
+
test("should load channel", async () => {
|
|
102
|
+
const chat = await sfu.loadChat({id: CHANNEL_ID});
|
|
103
|
+
expect(chat.id).toBe(CHANNEL_ID);
|
|
104
|
+
expect(chat.name).toBe(CHANNEL_NAME);
|
|
105
|
+
expect(chat.members).toContain(USER);
|
|
106
|
+
expect(chat.channel).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
64
109
|
test("should load chats", () => {
|
|
65
110
|
return sfu.getUserChats().then((chats) => {
|
|
66
111
|
expect(chats).toBeTruthy();
|
|
@@ -76,7 +121,47 @@ describe("chat", () => {
|
|
|
76
121
|
return sfu.sendMessage({
|
|
77
122
|
chatId: CHAT_ID,
|
|
78
123
|
body: MESSAGE_BODY
|
|
79
|
-
})
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
test("should send message with attachment", () => {
|
|
127
|
+
const file = fs.readFileSync(path.resolve(__dirname, FILE));
|
|
128
|
+
let byteArray = new Uint8Array(file);
|
|
129
|
+
let base64Content = Buffer.from(byteArray).toString('base64');
|
|
130
|
+
return sfu.sendMessage({
|
|
131
|
+
chatId: CHAT_ID,
|
|
132
|
+
body: MESSAGE_BODY,
|
|
133
|
+
attachments: [
|
|
134
|
+
{
|
|
135
|
+
type: "file",
|
|
136
|
+
name: FILE,
|
|
137
|
+
payload: base64Content,
|
|
138
|
+
size: byteArray.length
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
test("should mark message as read", async () => {
|
|
144
|
+
const msg = await sfu.sendMessage({
|
|
145
|
+
chatId: CHAT_ID,
|
|
146
|
+
body: MESSAGE_BODY
|
|
147
|
+
});
|
|
148
|
+
const freshState = await sfu.markMessageRead(msg);
|
|
149
|
+
expect(freshState.lastReadMessageId).toBeTruthy();
|
|
150
|
+
expect(freshState).toBeTruthy();
|
|
151
|
+
});
|
|
152
|
+
test("should mark message as unread", async () => {
|
|
153
|
+
const msg1 = await sfu.sendMessage({
|
|
154
|
+
chatId: CHAT_ID,
|
|
155
|
+
body: MESSAGE_BODY
|
|
156
|
+
});
|
|
157
|
+
const msg2 = await sfu.sendMessage({
|
|
158
|
+
chatId: CHAT_ID,
|
|
159
|
+
body: MESSAGE_BODY
|
|
160
|
+
});
|
|
161
|
+
const freshState = await sfu.markMessageUnread(msg2);
|
|
162
|
+
expect(freshState).toBeTruthy();
|
|
163
|
+
expect(freshState.lastReadMessageId).toBeTruthy();
|
|
164
|
+
expect(freshState.lastReadMessageId).toEqual(msg1.id);
|
|
80
165
|
});
|
|
81
166
|
test("should load chat", () => {
|
|
82
167
|
return sfu.loadChat({
|
|
@@ -101,6 +186,35 @@ describe("chat", () => {
|
|
|
101
186
|
name: CHAT_NAME2
|
|
102
187
|
});
|
|
103
188
|
});
|
|
189
|
+
test("should invite contact", async () => {
|
|
190
|
+
const contact = await sfu.inviteContact({
|
|
191
|
+
to: USER2
|
|
192
|
+
});
|
|
193
|
+
expect(contact).toBeTruthy();
|
|
194
|
+
expect(contact.invite).toBeTruthy();
|
|
195
|
+
expect(contact.invite.id).toBeTruthy();
|
|
196
|
+
});
|
|
197
|
+
test("should confirm invite", async () => {
|
|
198
|
+
const contacts = await sfu2.getUserList();
|
|
199
|
+
let unconfirmedContact;
|
|
200
|
+
contacts.every((contact) => {
|
|
201
|
+
if (contact.invite && contact.invite.from !== USER2) {
|
|
202
|
+
unconfirmedContact = contact;
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
});
|
|
207
|
+
expect(unconfirmedContact).toBeTruthy();
|
|
208
|
+
const contact = await sfu2.confirmContact(unconfirmedContact.invite);
|
|
209
|
+
expect(contact).toBeTruthy();
|
|
210
|
+
expect(contact.confirmed).toEqual(true);
|
|
211
|
+
});
|
|
212
|
+
test("should remove contact", async () => {
|
|
213
|
+
const contact = await sfu.removeContact({
|
|
214
|
+
id: USER2
|
|
215
|
+
});
|
|
216
|
+
expect(contact).toBeTruthy();
|
|
217
|
+
});
|
|
104
218
|
test.skip("should receive message", (done) => {
|
|
105
219
|
sfu.on(constants.SFU_EVENT.MESSAGE, (msg) => {
|
|
106
220
|
done();
|
|
@@ -110,14 +224,14 @@ describe("chat", () => {
|
|
|
110
224
|
body: MESSAGE_BODY
|
|
111
225
|
});
|
|
112
226
|
});
|
|
113
|
-
test("should receive ACK message", (
|
|
114
|
-
sfu.
|
|
115
|
-
done();
|
|
116
|
-
})
|
|
117
|
-
sfu.sendMessage({
|
|
227
|
+
test("should receive ACK message", async () => {
|
|
228
|
+
const msg = await sfu.sendMessage({
|
|
118
229
|
chatId: CHAT_ID,
|
|
119
230
|
body: MESSAGE_BODY
|
|
120
231
|
});
|
|
232
|
+
expect(msg).toBeTruthy();
|
|
233
|
+
expect(msg.id).toBeTruthy();
|
|
234
|
+
expect(msg.date).toBeTruthy();
|
|
121
235
|
});
|
|
122
236
|
test("should create new chat without id", () => {
|
|
123
237
|
return sfu.createChat({
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const sfu = require("../../sdk/sfu-extended");
|
|
4
|
+
const constants = require("../../sdk/constants");
|
|
5
|
+
|
|
6
|
+
const SERVER = "ws://127.0.0.1:8080";
|
|
7
|
+
const USER = "bob@flashphoner.com";
|
|
8
|
+
const PASSWD = "123456";
|
|
9
|
+
const CHAT_ID = "test-chat-id";
|
|
10
|
+
const CHANNEL_ID = "test-channel-id";
|
|
11
|
+
const CHANNEL_NAME = "test-channel";
|
|
12
|
+
const CHAT_NAME = "test-chat";
|
|
13
|
+
const CHAT_NAME2 = "test-chat2";
|
|
14
|
+
const USER2 = "alice@flashphoner.com";
|
|
15
|
+
const MESSAGE_BODY = "This is a test message";
|
|
16
|
+
const MEMBERS = [
|
|
17
|
+
"bob@flashphoner.com",
|
|
18
|
+
"alice@flashphoner.com",
|
|
19
|
+
"kiri@flashphoner.com"
|
|
20
|
+
];
|
|
21
|
+
const FILE = "../assets/1.jpeg";
|
|
22
|
+
|
|
23
|
+
jest.isolateModules(() => {
|
|
24
|
+
sfu2 = require("../../sdk/sfu-extended");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
beforeAll( async () => {
|
|
28
|
+
await sfu.connect({
|
|
29
|
+
url: SERVER,
|
|
30
|
+
username: USER,
|
|
31
|
+
password: PASSWD
|
|
32
|
+
});
|
|
33
|
+
const chats = await sfu.getUserChats();
|
|
34
|
+
if (chats) {
|
|
35
|
+
Object.entries(chats).map(async ([key, value]) => {
|
|
36
|
+
await sfu.deleteChat({id: value.id});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
await sfu2.connect({
|
|
40
|
+
url: SERVER,
|
|
41
|
+
username: USER2,
|
|
42
|
+
password: PASSWD
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
afterAll(async () => {
|
|
47
|
+
await sfu.disconnect();
|
|
48
|
+
await sfu2.disconnect();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
describe("connection", () => {
|
|
53
|
+
test("should connect to server", () => {
|
|
54
|
+
expect(sfu.state()).toBe(constants.SFU_STATE.AUTHENTICATED);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
describe("contacts", () => {
|
|
59
|
+
test("should load user list", () => {
|
|
60
|
+
return sfu.getUserList();
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("calendar", () => {
|
|
65
|
+
test("should load calendar", () => {
|
|
66
|
+
return sfu.getUserCalendar().then((calendar) => {
|
|
67
|
+
expect(calendar).toHaveProperty("events");
|
|
68
|
+
})
|
|
69
|
+
})
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe("chat", () => {
|
|
73
|
+
test("should create new chat", () => {
|
|
74
|
+
return sfu.createChat({
|
|
75
|
+
id: CHAT_ID,
|
|
76
|
+
name: CHAT_NAME
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe("channels", () => {
|
|
80
|
+
test("should create new channel", () => {
|
|
81
|
+
return sfu.createChat({
|
|
82
|
+
id: CHANNEL_ID,
|
|
83
|
+
name: CHANNEL_NAME,
|
|
84
|
+
members: [USER2],
|
|
85
|
+
channel: true,
|
|
86
|
+
channelType: "PUBLIC",
|
|
87
|
+
channelSendPolicy: "ADMIN_AND_LIST",
|
|
88
|
+
sendPermissionList: [USER2]
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
test("should load public channels", async () => {
|
|
92
|
+
const channels = await sfu.getPublicChannels();
|
|
93
|
+
expect(channels).toBeTruthy();
|
|
94
|
+
expect(channels).toHaveProperty(CHANNEL_ID);
|
|
95
|
+
});
|
|
96
|
+
test("channel should appear in loaded chats", async () => {
|
|
97
|
+
const chats = await sfu.getUserChats();
|
|
98
|
+
expect(chats).toBeTruthy();
|
|
99
|
+
expect(chats).toHaveProperty(CHANNEL_ID);
|
|
100
|
+
});
|
|
101
|
+
test("should load channel", async () => {
|
|
102
|
+
const chat = await sfu.loadChat({id: CHANNEL_ID});
|
|
103
|
+
expect(chat.id).toBe(CHANNEL_ID);
|
|
104
|
+
expect(chat.name).toBe(CHANNEL_NAME);
|
|
105
|
+
expect(chat.members).toContain(USER);
|
|
106
|
+
expect(chat.channel).toBe(true);
|
|
107
|
+
});
|
|
108
|
+
});
|
|
109
|
+
test("should load chats", () => {
|
|
110
|
+
return sfu.getUserChats().then((chats) => {
|
|
111
|
+
expect(chats).toBeTruthy();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
test("should add new member", () => {
|
|
115
|
+
return sfu.addMemberToChat({
|
|
116
|
+
id: CHAT_ID,
|
|
117
|
+
member: USER2
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
test("should send a message", () => {
|
|
121
|
+
return sfu.sendMessage({
|
|
122
|
+
chatId: CHAT_ID,
|
|
123
|
+
body: MESSAGE_BODY
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
test("should send message with attachment", () => {
|
|
127
|
+
const file = fs.readFileSync(path.resolve(__dirname, FILE));
|
|
128
|
+
let byteArray = new Uint8Array(file);
|
|
129
|
+
let base64Content = Buffer.from(byteArray).toString('base64');
|
|
130
|
+
return sfu.sendMessage({
|
|
131
|
+
chatId: CHAT_ID,
|
|
132
|
+
body: MESSAGE_BODY,
|
|
133
|
+
attachments: [
|
|
134
|
+
{
|
|
135
|
+
type: "file",
|
|
136
|
+
name: FILE,
|
|
137
|
+
payload: base64Content,
|
|
138
|
+
size: byteArray.length
|
|
139
|
+
}
|
|
140
|
+
]
|
|
141
|
+
});
|
|
142
|
+
});
|
|
143
|
+
test("should mark message as read", async () => {
|
|
144
|
+
const msg = await sfu.sendMessage({
|
|
145
|
+
chatId: CHAT_ID,
|
|
146
|
+
body: MESSAGE_BODY
|
|
147
|
+
});
|
|
148
|
+
const freshState = await sfu.markMessageRead(msg);
|
|
149
|
+
expect(freshState.lastReadMessageId).toBeTruthy();
|
|
150
|
+
expect(freshState).toBeTruthy();
|
|
151
|
+
});
|
|
152
|
+
test("should mark message as unread", async () => {
|
|
153
|
+
const msg1 = await sfu.sendMessage({
|
|
154
|
+
chatId: CHAT_ID,
|
|
155
|
+
body: MESSAGE_BODY
|
|
156
|
+
});
|
|
157
|
+
const msg2 = await sfu.sendMessage({
|
|
158
|
+
chatId: CHAT_ID,
|
|
159
|
+
body: MESSAGE_BODY
|
|
160
|
+
});
|
|
161
|
+
const freshState = await sfu.markMessageUnread(msg2);
|
|
162
|
+
expect(freshState).toBeTruthy();
|
|
163
|
+
expect(freshState.lastReadMessageId).toBeTruthy();
|
|
164
|
+
expect(freshState.lastReadMessageId).toEqual(msg1.id);
|
|
165
|
+
});
|
|
166
|
+
test("should load chat", () => {
|
|
167
|
+
return sfu.loadChat({
|
|
168
|
+
id: CHAT_ID
|
|
169
|
+
}).then((chat) => {
|
|
170
|
+
expect(chat.id).toBe(CHAT_ID);
|
|
171
|
+
expect(chat.name).toBe(CHAT_NAME);
|
|
172
|
+
expect(chat.members).toContain(USER);
|
|
173
|
+
expect(Array.isArray(chat.messages)).toBe(true);
|
|
174
|
+
expect(chat.messages.length).toBeGreaterThan(0);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
test("should remove member", () => {
|
|
178
|
+
return sfu.removeMemberFromChat({
|
|
179
|
+
id: CHAT_ID,
|
|
180
|
+
member: USER2
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
test("should rename chat", () => {
|
|
184
|
+
return sfu.renameChat({
|
|
185
|
+
id: CHAT_ID,
|
|
186
|
+
name: CHAT_NAME2
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
test("should invite contact", async () => {
|
|
190
|
+
const contact = await sfu.inviteContact({
|
|
191
|
+
to: USER2
|
|
192
|
+
});
|
|
193
|
+
expect(contact).toBeTruthy();
|
|
194
|
+
expect(contact.invite).toBeTruthy();
|
|
195
|
+
expect(contact.invite.id).toBeTruthy();
|
|
196
|
+
});
|
|
197
|
+
test("should confirm invite", async () => {
|
|
198
|
+
const contacts = await sfu2.getUserList();
|
|
199
|
+
let unconfirmedContact;
|
|
200
|
+
contacts.every((contact) => {
|
|
201
|
+
if (contact.invite && contact.invite.from !== USER2) {
|
|
202
|
+
unconfirmedContact = contact;
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
return true;
|
|
206
|
+
});
|
|
207
|
+
expect(unconfirmedContact).toBeTruthy();
|
|
208
|
+
const contact = await sfu2.confirmContact(unconfirmedContact.invite);
|
|
209
|
+
expect(contact).toBeTruthy();
|
|
210
|
+
expect(contact.confirmed).toEqual(true);
|
|
211
|
+
});
|
|
212
|
+
test("should remove contact", async () => {
|
|
213
|
+
const contact = await sfu.removeContact({
|
|
214
|
+
id: USER2
|
|
215
|
+
});
|
|
216
|
+
expect(contact).toBeTruthy();
|
|
217
|
+
});
|
|
218
|
+
test.skip("should receive message", (done) => {
|
|
219
|
+
sfu.on(constants.SFU_EVENT.MESSAGE, (msg) => {
|
|
220
|
+
done();
|
|
221
|
+
})
|
|
222
|
+
sfu.sendMessage({
|
|
223
|
+
chatId: CHAT_ID,
|
|
224
|
+
body: MESSAGE_BODY
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
test("should receive ACK message", async () => {
|
|
228
|
+
const msg = await sfu.sendMessage({
|
|
229
|
+
chatId: CHAT_ID,
|
|
230
|
+
body: MESSAGE_BODY
|
|
231
|
+
});
|
|
232
|
+
expect(msg).toBeTruthy();
|
|
233
|
+
expect(msg.id).toBeTruthy();
|
|
234
|
+
expect(msg.date).toBeTruthy();
|
|
235
|
+
});
|
|
236
|
+
test("should create new chat without id", () => {
|
|
237
|
+
return sfu.createChat({
|
|
238
|
+
name: CHAT_NAME
|
|
239
|
+
});
|
|
240
|
+
});
|
|
241
|
+
test("should create new chat with member list", () => {
|
|
242
|
+
return sfu.createChat({
|
|
243
|
+
name: CHAT_NAME,
|
|
244
|
+
members: MEMBERS
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
test("should create new chat without name based on members", async () => {
|
|
248
|
+
const chat = await sfu.createChat({
|
|
249
|
+
members: MEMBERS
|
|
250
|
+
});
|
|
251
|
+
expect(chat.name).toBeTruthy();
|
|
252
|
+
});
|
|
253
|
+
test("should delete chat", () => {
|
|
254
|
+
return sfu.deleteChat({
|
|
255
|
+
id: CHAT_ID
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
test("should change name after member was added", async () => {
|
|
259
|
+
const chat = await sfu.createChat({});
|
|
260
|
+
expect(chat.name).toBeTruthy();
|
|
261
|
+
const name1 = chat.name;
|
|
262
|
+
const sameChat = await sfu.addMemberToChat({id: chat.id, member: USER2});
|
|
263
|
+
expect(sameChat.name !== name1).toBeTruthy();
|
|
264
|
+
});
|
|
265
|
+
});
|