diff --git a/src/AvaloniaInside.Shell.BasicTests/AvaloniaInside.Shell.BasicTests.csproj b/src/AvaloniaInside.Shell.BasicTests/AvaloniaInside.Shell.BasicTests.csproj
new file mode 100644
index 0000000..83b418c
--- /dev/null
+++ b/src/AvaloniaInside.Shell.BasicTests/AvaloniaInside.Shell.BasicTests.csproj
@@ -0,0 +1,24 @@
+
+
+
+ net8.0
+ enable
+ enable
+ false
+ true
+ latest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AvaloniaInside.Shell.BasicTests/NavigationCancellationConceptTests.cs b/src/AvaloniaInside.Shell.BasicTests/NavigationCancellationConceptTests.cs
new file mode 100644
index 0000000..60d91de
--- /dev/null
+++ b/src/AvaloniaInside.Shell.BasicTests/NavigationCancellationConceptTests.cs
@@ -0,0 +1,203 @@
+using System;
+using System.Collections.Concurrent;
+using System.Threading;
+using System.Threading.Tasks;
+using NUnit.Framework;
+
+namespace AvaloniaInside.Shell.BasicTests;
+
+[TestFixture]
+public class NavigationCancellationConceptTests
+{
+ [Test]
+ public void CancellationTokenSource_WhenCancelled_ShouldBeCancelled()
+ {
+ // Arrange
+ using var cts = new CancellationTokenSource();
+
+ // Act
+ cts.Cancel();
+
+ // Assert
+ Assert.That(cts.Token.IsCancellationRequested, Is.True);
+ }
+
+ [Test]
+ public async Task AsyncLocal_Stack_ShouldMaintainSeparateContexts()
+ {
+ // Arrange
+ var asyncLocal = new AsyncLocal>();
+ asyncLocal.Value = new Stack();
+ asyncLocal.Value.Push(1);
+
+ // Act & Assert
+ var task1 = Task.Run(() =>
+ {
+ asyncLocal.Value ??= new Stack();
+ asyncLocal.Value.Push(10);
+ return asyncLocal.Value.Count;
+ });
+
+ var task2 = Task.Run(() =>
+ {
+ asyncLocal.Value ??= new Stack();
+ asyncLocal.Value.Push(20);
+ return asyncLocal.Value.Count;
+ });
+
+ var results = await Task.WhenAll(task1, task2);
+
+ Assert.That(results[0], Is.EqualTo(1));
+ Assert.That(results[1], Is.EqualTo(1));
+ Assert.That(asyncLocal.Value.Count, Is.EqualTo(1)); // Original context unchanged
+ }
+
+ [Test]
+ public async Task OperationCanceledException_ShouldBeThrown_WhenTokenCancelled()
+ {
+ // Arrange
+ using var cts = new CancellationTokenSource();
+
+ // Act & Assert
+ var task = Task.Run(async () =>
+ {
+ await Task.Delay(100, cts.Token);
+ });
+
+ cts.Cancel();
+
+ Assert.ThrowsAsync(async () => await task);
+ }
+
+ [Test]
+ public async Task LinkedCancellationToken_ShouldCancelWhenParentCancels()
+ {
+ // Arrange
+ using var parentCts = new CancellationTokenSource();
+ using var childCts = CancellationTokenSource.CreateLinkedTokenSource(parentCts.Token);
+
+ // Act
+ parentCts.Cancel();
+
+ // Assert
+ Assert.That(childCts.Token.IsCancellationRequested, Is.True);
+
+ // Verify that operations using the child token are cancelled
+ Assert.ThrowsAsync(async () =>
+ {
+ await Task.Delay(100, childCts.Token);
+ });
+ }
+
+ [Test]
+ public async Task TaskWhenAny_ShouldCompleteWhenFirstTaskCompletes()
+ {
+ // Arrange
+ var tcs1 = new TaskCompletionSource();
+ var tcs2 = new TaskCompletionSource();
+
+ // Act
+ var firstCompleted = Task.WhenAny(tcs1.Task, tcs2.Task);
+ tcs1.SetResult(42);
+
+ var result = await firstCompleted;
+
+ // Assert
+ Assert.That(result, Is.EqualTo(tcs1.Task));
+ Assert.That(await result, Is.EqualTo(42));
+ Assert.That(tcs2.Task.IsCompleted, Is.False);
+ }
+
+ [Test]
+ public void ConcurrentDictionary_ShouldBeThreadSafe()
+ {
+ // Arrange
+ var dict = new ConcurrentDictionary();
+ var tasks = new Task[10];
+
+ // Act
+ for (int i = 0; i < 10; i++)
+ {
+ var index = i;
+ tasks[i] = Task.Run(() =>
+ {
+ var cts = new CancellationTokenSource();
+ dict.TryAdd($"key{index}", cts);
+ return dict.TryRemove($"key{index}", out _);
+ });
+ }
+
+ Task.WaitAll(tasks);
+
+ // Assert
+ Assert.That(dict.Count, Is.EqualTo(0));
+ }
+
+ [Test]
+ public async Task NestedCancellationTokens_ShouldPropagateCorrectly()
+ {
+ // Arrange
+ using var outerCts = new CancellationTokenSource();
+ using var middleCts = CancellationTokenSource.CreateLinkedTokenSource(outerCts.Token);
+ using var innerCts = CancellationTokenSource.CreateLinkedTokenSource(middleCts.Token);
+
+ // Act
+ outerCts.Cancel();
+
+ // Assert
+ Assert.That(middleCts.Token.IsCancellationRequested, Is.True);
+ Assert.That(innerCts.Token.IsCancellationRequested, Is.True);
+
+ // Verify that all levels are cancelled
+ Assert.ThrowsAsync(async () => await Task.Delay(1, outerCts.Token));
+ Assert.ThrowsAsync(async () => await Task.Delay(1, middleCts.Token));
+ Assert.ThrowsAsync(async () => await Task.Delay(1, innerCts.Token));
+ }
+
+ [Test]
+ public async Task AsyncLocalStack_SimulatesNavigationStack()
+ {
+ // This test simulates how the navigation cancellation would work
+ var navigationStack = new AsyncLocal>();
+
+ async Task SimulateNestedNavigation(int level)
+ {
+ navigationStack.Value ??= new Stack();
+
+ using var cts = new CancellationTokenSource();
+ navigationStack.Value.Push(cts);
+
+ try
+ {
+ if (level > 0)
+ {
+ // Simulate nested navigation
+ await SimulateNestedNavigation(level - 1);
+ }
+ else
+ {
+ // Simulate the deepest level cancelling all
+ while (navigationStack.Value.Count > 0)
+ {
+ var cancelCts = navigationStack.Value.Pop();
+ cancelCts.Cancel();
+ }
+ }
+ }
+ finally
+ {
+ // Clean up
+ if (navigationStack.Value.Count > 0 && navigationStack.Value.Peek() == cts)
+ {
+ navigationStack.Value.Pop();
+ }
+ }
+ }
+
+ // Act & Assert
+ Assert.ThrowsAsync(async () =>
+ {
+ await SimulateNestedNavigation(3);
+ });
+ }
+}
\ No newline at end of file
diff --git a/src/AvaloniaInside.Shell.Tests/AvaloniaInside.Shell.SimpleTests.csproj b/src/AvaloniaInside.Shell.Tests/AvaloniaInside.Shell.SimpleTests.csproj
new file mode 100644
index 0000000..4c1ec2c
--- /dev/null
+++ b/src/AvaloniaInside.Shell.Tests/AvaloniaInside.Shell.SimpleTests.csproj
@@ -0,0 +1,30 @@
+
+
+
+ net8.0
+ enable
+ enable
+ false
+ true
+ latest
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AvaloniaInside.Shell.Tests/AvaloniaInside.Shell.Tests.csproj b/src/AvaloniaInside.Shell.Tests/AvaloniaInside.Shell.Tests.csproj
new file mode 100644
index 0000000..fa44076
--- /dev/null
+++ b/src/AvaloniaInside.Shell.Tests/AvaloniaInside.Shell.Tests.csproj
@@ -0,0 +1,34 @@
+
+
+
+ net8.0
+ enable
+ enable
+ false
+ true
+ latest
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/AvaloniaInside.Shell.Tests/GlobalUsings.cs b/src/AvaloniaInside.Shell.Tests/GlobalUsings.cs
new file mode 100644
index 0000000..5057206
--- /dev/null
+++ b/src/AvaloniaInside.Shell.Tests/GlobalUsings.cs
@@ -0,0 +1,6 @@
+global using Xunit;
+global using Moq;
+global using Shouldly;
+global using System;
+global using System.Threading;
+global using System.Threading.Tasks;
\ No newline at end of file
diff --git a/src/AvaloniaInside.Shell.Tests/NavigatorTests.cs b/src/AvaloniaInside.Shell.Tests/NavigatorTests.cs
new file mode 100644
index 0000000..213c902
--- /dev/null
+++ b/src/AvaloniaInside.Shell.Tests/NavigatorTests.cs
@@ -0,0 +1,317 @@
+using AvaloniaInside.Shell;
+using Avalonia.Animation;
+
+namespace AvaloniaInside.Shell.Tests;
+
+public class NavigatorTests : IDisposable
+{
+ private readonly Mock _mockRegistrar;
+ private readonly Mock _mockNavigateStrategy;
+ private readonly Mock _mockUpdateStrategy;
+ private readonly Mock _mockViewLocator;
+ private readonly Navigator _navigator;
+ private readonly ShellView _shellView;
+
+ public NavigatorTests()
+ {
+ _mockRegistrar = new Mock();
+ _mockNavigateStrategy = new Mock();
+ _mockUpdateStrategy = new Mock();
+ _mockViewLocator = new Mock();
+
+ _navigator = new Navigator(
+ _mockRegistrar.Object,
+ _mockNavigateStrategy.Object,
+ _mockUpdateStrategy.Object,
+ _mockViewLocator.Object);
+
+ _shellView = new ShellView(_navigator);
+
+ SetupBasicMocks();
+ }
+
+ private void SetupBasicMocks()
+ {
+ _mockRegistrar.Setup(r => r.RootUri).Returns(new Uri("app://root"));
+ _mockRegistrar.Setup(r => r.TryGetNode(It.IsAny(), out It.Ref.IsAny))
+ .Returns((string path, out NavigationNode node) =>
+ {
+ node = CreateMockNavigationNode(path);
+ return true;
+ });
+
+ _mockNavigateStrategy.Setup(s => s.NavigateAsync(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny()))
+ .ReturnsAsync(new Uri("app://root/test"));
+
+ _mockNavigateStrategy.Setup(s => s.BackAsync(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny()))
+ .ReturnsAsync(new Uri("app://root"));
+
+ _mockUpdateStrategy.Setup(s => s.UpdateChangesAsync(
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny(),
+ It.IsAny