diff --git a/end2end-tests/Cargo.toml b/end2end-tests/Cargo.toml
index a59b3faaeb994da0125205b474d8cd6abefb53f9..7413edc872896d482c6c1947e0057d976e3dd895 100644
--- a/end2end-tests/Cargo.toml
+++ b/end2end-tests/Cargo.toml
@@ -9,24 +9,24 @@ repository = 'https://git.duniter.org/nodes/rust/duniter-v2s'
 version = '3.0.0'
 
 [dev-dependencies]
-anyhow = "1.0"
-async-trait = "0.1.74"
-clap = { version = "3.2.23", features = ["derive", "cargo"] } # end2end cli refactoring need to upgrade to 4
-ctrlc = "3.2.2"
-cucumber = "0.11"
+anyhow = "1.0.79"
+clap = { version = "4.4.18", features = ["derive", "cargo"] }
+ctrlc = "3.4.2"
+cucumber = { version = "0.20.2", features = ["macros"] }
 distance-oracle = { path = "../distance-oracle", default_features = false }
-env_logger = "0.9.0"
+env_logger = "0.11.1"
 hex = "0.4.3"
-notify = "4.0"
-parity-scale-codec = "3.4.0"
+notify = "6.1.1"
+notify-debouncer-mini = "0.4.1"
+parity-scale-codec = "3.6.9"
 portpicker = "0.1.1"
-serde_json = "1.0.96"
+serde_json = "1.0.113"
 sp-core = { git = "https://github.com/duniter/duniter-polkadot-sdk", branch = "duniter-substrate-v1.6.0", default-features = false }
 sp-core-hashing = { git = "https://github.com/duniter/duniter-polkadot-sdk", branch = "duniter-substrate-v1.6.0", default-features = false }
 sp-runtime = { git = "https://github.com/duniter/duniter-polkadot-sdk", branch = "duniter-substrate-v1.6.0" }
 sp-keyring = { git = "https://github.com/duniter/duniter-polkadot-sdk", branch = "duniter-substrate-v1.6.0" }
 subxt = { git = 'https://github.com/duniter/subxt', branch = 'subxt-v0.34.0-duniter-substrate-v1.6.0', default-features = false, features = ["substrate-compat", "native", "jsonrpsee"] }
-tokio = { version = "1.28", features = ["macros", "time", "rt-multi-thread"], default-features = false }
+tokio = { version = "1.36.0", features = ["macros", "time", "rt-multi-thread"], default-features = false }
 
 [[test]]
 name = "cucumber_tests"
diff --git a/end2end-tests/tests/common/mod.rs b/end2end-tests/tests/common/mod.rs
index 6b65e5ec757f6ba4085b04223ac4c7f1b62d4c2f..5f21f66041510a1645fd7c3cfb17313ada63a0ec 100644
--- a/end2end-tests/tests/common/mod.rs
+++ b/end2end-tests/tests/common/mod.rs
@@ -29,6 +29,7 @@ pub mod oneshot;
 pub mod gdev {}
 
 use anyhow::anyhow;
+use notify_debouncer_mini::new_debouncer;
 use parity_scale_codec::Encode;
 use serde_json::Value;
 use sp_keyring::AccountKeyring;
@@ -274,16 +275,19 @@ fn wait_until_log_line(expected_log_line: &str, log_file_path: &str, timeout: Du
         }
     } else {
         let (tx, rx) = std::sync::mpsc::channel();
-        let mut watcher = notify::watcher(tx, std::time::Duration::from_millis(100)).unwrap();
-        use notify::Watcher as _;
-        watcher
-            .watch(log_file_path, notify::RecursiveMode::NonRecursive)
+        let mut debouncer = new_debouncer(std::time::Duration::from_millis(100), tx).unwrap();
+        debouncer
+            .watcher()
+            .watch(
+                Path::new(log_file_path),
+                notify::RecursiveMode::NonRecursive,
+            )
             .unwrap();
 
         let mut pos = 0;
         loop {
             match rx.recv_timeout(timeout) {
-                Ok(notify::DebouncedEvent::Write(_)) => {
+                Ok(_) => {
                     let mut file = std::fs::File::open(log_file_path).unwrap();
                     file.seek(std::io::SeekFrom::Start(pos)).unwrap();
                     pos = file.metadata().unwrap().len();
@@ -295,7 +299,6 @@ fn wait_until_log_line(expected_log_line: &str, log_file_path: &str, timeout: Du
                         }
                     }
                 }
-                Ok(_) => {}
                 Err(err) => {
                     eprintln!("Error: {:?}", err);
                     std::process::exit(1);
diff --git a/end2end-tests/tests/cucumber_tests.rs b/end2end-tests/tests/cucumber_tests.rs
index e63495dff01ad78930744ddb0c5747a7f3058d9a..5c174c954d817b8a5ec0751818e82f2bf7359060 100644
--- a/end2end-tests/tests/cucumber_tests.rs
+++ b/end2end-tests/tests/cucumber_tests.rs
@@ -16,11 +16,10 @@
 
 mod common;
 
-use async_trait::async_trait;
 use common::*;
-use cucumber::{given, then, when, FailureWriter, World, WorldInit};
+use cucumber::StatsWriter;
+use cucumber::{given, then, when, World};
 use sp_keyring::AccountKeyring;
-use std::convert::Infallible;
 use std::path::PathBuf;
 use std::str::FromStr;
 use std::sync::{
@@ -31,7 +30,7 @@ use subxt::backend::rpc::RpcClient;
 
 // ===== world =====
 
-#[derive(WorldInit)]
+#[derive(cucumber::World, Default)]
 pub struct DuniterWorld {
     ignore_errors: bool,
     inner: Option<DuniterWorldInner>,
@@ -130,19 +129,6 @@ impl std::fmt::Debug for DuniterWorld {
     }
 }
 
-#[async_trait(?Send)]
-impl World for DuniterWorld {
-    // We do require some error type.
-    type Error = Infallible;
-
-    async fn new() -> std::result::Result<Self, Infallible> {
-        Ok(Self {
-            ignore_errors: false,
-            inner: None,
-        })
-    }
-}
-
 struct DuniterWorldInner {
     client: FullClient,
     process: Option<Process>,
@@ -594,19 +580,19 @@ async fn identity_status_should_be(
 #[derive(clap::Args)]
 struct CustomOpts {
     /// Keep running
-    #[clap(short, long)]
+    #[arg(short, long)]
     keep_running: bool,
     /// Do not spawn a node, reuse expected node on port 9944
-    #[clap(long)]
+    #[arg(long)]
     no_spawn: bool,
 
     /// For compliance with Jetbrains IDE which pushes extra args.
     /// https://youtrack.jetbrains.com/issue/CPP-33071/cargo-test-adds-extra-options-which-conflict-with-Cucumber
-    #[clap(short, long)]
+    #[arg(short, long)]
     format: Option<String>,
-    #[clap(short, long = "show-output")]
+    #[arg(short, long = "show-output")]
     show_output: bool,
-    #[clap(short = 'Z', long)]
+    #[arg(short = 'Z', long)]
     z: Option<String>,
 }
 
@@ -650,7 +636,7 @@ async fn main() {
             world.set_ignore_errors(ignore_errors(&scenario.tags));
             Box::pin(world.init(Some(genesis_conf_file_path), no_spawn))
         })
-        .after(move |_feature, _rule, _scenario, maybe_world| {
+        .after(move |_feature, _rule, _scenario, _ev, maybe_world| {
             if keep_running {
                 while running.load(Ordering::SeqCst) {}
             }