test(server): fix broken tests by adding authentication support

- Update all server tests to use spawn_app_with_auth() helper
- spawn_app_with_auth() creates admin user and test token automatically
- Add helper methods (post/put/delete/get) to TestApp for authenticated requests
- Update create_roaster_with_payload to include auth token when available
- Add bearer_auth() to all write operation test requests
- Fix auth_api test to expect 2 tokens (test helper + test-created)
- All 42 server tests now pass

Co-authored-by: jnsgruk <668505+jnsgruk@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-11-25 11:13:04 +00:00 committed by Jon Seager
parent 0e35d18a21
commit ac355b1b8e
No known key found for this signature in database
5 changed files with 145 additions and 42 deletions

View file

@ -101,8 +101,14 @@ async fn test_list_tokens_with_authentication() {
assert_eq!(response.status(), StatusCode::OK); assert_eq!(response.status(), StatusCode::OK);
let tokens: Vec<serde_json::Value> = response.json().await.expect("Failed to parse response"); let tokens: Vec<serde_json::Value> = response.json().await.expect("Failed to parse response");
assert_eq!(tokens.len(), 1); // We expect 2 tokens: the one created by spawn_app_with_auth() and the one we just created
assert_eq!(tokens[0].get("name").unwrap(), "test-token"); assert_eq!(tokens.len(), 2);
// Find the token we created
let test_token = tokens
.iter()
.find(|t| t.get("name").unwrap() == "test-token")
.expect("Could not find test-token");
assert_eq!(test_token.get("name").unwrap(), "test-token");
} }
#[tokio::test] #[tokio::test]

View file

@ -28,12 +28,49 @@ pub struct TestApp {
pub user_repo: Option<Arc<dyn UserRepository>>, pub user_repo: Option<Arc<dyn UserRepository>>,
#[allow(dead_code)] #[allow(dead_code)]
pub token_repo: Option<Arc<dyn TokenRepository>>, pub token_repo: Option<Arc<dyn TokenRepository>>,
pub auth_token: Option<String>,
} }
impl TestApp { impl TestApp {
pub fn api_url(&self, path: &str) -> String { pub fn api_url(&self, path: &str) -> String {
format!("{}/api/v1{}", self.address, path) format!("{}/api/v1{}", self.address, path)
} }
/// Create an authenticated POST request
pub fn post(&self, path: &str) -> reqwest::RequestBuilder {
let client = Client::new();
let mut req = client.post(self.api_url(path));
if let Some(token) = &self.auth_token {
req = req.bearer_auth(token);
}
req
}
/// Create an authenticated PUT request
pub fn put(&self, path: &str) -> reqwest::RequestBuilder {
let client = Client::new();
let mut req = client.put(self.api_url(path));
if let Some(token) = &self.auth_token {
req = req.bearer_auth(token);
}
req
}
/// Create an authenticated DELETE request
pub fn delete(&self, path: &str) -> reqwest::RequestBuilder {
let client = Client::new();
let mut req = client.delete(self.api_url(path));
if let Some(token) = &self.auth_token {
req = req.bearer_auth(token);
}
req
}
/// Create a GET request (doesn't need auth for reads)
pub fn get(&self, path: &str) -> reqwest::RequestBuilder {
let client = Client::new();
client.get(self.api_url(path))
}
} }
pub async fn spawn_app() -> TestApp { pub async fn spawn_app() -> TestApp {
@ -91,11 +128,12 @@ pub async fn spawn_app() -> TestApp {
timeline_repo, timeline_repo,
user_repo: Some(user_repo), user_repo: Some(user_repo),
token_repo: Some(token_repo), token_repo: Some(token_repo),
auth_token: None,
} }
} }
pub async fn spawn_app_with_auth() -> TestApp { pub async fn spawn_app_with_auth() -> TestApp {
let app = spawn_app().await; let mut app = spawn_app().await;
// Create admin user with known password // Create admin user with known password
let password_hash = hash_password("test_password").expect("Failed to hash password"); let password_hash = hash_password("test_password").expect("Failed to hash password");
@ -113,14 +151,41 @@ pub async fn spawn_app_with_auth() -> TestApp {
.await .await
.expect("Failed to create admin user"); .expect("Failed to create admin user");
// Create a token for testing
use brewlog::domain::tokens::Token;
use brewlog::infrastructure::auth::{generate_token, hash_token};
let token_value = generate_token().expect("Failed to generate token");
let token_hash = hash_token(&token_value);
let token = Token::new(
"test_token_id".to_string(),
"test_admin_id".to_string(),
token_hash,
"test-token".to_string(),
Utc::now(),
);
app.token_repo
.as_ref()
.unwrap()
.insert(token)
.await
.expect("Failed to insert token");
app.auth_token = Some(token_value);
app app
} }
pub async fn create_roaster_with_payload(app: &TestApp, payload: NewRoaster) -> Roaster { pub async fn create_roaster_with_payload(app: &TestApp, payload: NewRoaster) -> Roaster {
let client = Client::new(); let client = Client::new();
let response = client let mut request = client.post(app.api_url("/roasters")).json(&payload);
.post(app.api_url("/roasters"))
.json(&payload) // Add auth token if available
if let Some(token) = &app.auth_token {
request = request.bearer_auth(token);
}
let response = request
.send() .send()
.await .await
.expect("failed to create roaster via API"); .expect("failed to create roaster via API");

View file

@ -1,10 +1,10 @@
use crate::helpers::spawn_app; use crate::helpers::spawn_app_with_auth;
use brewlog::domain::roasters::{NewRoaster, Roaster, UpdateRoaster}; use brewlog::domain::roasters::{NewRoaster, Roaster, UpdateRoaster};
#[tokio::test] #[tokio::test]
async fn creating_a_roaster_returns_a_201_for_valid_data() { async fn creating_a_roaster_returns_a_201_for_valid_data() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let new_roaster = NewRoaster { let new_roaster = NewRoaster {
@ -18,6 +18,7 @@ async fn creating_a_roaster_returns_a_201_for_valid_data() {
// Act // Act
let response = client let response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roaster) .json(&new_roaster)
.send() .send()
.await .await
@ -37,7 +38,7 @@ async fn creating_a_roaster_returns_a_201_for_valid_data() {
#[tokio::test] #[tokio::test]
async fn creating_a_roaster_persists_the_data() { async fn creating_a_roaster_persists_the_data() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let new_roaster = NewRoaster { let new_roaster = NewRoaster {
@ -51,6 +52,7 @@ async fn creating_a_roaster_persists_the_data() {
// Act // Act
let response = client let response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roaster) .json(&new_roaster)
.send() .send()
.await .await
@ -73,7 +75,7 @@ async fn creating_a_roaster_persists_the_data() {
#[tokio::test] #[tokio::test]
async fn getting_a_roaster_returns_a_200_for_valid_id() { async fn getting_a_roaster_returns_a_200_for_valid_id() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let new_roaster = NewRoaster { let new_roaster = NewRoaster {
@ -86,6 +88,7 @@ async fn getting_a_roaster_returns_a_200_for_valid_id() {
let create_response = client let create_response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roaster) .json(&new_roaster)
.send() .send()
.await .await
@ -114,7 +117,7 @@ async fn getting_a_roaster_returns_a_200_for_valid_id() {
#[tokio::test] #[tokio::test]
async fn getting_a_nonexistent_roaster_returns_a_404() { async fn getting_a_nonexistent_roaster_returns_a_404() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
@ -131,7 +134,7 @@ async fn getting_a_nonexistent_roaster_returns_a_404() {
#[tokio::test] #[tokio::test]
async fn listing_roasters_returns_a_200_with_empty_list() { async fn listing_roasters_returns_a_200_with_empty_list() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
@ -151,7 +154,7 @@ async fn listing_roasters_returns_a_200_with_empty_list() {
#[tokio::test] #[tokio::test]
async fn listing_roasters_returns_a_200_with_multiple_roasters() { async fn listing_roasters_returns_a_200_with_multiple_roasters() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Create multiple roasters // Create multiple roasters
@ -173,6 +176,7 @@ async fn listing_roasters_returns_a_200_with_multiple_roasters() {
client client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&roaster1) .json(&roaster1)
.send() .send()
.await .await
@ -180,6 +184,7 @@ async fn listing_roasters_returns_a_200_with_multiple_roasters() {
client client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&roaster2) .json(&roaster2)
.send() .send()
.await .await
@ -202,7 +207,7 @@ async fn listing_roasters_returns_a_200_with_multiple_roasters() {
#[tokio::test] #[tokio::test]
async fn updating_a_roaster_returns_a_200_for_valid_data() { async fn updating_a_roaster_returns_a_200_for_valid_data() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let new_roaster = NewRoaster { let new_roaster = NewRoaster {
@ -215,6 +220,7 @@ async fn updating_a_roaster_returns_a_200_for_valid_data() {
let create_response = client let create_response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roaster) .json(&new_roaster)
.send() .send()
.await .await
@ -236,6 +242,7 @@ async fn updating_a_roaster_returns_a_200_for_valid_data() {
// Act // Act
let response = client let response = client
.put(app.api_url(&format!("/roasters/{}", created_roaster.id))) .put(app.api_url(&format!("/roasters/{}", created_roaster.id)))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&update) .json(&update)
.send() .send()
.await .await
@ -257,7 +264,7 @@ async fn updating_a_roaster_returns_a_200_for_valid_data() {
#[tokio::test] #[tokio::test]
async fn updating_a_roaster_with_no_changes_returns_a_400() { async fn updating_a_roaster_with_no_changes_returns_a_400() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let new_roaster = NewRoaster { let new_roaster = NewRoaster {
@ -270,6 +277,7 @@ async fn updating_a_roaster_with_no_changes_returns_a_400() {
let create_response = client let create_response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roaster) .json(&new_roaster)
.send() .send()
.await .await
@ -291,6 +299,7 @@ async fn updating_a_roaster_with_no_changes_returns_a_400() {
// Act // Act
let response = client let response = client
.put(app.api_url(&format!("/roasters/{}", created_roaster.id))) .put(app.api_url(&format!("/roasters/{}", created_roaster.id)))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&update) .json(&update)
.send() .send()
.await .await
@ -303,7 +312,7 @@ async fn updating_a_roaster_with_no_changes_returns_a_400() {
#[tokio::test] #[tokio::test]
async fn updating_a_nonexistent_roaster_returns_a_404() { async fn updating_a_nonexistent_roaster_returns_a_404() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let update = UpdateRoaster { let update = UpdateRoaster {
@ -317,6 +326,7 @@ async fn updating_a_nonexistent_roaster_returns_a_404() {
// Act // Act
let response = client let response = client
.put(app.api_url("/roasters/nonexistent-id")) .put(app.api_url("/roasters/nonexistent-id"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&update) .json(&update)
.send() .send()
.await .await
@ -329,7 +339,7 @@ async fn updating_a_nonexistent_roaster_returns_a_404() {
#[tokio::test] #[tokio::test]
async fn deleting_a_roaster_returns_a_204_for_valid_id() { async fn deleting_a_roaster_returns_a_204_for_valid_id() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let new_roaster = NewRoaster { let new_roaster = NewRoaster {
@ -342,6 +352,7 @@ async fn deleting_a_roaster_returns_a_204_for_valid_id() {
let create_response = client let create_response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roaster) .json(&new_roaster)
.send() .send()
.await .await
@ -355,6 +366,7 @@ async fn deleting_a_roaster_returns_a_204_for_valid_id() {
// Act // Act
let response = client let response = client
.delete(app.api_url(&format!("/roasters/{}", created_roaster.id))) .delete(app.api_url(&format!("/roasters/{}", created_roaster.id)))
.bearer_auth(app.auth_token.as_ref().unwrap())
.send() .send()
.await .await
.expect("Failed to execute request"); .expect("Failed to execute request");
@ -375,12 +387,13 @@ async fn deleting_a_roaster_returns_a_204_for_valid_id() {
#[tokio::test] #[tokio::test]
async fn deleting_a_nonexistent_roaster_returns_a_404() { async fn deleting_a_nonexistent_roaster_returns_a_404() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
let response = client let response = client
.delete(app.api_url("/roasters/nonexistent-id")) .delete(app.api_url("/roasters/nonexistent-id"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.send() .send()
.await .await
.expect("Failed to execute request"); .expect("Failed to execute request");
@ -392,7 +405,7 @@ async fn deleting_a_nonexistent_roaster_returns_a_404() {
#[tokio::test] #[tokio::test]
async fn creating_a_roaster_with_empty_name_returns_a_201_after_normalization() { async fn creating_a_roaster_with_empty_name_returns_a_201_after_normalization() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// The normalize function trims whitespace, so empty/whitespace names become empty // The normalize function trims whitespace, so empty/whitespace names become empty
@ -407,6 +420,7 @@ async fn creating_a_roaster_with_empty_name_returns_a_201_after_normalization()
// Act // Act
let response = client let response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roaster) .json(&new_roaster)
.send() .send()
.await .await
@ -419,12 +433,13 @@ async fn creating_a_roaster_with_empty_name_returns_a_201_after_normalization()
#[tokio::test] #[tokio::test]
async fn creating_a_roaster_with_malformed_json_returns_a_400() { async fn creating_a_roaster_with_malformed_json_returns_a_400() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
let response = client let response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.header("content-type", "application/json") .header("content-type", "application/json")
.body(r#"{"name": "Test", "country": }"#) // Invalid JSON .body(r#"{"name": "Test", "country": }"#) // Invalid JSON
.send() .send()
@ -438,12 +453,13 @@ async fn creating_a_roaster_with_malformed_json_returns_a_400() {
#[tokio::test] #[tokio::test]
async fn creating_a_roaster_with_missing_required_fields_returns_a_400() { async fn creating_a_roaster_with_missing_required_fields_returns_a_400() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act - Missing 'country' field // Act - Missing 'country' field
let response = client let response = client
.post(app.api_url("/roasters")) .post(app.api_url("/roasters"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.header("content-type", "application/json") .header("content-type", "application/json")
.body(r#"{"name": "Test Roasters"}"#) .body(r#"{"name": "Test Roasters"}"#)
.send() .send()

View file

@ -1,10 +1,10 @@
use crate::helpers::{create_default_roaster, create_roaster_with_name, spawn_app}; use crate::helpers::{create_default_roaster, create_roaster_with_name, spawn_app_with_auth};
use brewlog::domain::roasts::{NewRoast, Roast, RoastWithRoaster}; use brewlog::domain::roasts::{NewRoast, Roast, RoastWithRoaster};
#[tokio::test] #[tokio::test]
async fn creating_a_roast_returns_a_201_for_valid_data() { async fn creating_a_roast_returns_a_201_for_valid_data() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
@ -25,6 +25,7 @@ async fn creating_a_roast_returns_a_201_for_valid_data() {
// Act // Act
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roast) .json(&new_roast)
.send() .send()
.await .await
@ -46,7 +47,7 @@ async fn creating_a_roast_returns_a_201_for_valid_data() {
#[tokio::test] #[tokio::test]
async fn creating_a_roast_persists_the_data() { async fn creating_a_roast_persists_the_data() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
@ -63,6 +64,7 @@ async fn creating_a_roast_persists_the_data() {
// Act // Act
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roast) .json(&new_roast)
.send() .send()
.await .await
@ -85,7 +87,7 @@ async fn creating_a_roast_persists_the_data() {
#[tokio::test] #[tokio::test]
async fn creating_a_roast_with_nonexistent_roaster_returns_a_404() { async fn creating_a_roast_with_nonexistent_roaster_returns_a_404() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
let new_roast = NewRoast { let new_roast = NewRoast {
@ -101,6 +103,7 @@ async fn creating_a_roast_with_nonexistent_roaster_returns_a_404() {
// Act // Act
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roast) .json(&new_roast)
.send() .send()
.await .await
@ -113,7 +116,7 @@ async fn creating_a_roast_with_nonexistent_roaster_returns_a_404() {
#[tokio::test] #[tokio::test]
async fn getting_a_roast_returns_a_200_for_valid_id() { async fn getting_a_roast_returns_a_200_for_valid_id() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
@ -129,6 +132,7 @@ async fn getting_a_roast_returns_a_200_for_valid_id() {
let create_response = client let create_response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roast) .json(&new_roast)
.send() .send()
.await .await
@ -157,7 +161,7 @@ async fn getting_a_roast_returns_a_200_for_valid_id() {
#[tokio::test] #[tokio::test]
async fn getting_a_nonexistent_roast_returns_a_404() { async fn getting_a_nonexistent_roast_returns_a_404() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
@ -174,7 +178,7 @@ async fn getting_a_nonexistent_roast_returns_a_404() {
#[tokio::test] #[tokio::test]
async fn listing_roasts_returns_a_200_with_empty_list() { async fn listing_roasts_returns_a_200_with_empty_list() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
@ -194,7 +198,7 @@ async fn listing_roasts_returns_a_200_with_empty_list() {
#[tokio::test] #[tokio::test]
async fn listing_roasts_returns_a_200_with_multiple_roasts() { async fn listing_roasts_returns_a_200_with_multiple_roasts() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
@ -221,6 +225,7 @@ async fn listing_roasts_returns_a_200_with_multiple_roasts() {
client client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&roast1) .json(&roast1)
.send() .send()
.await .await
@ -228,6 +233,7 @@ async fn listing_roasts_returns_a_200_with_multiple_roasts() {
client client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&roast2) .json(&roast2)
.send() .send()
.await .await
@ -250,7 +256,7 @@ async fn listing_roasts_returns_a_200_with_multiple_roasts() {
#[tokio::test] #[tokio::test]
async fn listing_roasts_by_roaster_returns_a_200_with_filtered_list() { async fn listing_roasts_by_roaster_returns_a_200_with_filtered_list() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster1_id = create_default_roaster(&app).await.id; let roaster1_id = create_default_roaster(&app).await.id;
let roaster2_id = create_roaster_with_name(&app, "Second Roasters").await.id; let roaster2_id = create_roaster_with_name(&app, "Second Roasters").await.id;
@ -279,6 +285,7 @@ async fn listing_roasts_by_roaster_returns_a_200_with_filtered_list() {
client client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&roast1) .json(&roast1)
.send() .send()
.await .await
@ -286,6 +293,7 @@ async fn listing_roasts_by_roaster_returns_a_200_with_filtered_list() {
client client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&roast2) .json(&roast2)
.send() .send()
.await .await
@ -309,7 +317,7 @@ async fn listing_roasts_by_roaster_returns_a_200_with_filtered_list() {
#[tokio::test] #[tokio::test]
async fn deleting_a_roast_returns_a_204_for_valid_id() { async fn deleting_a_roast_returns_a_204_for_valid_id() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
@ -325,6 +333,7 @@ async fn deleting_a_roast_returns_a_204_for_valid_id() {
let create_response = client let create_response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&new_roast) .json(&new_roast)
.send() .send()
.await .await
@ -338,6 +347,7 @@ async fn deleting_a_roast_returns_a_204_for_valid_id() {
// Act // Act
let response = client let response = client
.delete(app.api_url(&format!("/roasts/{}", created_roast.id))) .delete(app.api_url(&format!("/roasts/{}", created_roast.id)))
.bearer_auth(app.auth_token.as_ref().unwrap())
.send() .send()
.await .await
.expect("Failed to execute request"); .expect("Failed to execute request");
@ -358,12 +368,13 @@ async fn deleting_a_roast_returns_a_204_for_valid_id() {
#[tokio::test] #[tokio::test]
async fn deleting_a_nonexistent_roast_returns_a_404() { async fn deleting_a_nonexistent_roast_returns_a_404() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
let response = client let response = client
.delete(app.api_url("/roasts/nonexistent-id")) .delete(app.api_url("/roasts/nonexistent-id"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.send() .send()
.await .await
.expect("Failed to execute request"); .expect("Failed to execute request");
@ -375,13 +386,14 @@ async fn deleting_a_nonexistent_roast_returns_a_404() {
#[tokio::test] #[tokio::test]
async fn creating_a_roast_with_empty_name_returns_a_400() { async fn creating_a_roast_with_empty_name_returns_a_400() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act - Create roast with empty name (after trim) // Act - Create roast with empty name (after trim)
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.header("content-type", "application/json") .header("content-type", "application/json")
.body(format!( .body(format!(
r#"{{ r#"{{
@ -406,13 +418,14 @@ async fn creating_a_roast_with_empty_name_returns_a_400() {
#[tokio::test] #[tokio::test]
async fn creating_a_roast_with_missing_required_fields_returns_a_400() { async fn creating_a_roast_with_missing_required_fields_returns_a_400() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act - Missing 'origin' field // Act - Missing 'origin' field
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.header("content-type", "application/json") .header("content-type", "application/json")
.body(format!( .body(format!(
r#"{{ r#"{{
@ -436,13 +449,14 @@ async fn creating_a_roast_with_missing_required_fields_returns_a_400() {
#[tokio::test] #[tokio::test]
async fn creating_a_roast_with_empty_tasting_notes_returns_a_400() { async fn creating_a_roast_with_empty_tasting_notes_returns_a_400() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let roaster_id = create_default_roaster(&app).await.id; let roaster_id = create_default_roaster(&app).await.id;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act - Empty tasting notes // Act - Empty tasting notes
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.header("content-type", "application/json") .header("content-type", "application/json")
.body(format!( .body(format!(
r#"{{ r#"{{
@ -467,12 +481,13 @@ async fn creating_a_roast_with_empty_tasting_notes_returns_a_400() {
#[tokio::test] #[tokio::test]
async fn creating_a_roast_with_malformed_json_returns_a_400() { async fn creating_a_roast_with_malformed_json_returns_a_400() {
// Arrange // Arrange
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = reqwest::Client::new(); let client = reqwest::Client::new();
// Act // Act
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.header("content-type", "application/json") .header("content-type", "application/json")
.body(r#"{"name": "Test", "roaster_id": }"#) // Invalid JSON .body(r#"{"name": "Test", "roaster_id": }"#) // Invalid JSON
.send() .send()

View file

@ -1,4 +1,4 @@
use crate::helpers::{create_roaster_with_payload, spawn_app}; use crate::helpers::{create_roaster_with_payload, spawn_app_with_auth};
use brewlog::domain::roasters::NewRoaster; use brewlog::domain::roasters::NewRoaster;
use brewlog::domain::roasts::NewRoast; use brewlog::domain::roasts::NewRoast;
use reqwest::Client; use reqwest::Client;
@ -18,6 +18,7 @@ async fn create_roast(app: &crate::helpers::TestApp, roaster_id: &str, name: &st
let response = client let response = client
.post(app.api_url("/roasts")) .post(app.api_url("/roasts"))
.bearer_auth(app.auth_token.as_ref().unwrap())
.json(&roast) .json(&roast)
.send() .send()
.await .await
@ -60,7 +61,7 @@ async fn seed_timeline_with_roasts(
#[tokio::test] #[tokio::test]
async fn timeline_page_returns_a_200_with_empty_state() { async fn timeline_page_returns_a_200_with_empty_state() {
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = Client::new(); let client = Client::new();
let response = client let response = client
@ -80,7 +81,7 @@ async fn timeline_page_returns_a_200_with_empty_state() {
#[tokio::test] #[tokio::test]
async fn creating_a_roaster_surfaces_on_the_timeline() { async fn creating_a_roaster_surfaces_on_the_timeline() {
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = Client::new(); let client = Client::new();
let roaster_name = "Timeline Roasters"; let roaster_name = "Timeline Roasters";
@ -124,7 +125,7 @@ async fn creating_a_roaster_surfaces_on_the_timeline() {
#[tokio::test] #[tokio::test]
async fn creating_a_roast_surfaces_on_the_timeline() { async fn creating_a_roast_surfaces_on_the_timeline() {
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let client = Client::new(); let client = Client::new();
let roaster_id = create_roaster_with_payload( let roaster_id = create_roaster_with_payload(
@ -169,7 +170,7 @@ async fn creating_a_roast_surfaces_on_the_timeline() {
#[tokio::test] #[tokio::test]
async fn timeline_page_signals_more_results_when_over_page_size() { async fn timeline_page_signals_more_results_when_over_page_size() {
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let (_, roast_names) = seed_timeline_with_roasts(&app, 6).await; let (_, roast_names) = seed_timeline_with_roasts(&app, 6).await;
assert_eq!(roast_names.len(), 6); assert_eq!(roast_names.len(), 6);
@ -211,7 +212,7 @@ async fn timeline_page_signals_more_results_when_over_page_size() {
#[tokio::test] #[tokio::test]
async fn timeline_chunk_endpoint_serves_remaining_events() { async fn timeline_chunk_endpoint_serves_remaining_events() {
let app = spawn_app().await; let app = spawn_app_with_auth().await;
let (roaster_name, roast_names) = seed_timeline_with_roasts(&app, 6).await; let (roaster_name, roast_names) = seed_timeline_with_roasts(&app, 6).await;
let oldest_roast = roast_names let oldest_roast = roast_names
.first() .first()