diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index f1f313125..43612bb12 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -136,6 +136,10 @@ jobs: image: kennethreitz/httpbin@sha256:599fe5e5073102dbb0ee3dbb65f049dab44fa9fc251f6835c9990f8fb196a72b ports: - 8080:80 + echo_server: + image: jmalloc/echo-server@sha256:c461e7e54d947a8777413aaf9c624b4ad1f1bac5d8272475da859ae82c1abd7d + ports: + - 8081:8080 strategy: matrix: @@ -169,19 +173,19 @@ jobs: - name: Run tests - yew env: HTTPBIN_URL: "http://localhost:8080" + ECHO_SERVER_URL: "ws://localhost:8081" run: | cd packages/yew - # FIXME: Chrome appears to be timing out occasionally - wasm-pack test --firefox --headless -- --features "wasm_test httpbin_test" + wasm-pack test --chrome --firefox --headless -- --features "wasm_test httpbin_test echo_server_test" - name: Run tests - yew-stdweb if: matrix.toolchain != 'stable' env: HTTPBIN_URL: "http://localhost:8080" + ECHO_SERVER_URL: "ws://localhost:8081" run: | cd packages/yew-stdweb - # FIXME: Chrome really doesn't seem to like yew-stdweb - wasm-pack test --firefox --headless -- --features "wasm_test httpbin_test" + wasm-pack test --chrome --firefox --headless -- --features "wasm_test httpbin_test echo_server_test" - name: Run tests - yew-functional run: | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 72809627f..c568dce42 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -54,9 +54,15 @@ The tests for the fetch service require a local [httpbin](https://httpbin.org/) If you have [Docker](https://www.docker.com/) installed, `cargo make tests` will automatically run httpbin in a container for you. -Alternatively, you can manually run an httpbin instance however you want and set the `HTTPBIN_URL` environment variable to the URL. +Alternatively, you can set the `HTTPBIN_URL` environment variable to the URL you wish to run tests against. -Please note that the public httpbin instance can't be used for these tests. +### WebSocket service tests + +The tests for the web-socket service require an echo server. +If you have [Docker](https://www.docker.com/) installed, +`cargo make tests` will automatically run an [echo server](https://hub.docker.com/r/jmalloc/echo-server) in a container for you. + +Alternatively, you can set the `ECHO_SERVER_URL` environment variable to the URL you wish to run tests against. ### Macro tests diff --git a/Makefile.toml b/Makefile.toml index 5bbf989f2..03fcddd2e 100644 --- a/Makefile.toml +++ b/Makefile.toml @@ -80,9 +80,27 @@ script = [ yew_test_features = set "${yew_test_features},httpbin_test" end + fn set_echo_server_test_features + ECHO_SERVER_URL = get_env ECHO_SERVER_URL + echo INFO: using ${ECHO_SERVER_URL} for web-socket service tests + yew_test_features = set "${yew_test_features},echo_server_test" + end + + run_httpbin_container = set false if is_defined HTTPBIN_URL set_httpbin_test_features else + run_httpbin_container = set true + end + + run_echo_server_container = set false + if is_defined ECHO_SERVER_URL + set_echo_server_test_features + else + run_echo_server_container = set true + end + + if ${run_httpbin_container} or ${run_echo_server_container} # only enable docker if docker executable is available # and --skip-httpbin cli argument not provided to cargo make docker_path = which docker @@ -99,41 +117,85 @@ script = [ end if ${start_docker} - echo Starting httpbin docker image... mkdir ./target - cidfile = set ./target/httpbin_container.cid - # if container already running, stop it - if is_file ${cidfile} + if ${run_httpbin_container} + echo Starting httpbin docker image... + cidfile = set ./target/httpbin_container.cid + + # if container already running, stop it + if is_file ${cidfile} + container_id = readfile ${cidfile} + rm ${cidfile} + set_env HTTPBIN_CONTAINER_ID ${container_id} + cm_run_task tests-cleanup-httpbin + end + + # get local port + docker_port = get_env YEW_HTTPBIN_PORT + if not is_defined docker_port + docker_port = set 7117 + end + + exec --fail-on-error docker run -d --cidfile ${cidfile} -p "${docker_port}:80" kennethreitz/httpbin container_id = readfile ${cidfile} - rm ${cidfile} + container_id = trim ${container_id} set_env HTTPBIN_CONTAINER_ID ${container_id} - cm_run_task tests-cleanup + + set_env HTTPBIN_URL http://localhost:${docker_port} + set_httpbin_test_features + + # wait for docker container to boot before running tests + if is_defined HTTPBIN_WAIT + sleep ${HTTPBIN_WAIT} + else + sleep 500 + end end - # get local port - docker_port = get_env YEW_HTTPBIN_PORT - if not is_defined docker_port - docker_port = set 7117 - end + if ${run_echo_server_container} + echo Starting echo-server docker image... + cidfile = set ./target/echo_server_container.cid - exec --fail-on-error docker run -d --cidfile ${cidfile} -p "${docker_port}:80" kennethreitz/httpbin - container_id = readfile ${cidfile} - container_id = trim ${container_id} - set_env HTTPBIN_CONTAINER_ID ${container_id} + # if container already running, stop it + if is_file ${cidfile} + container_id = readfile ${cidfile} + rm ${cidfile} + set_env ECHO_SERVER_CONTAINER_ID ${container_id} + cm_run_task tests-cleanup-echo-server + end - set_env HTTPBIN_URL http://localhost:${docker_port} - set_httpbin_test_features + # get local port + docker_port = get_env YEW_ECHO_SERVER_PORT + if not is_defined docker_port + docker_port = set 7118 + end - # wait for docker container to boot before running tests - if is_defined HTTPBIN_WAIT - sleep ${HTTPBIN_WAIT} - else - sleep 500 + exec --fail-on-error docker run -d --cidfile ${cidfile} -p "${docker_port}:8080" jmalloc/echo-server + container_id = readfile ${cidfile} + container_id = trim ${container_id} + set_env ECHO_SERVER_CONTAINER_ID ${container_id} + + set_env ECHO_SERVER_URL ws://localhost:${docker_port} + set_echo_server_test_features + + # wait for docker container to boot before running tests + if is_defined ECHO_SERVER_WAIT + sleep ${ECHO_SERVER_WAIT} + else + sleep 500 + end end else - echo "INFO: HTTPBIN_URL isn't set, won't run fetch service tests" - echo " please see the CONTRIBUTING.md file for instructions" + if ${run_httpbin_container} + echo "INFO: HTTPBIN_URL isn't set, won't run fetch service tests" + echo " please see the CONTRIBUTING.md file for instructions" + end + + if ${run_echo_server_container} + echo "INFO: ECHO_SERVER_URL isn't set, won't run web-socket service tests" + echo " please see the CONTRIBUTING.md file for instructions" + end end end @@ -147,11 +209,26 @@ script = [ [tasks.tests-cleanup] private = true +ignore_errors = true +run_task = { name = [ + "test-cleanup-httpbin", + "test-cleanup-echo-server", +] } + +[tasks.tests-cleanup-httpbin] +private = true condition = { env_set = ["HTTPBIN_CONTAINER_ID"] } ignore_errors = true command = "docker" args = ["rm", "--force", "${HTTPBIN_CONTAINER_ID}"] +[tasks.tests-cleanup-echo-server] +private = true +condition = { env_set = ["ECHO_SERVER_CONTAINER_ID"] } +ignore_errors = true +command = "docker" +args = ["rm", "--force", "${ECHO_SERVER_CONTAINER_ID}"] + [tasks.tests-stdweb] private = true extend = "core::wasm-pack-base" diff --git a/packages/yew-stdweb/Cargo.toml b/packages/yew-stdweb/Cargo.toml index 0125b1cfb..61c259b97 100644 --- a/packages/yew-stdweb/Cargo.toml +++ b/packages/yew-stdweb/Cargo.toml @@ -69,6 +69,7 @@ std_web = ["stdweb"] doc_test = [] wasm_test = [] httpbin_test = [] +echo_server_test = [] services = [] agent = ["bincode"] yaml = ["serde_yaml"] diff --git a/packages/yew/Cargo.toml b/packages/yew/Cargo.toml index 03f36cca5..1beadc545 100644 --- a/packages/yew/Cargo.toml +++ b/packages/yew/Cargo.toml @@ -135,6 +135,7 @@ web_sys = [ doc_test = [] wasm_test = [] httpbin_test = [] +echo_server_test = [] wasm_bench = [] services = [] agent = ["bincode"] diff --git a/packages/yew/src/callback.rs b/packages/yew/src/callback.rs index f532acb40..41f151710 100644 --- a/packages/yew/src/callback.rs +++ b/packages/yew/src/callback.rs @@ -172,7 +172,7 @@ pub(crate) mod test_util { } impl CallbackFuture { - fn ready(&self) -> Option { + pub fn ready(&self) -> Option { self.0.borrow_mut().output.take() } diff --git a/packages/yew/src/services/websocket.rs b/packages/yew/src/services/websocket.rs index 55a89b2fa..a5120121b 100644 --- a/packages/yew/src/services/websocket.rs +++ b/packages/yew/src/services/websocket.rs @@ -366,16 +366,32 @@ impl Drop for WebSocketTask { } #[cfg(test)] -#[cfg(feature = "wasm_test")] +#[cfg(all(feature = "wasm_test", feature = "echo_server_test"))] mod tests { use super::*; use crate::callback::{test_util::CallbackFuture, Callback}; use crate::format::{FormatError, Json}; + use crate::services::TimeoutService; use serde::{Deserialize, Serialize}; + use std::time::Duration; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; wasm_bindgen_test_configure!(run_in_browser); + const fn echo_server_url() -> &'static str { + // we can't do this at runtime because we're running in the browser. + env!("ECHO_SERVER_URL") + } + + // Ignore the first response from the echo server + async fn ignore_first_message(cb_future: &CallbackFuture) { + let sleep_future = CallbackFuture::<()>::default(); + let _sleep_task = + TimeoutService::spawn(Duration::from_millis(10), sleep_future.clone().into()); + sleep_future.await; + cb_future.ready(); + } + #[derive(Serialize, Deserialize, Debug, PartialEq)] struct Message { test: String, @@ -383,7 +399,7 @@ mod tests { #[test] async fn connect() { - let url = "wss://echo.websocket.org"; + let url = echo_server_url(); let cb_future = CallbackFuture::>>::default(); let callback: Callback<_> = cb_future.clone().into(); let status_future = CallbackFuture::::default(); @@ -391,6 +407,7 @@ mod tests { let mut task = WebSocketService::connect(url, callback, notification).unwrap(); assert_eq!(status_future.await, WebSocketStatus::Opened); + ignore_first_message(&cb_future).await; let msg = Message { test: String::from("hello"), @@ -431,7 +448,7 @@ mod tests { #[test] async fn connect_text() { - let url = "wss://echo.websocket.org"; + let url = echo_server_url(); let cb_future = CallbackFuture::>>::default(); let callback: Callback<_> = cb_future.clone().into(); let status_future = CallbackFuture::::default(); @@ -439,6 +456,7 @@ mod tests { let mut task = WebSocketService::connect_text(url, callback, notification).unwrap(); assert_eq!(status_future.await, WebSocketStatus::Opened); + ignore_first_message(&cb_future).await; let msg = Message { test: String::from("hello"), @@ -462,7 +480,7 @@ mod tests { #[test] async fn connect_binary() { - let url = "wss://echo.websocket.org"; + let url = echo_server_url(); let cb_future = CallbackFuture::>>::default(); let callback: Callback<_> = cb_future.clone().into(); let status_future = CallbackFuture::::default(); @@ -470,6 +488,7 @@ mod tests { let mut task = WebSocketService::connect_binary(url, callback, notification).unwrap(); assert_eq!(status_future.await, WebSocketStatus::Opened); + ignore_first_message(&cb_future).await; let msg = Message { test: String::from("hello"),