diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..ea48f000a1a5251286403a45c5d724a3c81a998b
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,9 @@
+stages:
+  - test
+
+tests:
+  stage: test
+  tags: 
+    - ios
+  script:
+    - ./run-tests.sh
diff --git a/Sources/XXMessengerClient/Messenger/Functors/MessengerDestroy.swift b/Sources/XXMessengerClient/Messenger/Functors/MessengerDestroy.swift
new file mode 100644
index 0000000000000000000000000000000000000000..51f6092321c0b08fb24729de3e30f55abba10318
--- /dev/null
+++ b/Sources/XXMessengerClient/Messenger/Functors/MessengerDestroy.swift
@@ -0,0 +1,26 @@
+import XCTestDynamicOverlay
+
+public struct MessengerDestroy {
+  public var run: () throws -> Void
+
+  public func callAsFunction() throws -> Void {
+    try run()
+  }
+}
+
+extension MessengerDestroy {
+  public static func live(_ env: MessengerEnvironment) -> MessengerDestroy {
+    MessengerDestroy {
+      env.ud.set(nil)
+      env.e2e.set(nil)
+      env.cMix.set(nil)
+      try env.fileManager.removeDirectory(env.storageDir)
+    }
+  }
+}
+
+extension MessengerDestroy {
+  public static let unimplemented = MessengerDestroy(
+    run: XCTUnimplemented("\(Self.self)")
+  )
+}
diff --git a/Sources/XXMessengerClient/Messenger/Messenger.swift b/Sources/XXMessengerClient/Messenger/Messenger.swift
index c9563fe8a4db09ab0e7c9e8e1c6dfcfcdb7ab3be..652eda396d5d619e7e98892274c88a7f851ba4a9 100644
--- a/Sources/XXMessengerClient/Messenger/Messenger.swift
+++ b/Sources/XXMessengerClient/Messenger/Messenger.swift
@@ -18,6 +18,7 @@ public struct Messenger {
   public var logIn: MessengerLogIn
   public var waitForNetwork: MessengerWaitForNetwork
   public var waitForNodes: MessengerWaitForNodes
+  public var destroy: MessengerDestroy
 }
 
 extension Messenger {
@@ -39,7 +40,8 @@ extension Messenger {
       isLoggedIn: .live(env),
       logIn: .live(env),
       waitForNetwork: .live(env),
-      waitForNodes: .live(env)
+      waitForNodes: .live(env),
+      destroy: .live(env)
     )
   }
 }
@@ -62,6 +64,7 @@ extension Messenger {
     isLoggedIn: .unimplemented,
     logIn: .unimplemented,
     waitForNetwork: .unimplemented,
-    waitForNodes: .unimplemented
+    waitForNodes: .unimplemented,
+    destroy: .unimplemented
   )
 }
diff --git a/Tests/XXMessengerClientTests/Messenger/Functors/MessengerDestroyTests.swift b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerDestroyTests.swift
new file mode 100644
index 0000000000000000000000000000000000000000..cfe3f9a51f447c41cf94ae077c71a0b63f3639e3
--- /dev/null
+++ b/Tests/XXMessengerClientTests/Messenger/Functors/MessengerDestroyTests.swift
@@ -0,0 +1,51 @@
+import CustomDump
+import XCTest
+import XXClient
+@testable import XXMessengerClient
+
+final class MessengerDestroyTests: XCTestCase {
+  func testDestroy() throws {
+    let storageDir = "test-storage-dir"
+    var didRemoveDirectory: [String] = []
+    var didSetUD: [UserDiscovery?] = []
+    var didSetE2E: [E2E?] = []
+    var didSetCMix: [CMix?] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.storageDir = storageDir
+    env.ud.set = { didSetUD.append($0) }
+    env.e2e.set = { didSetE2E.append($0) }
+    env.cMix.set = { didSetCMix.append($0) }
+    env.fileManager.removeDirectory = { didRemoveDirectory.append($0) }
+    let destroy: MessengerDestroy = .live(env)
+
+    try destroy()
+
+    XCTAssertNoDifference(didSetUD.map { $0 == nil }, [true])
+    XCTAssertNoDifference(didSetE2E.map { $0 == nil }, [true])
+    XCTAssertNoDifference(didSetCMix.map { $0 == nil }, [true])
+    XCTAssertNoDifference(didRemoveDirectory, [storageDir])
+  }
+
+  func testRemoveDirectoryFailure() {
+    struct Error: Swift.Error, Equatable {}
+    let error = Error()
+    var didSetUD: [UserDiscovery?] = []
+    var didSetE2E: [E2E?] = []
+    var didSetCMix: [CMix?] = []
+
+    var env: MessengerEnvironment = .unimplemented
+    env.ud.set = { didSetUD.append($0) }
+    env.e2e.set = { didSetE2E.append($0) }
+    env.cMix.set = { didSetCMix.append($0) }
+    env.fileManager.removeDirectory = { _ in throw error }
+    let destroy: MessengerDestroy = .live(env)
+
+    XCTAssertThrowsError(try destroy()) { err in
+      XCTAssertEqual(err as? Error, error)
+    }
+    XCTAssertNoDifference(didSetUD.map { $0 == nil }, [true])
+    XCTAssertNoDifference(didSetE2E.map { $0 == nil }, [true])
+    XCTAssertNoDifference(didSetCMix.map { $0 == nil }, [true])
+  }
+}
diff --git a/run-tests.sh b/run-tests.sh
new file mode 100755
index 0000000000000000000000000000000000000000..80f7cd7ee032c01a5826cd995efdd3ae0072b8f3
--- /dev/null
+++ b/run-tests.sh
@@ -0,0 +1,3 @@
+#!/bin/sh
+set -e
+set -o pipefail && xcodebuild -scheme 'elixxir-dapps-sdk-swift-Package' -sdk iphonesimulator -destination 'platform=iOS Simulator,OS=15.5,name=iPhone 13' test | ./xcbeautify
diff --git a/xcbeautify b/xcbeautify
new file mode 100755
index 0000000000000000000000000000000000000000..c68c40e98dc4aff708435c6c159fa713ac74a58b
Binary files /dev/null and b/xcbeautify differ