1111//! # Examples
1212//!
1313//! ```rust
14+ //! use tauri::test::{mock_builder, mock_context, noop_assets};
15+ //!
1416//! #[tauri::command]
15- //! fn my_cmd() {}
17+ //! fn ping() -> &'static str {
18+ //! "pong"
19+ //! }
1620//!
17- //! fn create_app<R: tauri::Runtime>(mut builder: tauri::Builder<R>) -> tauri::App<R> {
18- //! builder
19- //! .setup(|app| {
20- //! // do something
21- //! Ok(())
22- //! })
23- //! .invoke_handler(tauri::generate_handler![my_cmd])
24- //! // remove the string argument on your app
25- //! .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
26- //! .expect("failed to build app")
21+ //! fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
22+ //! builder
23+ //! .invoke_handler(tauri::generate_handler![ping])
24+ //! // remove the string argument to use your app's config file
25+ //! .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
26+ //! .expect("failed to build app")
2727//! }
2828//!
2929//! fn main() {
30- //! // let app = create_app(tauri::Builder::default());
31- //! // app.run(|_handle, _event| {});
32- //! }
30+ //! let app = create_app(mock_builder());
31+ //! let window = tauri::WindowBuilder::new(&app, "main", Default::default())
32+ //! .build()
33+ //! .unwrap();
3334//!
34- //! //#[cfg(test)]
35- //! mod tests {
36- //! use tauri::Manager;
37- //! //#[cfg(test)]
38- //! fn something() {
39- //! let app = super::create_app(tauri::test::mock_builder());
40- //! let window = app.get_window("main").unwrap();
41- //! // do something with the app and window
42- //! // in this case we'll run the my_cmd command with no arguments
43- //! tauri::test::assert_ipc_response(
44- //! &window,
45- //! tauri::window::InvokeRequest {
46- //! cmd: "my_cmd".into(),
47- //! callback: tauri::ipc::CallbackFn(0),
48- //! error: tauri::ipc::CallbackFn(1),
49- //! body: serde_json::Value::Null.into(),
50- //! headers: Default::default(),
51- //! },
52- //! Ok(())
53- //! );
54- //! }
35+ //! // run the `ping` command and assert it returns `pong`
36+ //! let res = tauri::test::get_ipc_response(
37+ //! &window,
38+ //! tauri::window::InvokeRequest {
39+ //! cmd: "ping".into(),
40+ //! callback: tauri::ipc::CallbackFn(0),
41+ //! error: tauri::ipc::CallbackFn(1),
42+ //! body: tauri::ipc::InvokeBody::default(),
43+ //! headers: Default::default(),
44+ //! },
45+ //! ).map(|b| b.deserialize::<String>().unwrap());
5546//! }
5647//! ```
5748
@@ -61,14 +52,10 @@ mod mock_runtime;
6152pub use mock_runtime:: * ;
6253use serde:: Serialize ;
6354
64- use std:: {
65- borrow:: Cow ,
66- fmt:: Debug ,
67- hash:: { Hash , Hasher } ,
68- } ;
55+ use std:: { borrow:: Cow , fmt:: Debug } ;
6956
7057use crate :: {
71- ipc:: { CallbackFn , InvokeResponse } ,
58+ ipc:: { InvokeBody , InvokeError , InvokeResponse } ,
7259 window:: InvokeRequest ,
7360 App , Builder , Context , Pattern , Window ,
7461} ;
@@ -77,19 +64,6 @@ use tauri_utils::{
7764 config:: { Config , PatternKind , TauriConfig } ,
7865} ;
7966
80- #[ derive( Eq , PartialEq ) ]
81- struct IpcKey {
82- callback : CallbackFn ,
83- error : CallbackFn ,
84- }
85-
86- impl Hash for IpcKey {
87- fn hash < H : Hasher > ( & self , state : & mut H ) {
88- self . callback . 0 . hash ( state) ;
89- self . error . 0 . hash ( state) ;
90- }
91- }
92-
9367/// An empty [`Assets`] implementation.
9468pub struct NoopAsset {
9569 csp_hashes : Vec < CspHash < ' static > > ,
@@ -175,74 +149,114 @@ pub fn mock_app() -> App<MockRuntime> {
175149/// # Examples
176150///
177151/// ```rust
152+ /// use tauri::test::{mock_builder, mock_context, noop_assets};
153+ ///
178154/// #[tauri::command]
179155/// fn ping() -> &'static str {
180- /// "pong"
156+ /// "pong"
181157/// }
182158///
183- /// fn create_app<R: tauri::Runtime>(mut builder: tauri::Builder<R>) -> tauri::App<R> {
184- /// builder
185- /// .invoke_handler(tauri::generate_handler![ping])
186- /// // remove the string argument on your app
187- /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
188- /// .expect("failed to build app")
159+ /// fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
160+ /// builder
161+ /// .invoke_handler(tauri::generate_handler![ping])
162+ /// // remove the string argument to use your app's config file
163+ /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
164+ /// .expect("failed to build app")
189165/// }
190166///
191167/// fn main() {
192- /// // let app = create_app(tauri::Builder::default());
193- /// // app.run(|_handle, _event| {});}
194- /// }
195- ///
196- /// //#[cfg(test)]
197- /// mod tests {
198- /// use tauri::Manager;
199- ///
200- /// //#[cfg(test)]
201- /// fn something() {
202- /// let app = super::create_app(tauri::test::mock_builder());
203- /// let window = app.get_window("main").unwrap();
168+ /// let app = create_app(mock_builder());
169+ /// let window = tauri::WindowBuilder::new(&app, "main", Default::default())
170+ /// .build()
171+ /// .unwrap();
204172///
205173/// // run the `ping` command and assert it returns `pong`
206174/// tauri::test::assert_ipc_response(
207- /// &window,
208- /// tauri::window::InvokeRequest {
209- /// cmd: "ping".into(),
210- /// callback: tauri::ipc::CallbackFn(0),
211- /// error: tauri::ipc::CallbackFn(1),
212- /// body: serde_json::Value::Null.into(),
213- /// headers: Default::default(),
214- /// },
215- /// // the expected response is a success with the "pong" payload
216- /// // we could also use Err("error message") here to ensure the command failed
175+ /// &window,
176+ /// tauri::window::InvokeRequest {
177+ /// cmd: "ping".into(),
178+ /// callback: tauri::ipc::CallbackFn(0),
179+ /// error: tauri::ipc::CallbackFn(1),
180+ /// body: tauri::ipc::InvokeBody::default(),
181+ /// headers: Default::default(),
182+ /// },
217183/// Ok("pong")
218184/// );
219- /// }
220185/// }
221186/// ```
222187pub fn assert_ipc_response < T : Serialize + Debug + Send + Sync + ' static > (
223188 window : & Window < MockRuntime > ,
224189 request : InvokeRequest ,
225190 expected : Result < T , T > ,
226191) {
192+ let response =
193+ get_ipc_response ( window, request) . map ( |b| b. deserialize :: < serde_json:: Value > ( ) . unwrap ( ) ) ;
194+ assert_eq ! (
195+ response,
196+ expected
197+ . map( |e| serde_json:: to_value( e) . unwrap( ) )
198+ . map_err( |e| serde_json:: to_value( e) . unwrap( ) )
199+ ) ;
200+ }
201+
202+ /// Executes the given IPC message and get the return value.
203+ ///
204+ /// # Examples
205+ ///
206+ /// ```rust
207+ /// use tauri::test::{mock_builder, mock_context, noop_assets};
208+ ///
209+ /// #[tauri::command]
210+ /// fn ping() -> &'static str {
211+ /// "pong"
212+ /// }
213+ ///
214+ /// fn create_app<R: tauri::Runtime>(builder: tauri::Builder<R>) -> tauri::App<R> {
215+ /// builder
216+ /// .invoke_handler(tauri::generate_handler![ping])
217+ /// // remove the string argument to use your app's config file
218+ /// .build(tauri::generate_context!("test/fixture/src-tauri/tauri.conf.json"))
219+ /// .expect("failed to build app")
220+ /// }
221+ ///
222+ /// fn main() {
223+ /// let app = create_app(mock_builder());
224+ /// let window = tauri::WindowBuilder::new(&app, "main", Default::default())
225+ /// .build()
226+ /// .unwrap();
227+ ///
228+ /// // run the `ping` command and assert it returns `pong`
229+ /// let res = tauri::test::get_ipc_response(
230+ /// &window,
231+ /// tauri::window::InvokeRequest {
232+ /// cmd: "ping".into(),
233+ /// callback: tauri::ipc::CallbackFn(0),
234+ /// error: tauri::ipc::CallbackFn(1),
235+ /// body: tauri::ipc::InvokeBody::default(),
236+ /// headers: Default::default(),
237+ /// },
238+ /// );
239+ /// assert!(res.is_ok());
240+ /// assert_eq!(res.unwrap().deserialize::<String>().unwrap(), String::from("pong"));
241+ /// }
242+ ///```
243+ pub fn get_ipc_response (
244+ window : & Window < MockRuntime > ,
245+ request : InvokeRequest ,
246+ ) -> Result < InvokeBody , serde_json:: Value > {
227247 let ( tx, rx) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
228248 window. clone ( ) . on_message (
229249 request,
230250 Box :: new ( move |_window, _cmd, response, _callback, _error| {
231- assert_eq ! (
232- match response {
233- InvokeResponse :: Ok ( b) => Ok ( b. into_json( ) ) ,
234- InvokeResponse :: Err ( e) => Err ( e. 0 ) ,
235- } ,
236- expected
237- . map( |e| serde_json:: to_value( e) . unwrap( ) )
238- . map_err( |e| serde_json:: to_value( e) . unwrap( ) )
239- ) ;
240-
241- tx. send ( ( ) ) . unwrap ( ) ;
251+ tx. send ( response) . unwrap ( ) ;
242252 } ) ,
243253 ) ;
244254
245- rx. recv ( ) . unwrap ( ) ;
255+ let res = rx. recv ( ) . expect ( "Failed to receive result from command" ) ;
256+ match res {
257+ InvokeResponse :: Ok ( b) => Ok ( b) ,
258+ InvokeResponse :: Err ( InvokeError ( v) ) => Err ( v) ,
259+ }
246260}
247261
248262#[ cfg( test) ]
0 commit comments