1import { describe, it } from "@effect/vitest"
2import { Cause, Redacted, Result } from "effect"
3
4import { Url, UrlParams } from "effect/http"
5import {
6 assertFailure,
7 assertInstanceOf,
8 assertSuccess,
9 assertTrue,
10 deepStrictEqual,
11 strictEqual
12} from "../utils/assert.ts"
13
14describe("Url", () => {
15 const testURL = new URL("https://example.com/test")
16
17 const expectUrl = (updatedUrl: URL, expected: string) => {
18 assertTrue(updatedUrl !== testURL)
19 assertTrue(updatedUrl.toString() !== testURL.toString())
20 strictEqual(updatedUrl.toString(), expected)
21 }
22
23 describe("make", () => {
24 it("appends query parameters and hash", () => {
25 assertSuccess(
26 Url.make(
27 "https://example.com/test?existing=true",
28 UrlParams.fromInput([["foo", "bar"], ["foo", "baz"]]),
29 "section"
30 ),
31 new URL("https://example.com/test?existing=true&foo=bar&foo=baz#section")
32 )
33 })
34
35 it("fails when the URL cannot be constructed", () => {
36 const result = Url.make("http://%", UrlParams.empty, undefined)
37
38 assertTrue(Result.isFailure(result))
39 assertInstanceOf(result.failure, Url.UrlError)
40 })
41 })
42
43 describe("fromString", () => {
44 it("parses absolute URLs", () => {
45 const url = Url.fromString(testURL.toString())
46 assertSuccess(url, testURL)
47 })
48
49 it("resolves relative URLs against a base URL", () => {
50 const error = Url.fromString("??")
51 assertFailure(error, new Cause.IllegalArgumentError("Invalid URL: \"??\""))
52 })
53 })
54
55 it("mutate", () => {
56 expectUrl(
57 Url.mutate(testURL, (url) => {
58 url.username = "user"
59 url.password = "pass"
60 }),
61 "https://user:pass@example.com/test"
62 )
63 })
64
65 it("setHash", () => {
66 expectUrl(Url.setHash(testURL, "test"), "https://example.com/test#test")
67 })
68
69 it("setHost", () => {
70 expectUrl(Url.setHost(testURL, "newhost.com"), "https://newhost.com/test")
71 })
72
73 it("setHostname", () => {
74 expectUrl(Url.setHostname(testURL, "newhostname.com"), "https://newhostname.com/test")
75 })
76
77 it("setHref", () => {
78 expectUrl(Url.setHref(testURL, "https://newhref.com"), "https://newhref.com/")
79 })
80
81 it("setPassword", () => {
82 expectUrl(Url.setPassword(testURL, "newpassword"), "https://:newpassword@example.com/test")
83 })
84
85 it("setPassword - Redacted", () => {
86 expectUrl(Url.setPassword(testURL, Redacted.make("newpassword")), "https://:newpassword@example.com/test")
87 })
88
89 it("setPathname", () => {
90 expectUrl(Url.setPathname(testURL, "/newpath"), "https://example.com/newpath")
91 })
92
93 it("setPort", () => {
94 expectUrl(Url.setPort(testURL, "8080"), "https://example.com:8080/test")
95 expectUrl(Url.setPort(testURL, 8080), "https://example.com:8080/test")
96 })
97
98 it("setProtocol", () => {
99 expectUrl(Url.setProtocol(testURL, "http"), "http://example.com/test")
100 })
101
102 it("setSearch", () => {
103 expectUrl(Url.setSearch(testURL, "?key=value"), "https://example.com/test?key=value")
104 })
105
106 it("setUsername", () => {
107 expectUrl(Url.setUsername(testURL, "newuser"), "https://newuser@example.com/test")
108 })
109
110 it("modifyUrlParams", () => {
111 expectUrl(Url.modifyUrlParams(testURL, UrlParams.append("key", "value")), "https://example.com/test?key=value")
112 })
113
114 it("urlParams", () => {
115 const params = Url.urlParams(new URL("https://example.com?foo=bar&baz=qux"))
116 deepStrictEqual(params, UrlParams.fromInput([["foo", "bar"], ["baz", "qux"]]))
117 })
118
119 it("setUrlParams", () => {
120 const url = new URL("https://example.com/?foo=bar&a=b")
121 const newParams = UrlParams.fromInput([["foo", "bar2"], ["baz", "qux"]])
122 const updatedUrl = Url.setUrlParams(url, newParams)
123 expectUrl(updatedUrl, "https://example.com/?foo=bar2&baz=qux")
124 })
125})