fabrica

hanna/fabrica

test(web): cover the signed-in dashboard activity view

243de22 · hanna committed on 2026-07-25

Add a login helper and assert the dashboard renders the contribution heatmap
and recent-activity feed for a signed-in viewer.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed by hannaSSH key fingerprint: SHA256:4g9cWhkAAw8gwqhJUcVbSnGEvdGwklW+1Aa/fMUu59k
1 files changed · +56 −0UnifiedSplit
crates/web/src/tests.rs +56 −0
@@ -331,6 +331,62 @@ async fn explore_users_lists_the_directory() {
331 assert!(html.contains("/avatar/ada"), "user avatar shown");331 assert!(html.contains("/avatar/ada"), "user avatar shown");
332}332}
333333
334/// Sign in as `ada` and return the `Cookie` header value carrying the session.
335async fn login(app: &Router) -> String {
336 let form = app.clone().oneshot(get("/login")).await.unwrap();
337 let csrf = form
338 .headers()
339 .get(header::SET_COOKIE)
340 .unwrap()
341 .to_str()
342 .unwrap()
343 .to_string();
344 let token = csrf
345 .split("fabrica_csrf=")
346 .nth(1)
347 .and_then(|s| s.split(';').next())
348 .unwrap()
349 .to_string();
350 let req = Request::builder()
351 .method("POST")
352 .uri("/login")
353 .header(header::CONTENT_TYPE, "application/x-www-form-urlencoded")
354 .header(header::COOKIE, format!("fabrica_csrf={token}"))
355 .body(Body::from(format!(
356 "username=ada&password=secret12&_csrf={token}"
357 )))
358 .unwrap();
359 let res = app.clone().oneshot(req).await.unwrap();
360 let session = res
361 .headers()
362 .get(header::SET_COOKIE)
363 .unwrap()
364 .to_str()
365 .unwrap();
366 let session = session.split(';').next().unwrap();
367 format!("fabrica_csrf={token}; {session}")
368}
369
370#[tokio::test]
371async fn dashboard_shows_activity_and_repos_when_signed_in() {
372 let (_state, app) = app().await;
373 let cookie = login(&app).await;
374 let req = Request::builder()
375 .uri("/")
376 .header(header::COOKIE, cookie)
377 .body(Body::empty())
378 .unwrap();
379 let res = app.oneshot(req).await.unwrap();
380 assert_eq!(res.status(), StatusCode::OK);
381 let html = body_string(res).await;
382 assert!(
383 html.contains("contributions in the last year"),
384 "activity heatmap caption present"
385 );
386 assert!(html.contains("Recent activity"), "activity feed present");
387 assert!(html.contains("class=\"heatmap\""), "heatmap svg present");
388}
389
334#[tokio::test]390#[tokio::test]
335async fn settings_requires_authentication() {391async fn settings_requires_authentication() {
336 let (_state, app) = app().await;392 let (_state, app) = app().await;