use crate::helpers::{ TestApp, assert_is_redirect_to, content, fake_post_body, subject, when_sending_an_email, }; use sqlx::PgPool; use uuid::Uuid; use wiremock::ResponseTemplate; #[sqlx::test] async fn you_must_be_logged_in_to_create_a_new_post(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; let title = subject(); let content = content(); let body = serde_json::json!({ "title": title, "content": content, }); let response = app.post_create_post(&body).await; assert_is_redirect_to(&response, "/login"); } #[sqlx::test] async fn new_posts_are_stored_in_the_database(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; app.admin_login().await; let title = subject(); let content = content(); let body = serde_json::json!({ "title": title, "content": content, "idempotency_key": Uuid::new_v4(), }); let response = app.post_create_post(&body).await; assert!(response.status().is_success()); let html_fragment = response.text().await.unwrap(); assert!(html_fragment.contains("Your new post has been published")); let saved = sqlx::query!("SELECT title, content FROM posts") .fetch_one(&app.connection_pool) .await .expect("Failed to fetch saved post"); assert_eq!(saved.title, title); assert_eq!(saved.content, content); } #[sqlx::test] async fn confirmed_subscribers_are_notified_when_a_new_post_is_published(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; app.create_unconfirmed_subscriber().await; app.create_confirmed_subscriber().await; app.admin_login().await; when_sending_an_email() .respond_with(ResponseTemplate::new(200)) .expect(1) .mount(&app.email_server) .await; let title = subject(); let content = content(); let body = serde_json::json!({ "title": title, "content": content, "idempotency_key": Uuid::new_v4(), }); app.post_create_post(&body).await; app.dispatch_all_pending_emails().await; } #[sqlx::test] async fn notification_contains_the_blog_post_url(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; app.create_confirmed_subscriber().await; app.admin_login().await; let title = subject(); let content = content(); let body = serde_json::json!({ "title": title, "content": content, "idempotency_key": Uuid::new_v4(), }); app.post_create_post(&body).await; when_sending_an_email() .respond_with(ResponseTemplate::new(200)) .expect(1) .mount(&app.email_server) .await; app.dispatch_all_pending_emails().await; let email_request = app .email_server .received_requests() .await .unwrap() .pop() .unwrap(); let post_id = sqlx::query!("SELECT post_id FROM posts") .fetch_one(&app.connection_pool) .await .unwrap() .post_id; let links = app.get_post_urls(&email_request); let text = String::from_utf8(email_request.body).unwrap(); assert!(text.contains(&title)); assert!(links.html.as_str().contains(&post_id.to_string())); } #[sqlx::test] async fn new_posts_are_visible_on_the_website(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; let html = app.get_posts_html().await; assert!(html.contains("No posts yet")); let title = subject(); let content = content(); let body = serde_json::json!({ "title": title, "content": content, "idempotency_key": Uuid::new_v4(), }); app.admin_login().await; app.post_create_post(&body).await; app.logout().await; let html = app.get_posts_html().await; assert!(html.contains(&title)); let post = sqlx::query!("SELECT post_id FROM posts") .fetch_one(&app.connection_pool) .await .unwrap(); let html = app.get_post_html(post.post_id).await; assert!(html.contains(&title)); } #[sqlx::test] async fn visitor_can_read_a_blog_post(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; let title = subject(); let content = content(); let body = serde_json::json!({ "title": title, "content": content, "idempotency_key": Uuid::new_v4(), }); app.admin_login().await; app.post_create_post(&body).await; app.logout().await; let html = app.get_posts_html().await; assert!(html.contains(&title)); let post = sqlx::query!("SELECT post_id FROM posts") .fetch_one(&app.connection_pool) .await .unwrap(); let html = app.get_post_html(post.post_id).await; assert!(html.contains(&title)); } #[sqlx::test] async fn a_deleted_blog_post_returns_404(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; app.admin_login().await; let title = subject(); let content = content(); let body = serde_json::json!({ "title": title, "content": content, "idempotency_key": Uuid::new_v4(), }); app.post_create_post(&body).await; let post = sqlx::query!("SELECT post_id FROM posts") .fetch_one(&app.connection_pool) .await .unwrap(); app.delete_post(post.post_id).await; let html = app.get_post_html(post.post_id).await; assert!(html.contains("Not Found")); } #[sqlx::test] async fn clicking_the_notification_link_marks_the_email_as_opened(connection_pool: PgPool) { let app = TestApp::spawn(connection_pool).await; app.admin_login().await; app.create_confirmed_subscriber().await; app.post_create_post(&fake_post_body()).await; when_sending_an_email() .respond_with(ResponseTemplate::new(200)) .expect(1) .mount(&app.email_server) .await; app.dispatch_all_pending_emails().await; let email_request = app .email_server .received_requests() .await .unwrap() .pop() .unwrap(); let links = app.get_post_urls(&email_request); reqwest::get(links.html.as_str()).await.unwrap(); assert!( sqlx::query!("SELECT opened FROM notifications_delivered") .fetch_one(&app.connection_pool) .await .unwrap() .opened ); }