server/api/api/v1/statuses/[id]/reactions/[name].test.ts
2025-05-26 15:13:56 +02:00

229 lines
7.3 KiB
TypeScript

import { afterAll, beforeAll, describe, expect, test } from "bun:test";
import { randomUUIDv7 } from "bun";
import { Emoji } from "~/classes/database/emoji";
import { Media } from "~/classes/database/media";
import { generateClient, getTestStatuses, getTestUsers } from "~/tests/utils";
const { users, deleteUsers } = await getTestUsers(3);
const timeline = (await getTestStatuses(2, users[0])).toReversed();
let emojiMedia: Media;
let customEmoji: Emoji;
beforeAll(async () => {
emojiMedia = await Media.insert({
id: randomUUIDv7(),
content: {
"image/png": {
content: "https://example.com/image.png",
remote: true,
},
},
});
customEmoji = await Emoji.insert({
id: randomUUIDv7(),
shortcode: "test_emoji",
visibleInPicker: true,
mediaId: emojiMedia.id,
});
});
afterAll(async () => {
await deleteUsers();
await customEmoji.delete();
await emojiMedia.delete();
});
describe("/api/v1/statuses/:id/reactions/:name", () => {
describe("PUT (add reaction)", () => {
test("should return 401 if not authenticated", async () => {
await using client = await generateClient();
const { ok, raw } = await client.createEmojiReaction(
timeline[0].id,
"👍",
);
expect(ok).toBe(false);
expect(raw.status).toBe(401);
});
test("should add unicode emoji reaction", async () => {
await using client = await generateClient(users[1]);
const { data, ok } = await client.createEmojiReaction(
timeline[0].id,
"👍",
);
expect(ok).toBe(true);
expect(data.reactions).toContainEqual(
expect.objectContaining({
name: "👍",
count: 1,
me: true,
}),
);
});
test("should add custom emoji reaction", async () => {
await using client = await generateClient(users[1]);
const { data, ok } = await client.createEmojiReaction(
timeline[0].id,
`:${customEmoji.data.shortcode}:`,
);
expect(ok).toBe(true);
expect(data.reactions).toContainEqual(
expect.objectContaining({
name: `:${customEmoji.data.shortcode}:`,
count: 1,
me: true,
}),
);
expect(data.emojis).toContainEqual(
expect.objectContaining({
shortcode: customEmoji.data.shortcode,
}),
);
});
test("should add multiple different reactions", async () => {
await using client1 = await generateClient(users[1]);
await using client2 = await generateClient(users[2]);
await client1.createEmojiReaction(timeline[1].id, "❤️");
const { data, ok } = await client2.createEmojiReaction(
timeline[1].id,
"😂",
);
expect(ok).toBe(true);
expect(data.reactions).toHaveLength(2);
expect(data.reactions).toContainEqual(
expect.objectContaining({
name: "❤️",
count: 1,
me: false,
}),
);
expect(data.reactions).toContainEqual(
expect.objectContaining({
name: "😂",
count: 1,
me: true,
}),
);
});
test("should not duplicate reactions from same user", async () => {
await using client = await generateClient(users[1]);
// Add same reaction twice
await client.createEmojiReaction(timeline[1].id, "👍");
const { data, ok } = await client.createEmojiReaction(
timeline[1].id,
"👍",
);
expect(ok).toBe(true);
const thumbsReaction = data.reactions.find((r) => r.name === "👍");
expect(thumbsReaction).toMatchObject({
name: "👍",
count: 1,
me: true,
});
});
test("should return 404 for non-existent status", async () => {
await using client = await generateClient(users[1]);
const { ok, raw } = await client.createEmojiReaction(
"00000000-0000-0000-0000-000000000000",
"👍",
);
expect(ok).toBe(false);
expect(raw.status).toBe(404);
});
});
describe("DELETE (remove reaction)", () => {
test("should return 401 if not authenticated", async () => {
await using client = await generateClient();
const { ok, raw } = await client.deleteEmojiReaction(
timeline[0].id,
"👍",
);
expect(ok).toBe(false);
expect(raw.status).toBe(401);
});
test("should remove existing reaction", async () => {
await using client = await generateClient(users[1]);
// First add a reaction
await client.createEmojiReaction(timeline[0].id, "🎉");
// Then remove it
const { data, ok } = await client.deleteEmojiReaction(
timeline[0].id,
"🎉",
);
expect(ok).toBe(true);
expect(data.reactions.find((r) => r.name === "🎉")).toBeUndefined();
});
test("should not fail when removing non-existent reaction", async () => {
await using client = await generateClient(users[1]);
const { data, ok } = await client.deleteEmojiReaction(
timeline[0].id,
"🚀",
);
expect(ok).toBe(true);
expect(data.reactions.find((r) => r.name === "🚀")).toBeUndefined();
});
test("should only remove own reaction", async () => {
await using client1 = await generateClient(users[1]);
await using client2 = await generateClient(users[2]);
// Both users add same reaction
await client1.createEmojiReaction(timeline[0].id, "⭐");
await client2.createEmojiReaction(timeline[0].id, "⭐");
// User 1 removes their reaction
const { data, ok } = await client1.deleteEmojiReaction(
timeline[0].id,
"⭐",
);
expect(ok).toBe(true);
const starReaction = data.reactions.find((r) => r.name === "⭐");
expect(starReaction).toMatchObject({
name: "⭐",
count: 1,
me: false, // Should be false for user 1 now
});
});
test("should return 404 for non-existent status", async () => {
await using client = await generateClient(users[1]);
const { ok, raw } = await client.deleteEmojiReaction(
"00000000-0000-0000-0000-000000000000",
"👍",
);
expect(ok).toBe(false);
expect(raw.status).toBe(404);
});
});
});