use crate::helpers::{ConfirmationLinks, TestApp, assert_is_redirect_to}; use wiremock::{ Mock, ResponseTemplate, matchers::{any, method, path}, }; #[tokio::test] async fn newsletters_are_not_delivered_to_unconfirmed_subscribers() { let app = TestApp::spawn().await; create_unconfirmed_subscriber(&app).await; let login_body = serde_json::json!({ "username": app.test_user.username, "password": app.test_user.password }); app.post_login(&login_body).await; Mock::given(any()) .respond_with(ResponseTemplate::new(200)) .expect(0) .mount(&app.email_server) .await; let newsletter_request_body = serde_json::json!({ "title": "Newsletter title", "text": "Newsletter body as plain text", "html": "

Newsletter body as HTML

" }); app.post_newsletters(&newsletter_request_body).await; } #[tokio::test] async fn requests_without_authentication_are_redirected() { let app = TestApp::spawn().await; Mock::given(any()) .respond_with(ResponseTemplate::new(200)) .expect(0) .mount(&app.email_server) .await; let newsletter_request_body = serde_json::json!({ "title": "Newsletter title", "text": "Newsletter body as plain text", "html": "

Newsletter body as HTML

" }); let response = app.post_newsletters(&newsletter_request_body).await; assert_is_redirect_to(&response, "/login"); } #[tokio::test] async fn newsletters_are_delivered_to_confirmed_subscribers() { let app = TestApp::spawn().await; create_confirmed_subscriber(&app).await; let login_body = serde_json::json!({ "username": app.test_user.username, "password": app.test_user.password }); app.post_login(&login_body).await; Mock::given(any()) .respond_with(ResponseTemplate::new(200)) .expect(1) .mount(&app.email_server) .await; let newsletter_title = "Newsletter title"; let newsletter_request_body = serde_json::json!({ "title": newsletter_title, "text": "Newsletter body as plain text", "html": "

Newsletter body as HTML

" }); let response = app.post_newsletters(&newsletter_request_body).await; assert_is_redirect_to(&response, "/admin/newsletters"); let html_page = app.get_newsletter_form_html().await; assert!(html_page.contains(&format!( "The newsletter issue '{}' has been published", newsletter_title ))); } #[tokio::test] async fn form_shows_error_for_invalid_data() { let app = TestApp::spawn().await; let login_body = serde_json::json!({ "username": app.test_user.username, "password": app.test_user.password }); app.post_login(&login_body).await; Mock::given(any()) .respond_with(ResponseTemplate::new(200)) .expect(0) .mount(&app.email_server) .await; let test_cases = [ ( serde_json::json!({ "title": "", "text": "Newsletter body as plain text", "html": "

Newsletter body as HTML

" }), "The title was empty", ), ( serde_json::json!({ "title": "Newsletter", "text": "", "html": "" }), "The content was empty", ), ]; for (invalid_body, error_message) in test_cases { app.post_newsletters(&invalid_body).await; let html_page = app.get_newsletter_form_html().await; assert!(html_page.contains(error_message)); } } #[tokio::test] async fn newsletter_creation_is_idempotent() { let app = TestApp::spawn().await; create_confirmed_subscriber(&app).await; let login_body = serde_json::json!({ "username": app.test_user.username, "password": app.test_user.password }); app.post_login(&login_body).await; Mock::given(any()) .respond_with(ResponseTemplate::new(200)) .expect(1) .mount(&app.email_server) .await; let newsletter_title = "Newsletter title"; let newsletter_request_body = serde_json::json!({ "title": newsletter_title, "text": "Newsletter body as plain text", "html": "

Newsletter body as HTML

" }); let response = app.post_newsletters(&newsletter_request_body).await; assert_is_redirect_to(&response, "/admin/newsletters"); let html_page = app.get_newsletter_form_html().await; assert!(html_page.contains(&format!( "The newsletter issue '{}' has been published", newsletter_title ))); let response = app.post_newsletters(&newsletter_request_body).await; assert_is_redirect_to(&response, "/admin/newsletters"); let html_page = app.get_newsletter_form_html().await; assert!(html_page.contains(&format!( "The newsletter issue '{}' has been published", newsletter_title ))); } async fn create_unconfirmed_subscriber(app: &TestApp) -> ConfirmationLinks { let body = "name=Alphonse&email=alphonse.paix%40outlook.com"; let _mock_guard = Mock::given(path("/v1/email")) .and(method("POST")) .respond_with(ResponseTemplate::new(200)) .named("Create unconfirmed subscriber") .expect(1) .mount_as_scoped(&app.email_server) .await; app.post_subscriptions(body.into()) .await .error_for_status() .unwrap(); let email_request = &app .email_server .received_requests() .await .unwrap() .pop() .unwrap(); app.get_confirmation_links(email_request) } async fn create_confirmed_subscriber(app: &TestApp) { let confirmation_links = create_unconfirmed_subscriber(app).await; reqwest::get(confirmation_links.html) .await .unwrap() .error_for_status() .unwrap(); }