Skip to content

Commit

Permalink
feat(core): add test::test::get_ipc_response, closes #8199 (#8228)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people committed Dec 14, 2023
1 parent c1bc4d2 commit 3c371aa
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 34 deletions.
5 changes: 5 additions & 0 deletions .changes/get-ipc-response-test.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"tauri": patch:enhance
---

Added `test::get_ipc_response`.
113 changes: 79 additions & 34 deletions core/tauri/src/test/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,9 @@
//! }
//!
//! 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| {});
//! }
//!
Expand Down Expand Up @@ -59,6 +61,7 @@

mod mock_runtime;
pub use mock_runtime::*;
use serde::de::DeserializeOwned;
use serde::Serialize;
use serde_json::Value as JsonValue;

Expand All @@ -82,9 +85,12 @@ use tauri_utils::{
config::{CliConfig, Config, PatternKind, TauriConfig},
};

/// A key for an [`Ipc`] call.
#[derive(Eq, PartialEq)]
struct IpcKey {
/// callback
callback: CallbackFn,
/// error callback
error: CallbackFn,
}

Expand All @@ -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>>>>);

/// An empty [`Assets`] implementation.
Expand Down Expand Up @@ -227,55 +234,93 @@ pub fn mock_app() -> App<MockRuntime> {
/// .expect("failed to build app")
/// }
///
/// use tauri::Manager;
/// use tauri::test::mock_builder;
/// fn main() {
/// let app = create_app(tauri::Builder::default());
/// // app.run(|_handle, _event| {});}
/// }
///
/// //#[cfg(test)]
/// mod tests {
/// use tauri::Manager;
///
/// //#[cfg(test)]
/// fn something() {
/// let app = super::create_app(tauri::test::mock_builder());
/// let window = app.get_window("main").unwrap();
/// // app createion with a `MockRuntime`
/// let app = create_app(mock_builder());
/// let window = app.get_window("main").unwrap();
///
/// // run the `ping` command and assert it returns `pong`
/// tauri::test::assert_ipc_response(
/// &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,
/// },
/// // 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")
/// );
/// }
/// // run the `ping` command and assert it returns `pong`
/// tauri::test::assert_ipc_response(
/// &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,
/// },
/// // 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>(
window: &Window<MockRuntime>,
payload: InvokePayload,
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 error = payload.error;
let ipc = window.state::<Ipc>();
let (tx, rx) = channel();
ipc.0.lock().unwrap().insert(IpcKey { callback, error }, tx);
window.clone().on_message(payload).unwrap();

assert_eq!(
rx.recv().unwrap(),
expected
.map(|e| serde_json::to_value(e).unwrap())
.map_err(|e| serde_json::to_value(e).unwrap())
);
let res: Result<JsonValue, JsonValue> = rx.recv().expect("Failed to receive result from command");
res
.map(|v| serde_json::from_value(v).unwrap())
.map_err(|e| serde_json::from_value(e).unwrap())
}

#[cfg(test)]
Expand Down

0 comments on commit 3c371aa

Please sign in to comment.