- Add /v1/feed API endpoint with handler and tests - Remove health endpoint rate limiting (behind firewall, caused spurious 429s) - Add dashboard feed panel with list, row, empty state, and loading skeleton - Update home page to show feed instead of redirecting to skeptic - Improve API key auth middleware and DTO create/query params - Add OpenAPI conceptual guide (api-intro.md) with semaglutide examples - Add FindMyHealth application scaffolding (vision, architecture, prototypes) - Add FindMyHealth designer/writer and Aphoria founder-CEO agents - Update roadmap with current progress Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
94 lines
2.9 KiB
Rust
94 lines
2.9 KiB
Rust
//! HTTP integration tests for the `/v1/feed` endpoint.
|
|
|
|
#![allow(clippy::expect_used)]
|
|
|
|
mod common;
|
|
|
|
use axum::{
|
|
body::Body,
|
|
http::{Request, StatusCode},
|
|
};
|
|
use tower::ServiceExt;
|
|
|
|
use stemedb_api::create_router;
|
|
|
|
// ============================================================================
|
|
// Feed Endpoint Tests
|
|
// ============================================================================
|
|
|
|
#[tokio::test]
|
|
async fn test_feed_empty_db() {
|
|
let env = common::create_test_env().await;
|
|
let app = create_router(env.state);
|
|
|
|
let request =
|
|
Request::builder().uri("/v1/feed").method("GET").body(Body::empty()).expect("Request");
|
|
|
|
let response = app.oneshot(request).await.expect("Request");
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
|
|
let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");
|
|
|
|
assert_eq!(json["assertions"], serde_json::json!([]));
|
|
assert_eq!(json["total_count"], 0);
|
|
assert_eq!(json["has_more"], false);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_feed_with_limit_and_offset() {
|
|
let env = common::create_test_env().await;
|
|
let app = create_router(env.state);
|
|
|
|
let request = Request::builder()
|
|
.uri("/v1/feed?limit=10&offset=0")
|
|
.method("GET")
|
|
.body(Body::empty())
|
|
.expect("Request");
|
|
|
|
let response = app.oneshot(request).await.expect("Request");
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
|
|
let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");
|
|
|
|
assert_eq!(json["total_count"], 0);
|
|
assert_eq!(json["has_more"], false);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_feed_default_params() {
|
|
let env = common::create_test_env().await;
|
|
let app = create_router(env.state);
|
|
|
|
// No query params at all — should use defaults (limit=50, offset=0)
|
|
let request =
|
|
Request::builder().uri("/v1/feed").method("GET").body(Body::empty()).expect("Request");
|
|
|
|
let response = app.oneshot(request).await.expect("Request");
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_query_no_subject_returns_ok() {
|
|
let env = common::create_test_env().await;
|
|
let app = create_router(env.state);
|
|
|
|
// GET /v1/query with no subject should return 200 with empty results
|
|
let request =
|
|
Request::builder().uri("/v1/query").method("GET").body(Body::empty()).expect("Request");
|
|
|
|
let response = app.oneshot(request).await.expect("Request");
|
|
|
|
assert_eq!(response.status(), StatusCode::OK);
|
|
|
|
let body = axum::body::to_bytes(response.into_body(), usize::MAX).await.expect("Body");
|
|
let json: serde_json::Value = serde_json::from_slice(&body).expect("JSON");
|
|
|
|
assert_eq!(json["assertions"], serde_json::json!([]));
|
|
assert_eq!(json["total_count"], 0);
|
|
}
|