Skip to main content

max / multithreaded

6.8 KB · 207 lines History Blame Raw
1 use crate::harness::TestHarness;
2
3 #[tokio::test]
4 async fn profile_page_shows_user_info() {
5 let mut h = TestHarness::new().await;
6 let user_id = h.login_as("profileuser").await;
7 let comm_id = h.create_community("TestCommunity", "test-comm").await;
8 h.create_category(comm_id, "General", "general").await;
9 h.add_membership(user_id, comm_id, "member").await;
10
11 let resp = h.client.get("/p/test-comm/u/profileuser").await;
12 assert_eq!(resp.status.as_u16(), 200, "profile page should load");
13 assert!(resp.text.contains("profileuser"), "should show username");
14 assert!(resp.text.contains("member"), "should show role badge");
15 assert!(resp.text.contains("Joined"), "should show join date");
16 }
17
18 #[tokio::test]
19 async fn profile_page_shows_activity() {
20 let mut h = TestHarness::new().await;
21 let user_id = h.login_as("activeuser").await;
22 let comm_id = h.create_community("ActivityComm", "activity-comm").await;
23 let cat_id = h.create_category(comm_id, "General", "general").await;
24 h.add_membership(user_id, comm_id, "member").await;
25
26 // Create a thread (user is thread author)
27 let thread_id = h
28 .create_thread_with_post(cat_id, user_id, "My Thread", "Hello world")
29 .await;
30
31 // Create a reply in another thread
32 let thread_id_2 = h
33 .create_thread_with_post(cat_id, user_id, "Another Thread", "Second post")
34 .await;
35 mt_db::mutations::create_post(
36 &h.db,
37 thread_id_2,
38 user_id,
39 "A reply",
40 "<p>A reply</p>",
41 )
42 .await
43 .unwrap();
44
45 let resp = h.client.get("/p/activity-comm/u/activeuser").await;
46 assert_eq!(resp.status.as_u16(), 200);
47 assert!(resp.text.contains("My Thread"), "should list thread activity");
48 assert!(resp.text.contains("Another Thread"), "should list reply activity");
49
50 // Verify thread_id link is present
51 assert!(
52 resp.text.contains(&thread_id.to_string()),
53 "should link to thread"
54 );
55 }
56
57 #[tokio::test]
58 async fn profile_nonmember_returns_404() {
59 let mut h = TestHarness::new().await;
60 h.login_as("outsider").await;
61 let _comm_id = h.create_community("ClosedComm", "closed-comm").await;
62
63 // User exists but is not a member
64 let resp = h.client.get("/p/closed-comm/u/outsider").await;
65 assert_eq!(resp.status.as_u16(), 404, "non-member should get 404");
66 }
67
68 #[tokio::test]
69 async fn profile_nonexistent_user_404() {
70 let mut h = TestHarness::new().await;
71 h.login_as("someuser").await;
72 let _comm_id = h.create_community("SomeComm", "some-comm").await;
73
74 let resp = h.client.get("/p/some-comm/u/nobodyhere").await;
75 assert_eq!(resp.status.as_u16(), 404, "nonexistent user should get 404");
76 }
77
78 #[tokio::test]
79 async fn profile_suspended_community_blocked() {
80 let mut h = TestHarness::new().await;
81 let user_id = h.login_as("suspendedfan").await;
82 let comm_id = h.create_community("SuspendedComm", "suspended-comm").await;
83 h.add_membership(user_id, comm_id, "member").await;
84
85 // Suspend the community
86 sqlx::query("UPDATE communities SET suspended_at = now() WHERE id = $1")
87 .bind(comm_id)
88 .execute(&h.db)
89 .await
90 .unwrap();
91
92 let resp = h.client.get("/p/suspended-comm/u/suspendedfan").await;
93 assert_eq!(
94 resp.status.as_u16(),
95 403,
96 "suspended community should return 403"
97 );
98 }
99
100 #[tokio::test]
101 async fn api_summary_requires_auth() {
102 let mut h = TestHarness::new().await;
103 // Don't log in — make unauthenticated request
104 h.client.get("/").await; // establish session
105
106 let user_id = uuid::Uuid::new_v4();
107 let resp = h
108 .client
109 .get(&format!("/api/user/{}/summary", user_id))
110 .await;
111 assert_eq!(resp.status.as_u16(), 401, "unauthenticated should get 401");
112 }
113
114 #[tokio::test]
115 async fn api_summary_returns_memberships() {
116 let mut h = TestHarness::new().await;
117 let user_id = h.login_as("summaryuser").await;
118 let comm_id = h.create_community("SummaryComm", "summary-comm").await;
119 h.add_membership(user_id, comm_id, "member").await;
120
121 let resp = h
122 .client
123 .get(&format!("/api/user/{}/summary", user_id))
124 .await;
125 assert_eq!(resp.status.as_u16(), 200, "should return 200");
126
127 let json: serde_json::Value = resp.json();
128 let memberships = json["memberships"].as_array().unwrap();
129 assert_eq!(memberships.len(), 1, "should have one membership");
130 assert_eq!(memberships[0]["community_name"], "SummaryComm");
131 assert_eq!(memberships[0]["community_slug"], "summary-comm");
132 assert_eq!(memberships[0]["role"], "member");
133 }
134
135 #[tokio::test]
136 async fn api_summary_only_own_data() {
137 let mut h = TestHarness::new().await;
138 let _user_id = h.login_as("snoop").await;
139
140 // Try to access another user's summary
141 let other_id = uuid::Uuid::new_v4();
142 let resp = h
143 .client
144 .get(&format!("/api/user/{}/summary", other_id))
145 .await;
146 assert_eq!(
147 resp.status.as_u16(),
148 403,
149 "accessing other user's data should return 403"
150 );
151 }
152
153 #[tokio::test]
154 async fn profile_shows_endorsement_count() {
155 let mut h = TestHarness::new().await;
156 let author_id = h.login_as("endorsedauthor").await;
157 let comm_id = h.create_community("EndorseComm", "endorse-comm").await;
158 let cat_id = h.create_category(comm_id, "General", "general").await;
159 h.add_membership(author_id, comm_id, "member").await;
160
161 // Author creates a thread with a post
162 let thread_id = h
163 .create_thread_with_post(cat_id, author_id, "Great Thread", "Great content")
164 .await;
165
166 // Get the first post ID
167 let posts = mt_db::queries::list_posts_in_thread(&h.db, thread_id).await.unwrap();
168 let post_id = posts[0].id;
169
170 // Another user endorses the post
171 let endorser_id = h.login_as("endorser1").await;
172 h.add_membership(endorser_id, comm_id, "member").await;
173 mt_db::mutations::toggle_endorsement(&h.db, post_id, endorser_id)
174 .await
175 .unwrap();
176
177 // Check the author's profile shows endorsement count
178 let resp = h.client.get("/p/endorse-comm/u/endorsedauthor").await;
179 assert_eq!(resp.status.as_u16(), 200);
180 assert!(
181 resp.text.contains("1 endorsement received"),
182 "Profile should show endorsement count. Body: {}",
183 &resp.text[..500.min(resp.text.len())]
184 );
185 }
186
187 #[tokio::test]
188 async fn tracking_info_page_loads() {
189 let mut h = TestHarness::new().await;
190 h.login_as("infouser").await;
191
192 let resp = h.client.get("/about/tracking").await;
193 assert_eq!(resp.status.as_u16(), 200);
194 assert!(
195 resp.text.contains("How Tracking Works"),
196 "Should show tracking info heading"
197 );
198 assert!(
199 resp.text.contains("localStorage"),
200 "Should explain localStorage tracking"
201 );
202 assert!(
203 resp.text.contains("No third-party"),
204 "Should mention no third-party tracking"
205 );
206 }
207