test: improve email client unit test
This commit is contained in:
parent
c021b989c2
commit
e07e4dfe53
3 changed files with 34 additions and 6 deletions
|
|
@ -67,3 +67,4 @@ quickcheck = "1.0.3"
|
||||||
quickcheck_macros = "1.0.0"
|
quickcheck_macros = "1.0.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
wiremock = "0.6.0"
|
wiremock = "0.6.0"
|
||||||
|
serde_json = "1"
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ impl EmailClient {
|
||||||
html_body: html_content.to_owned(),
|
html_body: html_content.to_owned(),
|
||||||
text_body: text_content.to_owned(),
|
text_body: text_content.to_owned(),
|
||||||
};
|
};
|
||||||
let builder = self
|
let _builder = self
|
||||||
.http_client
|
.http_client
|
||||||
.post(&url)
|
.post(&url)
|
||||||
.header(
|
.header(
|
||||||
|
|
@ -54,6 +54,7 @@ impl EmailClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
|
#[serde(rename_all = "PascalCase")]
|
||||||
struct SendEmailRequest {
|
struct SendEmailRequest {
|
||||||
from: String,
|
from: String,
|
||||||
to: String,
|
to: String,
|
||||||
|
|
@ -71,17 +72,43 @@ mod tests {
|
||||||
use fake::faker::lorem::en::{Paragraph, Sentence};
|
use fake::faker::lorem::en::{Paragraph, Sentence};
|
||||||
use fake::{Fake, Faker};
|
use fake::{Fake, Faker};
|
||||||
use secrecy::Secret;
|
use secrecy::Secret;
|
||||||
use wiremock::matchers::any;
|
use wiremock::matchers::{header, header_exists, method, path};
|
||||||
use wiremock::{Mock, MockServer, ResponseTemplate};
|
use wiremock::{Mock, MockServer, Request, ResponseTemplate};
|
||||||
|
|
||||||
|
struct SendEmailBodyMatcher;
|
||||||
|
|
||||||
|
impl wiremock::Match for SendEmailBodyMatcher {
|
||||||
|
fn matches(&self, request: &Request) -> bool {
|
||||||
|
// Try to parse the body as a JSON value
|
||||||
|
let result: Result<serde_json::Value, _> = serde_json::from_slice(&request.body);
|
||||||
|
if let Ok(body) = result {
|
||||||
|
dbg!(&body);
|
||||||
|
// Check that all the mandatory fields are populated
|
||||||
|
// without inspecting the field values
|
||||||
|
body.get("From").is_some()
|
||||||
|
&& body.get("To").is_some()
|
||||||
|
&& body.get("Subject").is_some()
|
||||||
|
&& body.get("HtmlBody").is_some()
|
||||||
|
&& body.get("TextBody").is_some()
|
||||||
|
} else {
|
||||||
|
// If parsing failed, do not match the request
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn send_email_fires_a_request_to_base_url() {
|
async fn send_email_sends_the_expected_request() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let mock_server = MockServer::start().await;
|
let mock_server = MockServer::start().await;
|
||||||
let sender = SubscriberEmail::parse(SafeEmail().fake()).unwrap();
|
let sender = SubscriberEmail::parse(SafeEmail().fake()).unwrap();
|
||||||
let email_client = EmailClient::new(mock_server.uri(), sender, Secret::new(Faker.fake()));
|
let email_client = EmailClient::new(mock_server.uri(), sender, Secret::new(Faker.fake()));
|
||||||
|
|
||||||
Mock::given(any())
|
Mock::given(header_exists("X-Postmark-Server-Token"))
|
||||||
|
.and(header("Content-Type", "application/json"))
|
||||||
|
.and(path("/email"))
|
||||||
|
.and(method("POST"))
|
||||||
|
.and(SendEmailBodyMatcher)
|
||||||
.respond_with(ResponseTemplate::new(200))
|
.respond_with(ResponseTemplate::new(200))
|
||||||
.expect(1)
|
.expect(1)
|
||||||
.mount(&mock_server)
|
.mount(&mock_server)
|
||||||
|
|
@ -97,5 +124,6 @@ mod tests {
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
|
// Mock expectations are checked on drop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::domain::SubscriberEmail;
|
use crate::domain::SubscriberEmail;
|
||||||
use crate::domain::{NewSubscriber, SubscriberName};
|
use crate::domain::{NewSubscriber, SubscriberName};
|
||||||
use crate::email_client;
|
|
||||||
use crate::startup::AppState;
|
use crate::startup::AppState;
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use axum::routing::post;
|
use axum::routing::post;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue