Skip to main content

max / makenotwork

5.2 KB · 181 lines History Blame Raw
1 //! Custom profile link CRUD and reorder workflow tests.
2
3 use crate::harness::TestHarness;
4 use serde_json::Value;
5
6 #[tokio::test]
7 async fn custom_link_crud_lifecycle() {
8 let mut h = TestHarness::new().await;
9 let _user_id = h
10 .signup("linkuser", "linkuser@test.com", "password123")
11 .await;
12
13 // Create a link
14 let resp = h
15 .client
16 .post_form(
17 "/api/links",
18 "url=https%3A%2F%2Fexample.com&title=My+Website&description=Personal+site",
19 )
20 .await;
21 assert_eq!(
22 resp.status, 200,
23 "Create link failed: {} {}",
24 resp.status, resp.text
25 );
26 let link: Value = resp.json();
27 assert_eq!(link["url"].as_str().unwrap(), "https://example.com");
28 assert_eq!(link["title"].as_str().unwrap(), "My Website");
29 assert_eq!(link["description"].as_str().unwrap(), "Personal site");
30 let link_id = link["id"].as_str().expect("link should have id");
31
32 // Update only the title (partial update via JSON)
33 let resp = h
34 .client
35 .put_json(
36 &format!("/api/links/{link_id}"),
37 r#"{"title": "Updated Title"}"#,
38 )
39 .await;
40 assert_eq!(
41 resp.status, 200,
42 "Update link failed: {} {}",
43 resp.status, resp.text
44 );
45 let updated: Value = resp.json();
46 assert_eq!(updated["title"].as_str().unwrap(), "Updated Title");
47 assert_eq!(
48 updated["url"].as_str().unwrap(),
49 "https://example.com",
50 "URL should remain unchanged"
51 );
52
53 let resp = h.client.delete(&format!("/api/links/{link_id}")).await;
54 assert_eq!(resp.status, 204, "Delete should return 204");
55 }
56
57 #[tokio::test]
58 async fn custom_link_reorder() {
59 let mut h = TestHarness::new().await;
60 let _user_id = h
61 .signup("linkorder", "linkorder@test.com", "password123")
62 .await;
63
64 // Create 3 links
65 let resp = h
66 .client
67 .post_form("/api/links", "url=https%3A%2F%2Fa.com&title=Link+A")
68 .await;
69 let link_a: Value = resp.json();
70 let id_a = link_a["id"].as_str().unwrap();
71
72 let resp = h
73 .client
74 .post_form("/api/links", "url=https%3A%2F%2Fb.com&title=Link+B")
75 .await;
76 let link_b: Value = resp.json();
77 let id_b = link_b["id"].as_str().unwrap();
78
79 let resp = h
80 .client
81 .post_form("/api/links", "url=https%3A%2F%2Fc.com&title=Link+C")
82 .await;
83 let link_c: Value = resp.json();
84 let id_c = link_c["id"].as_str().unwrap();
85
86 // Reorder: C, A, B
87 let reorder_body = format!(r#"{{"link_ids": ["{id_c}", "{id_a}", "{id_b}"]}}"#);
88 let resp = h.client.put_json("/api/links/reorder", &reorder_body).await;
89 assert_eq!(
90 resp.status, 204,
91 "Reorder should return 204, got {}: {}",
92 resp.status, resp.text
93 );
94
95 // Verify order via direct SQL
96 let rows: Vec<(String, i32)> = sqlx::query_as(
97 "SELECT title, sort_order FROM custom_links WHERE user_id = (SELECT id FROM users WHERE username = 'linkorder') ORDER BY sort_order"
98 )
99 .fetch_all(&h.db)
100 .await
101 .unwrap();
102
103 assert_eq!(rows.len(), 3);
104 assert_eq!(rows[0].0, "Link C", "First should be Link C");
105 assert_eq!(rows[1].0, "Link A", "Second should be Link A");
106 assert_eq!(rows[2].0, "Link B", "Third should be Link B");
107 }
108
109 #[tokio::test]
110 async fn custom_link_validation_errors() {
111 let mut h = TestHarness::new().await;
112 let _user_id = h.signup("linkval", "linkval@test.com", "password123").await;
113
114 // Bad URL scheme (ftp)
115 let resp = h
116 .client
117 .post_form("/api/links", "url=ftp%3A%2F%2Fexample.com&title=Bad+Link")
118 .await;
119 assert_eq!(
120 resp.status, 422,
121 "Bad URL scheme should return 422, got {}: {}",
122 resp.status, resp.text
123 );
124
125 // Empty title
126 let resp = h
127 .client
128 .post_form("/api/links", "url=https%3A%2F%2Fexample.com&title=")
129 .await;
130 assert_eq!(
131 resp.status, 422,
132 "Empty title should return 422, got {}: {}",
133 resp.status, resp.text
134 );
135 }
136
137 #[tokio::test]
138 async fn custom_link_auth_other_user() {
139 let mut h = TestHarness::new().await;
140
141 // User A creates a link
142 let _user_a = h
143 .signup("linkowner", "linkowner@test.com", "password123")
144 .await;
145 let resp = h
146 .client
147 .post_form(
148 "/api/links",
149 "url=https%3A%2F%2Fexample.com&title=Owner+Link",
150 )
151 .await;
152 assert_eq!(resp.status, 200, "{}", resp.text);
153 let link: Value = resp.json();
154 let link_id = link["id"].as_str().unwrap();
155
156 // Switch to User B
157 h.client.post_form("/logout", "").await;
158 let _user_b = h
159 .signup("linkthief", "linkthief@test.com", "password123")
160 .await;
161
162 // User B tries to update User A's link
163 let resp = h
164 .client
165 .put_json(&format!("/api/links/{link_id}"), r#"{"title": "Stolen"}"#)
166 .await;
167 assert_eq!(
168 resp.status, 404,
169 "Updating another user's link should return 404, got {}",
170 resp.status
171 );
172
173 // User B tries to delete User A's link
174 let resp = h.client.delete(&format!("/api/links/{link_id}")).await;
175 assert_eq!(
176 resp.status, 404,
177 "Deleting another user's link should return 404, got {}",
178 resp.status
179 );
180 }
181