test(brews): add server and CLI integration tests
- Test create, list, get, delete operations - Test bag deduction and conflict on insufficient coffee - Test CLI commands with defaults - Add create_default_gear helper
This commit is contained in:
parent
0eedf09c08
commit
b3d697978c
5 changed files with 691 additions and 0 deletions
286
tests/cli/brews_cli.rs
Normal file
286
tests/cli/brews_cli.rs
Normal file
|
|
@ -0,0 +1,286 @@
|
|||
use crate::helpers::{create_roast, create_roaster, create_token, run_brewlog};
|
||||
|
||||
fn create_bag(roast_id: &str, token: &str) -> String {
|
||||
let output = run_brewlog(
|
||||
&["bag", "add", "--roast-id", roast_id, "--amount", "250"],
|
||||
&[("BREWLOG_TOKEN", token)],
|
||||
);
|
||||
|
||||
if !output.status.success() {
|
||||
panic!(
|
||||
"Failed to create bag: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let bag: serde_json::Value = serde_json::from_str(&stdout).expect("Should output valid JSON");
|
||||
bag["id"]
|
||||
.as_i64()
|
||||
.expect("bag id should be numeric")
|
||||
.to_string()
|
||||
}
|
||||
|
||||
fn create_gear(category: &str, make: &str, model: &str, token: &str) -> String {
|
||||
let output = run_brewlog(
|
||||
&[
|
||||
"gear",
|
||||
"add",
|
||||
"--category",
|
||||
category,
|
||||
"--make",
|
||||
make,
|
||||
"--model",
|
||||
model,
|
||||
],
|
||||
&[("BREWLOG_TOKEN", token)],
|
||||
);
|
||||
|
||||
if !output.status.success() {
|
||||
panic!(
|
||||
"Failed to create gear: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
}
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let gear: serde_json::Value = serde_json::from_str(&stdout).expect("Should output valid JSON");
|
||||
gear["id"]
|
||||
.as_i64()
|
||||
.expect("gear id should be numeric")
|
||||
.to_string()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn brew_add_creates_brew_via_api() {
|
||||
let token = create_token("brew-add-test");
|
||||
let roaster_id = create_roaster("Brew Test Roaster", &token);
|
||||
let roast_id = create_roast(&roaster_id, "Brew Test Roast", &token);
|
||||
let bag_id = create_bag(&roast_id, &token);
|
||||
let grinder_id = create_gear("grinder", "Comandante", "C40", &token);
|
||||
let brewer_id = create_gear("brewer", "Hario", "V60", &token);
|
||||
|
||||
let output = run_brewlog(
|
||||
&[
|
||||
"brew",
|
||||
"add",
|
||||
"--bag-id",
|
||||
&bag_id,
|
||||
"--coffee-weight",
|
||||
"15.0",
|
||||
"--grinder-id",
|
||||
&grinder_id,
|
||||
"--grind-setting",
|
||||
"24.0",
|
||||
"--brewer-id",
|
||||
&brewer_id,
|
||||
"--water-volume",
|
||||
"250",
|
||||
"--water-temp",
|
||||
"92.0",
|
||||
],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"brew add should succeed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let brew: serde_json::Value = serde_json::from_str(&stdout).expect("Should output valid JSON");
|
||||
|
||||
assert_eq!(brew["coffee_weight"], 15.0);
|
||||
assert_eq!(brew["grind_setting"], 24.0);
|
||||
assert_eq!(brew["water_volume"], 250);
|
||||
assert_eq!(brew["water_temp"], 92.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn brew_add_with_defaults_uses_default_values() {
|
||||
let token = create_token("brew-defaults-test");
|
||||
let roaster_id = create_roaster("Brew Defaults Roaster", &token);
|
||||
let roast_id = create_roast(&roaster_id, "Brew Defaults Roast", &token);
|
||||
let bag_id = create_bag(&roast_id, &token);
|
||||
let grinder_id = create_gear("grinder", "1Zpresso", "JMax", &token);
|
||||
let brewer_id = create_gear("brewer", "AeroPress", "Original", &token);
|
||||
|
||||
// Only provide required args, let defaults apply
|
||||
let output = run_brewlog(
|
||||
&[
|
||||
"brew",
|
||||
"add",
|
||||
"--bag-id",
|
||||
&bag_id,
|
||||
"--grinder-id",
|
||||
&grinder_id,
|
||||
"--brewer-id",
|
||||
&brewer_id,
|
||||
],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"brew add should succeed with defaults: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let brew: serde_json::Value = serde_json::from_str(&stdout).expect("Should output valid JSON");
|
||||
|
||||
// Check defaults: 15.0g coffee, 6.0 grind, 250ml water, 91.0°C
|
||||
assert_eq!(brew["coffee_weight"], 15.0);
|
||||
assert_eq!(brew["grind_setting"], 6.0);
|
||||
assert_eq!(brew["water_volume"], 250);
|
||||
assert_eq!(brew["water_temp"], 91.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn brew_list_returns_json_array() {
|
||||
let token = create_token("brew-list-test");
|
||||
let roaster_id = create_roaster("Brew List Roaster", &token);
|
||||
let roast_id = create_roast(&roaster_id, "Brew List Roast", &token);
|
||||
let bag_id = create_bag(&roast_id, &token);
|
||||
let grinder_id = create_gear("grinder", "Fellow", "Ode", &token);
|
||||
let brewer_id = create_gear("brewer", "Chemex", "Classic", &token);
|
||||
|
||||
// Create a brew first
|
||||
run_brewlog(
|
||||
&[
|
||||
"brew",
|
||||
"add",
|
||||
"--bag-id",
|
||||
&bag_id,
|
||||
"--grinder-id",
|
||||
&grinder_id,
|
||||
"--brewer-id",
|
||||
&brewer_id,
|
||||
],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
|
||||
// List brews
|
||||
let output = run_brewlog(&["brew", "list"], &[("BREWLOG_TOKEN", &token)]);
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"brew list should succeed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let brews: serde_json::Value = serde_json::from_str(&stdout).expect("Should output valid JSON");
|
||||
|
||||
assert!(brews.is_array(), "brew list should return an array");
|
||||
assert!(
|
||||
!brews.as_array().unwrap().is_empty(),
|
||||
"should have at least one brew"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn brew_get_returns_brew_details() {
|
||||
let token = create_token("brew-get-test");
|
||||
let roaster_id = create_roaster("Brew Get Roaster", &token);
|
||||
let roast_id = create_roast(&roaster_id, "Brew Get Roast", &token);
|
||||
let bag_id = create_bag(&roast_id, &token);
|
||||
let grinder_id = create_gear("grinder", "Baratza", "Encore", &token);
|
||||
let brewer_id = create_gear("brewer", "Kalita", "Wave", &token);
|
||||
|
||||
// Create a brew
|
||||
let create_output = run_brewlog(
|
||||
&[
|
||||
"brew",
|
||||
"add",
|
||||
"--bag-id",
|
||||
&bag_id,
|
||||
"--grinder-id",
|
||||
&grinder_id,
|
||||
"--brewer-id",
|
||||
&brewer_id,
|
||||
"--coffee-weight",
|
||||
"18.5",
|
||||
],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
|
||||
let create_stdout = String::from_utf8_lossy(&create_output.stdout);
|
||||
let created_brew: serde_json::Value =
|
||||
serde_json::from_str(&create_stdout).expect("Should output valid JSON");
|
||||
let brew_id = created_brew["id"].as_i64().unwrap().to_string();
|
||||
|
||||
// Get the brew
|
||||
let output = run_brewlog(
|
||||
&["brew", "get", "--id", &brew_id],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"brew get should succeed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let brew: serde_json::Value = serde_json::from_str(&stdout).expect("Should output valid JSON");
|
||||
|
||||
assert_eq!(brew["coffee_weight"], 18.5);
|
||||
assert!(
|
||||
brew["roast_name"].is_string(),
|
||||
"should include enriched roast_name"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn brew_delete_removes_brew() {
|
||||
let token = create_token("brew-delete-test");
|
||||
let roaster_id = create_roaster("Brew Delete Roaster", &token);
|
||||
let roast_id = create_roast(&roaster_id, "Brew Delete Roast", &token);
|
||||
let bag_id = create_bag(&roast_id, &token);
|
||||
let grinder_id = create_gear("grinder", "Timemore", "C2", &token);
|
||||
let brewer_id = create_gear("brewer", "Melitta", "Pour Over", &token);
|
||||
|
||||
// Create a brew
|
||||
let create_output = run_brewlog(
|
||||
&[
|
||||
"brew",
|
||||
"add",
|
||||
"--bag-id",
|
||||
&bag_id,
|
||||
"--grinder-id",
|
||||
&grinder_id,
|
||||
"--brewer-id",
|
||||
&brewer_id,
|
||||
],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
|
||||
let create_stdout = String::from_utf8_lossy(&create_output.stdout);
|
||||
let created_brew: serde_json::Value =
|
||||
serde_json::from_str(&create_stdout).expect("Should output valid JSON");
|
||||
let brew_id = created_brew["id"].as_i64().unwrap().to_string();
|
||||
|
||||
// Delete the brew
|
||||
let output = run_brewlog(
|
||||
&["brew", "delete", "--id", &brew_id],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"brew delete should succeed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
|
||||
// Verify it's gone
|
||||
let get_output = run_brewlog(
|
||||
&["brew", "get", "--id", &brew_id],
|
||||
&[("BREWLOG_TOKEN", &token)],
|
||||
);
|
||||
assert!(
|
||||
!get_output.status.success(),
|
||||
"brew get should fail after deletion"
|
||||
);
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
pub mod bags_cli;
|
||||
pub mod brews_cli;
|
||||
pub mod gear_cli;
|
||||
pub mod helpers;
|
||||
pub mod roasters_cli;
|
||||
|
|
|
|||
368
tests/server/brews_api.rs
Normal file
368
tests/server/brews_api.rs
Normal file
|
|
@ -0,0 +1,368 @@
|
|||
use crate::helpers::{
|
||||
create_default_bag, create_default_gear, create_default_roast, create_default_roaster,
|
||||
spawn_app, spawn_app_with_auth,
|
||||
};
|
||||
use brewlog::domain::bags::Bag;
|
||||
use brewlog::domain::brews::{Brew, BrewWithDetails, NewBrew};
|
||||
|
||||
#[tokio::test]
|
||||
async fn creating_a_brew_returns_201_for_valid_data() {
|
||||
// Arrange
|
||||
let app = spawn_app_with_auth().await;
|
||||
let roaster = create_default_roaster(&app).await;
|
||||
let roast = create_default_roast(&app, roaster.id).await;
|
||||
let bag = create_default_bag(&app, roast.id).await;
|
||||
let grinder = create_default_gear(&app, "grinder", "Comandante", "C40 MK4").await;
|
||||
let brewer = create_default_gear(&app, "brewer", "Hario", "V60 02").await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let new_brew = NewBrew {
|
||||
bag_id: bag.id,
|
||||
coffee_weight: 15.0,
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 24.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 250,
|
||||
water_temp: 92.0,
|
||||
};
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert
|
||||
assert_eq!(response.status(), 201);
|
||||
|
||||
let brew: Brew = response.json().await.expect("Failed to parse response");
|
||||
assert_eq!(brew.bag_id, bag.id);
|
||||
assert_eq!(brew.coffee_weight, 15.0);
|
||||
assert_eq!(brew.grinder_id, grinder.id);
|
||||
assert_eq!(brew.grind_setting, 24.0);
|
||||
assert_eq!(brew.brewer_id, brewer.id);
|
||||
assert_eq!(brew.water_volume, 250);
|
||||
assert_eq!(brew.water_temp, 92.0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn creating_a_brew_deducts_from_bag_remaining() {
|
||||
// Arrange
|
||||
let app = spawn_app_with_auth().await;
|
||||
let roaster = create_default_roaster(&app).await;
|
||||
let roast = create_default_roast(&app, roaster.id).await;
|
||||
let bag = create_default_bag(&app, roast.id).await; // 250g
|
||||
let grinder = create_default_gear(&app, "grinder", "Comandante", "C40 MK4").await;
|
||||
let brewer = create_default_gear(&app, "brewer", "Hario", "V60 02").await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let new_brew = NewBrew {
|
||||
bag_id: bag.id,
|
||||
coffee_weight: 15.0,
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 24.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 250,
|
||||
water_temp: 92.0,
|
||||
};
|
||||
|
||||
// Act
|
||||
client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert - check bag remaining was deducted
|
||||
let bag_response = client
|
||||
.get(app.api_url(&format!("/bags/{}", bag.id)))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to get bag");
|
||||
|
||||
let updated_bag: Bag = bag_response.json().await.expect("Failed to parse bag");
|
||||
assert_eq!(updated_bag.remaining, 235.0); // 250 - 15 = 235
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn creating_a_brew_fails_if_insufficient_coffee_in_bag() {
|
||||
// Arrange
|
||||
let app = spawn_app_with_auth().await;
|
||||
let roaster = create_default_roaster(&app).await;
|
||||
let roast = create_default_roast(&app, roaster.id).await;
|
||||
let bag = create_default_bag(&app, roast.id).await; // 250g
|
||||
let grinder = create_default_gear(&app, "grinder", "Comandante", "C40 MK4").await;
|
||||
let brewer = create_default_gear(&app, "brewer", "Hario", "V60 02").await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let new_brew = NewBrew {
|
||||
bag_id: bag.id,
|
||||
coffee_weight: 300.0, // More than the 250g in the bag
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 24.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 250,
|
||||
water_temp: 92.0,
|
||||
};
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert
|
||||
assert_eq!(response.status(), 409); // Conflict
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn creating_a_brew_without_auth_returns_401() {
|
||||
// Arrange
|
||||
let app = spawn_app().await; // No auth
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let new_brew = serde_json::json!({
|
||||
"bag_id": 1,
|
||||
"coffee_weight": 15.0,
|
||||
"grinder_id": 1,
|
||||
"grind_setting": 24.0,
|
||||
"brewer_id": 2,
|
||||
"water_volume": 250,
|
||||
"water_temp": 92.0
|
||||
});
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
.post(app.api_url("/brews"))
|
||||
.json(&new_brew)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert
|
||||
assert_eq!(response.status(), 401);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn listing_brews_returns_200_and_enriched_data() {
|
||||
// Arrange
|
||||
let app = spawn_app_with_auth().await;
|
||||
let roaster = create_default_roaster(&app).await;
|
||||
let roast = create_default_roast(&app, roaster.id).await;
|
||||
let bag = create_default_bag(&app, roast.id).await;
|
||||
let grinder = create_default_gear(&app, "grinder", "Comandante", "C40 MK4").await;
|
||||
let brewer = create_default_gear(&app, "brewer", "Hario", "V60 02").await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
// Create a brew
|
||||
let new_brew = NewBrew {
|
||||
bag_id: bag.id,
|
||||
coffee_weight: 15.0,
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 24.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 250,
|
||||
water_temp: 92.0,
|
||||
};
|
||||
|
||||
client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to create brew");
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
.get(app.api_url("/brews"))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert
|
||||
assert_eq!(response.status(), 200);
|
||||
|
||||
let brews: Vec<BrewWithDetails> = response.json().await.expect("Failed to parse response");
|
||||
assert_eq!(brews.len(), 1);
|
||||
assert_eq!(brews[0].roast_name, roast.name);
|
||||
assert_eq!(brews[0].roaster_name, roaster.name);
|
||||
assert_eq!(brews[0].grinder_name, "Comandante C40 MK4");
|
||||
assert_eq!(brews[0].brewer_name, "Hario V60 02");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn listing_brews_with_bag_filter_returns_filtered_results() {
|
||||
// Arrange
|
||||
let app = spawn_app_with_auth().await;
|
||||
let roaster = create_default_roaster(&app).await;
|
||||
let roast = create_default_roast(&app, roaster.id).await;
|
||||
let bag1 = create_default_bag(&app, roast.id).await;
|
||||
let bag2 = create_default_bag(&app, roast.id).await;
|
||||
let grinder = create_default_gear(&app, "grinder", "Comandante", "C40 MK4").await;
|
||||
let brewer = create_default_gear(&app, "brewer", "Hario", "V60 02").await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
// Create brew for bag1
|
||||
let new_brew1 = NewBrew {
|
||||
bag_id: bag1.id,
|
||||
coffee_weight: 15.0,
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 24.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 250,
|
||||
water_temp: 92.0,
|
||||
};
|
||||
|
||||
client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew1)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to create brew 1");
|
||||
|
||||
// Create brew for bag2
|
||||
let new_brew2 = NewBrew {
|
||||
bag_id: bag2.id,
|
||||
coffee_weight: 17.0,
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 22.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 255,
|
||||
water_temp: 88.0,
|
||||
};
|
||||
|
||||
client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew2)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to create brew 2");
|
||||
|
||||
// Act - filter by bag1
|
||||
let response = client
|
||||
.get(app.api_url(&format!("/brews?bag_id={}", bag1.id)))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert
|
||||
assert_eq!(response.status(), 200);
|
||||
|
||||
let brews: Vec<BrewWithDetails> = response.json().await.expect("Failed to parse response");
|
||||
assert_eq!(brews.len(), 1);
|
||||
assert_eq!(brews[0].brew.coffee_weight, 15.0);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn getting_a_brew_returns_200_for_valid_id() {
|
||||
// Arrange
|
||||
let app = spawn_app_with_auth().await;
|
||||
let roaster = create_default_roaster(&app).await;
|
||||
let roast = create_default_roast(&app, roaster.id).await;
|
||||
let bag = create_default_bag(&app, roast.id).await;
|
||||
let grinder = create_default_gear(&app, "grinder", "Comandante", "C40 MK4").await;
|
||||
let brewer = create_default_gear(&app, "brewer", "Hario", "V60 02").await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let new_brew = NewBrew {
|
||||
bag_id: bag.id,
|
||||
coffee_weight: 15.0,
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 24.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 250,
|
||||
water_temp: 92.0,
|
||||
};
|
||||
|
||||
let create_response = client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to create brew");
|
||||
|
||||
let created_brew: Brew = create_response
|
||||
.json()
|
||||
.await
|
||||
.expect("Failed to parse response");
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
.get(app.api_url(&format!("/brews/{}", created_brew.id)))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert
|
||||
assert_eq!(response.status(), 200);
|
||||
let brew: BrewWithDetails = response.json().await.expect("Failed to parse response");
|
||||
assert_eq!(brew.brew.id, created_brew.id);
|
||||
assert_eq!(brew.roast_name, roast.name);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn deleting_a_brew_returns_204() {
|
||||
// Arrange
|
||||
let app = spawn_app_with_auth().await;
|
||||
let roaster = create_default_roaster(&app).await;
|
||||
let roast = create_default_roast(&app, roaster.id).await;
|
||||
let bag = create_default_bag(&app, roast.id).await;
|
||||
let grinder = create_default_gear(&app, "grinder", "Comandante", "C40 MK4").await;
|
||||
let brewer = create_default_gear(&app, "brewer", "Hario", "V60 02").await;
|
||||
let client = reqwest::Client::new();
|
||||
|
||||
let new_brew = NewBrew {
|
||||
bag_id: bag.id,
|
||||
coffee_weight: 15.0,
|
||||
grinder_id: grinder.id,
|
||||
grind_setting: 24.0,
|
||||
brewer_id: brewer.id,
|
||||
water_volume: 250,
|
||||
water_temp: 92.0,
|
||||
};
|
||||
|
||||
let create_response = client
|
||||
.post(app.api_url("/brews"))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.json(&new_brew)
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to create brew");
|
||||
|
||||
let created_brew: Brew = create_response
|
||||
.json()
|
||||
.await
|
||||
.expect("Failed to parse response");
|
||||
|
||||
// Act
|
||||
let response = client
|
||||
.delete(app.api_url(&format!("/brews/{}", created_brew.id)))
|
||||
.bearer_auth(app.auth_token.as_ref().unwrap())
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
// Assert
|
||||
assert_eq!(response.status(), 204);
|
||||
|
||||
// Verify deletion
|
||||
let get_response = client
|
||||
.get(app.api_url(&format!("/brews/{}", created_brew.id)))
|
||||
.send()
|
||||
.await
|
||||
.expect("Failed to execute request");
|
||||
|
||||
assert_eq!(get_response.status(), 404);
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ use brewlog::domain::users::NewUser;
|
|||
use brewlog::infrastructure::auth::hash_password;
|
||||
use brewlog::infrastructure::database::Database;
|
||||
use brewlog::infrastructure::repositories::bags::SqlBagRepository;
|
||||
use brewlog::infrastructure::repositories::brews::SqlBrewRepository;
|
||||
use brewlog::infrastructure::repositories::gear::SqlGearRepository;
|
||||
use brewlog::infrastructure::repositories::roasters::SqlRoasterRepository;
|
||||
use brewlog::infrastructure::repositories::roasts::SqlRoastRepository;
|
||||
|
|
@ -57,6 +58,7 @@ pub async fn spawn_app() -> TestApp {
|
|||
let roast_repo = Arc::new(SqlRoastRepository::new(database.clone_pool()));
|
||||
let bag_repo = Arc::new(SqlBagRepository::new(database.clone_pool()));
|
||||
let gear_repo = Arc::new(SqlGearRepository::new(database.clone_pool()));
|
||||
let brew_repo = Arc::new(SqlBrewRepository::new(database.clone_pool()));
|
||||
let timeline_repo = Arc::new(SqlTimelineEventRepository::new(database.clone_pool()));
|
||||
let user_repo: Arc<dyn UserRepository> =
|
||||
Arc::new(SqlUserRepository::new(database.clone_pool()));
|
||||
|
|
@ -71,6 +73,7 @@ pub async fn spawn_app() -> TestApp {
|
|||
roast_repo.clone(),
|
||||
bag_repo.clone(),
|
||||
gear_repo.clone(),
|
||||
brew_repo.clone(),
|
||||
timeline_repo.clone(),
|
||||
user_repo.clone(),
|
||||
token_repo.clone(),
|
||||
|
|
@ -289,3 +292,35 @@ pub fn assert_full_page(body: &str) {
|
|||
"Expected full HTML page with DOCTYPE or <html> tag"
|
||||
);
|
||||
}
|
||||
|
||||
pub async fn create_default_gear(
|
||||
app: &TestApp,
|
||||
category: &str,
|
||||
make: &str,
|
||||
model: &str,
|
||||
) -> brewlog::domain::gear::Gear {
|
||||
let client = Client::new();
|
||||
let gear_category = match category {
|
||||
"grinder" => brewlog::domain::gear::GearCategory::Grinder,
|
||||
"brewer" => brewlog::domain::gear::GearCategory::Brewer,
|
||||
_ => panic!("Unknown gear category: {}", category),
|
||||
};
|
||||
let new_gear = brewlog::domain::gear::NewGear {
|
||||
category: gear_category,
|
||||
make: make.to_string(),
|
||||
model: model.to_string(),
|
||||
};
|
||||
|
||||
let mut request = client.post(app.api_url("/gear")).json(&new_gear);
|
||||
|
||||
if let Some(token) = &app.auth_token {
|
||||
request = request.bearer_auth(token);
|
||||
}
|
||||
|
||||
let response = request.send().await.expect("failed to create gear via API");
|
||||
|
||||
response
|
||||
.json()
|
||||
.await
|
||||
.expect("failed to deserialize gear from response")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
pub mod auth_api;
|
||||
pub mod bags_api;
|
||||
pub mod brews_api;
|
||||
pub mod datastar;
|
||||
pub mod gear_api;
|
||||
pub mod helpers;
|
||||
|
|
|
|||
Loading…
Reference in a new issue