mod common;
use common::{client_for, mock_server};
use hevy::{CreateExerciseTemplateRequest, EquipmentCategory, MuscleGroup, NewCustomExercise, CustomExerciseType};
use serde_json::json;
use wiremock::matchers::{method, path, query_param};
use wiremock::{Mock, ResponseTemplate};
fn sample_template_json() -> serde_json::Value {
json!({
"id": "b459cba5-cd6d-463c-abd6-54f8eafcadcb",
"title": "Bench Press (Barbell)",
"type": "weight_reps",
"primary_muscle_group": "chest",
"secondary_muscle_groups": ["shoulders", "triceps"],
"equipment_category": "barbell",
"is_custom": false,
})
}
#[tokio::test]
async fn list_exercise_templates() {
let server = mock_server().await;
let client = client_for(&server);
Mock::given(method("GET"))
.and(path("/v1/exercise_templates"))
.and(query_param("page", "1"))
.and(query_param("pageSize", "20"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({
"page": 1,
"page_count": 3,
"exercise_templates": [sample_template_json()],
})))
.mount(&server)
.await;
let page = client
.list_exercise_templates(Some(1), Some(20))
.await
.unwrap();
assert_eq!(page.page_count, 3);
assert_eq!(page.exercise_templates[0].title, "Bench Press (Barbell)");
assert_eq!(
page.exercise_templates[0].equipment_category,
Some(EquipmentCategory::Barbell)
);
}
#[tokio::test]
async fn get_exercise_template_by_id() {
let server = mock_server().await;
let client = client_for(&server);
Mock::given(method("GET"))
.and(path("/v1/exercise_templates/05293BCA"))
.respond_with(ResponseTemplate::new(200).set_body_json(sample_template_json()))
.mount(&server)
.await;
let template = client.get_exercise_template("05293BCA").await.unwrap();
assert_eq!(template.primary_muscle_group, "chest");
assert!(!template.is_custom);
}
#[tokio::test]
async fn create_exercise_template_returns_new_id() {
let server = mock_server().await;
let client = client_for(&server);
Mock::given(method("POST"))
.and(path("/v1/exercise_templates"))
.respond_with(ResponseTemplate::new(200).set_body_json(json!({ "id": 123 })))
.mount(&server)
.await;
let exercise = NewCustomExercise::new(
"Bench Press",
CustomExerciseType::WeightReps,
EquipmentCategory::Barbell,
MuscleGroup::Chest,
)
.with_other_muscles([MuscleGroup::Biceps, MuscleGroup::Triceps]);
let id = client
.create_exercise_template(&CreateExerciseTemplateRequest::new(exercise))
.await
.unwrap();
assert_eq!(id, 123);
}
#[tokio::test]
async fn create_exercise_template_over_limit_returns_error() {
let server = mock_server().await;
let client = client_for(&server);
Mock::given(method("POST"))
.and(path("/v1/exercise_templates"))
.respond_with(ResponseTemplate::new(403).set_body_json(json!({
"error": "exceeds-custom-exercise-limit"
})))
.mount(&server)
.await;
let exercise = NewCustomExercise::new(
"Bench Press",
CustomExerciseType::WeightReps,
EquipmentCategory::Barbell,
MuscleGroup::Chest,
);
let err = client
.create_exercise_template(&CreateExerciseTemplateRequest::new(exercise))
.await
.unwrap_err();
match err {
hevy::HevyError::Api { status, message } => {
assert_eq!(status, 403);
assert_eq!(message, "exceeds-custom-exercise-limit");
}
other => panic!("expected HevyError::Api, got {other:?}"),
}
}