Skip to main content

max / makenotwork

9.8 KB · 313 lines History Blame Raw
1 use crate::harness::TestHarness;
2
3 #[tokio::test]
4 async fn directory_pagination_shows_limited_communities() {
5 let mut h = TestHarness::new().await;
6
7 // Create 30 communities (page size is 25)
8 for i in 0..30 {
9 h.create_community(&format!("Community {:02}", i), &format!("comm-{:02}", i))
10 .await;
11 }
12
13 // Page 1 should show 25
14 let resp = h.client.get("/").await;
15 assert!(resp.status.is_success());
16 assert!(
17 resp.text.contains("Page 1 of 2"),
18 "Should show pagination info: {}", &resp.text[..200.min(resp.text.len())]
19 );
20 assert!(
21 resp.text.contains("Next"),
22 "Should show Next link on page 1"
23 );
24 assert!(
25 !resp.text.contains("Previous"),
26 "Should not show Previous link on page 1"
27 );
28
29 // Page 2 should show the remaining 5
30 let resp = h.client.get("/?page=2").await;
31 assert!(resp.status.is_success());
32 assert!(
33 resp.text.contains("Previous"),
34 "Should show Previous link on page 2"
35 );
36 }
37
38 #[tokio::test]
39 async fn empty_category_shows_no_threads() {
40 let mut h = TestHarness::new().await;
41 let comm_id = h.create_community("Test", "test").await;
42 let _cat_id = h.create_category(comm_id, "General", "general").await;
43
44 let resp = h.client.get("/p/test/general").await;
45
46 assert!(resp.status.is_success());
47 assert!(
48 resp.text.contains("No threads yet"),
49 "expected empty state message"
50 );
51 // Should not render pagination
52 assert!(
53 !resp.text.contains("pagination"),
54 "pagination should not appear with 0 threads"
55 );
56 }
57
58 #[tokio::test]
59 async fn page_beyond_max_shows_last_page() {
60 let mut h = TestHarness::new().await;
61 let user_id = h.login_as("pager").await;
62 let comm_id = h.create_community("Test", "test").await;
63 let cat_id = h.create_category(comm_id, "General", "general").await;
64 h.add_membership(user_id, comm_id, "member").await;
65
66 // Create one thread
67 h.create_thread_with_post(cat_id, user_id, "Thread One", "body")
68 .await;
69
70 // Request page=999
71 let resp = h.client.get("/p/test/general?page=999").await;
72
73 assert!(resp.status.is_success());
74 // Should still show the thread (clamped to page 1)
75 assert!(
76 resp.text.contains("Thread One"),
77 "thread should be visible on clamped page"
78 );
79 }
80
81 #[tokio::test]
82 async fn page_zero_treated_as_page_one() {
83 let mut h = TestHarness::new().await;
84 let user_id = h.login_as("pager").await;
85 let comm_id = h.create_community("Test", "test").await;
86 let cat_id = h.create_category(comm_id, "General", "general").await;
87 h.add_membership(user_id, comm_id, "member").await;
88
89 h.create_thread_with_post(cat_id, user_id, "First Thread", "body")
90 .await;
91
92 let resp = h.client.get("/p/test/general?page=0").await;
93
94 assert!(resp.status.is_success());
95 assert!(
96 resp.text.contains("First Thread"),
97 "thread should be visible with page=0"
98 );
99 }
100
101 #[tokio::test]
102 async fn sort_by_replies_works() {
103 let mut h = TestHarness::new().await;
104 let user_id = h.login_as("sorter").await;
105 let comm_id = h.create_community("Test", "test").await;
106 let cat_id = h.create_category(comm_id, "General", "general").await;
107 h.add_membership(user_id, comm_id, "member").await;
108
109 // Create two threads
110 let _t1 = h
111 .create_thread_with_post(cat_id, user_id, "Few Replies", "body")
112 .await;
113 let t2 = h
114 .create_thread_with_post(cat_id, user_id, "Many Replies", "body")
115 .await;
116
117 // Add extra replies to t2
118 for i in 0..3 {
119 mt_db::mutations::create_post(
120 &h.db,
121 t2,
122 user_id,
123 &format!("reply {i}"),
124 &format!("<p>reply {i}</p>"),
125 true,
126 )
127 .await
128 .unwrap();
129 }
130
131 // Sort by replies desc — "Many Replies" should come first
132 let resp = h
133 .client
134 .get("/p/test/general?sort=replies&order=desc")
135 .await;
136 assert!(resp.status.is_success());
137 let many_pos = resp.text.find("Many Replies").expect("Many Replies not found");
138 let few_pos = resp.text.find("Few Replies").expect("Few Replies not found");
139 assert!(
140 many_pos < few_pos,
141 "Many Replies should appear before Few Replies when sorted by replies desc"
142 );
143
144 // Sort by replies asc — "Few Replies" should come first (after pinned)
145 let resp = h
146 .client
147 .get("/p/test/general?sort=replies&order=asc")
148 .await;
149 assert!(resp.status.is_success());
150 let many_pos = resp.text.find("Many Replies").expect("Many Replies not found");
151 let few_pos = resp.text.find("Few Replies").expect("Few Replies not found");
152 assert!(
153 few_pos < many_pos,
154 "Few Replies should appear before Many Replies when sorted by replies asc"
155 );
156 }
157
158 #[tokio::test]
159 async fn sort_headers_present_in_category() {
160 let mut h = TestHarness::new().await;
161 let comm_id = h.create_community("Test", "test").await;
162 let _cat_id = h.create_category(comm_id, "General", "general").await;
163 let user_id = h.login_as("viewer").await;
164 h.add_membership(user_id, comm_id, "member").await;
165 h.create_thread_with_post(_cat_id, user_id, "A Thread", "body")
166 .await;
167
168 let resp = h.client.get("/p/test/general").await;
169 assert!(resp.status.is_success());
170
171 // Default sort is activity desc, so activity header should have the arrow
172 assert!(
173 resp.text.contains("sort-active"),
174 "active sort indicator should be present"
175 );
176 assert!(
177 resp.text.contains("?sort=replies"),
178 "replies sort link should be present"
179 );
180 assert!(
181 resp.text.contains("?sort=activity"),
182 "activity sort link should be present"
183 );
184 }
185
186 #[tokio::test]
187 async fn thread_pagination_page_zero() {
188 let mut h = TestHarness::new().await;
189 let user_id = h.login_as("poster").await;
190 let comm_id = h.create_community("Test", "test").await;
191 let cat_id = h.create_category(comm_id, "General", "general").await;
192 h.add_membership(user_id, comm_id, "member").await;
193
194 let thread_id = h
195 .create_thread_with_post(cat_id, user_id, "My Thread", "first post")
196 .await;
197
198 let resp = h
199 .client
200 .get(&format!("/p/test/general/{thread_id}?page=0"))
201 .await;
202
203 assert!(resp.status.is_success());
204 assert!(
205 resp.text.contains("first post"),
206 "post should be visible with page=0"
207 );
208 }
209
210 #[tokio::test]
211 async fn meta_description_present_on_category() {
212 let mut h = TestHarness::new().await;
213 let comm_id = h.create_community("TestProject", "testproject").await;
214 let _cat_id = h
215 .create_category(comm_id, "Bugs", "bugs")
216 .await;
217
218 let resp = h.client.get("/p/testproject/bugs").await;
219 assert!(resp.status.is_success());
220 assert!(
221 resp.text.contains(r#"<meta name="description""#),
222 "meta description should be present"
223 );
224 }
225
226 #[tokio::test]
227 async fn meta_description_present_on_thread() {
228 let mut h = TestHarness::new().await;
229 let user_id = h.login_as("metauser").await;
230 let comm_id = h.create_community("Test", "test").await;
231 let cat_id = h.create_category(comm_id, "General", "general").await;
232 h.add_membership(user_id, comm_id, "member").await;
233
234 let thread_id = h
235 .create_thread_with_post(cat_id, user_id, "Meta Thread", "body")
236 .await;
237
238 let resp = h
239 .client
240 .get(&format!("/p/test/general/{thread_id}"))
241 .await;
242 assert!(resp.status.is_success());
243 assert!(
244 resp.text.contains(r#"<meta name="description""#),
245 "meta description should be present on thread page"
246 );
247 }
248
249 #[tokio::test]
250 async fn noindex_on_error_page() {
251 let mut h = TestHarness::new().await;
252
253 let resp = h.client.get("/nonexistent-page-xyz").await;
254 assert_eq!(resp.status, axum::http::StatusCode::NOT_FOUND);
255 assert!(
256 resp.text.contains(r#"<meta name="robots" content="noindex">"#),
257 "404 page should have noindex meta"
258 );
259 }
260
261 #[tokio::test]
262 async fn member_list_shows_members_with_roles() {
263 let mut h = TestHarness::new().await;
264 let owner_id = h.login_as("theowner").await;
265 let comm_id = h.create_community("Test", "test").await;
266 h.add_membership(owner_id, comm_id, "owner").await;
267
268 let mod_id = h.login_as("themod").await;
269 h.add_membership(mod_id, comm_id, "moderator").await;
270
271 let member_id = h.login_as("regular").await;
272 h.add_membership(member_id, comm_id, "member").await;
273
274 let resp = h.client.get("/p/test/members").await;
275
276 assert!(resp.status.is_success());
277 assert!(resp.text.contains("theowner"), "owner should be listed");
278 assert!(resp.text.contains("themod"), "mod should be listed");
279 assert!(resp.text.contains("regular"), "member should be listed");
280 // Owner should appear before member in the table (sorted by role)
281 // Search within the data-table to avoid matching the header nav Profile link
282 let table_start = resp.text.find("data-table").unwrap();
283 let table_html = &resp.text[table_start..];
284 let owner_pos = table_html.find("/u/theowner").unwrap();
285 let member_pos = table_html.find("/u/regular").unwrap();
286 assert!(
287 owner_pos < member_pos,
288 "owner should appear before regular member"
289 );
290 }
291
292 #[tokio::test]
293 async fn member_list_nonexistent_community_404() {
294 let mut h = TestHarness::new().await;
295
296 let resp = h.client.get("/p/nonexistent/members").await;
297 assert_eq!(resp.status, axum::http::StatusCode::NOT_FOUND);
298 }
299
300 #[tokio::test]
301 async fn community_page_has_members_link() {
302 let mut h = TestHarness::new().await;
303 let comm_id = h.create_community("Test", "test").await;
304 let _cat_id = h.create_category(comm_id, "General", "general").await;
305
306 let resp = h.client.get("/p/test").await;
307 assert!(resp.status.is_success());
308 assert!(
309 resp.text.contains("/p/test/members"),
310 "community page should have members link"
311 );
312 }
313