@openclaw/bluebubbles 2026.2.17 → 2026.2.19
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 +1 -1
- package/src/chat.test.ts +38 -87
package/package.json
CHANGED
package/src/chat.test.ts
CHANGED
|
@@ -13,29 +13,20 @@ installBlueBubblesFetchTestHooks({
|
|
|
13
13
|
|
|
14
14
|
describe("chat", () => {
|
|
15
15
|
describe("markBlueBubblesChatRead", () => {
|
|
16
|
-
it("does nothing when chatGuid is empty", async () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
it("does nothing when chatGuid is whitespace", async () => {
|
|
25
|
-
await markBlueBubblesChatRead(" ", {
|
|
26
|
-
serverUrl: "http://localhost:1234",
|
|
27
|
-
password: "test",
|
|
28
|
-
});
|
|
16
|
+
it("does nothing when chatGuid is empty or whitespace", async () => {
|
|
17
|
+
for (const chatGuid of ["", " "]) {
|
|
18
|
+
await markBlueBubblesChatRead(chatGuid, {
|
|
19
|
+
serverUrl: "http://localhost:1234",
|
|
20
|
+
password: "test",
|
|
21
|
+
});
|
|
22
|
+
}
|
|
29
23
|
expect(mockFetch).not.toHaveBeenCalled();
|
|
30
24
|
});
|
|
31
25
|
|
|
32
|
-
it("throws when
|
|
26
|
+
it("throws when required credentials are missing", async () => {
|
|
33
27
|
await expect(markBlueBubblesChatRead("chat-guid", {})).rejects.toThrow(
|
|
34
28
|
"serverUrl is required",
|
|
35
29
|
);
|
|
36
|
-
});
|
|
37
|
-
|
|
38
|
-
it("throws when password is missing", async () => {
|
|
39
30
|
await expect(
|
|
40
31
|
markBlueBubblesChatRead("chat-guid", {
|
|
41
32
|
serverUrl: "http://localhost:1234",
|
|
@@ -141,29 +132,20 @@ describe("chat", () => {
|
|
|
141
132
|
});
|
|
142
133
|
|
|
143
134
|
describe("sendBlueBubblesTyping", () => {
|
|
144
|
-
it("does nothing when chatGuid is empty", async () => {
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
it("does nothing when chatGuid is whitespace", async () => {
|
|
153
|
-
await sendBlueBubblesTyping(" ", false, {
|
|
154
|
-
serverUrl: "http://localhost:1234",
|
|
155
|
-
password: "test",
|
|
156
|
-
});
|
|
135
|
+
it("does nothing when chatGuid is empty or whitespace", async () => {
|
|
136
|
+
for (const chatGuid of ["", " "]) {
|
|
137
|
+
await sendBlueBubblesTyping(chatGuid, true, {
|
|
138
|
+
serverUrl: "http://localhost:1234",
|
|
139
|
+
password: "test",
|
|
140
|
+
});
|
|
141
|
+
}
|
|
157
142
|
expect(mockFetch).not.toHaveBeenCalled();
|
|
158
143
|
});
|
|
159
144
|
|
|
160
|
-
it("throws when
|
|
145
|
+
it("throws when required credentials are missing", async () => {
|
|
161
146
|
await expect(sendBlueBubblesTyping("chat-guid", true, {})).rejects.toThrow(
|
|
162
147
|
"serverUrl is required",
|
|
163
148
|
);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
it("throws when password is missing", async () => {
|
|
167
149
|
await expect(
|
|
168
150
|
sendBlueBubblesTyping("chat-guid", true, {
|
|
169
151
|
serverUrl: "http://localhost:1234",
|
|
@@ -171,49 +153,46 @@ describe("chat", () => {
|
|
|
171
153
|
).rejects.toThrow("password is required");
|
|
172
154
|
});
|
|
173
155
|
|
|
174
|
-
it("
|
|
175
|
-
|
|
176
|
-
ok: true,
|
|
177
|
-
text: () => Promise.resolve(""),
|
|
178
|
-
});
|
|
156
|
+
it("does not send typing when private API is disabled", async () => {
|
|
157
|
+
vi.mocked(getCachedBlueBubblesPrivateApiStatus).mockReturnValueOnce(false);
|
|
179
158
|
|
|
180
159
|
await sendBlueBubblesTyping("iMessage;-;+15551234567", true, {
|
|
181
160
|
serverUrl: "http://localhost:1234",
|
|
182
161
|
password: "test",
|
|
183
162
|
});
|
|
184
163
|
|
|
185
|
-
expect(mockFetch).
|
|
186
|
-
expect.stringContaining("/api/v1/chat/iMessage%3B-%3B%2B15551234567/typing"),
|
|
187
|
-
expect.objectContaining({ method: "POST" }),
|
|
188
|
-
);
|
|
164
|
+
expect(mockFetch).not.toHaveBeenCalled();
|
|
189
165
|
});
|
|
190
166
|
|
|
191
|
-
it("
|
|
192
|
-
|
|
167
|
+
it("uses POST for start and DELETE for stop", async () => {
|
|
168
|
+
mockFetch
|
|
169
|
+
.mockResolvedValueOnce({
|
|
170
|
+
ok: true,
|
|
171
|
+
text: () => Promise.resolve(""),
|
|
172
|
+
})
|
|
173
|
+
.mockResolvedValueOnce({
|
|
174
|
+
ok: true,
|
|
175
|
+
text: () => Promise.resolve(""),
|
|
176
|
+
});
|
|
193
177
|
|
|
194
178
|
await sendBlueBubblesTyping("iMessage;-;+15551234567", true, {
|
|
195
179
|
serverUrl: "http://localhost:1234",
|
|
196
180
|
password: "test",
|
|
197
181
|
});
|
|
198
|
-
|
|
199
|
-
expect(mockFetch).not.toHaveBeenCalled();
|
|
200
|
-
});
|
|
201
|
-
|
|
202
|
-
it("sends typing stop with DELETE method", async () => {
|
|
203
|
-
mockFetch.mockResolvedValueOnce({
|
|
204
|
-
ok: true,
|
|
205
|
-
text: () => Promise.resolve(""),
|
|
206
|
-
});
|
|
207
|
-
|
|
208
182
|
await sendBlueBubblesTyping("iMessage;-;+15551234567", false, {
|
|
209
183
|
serverUrl: "http://localhost:1234",
|
|
210
184
|
password: "test",
|
|
211
185
|
});
|
|
212
186
|
|
|
213
|
-
expect(mockFetch).
|
|
214
|
-
|
|
215
|
-
|
|
187
|
+
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
188
|
+
expect(mockFetch.mock.calls[0][0]).toContain(
|
|
189
|
+
"/api/v1/chat/iMessage%3B-%3B%2B15551234567/typing",
|
|
216
190
|
);
|
|
191
|
+
expect(mockFetch.mock.calls[0][1].method).toBe("POST");
|
|
192
|
+
expect(mockFetch.mock.calls[1][0]).toContain(
|
|
193
|
+
"/api/v1/chat/iMessage%3B-%3B%2B15551234567/typing",
|
|
194
|
+
);
|
|
195
|
+
expect(mockFetch.mock.calls[1][1].method).toBe("DELETE");
|
|
217
196
|
});
|
|
218
197
|
|
|
219
198
|
it("includes password in URL query", async () => {
|
|
@@ -297,31 +276,6 @@ describe("chat", () => {
|
|
|
297
276
|
expect(calledUrl).toContain("typing-server:8888");
|
|
298
277
|
expect(calledUrl).toContain("password=typing-pass");
|
|
299
278
|
});
|
|
300
|
-
|
|
301
|
-
it("can start and stop typing in sequence", async () => {
|
|
302
|
-
mockFetch
|
|
303
|
-
.mockResolvedValueOnce({
|
|
304
|
-
ok: true,
|
|
305
|
-
text: () => Promise.resolve(""),
|
|
306
|
-
})
|
|
307
|
-
.mockResolvedValueOnce({
|
|
308
|
-
ok: true,
|
|
309
|
-
text: () => Promise.resolve(""),
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
await sendBlueBubblesTyping("chat-123", true, {
|
|
313
|
-
serverUrl: "http://localhost:1234",
|
|
314
|
-
password: "test",
|
|
315
|
-
});
|
|
316
|
-
await sendBlueBubblesTyping("chat-123", false, {
|
|
317
|
-
serverUrl: "http://localhost:1234",
|
|
318
|
-
password: "test",
|
|
319
|
-
});
|
|
320
|
-
|
|
321
|
-
expect(mockFetch).toHaveBeenCalledTimes(2);
|
|
322
|
-
expect(mockFetch.mock.calls[0][1].method).toBe("POST");
|
|
323
|
-
expect(mockFetch.mock.calls[1][1].method).toBe("DELETE");
|
|
324
|
-
});
|
|
325
279
|
});
|
|
326
280
|
|
|
327
281
|
describe("setGroupIconBlueBubbles", () => {
|
|
@@ -343,13 +297,10 @@ describe("chat", () => {
|
|
|
343
297
|
).rejects.toThrow("image buffer");
|
|
344
298
|
});
|
|
345
299
|
|
|
346
|
-
it("throws when
|
|
300
|
+
it("throws when required credentials are missing", async () => {
|
|
347
301
|
await expect(
|
|
348
302
|
setGroupIconBlueBubbles("chat-guid", new Uint8Array([1, 2, 3]), "icon.png", {}),
|
|
349
303
|
).rejects.toThrow("serverUrl is required");
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
it("throws when password is missing", async () => {
|
|
353
304
|
await expect(
|
|
354
305
|
setGroupIconBlueBubbles("chat-guid", new Uint8Array([1, 2, 3]), "icon.png", {
|
|
355
306
|
serverUrl: "http://localhost:1234",
|