Skip to main content

max / makenotwork

4.7 KB · 124 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.signup("linkuser", "linkuser@test.com", "password123").await;
10
11 // Create a link
12 let resp = h.client.post_form(
13 "/api/links",
14 "url=https%3A%2F%2Fexample.com&title=My+Website&description=Personal+site",
15 ).await;
16 assert!(resp.status.is_success(), "Create link failed: {} {}", resp.status, resp.text);
17 let link: Value = resp.json();
18 assert_eq!(link["url"].as_str().unwrap(), "https://example.com");
19 assert_eq!(link["title"].as_str().unwrap(), "My Website");
20 assert_eq!(link["description"].as_str().unwrap(), "Personal site");
21 let link_id = link["id"].as_str().expect("link should have id");
22
23 // Update only the title (partial update via JSON)
24 let resp = h.client.put_json(
25 &format!("/api/links/{}", link_id),
26 r#"{"title": "Updated Title"}"#,
27 ).await;
28 assert!(resp.status.is_success(), "Update link failed: {} {}", resp.status, resp.text);
29 let updated: Value = resp.json();
30 assert_eq!(updated["title"].as_str().unwrap(), "Updated Title");
31 assert_eq!(updated["url"].as_str().unwrap(), "https://example.com", "URL should remain unchanged");
32
33 // Delete the link
34 let resp = h.client.delete(&format!("/api/links/{}", link_id)).await;
35 assert_eq!(resp.status, 204, "Delete should return 204");
36 }
37
38 #[tokio::test]
39 async fn custom_link_reorder() {
40 let mut h = TestHarness::new().await;
41 let _user_id = h.signup("linkorder", "linkorder@test.com", "password123").await;
42
43 // Create 3 links
44 let resp = h.client.post_form("/api/links", "url=https%3A%2F%2Fa.com&title=Link+A").await;
45 let link_a: Value = resp.json();
46 let id_a = link_a["id"].as_str().unwrap();
47
48 let resp = h.client.post_form("/api/links", "url=https%3A%2F%2Fb.com&title=Link+B").await;
49 let link_b: Value = resp.json();
50 let id_b = link_b["id"].as_str().unwrap();
51
52 let resp = h.client.post_form("/api/links", "url=https%3A%2F%2Fc.com&title=Link+C").await;
53 let link_c: Value = resp.json();
54 let id_c = link_c["id"].as_str().unwrap();
55
56 // Reorder: C, A, B
57 let reorder_body = format!(r#"{{"link_ids": ["{}", "{}", "{}"]}}"#, id_c, id_a, id_b);
58 let resp = h.client.put_json("/api/links/reorder", &reorder_body).await;
59 assert_eq!(resp.status, 204, "Reorder should return 204, got {}: {}", resp.status, resp.text);
60
61 // Verify order via direct SQL
62 let rows: Vec<(String, i32)> = sqlx::query_as(
63 "SELECT title, sort_order FROM custom_links WHERE user_id = (SELECT id FROM users WHERE username = 'linkorder') ORDER BY sort_order"
64 )
65 .fetch_all(&h.db)
66 .await
67 .unwrap();
68
69 assert_eq!(rows.len(), 3);
70 assert_eq!(rows[0].0, "Link C", "First should be Link C");
71 assert_eq!(rows[1].0, "Link A", "Second should be Link A");
72 assert_eq!(rows[2].0, "Link B", "Third should be Link B");
73 }
74
75 #[tokio::test]
76 async fn custom_link_validation_errors() {
77 let mut h = TestHarness::new().await;
78 let _user_id = h.signup("linkval", "linkval@test.com", "password123").await;
79
80 // Bad URL scheme (ftp)
81 let resp = h.client.post_form(
82 "/api/links",
83 "url=ftp%3A%2F%2Fexample.com&title=Bad+Link",
84 ).await;
85 assert_eq!(resp.status, 422, "Bad URL scheme should return 422, got {}: {}", resp.status, resp.text);
86
87 // Empty title
88 let resp = h.client.post_form(
89 "/api/links",
90 "url=https%3A%2F%2Fexample.com&title=",
91 ).await;
92 assert_eq!(resp.status, 422, "Empty title should return 422, got {}: {}", resp.status, resp.text);
93 }
94
95 #[tokio::test]
96 async fn custom_link_auth_other_user() {
97 let mut h = TestHarness::new().await;
98
99 // User A creates a link
100 let _user_a = h.signup("linkowner", "linkowner@test.com", "password123").await;
101 let resp = h.client.post_form(
102 "/api/links",
103 "url=https%3A%2F%2Fexample.com&title=Owner+Link",
104 ).await;
105 assert!(resp.status.is_success());
106 let link: Value = resp.json();
107 let link_id = link["id"].as_str().unwrap();
108
109 // Switch to User B
110 h.client.post_form("/logout", "").await;
111 let _user_b = h.signup("linkthief", "linkthief@test.com", "password123").await;
112
113 // User B tries to update User A's link
114 let resp = h.client.put_json(
115 &format!("/api/links/{}", link_id),
116 r#"{"title": "Stolen"}"#,
117 ).await;
118 assert_eq!(resp.status, 404, "Updating another user's link should return 404, got {}", resp.status);
119
120 // User B tries to delete User A's link
121 let resp = h.client.delete(&format!("/api/links/{}", link_id)).await;
122 assert_eq!(resp.status, 404, "Deleting another user's link should return 404, got {}", resp.status);
123 }
124