mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-12-24 11:14:40 +03:00
feat(core): allow the MockRuntime
to call a command and get a return value + fix doctest (#8380)
* Add `get_ipc_response` to the `MockRuntime` * Fix `MockRuntime` doctests * Add support for raw ipc * cleanup, add change file * only a single get fn --------- Co-authored-by: Lucas Nogueira <lucas@crabnebula.dev>
This commit is contained in:
parent
5848b4e8e9
commit
db12777742
5
.changes/get-ipc-response-test.md
Normal file
5
.changes/get-ipc-response-test.md
Normal file
@ -0,0 +1,5 @@
|
||||
---
|
||||
"tauri": patch:enhance
|
||||
---
|
||||
|
||||
Added `test::get_ipc_response`.
|
@ -11,47 +11,38 @@
|
||||
//! # Examples
|
||||
//!
|
||||
//! ```rust
|
||||
//! #[tauri::command]
|
||||
//! fn my_cmd() {}
|
||||
//! use tauri::test::{mock_builder, mock_context, noop_assets};
|
||||
//!
|
||||
//! fn create_app<R: tauri::Runtime>(mut builder: tauri::Builder<R>) -> tauri::App<R> {
|
||||
//! #[tauri::command]
|
||||
//! fn ping() -> &'static str {
|
||||
//! "pong"
|
||||
//! }
|
||||
//!
|
||||
//! fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
|
||||
//! builder
|
||||
//! .setup(|app| {
|
||||
//! // do something
|
||||
//! Ok(())
|
||||
//! })
|
||||
//! .invoke_handler(tauri::generate_handler![my_cmd])
|
||||
//! // remove the string argument on your app
|
||||
//! .invoke_handler(tauri::generate_handler![ping])
|
||||
//! // remove the string argument to use your app's config file
|
||||
//! .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
//! .expect("failed to build app")
|
||||
//! }
|
||||
//!
|
||||
//! fn main() {
|
||||
//! // let app = create_app(tauri::Builder::default());
|
||||
//! // app.run(|_handle, _event| {});
|
||||
//! }
|
||||
//! let app = create_app(mock_builder());
|
||||
//! let window = tauri::WindowBuilder::new(&app, "main", Default::default())
|
||||
//! .build()
|
||||
//! .unwrap();
|
||||
//!
|
||||
//! //#[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();
|
||||
//! // do something with the app and window
|
||||
//! // in this case we'll run the my_cmd command with no arguments
|
||||
//! tauri::test::assert_ipc_response(
|
||||
//! // run the `ping` command and assert it returns `pong`
|
||||
//! let res = tauri::test::get_ipc_response(
|
||||
//! &window,
|
||||
//! tauri::window::InvokeRequest {
|
||||
//! cmd: "my_cmd".into(),
|
||||
//! cmd: "ping".into(),
|
||||
//! callback: tauri::ipc::CallbackFn(0),
|
||||
//! error: tauri::ipc::CallbackFn(1),
|
||||
//! body: serde_json::Value::Null.into(),
|
||||
//! body: tauri::ipc::InvokeBody::default(),
|
||||
//! headers: Default::default(),
|
||||
//! },
|
||||
//! Ok(())
|
||||
//! );
|
||||
//! }
|
||||
//! ).map(|b| b.deserialize::<String>().unwrap());
|
||||
//! }
|
||||
//! ```
|
||||
|
||||
@ -61,14 +52,10 @@ mod mock_runtime;
|
||||
pub use mock_runtime::*;
|
||||
use serde::Serialize;
|
||||
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
fmt::Debug,
|
||||
hash::{Hash, Hasher},
|
||||
};
|
||||
use std::{borrow::Cow, fmt::Debug};
|
||||
|
||||
use crate::{
|
||||
ipc::{CallbackFn, InvokeResponse},
|
||||
ipc::{InvokeBody, InvokeError, InvokeResponse},
|
||||
window::InvokeRequest,
|
||||
App, Builder, Context, Pattern, Window,
|
||||
};
|
||||
@ -77,19 +64,6 @@ use tauri_utils::{
|
||||
config::{Config, PatternKind, TauriConfig},
|
||||
};
|
||||
|
||||
#[derive(Eq, PartialEq)]
|
||||
struct IpcKey {
|
||||
callback: CallbackFn,
|
||||
error: CallbackFn,
|
||||
}
|
||||
|
||||
impl Hash for IpcKey {
|
||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||
self.callback.0.hash(state);
|
||||
self.error.0.hash(state);
|
||||
}
|
||||
}
|
||||
|
||||
/// An empty [`Assets`] implementation.
|
||||
pub struct NoopAsset {
|
||||
csp_hashes: Vec<CspHash<'static>>,
|
||||
@ -175,32 +149,26 @@ pub fn mock_app() -> App<MockRuntime> {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri::test::{mock_builder, mock_context, noop_assets};
|
||||
///
|
||||
/// #[tauri::command]
|
||||
/// fn ping() -> &'static str {
|
||||
/// "pong"
|
||||
/// }
|
||||
///
|
||||
/// fn create_app<R: tauri::Runtime>(mut builder: tauri::Builder<R>) -> tauri::App<R> {
|
||||
/// fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
|
||||
/// builder
|
||||
/// .invoke_handler(tauri::generate_handler![ping])
|
||||
/// // remove the string argument on your app
|
||||
/// // remove the string argument to use your app's config file
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .expect("failed to build app")
|
||||
/// }
|
||||
///
|
||||
/// 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();
|
||||
/// let app = create_app(mock_builder());
|
||||
/// let window = tauri::WindowBuilder::new(&app, "main", Default::default())
|
||||
/// .build()
|
||||
/// .unwrap();
|
||||
///
|
||||
/// // run the `ping` command and assert it returns `pong`
|
||||
/// tauri::test::assert_ipc_response(
|
||||
@ -209,40 +177,86 @@ pub fn mock_app() -> App<MockRuntime> {
|
||||
/// cmd: "ping".into(),
|
||||
/// callback: tauri::ipc::CallbackFn(0),
|
||||
/// error: tauri::ipc::CallbackFn(1),
|
||||
/// body: serde_json::Value::Null.into(),
|
||||
/// body: tauri::ipc::InvokeBody::default(),
|
||||
/// headers: Default::default(),
|
||||
/// },
|
||||
/// // 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 + Send + Sync + 'static>(
|
||||
window: &Window<MockRuntime>,
|
||||
request: InvokeRequest,
|
||||
expected: Result<T, T>,
|
||||
) {
|
||||
let (tx, rx) = std::sync::mpsc::sync_channel(1);
|
||||
window.clone().on_message(
|
||||
request,
|
||||
Box::new(move |_window, _cmd, response, _callback, _error| {
|
||||
let response =
|
||||
get_ipc_response(window, request).map(|b| b.deserialize::<serde_json::Value>().unwrap());
|
||||
assert_eq!(
|
||||
match response {
|
||||
InvokeResponse::Ok(b) => Ok(b.into_json()),
|
||||
InvokeResponse::Err(e) => Err(e.0),
|
||||
},
|
||||
response,
|
||||
expected
|
||||
.map(|e| serde_json::to_value(e).unwrap())
|
||||
.map_err(|e| serde_json::to_value(e).unwrap())
|
||||
);
|
||||
}
|
||||
|
||||
tx.send(()).unwrap();
|
||||
/// Executes the given IPC message and get the return value.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use tauri::test::{mock_builder, mock_context, noop_assets};
|
||||
///
|
||||
/// #[tauri::command]
|
||||
/// fn ping() -> &'static str {
|
||||
/// "pong"
|
||||
/// }
|
||||
///
|
||||
/// fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
|
||||
/// builder
|
||||
/// .invoke_handler(tauri::generate_handler![ping])
|
||||
/// // remove the string argument to use your app's config file
|
||||
/// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
|
||||
/// .expect("failed to build app")
|
||||
/// }
|
||||
///
|
||||
/// fn main() {
|
||||
/// let app = create_app(mock_builder());
|
||||
/// let window = tauri::WindowBuilder::new(&app, "main", Default::default())
|
||||
/// .build()
|
||||
/// .unwrap();
|
||||
///
|
||||
/// // run the `ping` command and assert it returns `pong`
|
||||
/// let res = tauri::test::get_ipc_response(
|
||||
/// &window,
|
||||
/// tauri::window::InvokeRequest {
|
||||
/// cmd: "ping".into(),
|
||||
/// callback: tauri::ipc::CallbackFn(0),
|
||||
/// error: tauri::ipc::CallbackFn(1),
|
||||
/// body: tauri::ipc::InvokeBody::default(),
|
||||
/// headers: Default::default(),
|
||||
/// },
|
||||
/// );
|
||||
/// assert!(res.is_ok());
|
||||
/// assert_eq!(res.unwrap().deserialize::<String>().unwrap(), String::from("pong"));
|
||||
/// }
|
||||
///```
|
||||
pub fn get_ipc_response(
|
||||
window: &Window<MockRuntime>,
|
||||
request: InvokeRequest,
|
||||
) -> Result<InvokeBody, serde_json::Value> {
|
||||
let (tx, rx) = std::sync::mpsc::sync_channel(1);
|
||||
window.clone().on_message(
|
||||
request,
|
||||
Box::new(move |_window, _cmd, response, _callback, _error| {
|
||||
tx.send(response).unwrap();
|
||||
}),
|
||||
);
|
||||
|
||||
rx.recv().unwrap();
|
||||
let res = rx.recv().expect("Failed to receive result from command");
|
||||
match res {
|
||||
InvokeResponse::Ok(b) => Ok(b),
|
||||
InvokeResponse::Err(InvokeError(v)) => Err(v),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
Loading…
Reference in New Issue
Block a user