//! Tests for unified note footer behavior across feed and profile pages.
mod support;
use std::time::Duration;
use support::{Client, Server, free_port};
/// Register a user through the web form.
fn register(client: &mut Client, name: &str) {
let email = format!("{name}@example.org");
let response = client.post_form(
"/register",
&[
("name", name),
("email", &email),
("password", "correct horse battery staple"),
],
);
assert_eq!(
response.status, 303,
"registering should log in\n{}",
response.body
);
}
/// Extract note UUID from profile page HTML.
fn extract_note_uuid(html: &str, author: &str) -> Option<String> {
// Look for permalink pattern: href="http://.../~author/notes/{uuid}"
let pattern = format!("/~{author}/notes/");
let start = html.find(&pattern)?;
let after_pattern = &html[start + pattern.len()..];
let end = after_pattern.find('"')?;
Some(after_pattern[..end].to_string())
}
/// Test: Profile page shows a permalink for each note
#[tokio::test]
async fn profile_shows_note_permalink() -> miette::Result<()> {
let port = free_port();
let mut server = Server::spawn_federated(&format!("127.0.0.1:{port}"));
server.wait_for_connection(port);
let mut alice_client = Client::new(port);
register(&mut alice_client, "alice");
// Post a note
let response = alice_client.post_form("/~alice/notes", &[("content", "Test note content")]);
assert_eq!(
response.status, 303,
"posting a note should redirect. Body:\n{}",
response.body
);
// Visit the profile page
let response = alice_client.get("/~alice");
assert_eq!(response.status, 200, "profile page should load");
assert!(
response.body.contains("Test note content"),
"profile should contain the note content. Body:\n{}",
response.body
);
// Check for permalink anchor
assert!(
response.body.contains("permalink"),
"profile should contain a permalink link. Body:\n{}",
response.body
);
// Check for a link to the note URL (should be /~alice/notes/{uuid})
assert!(
response.body.contains("/~alice/notes/"),
"profile should contain a link to the note. Body:\n{}",
response.body
);
Ok(())
}
/// Test: Feed shows reaction counts
#[tokio::test]
async fn feed_shows_reaction_counts() -> miette::Result<()> {
let port = free_port();
let mut server = Server::spawn_federated(&format!("127.0.0.1:{port}"));
server.wait_for_connection(port);
let mut alice_client = Client::new(port);
register(&mut alice_client, "alice");
// Post a note
let response = alice_client.post_form("/~alice/notes", &[("content", "Test note")]);
assert_eq!(response.status, 303);
// Visit the home page - should see the feed with counts
let response = alice_client.get("/");
assert_eq!(response.status, 200, "home page should load");
assert!(
response.body.contains("Test note"),
"feed should contain the note. Body:\n{}",
response.body
);
// The feed should show reaction counts (even if 0)
// After we implement, this will show the counts markup
// For now, just check the note is there
Ok(())
}
/// Test: Note page content negotiation - HTML vs JSON
#[tokio::test]
async fn note_page_content_negotiation() -> miette::Result<()> {
let port = free_port();
let mut server = Server::spawn_federated(&format!("127.0.0.1:{port}"));
server.wait_for_connection(port);
let mut alice_client = Client::new(port);
register(&mut alice_client, "alice");
// Post a note
let response =
alice_client.post_form("/~alice/notes", &[("content", "Test note for negotiation")]);
assert_eq!(response.status, 303);
// Visit profile to get the note UUID
let response = alice_client.get("/~alice");
assert_eq!(response.status, 200);
let uuid =
extract_note_uuid(&response.body, "alice").expect("should find note UUID in profile");
// Request with Accept: text/html should return HTML
let response =
alice_client.get_with(&format!("/~alice/notes/{uuid}"), &[("Accept", "text/html")]);
assert_eq!(response.status, 200, "HTML request should succeed with 200");
assert!(
response.body.contains("<!DOCTYPE html>"),
"should return HTML page"
);
assert!(
response.body.contains("Test note for negotiation"),
"HTML should contain note content"
);
// Request with Accept: application/activity+json should return JSON
let response = alice_client.get_with(
&format!("/~alice/notes/{uuid}"),
&[("Accept", "application/activity+json")],
);
assert_eq!(
response.status, 200,
"ActivityPub JSON request should succeed with 200"
);
assert!(
response.body.contains("\"type\"") && response.body.contains("\"Note\""),
"should return ActivityPub Note JSON. Body:\n{}",
response.body
);
Ok(())
}