feat(core): add test::test::get_ipc_response, closes #8199 (#8228)

* feat(core): Add additional functions to the

* Add documentation and cleanup the code

* Improve and add tests to helper functions

* Clean unecessary code and correct tests

* Make `Ipc` and `IpcKey` public

* Open `Ipc` with public functions

* Update core/tauri/src/test/mod.rs

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>

* cleanup, change file

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
Co-authored-by: Lucas Nogueira <lucas@crabnebula.dev>
This commit is contained in:
Alexandre Dang 2023-12-14 15:52:45 +01:00 committed by GitHub
parent c1bc4d2948
commit 3c371aa8ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 84 additions and 34 deletions

View File

@ -0,0 +1,5 @@
---
"tauri": patch:enhance
---
Added `test::get_ipc_response`.

View File

@ -27,7 +27,9 @@
//! } //! }
//! //!
//! fn main() { //! fn main() {
//! let app = create_app(tauri::Builder::default()); //! // Use `tauri::Builder::default()` to use the default runtime rather than the `MockRuntime`;
//! // let app = create_app(tauri::Builder::default());
//! let app = create_app(tauri::test::mock_builder());
//! // app.run(|_handle, _event| {}); //! // app.run(|_handle, _event| {});
//! } //! }
//! //!
@ -59,6 +61,7 @@
mod mock_runtime; mod mock_runtime;
pub use mock_runtime::*; pub use mock_runtime::*;
use serde::de::DeserializeOwned;
use serde::Serialize; use serde::Serialize;
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
@ -82,9 +85,12 @@ use tauri_utils::{
config::{CliConfig, Config, PatternKind, TauriConfig}, config::{CliConfig, Config, PatternKind, TauriConfig},
}; };
/// A key for an [`Ipc`] call.
#[derive(Eq, PartialEq)] #[derive(Eq, PartialEq)]
struct IpcKey { struct IpcKey {
/// callback
callback: CallbackFn, callback: CallbackFn,
/// error callback
error: CallbackFn, error: CallbackFn,
} }
@ -95,6 +101,7 @@ impl Hash for IpcKey {
} }
} }
/// Structure to retrieve result of a Tauri command
struct Ipc(Mutex<HashMap<IpcKey, Sender<std::result::Result<JsonValue, JsonValue>>>>); struct Ipc(Mutex<HashMap<IpcKey, Sender<std::result::Result<JsonValue, JsonValue>>>>);
/// An empty [`Assets`] implementation. /// An empty [`Assets`] implementation.
@ -227,35 +234,27 @@ pub fn mock_app() -> App<MockRuntime> {
/// .expect("failed to build app") /// .expect("failed to build app")
/// } /// }
/// ///
/// use tauri::Manager;
/// use tauri::test::mock_builder;
/// fn main() { /// fn main() {
/// let app = create_app(tauri::Builder::default()); /// // app createion with a `MockRuntime`
/// // app.run(|_handle, _event| {});} /// let app = create_app(mock_builder());
/// } /// let window = app.get_window("main").unwrap();
/// ///
/// //#[cfg(test)] /// // run the `ping` command and assert it returns `pong`
/// mod tests { /// tauri::test::assert_ipc_response(
/// use tauri::Manager; /// &window,
/// /// tauri::InvokePayload {
/// //#[cfg(test)] /// cmd: "ping".into(),
/// fn something() { /// tauri_module: None,
/// let app = super::create_app(tauri::test::mock_builder()); /// callback: tauri::api::ipc::CallbackFn(0),
/// let window = app.get_window("main").unwrap(); /// error: tauri::api::ipc::CallbackFn(1),
/// /// inner: serde_json::Value::Null,
/// // run the `ping` command and assert it returns `pong` /// },
/// tauri::test::assert_ipc_response( /// // the expected response is a success with the "pong" payload
/// &window, /// // we could also use Err("error message") here to ensure the command failed
/// tauri::InvokePayload { /// Ok("pong")
/// cmd: "ping".into(), /// );
/// tauri_module: None,
/// callback: tauri::api::ipc::CallbackFn(0),
/// error: tauri::api::ipc::CallbackFn(1),
/// inner: serde_json::Value::Null,
/// },
/// // the expected response is a success with the "pong" payload
/// // we could also use Err("error message") here to ensure the command failed
/// Ok("pong")
/// );
/// }
/// } /// }
/// ``` /// ```
pub fn assert_ipc_response<T: Serialize + Debug>( pub fn assert_ipc_response<T: Serialize + Debug>(
@ -263,6 +262,54 @@ pub fn assert_ipc_response<T: Serialize + Debug>(
payload: InvokePayload, payload: InvokePayload,
expected: Result<T, T>, expected: Result<T, T>,
) { ) {
assert_eq!(
get_ipc_response(window, payload),
expected
.map(|e| serde_json::to_value(e).unwrap())
.map_err(|e| serde_json::to_value(e).unwrap())
);
}
/// The application processes the command and stops.
///
/// # Examples
///
/// ```rust
///
/// #[tauri::command]
/// fn ping() -> &'static str {
/// "pong"
/// }
///
/// fn create_app<R: tauri::Runtime>(mut builder: tauri::Builder<R>) -> tauri::App<R> {
/// builder
/// .invoke_handler(tauri::generate_handler![ping])
/// // remove the string argument on your app
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
/// .expect("failed to build app")
/// }
///
/// use tauri::test::*;
/// use tauri::Manager;
/// let app = create_app(mock_builder());
/// let window = app.get_window("main").unwrap();
///
/// // run the `ping` command and assert it returns `pong`
/// let res = tauri::test::get_ipc_response::<String>(
/// &window,
/// tauri::InvokePayload {
/// cmd: "ping".into(),
/// tauri_module: None,
/// callback: tauri::api::ipc::CallbackFn(0),
/// error: tauri::api::ipc::CallbackFn(1),
/// inner: serde_json::Value::Null,
/// });
/// assert_eq!(res, Ok("pong".into()))
/// ```
pub fn get_ipc_response<T: DeserializeOwned + Debug>(
window: &Window<MockRuntime>,
payload: InvokePayload,
) -> Result<T, T> {
let callback = payload.callback; let callback = payload.callback;
let error = payload.error; let error = payload.error;
let ipc = window.state::<Ipc>(); let ipc = window.state::<Ipc>();
@ -270,12 +317,10 @@ pub fn assert_ipc_response<T: Serialize + Debug>(
ipc.0.lock().unwrap().insert(IpcKey { callback, error }, tx); ipc.0.lock().unwrap().insert(IpcKey { callback, error }, tx);
window.clone().on_message(payload).unwrap(); window.clone().on_message(payload).unwrap();
assert_eq!( let res: Result<JsonValue, JsonValue> = rx.recv().expect("Failed to receive result from command");
rx.recv().unwrap(), res
expected .map(|v| serde_json::from_value(v).unwrap())
.map(|e| serde_json::to_value(e).unwrap()) .map_err(|e| serde_json::from_value(e).unwrap())
.map_err(|e| serde_json::to_value(e).unwrap())
);
} }
#[cfg(test)] #[cfg(test)]