feat: enhance user registration and follow functionality, add popular tags endpoint, and update tests

This commit is contained in:
2025-09-06 16:49:38 +02:00
parent 508f218fc0
commit 728bf0e231
23 changed files with 216 additions and 64 deletions

View File

@@ -9,7 +9,7 @@ use utils::testing::{
#[tokio::test]
async fn test_webfinger_discovery() {
let app = setup().await;
create_user_with_password(&app.db, "testuser", "password123").await;
create_user_with_password(&app.db, "testuser", "password123", "testuser@example.com").await;
// 1. Valid WebFinger lookup for existing user
let url = "/.well-known/webfinger?resource=acct:testuser@localhost:3000";
@@ -36,7 +36,7 @@ async fn test_webfinger_discovery() {
#[tokio::test]
async fn test_user_actor_endpoint() {
let app = setup().await;
create_user_with_password(&app.db, "testuser", "password123").await;
create_user_with_password(&app.db, "testuser", "password123", "testuser@example.com").await;
let response = make_request_with_headers(
app.router.clone(),
@@ -64,9 +64,11 @@ async fn test_user_actor_endpoint() {
async fn test_user_inbox_follow() {
let app = setup().await;
// user1 will be followed
let user1 = create_user_with_password(&app.db, "user1", "password123").await;
let user1 =
create_user_with_password(&app.db, "user1", "password123", "user1@example.com").await;
// user2 will be the follower
let user2 = create_user_with_password(&app.db, "user2", "password123").await;
let user2 =
create_user_with_password(&app.db, "user2", "password123", "user2@example.com").await;
// Construct a follow activity from user2, targeting user1
let follow_activity = json!({
@@ -90,7 +92,7 @@ async fn test_user_inbox_follow() {
assert_eq!(response.status(), StatusCode::ACCEPTED);
// Verify that user2 is now following user1 in the database
let followers = app::persistence::follow::get_followed_ids(&app.db, user2.id)
let followers = app::persistence::follow::get_following_ids(&app.db, user2.id)
.await
.unwrap();
assert!(
@@ -98,7 +100,7 @@ async fn test_user_inbox_follow() {
"User2 should be following user1"
);
let following = app::persistence::follow::get_followed_ids(&app.db, user1.id)
let following = app::persistence::follow::get_following_ids(&app.db, user1.id)
.await
.unwrap();
assert!(
@@ -111,7 +113,7 @@ async fn test_user_inbox_follow() {
#[tokio::test]
async fn test_user_outbox_get() {
let app = setup().await;
create_user_with_password(&app.db, "testuser", "password123").await;
create_user_with_password(&app.db, "testuser", "password123", "testuser@example.com").await;
let token = super::main::login_user(app.router.clone(), "testuser", "password123").await;
// Create a thought first

View File

@@ -7,7 +7,13 @@ use utils::testing::{make_jwt_request, make_request_with_headers};
#[tokio::test]
async fn test_api_key_flow() {
let app = setup().await;
let _ = create_user_with_password(&app.db, "apikey_user", "password123").await;
let _ = create_user_with_password(
&app.db,
"apikey_user",
"password123",
"apikey_user@example.com",
)
.await;
let jwt = login_user(app.router.clone(), "apikey_user", "password123").await;
// 1. Create a new API key using JWT auth

View File

@@ -11,6 +11,7 @@ async fn test_auth_flow() {
let register_body = json!({
"username": "testuser",
"email": "testuser@example.com",
"password": "password123"
})
.to_string();
@@ -26,6 +27,7 @@ async fn test_auth_flow() {
"/auth/register",
json!({
"username": "testuser",
"email": "testuser@example.com",
"password": "password456"
})
.to_string(),
@@ -48,6 +50,7 @@ async fn test_auth_flow() {
let bad_login_body = json!({
"username": "testuser",
"email": "testuser@example.com",
"password": "wrongpassword"
})
.to_string();

View File

@@ -7,9 +7,9 @@ use utils::testing::make_jwt_request;
#[tokio::test]
async fn test_feed_and_user_thoughts() {
let app = setup().await;
create_user_with_password(&app.db, "user1", "password1").await;
create_user_with_password(&app.db, "user2", "password2").await;
create_user_with_password(&app.db, "user3", "password3").await;
create_user_with_password(&app.db, "user1", "password1", "user1@example.com").await;
create_user_with_password(&app.db, "user2", "password2", "user2@example.com").await;
create_user_with_password(&app.db, "user3", "password3", "user3@example.com").await;
// As user1, post a thought
let token = super::main::login_user(app.router.clone(), "user1", "password1").await;

View File

@@ -7,8 +7,8 @@ async fn test_follow_endpoints() {
std::env::set_var("AUTH_SECRET", "test-secret");
let app = setup().await;
create_user_with_password(&app.db, "user1", "password1").await;
create_user_with_password(&app.db, "user2", "password2").await;
create_user_with_password(&app.db, "user1", "password1", "user1@example.com").await;
create_user_with_password(&app.db, "user2", "password2", "user2@example.com").await;
let token = super::main::login_user(app.router.clone(), "user1", "password1").await;

View File

@@ -38,10 +38,12 @@ pub async fn create_user_with_password(
db: &DatabaseConnection,
username: &str,
password: &str,
email: &str,
) -> user::Model {
let params = RegisterParams {
username: username.to_string(),
password: password.to_string(),
email: email.to_string(),
};
app::persistence::auth::register_user(db, params)
.await

View File

@@ -1,4 +1,4 @@
use crate::api::main::{create_user_with_password, login_user, setup};
use crate::api::main::{create_user_with_password, login_user, setup, TestApp};
use axum::http::StatusCode;
use http_body_util::BodyExt;
use serde_json::{json, Value};
@@ -7,7 +7,8 @@ use utils::testing::{make_get_request, make_jwt_request};
#[tokio::test]
async fn test_hashtag_flow() {
let app = setup().await;
let user = create_user_with_password(&app.db, "taguser", "password123").await;
let user =
create_user_with_password(&app.db, "taguser", "password123", "taguser@example.com").await;
let token = login_user(app.router.clone(), "taguser", "password123").await;
// 1. Post a thought with hashtags
@@ -48,3 +49,43 @@ async fn test_hashtag_flow() {
assert_eq!(thoughts.len(), 1);
assert_eq!(thoughts[0]["id"], thought_id);
}
#[tokio::test]
async fn test_popular_tags() {
let app = setup().await;
let _ = create_user_with_password(&app.db, "poptag_user", "password123", "poptag@example.com")
.await;
let token = login_user(app.router.clone(), "poptag_user", "password123").await;
// Helper async function to post a thought
async fn post_thought(app: &TestApp, token: &str, content: &str) {
let body = json!({ "content": content }).to_string();
let response =
make_jwt_request(app.router.clone(), "/thoughts", "POST", Some(body), token).await;
assert_eq!(response.status(), StatusCode::CREATED);
}
// 1. Post thoughts to create tag usage data
// Expected counts: rust (3), web (2), axum (2), testing (1)
post_thought(&app, &token, "My first post about #rust and the #web").await;
post_thought(&app, &token, "Another post about #rust and #axum").await;
post_thought(&app, &token, "I'm really enjoying #rust lately").await;
post_thought(&app, &token, "Let's talk about #axum and the #web").await;
post_thought(&app, &token, "Don't forget about #testing").await;
// 2. Fetch the popular tags
let response = make_get_request(app.router.clone(), "/tags/popular", None).await;
println!("Response: {:?}", response);
assert_eq!(response.status(), StatusCode::OK);
let body = response.into_body().collect().await.unwrap().to_bytes();
let v: Vec<String> = serde_json::from_slice(&body).unwrap();
// 3. Assert the results
assert_eq!(v.len(), 4, "Should return the 4 unique tags used");
assert_eq!(
v,
vec!["rust", "axum", "web", "testing"],
"Tags should be ordered by popularity, then alphabetically"
);
}

View File

@@ -10,8 +10,10 @@ use utils::testing::{make_delete_request, make_post_request};
#[tokio::test]
async fn test_thought_endpoints() {
let app = setup().await;
let user1 = create_user_with_password(&app.db, "user1", "password123").await; // AuthUser is ID 1
let _user2 = create_user_with_password(&app.db, "user2", "password123").await; // Other user is ID 2
let user1 =
create_user_with_password(&app.db, "user1", "password123", "user1@example.com").await; // AuthUser is ID 1
let _user2 =
create_user_with_password(&app.db, "user2", "password123", "user2@example.com").await; // Other user is ID 2
// 1. Post a new thought as user 1
let body = json!({ "content": "My first thought!" }).to_string();

View File

@@ -12,7 +12,8 @@ use crate::api::main::{create_user_with_password, login_user, setup};
async fn test_post_users() {
let app = setup().await;
let body = r#"{"username": "test", "password": "password123"}"#.to_owned();
let body = r#"{"username": "test", "email": "test@example.com", "password": "password123"}"#
.to_owned();
let response = make_post_request(app.router, "/auth/register", body, None).await;
assert_eq!(response.status(), StatusCode::CREATED);
@@ -21,14 +22,15 @@ async fn test_post_users() {
let v: Value = serde_json::from_slice(&body).unwrap();
assert_eq!(v["username"], "test");
assert!(v["display_name"].is_null());
assert!(v["display_name"].is_string());
}
#[tokio::test]
pub(super) async fn test_post_users_error() {
let app = setup().await;
let body = r#"{"username": "1", "password": "password123"}"#.to_owned();
let body =
r#"{"username": "1", "email": "test@example.com", "password": "password123"}"#.to_owned();
let response = make_post_request(app.router, "/auth/register", body, None).await;
assert_eq!(response.status(), StatusCode::UNPROCESSABLE_ENTITY);
@@ -43,7 +45,8 @@ pub(super) async fn test_post_users_error() {
pub async fn test_get_users() {
let app = setup().await;
let body = r#"{"username": "test", "password": "password123"}"#.to_owned();
let body = r#"{"username": "test", "email": "test@example.com", "password": "password123"}"#
.to_owned();
make_post_request(app.router.clone(), "/auth/register", body, None).await;
let response = make_get_request(app.router, "/users", None).await;
@@ -65,6 +68,7 @@ async fn test_me_endpoints() {
// 1. Register a new user
let register_body = json!({
"username": "me_user",
"email": "me_user@example.com",
"password": "password123"
})
.to_string();
@@ -82,7 +86,7 @@ async fn test_me_endpoints() {
let v: Value = serde_json::from_slice(&body).unwrap();
assert_eq!(v["username"], "me_user");
assert!(v["bio"].is_null());
assert!(v["display_name"].is_null());
assert!(v["display_name"].is_string());
// 4. PUT /users/me to update the profile
let update_body = json!({
@@ -119,10 +123,14 @@ async fn test_update_me_top_friends() {
let app = setup().await;
// 1. Create users for the test
let user_me = create_user_with_password(&app.db, "me_user", "password123").await;
let friend1 = create_user_with_password(&app.db, "friend1", "password123").await;
let friend2 = create_user_with_password(&app.db, "friend2", "password123").await;
let _friend3 = create_user_with_password(&app.db, "friend3", "password123").await;
let user_me =
create_user_with_password(&app.db, "me_user", "password123", "me_user@example.com").await;
let friend1 =
create_user_with_password(&app.db, "friend1", "password123", "friend1@example.com").await;
let friend2 =
create_user_with_password(&app.db, "friend2", "password123", "friend2@example.com").await;
let _friend3 =
create_user_with_password(&app.db, "friend3", "password123", "friend3@example.com").await;
// 2. Log in as "me_user"
let token = login_user(app.router.clone(), "me_user", "password123").await;
@@ -189,7 +197,8 @@ async fn test_update_me_css_and_images() {
let app = setup().await;
// 1. Create and log in as a user
let _ = create_user_with_password(&app.db, "css_user", "password123").await;
let _ =
create_user_with_password(&app.db, "css_user", "password123", "css_user@example.com").await;
let token = login_user(app.router.clone(), "css_user", "password123").await;
// 2. Attempt to update with an invalid avatar URL