| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| use argon2::{ | ||
| password_hash::{rand_core::OsRng, PasswordHasher, SaltString}, | ||
| Argon2, | ||
| }; | ||
| use once_cell::sync::Lazy; | ||
| use sqlx::Row; | ||
|
|
||
| static TRACING: Lazy<()> = Lazy::new(|| { | ||
| let subscriber = backend::telemetry::get_subscriber(false); | ||
| backend::telemetry::init_subscriber(subscriber); | ||
| }); | ||
|
|
||
| pub struct TestApp { | ||
| pub address: String, | ||
| pub test_user: TestUser, | ||
| pub api_client: reqwest::Client, | ||
| } | ||
|
|
||
| impl TestApp { | ||
| pub async fn post_login<Body>(&self, body: &Body) -> reqwest::Response | ||
| where | ||
| Body: serde::Serialize, | ||
| { | ||
| self.api_client | ||
| .post(&format!("{}/users/login/", &self.address)) | ||
| .json(body) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request.") | ||
| } | ||
| } | ||
|
|
||
| pub async fn spawn_app(pool: sqlx::postgres::PgPool) -> TestApp { | ||
| dotenv::from_filename(".env.test").ok(); | ||
| Lazy::force(&TRACING); | ||
|
|
||
| let settings = { | ||
| let mut s = backend::settings::get_settings().expect("Failed to read settings."); | ||
| // Use a random OS port | ||
| s.application.port = 0; | ||
| s | ||
| }; | ||
|
|
||
| let application = backend::startup::Application::build(settings.clone(), Some(pool.clone())) | ||
| .await | ||
| .expect("Failed to build application."); | ||
| let address = format!("http://127.0.0.1:{}", application.port()); | ||
|
|
||
| let _ = tokio::spawn(application.run_until_stopped()); | ||
|
|
||
| let client = reqwest::Client::builder() | ||
| .redirect(reqwest::redirect::Policy::none()) | ||
| .cookie_store(true) | ||
| .build() | ||
| .unwrap(); | ||
|
|
||
| let test_app = TestApp { | ||
| address, | ||
| test_user: TestUser::generate().await, | ||
| api_client: client, | ||
| }; | ||
|
|
||
| test_app.test_user.store(&pool).await; | ||
|
|
||
| test_app | ||
| } | ||
|
|
||
| pub struct TestUser { | ||
| pub email: String, | ||
| pub password: String, | ||
| first_name: String, | ||
| last_name: String, | ||
| } | ||
|
|
||
| impl TestUser { | ||
| pub async fn generate() -> Self { | ||
| Self { | ||
| email: uuid::Uuid::new_v4().to_string(), | ||
| password: uuid::Uuid::new_v4().to_string(), | ||
| first_name: uuid::Uuid::new_v4().to_string(), | ||
| last_name: uuid::Uuid::new_v4().to_string(), | ||
| } | ||
| } | ||
|
|
||
| async fn store(&self, pool: &sqlx::postgres::PgPool) { | ||
| let salt = SaltString::generate(&mut OsRng); | ||
|
|
||
| let password_hash = Argon2::default() | ||
| .hash_password(self.password.as_bytes(), &salt) | ||
| .expect("Unable to hash password.") | ||
| .to_string(); | ||
|
|
||
| let user_id = sqlx::query( | ||
| "INSERT INTO users (email, password, first_name, last_name, is_active, is_staff, is_superuser) | ||
| VALUES ($1, $2, $3, $4, true, true, true) RETURNING id" | ||
| ) | ||
| .bind(&self.email) | ||
| .bind(password_hash) | ||
| .bind(&self.first_name) | ||
| .bind(&self.last_name) | ||
| .map(|row: sqlx::postgres::PgRow| -> uuid::Uuid{ | ||
| row.get("id") | ||
| }) | ||
| .fetch_one(pool) | ||
| .await | ||
| .expect("Failed to store test user."); | ||
|
|
||
| sqlx::query( | ||
| "INSERT INTO user_profile (user_id) | ||
| VALUES ($1) | ||
| ON CONFLICT (user_id) | ||
| DO NOTHING", | ||
| ) | ||
| .bind(user_id) | ||
| .execute(pool) | ||
| .await | ||
| .expect("Cannot store user_profile to the DB"); | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| mod helpers; | ||
| mod users; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| use crate::helpers::spawn_app; | ||
|
|
||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct LoginUser { | ||
| email: String, | ||
| password: String, | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_get_current_user_failure(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // Then get current user | ||
| let get_user_response = app | ||
| .api_client | ||
| .get(&format!("{}/users/current-user/", &app.address)) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = get_user_response | ||
| .json::<backend::types::ErrorResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!( | ||
| response.error, | ||
| "You are not logged in. Kindly ensure you are logged in and try again" | ||
| ); | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_get_current_user_success(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // First login | ||
| let login_body = LoginUser { | ||
| email: app.test_user.email.clone(), | ||
| password: app.test_user.password.clone(), | ||
| }; | ||
| let login_response = app.post_login(&login_body).await; | ||
| assert!(login_response.status().is_success()); | ||
|
|
||
| // Then get current user | ||
| let get_user_response = app | ||
| .api_client | ||
| .get(&format!("{}/users/current-user/", &app.address)) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = get_user_response | ||
| .json::<backend::types::UserVisible>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!(response.email, app.test_user.email); | ||
| assert!(response.is_active); | ||
| assert_eq!(response.id, response.profile.user_id); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| use crate::helpers::spawn_app; | ||
| use fake::Fake; | ||
|
|
||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct LoginUser { | ||
| email: String, | ||
| password: String, | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_login_user_failure_bad_request(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // Act - Part 1 - Login | ||
| let login_body = LoginUser { | ||
| email: app.test_user.email.clone(), | ||
| password: fake::faker::name::en::NameWithTitle().fake(), | ||
| }; | ||
| let login_response = app.post_login(&login_body).await; | ||
| assert!(login_response.status().is_client_error()); | ||
|
|
||
| let error_response = login_response | ||
| .json::<backend::types::ErrorResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!(error_response.error, "Email and password do not match"); | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_login_user_failure_notfound(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // Act - Part 1 - Login | ||
| let login_body = LoginUser { | ||
| email: fake::faker::internet::en::SafeEmail().fake(), | ||
| password: app.test_user.password.clone(), | ||
| }; | ||
| let login_response = app.post_login(&login_body).await; | ||
| assert!(login_response.status().is_client_error()); | ||
|
|
||
| let error_response = login_response | ||
| .json::<backend::types::ErrorResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!(error_response.error, "A user with these details does not exist. If you registered with these details, ensure you activate your account by clicking on the link sent to your e-mail address"); | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_login_user_success(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| let login_body = LoginUser { | ||
| email: app.test_user.email.clone(), | ||
| password: app.test_user.password.clone(), | ||
| }; | ||
| let login_response = app.post_login(&login_body).await; | ||
| assert!(login_response.status().is_success()); | ||
|
|
||
| // Check that there is cookie present | ||
| let headers = login_response.headers(); | ||
| assert!(headers.get("set-cookie").is_some()); | ||
| let cookie_str = headers.get("set-cookie").unwrap().to_str().unwrap(); | ||
| assert!(cookie_str.contains("sessionid=")); | ||
|
|
||
| // Check response | ||
| let response = login_response | ||
| .json::<backend::types::UserVisible>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!(response.email, app.test_user.email); | ||
| assert!(response.is_active); | ||
| assert_eq!(response.id, response.profile.user_id); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| use crate::helpers::spawn_app; | ||
|
|
||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct LoginUser { | ||
| email: String, | ||
| password: String, | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_logout_failure(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // Test logout user | ||
| let logout_response = app | ||
| .api_client | ||
| .post(&format!("{}/users/logout/", &app.address)) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = logout_response | ||
| .json::<backend::types::ErrorResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!( | ||
| response.error, | ||
| "We currently have some issues. Kindly try again and ensure you are logged in" | ||
| ); | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_logout_success(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // First login | ||
| let login_body = LoginUser { | ||
| email: app.test_user.email.clone(), | ||
| password: app.test_user.password.clone(), | ||
| }; | ||
| let login_response = app.post_login(&login_body).await; | ||
| assert!(login_response.status().is_success()); | ||
|
|
||
| // Check that there is cookie present | ||
| let headers = login_response.headers(); | ||
| assert!(headers.get("set-cookie").is_some()); | ||
| let cookie_str = headers.get("set-cookie").unwrap().to_str().unwrap(); | ||
| assert!(cookie_str.contains("sessionid=")); | ||
|
|
||
| // Then logout user | ||
| let logout_response = app | ||
| .api_client | ||
| .post(&format!("{}/users/logout/", &app.address)) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = logout_response | ||
| .json::<backend::types::SuccessResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!(response.message, "You have successfully logged out"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| mod current_user; | ||
| mod login; | ||
| mod logout; | ||
| mod regenerate_token; | ||
| mod register; | ||
| mod update_users; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,95 @@ | ||
| use crate::helpers::spawn_app; | ||
|
|
||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct LoginUser { | ||
| email: String, | ||
| password: String, | ||
| } | ||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct UserEmail { | ||
| email: String, | ||
| } | ||
|
|
||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct NewUser<'a> { | ||
| email: &'a str, | ||
| password: String, | ||
| first_name: String, | ||
| last_name: String, | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_regenerate_token_failure(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // First login | ||
| let login_body = LoginUser { | ||
| email: app.test_user.email.clone(), | ||
| password: app.test_user.password.clone(), | ||
| }; | ||
| let login_response = app.post_login(&login_body).await; | ||
| assert!(login_response.status().is_success()); | ||
|
|
||
| let user_email = UserEmail { | ||
| email: app.test_user.email.clone(), | ||
| }; | ||
|
|
||
| // Then get current user | ||
| let res = app | ||
| .api_client | ||
| .post(&format!("{}/users/regenerate-token/", &app.address)) | ||
| .json(&user_email) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = res | ||
| .json::<backend::types::ErrorResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!( | ||
| response.error, | ||
| "A user with this e-mail address does not exist. If you registered with this email, ensure you haven't activated it yet. You can check by logging in" | ||
| ); | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_regenerate_token_success(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // Request data | ||
| sqlx::query( | ||
| "INSERT INTO users (email, password, first_name, last_name, is_active, is_staff, is_superuser) | ||
| VALUES ($1, $2, $3, $4, false, true, true)" | ||
| ) | ||
| .bind("email@example.com") | ||
| .bind("password_hash") | ||
| .bind("first_name") | ||
| .bind("last_name") | ||
| .execute(&pool) | ||
| .await | ||
| .expect("Failed to store test user."); | ||
|
|
||
| let user_email = UserEmail { | ||
| email: "email@example.com".to_string(), | ||
| }; | ||
|
|
||
| // Then get current user | ||
| let get_user_response = app | ||
| .api_client | ||
| .post(&format!("{}/users/regenerate-token/", &app.address)) | ||
| .json(&user_email) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = get_user_response | ||
| .json::<backend::types::SuccessResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!(response.message, "Account activation link has been sent to your email address. Kindly take action before its expiration"); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| use crate::helpers::spawn_app; | ||
| use fake::faker::{ | ||
| internet::en::SafeEmail, | ||
| name::en::{FirstName, LastName, NameWithTitle}, | ||
| }; | ||
| use fake::Fake; | ||
| use sqlx::Row; | ||
|
|
||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct NewUser<'a> { | ||
| email: &'a str, | ||
| password: String, | ||
| first_name: String, | ||
| last_name: String, | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_register_user_success(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // Request data | ||
| let email: String = SafeEmail().fake(); | ||
| let first_name: String = FirstName().fake(); | ||
| let last_name: String = LastName().fake(); | ||
| let password = NameWithTitle().fake(); | ||
| let new_user = NewUser { | ||
| email: &email, | ||
| password, | ||
| first_name, | ||
| last_name, | ||
| }; | ||
|
|
||
| let response = app | ||
| .api_client | ||
| .post(&format!("{}/users/register/", &app.address)) | ||
| .json(&new_user) | ||
| .header("Content-Type", "application/json") | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| assert!(response.status().is_success()); | ||
|
|
||
| let saved_user = sqlx::query( | ||
| "SELECT | ||
| u.id AS u_id, | ||
| u.email AS u_email, | ||
| u.password AS u_password, | ||
| u.first_name AS u_first_name, | ||
| u.last_name AS u_last_name, | ||
| u.is_active AS u_is_active, | ||
| u.is_staff AS u_is_staff, | ||
| u.is_superuser AS u_is_superuser, | ||
| u.thumbnail AS u_thumbnail, | ||
| u.date_joined AS u_date_joined, | ||
| p.id AS p_id, | ||
| p.user_id AS p_user_id, | ||
| p.phone_number AS p_phone_number, | ||
| p.birth_date AS p_birth_date, | ||
| p.github_link AS p_github_link | ||
| FROM | ||
| users u | ||
| LEFT JOIN user_profile p ON p.user_id = u.id | ||
| WHERE | ||
| u.is_active=false AND u.email=$1 | ||
| ", | ||
| ) | ||
| .bind(&email) | ||
| .map(|row: sqlx::postgres::PgRow| backend::types::User { | ||
| id: row.get("u_id"), | ||
| email: row.get("u_email"), | ||
| first_name: row.get("u_first_name"), | ||
| password: row.get("u_password"), | ||
| last_name: row.get("u_last_name"), | ||
| is_active: row.get("u_is_active"), | ||
| is_staff: row.get("u_is_staff"), | ||
| is_superuser: row.get("u_is_superuser"), | ||
| thumbnail: row.get("u_thumbnail"), | ||
| date_joined: row.get("u_date_joined"), | ||
| profile: backend::types::UserProfile { | ||
| id: row.get("p_id"), | ||
| user_id: row.get("p_user_id"), | ||
| phone_number: row.get("p_phone_number"), | ||
| birth_date: row.get("p_birth_date"), | ||
| github_link: row.get("p_github_link"), | ||
| }, | ||
| }) | ||
| .fetch_one(&pool) | ||
| .await | ||
| .expect("msg"); | ||
|
|
||
| assert_eq!(saved_user.is_active, false); | ||
| assert_eq!(saved_user.email, email); | ||
| assert_eq!(saved_user.thumbnail, None); | ||
| assert_eq!(saved_user.profile.user_id, saved_user.id); | ||
| assert_eq!(saved_user.profile.phone_number, None) | ||
| } | ||
| #[sqlx::test] | ||
| async fn test_register_user_failure_email(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // First request data | ||
| let email = "backend@api.com".to_string(); | ||
| let first_name: String = FirstName().fake(); | ||
| let last_name: String = LastName().fake(); | ||
| let password = NameWithTitle().fake(); | ||
| let new_user_one = NewUser { | ||
| email: &email, | ||
| password, | ||
| first_name, | ||
| last_name, | ||
| }; | ||
|
|
||
| let response_one = app | ||
| .api_client | ||
| .post(&format!("{}/users/register/", &app.address)) | ||
| .json(&new_user_one) | ||
| .header("Content-Type", "application/json") | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| assert!(response_one.status().is_success()); | ||
|
|
||
| // First request data | ||
| let email = "backend@api.com".to_string(); | ||
| let first_name: String = FirstName().fake(); | ||
| let last_name: String = LastName().fake(); | ||
| let password = NameWithTitle().fake(); | ||
| let new_user_two = NewUser { | ||
| email: &email, | ||
| password, | ||
| first_name, | ||
| last_name, | ||
| }; | ||
|
|
||
| let response_two = app | ||
| .api_client | ||
| .post(&format!("{}/users/register/", &app.address)) | ||
| .json(&new_user_two) | ||
| .header("Content-Type", "application/json") | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| assert!(response_two.status().is_client_error()); | ||
|
|
||
| let error_response = response_two | ||
| .json::<backend::types::ErrorResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!( | ||
| error_response.error, | ||
| "A user with that email address already exists" | ||
| ); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,86 @@ | ||
| use crate::helpers::spawn_app; | ||
|
|
||
| #[derive(serde::Deserialize, Debug, serde::Serialize)] | ||
| pub struct LoginUser { | ||
| email: String, | ||
| password: String, | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_update_user_failure_not_logged_in(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // multipart form | ||
| let form = reqwest::multipart::Form::new() | ||
| .text("github_link", "https://github.com/Sirneij") | ||
| .text("phone_number", "+2348135459073"); | ||
|
|
||
| let update_user_response = app | ||
| .api_client | ||
| .patch(&format!("{}/users/update-user/", &app.address)) | ||
| .multipart(form) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = update_user_response | ||
| .json::<backend::types::ErrorResponse>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!( | ||
| response.error, | ||
| "You are not logged in. Kindly ensure you are logged in and try again" | ||
| ); | ||
| } | ||
|
|
||
| #[sqlx::test] | ||
| async fn test_update_user_success(pool: sqlx::postgres::PgPool) { | ||
| let app = spawn_app(pool.clone()).await; | ||
|
|
||
| // First login | ||
| let login_body = LoginUser { | ||
| email: app.test_user.email.clone(), | ||
| password: app.test_user.password.clone(), | ||
| }; | ||
| let login_response = app.post_login(&login_body).await; | ||
| assert!(login_response.status().is_success()); | ||
|
|
||
| // Check that there is cookie present | ||
| let headers = login_response.headers(); | ||
| assert!(headers.get("set-cookie").is_some()); | ||
| let cookie_str = headers.get("set-cookie").unwrap().to_str().unwrap(); | ||
| assert!(cookie_str.contains("sessionid=")); | ||
|
|
||
| // multipart form | ||
| let form = reqwest::multipart::Form::new() | ||
| .text("github_link", "https://github.com/Sirneij") | ||
| .text("phone_number", "+2348135459073"); | ||
|
|
||
| let update_user_response = app | ||
| .api_client | ||
| .patch(&format!("{}/users/update-user/", &app.address)) | ||
| .multipart(form) | ||
| .send() | ||
| .await | ||
| .expect("Failed to execute request."); | ||
|
|
||
| // Check response | ||
| let response = update_user_response | ||
| .json::<backend::types::UserVisible>() | ||
| .await | ||
| .expect("Cannot get user response"); | ||
|
|
||
| assert_eq!(response.email, app.test_user.email); | ||
| assert!(response.is_active); | ||
| assert_eq!(response.id, response.profile.user_id); | ||
| assert_eq!( | ||
| response.profile.github_link, | ||
| Some("https://github.com/Sirneij".to_string()) | ||
| ); | ||
| assert_eq!( | ||
| response.profile.phone_number, | ||
| Some("+2348135459073".to_string()) | ||
| ); | ||
| } |