Skip to content

Commit 91b6cea

Browse files
committed
More tests
1 parent fb17178 commit 91b6cea

File tree

3 files changed

+190
-7
lines changed

3 files changed

+190
-7
lines changed

src/message-impl.test.ts

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,26 @@
1515
// along with this program. If not, see <https://www.gnu.org/licenses/>.
1616
import { MemoryKvStore } from "@fedify/fedify/federation";
1717
import {
18+
Announce,
19+
Create,
20+
Delete,
1821
Hashtag,
1922
Mention,
2023
Note,
24+
Person,
2125
PUBLIC_COLLECTION,
26+
Tombstone,
27+
Undo,
2228
} from "@fedify/fedify/vocab";
29+
import { assert } from "@std/assert/assert";
2330
import { assertEquals } from "@std/assert/equals";
31+
import { assertInstanceOf } from "@std/assert/instance-of";
2432
import { assertRejects } from "@std/assert/rejects";
2533
import { BotImpl } from "./bot-impl.ts";
2634
import { createMessage } from "./message-impl.ts";
35+
import { createMockContext } from "./session-impl.test.ts";
36+
import { SessionImpl } from "./session-impl.ts";
37+
import { text } from "./text.ts";
2738

2839
Deno.test("createMessage()", async () => {
2940
const bot = new BotImpl<void>({ kv: new MemoryKvStore(), username: "bot" });
@@ -126,3 +137,173 @@ Deno.test("createMessage()", async () => {
126137
const unknownMessage = await createMessage<Note, void>(unknown, session);
127138
assertEquals(unknownMessage.visibility, "unknown");
128139
});
140+
141+
Deno.test("MessageImpl.delete()", async () => {
142+
const kv = new MemoryKvStore();
143+
const bot = new BotImpl<void>({ kv, username: "bot" });
144+
const ctx = createMockContext(bot, "https://example.com");
145+
const session = new SessionImpl(bot, ctx);
146+
const note = new Note({
147+
id: new URL(
148+
"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788",
149+
),
150+
content: "<p>Hello, world!</p>",
151+
attribution: new URL("https://example.com/ap/actor/bot"),
152+
to: PUBLIC_COLLECTION,
153+
cc: new URL("https://example.com/ap/actor/bot/followers"),
154+
});
155+
const msg = await createMessage<Note, void>(note, session);
156+
await kv.set(
157+
bot.kvPrefixes.messages,
158+
["c1c792ce-a0be-4685-b396-e59e5ef8c788"],
159+
);
160+
await kv.set(
161+
[...bot.kvPrefixes.messages, "c1c792ce-a0be-4685-b396-e59e5ef8c788"],
162+
{
163+
"@context": "https://www.w3.org/ns/activitystreams",
164+
"type": "Create",
165+
"id":
166+
"https://example.com/ap/create/c1c792ce-a0be-4685-b396-e59e5ef8c788",
167+
"actor": "https://example.com/ap/actor/bot",
168+
"to": "https://www.w3.org/ns/activitystreams#Public",
169+
"cc": "https://example.com/ap/actor/bot/followers",
170+
object: await note.toJsonLd(),
171+
},
172+
);
173+
await msg.delete();
174+
assertEquals(await kv.get(bot.kvPrefixes.messages), []);
175+
assertEquals(
176+
await kv.get([
177+
...bot.kvPrefixes.messages,
178+
"c1c792ce-a0be-4685-b396-e59e5ef8c788",
179+
]),
180+
undefined,
181+
);
182+
assertEquals(ctx.sentActivities.length, 1);
183+
const { recipients, activity } = ctx.sentActivities[0];
184+
assertEquals(recipients, "followers");
185+
assertInstanceOf(activity, Delete);
186+
assertEquals(activity.actorId, ctx.getActorUri(bot.identifier));
187+
assertEquals(activity.toIds, [PUBLIC_COLLECTION]);
188+
assertEquals(activity.ccIds, [ctx.getFollowersUri(bot.identifier)]);
189+
const tombstone = await activity.getObject();
190+
assertInstanceOf(tombstone, Tombstone);
191+
assertEquals(tombstone.id, note.id);
192+
});
193+
194+
Deno.test("MessageImpl.reply()", async () => {
195+
const kv = new MemoryKvStore();
196+
const bot = new BotImpl<void>({ kv, username: "bot" });
197+
const ctx = createMockContext(bot, "https://example.com");
198+
const session = new SessionImpl(bot, ctx);
199+
const originalPost = new Note({
200+
id: new URL(
201+
"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788",
202+
),
203+
content: "<p>Hello, world!</p>",
204+
attribution: new Person({
205+
id: new URL("https://example.com/ap/actor/john"),
206+
preferredUsername: "john",
207+
}),
208+
to: new URL("https://example.com/ap/actor/john/followers"),
209+
cc: PUBLIC_COLLECTION,
210+
});
211+
const originalMsg = await createMessage<Note, void>(originalPost, session);
212+
const reply = await originalMsg.reply(text`Hello, John!`);
213+
const msgIds = await kv.get<string[]>(bot.kvPrefixes.messages);
214+
assert(msgIds != null);
215+
assertEquals(msgIds.length, 1);
216+
const [msgId] = msgIds;
217+
const activityJson = await kv.get([...bot.kvPrefixes.messages, msgId]);
218+
assert(activityJson != null);
219+
const create = await Create.fromJsonLd(activityJson);
220+
assertEquals(ctx.sentActivities.length, 1);
221+
const { recipients, activity } = ctx.sentActivities[0];
222+
assertEquals(recipients, "followers");
223+
assertInstanceOf(activity, Create);
224+
assertEquals(
225+
await activity.toJsonLd({ format: "compact" }),
226+
await create.toJsonLd({ format: "compact" }),
227+
);
228+
assertEquals(
229+
await reply.raw.toJsonLd({ format: "compact" }),
230+
await (await create.getObject())?.toJsonLd({ format: "compact" }),
231+
);
232+
assertEquals(reply.actor, await session.getActor());
233+
assertEquals(reply.replyTarget, originalMsg);
234+
assertEquals(reply.visibility, "unlisted");
235+
});
236+
237+
Deno.test("MessageImpl.share()", async (t) => {
238+
const kv = new MemoryKvStore();
239+
const bot = new BotImpl<void>({ kv, username: "bot" });
240+
const ctx = createMockContext(bot, "https://example.com");
241+
const session = new SessionImpl(bot, ctx);
242+
const originalPost = new Note({
243+
id: new URL(
244+
"https://example.com/ap/note/c1c792ce-a0be-4685-b396-e59e5ef8c788",
245+
),
246+
content: "<p>Hello, world!</p>",
247+
attribution: new Person({
248+
id: new URL("https://example.com/ap/actor/john"),
249+
preferredUsername: "john",
250+
}),
251+
to: new URL("https://example.com/ap/actor/john/followers"),
252+
cc: PUBLIC_COLLECTION,
253+
});
254+
const originalMsg = await createMessage<Note, void>(originalPost, session);
255+
const sharedMsg = await originalMsg.share();
256+
let msgId: string;
257+
258+
await t.step("share()", async () => {
259+
const msgIds = await kv.get<string[]>(bot.kvPrefixes.messages);
260+
assert(msgIds != null);
261+
assertEquals(msgIds.length, 1);
262+
[msgId] = msgIds;
263+
const activityJson = await kv.get([...bot.kvPrefixes.messages, msgId]);
264+
assert(activityJson != null);
265+
const announce = await Announce.fromJsonLd(activityJson);
266+
assertEquals(ctx.sentActivities.length, 1);
267+
const { recipients, activity } = ctx.sentActivities[0];
268+
assertEquals(recipients, "followers");
269+
assertInstanceOf(activity, Announce);
270+
assertEquals(activity.toIds, [ctx.getFollowersUri(bot.identifier)]);
271+
assertEquals(activity.ccIds, [
272+
PUBLIC_COLLECTION,
273+
originalPost.attributionId,
274+
]);
275+
assertEquals(
276+
await activity.toJsonLd({ format: "compact" }),
277+
await announce.toJsonLd({ format: "compact" }),
278+
);
279+
assertEquals(
280+
await sharedMsg.raw.toJsonLd({ format: "compact" }),
281+
await announce.toJsonLd({ format: "compact" }),
282+
);
283+
assertEquals(sharedMsg.actor, await session.getActor());
284+
assertEquals(sharedMsg.visibility, "unlisted");
285+
assertEquals(sharedMsg.original, originalMsg);
286+
});
287+
288+
ctx.sentActivities = [];
289+
290+
await t.step("unshare()", async () => {
291+
await sharedMsg.unshare();
292+
assertEquals(await kv.get(bot.kvPrefixes.messages), []);
293+
assertEquals(
294+
await kv.get([...bot.kvPrefixes.messages, msgId]),
295+
undefined,
296+
);
297+
assertEquals(ctx.sentActivities.length, 1);
298+
const { recipients, activity } = ctx.sentActivities[0];
299+
assertEquals(recipients, "followers");
300+
assertInstanceOf(activity, Undo);
301+
assertEquals(activity.actorId, ctx.getActorUri(bot.identifier));
302+
assertEquals(activity.toIds, [ctx.getFollowersUri(bot.identifier)]);
303+
assertEquals(activity.ccIds, [
304+
PUBLIC_COLLECTION,
305+
originalPost.attributionId,
306+
]);
307+
assertEquals(activity.objectId, sharedMsg.id);
308+
});
309+
});

src/message-impl.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,9 @@ export class MessageImpl<T extends MessageClass, TContextData>
231231
excludeBaseUris: [new URL(this.session.context.origin)],
232232
},
233233
);
234-
const actor = await announce.getActor(this.session.context);
234+
const actor = announce.actorId?.href === this.session.actorId.href
235+
? await this.session.getActor()
236+
: await announce.getActor(this.session.context);
235237
if (actor == null) throw new TypeError("The actor is required.");
236238
return {
237239
raw: announce,
@@ -289,9 +291,9 @@ export async function createMessage<T extends MessageClass, TContextData>(
289291
session: SessionImpl<TContextData>,
290292
replyTarget?: Message<MessageClass, TContextData>,
291293
): Promise<Message<T, TContextData>> {
292-
if (raw.id == null) throw new TypeError(`The raw.id is required.`);
294+
if (raw.id == null) throw new TypeError("The raw.id is required.");
293295
else if (raw.content == null) {
294-
throw new TypeError(`The raw.content is required.`);
296+
throw new TypeError("The raw.content is required.");
295297
}
296298
const documentLoader = await session.context.getDocumentLoader(session.bot);
297299
const options = {
@@ -303,7 +305,7 @@ export async function createMessage<T extends MessageClass, TContextData>(
303305
? await session.getActor()
304306
: await raw.getAttribution(options);
305307
if (actor == null) {
306-
throw new TypeError(`The raw.attributionId is required.`);
308+
throw new TypeError("The raw.attributionId is required.");
307309
}
308310
const content = raw.content.toString();
309311
const text = textXss.process(content);

src/session-impl.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -150,16 +150,16 @@ Deno.test("SessionImpl.publish()", async (t) => {
150150
});
151151
});
152152

153-
interface SentActivity {
153+
export interface SentActivity {
154154
recipients: "followers" | Recipient[];
155155
activity: Activity;
156156
}
157157

158-
interface MockContext extends Context<void> {
158+
export interface MockContext extends Context<void> {
159159
sentActivities: SentActivity[];
160160
}
161161

162-
function createMockContext(
162+
export function createMockContext(
163163
bot: BotImpl<void>,
164164
origin: URL | string,
165165
): MockContext {

0 commit comments

Comments
 (0)