diff --git a/client/Cargo.toml b/client/Cargo.toml
index a0574e8f2b..26e3795775 100644
--- a/client/Cargo.toml
+++ b/client/Cargo.toml
@@ -20,6 +20,7 @@ futures = "0.3.9"
jsonrpsee = { git = "https://github.com/paritytech/jsonrpsee/", branch = "extract-async-client", features = ["client"] }
log = "0.4.13"
thiserror = "1.0.23"
+serde_json = "1"
sc-client-db = { git = "https://github.com/paritytech/substrate.git", branch = "master" }
sp-keyring = { git = "https://github.com/paritytech/substrate.git", branch = "master" }
@@ -38,3 +39,5 @@ async-std = { version = "1.8.0", features = ["attributes"] }
env_logger = "0.8.2"
node-cli = { git = "https://github.com/paritytech/substrate.git", branch = "master", default-features = false }
tempdir = "0.3.7"
+subxt = { path = ".." }
+test-runtime = { path = "../test-runtime" }
diff --git a/client/src/lib.rs b/client/src/lib.rs
index 3ea925662d..d3d82fb8f0 100644
--- a/client/src/lib.rs
+++ b/client/src/lib.rs
@@ -14,8 +14,13 @@
// You should have received a copy of the GNU General Public License
// along with subxt. If not, see .
+//! Client for embedding substrate nodes.
+
#![deny(missing_docs)]
+#[cfg(test)]
+mod tests;
+
use async_std::task;
use futures::{
channel::mpsc,
diff --git a/client/src/tests.rs b/client/src/tests.rs
new file mode 100644
index 0000000000..e7eabc311c
--- /dev/null
+++ b/client/src/tests.rs
@@ -0,0 +1,79 @@
+use node_cli::service::NewFullBase;
+use sp_keyring::AccountKeyring;
+use subxt::{ClientBuilder, PairSigner};
+use test_runtime::node_runtime::{self, system, DefaultConfig}
+use crate::{
+ DatabaseSource,
+ KeystoreConfig,
+ Role,
+ SubxtClient,
+ SubxtClientConfig,
+ WasmExecutionMethod,
+};
+use tempdir::TempDir;
+
+#[async_std::test]
+pub async fn test_embedded_client() {
+ let tmp = TempDir::new("subxt-").expect("failed to create tempdir");
+ let config = SubxtClientConfig {
+ impl_name: "full-client",
+ impl_version: "0.0.1",
+ author: "",
+ copyright_start_year: 2020,
+ db: DatabaseSource::RocksDb {
+ path: tmp.path().join("db"),
+ cache_size: 16,
+ },
+ keystore: KeystoreConfig::Path {
+ path: tmp.path().join("keystore"),
+ password: None,
+ },
+ chain_spec: node_cli::chain_spec::development_config(),
+ role: Role::Authority(AccountKeyring::Alice),
+ telemetry: None,
+ wasm_method: WasmExecutionMethod::Compiled,
+ tokio_handle: tokio::runtime::Handle::current(),
+ };
+
+ let NewFullBase {
+ task_manager,
+ rpc_handlers,
+ ..
+ } = node_cli::service::new_full_base(config.into_service_config(), |_, _| ())
+ .unwrap();
+
+ let client = SubxtClient::new(task_manager, rpc_handlers);
+
+ let ext_client = ClientBuilder::new()
+ .set_client(client)
+ .build::()
+ .await
+ .unwrap();
+ let api: node_runtime::RuntimeApi =
+ ext_client.clone().to_runtime_api();
+
+ // verify that we can read storage
+ api.storage()
+ .system()
+ .account(AccountKeyring::Alice.to_account_id().into(), None)
+ .await
+ .unwrap();
+
+ let alice = PairSigner::::new(AccountKeyring::Alice.pair());
+ let bob_address = AccountKeyring::Bob.to_account_id().into();
+
+ // verify that we can call dispatchable functions
+ let result = api
+ .tx()
+ .balances()
+ .transfer(bob_address, 100_000_000_000_000_000)
+ .sign_and_submit_then_watch(&alice)
+ .await
+ .unwrap();
+
+ // verify that we receive events
+ let success = result
+ .find_event::()
+ .unwrap();
+ assert!(success.is_some());
+}