BlueSky & more on desktop
lazurite.stormlightlabs.org/
tauri
rust
typescript
bluesky
appview
atproto
solid
1import { describe, expect, it } from "vitest";
2import {
3 parseGetConvoForMembersResponse,
4 parseGetMessagesResponse,
5 parseListConvosResponse,
6 parseSendMessageResponse,
7} from "../conversations";
8
9function createMember(overrides: Record<string, unknown> = {}) {
10 return { did: "did:plc:bob", displayName: "Bob", handle: "bob.test", ...overrides };
11}
12
13function createMessage(overrides: Record<string, unknown> = {}) {
14 return {
15 $type: "chat.bsky.convo.defs#messageView",
16 id: "msg-1",
17 rev: "1",
18 sender: { did: "did:plc:bob" },
19 sentAt: "2026-03-29T12:00:00.000Z",
20 text: "hello",
21 ...overrides,
22 };
23}
24
25function createConvo(overrides: Record<string, unknown> = {}) {
26 return {
27 id: "convo-1",
28 lastMessage: createMessage(),
29 members: [createMember()],
30 muted: false,
31 rev: "1",
32 status: "active",
33 unreadCount: 2,
34 ...overrides,
35 };
36}
37
38describe("conversation payload parsers", () => {
39 it("parses the conversation list response", () => {
40 const response = parseListConvosResponse({
41 convos: [createConvo({ members: [createMember({ labels: [{ src: "did:plc:labeler", val: "sexual" }] })] })],
42 cursor: "cursor-1",
43 });
44
45 expect(response.cursor).toBe("cursor-1");
46 expect(response.convos).toHaveLength(1);
47 expect(response.convos[0]?.members[0]?.handle).toBe("bob.test");
48 expect(response.convos[0]?.members[0]?.labels).toEqual([{ src: "did:plc:labeler", val: "sexual" }]);
49 });
50
51 it("parses a conversation lookup response", () => {
52 const response = parseGetConvoForMembersResponse({ convo: createConvo() });
53
54 expect(response.convo.id).toBe("convo-1");
55 });
56
57 it("parses mixed message payloads", () => {
58 const response = parseGetMessagesResponse({
59 cursor: "cursor-2",
60 messages: [createMessage(), {
61 $type: "chat.bsky.convo.defs#deletedMessageView",
62 id: "msg-2",
63 rev: "2",
64 sender: { did: "did:plc:alice" },
65 sentAt: "2026-03-29T12:01:00.000Z",
66 }],
67 });
68
69 expect(response.cursor).toBe("cursor-2");
70 expect(response.messages).toHaveLength(2);
71 expect(response.messages[1]?.$type).toBe("chat.bsky.convo.defs#deletedMessageView");
72 });
73
74 it("parses a sent message payload", () => {
75 const response = parseSendMessageResponse(createMessage({ id: "msg-3" }));
76
77 expect(response.id).toBe("msg-3");
78 expect(response.text).toBe("hello");
79 });
80
81 it("rejects invalid conversations", () => {
82 expect(() => parseListConvosResponse({ convos: [{ nope: true }] })).toThrow(
83 "conversations response contains an invalid conversation",
84 );
85 });
86
87 it("rejects invalid messages", () => {
88 expect(() => parseGetMessagesResponse({ messages: [{ nope: true }] })).toThrow(
89 "messages response contains an invalid message",
90 );
91 });
92});