@sockethub/client 5.0.0-alpha.11 → 5.0.0-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sockethub/client",
3
- "version": "5.0.0-alpha.11",
3
+ "version": "5.0.0-alpha.12",
4
4
  "description": "A JavaScript client for the Sockethub protocol gateway",
5
5
  "main": "./dist/sockethub-client.js",
6
6
  "exports": {
@@ -47,11 +47,11 @@
47
47
  "test:browser": "wtr dist/**/*.test.js --node-resolve --puppeteer"
48
48
  },
49
49
  "dependencies": {
50
+ "@sockethub/activity-streams": "^4.4.0-alpha.12",
51
+ "@sockethub/schemas": "^3.0.0-alpha.12",
50
52
  "eventemitter3": "^5.0.4"
51
53
  },
52
54
  "devDependencies": {
53
- "@sockethub/activity-streams": "^4.4.0-alpha.11",
54
- "@sockethub/schemas": "^3.0.0-alpha.11",
55
55
  "@types/bun": "latest",
56
56
  "@types/sinon": "^17.0.4",
57
57
  "@web/test-runner": "^0.19.0",
@@ -59,5 +59,5 @@
59
59
  "sinon": "^17.0.2",
60
60
  "socket.io-client": "^4.8.3"
61
61
  },
62
- "gitHead": "c243fa9e76c688ce5ffcf524400b1dd27dcce615"
62
+ "gitHead": "f039dab3c3f67cbbf204476fc397532e973f82a8"
63
63
  }
@@ -5,6 +5,40 @@ import { createSandbox, restore } from "sinon";
5
5
 
6
6
  import SockethubClient from "./sockethub-client";
7
7
 
8
+ const TEST_REGISTRY = {
9
+ version: "5.0.0-alpha.11",
10
+ contexts: {
11
+ as: "https://example.com/as2",
12
+ sockethub: "https://example.com/sh",
13
+ },
14
+ platforms: [
15
+ {
16
+ id: "xmpp",
17
+ version: "1.0.0",
18
+ contextUrl: "https://example.com/context/platform/xmpp/v9.jsonld",
19
+ contextVersion: "9",
20
+ schemaVersion: "9",
21
+ types: ["connect", "send", "join", "leave", "disconnect"],
22
+ schemas: {
23
+ messages: {},
24
+ credentials: {},
25
+ },
26
+ },
27
+ {
28
+ id: "dummy",
29
+ version: "1.0.0",
30
+ contextUrl: "https://example.com/context/platform/dummy/v1.jsonld",
31
+ contextVersion: "1",
32
+ schemaVersion: "1",
33
+ types: ["echo"],
34
+ schemas: {
35
+ messages: {},
36
+ credentials: {},
37
+ },
38
+ },
39
+ ],
40
+ };
41
+
8
42
  describe("SockethubClient bad initialization", () => {
9
43
  it("no socket.io instance", () => {
10
44
  class TestSockethubClient extends SockethubClient {
@@ -33,7 +67,22 @@ describe("SockethubClient", () => {
33
67
  asInstance = new EventEmitter();
34
68
  sandbox.spy(asInstance, "on");
35
69
  sandbox.spy(asInstance, "emit");
36
- asInstance.Stream = sandbox.stub().returnsArg(0);
70
+ asInstance.Stream = sandbox.stub().callsFake((stream: any) => {
71
+ if (!stream || typeof stream !== "object") {
72
+ return stream;
73
+ }
74
+ const next = { ...stream };
75
+ if (typeof next.actor === "string") {
76
+ next.actor = { id: next.actor };
77
+ }
78
+ if (typeof next.target === "string") {
79
+ next.target = { id: next.target };
80
+ }
81
+ if (typeof next.object === "string") {
82
+ next.object = { content: next.object };
83
+ }
84
+ return next;
85
+ });
37
86
  asInstance.Object = {
38
87
  create: sandbox.stub(),
39
88
  };
@@ -73,12 +122,163 @@ describe("SockethubClient", () => {
73
122
  });
74
123
 
75
124
  it("registers a listeners for socket events", () => {
76
- expect(socket.on.callCount).to.equal(5);
125
+ expect(socket.on.callCount).to.equal(6);
77
126
  expect(socket.on.calledWithMatch("activity-object")).to.be.true;
78
127
  expect(socket.on.calledWithMatch("connect")).to.be.true;
79
128
  expect(socket.on.calledWithMatch("connect_error")).to.be.true;
80
129
  expect(socket.on.calledWithMatch("disconnect")).to.be.true;
81
130
  expect(socket.on.calledWithMatch("message")).to.be.true;
131
+ expect(socket.on.calledWithMatch("schemas")).to.be.true;
132
+ });
133
+
134
+ describe("contextFor", () => {
135
+ it("tracks schema readiness", () => {
136
+ expect(sc.isSchemasReady()).to.equal(false);
137
+ socket.emit("schemas", TEST_REGISTRY);
138
+ expect(sc.isSchemasReady()).to.equal(true);
139
+ });
140
+
141
+ it("waitForSchemas resolves once registry arrives", async () => {
142
+ socket.io = {};
143
+ socket.connected = true;
144
+ sc.socket.connected = true;
145
+ socket.on("schemas", (ack: any) => {
146
+ if (typeof ack === "function") {
147
+ ack(TEST_REGISTRY);
148
+ }
149
+ });
150
+ const registry = await sc.waitForSchemas();
151
+ expect(registry.contexts).to.eql({
152
+ as: "https://example.com/as2",
153
+ sockethub: "https://example.com/sh",
154
+ });
155
+ expect(registry.platforms?.[0]?.id).to.equal("xmpp");
156
+ });
157
+
158
+ it("throws before schema registry is loaded", () => {
159
+ expect(() => sc.contextFor("xmpp")).to.throw(
160
+ "Schema registry not loaded yet",
161
+ );
162
+ });
163
+
164
+ it("throws when platform is missing", () => {
165
+ expect(() => sc.contextFor("")).to.throw(
166
+ "requires a non-empty platform string",
167
+ );
168
+ });
169
+
170
+ it("uses server-provided contexts and platform context URL", () => {
171
+ socket.emit("schemas", TEST_REGISTRY);
172
+
173
+ expect(sc.contextFor("xmpp")).to.eql([
174
+ "https://example.com/as2",
175
+ "https://example.com/sh",
176
+ "https://example.com/context/platform/xmpp/v9.jsonld",
177
+ ]);
178
+ });
179
+
180
+ it("throws for unknown platform when registry is loaded", () => {
181
+ socket.emit("schemas", TEST_REGISTRY);
182
+
183
+ expect(() => sc.contextFor("irc")).to.throw(
184
+ "unknown platform 'irc'",
185
+ );
186
+ });
187
+ });
188
+
189
+ describe("initialization API", () => {
190
+ it("ready() resolves with ClientReadyInfo after server emits schemas", async () => {
191
+ socket.io = {};
192
+ socket.connected = true;
193
+ sc.socket.connected = true;
194
+ socket.on("schemas", (ack: any) => {
195
+ if (typeof ack === "function") {
196
+ ack(TEST_REGISTRY);
197
+ }
198
+ });
199
+ const info = await sc.ready(2000);
200
+ expect(info.state).to.equal("ready");
201
+ expect(info.reason).to.be.a("string");
202
+ expect(info.sockethubVersion).to.equal("5.0.0-alpha.11");
203
+ expect(info.platforms).to.be.an("array").with.length.greaterThan(0);
204
+ expect(info.contexts.as).to.equal("https://example.com/as2");
205
+ });
206
+
207
+ it("ready() resolves immediately when already ready", async () => {
208
+ socket.emit("schemas", TEST_REGISTRY);
209
+ const info = await sc.ready();
210
+ expect(info.state).to.equal("ready");
211
+ });
212
+
213
+ it("ready() rejects on timeout when schemas never arrive", async () => {
214
+ const timeoutSocket = new EventEmitter();
215
+ timeoutSocket.connected = true;
216
+ timeoutSocket.__instance = "socketio";
217
+ timeoutSocket.io = {};
218
+ sandbox.spy(timeoutSocket, "on");
219
+ sandbox.spy(timeoutSocket, "emit");
220
+
221
+ class TimeoutClient extends SockethubClient {
222
+ initActivityStreams() {
223
+ this.ActivityStreams = asInstance as ASManager;
224
+ }
225
+ }
226
+ const client = new TimeoutClient(timeoutSocket);
227
+ client.socket.connected = true;
228
+ try {
229
+ await client.ready(50);
230
+ expect.fail("should have rejected");
231
+ } catch (err: any) {
232
+ expect(err.message).to.contain("timed out");
233
+ }
234
+ timeoutSocket.emit("disconnect");
235
+ });
236
+
237
+ it("emits ready payload including sockethub and platform versions", (done) => {
238
+ sc.socket.on("ready", (info: any) => {
239
+ expect(info.state).to.equal("ready");
240
+ expect(info.sockethubVersion).to.equal("5.0.0-alpha.11");
241
+ expect(info.platforms[0]).to.include.keys([
242
+ "id",
243
+ "version",
244
+ "contextVersion",
245
+ "schemaVersion",
246
+ ]);
247
+ done();
248
+ });
249
+ socket.emit("schemas", TEST_REGISTRY);
250
+ });
251
+
252
+ it("emits init_error and timeout warning when schemas never arrive", (done) => {
253
+ const timeoutSocket = new EventEmitter();
254
+ timeoutSocket.connected = false;
255
+ timeoutSocket.__instance = "socketio";
256
+ sandbox.spy(timeoutSocket, "on");
257
+ sandbox.spy(timeoutSocket, "emit");
258
+ const warnStub = sandbox.stub(console, "warn");
259
+
260
+ class TimeoutSockethubClient extends SockethubClient {
261
+ initActivityStreams() {
262
+ this.ActivityStreams = asInstance as ASManager;
263
+ }
264
+ }
265
+ const timeoutClient = new TimeoutSockethubClient(timeoutSocket, {
266
+ initTimeoutMs: 10,
267
+ });
268
+ timeoutClient.socket.on("init_error", (err: any) => {
269
+ expect(err.phase).to.equal("timeout");
270
+ expect(err.error).to.contain("timed out");
271
+ expect(
272
+ warnStub.calledWithMatch(
273
+ "Initialization timed out after 10ms",
274
+ ),
275
+ ).to.equal(true);
276
+ timeoutSocket.emit("disconnect");
277
+ done();
278
+ });
279
+
280
+ timeoutSocket.emit("connect");
281
+ });
82
282
  });
83
283
 
84
284
  describe("event handling", () => {
@@ -93,9 +293,12 @@ describe("SockethubClient", () => {
93
293
  });
94
294
 
95
295
  it("activity-object-create", (done) => {
296
+ sc.socket.connected = true;
297
+ sc._socket.connected = true;
298
+ socket.emit("schemas", TEST_REGISTRY);
96
299
  asInstance.emit("activity-object-create", { foo: "bar" });
97
300
  setTimeout(() => {
98
- expect(socket.emit.callCount).to.equal(1);
301
+ expect(socket.emit.callCount).to.be.greaterThanOrEqual(2);
99
302
  expect(
100
303
  socket.emit.calledWithMatch("activity-object", {
101
304
  foo: "bar",
@@ -105,13 +308,73 @@ describe("SockethubClient", () => {
105
308
  }, 0);
106
309
  });
107
310
 
311
+ it("activity-object-create stores object only after successful ACK", (done) => {
312
+ sc.socket.connected = true;
313
+ sc._socket.connected = true;
314
+ socket.emit("schemas", TEST_REGISTRY);
315
+ // Intercept the emit to capture the ACK callback
316
+ socket.on("activity-object", (_data: any, ackCb: any) => {
317
+ // Simulate successful ACK (no error)
318
+ if (typeof ackCb === "function") {
319
+ ackCb();
320
+ }
321
+ });
322
+ asInstance.emit("activity-object-create", {
323
+ id: "good-obj",
324
+ foo: "bar",
325
+ });
326
+ setTimeout(() => {
327
+ expect(sc.events["activity-object"].has("good-obj")).to.be.true;
328
+ done();
329
+ }, 0);
330
+ });
331
+
332
+ it("activity-object-create does not store object on ACK error", (done) => {
333
+ sc.socket.connected = true;
334
+ sc._socket.connected = true;
335
+ socket.emit("schemas", TEST_REGISTRY);
336
+ // Intercept the emit to capture the ACK callback
337
+ socket.on("activity-object", (_data: any, ackCb: any) => {
338
+ // Simulate error ACK
339
+ if (typeof ackCb === "function") {
340
+ ackCb({ error: "rejected by server" });
341
+ }
342
+ });
343
+ asInstance.emit("activity-object-create", {
344
+ id: "bad-obj",
345
+ foo: "bar",
346
+ });
347
+ setTimeout(() => {
348
+ expect(sc.events["activity-object"].has("bad-obj")).to.be
349
+ .false;
350
+ done();
351
+ }, 0);
352
+ });
353
+
108
354
  it("connect", (done) => {
109
355
  expect(sc.socket.connected).to.be.false;
356
+ socket.io = {};
357
+ socket.on("schemas", (ack: any) => {
358
+ if (typeof ack === "function") {
359
+ ack({
360
+ contexts: {
361
+ as: "https://example.com/as2",
362
+ sockethub: "https://example.com/sh",
363
+ },
364
+ platforms: [],
365
+ });
366
+ }
367
+ });
110
368
  sc.socket.on("connect", () => {
111
- expect(sc.socket.connected).to.be.true;
112
- expect(sc.socket._emit.callCount).to.equal(1);
113
- expect(sc.socket._emit.calledWithMatch("connect"));
114
- done();
369
+ setTimeout(() => {
370
+ expect(sc.socket.connected).to.be.true;
371
+ expect(sc.socket._emit.callCount).to.be.greaterThanOrEqual(
372
+ 1,
373
+ );
374
+ expect(sc.socket._emit.calledWithMatch("connect"));
375
+ expect(socket.emit.calledWithMatch("schemas")).to.be.true;
376
+ done();
377
+ }, 0);
115
378
  });
116
379
  socket.emit("connect");
117
380
  });
@@ -136,6 +399,40 @@ describe("SockethubClient", () => {
136
399
  socket.emit("connect_error");
137
400
  });
138
401
 
402
+ it("schemas", (done) => {
403
+ sc.socket.on("schemas", (registry: any) => {
404
+ expect(registry.contexts).to.eql({
405
+ as: "https://example.com/as2",
406
+ sockethub: "https://example.com/sh",
407
+ });
408
+ expect(registry.platforms).to.be.an("array");
409
+ expect(registry.platforms[0]?.id).to.equal("xmpp");
410
+ done();
411
+ });
412
+ socket.emit("schemas", {
413
+ version: "5.0.0-alpha.11",
414
+ contexts: {
415
+ as: "https://example.com/as2",
416
+ sockethub: "https://example.com/sh",
417
+ },
418
+ platforms: [
419
+ {
420
+ id: "xmpp",
421
+ version: "1.0.0",
422
+ contextUrl:
423
+ "https://example.com/context/platform/xmpp/v9.jsonld",
424
+ contextVersion: "9",
425
+ schemaVersion: "9",
426
+ types: ["connect"],
427
+ schemas: {
428
+ messages: {},
429
+ credentials: {},
430
+ },
431
+ },
432
+ ],
433
+ });
434
+ });
435
+
139
436
  it("message", (done) => {
140
437
  sc.socket.on("message", () => {
141
438
  expect(sc.socket._emit.callCount).to.equal(1);
@@ -147,20 +444,54 @@ describe("SockethubClient", () => {
147
444
  });
148
445
 
149
446
  describe("event emitting", () => {
150
- it("message (no actor)", () => {
447
+ beforeEach(() => {
151
448
  sc._socket.connected = true;
152
- const callback = () => {
153
- };
449
+ sc.socket.connected = true;
450
+ socket.emit("schemas", TEST_REGISTRY);
451
+ sandbox.stub(sc, "validateActivity").returns("");
452
+ });
453
+
454
+ it("message (no actor) returns callback error", () => {
455
+ const callback = sandbox.spy();
456
+ sc.socket.emit("message", { foo: "bar" }, callback);
457
+ expect(callback.calledOnce).to.equal(true);
458
+ expect(callback.firstCall.args[0]?.error).to.contain(
459
+ "actor property not present",
460
+ );
461
+ });
462
+
463
+ it("returns validation error via callback when registry is loaded", () => {
464
+ (sc.validateActivity as any).returns(
465
+ "[xmpp] /actor: invalid actor for this activity",
466
+ );
467
+ const callback = sandbox.spy();
468
+ socket.emit.resetHistory();
469
+
154
470
  expect(() => {
155
- sc.socket.emit("message", { foo: "bar" }, callback);
156
- }).to.throw("actor property not present");
471
+ sc.socket.emit(
472
+ "message",
473
+ { actor: "bar", type: "send" },
474
+ callback,
475
+ );
476
+ }).to.not.throw();
477
+
478
+ expect(sc.validateActivity.calledOnce).to.equal(true);
479
+ expect(callback.calledOnce).to.equal(true);
480
+ expect(callback.firstCall.args[0]).to.eql({
481
+ error:
482
+ "SockethubClient validation failed: [xmpp] /actor: invalid actor for this activity",
483
+ });
484
+ expect(socket.emit.calledWithMatch("message")).to.equal(false);
157
485
  });
158
486
 
159
487
  it("message", (done) => {
160
488
  sc.socket.connected = true;
161
489
  const callback = () => {};
162
490
  socket.once("message", (data: any, cb: any) => {
163
- expect(data).to.be.eql({ actor: "bar", type: "bar" });
491
+ expect(data).to.be.eql({
492
+ actor: { id: "bar", type: "person" },
493
+ type: "bar",
494
+ });
164
495
  expect(cb).to.be.eql(callback);
165
496
  done();
166
497
  });
@@ -171,7 +502,10 @@ describe("SockethubClient", () => {
171
502
  sc.socket.connected = true;
172
503
  const callback = () => {};
173
504
  socket.once("message", (data: any, cb: any) => {
174
- expect(data).to.be.eql({ actor: "bar", type: "join" });
505
+ expect(data).to.be.eql({
506
+ actor: { id: "bar", type: "person" },
507
+ type: "join",
508
+ });
175
509
  expect(cb).to.be.eql(callback);
176
510
  done();
177
511
  });
@@ -182,7 +516,10 @@ describe("SockethubClient", () => {
182
516
  sc.socket.connected = true;
183
517
  const callback = () => {};
184
518
  socket.once("message", (data: any, cb: any) => {
185
- expect(data).to.be.eql({ actor: "bar", type: "leave" });
519
+ expect(data).to.be.eql({
520
+ actor: { id: "bar", type: "person" },
521
+ type: "leave",
522
+ });
186
523
  expect(cb).to.be.eql(callback);
187
524
  done();
188
525
  });
@@ -197,7 +534,10 @@ describe("SockethubClient", () => {
197
534
  sc.socket.connected = true;
198
535
  const callback = () => {};
199
536
  socket.once("message", (data: any, cb: any) => {
200
- expect(data).to.be.eql({ actor: "bar", type: "connect" });
537
+ expect(data).to.be.eql({
538
+ actor: { id: "bar", type: "person" },
539
+ type: "connect",
540
+ });
201
541
  expect(cb).to.be.eql(callback);
202
542
  done();
203
543
  });
@@ -212,7 +552,10 @@ describe("SockethubClient", () => {
212
552
  sc.socket.connected = true;
213
553
  const callback = () => {};
214
554
  socket.once("message", (data: any, cb: any) => {
215
- expect(data).to.be.eql({ actor: "bar", type: "disconnect" });
555
+ expect(data).to.be.eql({
556
+ actor: { id: "bar", type: "person" },
557
+ type: "disconnect",
558
+ });
216
559
  expect(cb).to.be.eql(callback);
217
560
  done();
218
561
  });
@@ -225,21 +568,29 @@ describe("SockethubClient", () => {
225
568
 
226
569
  it("message (offline)", (done) => {
227
570
  sc.socket.connected = false;
571
+ sc._socket.connected = false;
572
+ socket.emit("disconnect");
228
573
  const callback = () => {};
229
- socket.once("message", (data: any, cb: any) => {
230
- expect(data).to.be.eql({ actor: "bar" });
231
- expect(cb).to.be.eql(callback);
232
- done();
233
- });
234
574
  sc.socket.emit("message", { actor: "bar" }, callback);
575
+ setTimeout(() => {
576
+ expect(
577
+ socket.emit
578
+ .getCalls()
579
+ .some((call: any) => call.args[0] === "message"),
580
+ ).to.equal(false);
581
+ done();
582
+ }, 0);
235
583
  });
236
584
 
237
585
  it("activity-object", (done) => {
238
586
  sc.socket.connected = true;
239
- const callback = () => {};
587
+ const callback = sandbox.spy();
240
588
  socket.once("activity-object", (data: any, cb: any) => {
241
589
  expect(data).to.be.eql({ actor: "bar" });
242
- expect(cb).to.be.eql(callback);
590
+ // Callback is wrapped to defer persistence until ACK
591
+ expect(typeof cb).to.equal("function");
592
+ cb(); // simulate successful ACK
593
+ expect(callback.calledOnce).to.be.true;
243
594
  done();
244
595
  });
245
596
  sc.socket.emit("activity-object", { actor: "bar" }, callback);
@@ -249,12 +600,58 @@ describe("SockethubClient", () => {
249
600
  sc.socket.connected = true;
250
601
  const callback = () => {};
251
602
  socket.once("credentials", (data: any, cb: any) => {
252
- expect(data).to.be.eql({ actor: "bar" });
603
+ expect(data).to.be.eql({
604
+ type: "credentials",
605
+ actor: { id: "bar", type: "person" },
606
+ });
253
607
  expect(cb).to.be.eql(callback);
254
608
  done();
255
609
  });
256
610
  sc.socket.emit("credentials", { actor: "bar" }, callback);
257
611
  });
612
+
613
+ it("queues outbound messages before ready and flushes after schemas", (done) => {
614
+ const preReadySocket = new EventEmitter();
615
+ preReadySocket.connected = false;
616
+ preReadySocket.__instance = "socketio";
617
+ sandbox.spy(preReadySocket, "on");
618
+ sandbox.spy(preReadySocket, "emit");
619
+
620
+ class TestSockethubClient extends SockethubClient {
621
+ initActivityStreams() {
622
+ this.ActivityStreams = asInstance as ASManager;
623
+ }
624
+ }
625
+ const preReadyClient = new TestSockethubClient(preReadySocket);
626
+ sandbox.spy(preReadyClient.socket, "_emit");
627
+ sandbox.stub(preReadyClient, "validateActivity").returns("");
628
+
629
+ const callback = sandbox.spy();
630
+ preReadyClient.socket.emit(
631
+ "message",
632
+ { actor: "bar", type: "join" },
633
+ callback,
634
+ );
635
+ expect(
636
+ preReadySocket.emit
637
+ .getCalls()
638
+ .some((call: any) => call.args[0] === "message"),
639
+ ).to.equal(false);
640
+
641
+ preReadySocket.connected = true;
642
+ preReadyClient.socket.connected = true;
643
+ preReadySocket.emit("schemas", TEST_REGISTRY);
644
+
645
+ setTimeout(() => {
646
+ expect(
647
+ preReadySocket.emit
648
+ .getCalls()
649
+ .some((call: any) => call.args[0] === "message"),
650
+ ).to.equal(true);
651
+ expect(callback.called).to.equal(false);
652
+ done();
653
+ }, 0);
654
+ });
258
655
  });
259
656
 
260
657
  describe("replay functionality", () => {
@@ -266,6 +663,7 @@ describe("SockethubClient", () => {
266
663
  // Reset socket spy and trigger replay
267
664
  socket.emit.resetHistory();
268
665
  socket.emit("connect");
666
+ socket.emit("schemas", TEST_REGISTRY);
269
667
 
270
668
  setTimeout(() => {
271
669
  const replayCalls = socket.emit.getCalls().filter(call => call.args[0] === "activity-object");
@@ -293,6 +691,7 @@ describe("SockethubClient", () => {
293
691
 
294
692
  // Trigger reconnect which calls replay
295
693
  socket.emit("connect");
694
+ socket.emit("schemas", TEST_REGISTRY);
296
695
 
297
696
  setTimeout(() => {
298
697
  // Stream() should NOT be called for activity-objects
@@ -327,6 +726,7 @@ describe("SockethubClient", () => {
327
726
 
328
727
  // Trigger reconnect
329
728
  socket.emit("connect");
729
+ socket.emit("schemas", TEST_REGISTRY);
330
730
 
331
731
  setTimeout(() => {
332
732
  // Stream() SHOULD be called for credentials
@@ -344,6 +744,13 @@ describe("SockethubClient", () => {
344
744
  });
345
745
 
346
746
  describe("clearCredentials", () => {
747
+ beforeEach(() => {
748
+ sc.socket.connected = true;
749
+ sc._socket.connected = true;
750
+ socket.emit("schemas", TEST_REGISTRY);
751
+ sandbox.stub(sc, "validateActivity").returns("");
752
+ });
753
+
347
754
  it("clears stored credentials", () => {
348
755
  // Store some credentials
349
756
  sc.socket.emit("credentials", {
@@ -378,6 +785,7 @@ describe("SockethubClient", () => {
378
785
  });
379
786
 
380
787
  socket.emit("connect");
788
+ socket.emit("schemas", TEST_REGISTRY);
381
789
 
382
790
  setTimeout(() => {
383
791
  // No credentials should have been replayed