@evanp/activitypub-bot 0.13.0 → 0.13.2

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.
Files changed (41) hide show
  1. package/package.json +2 -2
  2. package/.github/dependabot.yml +0 -11
  3. package/.github/workflows/main.yml +0 -34
  4. package/.github/workflows/tag.yml +0 -106
  5. package/.nvmrc +0 -1
  6. package/Dockerfile +0 -17
  7. package/docs/activitypub.bot.drawio +0 -110
  8. package/tests/activitydistributor.test.js +0 -606
  9. package/tests/activityhandler.test.js +0 -2276
  10. package/tests/activitypubclient.test.js +0 -210
  11. package/tests/actorstorage.test.js +0 -283
  12. package/tests/app.test.js +0 -17
  13. package/tests/authorizer.test.js +0 -301
  14. package/tests/bot.donothing.test.js +0 -30
  15. package/tests/bot.ok.test.js +0 -101
  16. package/tests/botcontext.test.js +0 -720
  17. package/tests/botdatastorage.test.js +0 -88
  18. package/tests/botfactory.provincebotfactory.test.js +0 -430
  19. package/tests/digester.test.js +0 -56
  20. package/tests/fixtures/bots.js +0 -27
  21. package/tests/fixtures/eventloggingbot.js +0 -57
  22. package/tests/fixtures/provincebotfactory.js +0 -53
  23. package/tests/httpsignature.test.js +0 -199
  24. package/tests/httpsignatureauthenticator.test.js +0 -463
  25. package/tests/index.test.js +0 -12
  26. package/tests/keystorage.test.js +0 -124
  27. package/tests/microsyntax.test.js +0 -123
  28. package/tests/objectcache.test.js +0 -133
  29. package/tests/objectstorage.test.js +0 -149
  30. package/tests/remotekeystorage.test.js +0 -78
  31. package/tests/routes.actor.test.js +0 -214
  32. package/tests/routes.collection.test.js +0 -310
  33. package/tests/routes.health.test.js +0 -41
  34. package/tests/routes.inbox.test.js +0 -216
  35. package/tests/routes.object.test.js +0 -525
  36. package/tests/routes.server.test.js +0 -69
  37. package/tests/routes.sharedinbox.test.js +0 -473
  38. package/tests/routes.webfinger.test.js +0 -68
  39. package/tests/urlformatter.test.js +0 -164
  40. package/tests/utils/digest.js +0 -7
  41. package/tests/utils/nock.js +0 -499
@@ -1,720 +0,0 @@
1
- import { describe, it, before, after, beforeEach } from 'node:test'
2
- import assert from 'node:assert'
3
- import { BotContext } from '../lib/botcontext.js'
4
- import { Sequelize } from 'sequelize'
5
- import { BotDataStorage } from '../lib/botdatastorage.js'
6
- import { ObjectStorage } from '../lib/objectstorage.js'
7
- import { KeyStorage } from '../lib/keystorage.js'
8
- import { UrlFormatter } from '../lib/urlformatter.js'
9
- import { ActivityPubClient } from '../lib/activitypubclient.js'
10
- import { ActivityDistributor } from '../lib/activitydistributor.js'
11
- import { ActorStorage } from '../lib/actorstorage.js'
12
- import { Transformer } from '../lib/microsyntax.js'
13
- import {
14
- nockSetup,
15
- postInbox,
16
- resetInbox,
17
- makeActor,
18
- makeObject,
19
- nockFormat
20
- } from './utils/nock.js'
21
- import Logger from 'pino'
22
- import as2 from '../lib/activitystreams.js'
23
- import { HTTPSignature } from '../lib/httpsignature.js'
24
- import { Digester } from '../lib/digester.js'
25
- import { runMigrations } from '../lib/migrations/index.js'
26
-
27
- const AS2_NS = 'https://www.w3.org/ns/activitystreams#'
28
-
29
- describe('BotContext', () => {
30
- let connection = null
31
- let botDataStorage = null
32
- let objectStorage = null
33
- let keyStorage = null
34
- let actorStorage = null
35
- let formatter = null
36
- let client = null
37
- let distributor = null
38
- let context = null
39
- let actor3 = null
40
- let actor5 = null
41
- let actor6 = null
42
- let note = null
43
- let transformer = null
44
- let logger = null
45
- const botName = 'test1'
46
- before(async () => {
47
- logger = Logger({
48
- level: 'silent'
49
- })
50
- formatter = new UrlFormatter('https://activitypubbot.example')
51
- connection = new Sequelize({ dialect: 'sqlite', storage: ':memory:', logging: false })
52
- await connection.authenticate()
53
- await runMigrations(connection)
54
- botDataStorage = new BotDataStorage(connection)
55
- objectStorage = new ObjectStorage(connection)
56
- keyStorage = new KeyStorage(connection, logger)
57
- actorStorage = new ActorStorage(connection, formatter)
58
- const signer = new HTTPSignature(logger)
59
- const digester = new Digester(logger)
60
- client = new ActivityPubClient(keyStorage, formatter, signer, digester, logger)
61
- distributor = new ActivityDistributor(client, formatter, actorStorage, logger)
62
- transformer = new Transformer('https://activitypubbot.example/tag/', client)
63
- await objectStorage.create(
64
- await as2.import({
65
- id: formatter.format({
66
- username: botName,
67
- type: 'object',
68
- nanoid: '_pEWsKke-7lACTdM3J_qd'
69
- }),
70
- type: 'Object',
71
- attributedTo: formatter.format({ username: botName }),
72
- to: 'https://www.w3.org/ns/activitystreams#Public'
73
- })
74
- )
75
- nockSetup('social.example')
76
- })
77
- after(async () => {
78
- await connection.close()
79
- context = null
80
- distributor = null
81
- client = null
82
- formatter = null
83
- actorStorage = null
84
- keyStorage = null
85
- botDataStorage = null
86
- objectStorage = null
87
- connection = null
88
- })
89
- beforeEach(async () => {
90
- resetInbox()
91
- })
92
- it('can initialize', async () => {
93
- context = new BotContext(
94
- botName,
95
- botDataStorage,
96
- objectStorage,
97
- actorStorage,
98
- client,
99
- distributor,
100
- formatter,
101
- transformer,
102
- logger
103
- )
104
- })
105
- it('can get the bot ID', () => {
106
- assert.strictEqual(context.botId, botName)
107
- })
108
- it('can set a value', async () => {
109
- await context.setData('key1', 'value1')
110
- })
111
- it('can get a value', async () => {
112
- const value = await context.getData('key1')
113
- assert.equal(value, 'value1')
114
- })
115
- it('can delete a value', async () => {
116
- await context.deleteData('key1')
117
- })
118
- it('can return the correct flag for an unset key', async () => {
119
- const result = await context.hasData('doesnotexist')
120
- assert.strictEqual(result, false)
121
- })
122
- it('can return the correct flag for a set key', async () => {
123
- await context.setData('setkey', 'value')
124
- const result = await context.hasData('setkey')
125
- assert.strictEqual(result, true)
126
- })
127
- it('can get a local object', async () => {
128
- const id = formatter.format({
129
- username: botName,
130
- type: 'object',
131
- nanoid: '_pEWsKke-7lACTdM3J_qd'
132
- })
133
- const object = await context.getObject(id)
134
- assert.ok(object)
135
- assert.strictEqual(object.id, id)
136
- assert.strictEqual(
137
- object.type,
138
- 'https://www.w3.org/ns/activitystreams#Object'
139
- )
140
- })
141
- it('can get a remote object', async () => {
142
- const id = 'https://social.example/user/test2/object/1'
143
- const object = await context.getObject(id)
144
- assert.ok(object)
145
- assert.strictEqual(object.id, id)
146
- assert.strictEqual(
147
- object.type,
148
- 'https://www.w3.org/ns/activitystreams#Object'
149
- )
150
- })
151
- it('can send a note', async () => {
152
- const actor2 = await makeActor('test2')
153
- await actorStorage.addToCollection(botName, 'followers', actor2)
154
- let followers = await actorStorage.getCollection(botName, 'followers')
155
- assert.strictEqual(followers.totalItems, 1)
156
- const content = 'Hello World'
157
- const to = 'https://www.w3.org/ns/activitystreams#Public'
158
- note = await context.sendNote(content, { to })
159
- assert.ok(note)
160
- assert.strictEqual(note.type, 'https://www.w3.org/ns/activitystreams#Note')
161
- assert.strictEqual(await note.content.get(), `<p>${content}</p>`)
162
- const iter = note.attributedTo[Symbol.iterator]()
163
- const actor = iter.next().value
164
- assert.strictEqual(actor.id, 'https://activitypubbot.example/user/test1')
165
- const iter2 = note.to[Symbol.iterator]()
166
- const addressee = iter2.next().value
167
- assert.strictEqual(addressee.id, to)
168
- assert.strictEqual(typeof note.published, 'object')
169
- assert.strictEqual(typeof note.id, 'string')
170
- await context.onIdle()
171
- assert.strictEqual(postInbox.test2, 1)
172
- const outbox = await actorStorage.getCollection(botName, 'outbox')
173
- assert.strictEqual(outbox.totalItems, 1)
174
- const inbox = await actorStorage.getCollection(botName, 'inbox')
175
- assert.strictEqual(inbox.totalItems, 1)
176
- followers = await actorStorage.getCollection(botName, 'followers')
177
- assert.strictEqual(followers.totalItems, 1)
178
- })
179
- it('can like an object', async () => {
180
- const id = 'https://social.example/user/test2/object/1'
181
- const obj = await context.getObject(id)
182
- await context.likeObject(obj)
183
- await context.onIdle()
184
- assert.strictEqual(postInbox.test2, 1)
185
- const outbox = await actorStorage.getCollection(botName, 'outbox')
186
- assert.strictEqual(outbox.totalItems, 2)
187
- const inbox = await actorStorage.getCollection(botName, 'inbox')
188
- assert.strictEqual(inbox.totalItems, 2)
189
- const liked = await actorStorage.getCollection(botName, 'liked')
190
- assert.strictEqual(liked.totalItems, 1)
191
- })
192
- it('can unlike an object', async () => {
193
- const id = 'https://social.example/user/test2/object/1'
194
- const obj = await context.getObject(id)
195
- await context.unlikeObject(obj)
196
- await context.onIdle()
197
- assert.strictEqual(postInbox.test2, 1)
198
- const outbox = await actorStorage.getCollection(botName, 'outbox')
199
- assert.strictEqual(outbox.totalItems, 3)
200
- const inbox = await actorStorage.getCollection(botName, 'inbox')
201
- assert.strictEqual(inbox.totalItems, 3)
202
- const liked = await actorStorage.getCollection(botName, 'liked')
203
- assert.strictEqual(liked.totalItems, 0)
204
- })
205
- it('can follow an actor', async () => {
206
- actor3 = await makeActor('test3')
207
- await context.followActor(actor3)
208
- await context.onIdle()
209
- assert.strictEqual(postInbox.test3, 1)
210
- const outbox = await actorStorage.getCollection(botName, 'outbox')
211
- assert.strictEqual(outbox.totalItems, 4)
212
- const inbox = await actorStorage.getCollection(botName, 'inbox')
213
- assert.strictEqual(inbox.totalItems, 4)
214
- const pendingFollowing = await actorStorage.getCollection(
215
- botName,
216
- 'pendingFollowing'
217
- )
218
- assert.strictEqual(pendingFollowing.totalItems, 1)
219
- })
220
- it('can unfollow a pending actor', async () => {
221
- await context.unfollowActor(actor3)
222
- await context.onIdle()
223
- assert.strictEqual(postInbox.test3, 1)
224
- const outbox = await actorStorage.getCollection(botName, 'outbox')
225
- assert.strictEqual(outbox.totalItems, 5)
226
- const inbox = await actorStorage.getCollection(botName, 'inbox')
227
- assert.strictEqual(inbox.totalItems, 5)
228
- const pendingFollowing = await actorStorage.getCollection(
229
- botName,
230
- 'pendingFollowing'
231
- )
232
- assert.strictEqual(pendingFollowing.totalItems, 0)
233
- })
234
- it('can unfollow a followed actor', async () => {
235
- const actor4 = await makeActor('test4')
236
- await actorStorage.addToCollection(botName, 'following', actor4)
237
- let following = await actorStorage.getCollection(botName, 'following')
238
- assert.strictEqual(following.totalItems, 1)
239
- await context.unfollowActor(actor4)
240
- await context.onIdle()
241
- assert.strictEqual(postInbox.test4, 1)
242
- const outbox = await actorStorage.getCollection(botName, 'outbox')
243
- assert.strictEqual(outbox.totalItems, 6)
244
- const inbox = await actorStorage.getCollection(botName, 'inbox')
245
- assert.strictEqual(inbox.totalItems, 6)
246
- following = await actorStorage.getCollection(botName, 'following')
247
- assert.strictEqual(following.totalItems, 0)
248
- })
249
- it('can block an actor without a relationship', async () => {
250
- let followers = await actorStorage.getCollection(botName, 'followers')
251
- assert.strictEqual(followers.totalItems, 1)
252
- actor5 = await makeActor('test5')
253
- await context.blockActor(actor5)
254
- await context.onIdle()
255
- assert.ok(!postInbox.test5)
256
- const outbox = await actorStorage.getCollection(botName, 'outbox')
257
- assert.strictEqual(outbox.totalItems, 7)
258
- const inbox = await actorStorage.getCollection(botName, 'inbox')
259
- assert.strictEqual(inbox.totalItems, 7)
260
- const blocked = await actorStorage.getCollection(botName, 'blocked')
261
- assert.strictEqual(blocked.totalItems, 1)
262
- followers = await actorStorage.getCollection(botName, 'followers')
263
- assert.strictEqual(followers.totalItems, 1)
264
- })
265
- it('can unblock an actor without a relationship', async () => {
266
- let followers = await actorStorage.getCollection(botName, 'followers')
267
- assert.strictEqual(followers.totalItems, 1)
268
- await context.unblockActor(actor5)
269
- await context.onIdle()
270
- assert.ok(!postInbox.test5)
271
- const outbox = await actorStorage.getCollection(botName, 'outbox')
272
- assert.strictEqual(outbox.totalItems, 8)
273
- const inbox = await actorStorage.getCollection(botName, 'inbox')
274
- assert.strictEqual(inbox.totalItems, 8)
275
- const blocked = await actorStorage.getCollection(botName, 'blocked')
276
- assert.strictEqual(blocked.totalItems, 0)
277
- followers = await actorStorage.getCollection(botName, 'followers')
278
- assert.strictEqual(followers.totalItems, 1)
279
- })
280
- it('can block an actor with a relationship', async () => {
281
- actor6 = await makeActor('test6')
282
- let followers = await actorStorage.getCollection(botName, 'followers')
283
- assert.strictEqual(followers.totalItems, 1)
284
- await actorStorage.addToCollection(botName, 'following', actor6)
285
- await actorStorage.addToCollection(botName, 'followers', actor6)
286
- followers = await actorStorage.getCollection(botName, 'followers')
287
- assert.strictEqual(followers.totalItems, 2)
288
- await context.blockActor(actor6)
289
- await context.onIdle()
290
- assert.ok(!postInbox.test6)
291
- const outbox = await actorStorage.getCollection(botName, 'outbox')
292
- assert.strictEqual(outbox.totalItems, 9)
293
- const inbox = await actorStorage.getCollection(botName, 'inbox')
294
- assert.strictEqual(inbox.totalItems, 9)
295
- const blocked = await actorStorage.getCollection(botName, 'blocked')
296
- assert.strictEqual(blocked.totalItems, 1)
297
- const following = await actorStorage.getCollection(botName, 'following')
298
- assert.strictEqual(following.totalItems, 0)
299
- followers = await actorStorage.getCollection(botName, 'followers')
300
- assert.strictEqual(followers.totalItems, 1)
301
- })
302
- it('can unblock an actor with a former relationship', async () => {
303
- await context.unblockActor(actor6)
304
- assert.ok(!postInbox.test6)
305
- const outbox = await actorStorage.getCollection(botName, 'outbox')
306
- assert.strictEqual(outbox.totalItems, 10)
307
- const inbox = await actorStorage.getCollection(botName, 'inbox')
308
- assert.strictEqual(inbox.totalItems, 10)
309
- const blocked = await actorStorage.getCollection(botName, 'blocked')
310
- assert.strictEqual(blocked.totalItems, 0)
311
- const following = await actorStorage.getCollection(botName, 'following')
312
- assert.strictEqual(following.totalItems, 0)
313
- const followers = await actorStorage.getCollection(botName, 'followers')
314
- assert.strictEqual(followers.totalItems, 1)
315
- })
316
- it('can update a note', async () => {
317
- const content = 'Hello World 2'
318
- await context.updateNote(note, content)
319
- await context.onIdle()
320
- assert.strictEqual(postInbox.test2, 1)
321
- const outbox = await actorStorage.getCollection(botName, 'outbox')
322
- assert.strictEqual(outbox.totalItems, 11)
323
- const inbox = await actorStorage.getCollection(botName, 'inbox')
324
- assert.strictEqual(inbox.totalItems, 11)
325
- const copy = await context.getObject(note.id)
326
- assert.strictEqual(copy.content.get(), content)
327
- })
328
- it('can delete a note', async () => {
329
- await context.deleteNote(note)
330
- await context.onIdle()
331
- assert.strictEqual(postInbox.test2, 1)
332
- const outbox = await actorStorage.getCollection(botName, 'outbox')
333
- assert.strictEqual(outbox.totalItems, 12)
334
- const inbox = await actorStorage.getCollection(botName, 'inbox')
335
- assert.strictEqual(inbox.totalItems, 12)
336
- const copy = await context.getObject(note.id)
337
- assert.ok(copy)
338
- assert.strictEqual(
339
- copy.type,
340
- 'https://www.w3.org/ns/activitystreams#Tombstone'
341
- )
342
- assert.ok(copy.deleted)
343
- // FIXME: check for formerType when activitystrea.ms supports it
344
- })
345
- it('fails when liking an object twice', async () => {
346
- const id = 'https://social.example/user/test2/object/2'
347
- const obj = await context.getObject(id)
348
- await context.likeObject(obj)
349
- await context.onIdle()
350
- try {
351
- await context.likeObject(obj)
352
- assert.fail('Expected an error')
353
- } catch (error) {
354
- assert.ok(true)
355
- }
356
- })
357
- it('fails when unliking an object never seen before', async () => {
358
- const id = 'https://social.example/user/test2/object/3'
359
- const obj = await context.getObject(id)
360
- try {
361
- await context.unlikeObject(obj)
362
- assert.fail('Expected an error')
363
- } catch (error) {
364
- assert.ok(true)
365
- }
366
- })
367
- it('can send a reply', async () => {
368
- const actor3 = await makeActor('test3')
369
- const object = await makeObject('test7', 'Note', 1)
370
- const content = '@test2@social.example hello back'
371
- const to = [actor3.id, 'as:Public']
372
- const inReplyTo = object.id
373
- note = await context.sendNote(content, { to, inReplyTo })
374
- assert.ok(note)
375
- assert.strictEqual(note.type, 'https://www.w3.org/ns/activitystreams#Note')
376
- assert.strictEqual(
377
- await note.content.get(),
378
- '<p>' +
379
- '<a href="https://social.example/profile/test2">' +
380
- '@test2@social.example' +
381
- '</a> hello back</p>'
382
- )
383
- const iter = note.attributedTo[Symbol.iterator]()
384
- const actor = iter.next().value
385
- assert.strictEqual(actor.id, 'https://activitypubbot.example/user/test1')
386
- const iter2 = note.to[Symbol.iterator]()
387
- const addressee = iter2.next().value
388
- assert.strictEqual(addressee.id, actor3.id)
389
- assert.strictEqual(typeof note.published, 'object')
390
- assert.strictEqual(typeof note.id, 'string')
391
- const tag = note.tag.first
392
- assert.strictEqual(
393
- tag.type,
394
- 'https://www.w3.org/ns/activitystreams#Mention'
395
- )
396
- assert.strictEqual(tag.href, 'https://social.example/profile/test2')
397
- await context.onIdle()
398
- })
399
- it('can send a tag', async () => {
400
- const content = 'Thank you Sally! #gratitude'
401
- const to = 'as:Public'
402
- note = await context.sendNote(content, { to })
403
- assert.ok(note)
404
- assert.strictEqual(
405
- note.content.get(),
406
- '<p>Thank you Sally! ' +
407
- '<a href="https://activitypubbot.example/tag/gratitude">#gratitude</a></p>'
408
- )
409
- const tag = note.tag.first
410
- assert.strictEqual(
411
- tag.type,
412
- 'https://www.w3.org/ns/activitystreams#Hashtag'
413
- )
414
- assert.strictEqual(tag.name.get(), '#gratitude')
415
- })
416
- it('can send an url', async () => {
417
- const content = 'Check out this link: https://example.com'
418
- const to = 'as:Public'
419
- note = await context.sendNote(content, { to })
420
- assert.ok(note)
421
- assert.strictEqual(
422
- note.content.get(),
423
- '<p>Check out this link: ' +
424
- '<a href="https://example.com">https://example.com</a></p>'
425
- )
426
- })
427
- it('can get an actor ID from a Webfinger ID', async () => {
428
- const webfinger = 'test3@social.example'
429
- const actorId = await context.toActorId(webfinger)
430
- assert.ok(actorId)
431
- assert.strictEqual(typeof actorId, 'string')
432
- assert.strictEqual(actorId, 'https://social.example/user/test3')
433
- })
434
-
435
- it('can get a Webfinger ID from an actor ID', async () => {
436
- const actorId = 'https://social.example/user/test4'
437
- const webfinger = await context.toWebfinger(actorId)
438
- assert.ok(webfinger)
439
- assert.strictEqual(typeof webfinger, 'string')
440
- assert.strictEqual(webfinger, 'test4@social.example')
441
- })
442
-
443
- it('can reply to a note', async () => {
444
- const noteIn = await makeObject('test5', 'Note', 1)
445
- const note = await context.sendReply('@test5@social.example OK', noteIn)
446
- assert.ok(note)
447
- assert.strictEqual(note.type, AS2_NS + 'Note')
448
- const actor = note.attributedTo?.first
449
- assert.strictEqual(actor.id, 'https://activitypubbot.example/user/test1')
450
- const recipients = [
451
- 'https://social.example/user/test5',
452
- 'https://www.w3.org/ns/activitystreams#Public'
453
- ]
454
- for (const addressee in note.to) {
455
- assert.ok(recipients.includes(addressee.id))
456
- }
457
- await context.onIdle()
458
- assert.strictEqual(postInbox.test5, 1)
459
- })
460
-
461
- it('can reply to self', async () => {
462
- const original = await context.sendNote("s'alright?", { to: 'as:Public' })
463
- const reply = await context.sendReply("@test1@activitypubbot.example s'alright.", original)
464
- assert.ok(reply)
465
- assert.strictEqual(reply.type, AS2_NS + 'Note')
466
- const actor = reply.attributedTo?.first
467
- assert.strictEqual(actor.id, 'https://activitypubbot.example/user/test1')
468
- const recipients = [
469
- 'https://activitypubbot.example/user/test1',
470
- 'https://www.w3.org/ns/activitystreams#Public'
471
- ]
472
- for (const addressee in reply.to) {
473
- assert.ok(recipients.includes(addressee.id))
474
- }
475
- await context.onIdle()
476
- assert.strictEqual(postInbox.test2, 2)
477
- let found = false
478
- for await (const item of actorStorage.items(botName, 'inbox')) {
479
- const full = await objectStorage.read(item.id)
480
- if (full.object?.first?.id === reply.id) {
481
- found = true
482
- break
483
- }
484
- }
485
- assert.ok(found)
486
- })
487
-
488
- it('does local delivery', async () => {
489
- const note = await context.sendNote('say OK please',
490
- { to: 'https://activitypubbot.example/user/ok' }
491
- )
492
- await context.onIdle()
493
- assert.ok(note)
494
- let found = null
495
- for await (const item of actorStorage.items('ok', 'inbox')) {
496
- const full = await objectStorage.read(item.id)
497
- if (full.object?.first?.id === note.id) {
498
- found = full
499
- break
500
- }
501
- }
502
- assert.ok(found)
503
- for await (const item of actorStorage.items(botName, 'inbox')) {
504
- const full = await objectStorage.read(item.id)
505
- if (full.object?.first?.inReplyTo?.first?.id === note.id) {
506
- found = full
507
- break
508
- }
509
- }
510
- assert.ok(found)
511
- })
512
-
513
- it('has a working logger', async () => {
514
- assert.ok(context.logger)
515
- assert.doesNotThrow(() => context.logger.debug('debug'))
516
- assert.doesNotThrow(() => context.logger.info('info'))
517
- assert.doesNotThrow(() => context.logger.warn('warn'))
518
- assert.doesNotThrow(() => context.logger.error('error'))
519
- })
520
-
521
- describe('reactions in new content', async () => {
522
- let note = null
523
- before(async () => {
524
- const content = 'Hello World'
525
- const to = 'https://www.w3.org/ns/activitystreams#Public'
526
- note = await context.sendNote(content, { to })
527
- })
528
-
529
- it('has a replies property', async () => {
530
- const repliesProp = note.get('replies')
531
- assert.ok(repliesProp)
532
- const replieses = Array.from(repliesProp)
533
- assert.strictEqual(replieses.length, 1)
534
- const replies = replieses[0]
535
- assert.ok(replies.id)
536
- })
537
-
538
- it('has a shares property', async () => {
539
- const sharesProp = note.get('shares')
540
- assert.ok(sharesProp)
541
- const shareses = Array.from(sharesProp)
542
- assert.strictEqual(shareses.length, 1)
543
- const shares = shareses[0]
544
- assert.ok(shares.id)
545
- })
546
-
547
- it('has a likes property', async () => {
548
- const likesProp = note.get('likes')
549
- assert.ok(likesProp)
550
- const likeses = Array.from(likesProp)
551
- assert.strictEqual(likeses.length, 1)
552
- const likes = likeses[0]
553
- assert.ok(likes.id)
554
- })
555
- })
556
-
557
- describe('threads in new content', async () => {
558
- let note = null
559
- before(async () => {
560
- const content = 'Hello World'
561
- const to = 'https://www.w3.org/ns/activitystreams#Public'
562
- note = await context.sendNote(content, { to })
563
- })
564
-
565
- it('has a thread property', async () => {
566
- const threadProp = note.get('https://purl.archive.org/socialweb/thread#thread')
567
- assert.ok(threadProp)
568
- const threads = Array.from(threadProp)
569
- assert.strictEqual(threads.length, 1)
570
- const thread = threads[0]
571
- assert.ok(thread.id)
572
- })
573
-
574
- it('has a context property', async () => {
575
- const contextProp = note.get('context')
576
- assert.ok(contextProp)
577
- const contexts = Array.from(contextProp)
578
- assert.strictEqual(contexts.length, 1)
579
- const context = contexts[0]
580
- assert.ok(context.id)
581
- })
582
-
583
- it('has an ostatus:conversation property', async () => {
584
- const conversationProp = note.get('http://ostatus.org/schema/1.0/conversation')
585
- assert.ok(conversationProp)
586
- const conversations = Array.from(conversationProp)
587
- assert.strictEqual(conversations.length, 1)
588
- const conversation = conversations[0]
589
- assert.ok(conversation)
590
- })
591
- })
592
-
593
- describe('reactions in a reply', async () => {
594
- let note = null
595
- before(async () => {
596
- const noteIn = await makeObject('test8', 'Note', 1)
597
- const content = '@test8@social.example OK'
598
- note = await context.sendReply(content, noteIn)
599
- })
600
-
601
- it('has a replies property', async () => {
602
- const repliesProp = note.get('replies')
603
- assert.ok(repliesProp)
604
- const replieses = Array.from(repliesProp)
605
- assert.strictEqual(replieses.length, 1)
606
- const replies = replieses[0]
607
- assert.ok(replies.id)
608
- })
609
-
610
- it('has a shares property', async () => {
611
- const sharesProp = note.get('shares')
612
- assert.ok(sharesProp)
613
- const shareses = Array.from(sharesProp)
614
- assert.strictEqual(shareses.length, 1)
615
- const shares = shareses[0]
616
- assert.ok(shares.id)
617
- })
618
-
619
- it('has a likes property', async () => {
620
- const likesProp = note.get('likes')
621
- assert.ok(likesProp)
622
- const likeses = Array.from(likesProp)
623
- assert.strictEqual(likeses.length, 1)
624
- const likes = likeses[0]
625
- assert.ok(likes.id)
626
- })
627
- })
628
-
629
- describe('threads in a reply', async () => {
630
- let note = null
631
- let noteIn = null
632
- before(async () => {
633
- noteIn = await makeObject('test8', 'Note', 2)
634
- const content = '@test8@social.example OK'
635
- note = await context.sendReply(content, noteIn)
636
- })
637
-
638
- it('has a matching thread property', async () => {
639
- const propName = 'https://purl.archive.org/socialweb/thread#thread'
640
- const threadProp = note.get(propName)
641
- assert.ok(threadProp)
642
- const threads = Array.from(threadProp)
643
- assert.strictEqual(threads.length, 1)
644
- const thread = threads[0]
645
- assert.ok(thread.id)
646
- const threadIn = Array.from(noteIn.get(propName))[0]
647
- assert.strictEqual(thread.id, threadIn.id)
648
- })
649
-
650
- it('has a matching context property', async () => {
651
- const propName = 'context'
652
- const contextProp = note.get(propName)
653
- assert.ok(contextProp)
654
- const contexts = Array.from(contextProp)
655
- assert.strictEqual(contexts.length, 1)
656
- const context = contexts[0]
657
- assert.ok(context.id)
658
- const contextIn = Array.from(noteIn.get(propName))[0]
659
- assert.strictEqual(context.id, contextIn.id)
660
- })
661
-
662
- it('has a matching ostatus:conversation property', async () => {
663
- const propName = 'http://ostatus.org/schema/1.0/conversation'
664
- const conversationProp = note.get(propName)
665
- assert.ok(conversationProp)
666
- const conversations = Array.from(conversationProp)
667
- assert.strictEqual(conversations.length, 1)
668
- const conversation = conversations[0]
669
- assert.ok(conversation)
670
- const conversationIn = Array.from(noteIn.get(propName))[0]
671
- assert.strictEqual(context.id, conversationIn.id)
672
- })
673
- })
674
-
675
- it('can duplicate', async () => {
676
- const username = 'dupe1'
677
- let dupe = null
678
- dupe = await context.duplicate(username)
679
- assert.ok(dupe)
680
- assert.strictEqual(dupe.botId, username)
681
- })
682
-
683
- it('can announce an object', async () => {
684
- const username = 'test9'
685
- const type = 'Note'
686
- const num = 3035
687
-
688
- const id = nockFormat({ username, type, num })
689
-
690
- const obj = await context.getObject(id)
691
- const activity = await context.announceObject(obj)
692
-
693
- assert.ok(activity)
694
-
695
- assert.strictEqual(activity.type, `${AS2_NS}Announce`)
696
- assert.strictEqual(activity.object?.first?.id, obj.id)
697
-
698
- await context.onIdle()
699
-
700
- assert.strictEqual(postInbox[username], 1)
701
-
702
- let foundInOutbox = false
703
- for await (const item of actorStorage.items(botName, 'outbox')) {
704
- if (item.id === activity.id) {
705
- foundInOutbox = true
706
- break
707
- }
708
- }
709
- assert.ok(foundInOutbox)
710
-
711
- let foundInInbox = false
712
- for await (const item of actorStorage.items(botName, 'inbox')) {
713
- if (item.id === activity.id) {
714
- foundInInbox = true
715
- break
716
- }
717
- }
718
- assert.ok(foundInInbox)
719
- })
720
- })