Skip to content

Commit 0167262

Browse files
committed
feat: support webcal
1 parent 275b70e commit 0167262

7 files changed

Lines changed: 675 additions & 19 deletions

File tree

Lines changed: 354 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,354 @@
1+
/**
2+
* Webcal Integration Tests
3+
* Tests for webcal URL conversion and integration functionality
4+
*/
5+
6+
import { WebcalUrlConverter } from "../utils/ics/WebcalUrlConverter";
7+
8+
describe("WebcalUrlConverter", () => {
9+
describe("convertWebcalUrl", () => {
10+
test("should convert webcal URL to https", () => {
11+
const url = "webcal://p110-caldav.icloud.com/published/2/test";
12+
const result = WebcalUrlConverter.convertWebcalUrl(url);
13+
14+
expect(result.success).toBe(true);
15+
expect(result.wasWebcal).toBe(true);
16+
expect(result.convertedUrl).toBe(
17+
"https://p110-caldav.icloud.com/published/2/test"
18+
);
19+
expect(result.originalUrl).toBe(url);
20+
});
21+
22+
test("should convert webcal URL with path and query parameters", () => {
23+
const url =
24+
"webcal://example.com/calendar.ics?param=value&other=test";
25+
const result = WebcalUrlConverter.convertWebcalUrl(url);
26+
27+
expect(result.success).toBe(true);
28+
expect(result.wasWebcal).toBe(true);
29+
expect(result.convertedUrl).toBe(
30+
"https://example.com/calendar.ics?param=value&other=test"
31+
);
32+
});
33+
34+
test("should handle case-insensitive webcal protocol", () => {
35+
const url = "WEBCAL://example.com/calendar.ics";
36+
const result = WebcalUrlConverter.convertWebcalUrl(url);
37+
38+
expect(result.success).toBe(true);
39+
expect(result.wasWebcal).toBe(true);
40+
expect(result.convertedUrl).toBe(
41+
"https://example.com/calendar.ics"
42+
);
43+
});
44+
45+
test("should use http for localhost", () => {
46+
const url = "webcal://localhost:3000/calendar.ics";
47+
const result = WebcalUrlConverter.convertWebcalUrl(url);
48+
49+
expect(result.success).toBe(true);
50+
expect(result.wasWebcal).toBe(true);
51+
expect(result.convertedUrl).toBe(
52+
"http://localhost:3000/calendar.ics"
53+
);
54+
});
55+
56+
test("should use http for 127.0.0.1", () => {
57+
const url = "webcal://127.0.0.1:8080/calendar.ics";
58+
const result = WebcalUrlConverter.convertWebcalUrl(url);
59+
60+
expect(result.success).toBe(true);
61+
expect(result.wasWebcal).toBe(true);
62+
expect(result.convertedUrl).toBe(
63+
"http://127.0.0.1:8080/calendar.ics"
64+
);
65+
});
66+
67+
test("should accept valid https URL without conversion", () => {
68+
const url = "https://example.com/calendar.ics";
69+
const result = WebcalUrlConverter.convertWebcalUrl(url);
70+
71+
expect(result.success).toBe(true);
72+
expect(result.wasWebcal).toBe(false);
73+
expect(result.convertedUrl).toBe(url);
74+
});
75+
76+
test("should accept valid http URL without conversion", () => {
77+
const url = "http://example.com/calendar.ics";
78+
const result = WebcalUrlConverter.convertWebcalUrl(url);
79+
80+
expect(result.success).toBe(true);
81+
expect(result.wasWebcal).toBe(false);
82+
expect(result.convertedUrl).toBe(url);
83+
});
84+
85+
test("should reject empty URL", () => {
86+
const result = WebcalUrlConverter.convertWebcalUrl("");
87+
88+
expect(result.success).toBe(false);
89+
expect(result.wasWebcal).toBe(false);
90+
expect(result.error).toContain("URL cannot be empty");
91+
});
92+
93+
test("should reject whitespace-only URL", () => {
94+
const result = WebcalUrlConverter.convertWebcalUrl(" ");
95+
96+
expect(result.success).toBe(false);
97+
expect(result.wasWebcal).toBe(false);
98+
expect(result.error).toContain("URL cannot be empty");
99+
});
100+
101+
test("should reject invalid URL format", () => {
102+
const result = WebcalUrlConverter.convertWebcalUrl("not-a-url");
103+
104+
expect(result.success).toBe(false);
105+
expect(result.wasWebcal).toBe(false);
106+
expect(result.error).toContain("Invalid URL format");
107+
});
108+
109+
test("should reject unsupported protocol", () => {
110+
const result = WebcalUrlConverter.convertWebcalUrl(
111+
"ftp://example.com/calendar.ics"
112+
);
113+
114+
expect(result.success).toBe(false);
115+
expect(result.wasWebcal).toBe(false);
116+
expect(result.error).toContain("Invalid URL format");
117+
});
118+
119+
test("should handle URL with fragments", () => {
120+
const url = "webcal://example.com/calendar.ics#section";
121+
const result = WebcalUrlConverter.convertWebcalUrl(url);
122+
123+
expect(result.success).toBe(true);
124+
expect(result.wasWebcal).toBe(true);
125+
expect(result.convertedUrl).toBe(
126+
"https://example.com/calendar.ics#section"
127+
);
128+
});
129+
130+
test("should handle URL with authentication info", () => {
131+
const url = "webcal://user:pass@example.com/calendar.ics";
132+
const result = WebcalUrlConverter.convertWebcalUrl(url);
133+
134+
expect(result.success).toBe(true);
135+
expect(result.wasWebcal).toBe(true);
136+
expect(result.convertedUrl).toBe(
137+
"https://user:pass@example.com/calendar.ics"
138+
);
139+
});
140+
});
141+
142+
describe("isWebcalUrl", () => {
143+
test("should identify webcal URLs", () => {
144+
expect(WebcalUrlConverter.isWebcalUrl("webcal://example.com")).toBe(
145+
true
146+
);
147+
expect(WebcalUrlConverter.isWebcalUrl("WEBCAL://example.com")).toBe(
148+
true
149+
);
150+
expect(WebcalUrlConverter.isWebcalUrl("WebCal://example.com")).toBe(
151+
true
152+
);
153+
});
154+
155+
test("should not identify non-webcal URLs", () => {
156+
expect(WebcalUrlConverter.isWebcalUrl("https://example.com")).toBe(
157+
false
158+
);
159+
expect(WebcalUrlConverter.isWebcalUrl("http://example.com")).toBe(
160+
false
161+
);
162+
expect(WebcalUrlConverter.isWebcalUrl("ftp://example.com")).toBe(
163+
false
164+
);
165+
expect(WebcalUrlConverter.isWebcalUrl("example.com")).toBe(false);
166+
expect(WebcalUrlConverter.isWebcalUrl("")).toBe(false);
167+
});
168+
169+
test("should handle URLs with whitespace", () => {
170+
expect(
171+
WebcalUrlConverter.isWebcalUrl(" webcal://example.com ")
172+
).toBe(true);
173+
expect(
174+
WebcalUrlConverter.isWebcalUrl(" https://example.com ")
175+
).toBe(false);
176+
});
177+
});
178+
179+
describe("getFetchUrl", () => {
180+
test("should return converted URL for valid webcal", () => {
181+
const url = "webcal://example.com/calendar.ics";
182+
const fetchUrl = WebcalUrlConverter.getFetchUrl(url);
183+
184+
expect(fetchUrl).toBe("https://example.com/calendar.ics");
185+
});
186+
187+
test("should return original URL for valid http/https", () => {
188+
const url = "https://example.com/calendar.ics";
189+
const fetchUrl = WebcalUrlConverter.getFetchUrl(url);
190+
191+
expect(fetchUrl).toBe(url);
192+
});
193+
194+
test("should return null for invalid URL", () => {
195+
const fetchUrl = WebcalUrlConverter.getFetchUrl("invalid-url");
196+
197+
expect(fetchUrl).toBe(null);
198+
});
199+
200+
test("should return null for empty URL", () => {
201+
const fetchUrl = WebcalUrlConverter.getFetchUrl("");
202+
203+
expect(fetchUrl).toBe(null);
204+
});
205+
});
206+
207+
describe("getConversionDescription", () => {
208+
test("should describe successful webcal conversion", () => {
209+
const result = WebcalUrlConverter.convertWebcalUrl(
210+
"webcal://example.com/calendar.ics"
211+
);
212+
const description =
213+
WebcalUrlConverter.getConversionDescription(result);
214+
215+
expect(description).toContain("Converted webcal URL to:");
216+
expect(description).toContain("https://example.com/calendar.ics");
217+
});
218+
219+
test("should describe valid HTTP URL", () => {
220+
const result = WebcalUrlConverter.convertWebcalUrl(
221+
"https://example.com/calendar.ics"
222+
);
223+
const description =
224+
WebcalUrlConverter.getConversionDescription(result);
225+
226+
expect(description).toContain("Valid HTTP/HTTPS URL:");
227+
expect(description).toContain("https://example.com/calendar.ics");
228+
});
229+
230+
test("should describe conversion errors", () => {
231+
const result = WebcalUrlConverter.convertWebcalUrl("invalid-url");
232+
const description =
233+
WebcalUrlConverter.getConversionDescription(result);
234+
235+
expect(description).toContain("Error:");
236+
expect(description).toContain("Invalid URL format");
237+
});
238+
});
239+
240+
describe("Real-world URL scenarios", () => {
241+
test("should handle iCloud webcal URL", () => {
242+
const url =
243+
"webcal://p110-caldav.icloud.com/published/2/MTE1OTQ3OTAzNDAxMTU5NN9Kxibs06tCYSsC7GTzrvyViPGkfbZEn_8WMVGFcOzyjJ3ldmeaW-8szOZJQvs8jlkEVQoJJYDGsYisXTi9sVU";
244+
const result = WebcalUrlConverter.convertWebcalUrl(url);
245+
246+
expect(result.success).toBe(true);
247+
expect(result.wasWebcal).toBe(true);
248+
expect(result.convertedUrl).toBe(
249+
"https://p110-caldav.icloud.com/published/2/MTE1OTQ3OTAzNDAxMTU5NN9Kxibs06tCYSsC7GTzrvyViPGkfbZEn_8WMVGFcOzyjJ3ldmeaW-8szOZJQvs8jlkEVQoJJYDGsYisXTi9sVU"
250+
);
251+
});
252+
253+
test("should handle Google Calendar webcal URL", () => {
254+
const url =
255+
"webcal://calendar.google.com/calendar/ical/example%40gmail.com/public/basic.ics";
256+
const result = WebcalUrlConverter.convertWebcalUrl(url);
257+
258+
expect(result.success).toBe(true);
259+
expect(result.wasWebcal).toBe(true);
260+
expect(result.convertedUrl).toBe(
261+
"https://calendar.google.com/calendar/ical/example%40gmail.com/public/basic.ics"
262+
);
263+
});
264+
265+
test("should handle Outlook webcal URL", () => {
266+
const url =
267+
"webcal://outlook.live.com/owa/calendar/00000000-0000-0000-0000-000000000000/00000000-0000-0000-0000-000000000000/cid-0000000000000000/calendar.ics";
268+
const result = WebcalUrlConverter.convertWebcalUrl(url);
269+
270+
expect(result.success).toBe(true);
271+
expect(result.wasWebcal).toBe(true);
272+
expect(result.convertedUrl).toBe(
273+
"https://outlook.live.com/owa/calendar/00000000-0000-0000-0000-000000000000/00000000-0000-0000-0000-000000000000/cid-0000000000000000/calendar.ics"
274+
);
275+
});
276+
277+
test("should handle CalDAV server webcal URL", () => {
278+
const url =
279+
"webcal://caldav.example.com:8443/calendars/user/calendar.ics";
280+
const result = WebcalUrlConverter.convertWebcalUrl(url);
281+
282+
expect(result.success).toBe(true);
283+
expect(result.wasWebcal).toBe(true);
284+
expect(result.convertedUrl).toBe(
285+
"https://caldav.example.com:8443/calendars/user/calendar.ics"
286+
);
287+
});
288+
});
289+
290+
describe("Edge cases", () => {
291+
test("should handle URL with unusual characters", () => {
292+
const url =
293+
"webcal://example.com/calendar-with-dashes_and_underscores.ics";
294+
const result = WebcalUrlConverter.convertWebcalUrl(url);
295+
296+
expect(result.success).toBe(true);
297+
expect(result.convertedUrl).toBe(
298+
"https://example.com/calendar-with-dashes_and_underscores.ics"
299+
);
300+
});
301+
302+
test("should handle URL with encoded characters", () => {
303+
const url = "webcal://example.com/calendar%20with%20spaces.ics";
304+
const result = WebcalUrlConverter.convertWebcalUrl(url);
305+
306+
expect(result.success).toBe(true);
307+
expect(result.convertedUrl).toBe(
308+
"https://example.com/calendar%20with%20spaces.ics"
309+
);
310+
});
311+
312+
test("should handle URL with multiple subdirectories", () => {
313+
const url =
314+
"webcal://example.com/path/to/deeply/nested/calendar.ics";
315+
const result = WebcalUrlConverter.convertWebcalUrl(url);
316+
317+
expect(result.success).toBe(true);
318+
expect(result.convertedUrl).toBe(
319+
"https://example.com/path/to/deeply/nested/calendar.ics"
320+
);
321+
});
322+
323+
test("should handle URL with complex query parameters", () => {
324+
const url =
325+
"webcal://example.com/calendar.ics?timezone=UTC&format=ical&filter=work";
326+
const result = WebcalUrlConverter.convertWebcalUrl(url);
327+
328+
expect(result.success).toBe(true);
329+
expect(result.convertedUrl).toBe(
330+
"https://example.com/calendar.ics?timezone=UTC&format=ical&filter=work"
331+
);
332+
});
333+
});
334+
});
335+
336+
describe("Webcal Integration with ICS Manager", () => {
337+
// Mock tests to verify integration points
338+
test("should validate webcal URL in settings", () => {
339+
// This would test the integration with IcsSettingsTab
340+
const testUrl = "webcal://example.com/calendar.ics";
341+
const result = WebcalUrlConverter.convertWebcalUrl(testUrl);
342+
343+
expect(result.success).toBe(true);
344+
expect(result.wasWebcal).toBe(true);
345+
});
346+
347+
test("should convert webcal URL in fetch process", () => {
348+
// This would test the integration with IcsManager
349+
const testUrl = "webcal://example.com/calendar.ics";
350+
const fetchUrl = WebcalUrlConverter.getFetchUrl(testUrl);
351+
352+
expect(fetchUrl).toBe("https://example.com/calendar.ics");
353+
});
354+
});

0 commit comments

Comments
 (0)