From 20902b3feb752aa199e21694ef4c3228f2f266d6 Mon Sep 17 00:00:00 2001 From: Miroito Date: Fri, 10 Feb 2023 11:13:23 +0100 Subject: [PATCH] feat/client E2E testing --- Cargo.lock | 43 ++++++++++++ client/Cargo.toml | 4 ++ client/src/components/base_async_select.rs | 2 + client/src/templates/index.rs | 4 +- client/tests/index.rs | 79 ++++++++++++++++++++++ makefile | 12 ++++ server/src/amf/service/test/pdf.rs | 12 +--- 7 files changed, 145 insertions(+), 11 deletions(-) create mode 100644 client/tests/index.rs diff --git a/Cargo.lock b/Cargo.lock index 8db452f..b3414db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -542,11 +542,13 @@ dependencies = [ "chrono", "dotenvy", "envy", + "fantoccini", "perseus", "reqwasm", "serde", "serde_json", "sycamore", + "tokio", ] [[package]] @@ -1017,6 +1019,28 @@ version = "2.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" +[[package]] +name = "fantoccini" +version = "0.19.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65f0fbe245d714b596ba5802b46f937f5ce68dcae0f32f9a70b5c3b04d3c6f64" +dependencies = [ + "base64 0.13.1", + "cookie 0.16.2", + "futures-core", + "futures-util", + "http", + "hyper 0.14.24", + "hyper-tls", + "mime 0.3.16", + "serde", + "serde_json", + "time 0.3.17", + "tokio", + "url 2.3.1", + "webdriver", +] + [[package]] name = "fast-insiders" version = "0.1.0" @@ -4510,6 +4534,25 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webdriver" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9973cb72c8587d5ad5efdb91e663d36177dc37725e6c90ca86c626b0cc45c93f" +dependencies = [ + "base64 0.13.1", + "bytes", + "cookie 0.16.2", + "http", + "log 0.4.17", + "serde", + "serde_derive", + "serde_json", + "time 0.3.17", + "unicode-segmentation", + "url 2.3.1", +] + [[package]] name = "webpki" version = "0.22.0" diff --git a/client/Cargo.toml b/client/Cargo.toml index 0cd480e..cd7a6f9 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -14,3 +14,7 @@ envy = { workspace = true } perseus = { version = "0.3.6", features = ["hydrate"] } sycamore = { version = "0.7.1", features = ["ssr", "serde", "futures"] } reqwasm = "0.5.0" + +[dev-dependencies] +fantoccini = "0.19.3" +tokio = { version = "=1.20.1", features = ["macros", "rt", "rt-multi-thread"] } diff --git a/client/src/components/base_async_select.rs b/client/src/components/base_async_select.rs index 73ca286..24a1d8d 100644 --- a/client/src/components/base_async_select.rs +++ b/client/src/components/base_async_select.rs @@ -1,3 +1,4 @@ +use perseus::checkpoint; use serde::Deserialize; use sycamore::prelude::*; @@ -62,6 +63,7 @@ where .unwrap(); visible.set(!res.is_empty()); item_list.set(res); + checkpoint("async_select_item_change"); }), ); } diff --git a/client/src/templates/index.rs b/client/src/templates/index.rs index 726ac53..7ab7988 100644 --- a/client/src/templates/index.rs +++ b/client/src/templates/index.rs @@ -91,7 +91,7 @@ pub fn index_page( } } } - div (class="flex flex-col items-center justify-center ") { + div (id="main", class="flex flex-col items-center justify-center ") { div (class="w-4/5 m-10 p-3 bg-slate-100 dark:bg-slate-600 rounded-lg items-center justify-center") { a (class="hover:underline", href="/") { h1 ( @@ -102,7 +102,7 @@ pub fn index_page( } BaseButton(filter_expand) div () {} // Without this useless div, the code doesn't run in the browser - div (class=format!("p-2 border rounded-lg border-slate-200 dark:border-slate-800 bg-slate-200 dark:bg-slate-700 transition-all ease-in {}", + div (id="filters", class=format!("p-2 border rounded-lg border-slate-200 dark:border-slate-800 bg-slate-200 dark:bg-slate-700 transition-all ease-in {}", if *expand.get() { "h-40 visible" } else { "h-0 collapse" }, ) ) diff --git a/client/tests/index.rs b/client/tests/index.rs new file mode 100644 index 0000000..4157e9d --- /dev/null +++ b/client/tests/index.rs @@ -0,0 +1,79 @@ +use fantoccini::{ + actions::{InputSource, KeyAction, KeyActions}, + error::CmdError, + Client, Locator, +}; +use perseus::wait_for_checkpoint; +use std::time::Duration; + +// This is is an E2E test with the following steps: +// - Go to the index page +// - Use the async select component to find any company +// - Click on this company and verify that we arrived +// - Come back to the root using the top left link +// - Find the first link in the table and click on it +// - Verify that all the company names in the table of the new page are the same as the link we +// clicked before +// Run like this: +// - Run any headless browser drive like geckodriver +// - Run perseus test +// - The backend should be available with some data +// - run PERSEUS_RUN_WASM_TESTS=true cargo test -- --test-threads 1 +// (or use make test-client-cargo) +#[perseus::test] +async fn index(c: &mut Client) -> Result<(), fantoccini::error::CmdError> { + c.goto("http://localhost:8080").await?; + wait_for_checkpoint!("begin", 0, c); + let url = c.current_url().await?; + assert!(url.as_ref().starts_with("http://localhost:8080")); + + wait_for_checkpoint!("page_visible", 0, c); + // Verify the page title + let title = c.find(Locator::Css("title")).await?.html(false).await?; + assert!(title.contains("Fast Insiders")); + + wait_for_checkpoint!("page_interactive", 0, c); + // let table = c.find(Locator::Css("table")).await?.html(true).await?; + let filter_button = c.find(Locator::Css("#main button")).await?; + filter_button.click().await?; + + let company_select = c.find(Locator::Css("#filters input")).await?; + company_select.send_keys("E").await?; // E is one of the most used letter. + + wait_for_checkpoint!("async_select_item_change", 0, c); + + let first_company = c.find(Locator::Css("div.relative li")).await?; + let clicked_company = first_company.text().await?; + first_company.click().await?; + + let search_button = c.find(Locator::Css("#filters button")).await?; + search_button.click().await?; + let page = c.current_url().await?; + assert!( + page.as_ref().starts_with("http://localhost:8080/index/"), + "Unexpected target url reached: {}", + page + ); + for a in c.find_all(Locator::Css("table a")).await? { + let a_text = a.text().await?; + assert_eq!(clicked_company, a_text, "The clicked company is different from the target page list of companies, respectively {} and {}", clicked_company, a_text); + } + + let root_link = c.find(Locator::Css("a")).await?; + root_link.click().await?; + + let first_company_in_table = c.find(Locator::Css("table a")).await?; + let company_name = first_company_in_table.text().await?; + first_company_in_table.click().await?; + for a in c.find_all(Locator::Css("table a")).await? { + let a_text = a.text().await?; + assert_eq!(company_name, a_text, "The clicked company is different from the target page list of companies, respectively {} and {}", company_name, a_text); + } + assert!( + page.as_ref().starts_with("http://localhost:8080/index/"), + "Unexpected target url reached: {}", + page + ); + + Ok(()) +} diff --git a/makefile b/makefile index aa1659f..488c926 100644 --- a/makefile +++ b/makefile @@ -21,3 +21,15 @@ serve: client-deploy: cd client && \ perseus deploy + +test-client: + cd client && \ + perseus test -w + +test-server: + cd server && \ + cargo test + +test-client-cargo: + cd client && \ + PERSEUS_RUN_WASM_TESTS=true cargo test -- --test-threads 1 diff --git a/server/src/amf/service/test/pdf.rs b/server/src/amf/service/test/pdf.rs index 0a5fb10..883ae68 100644 --- a/server/src/amf/service/test/pdf.rs +++ b/server/src/amf/service/test/pdf.rs @@ -1,18 +1,12 @@ use futures::StreamExt; -use crate::{ - amf::service::{ - information_req::{AMFRequest, AMFRequestType}, - pdf::AMFPdf, - }, - env, logger, +use crate::amf::service::{ + information_req::{AMFRequest, AMFRequestType}, + pdf::AMFPdf, }; #[tokio::test] async fn read_data_from_last_100_amf_pdf() { - env::load_env().expect("Failed to load .env"); - logger::init_log().expect("Failed to init log"); - let size = 100; let req = AMFRequest::new(AMFRequestType::DD, 1, size) .get_list() -- 2.36.3