From 5678e4d4342de83e8d2cc16eaa05784134bef056 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Fri, 21 Apr 2023 12:51:15 +0100 Subject: [PATCH] tests: [#107] E2E tests for API entrypoint and about routes --- docker/README.md | 4 ++-- tests/e2e/asserts.rs | 15 +++++++++++++++ tests/e2e/client.rs | 12 +++++------- tests/e2e/contexts/about.rs | 21 --------------------- tests/e2e/mod.rs | 19 +++++++++++++++++-- tests/e2e/response.rs | 17 +++++++++++++++++ tests/e2e/routes/about.rs | 26 ++++++++++++++++++++++++++ tests/e2e/{contexts => routes}/mod.rs | 1 + tests/e2e/routes/root.rs | 15 +++++++++++++++ 9 files changed, 98 insertions(+), 32 deletions(-) create mode 100644 tests/e2e/asserts.rs delete mode 100644 tests/e2e/contexts/about.rs create mode 100644 tests/e2e/response.rs create mode 100644 tests/e2e/routes/about.rs rename tests/e2e/{contexts => routes}/mod.rs (51%) create mode 100644 tests/e2e/routes/root.rs diff --git a/docker/README.md b/docker/README.md index 664e58b8..d38a8066 100644 --- a/docker/README.md +++ b/docker/README.md @@ -21,7 +21,7 @@ Build and run locally: ```s docker context use default -export TORRUST_IDX_BACK_USER_UID=1000 +export TORRUST_IDX_BACK_USER_UID=$(id -u) ./docker/bin/build.sh $TORRUST_IDX_BACK_USER_UID ./bin/install.sh ./docker/bin/run.sh $TORRUST_IDX_BACK_USER_UID @@ -30,7 +30,7 @@ export TORRUST_IDX_BACK_USER_UID=1000 Run using the pre-built public docker image: ```s -export TORRUST_IDX_BACK_USER_UID=1000 +export TORRUST_IDX_BACK_USER_UID=$(id -u) docker run -it \ --user="$TORRUST_IDX_BACK_USER_UID" \ --publish 3000:3000/tcp \ diff --git a/tests/e2e/asserts.rs b/tests/e2e/asserts.rs new file mode 100644 index 00000000..d57954ad --- /dev/null +++ b/tests/e2e/asserts.rs @@ -0,0 +1,15 @@ +use crate::e2e::response::Response; + +pub fn assert_response_title(response: &Response, title: &str) { + let title_element = format!("{title}"); + + assert!( + response.body.contains(&title), + ":\n response does not contain the title element: `\"{title_element}\"`." + ); +} + +pub fn assert_ok(response: &Response) { + assert_eq!(response.status, 200); + assert_eq!(response.content_type, "text/html; charset=utf-8"); +} diff --git a/tests/e2e/client.rs b/tests/e2e/client.rs index 3d249d66..927734e0 100644 --- a/tests/e2e/client.rs +++ b/tests/e2e/client.rs @@ -1,7 +1,8 @@ -use reqwest::Response; +use reqwest::Response as ReqwestResponse; use crate::e2e::connection_info::ConnectionInfo; use crate::e2e::http::{Query, ReqwestQuery}; +use crate::e2e::response::Response; /// API Client pub struct Client { @@ -17,10 +18,6 @@ impl Client { } } - pub async fn entrypoint(&self) -> Response { - self.get("", Query::default()).await - } - pub async fn get(&self, path: &str, params: Query) -> Response { self.get_request_with_query(path, params).await } @@ -53,7 +50,7 @@ impl Client { } async fn get(path: &str, query: Option) -> Response { - match query { + let response: ReqwestResponse = match query { Some(params) => reqwest::Client::builder() .build() .unwrap() @@ -63,5 +60,6 @@ async fn get(path: &str, query: Option) -> Response { .await .unwrap(), None => reqwest::Client::builder().build().unwrap().get(path).send().await.unwrap(), - } + }; + Response::from(response).await } diff --git a/tests/e2e/contexts/about.rs b/tests/e2e/contexts/about.rs deleted file mode 100644 index 99bcb276..00000000 --- a/tests/e2e/contexts/about.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::e2e::client::Client; -use crate::e2e::connection_info::connection_with_no_token; - -#[tokio::test] -#[cfg_attr(not(feature = "e2e-tests"), ignore)] -async fn it_should_load_the_about_page_at_the_api_entrypoint() { - let client = Client::new(connection_with_no_token("localhost:3000")); - - let response = client.entrypoint().await; - - assert_eq!(response.status(), 200); - assert_eq!(response.headers().get("content-type").unwrap(), "text/html; charset=utf-8"); - - let title = format!("About"); - let response_text = response.text().await.unwrap(); - - assert!( - response_text.contains(&title), - ":\n response: `\"{response_text}\"`\n does not contain: `\"{title}\"`." - ); -} diff --git a/tests/e2e/mod.rs b/tests/e2e/mod.rs index 35de4dcf..3d6415b6 100644 --- a/tests/e2e/mod.rs +++ b/tests/e2e/mod.rs @@ -1,9 +1,24 @@ //! End-to-end tests. //! +//! Execute E2E tests with: +//! +//! ``` +//! cargo test --features e2e-tests //! ``` -//! cargo test -- --ignored +//! +//! or the Cargo alias +//! //! ``` +//! cargo e2e +//! ``` +//! +//! > **NOTICE**: E2E tests are not executed by default, because they require +//! a running instance of the API. +//! +//! See the docker documentation for more information on how to run the API. +mod asserts; mod client; mod connection_info; -mod contexts; mod http; +mod response; +mod routes; diff --git a/tests/e2e/response.rs b/tests/e2e/response.rs new file mode 100644 index 00000000..6861953e --- /dev/null +++ b/tests/e2e/response.rs @@ -0,0 +1,17 @@ +use reqwest::Response as ReqwestResponse; + +pub struct Response { + pub status: u16, + pub content_type: String, + pub body: String, +} + +impl Response { + pub async fn from(response: ReqwestResponse) -> Self { + Self { + status: response.status().as_u16(), + content_type: response.headers().get("content-type").unwrap().to_str().unwrap().to_owned(), + body: response.text().await.unwrap(), + } + } +} diff --git a/tests/e2e/routes/about.rs b/tests/e2e/routes/about.rs new file mode 100644 index 00000000..51c1e050 --- /dev/null +++ b/tests/e2e/routes/about.rs @@ -0,0 +1,26 @@ +use crate::e2e::asserts::{assert_ok, assert_response_title}; +use crate::e2e::client::Client; +use crate::e2e::connection_info::connection_with_no_token; +use crate::e2e::http::Query; + +#[tokio::test] +#[cfg_attr(not(feature = "e2e-tests"), ignore)] +async fn it_should_load_the_about_page_with_information_about_the_api() { + let client = Client::new(connection_with_no_token("localhost:3000")); + + let response = client.get("about", Query::empty()).await; + + assert_ok(&response); + assert_response_title(&response, "About"); +} + +#[tokio::test] +#[cfg_attr(not(feature = "e2e-tests"), ignore)] +async fn it_should_load_the_license_page_at_the_api_entrypoint() { + let client = Client::new(connection_with_no_token("localhost:3000")); + + let response = client.get("about/license", Query::empty()).await; + + assert_ok(&response); + assert_response_title(&response, "Licensing"); +} diff --git a/tests/e2e/contexts/mod.rs b/tests/e2e/routes/mod.rs similarity index 51% rename from tests/e2e/contexts/mod.rs rename to tests/e2e/routes/mod.rs index ced75210..395f4d3c 100644 --- a/tests/e2e/contexts/mod.rs +++ b/tests/e2e/routes/mod.rs @@ -1 +1,2 @@ pub mod about; +pub mod root; diff --git a/tests/e2e/routes/root.rs b/tests/e2e/routes/root.rs new file mode 100644 index 00000000..0a236006 --- /dev/null +++ b/tests/e2e/routes/root.rs @@ -0,0 +1,15 @@ +use crate::e2e::asserts::{assert_ok, assert_response_title}; +use crate::e2e::client::Client; +use crate::e2e::connection_info::connection_with_no_token; +use crate::e2e::http::Query; + +#[tokio::test] +#[cfg_attr(not(feature = "e2e-tests"), ignore)] +async fn it_should_load_the_about_page_at_the_api_entrypoint() { + let client = Client::new(connection_with_no_token("localhost:3000")); + + let response = client.get("", Query::empty()).await; + + assert_ok(&response); + assert_response_title(&response, "About"); +}