Skip to content

Commit c28f836

Browse files
committed
PresenceMap: only emit a leave if a member was present
per ably/specification#222
1 parent e94ddbd commit c28f836

File tree

3 files changed

+50
-2
lines changed

3 files changed

+50
-2
lines changed

.mocharc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const config = {
99
// if you've defined specs in your config. therefore we work around it by only adding specs to the
1010
// config if none are passed as arguments
1111
if (!process.argv.slice(2).some(isTestFile)) {
12-
config.spec = ['test/realtime/*.test.js', 'test/rest/*.test.js'];
12+
config.spec = ['test/realtime/*.test.js', 'test/rest/*.test.js', 'test/unit/*.test.js'];
1313
}
1414

1515
function isTestFile(arg) {

src/common/lib/client/presencemap.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ export class PresenceMap extends EventEmitter {
125125
delete map[key];
126126
}
127127

128-
return true;
128+
return !!existingItem;
129129
}
130130

131131
startSync() {

test/unit/presencemap.test.js

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
'use strict';
2+
3+
define(['chai', 'ably'], function (chai, Ably) {
4+
const { assert } = chai;
5+
const PresenceMap = Ably.Realtime._PresenceMap;
6+
7+
describe('PresenceMap', () => {
8+
let presenceMap;
9+
10+
// Helper function to create a presence message
11+
const createPresenceMessage = (clientId, connectionId, action, timestamp) => ({
12+
clientId,
13+
connectionId,
14+
timestamp,
15+
action,
16+
});
17+
18+
beforeEach(() => {
19+
// Initialize with a simple memberKey function that uses clientId as the key
20+
presenceMap = new PresenceMap(
21+
null,
22+
(item) => item.clientId + ':' + item.connectionId,
23+
(i, j) => i.timestamp > j.timestamp,
24+
);
25+
});
26+
27+
describe('remove()', () => {
28+
it('should return false when no matching member present', () => {
29+
const incoming = createPresenceMessage('client1', 'conn1', 'leave', 100);
30+
assert.isFalse(presenceMap.remove(incoming));
31+
});
32+
33+
it('should return true when removing an (older) matching member', () => {
34+
const original = createPresenceMessage('client1', 'conn1', 'present', 100);
35+
presenceMap.put(original);
36+
const incoming = createPresenceMessage('client1', 'conn1', 'leave', 150);
37+
assert.isTrue(presenceMap.remove(incoming));
38+
});
39+
40+
it('should return false when trying to remove a newer matching member', () => {
41+
const original = createPresenceMessage('client1', 'conn1', 'present', 100);
42+
presenceMap.put(original);
43+
const incoming = createPresenceMessage('client1', 'conn1', 'leave', 50);
44+
assert.isFalse(presenceMap.remove(incoming));
45+
});
46+
});
47+
});
48+
});

0 commit comments

Comments
 (0)