Repository: slawlor/ractor
Pull request #341 (2025-04-02 09:49:56)

Initial support for target `wasm32-unknown-unknown` in browser
This PR updates support for wasm in browser, this includes:
- Uses `tokio_with_wasm` as async runtime in target `wasm32-unknown-unknown`
- Uses `wasm-bindgen-test` as test runner
- Uses `web_time` to provide `Instant`, `Duration` on wasm
- Changed feature configuration for some crates on wasm32-unknown-unknown
- Remove `Send` marker on some future in return types of `Actor` and `Worker` traits on wasm (futures in `tokio_with_wasm` are not `Send`, since there is no threads on wasm32-unknown-unknown)

There are still some issues:
- panic unwind on `wasm32-unknown-unknown` is still a nightly feature. To allow actors panic, nightly version of rustc should be used. See https://github.com/rust-lang/rust/issues/118168 for details.
- Due to the lack of panic unwind, some unit tests are filtered out on `wasm32-unknown-unknown`
- Unit tests of wasm32-unknown-unknown can't be executed in CI. Headless browser execution of `wasm-pack` is totally broken (See https://github.com/rustwasm/wasm-pack/issues/1424 ). I have executed the unit-tests manually in a browser and all unit-tests (except for those needs panic unwind) passed. See the screenshot following.
![unittests](https://github.com/user-attachments/assets/7732e0a8-f141-4f0b-981f-b0b89edd230b)


codecov[bot]: ## [Codecov](https://app.codecov.io/gh/slawlor/ractor/pull/341?dropdown=coverage&src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) Report
Attention: Patch coverage is `0%` with `396 lines` in your changes missing coverage. Please review.
> Project coverage is 80.59%. Comparing base [(`caf94c0`)](https://app.codecov.io/gh/slawlor/ractor/commit/caf94c08beef51e863c09e74e83fdb4c5fccf589?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) to head [(`456ba9a`)](https://app.codecov.io/gh/slawlor/ractor/commit/456ba9aec88905aa94222f6b45bda6febb75d027?dropdown=coverage&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor).

| [Files with missing lines](https://app.codecov.io/gh/slawlor/ractor/pull/341?dropdown=coverage&src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) | Patch % | Lines |
|---|---|---|
| [ractor/src/actor/tests/mod.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Factor%2Ftests%2Fmod.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9hY3Rvci90ZXN0cy9tb2QucnM=) | 0.00% | [85 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/actor/tests/supervisor.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Factor%2Ftests%2Fsupervisor.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9hY3Rvci90ZXN0cy9zdXBlcnZpc29yLnJz) | 0.00% | [68 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/pg/tests.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Fpg%2Ftests.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9wZy90ZXN0cy5ycw==) | 0.00% | [64 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/factory/tests/basic.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Ffactory%2Ftests%2Fbasic.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9mYWN0b3J5L3Rlc3RzL2Jhc2ljLnJz) | 0.00% | [28 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/registry/tests.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Fregistry%2Ftests.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9yZWdpc3RyeS90ZXN0cy5ycw==) | 0.00% | [28 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/factory/tests/ratelim.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Ffactory%2Ftests%2Fratelim.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9mYWN0b3J5L3Rlc3RzL3JhdGVsaW0ucnM=) | 0.00% | [24 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/port/output/tests.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Fport%2Foutput%2Ftests.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9wb3J0L291dHB1dC90ZXN0cy5ycw==) | 0.00% | [16 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/rpc/tests.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Frpc%2Ftests.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9ycGMvdGVzdHMucnM=) | 0.00% | [16 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/time/tests.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Ftime%2Ftests.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy90aW1lL3Rlc3RzLnJz) | 0.00% | [16 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| [ractor/src/factory/queues.rs](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&filepath=ractor%2Fsrc%2Ffactory%2Fqueues.rs&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor#diff-cmFjdG9yL3NyYy9mYWN0b3J5L3F1ZXVlcy5ycw==) | 0.00% | [8 Missing :warning: ](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) |
| ... and [9 more](https://app.codecov.io/gh/slawlor/ractor/pull/341?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor) | |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##             main     #341      +/-   ##
==========================================
- Coverage   82.39%   80.59%   -1.80%     
==========================================
  Files          65       65              
  Lines       12917    13229     +312     
==========================================
+ Hits        10643    10662      +19     
- Misses       2274     2567     +293     
```

</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/slawlor/ractor/pull/341?dropdown=coverage&src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Sean+Lawlor).

<details><summary> :rocket: New features to boost your workflow: </summary>

- :snowflake: [Test Analytics](https://docs.codecov.com/docs/test-analytics): Detect flaky tests, report on failures, and find test suite problems.
</details>
slawlor: Can you add the steps to run the test-suite? What's needed to run the suite? Is there local install steps, etc?

It'd be good to document it in a guide somewhere, just a markdown file perhaps at the root of the repo would be awesome. (Since we can't run them in CI)
Officeyutong: > Can you add the steps to run the test-suite? What's needed to run the suite? Is there local install steps, etc?
> 
> It'd be good to document it in a guide somewhere, just a markdown file perhaps at the root of the repo would be awesome. (Since we can't run them in CI)

I have added a markdown document in the repo root and described how to run unit-tests for wasm32-unknown-unknown

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 82d0f6e..44e391c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -5,6 +5,7 @@ members = [
     "ractor_cluster_derive",
     "ractor_playground",
     "ractor_cluster_integration_tests",
-    "xtask"
+    "ractor_example_entry_proc",
+    "xtask",
 ]
-resolver = "2"
\ No newline at end of file
+resolver = "2"
diff --git a/ractor/Cargo.toml b/ractor/Cargo.toml
index fca52fd..708dfbb 100644
--- a/ractor/Cargo.toml
+++ b/ractor/Cargo.toml
@@ -14,7 +14,10 @@ categories = ["asynchronous"]
 rust-version = "1.64"
 
 [lints.rust]
-unexpected_cfgs = { level = "warn", check-cfg = ['cfg(tokio_unstable)', 'cfg(rust_analyzer)'] }
+unexpected_cfgs = { level = "warn", check-cfg = [
+    'cfg(tokio_unstable)',
+    'cfg(rust_analyzer)',
+] }
 
 [features]
 ### Other features
@@ -44,20 +47,48 @@ tracing = { version = "0.1", features = ["attributes"] }
 
 ## Blanket Serde
 serde = { version = "1", optional = true }
-pot =  { version = "3.0", optional = true }
+pot = { version = "3.0", optional = true }
+
+
+[target.'cfg(all(target_arch = "wasm32",target_os = "unknown"))'.dependencies]
+tokio_with_wasm = { version = "0.8.2", features = [
+    "macros",
+    "sync",
+    "rt",
+    "time",
+] }
+web-time = "1.1.0"
 
 [dev-dependencies]
 backtrace = "0.3"
-criterion = "0.5"
+
 function_name = "0.3"
 paste = "1"
 serial_test = "3.0.0"
 rand = "0.8"
-tokio = { version = "1.30", features = ["rt", "time", "sync", "macros", "rt-multi-thread", "tracing"] }
 tracing-glog = "0.4"
-tracing-subscriber = { version = "0.3", features = ["env-filter"]}
+tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+
+ractor_example_entry_proc = { path = "../ractor_example_entry_proc" }
+
+[target.'cfg(not(all(target_arch = "wasm32", target_os = "unknown")))'.dev-dependencies]
+tokio = { version = "1.30", features = [
+    "rt",
+    "time",
+    "sync",
+    "macros",
+    "rt-multi-thread",
+    "tracing",
+] }
+criterion = "0.5"
 tracing-test = "0.2"
 
+[target.'cfg(all(target_arch = "wasm32", target_os = "unknown"))'.dev-dependencies]
+tokio = { version = "1.30", features = ["rt", "time", "sync", "macros"] }
+wasm-bindgen-test = "0.3.50"
+getrandom = { version = "*", features = ["js"] }
+criterion = { version = "0.5", default-features = false }
+
 [[bench]]
 name = "actor"
 harness = false
@@ -66,4 +97,4 @@ required-features = []
 [[bench]]
 name = "async_traits"
 harness = false
-required-features = []
\ No newline at end of file
+required-features = []
diff --git a/ractor/examples/a_whole_lotta.rs b/ractor/examples/a_whole_lotta.rs
index 3cafb48..2f82769 100644
--- a/ractor/examples/a_whole_lotta.rs
+++ b/ractor/examples/a_whole_lotta.rs
@@ -63,7 +63,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
 
diff --git a/ractor/examples/a_whole_lotta_messages.rs b/ractor/examples/a_whole_lotta_messages.rs
index 1b1989a..5671310 100644
--- a/ractor/examples/a_whole_lotta_messages.rs
+++ b/ractor/examples/a_whole_lotta_messages.rs
@@ -74,7 +74,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
 
diff --git a/ractor/examples/counter.rs b/ractor/examples/counter.rs
index 0c507f3..1de42ea 100644
--- a/ractor/examples/counter.rs
+++ b/ractor/examples/counter.rs
@@ -101,7 +101,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
     let (actor, handle) = Actor::spawn(Some("test_name".to_string()), Counter, ())
diff --git a/ractor/examples/monte_carlo.rs b/ractor/examples/monte_carlo.rs
index 713309f..0477a6c 100644
--- a/ractor/examples/monte_carlo.rs
+++ b/ractor/examples/monte_carlo.rs
@@ -230,7 +230,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
 
diff --git a/ractor/examples/output_port.rs b/ractor/examples/output_port.rs
index d4b28bb..dd41c47 100644
--- a/ractor/examples/output_port.rs
+++ b/ractor/examples/output_port.rs
@@ -129,7 +129,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
 
diff --git a/ractor/examples/philosophers.rs b/ractor/examples/philosophers.rs
index f17fe84..f8cd9a2 100644
--- a/ractor/examples/philosophers.rs
+++ b/ractor/examples/philosophers.rs
@@ -487,7 +487,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
 
diff --git a/ractor/examples/ping_pong.rs b/ractor/examples/ping_pong.rs
index e2e5f3f..d346d6f 100644
--- a/ractor/examples/ping_pong.rs
+++ b/ractor/examples/ping_pong.rs
@@ -107,7 +107,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
 
diff --git a/ractor/examples/supervisor.rs b/ractor/examples/supervisor.rs
index 9a6f6bb..1a3f0fe 100644
--- a/ractor/examples/supervisor.rs
+++ b/ractor/examples/supervisor.rs
@@ -46,7 +46,7 @@ fn init_logging() {
     tracing::subscriber::set_global_default(subscriber).expect("to set global subscriber");
 }
 
-#[tokio::main]
+#[ractor_example_entry_proc::ractor_example_entry]
 async fn main() {
     init_logging();
 
diff --git a/ractor/src/actor/mod.rs b/ractor/src/actor/mod.rs
index e5ad6a8..5d96518 100644
--- a/ractor/src/actor/mod.rs
+++ b/ractor/src/actor/mod.rs
@@ -60,8 +60,9 @@ use futures::TryFutureExt;
 use tracing::Instrument;
 
 use crate::concurrency::JoinHandle;
+#[cfg(not(feature = "async-trait"))]
+use crate::concurrency::MaybeSend;
 use crate::ActorId;
-
 pub mod messages;
 use messages::*;
 
@@ -141,7 +142,7 @@ pub trait Actor: Sized + Sync + Send + 'static {
         &self,
         myself: ActorRef<Self::Msg>,
         args: Self::Arguments,
-    ) -> impl Future<Output = Result<Self::State, ActorProcessingErr>> + Send;
+    ) -> impl Future<Output = Result<Self::State, ActorProcessingErr>> + MaybeSend;
     /// Invoked when an actor is being started by the system.
     ///
     /// Any initialization inherent to the actor's role should be
@@ -178,9 +179,10 @@ pub trait Actor: Sized + Sync + Send + 'static {
         &self,
         myself: ActorRef<Self::Msg>,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async { Ok(()) }
     }
+
     /// Invoked after an actor has started.
     ///
     /// Any post initialization can be performed here, such as writing
@@ -214,7 +216,7 @@ pub trait Actor: Sized + Sync + Send + 'static {
         &self,
         myself: ActorRef<Self::Msg>,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async { Ok(()) }
     }
     /// Invoked after an actor has been stopped to perform final cleanup. In the
@@ -248,7 +250,7 @@ pub trait Actor: Sized + Sync + Send + 'static {
         myself: ActorRef<Self::Msg>,
         message: Self::Msg,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async { Ok(()) }
     }
     /// Handle the incoming message from the event processing loop. Unhandled panickes will be
@@ -281,7 +283,7 @@ pub trait Actor: Sized + Sync + Send + 'static {
         myself: ActorRef<Self::Msg>,
         message: crate::message::SerializedMessage,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async { Ok(()) }
     }
     /// Handle the remote incoming message from the event processing loop. Unhandled panickes will be
@@ -315,7 +317,7 @@ pub trait Actor: Sized + Sync + Send + 'static {
         myself: ActorRef<Self::Msg>,
         message: SupervisionEvent,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async move {
             match message {
                 SupervisionEvent::ActorTerminated(who, _, _)
@@ -367,7 +369,8 @@ pub trait Actor: Sized + Sync + Send + 'static {
         name: Option<ActorName>,
         handler: Self,
         startup_args: Self::Arguments,
-    ) -> impl Future<Output = Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr>> + Send {
+    ) -> impl Future<Output = Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr>> + MaybeSend
+    {
         ActorRuntime::<Self>::spawn(name, handler, startup_args)
     }
     /// Spawn an actor of this type, which is unsupervised, automatically starting
@@ -406,7 +409,8 @@ pub trait Actor: Sized + Sync + Send + 'static {
         handler: Self,
         startup_args: Self::Arguments,
         supervisor: ActorCell,
-    ) -> impl Future<Output = Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr>> + Send {
+    ) -> impl Future<Output = Result<(ActorRef<Self::Msg>, JoinHandle<()>), SpawnErr>> + MaybeSend
+    {
         ActorRuntime::<Self>::spawn_linked(name, handler, startup_args, supervisor)
     }
     /// Spawn an actor of this type with a supervisor, automatically starting the actor
diff --git a/ractor/src/actor/supervision.rs b/ractor/src/actor/supervision.rs
index cc4f15b..2f78e9a 100644
--- a/ractor/src/actor/supervision.rs
+++ b/ractor/src/actor/supervision.rs
@@ -134,14 +134,17 @@ impl SupervisionTree {
         }
         // drain the tasks
         while let Some(res) = js.join_next().await {
-            #[cfg(feature = "async-std")]
-            {
-                match res {
-                    Err(_) => panic!("JoinSet join error"),
-                    _ => {}
-                }
+            #[cfg(any(
+                feature = "async-std",
+                all(target_arch = "wasm32", target_os = "unknown")
+            ))]
+            if res.is_err() {
+                panic!("JoinSet join error");
             }
-            #[cfg(not(feature = "async-std"))]
+            #[cfg(not(any(
+                feature = "async-std",
+                all(target_arch = "wasm32", target_os = "unknown")
+            )))]
             {
                 match res {
                     Err(err) if err.is_panic() => std::panic::resume_unwind(err.into_panic()),
@@ -165,14 +168,17 @@ impl SupervisionTree {
         }
         // drain the tasks
         while let Some(res) = js.join_next().await {
-            #[cfg(feature = "async-std")]
-            {
-                match res {
-                    Err(_) => panic!("JoinSet join error"),
-                    _ => {}
-                }
+            #[cfg(any(
+                feature = "async-std",
+                all(target_arch = "wasm32", target_os = "unknown")
+            ))]
+            if res.is_err() {
+                panic!("JoinSet join error");
             }
-            #[cfg(not(feature = "async-std"))]
+            #[cfg(not(any(
+                feature = "async-std",
+                all(target_arch = "wasm32", target_os = "unknown")
+            )))]
             {
                 match res {
                     Err(err) if err.is_panic() => std::panic::resume_unwind(err.into_panic()),
diff --git a/ractor/src/concurrency/mod.rs b/ractor/src/concurrency/mod.rs
index 2921d47..33f0eee 100644
--- a/ractor/src/concurrency/mod.rs
+++ b/ractor/src/concurrency/mod.rs
@@ -58,12 +58,50 @@ pub fn broadcast<T: Clone>(buffer: usize) -> (BroadcastSender<T>, BroadcastRecei
     tokio::sync::broadcast::channel(buffer)
 }
 
-#[cfg(not(feature = "async-std"))]
+#[cfg(all(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    not(feature = "async-std")
+))]
 pub mod tokio_primitives;
-#[cfg(not(feature = "async-std"))]
+#[cfg(all(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    not(feature = "async-std")
+))]
 pub use self::tokio_primitives::*;
 
-#[cfg(feature = "async-std")]
+#[cfg(all(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    feature = "async-std"
+))]
 pub mod async_std_primitives;
-#[cfg(feature = "async-std")]
+#[cfg(all(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    feature = "async-std"
+))]
 pub use self::async_std_primitives::*;
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+pub mod tokio_with_wasm_primitives;
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+pub use self::tokio_with_wasm_primitives::*;
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+mod target_specific {
+    /// A wrapper for [std::marker::Send] on non-`wasm32-unknown-unknown` targets, or an empty trait on `wasm32-unknown-unknown` targets.
+    /// Introduced for compatibility between wasm32 and other targets
+    pub trait MaybeSend {}
+    impl<T> MaybeSend for T {}
+    pub(crate) use web_time::SystemTime;
+}
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
+mod target_specific {
+    /// A wrapper for [std::marker::Send] on non-`wasm32-unknown-unknown` targets, or an empty trait on `wasm32-unknown-unknown` targets.
+    /// Introduced for compatibility between wasm32 and other targets
+    pub trait MaybeSend: Send {}
+    impl<T> MaybeSend for T where T: Send {}
+    pub(crate) use std::time::SystemTime;
+}
+
+#[cfg(not(feature = "async-trait"))]
+pub use target_specific::MaybeSend;
+pub(crate) use target_specific::SystemTime;
diff --git a/ractor/src/concurrency/tokio_with_wasm_primitives.rs b/ractor/src/concurrency/tokio_with_wasm_primitives.rs
new file mode 100644
index 0000000..9bf7eb8
--- /dev/null
+++ b/ractor/src/concurrency/tokio_with_wasm_primitives.rs
@@ -0,0 +1,105 @@
+// Copyright (c) Sean Lawlor
+//
+// This source code is licensed under both the MIT license found in the
+// LICENSE-MIT file in the root directory of this source tree.
+
+//! Concurrency primitives based on `tokio`
+
+use std::future::Future;
+
+use tokio_with_wasm::alias as tokio;
+
+/// Represents a task JoinHandle
+pub type JoinHandle<T> = tokio::task::JoinHandle<T>;
+
+/// A duration of time
+pub type Duration = std::time::Duration;
+
+/// An instant measured on system time
+pub type Instant = web_time::Instant;
+
+/// Sleep the task for a duration of time
+pub async fn sleep(dur: Duration) {
+    tokio::time::sleep(dur).await;
+}
+
+/// An asynchronous interval calculation which waits until
+/// a checkpoint time to tick
+pub type Interval = tokio::time::Interval;
+
+/// Build a new interval at the given duration starting at now
+///
+/// Ticks 1 time immediately
+pub fn interval(dur: Duration) -> Interval {
+    tokio::time::interval(dur)
+}
+
+/// A set of futures to join on, in an unordered fashion
+/// (first-completed, first-served)
+pub type JoinSet<T> = tokio::task::JoinSet<T>;
+
+/// Spawn a task on the executor runtime
+pub fn spawn<F>(future: F) -> JoinHandle<F::Output>
+where
+    F: Future + 'static,
+    F::Output: 'static,
+{
+    spawn_named(None, future)
+}
+
+/// Spawn a (possibly) named task on the executor runtime
+pub fn spawn_named<F>(name: Option<&str>, future: F) -> JoinHandle<F::Output>
+where
+    F: Future + 'static,
+    F::Output: 'static,
+{
+    #[cfg(tokio_unstable)]
+    {
+        let mut builder = tokio::task::Builder::new();
+        if let Some(name) = name {
+            builder = builder.name(name);
+        }
+        builder.spawn(future).expect("Tokio task spawn failed")
+    }
+
+    #[cfg(not(tokio_unstable))]
+    {
+        let _ = name;
+        tokio::task::spawn(future)
+    }
+}
+
+/// Execute the future up to a timeout
+///
+/// * `dur`: The duration of time to allow the future to execute for
+/// * `future`: The future to execute
+///
+/// Returns [Ok(_)] if the future succeeded before the timeout, [Err(super::Timeout)] otherwise
+pub async fn timeout<F, T>(dur: super::Duration, future: F) -> Result<T, super::Timeout>
+where
+    F: Future<Output = T>,
+{
+    tokio::time::timeout(dur, future)
+        .await
+        .map_err(|_| super::Timeout)
+}
+
+macro_rules! select {
+        ($($tokens:tt)*) => {{
+            tokio::select! {
+                // Biased ensures that we poll the ports in the order they appear, giving
+                // priority to our message reception operations. See:
+                // https://docs.rs/tokio/latest/tokio/macro.select.html#fairness
+                // for more information
+                biased;
+
+                $( $tokens )*
+            }
+        }}
+    }
+
+pub(crate) use select;
+
+// test macro
+#[cfg(test)]
+pub use wasm_bindgen_test::wasm_bindgen_test as test;
diff --git a/ractor/src/factory/job.rs b/ractor/src/factory/job.rs
index 666fd7f..3c59078 100644
--- a/ractor/src/factory/job.rs
+++ b/ractor/src/factory/job.rs
@@ -5,10 +5,11 @@
 
 //! Specification for a [Job] sent to a factory
 
+use crate::concurrency::SystemTime;
 use std::fmt::Debug;
+use std::hash::Hash;
 use std::panic::RefUnwindSafe;
 use std::sync::Arc;
-use std::{hash::Hash, time::SystemTime};
 
 use bon::Builder;
 use tracing::Span;
@@ -701,7 +702,10 @@ mod tests {
     type TheJob = Job<TestKey, TestMessage>;
 
     #[test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     fn test_job_serialization() {
         // Check Cast variant
         let job_a = TheJob {
@@ -767,7 +771,10 @@ mod tests {
     }
 
     #[test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     fn test_factory_message_serialization() {
         let job_a = TheJob {
             key: TestKey { item: 123 },
diff --git a/ractor/src/factory/queues.rs b/ractor/src/factory/queues.rs
index 4073248..6575cc9 100644
--- a/ractor/src/factory/queues.rs
+++ b/ractor/src/factory/queues.rs
@@ -407,7 +407,10 @@ mod tests {
     }
 
     #[crate::concurrency::test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     async fn test_basic_queueing() {
         let mut queue = DefaultQueue::<u64, ()>::default();
         for i in 0..99 {
@@ -459,7 +462,10 @@ mod tests {
     }
 
     #[crate::concurrency::test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     async fn test_priority_queueing() {
         let mut queue = PriorityQueue::<u64, (), BasicPriority, BasicPriorityManager, 2>::new(
             BasicPriorityManager,
diff --git a/ractor/src/factory/worker.rs b/ractor/src/factory/worker.rs
index a0aebcd..fe6b5be 100644
--- a/ractor/src/factory/worker.rs
+++ b/ractor/src/factory/worker.rs
@@ -14,6 +14,8 @@ use std::sync::Arc;
 use bon::Builder;
 use tracing::Instrument;
 
+#[cfg(not(feature = "async-trait"))]
+use crate::concurrency::MaybeSend;
 use crate::concurrency::{Duration, Instant, JoinHandle};
 use crate::{Actor, ActorId, ActorProcessingErr};
 use crate::{ActorCell, ActorRef, Message, MessagingErr, SupervisionEvent};
@@ -83,7 +85,7 @@ pub trait Worker: Send + Sync + 'static {
         wid: WorkerId,
         factory: &ActorRef<FactoryMessage<Self::Key, Self::Message>>,
         args: Self::Arguments,
-    ) -> impl Future<Output = Result<Self::State, ActorProcessingErr>> + Send;
+    ) -> impl Future<Output = Result<Self::State, ActorProcessingErr>> + MaybeSend;
 
     /// Invoked when a worker is being started by the system.
     ///
@@ -125,7 +127,7 @@ pub trait Worker: Send + Sync + 'static {
         wid: WorkerId,
         factory: &ActorRef<FactoryMessage<Self::Key, Self::Message>>,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async { Ok(()) }
     }
     /// Invoked after an actor has started.
@@ -165,7 +167,7 @@ pub trait Worker: Send + Sync + 'static {
         wid: WorkerId,
         factory: &ActorRef<FactoryMessage<Self::Key, Self::Message>>,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async { Ok(()) }
     }
     /// Invoked after an actor has been stopped to perform final cleanup. In the
@@ -205,7 +207,7 @@ pub trait Worker: Send + Sync + 'static {
         factory: &ActorRef<FactoryMessage<Self::Key, Self::Message>>,
         job: Job<Self::Key, Self::Message>,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<Self::Key, ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<Self::Key, ActorProcessingErr>> + MaybeSend {
         async { Ok(job.key) }
     }
 
@@ -244,7 +246,7 @@ pub trait Worker: Send + Sync + 'static {
         myself: ActorCell,
         message: SupervisionEvent,
         state: &mut Self::State,
-    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + Send {
+    ) -> impl Future<Output = Result<(), ActorProcessingErr>> + MaybeSend {
         async move {
             match message {
                 SupervisionEvent::ActorTerminated(who, _, _)
diff --git a/ractor/src/lib.rs b/ractor/src/lib.rs
index 72df9a6..abdf843 100644
--- a/ractor/src/lib.rs
+++ b/ractor/src/lib.rs
@@ -182,7 +182,6 @@ pub mod time;
 use concurrency::JoinHandle;
 #[cfg(not(feature = "async-trait"))]
 use strum as _;
-
 // ======================== Test Modules and blind imports ======================== //
 
 #[cfg(test)]
diff --git a/ractor_example_entry_proc/Cargo.toml b/ractor_example_entry_proc/Cargo.toml
new file mode 100644
index 0000000..b2952ee
--- /dev/null
+++ b/ractor_example_entry_proc/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "ractor_example_entry_proc"
+version = "0.0.0"
+authors = ["Sean Lawlor <slawlor>"]
+description = "A wrapper for tokio::main which uses different arguments on wasm"
+license = "MIT"
+edition = "2021"
+categories = []
+keywords = ["actor", "ractor"]
+repository = "https://github.com/slawlor/ractor"
+readme = "../README.md"
+rust-version = "1.64"
+
+[lib]
+name = "ractor_example_entry_proc"
+path = "src/lib.rs"
+proc-macro = true
+
+[dependencies]
+quote = "1"
+syn = { version = "2", features = ["full"] }
diff --git a/ractor_example_entry_proc/src/lib.rs b/ractor_example_entry_proc/src/lib.rs
new file mode 100644
index 0000000..663ff20
--- /dev/null
+++ b/ractor_example_entry_proc/src/lib.rs
@@ -0,0 +1,25 @@
+// Copyright (c) Sean Lawlor
+//
+// This source code is licensed under both the MIT license found in the
+// LICENSE-MIT file in the root directory of this source tree.
+
+use proc_macro::TokenStream;
+use quote::quote;
+use syn::{parse_macro_input, ItemFn};
+
+/// Expands to `#[tokio::main(flavor = "current_thread")]` on `wasm32-unknown-unknown`, `#[tokio::main]` on other platforms
+#[proc_macro_attribute]
+pub fn ractor_example_entry(_: TokenStream, input: TokenStream) -> TokenStream {
+    let input_fn = parse_macro_input!(input as ItemFn);
+
+    (quote! {
+        #[cfg_attr(
+            all(target_arch = "wasm32", target_os = "unknown"),
+            tokio::main(flavor = "current_thread")
+        )]
+        #[cfg_attr(not(all(target_arch = "wasm32", target_os = "unknown")), tokio::main)]
+
+        #input_fn
+    })
+    .into()
+}


Test patch:
diff --git a/ractor/src/actor/tests/mod.rs b/ractor/src/actor/tests/mod.rs
index 0697e80..364ba7b 100644
--- a/ractor/src/actor/tests/mod.rs
+++ b/ractor/src/actor/tests/mod.rs
@@ -28,7 +28,11 @@ struct EmptyMessage;
 impl crate::Message for EmptyMessage {}
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 async fn test_panic_on_start_captured() {
     #[derive(Default)]
     struct TestActor;
@@ -53,7 +57,10 @@ async fn test_panic_on_start_captured() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_error_on_start_captured() {
     struct TestActor;
 
@@ -77,7 +84,10 @@ async fn test_error_on_start_captured() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_stop_higher_priority_over_messages() {
     let message_counter = Arc::new(AtomicU8::new(0u8));
 
@@ -156,7 +166,10 @@ async fn test_stop_higher_priority_over_messages() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_kill_terminates_work() {
     struct TestActor;
 
@@ -202,7 +215,10 @@ async fn test_kill_terminates_work() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_stop_does_not_terminate_async_work() {
     struct TestActor;
 
@@ -257,7 +273,10 @@ async fn test_stop_does_not_terminate_async_work() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_kill_terminates_supervision_work() {
     struct TestActor;
 
@@ -305,7 +324,10 @@ async fn test_kill_terminates_supervision_work() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_sending_message_to_invalid_actor_type() {
     struct TestActor1;
     struct TestMessage1;
@@ -363,7 +385,10 @@ async fn test_sending_message_to_invalid_actor_type() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_sending_message_to_dead_actor() {
     #[derive(Default)]
     struct TestActor;
@@ -400,7 +425,10 @@ async fn test_sending_message_to_dead_actor() {
 
 #[cfg(feature = "cluster")]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_serialized_cast() {
     use crate::message::{BoxedDowncastErr, SerializedMessage};
     use crate::Message;
@@ -515,7 +543,10 @@ where
 
 #[cfg(feature = "cluster")]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_serialized_rpc() {
     use crate::message::{BoxedDowncastErr, SerializedMessage};
     use crate::{Message, RpcReplyPort};
@@ -625,7 +656,10 @@ async fn test_serialized_rpc() {
 
 #[cfg(feature = "cluster")]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_remote_actor() {
     use crate::message::{BoxedDowncastErr, SerializedMessage};
     use crate::{ActorId, ActorRuntime, Message};
@@ -734,7 +768,10 @@ async fn test_remote_actor() {
 
 #[cfg(feature = "cluster")]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn spawning_local_actor_as_remote_fails() {
     use crate::ActorProcessingErr;
 
@@ -791,7 +828,10 @@ async fn spawning_local_actor_as_remote_fails() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn instant_spawns() {
     let counter = Arc::new(AtomicU8::new(0));
 
@@ -852,7 +892,10 @@ async fn instant_spawns() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn stop_and_wait() {
     struct SlowActor;
     #[cfg_attr(feature = "async-trait", crate::async_trait)]
@@ -881,7 +924,10 @@ async fn stop_and_wait() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn kill_and_wait() {
     struct SlowActor;
     #[cfg_attr(feature = "async-trait", crate::async_trait)]
@@ -910,7 +956,10 @@ async fn kill_and_wait() {
 }
 
 #[test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 fn test_err_map() {
     let err: RactorErr<i32> = RactorErr::Messaging(MessagingErr::SendErr(123));
 
@@ -970,7 +1019,10 @@ fn returns_actor_references() {
 
 /// https://github.com/slawlor/ractor/issues/240
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn actor_failing_in_spawn_err_doesnt_poison_registries() {
     #[derive(Default)]
     struct Test;
@@ -1016,7 +1068,10 @@ async fn actor_failing_in_spawn_err_doesnt_poison_registries() {
 
 /// https://github.com/slawlor/ractor/issues/254
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn actor_post_stop_executed_before_stop_and_wait_returns() {
     struct TestActor {
         signal: Arc<AtomicU8>,
@@ -1069,7 +1124,10 @@ async fn actor_post_stop_executed_before_stop_and_wait_returns() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn actor_drain_messages() {
     struct TestActor {
         signal: Arc<AtomicU32>,
@@ -1132,7 +1190,10 @@ async fn actor_drain_messages() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn runtime_message_typing() {
     struct TestActor;
 
@@ -1165,7 +1226,10 @@ async fn runtime_message_typing() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn wait_for_death() {
     struct TestActor;
 
@@ -1206,7 +1270,10 @@ async fn wait_for_death() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn derived_actor_ref() {
     let result_counter = Arc::new(AtomicU32::new(0));
 
diff --git a/ractor/src/actor/tests/supervisor.rs b/ractor/src/actor/tests/supervisor.rs
index 246f8f8..8894aa8 100644
--- a/ractor/src/actor/tests/supervisor.rs
+++ b/ractor/src/actor/tests/supervisor.rs
@@ -15,7 +15,11 @@ use crate::{concurrency::Duration, message::BoxedDowncastErr, periodic_check, Ac
 use crate::{Actor, ActorCell, ActorRef, ActorStatus, SupervisionEvent};
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 async fn test_supervision_panic_in_post_startup() {
     struct Child;
     struct Supervisor {
@@ -105,7 +109,10 @@ async fn test_supervision_panic_in_post_startup() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_supervision_error_in_post_startup() {
     struct Child;
     struct Supervisor {
@@ -192,7 +199,11 @@ async fn test_supervision_error_in_post_startup() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 async fn test_supervision_panic_in_handle() {
     struct Child;
     struct Supervisor {
@@ -288,7 +299,10 @@ async fn test_supervision_panic_in_handle() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_supervision_error_in_handle() {
     struct Child;
     struct Supervisor {
@@ -384,7 +398,11 @@ async fn test_supervision_error_in_handle() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 async fn test_supervision_panic_in_post_stop() {
     struct Child;
     struct Supervisor {
@@ -464,7 +482,10 @@ async fn test_supervision_panic_in_post_stop() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_supervision_error_in_post_stop() {
     struct Child;
     struct Supervisor {
@@ -546,7 +567,11 @@ async fn test_supervision_error_in_post_stop() {
 /// Test that a panic in the supervisor's handling propagates to
 /// the supervisor's supervisor
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 async fn test_supervision_panic_in_supervisor_handle() {
     struct Child;
     struct Midpoint;
@@ -687,7 +712,10 @@ async fn test_supervision_panic_in_supervisor_handle() {
 /// Test that a panic in the supervisor's handling propagates to
 /// the supervisor's supervisor
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_supervision_error_in_supervisor_handle() {
     struct Child;
     struct Midpoint;
@@ -826,7 +854,10 @@ async fn test_supervision_error_in_supervisor_handle() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_killing_a_supervisor_terminates_children() {
     struct Child;
     struct Supervisor;
@@ -899,7 +930,10 @@ async fn test_killing_a_supervisor_terminates_children() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn instant_supervised_spawns() {
     let counter = Arc::new(AtomicU8::new(0));
 
@@ -1001,7 +1035,10 @@ async fn instant_supervised_spawns() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_supervisor_captures_dead_childs_state() {
     struct Child;
     struct Supervisor {
@@ -1104,7 +1141,10 @@ async fn test_supervisor_captures_dead_childs_state() {
 // 1. terminate_children_after()
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_supervisor_double_link() {
     struct Who;
 
@@ -1146,7 +1186,12 @@ async fn test_supervisor_double_link() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
+// Ignored on wasm32-unknown-unknown, since panic can't be catched on this platform
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 async fn test_supervisor_exit_doesnt_call_child_post_stop() {
     struct Child {
         post_stop_calls: Arc<AtomicU8>,
@@ -1230,7 +1275,10 @@ async fn test_supervisor_exit_doesnt_call_child_post_stop() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn stopping_children_and_wait_during_parent_shutdown() {
     struct Child {
         post_stop_calls: Arc<AtomicU8>,
@@ -1312,7 +1360,10 @@ async fn stopping_children_and_wait_during_parent_shutdown() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn stopping_children_will_shutdown_parent_too() {
     struct Child {
         post_stop_calls: Arc<AtomicU8>,
@@ -1395,7 +1446,10 @@ async fn stopping_children_will_shutdown_parent_too() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn draining_children_and_wait_during_parent_shutdown() {
     struct Child {
         post_stop_calls: Arc<AtomicU8>,
@@ -1477,7 +1531,10 @@ async fn draining_children_and_wait_during_parent_shutdown() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn draining_children_will_shutdown_parent_too() {
     struct Child {
         post_stop_calls: Arc<AtomicU8>,
@@ -1563,7 +1620,10 @@ async fn draining_children_will_shutdown_parent_too() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 #[cfg(feature = "monitors")]
 async fn test_simple_monitor() {
     struct Peer;
diff --git a/ractor/src/common_test.rs b/ractor/src/common_test.rs
index 82970f3..52ceaa5 100644
--- a/ractor/src/common_test.rs
+++ b/ractor/src/common_test.rs
@@ -5,7 +5,7 @@
 
 // TODO #124 (slawlor): Redesign this without usage of core time primatives (i.e.
 // use concurrency instants)
-#[cfg(not(target_arch = "wasm32"))]
+
 use std::future::Future;
 
 use crate::concurrency::sleep;
diff --git a/ractor/src/factory/tests/basic.rs b/ractor/src/factory/tests/basic.rs
index 07c5e53..c0c23b3 100644
--- a/ractor/src/factory/tests/basic.rs
+++ b/ractor/src/factory/tests/basic.rs
@@ -138,7 +138,10 @@ impl WorkerBuilder<TestWorker, ()> for InsanelySlowWorkerBuilder {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_dispatch_key_persistent() {
     let worker_counters: [_; NUM_TEST_WORKERS] = [
         Arc::new(AtomicU16::new(0)),
@@ -210,7 +213,10 @@ async fn test_dispatch_key_persistent() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_dispatch_queuer() {
     let worker_counters: [_; NUM_TEST_WORKERS] = [
         Arc::new(AtomicU16::new(0)),
@@ -285,7 +291,10 @@ async fn test_dispatch_queuer() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_dispatch_round_robin() {
     let worker_counters: [_; NUM_TEST_WORKERS] = [
         Arc::new(AtomicU16::new(0)),
@@ -358,7 +367,10 @@ async fn test_dispatch_round_robin() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_dispatch_custom_hashing() {
     struct MyHasher<TKey>
     where
@@ -443,7 +455,10 @@ async fn test_dispatch_custom_hashing() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_dispatch_sticky_queueing() {
     let worker_counters: [_; NUM_TEST_WORKERS] = [
         Arc::new(AtomicU16::new(0)),
@@ -518,7 +533,10 @@ async fn test_dispatch_sticky_queueing() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_discarding_old_records_on_queuer() {
     let worker_counters: [_; NUM_TEST_WORKERS] = [
         Arc::new(AtomicU16::new(0)),
@@ -659,7 +677,10 @@ impl Actor for StuckWorker {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_stuck_workers() {
     let worker_counters: [_; NUM_TEST_WORKERS] = [
         Arc::new(AtomicU16::new(0)),
@@ -752,7 +773,6 @@ async fn test_stuck_workers() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
 async fn test_discarding_new_records_on_queuer() {
     let worker_counters: [_; NUM_TEST_WORKERS] = [
         Arc::new(AtomicU16::new(0)),
diff --git a/ractor/src/factory/tests/draining_requests.rs b/ractor/src/factory/tests/draining_requests.rs
index e0d90b6..58a8020 100644
--- a/ractor/src/factory/tests/draining_requests.rs
+++ b/ractor/src/factory/tests/draining_requests.rs
@@ -105,7 +105,10 @@ impl WorkerBuilder<TestWorker, ()> for SlowWorkerBuilder {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_request_draining() {
     let counter = Arc::new(AtomicU16::new(0));
 
diff --git a/ractor/src/factory/tests/dynamic_discarding.rs b/ractor/src/factory/tests/dynamic_discarding.rs
index 26661ec..9832684 100644
--- a/ractor/src/factory/tests/dynamic_discarding.rs
+++ b/ractor/src/factory/tests/dynamic_discarding.rs
@@ -134,7 +134,10 @@ impl DynamicDiscardController for DiscardController {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_dynamic_dispatch_basic() {
     // let handle = tokio::runtime::Handle::current();
     // Setup
diff --git a/ractor/src/factory/tests/dynamic_pool.rs b/ractor/src/factory/tests/dynamic_pool.rs
index 688ad5d..5fc7365 100644
--- a/ractor/src/factory/tests/dynamic_pool.rs
+++ b/ractor/src/factory/tests/dynamic_pool.rs
@@ -93,7 +93,10 @@ impl WorkerBuilder<TestWorker, ()> for TestWorkerBuilder {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_worker_pool_adjustment_manual() {
     // Setup
 
@@ -184,7 +187,10 @@ async fn test_worker_pool_adjustment_manual() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_worker_pool_adjustment_automatic() {
     // Setup
 
diff --git a/ractor/src/factory/tests/dynamic_settings.rs b/ractor/src/factory/tests/dynamic_settings.rs
index 7af003c..59b7fbe 100644
--- a/ractor/src/factory/tests/dynamic_settings.rs
+++ b/ractor/src/factory/tests/dynamic_settings.rs
@@ -55,7 +55,10 @@ impl WorkerBuilder<TestWorker, ()> for TestWorkerBuilder {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_dynamic_settings() {
     let counter_one = Arc::new(AtomicU8::new(0));
     let counter_two = Arc::new(AtomicU8::new(0));
diff --git a/ractor/src/factory/tests/lifecycle.rs b/ractor/src/factory/tests/lifecycle.rs
index 61fb31b..616680b 100644
--- a/ractor/src/factory/tests/lifecycle.rs
+++ b/ractor/src/factory/tests/lifecycle.rs
@@ -147,7 +147,10 @@ impl WorkerBuilder<TestWorker, ()> for TestWorkerBuilder {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_lifecycle_hooks() {
     let hooks = AtomicHooks {
         state: Arc::new(AtomicU8::new(0)),
diff --git a/ractor/src/factory/tests/mod.rs b/ractor/src/factory/tests/mod.rs
index a57650b..b1dc676 100644
--- a/ractor/src/factory/tests/mod.rs
+++ b/ractor/src/factory/tests/mod.rs
@@ -13,4 +13,5 @@ mod dynamic_settings;
 mod lifecycle;
 mod priority_queueing;
 mod ratelim;
+#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
 mod worker_lifecycle;
diff --git a/ractor/src/factory/tests/priority_queueing.rs b/ractor/src/factory/tests/priority_queueing.rs
index 5abe90b..c1ae0b2 100644
--- a/ractor/src/factory/tests/priority_queueing.rs
+++ b/ractor/src/factory/tests/priority_queueing.rs
@@ -116,7 +116,10 @@ impl WorkerBuilder<TestWorker, ()> for TestWorkerBuilder {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_basic_priority_queueing() {
     // Setup
     // a counter for each priority
diff --git a/ractor/src/factory/tests/ratelim.rs b/ractor/src/factory/tests/ratelim.rs
index b5ccc86..b5070c8 100644
--- a/ractor/src/factory/tests/ratelim.rs
+++ b/ractor/src/factory/tests/ratelim.rs
@@ -160,31 +160,46 @@ async fn test_factory_rate_limiting_common<TRouter: Router<(), ()>>(router: TRou
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_factory_rate_limiting_queuer() {
     test_factory_rate_limiting_common::<QueuerRouting<(), ()>>(Default::default()).await
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_factory_rate_limiting_sticky_queuer() {
     test_factory_rate_limiting_common::<StickyQueuerRouting<(), ()>>(Default::default()).await
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_factory_rate_limiting_key_persistent() {
     test_factory_rate_limiting_common::<KeyPersistentRouting<(), ()>>(Default::default()).await
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_factory_rate_limiting_round_robin() {
     test_factory_rate_limiting_common::<RoundRobinRouting<(), ()>>(Default::default()).await
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_factory_rate_limiting_custom_hash() {
     struct MyHasher;
 
@@ -200,7 +215,10 @@ async fn test_factory_rate_limiting_custom_hash() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_leaky_bucket_rate_limiting() {
     // Setup
 
diff --git a/ractor/src/factory/tests/worker_lifecycle.rs b/ractor/src/factory/tests/worker_lifecycle.rs
index 4c59c81..57bd7c7 100644
--- a/ractor/src/factory/tests/worker_lifecycle.rs
+++ b/ractor/src/factory/tests/worker_lifecycle.rs
@@ -98,7 +98,10 @@ impl WorkerBuilder<MyWorker, ()> for MyWorkerBuilder {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_worker_death_restarts_and_gets_next_message() {
     let counter = Arc::new(AtomicU16::new(0));
     let worker_builder = MyWorkerBuilder {
@@ -257,7 +260,10 @@ where
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_factory_can_silent_retry() {
     let num_retries = Arc::new(AtomicU8::new(0));
 
diff --git a/ractor/src/pg/tests.rs b/ractor/src/pg/tests.rs
index 5afb621..de3459f 100644
--- a/ractor/src/pg/tests.rs
+++ b/ractor/src/pg/tests.rs
@@ -34,7 +34,10 @@ impl Actor for TestActor {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_basic_group_in_default_scope() {
     let (actor, handle) = Actor::spawn(None, TestActor, ())
         .await
@@ -55,7 +58,10 @@ async fn test_basic_group_in_default_scope() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_basic_group_in_named_scope() {
     let (actor, handle) = Actor::spawn(None, TestActor, ())
         .await
@@ -78,7 +84,10 @@ async fn test_basic_group_in_named_scope() {
 #[named]
 #[serial]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_which_scopes_and_groups() {
     let (actor, handle) = Actor::spawn(None, TestActor, ())
         .await
@@ -116,7 +125,10 @@ async fn test_which_scopes_and_groups() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_multiple_members_in_group() {
     let group = function_name!().to_string();
 
@@ -153,7 +165,10 @@ async fn test_multiple_members_in_group() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_multiple_members_in_scoped_group() {
     let scope = function_name!().to_string();
     let group = function_name!().to_string();
@@ -192,7 +207,10 @@ async fn test_multiple_members_in_scoped_group() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_which_scoped_groups() {
     let scope = function_name!().to_string();
     let group = function_name!().to_string();
@@ -231,7 +249,10 @@ async fn test_which_scoped_groups() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_multiple_groups() {
     let group_a = concat!(function_name!(), "_a").to_string();
     let group_b = concat!(function_name!(), "_b").to_string();
@@ -276,7 +297,10 @@ async fn test_multiple_groups() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_multiple_groups_in_multiple_scopes() {
     let scope_a = concat!(function_name!(), "_b").to_string();
     let scope_b = concat!(function_name!(), "_b").to_string();
@@ -342,7 +366,10 @@ async fn test_multiple_groups_in_multiple_scopes() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_actor_leaves_pg_group_on_shutdown() {
     let (actor, handle) = Actor::spawn(None, TestActor, ())
         .await
@@ -367,7 +394,10 @@ async fn test_actor_leaves_pg_group_on_shutdown() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_actor_leaves_scope_on_shupdown() {
     let (actor, handle) = Actor::spawn(None, TestActor, ())
         .await
@@ -393,7 +423,10 @@ async fn test_actor_leaves_scope_on_shupdown() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_actor_leaves_pg_group_manually() {
     let group = function_name!().to_string();
 
@@ -433,7 +466,10 @@ async fn test_actor_leaves_pg_group_manually() {
 
 #[named]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_actor_leaves_scope_manually() {
     let scope = function_name!().to_string();
     let group = function_name!().to_string();
@@ -483,7 +519,10 @@ async fn test_actor_leaves_scope_manually() {
 #[named]
 #[serial]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_pg_monitoring() {
     let group = function_name!().to_string();
 
@@ -589,7 +628,10 @@ async fn test_pg_monitoring() {
 #[named]
 #[serial]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_scope_monitoring() {
     let scope = function_name!().to_string();
     let group = function_name!().to_string();
@@ -730,7 +772,10 @@ async fn test_scope_monitoring() {
 #[named]
 #[cfg(feature = "cluster")]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn local_vs_remote_pg_members() {
     use crate::ActorRuntime;
 
@@ -800,7 +845,10 @@ async fn local_vs_remote_pg_members() {
 #[named]
 #[cfg(feature = "cluster")]
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn local_vs_remote_pg_members_in_named_scopes() {
     use crate::ActorRuntime;
 
diff --git a/ractor/src/port/output/tests.rs b/ractor/src/port/output/tests.rs
index ec4c1b2..d59f26d 100644
--- a/ractor/src/port/output/tests.rs
+++ b/ractor/src/port/output/tests.rs
@@ -15,7 +15,10 @@ use crate::{Actor, ActorRef};
 use super::*;
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_single_forward() {
     struct TestActor;
     enum TestActorMessage {
@@ -79,7 +82,10 @@ async fn test_single_forward() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_50_receivers() {
     struct TestActor;
     enum TestActorMessage {
@@ -159,7 +165,10 @@ async fn test_50_receivers() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_delivery() {
     struct TestActor;
     enum TestActorMessage {
@@ -395,7 +404,10 @@ mod output_port_subscriber_tests {
     }
 
     #[crate::concurrency::test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     async fn test_output_port_subscriber() {
         let (number_publisher_ref, number_publisher_handler) =
             Actor::spawn(None, NumberPublisher, ()).await.unwrap();
diff --git a/ractor/src/registry/tests.rs b/ractor/src/registry/tests.rs
index 5a5ae86..a1ee674 100644
--- a/ractor/src/registry/tests.rs
+++ b/ractor/src/registry/tests.rs
@@ -10,7 +10,10 @@ use crate::concurrency::Duration;
 use crate::{Actor, ActorProcessingErr, SpawnErr};
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_basic_registation() {
     #[derive(Default)]
     struct EmptyActor;
@@ -46,7 +49,10 @@ async fn test_basic_registation() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_duplicate_registration() {
     struct EmptyActor;
 
@@ -94,7 +100,10 @@ async fn test_duplicate_registration() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_actor_registry_unenrollment() {
     struct EmptyActor;
 
@@ -163,7 +172,10 @@ mod pid_registry_tests {
     }
 
     #[crate::concurrency::test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     async fn try_enroll_remote_actor() {
         struct EmptyActor;
         #[cfg_attr(feature = "async-trait", crate::async_trait)]
@@ -209,7 +221,10 @@ mod pid_registry_tests {
     }
 
     #[crate::concurrency::test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     async fn test_basic_registation() {
         struct EmptyActor;
 
@@ -243,7 +258,10 @@ mod pid_registry_tests {
     }
 
     #[crate::concurrency::test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     async fn test_actor_registry_unenrollment() {
         struct EmptyActor;
 
@@ -285,7 +303,10 @@ mod pid_registry_tests {
     }
 
     #[crate::concurrency::test]
-    #[tracing_test::traced_test]
+    #[cfg_attr(
+        not(all(target_arch = "wasm32", target_os = "unknown")),
+        tracing_test::traced_test
+    )]
     async fn test_pid_lifecycle_monitoring() {
         let counter = Arc::new(DashMap::new());
 
diff --git a/ractor/src/rpc/tests.rs b/ractor/src/rpc/tests.rs
index d072a58..3aff8dd 100644
--- a/ractor/src/rpc/tests.rs
+++ b/ractor/src/rpc/tests.rs
@@ -16,7 +16,10 @@ use crate::{cast, forward, Actor, ActorRef};
 use crate::{rpc, ActorProcessingErr};
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_rpc_cast() {
     let counter = Arc::new(AtomicU8::new(0u8));
 
@@ -75,7 +78,10 @@ async fn test_rpc_cast() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_rpc_call() {
     struct TestActor;
     enum MessageFormat {
@@ -169,7 +175,10 @@ async fn test_rpc_call() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_rpc_call_forwarding() {
     struct Worker;
 
@@ -326,7 +335,10 @@ async fn test_rpc_call_forwarding() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_multi_call() {
     struct TestActor;
     enum MessageFormat {
diff --git a/ractor/src/tests.rs b/ractor/src/tests.rs
index 06c919b..801e785 100644
--- a/ractor/src/tests.rs
+++ b/ractor/src/tests.rs
@@ -12,8 +12,19 @@ use crate::ActorProcessingErr;
 use crate::ActorRef;
 use crate::RactorErr;
 
+// It was used by examples
+use ractor_example_entry_proc as _;
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+use getrandom as _;
+
+#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
+wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
 #[test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 fn test_error_conversions() {
     let messaging = crate::MessagingErr::<()>::InvalidActorType;
     let ractor_err = RactorErr::<()>::from(crate::MessagingErr::InvalidActorType);
@@ -36,7 +47,10 @@ fn test_error_conversions() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_error_message_extraction() {
     struct TestActor;
 
diff --git a/ractor/src/time/tests.rs b/ractor/src/time/tests.rs
index 75e46a5..b9d020b 100644
--- a/ractor/src/time/tests.rs
+++ b/ractor/src/time/tests.rs
@@ -15,7 +15,10 @@ use crate::{common_test::periodic_check, concurrency::Duration, ActorProcessingE
 use crate::{Actor, ActorRef};
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_intervals() {
     let counter = Arc::new(AtomicU8::new(0u8));
 
@@ -79,7 +82,10 @@ async fn test_intervals() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_send_after() {
     let counter = Arc::new(AtomicU8::new(0u8));
 
@@ -143,7 +149,10 @@ async fn test_send_after() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_exit_after() {
     struct TestActor;
 
@@ -175,7 +184,10 @@ async fn test_exit_after() {
 }
 
 #[crate::concurrency::test]
-#[tracing_test::traced_test]
+#[cfg_attr(
+    not(all(target_arch = "wasm32", target_os = "unknown")),
+    tracing_test::traced_test
+)]
 async fn test_kill_after() {
     struct TestActor;
 
diff --git a/ractor_cluster_integration_tests/src/tests/encryption.rs b/ractor_cluster_integration_tests/src/tests/encryption.rs
index 8a8b7a9..d18221a 100644
--- a/ractor_cluster_integration_tests/src/tests/encryption.rs
+++ b/ractor_cluster_integration_tests/src/tests/encryption.rs
@@ -66,13 +66,7 @@ pub async fn test(config: EncryptionConfig) -> i32 {
 
     let ca_path = PathBuf::from("test-ca/rsa-2048/ca.cert");
     let mut ca_pem = BufReader::new(File::open(ca_path).expect("Failed to load CA certificate"));
-    let ca_certs = rustls_pemfile::certs(&mut ca_pem).filter_map(|cert| {
-        if let Ok(c) = cert {
-            Some(c)
-        } else {
-            None
-        }
-    });
+    let ca_certs = rustls_pemfile::certs(&mut ca_pem).filter_map(|cert| cert.ok());
 
     let mut root_cert_store = tokio_rustls::rustls::RootCertStore::empty();
     let trust_anchors = ca_certs.map(|cert| {
diff --git a/unit-tests-for-wasm32-unknown-unknown.md b/unit-tests-for-wasm32-unknown-unknown.md
new file mode 100644
index 0000000..6d80839
--- /dev/null
+++ b/unit-tests-for-wasm32-unknown-unknown.md
@@ -0,0 +1,128 @@
+# Steps to run unit tests for target `wasm32-unknown-unknown`
+
+`ractor` is supposed to support wasm32-unknown-unknown in browser, but unit-tests can't be executed in CI due to some known issues (see https://github.com/rustwasm/wasm-pack/issues/1424 ). Here are steps to run unit-tests manually.
+
+## Install dependencies
+
+```sh
+rustup target add wasm32-unknown-unknown
+cargo install wasm-pack
+```
+
+`wasm-pack` is a bundler and test executor for wasm targets.
+
+## Run unit tests in browser
+
+### Build unit-tests and start web server
+
+```sh
+wasm-pack test --firefox ./ractor
+```
+### Wait for unit-tests to be built and server started
+
+```console
+Interactive browsers tests are now available at http://127.0.0.1:8000
+
+Note that interactive mode is enabled because `NO_HEADLESS`
+is specified in the environment of this process. Once you're
+done with testing you'll need to kill this server with
+Ctrl-C.
+```
+
+Now access `http://127.0.0.1:8000` in browser.
+
+### Monitor test progress in browser
+
+```console
+running 84 tests
+test factory::queues::tests::test_priority_queueing ... ok
+test factory::queues::tests::test_basic_queueing ... ok
+test factory::tests::dynamic_discarding::test_dynamic_dispatch_basic ... ok
+test port::output::tests::output_port_subscriber_tests::test_output_port_subscriber ... ok
+test tests::test_platform_sleep_works ... ok
+test tests::test_error_message_extraction ... ok
+test factory::ratelim::tests::test_leaky_bucket_max ... ok
+test factory::ratelim::tests::test_basic_leaky_bucket ... ok
+test time::tests::test_kill_after ... ok
+test time::tests::test_exit_after ... ok
+test time::tests::test_send_after ... ok
+test time::tests::test_intervals ... ok
+test actor::tests::supervisor::draining_children_will_shutdown_parent_too ... ok
+test actor::tests::supervisor::draining_children_and_wait_during_parent_shutdown ... ok
+test actor::tests::supervisor::stopping_children_will_shutdown_parent_too ... ok
+test actor::tests::supervisor::stopping_children_and_wait_during_parent_shutdown ... ok
+test actor::tests::supervisor::test_supervisor_double_link ... ok
+test actor::tests::supervisor::test_supervisor_captures_dead_childs_state ... ok
+test actor::tests::supervisor::instant_supervised_spawns ... ok
+test actor::tests::supervisor::test_killing_a_supervisor_terminates_children ... ok
+test actor::tests::supervisor::test_supervision_error_in_supervisor_handle ... ok
+test actor::tests::supervisor::test_supervision_error_in_post_stop ... ok
+test actor::tests::supervisor::test_supervision_error_in_handle ... ok
+test actor::tests::supervisor::test_supervision_error_in_post_startup ... ok
+test factory::tests::dynamic_settings::test_dynamic_settings ... ok
+test pg::tests::test_scope_monitoring ... ok
+test pg::tests::test_pg_monitoring ... ok
+test pg::tests::test_actor_leaves_scope_manually ... ok
+test pg::tests::test_actor_leaves_pg_group_manually ... ok
+test pg::tests::test_actor_leaves_scope_on_shupdown ... ok
+test pg::tests::test_actor_leaves_pg_group_on_shutdown ... ok
+test pg::tests::test_multiple_groups_in_multiple_scopes ... ok
+test pg::tests::test_multiple_groups ... ok
+test pg::tests::test_which_scoped_groups ... ok
+test pg::tests::test_multiple_members_in_scoped_group ... ok
+test pg::tests::test_multiple_members_in_group ... ok
+test pg::tests::test_which_scopes_and_groups ... ok
+test pg::tests::test_basic_group_in_named_scope ... ok
+test pg::tests::test_basic_group_in_default_scope ... ok
+test factory::tests::lifecycle::test_lifecycle_hooks ... ok
+test factory::tests::ratelim::test_leaky_bucket_rate_limiting ... ok
+test factory::tests::ratelim::test_factory_rate_limiting_custom_hash ... ok
+test factory::tests::ratelim::test_factory_rate_limiting_round_robin ... ok
+test factory::tests::ratelim::test_factory_rate_limiting_key_persistent ... ok
+test factory::tests::ratelim::test_factory_rate_limiting_sticky_queuer ... ok
+test factory::tests::ratelim::test_factory_rate_limiting_queuer ... ok
+test registry::tests::test_actor_registry_unenrollment ... ok
+test registry::tests::test_duplicate_registration ... ok
+test registry::tests::test_basic_registation ... ok
+test factory::tests::draining_requests::test_request_draining ... ok
+test rpc::tests::test_multi_call ... ok
+test rpc::tests::test_rpc_call_forwarding ... ok
+test rpc::tests::test_rpc_call ... ok
+test rpc::tests::test_rpc_cast ... ok
+test port::output::tests::test_delivery ... ok
+test port::output::tests::test_50_receivers ... ok
+test port::output::tests::test_single_forward ... ok
+test factory::tests::priority_queueing::test_basic_priority_queueing ... ok
+test factory::tests::basic::test_discarding_new_records_on_queuer ... ok
+test factory::tests::basic::test_stuck_workers ... ok
+test factory::tests::basic::test_discarding_old_records_on_queuer ... ok
+test factory::tests::basic::test_dispatch_sticky_queueing ... ok
+test factory::tests::basic::test_dispatch_custom_hashing ... ok
+test factory::tests::basic::test_dispatch_round_robin ... ok
+test factory::tests::basic::test_dispatch_queuer ... ok
+test factory::tests::basic::test_dispatch_key_persistent ... ok
+test actor::tests::derived_actor_ref ... ok
+test actor::tests::wait_for_death ... ok
+test actor::tests::runtime_message_typing ... ok
+test actor::tests::actor_drain_messages ... ok
+test actor::tests::actor_post_stop_executed_before_stop_and_wait_returns ... ok
+test actor::tests::actor_failing_in_spawn_err_doesnt_poison_registries ... ok
+test actor::tests::kill_and_wait ... ok
+test actor::tests::stop_and_wait ... ok
+test actor::tests::instant_spawns ... ok
+test actor::tests::test_sending_message_to_dead_actor ... ok
+test actor::tests::test_sending_message_to_invalid_actor_type ... ok
+test actor::tests::test_kill_terminates_supervision_work ... ok
+test actor::tests::test_stop_does_not_terminate_async_work ... ok
+test actor::tests::test_kill_terminates_work ... ok
+test actor::tests::test_stop_higher_priority_over_messages ... ok
+test actor::tests::test_error_on_start_captured ... ok
+test factory::tests::dynamic_pool::test_worker_pool_adjustment_automatic ... ok
+test factory::tests::dynamic_pool::test_worker_pool_adjustment_manual ... ok
+
+test result: ok. 84 passed; 0 failed; 0 ignored; 0 filtered out; finished in 165.20s
+```
+
+### Clean up
+
+Press `Ctrl + C` to shutdown the web server started by `wasm-pack`