diff --git a/TUnit.Assertions.Tests/WaitsForAssertionTests.cs b/TUnit.Assertions.Tests/WaitsForAssertionTests.cs index 9ff2ed7e80..9cfb5ffca8 100644 --- a/TUnit.Assertions.Tests/WaitsForAssertionTests.cs +++ b/TUnit.Assertions.Tests/WaitsForAssertionTests.cs @@ -407,6 +407,110 @@ public async Task WaitsFor_WithIsNotNull_ReturnsResolvedValue_Issue3623() await Assert.That(entity.IsReady).IsEqualTo(true); } + [Test] + public async Task WaitsFor_PropagatesExternalCancellation_Before_Internal_Timeout() + { + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromMilliseconds(100)); + + var stopwatch = Stopwatch.StartNew(); + + var act = async () => await Assert.That(() => false) + .WaitsFor( + assert => assert.IsTrue(), + timeout: TimeSpan.FromSeconds(30), + cancellationToken: cts.Token); + + await Assert.That(act).Throws(); + + stopwatch.Stop(); + + await Assert.That(stopwatch.Elapsed).IsLessThan(TimeSpan.FromSeconds(1)); + } + + [Test] + public async Task WaitsFor_Throws_AssertionException_On_Internal_Timeout_When_Token_Not_Cancelled() + { + using var cts = new CancellationTokenSource(); + + var act = async () => await Assert.That(() => false) + .WaitsFor( + assert => assert.IsTrue(), + timeout: TimeSpan.FromMilliseconds(200), + cancellationToken: cts.Token); + + await Assert.That(act).Throws(); + } + + [Test] + public async Task WaitsFor_Honours_PreCancelled_Token_Before_First_Poll() + { + using var cts = new CancellationTokenSource(); + cts.Cancel(); + + var stopwatch = Stopwatch.StartNew(); + + var act = async () => await Assert.That(() => false) + .WaitsFor( + assert => assert.IsTrue(), + timeout: TimeSpan.FromSeconds(5), + cancellationToken: cts.Token); + + await Assert.That(act).Throws(); + + stopwatch.Stop(); + + await Assert.That(stopwatch.Elapsed).IsLessThan(TimeSpan.FromMilliseconds(500)); + } + + [Test] + public async Task Eventually_PropagatesExternalCancellation_Before_Internal_Timeout() + { + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromMilliseconds(100)); + + var stopwatch = Stopwatch.StartNew(); + + var act = async () => await Assert.That(() => false) + .Eventually( + assert => assert.IsTrue(), + timeout: TimeSpan.FromSeconds(30), + cancellationToken: cts.Token); + + await Assert.That(act).Throws(); + + stopwatch.Stop(); + + await Assert.That(stopwatch.Elapsed).IsLessThan(TimeSpan.FromSeconds(1)); + } + + [Test] + public async Task WaitsFor_Propagates_OCE_When_Predicate_Observes_Supplied_Token() + { + using var cts = new CancellationTokenSource(); + cts.CancelAfter(TimeSpan.FromMilliseconds(50)); + + Func tokenAwarePredicate = () => + { + cts.Token.ThrowIfCancellationRequested(); + return false; + }; + + var stopwatch = Stopwatch.StartNew(); + + var act = async () => await Assert.That(tokenAwarePredicate) + .WaitsFor( + assert => assert.IsTrue(), + timeout: TimeSpan.FromSeconds(30), + cancellationToken: cts.Token); + + await Assert.That(act).Throws(); + + stopwatch.Stop(); + + await Assert.That(stopwatch.Elapsed).IsLessThan(TimeSpan.FromMilliseconds(500)); + } + // Helper class for testing complex objects private class TestEntity { diff --git a/TUnit.Assertions/Conditions/WaitsForAssertion.cs b/TUnit.Assertions/Conditions/WaitsForAssertion.cs index e57df59e0f..992886004e 100644 --- a/TUnit.Assertions/Conditions/WaitsForAssertion.cs +++ b/TUnit.Assertions/Conditions/WaitsForAssertion.cs @@ -15,17 +15,20 @@ public class WaitsForAssertion : Assertion private readonly Func, Assertion> _assertionBuilder; private readonly TimeSpan _timeout; private readonly TimeSpan _pollingInterval; + private readonly CancellationToken _cancellationToken; public WaitsForAssertion( AssertionContext context, Func, Assertion> assertionBuilder, TimeSpan timeout, - TimeSpan? pollingInterval = null) + TimeSpan? pollingInterval = null, + CancellationToken cancellationToken = default) : base(context) { _assertionBuilder = assertionBuilder ?? throw new ArgumentNullException(nameof(assertionBuilder)); _timeout = timeout; _pollingInterval = pollingInterval ?? TimeSpan.FromMilliseconds(10); + _cancellationToken = cancellationToken; if (_timeout <= TimeSpan.Zero) { @@ -44,10 +47,20 @@ protected override async Task CheckAsync(EvaluationMetadata CheckAsync(EvaluationMetadataA function that builds the assertion to be evaluated on each poll /// The maximum time to wait for the assertion to pass /// The interval between polling attempts (defaults to 10ms if not specified) + /// A token to cancel the polling loop. External cancellation throws ; the internal timeout still produces the standard . /// Captured expression for the timeout parameter /// Captured expression for the polling interval parameter /// An assertion that can be awaited or chained with And/Or @@ -1727,12 +1728,13 @@ public static WaitsForAssertion WaitsFor( Func, Assertion> assertionBuilder, TimeSpan timeout, TimeSpan? pollingInterval = null, + CancellationToken cancellationToken = default, [CallerArgumentExpression(nameof(timeout))] string? timeoutExpression = null, [CallerArgumentExpression(nameof(pollingInterval))] string? pollingIntervalExpression = null) { var intervalExpr = pollingInterval.HasValue ? $", pollingInterval: {pollingIntervalExpression}" : ""; source.Context.ExpressionBuilder.Append($".WaitsFor(..., timeout: {timeoutExpression}{intervalExpr})"); - return new WaitsForAssertion(source.Context, assertionBuilder, timeout, pollingInterval); + return new WaitsForAssertion(source.Context, assertionBuilder, timeout, pollingInterval, cancellationToken); } /// @@ -1745,6 +1747,7 @@ public static WaitsForAssertion WaitsFor( /// A function that builds the assertion to be evaluated on each poll /// The maximum time to wait for the assertion to pass /// The interval between polling attempts (defaults to 10ms if not specified) + /// A token to cancel the polling loop. External cancellation throws ; the internal timeout still produces the standard . /// Captured expression for the timeout parameter /// Captured expression for the polling interval parameter /// An assertion that can be awaited or chained with And/Or @@ -1753,10 +1756,11 @@ public static WaitsForAssertion Eventually( Func, Assertion> assertionBuilder, TimeSpan timeout, TimeSpan? pollingInterval = null, + CancellationToken cancellationToken = default, [CallerArgumentExpression(nameof(timeout))] string? timeoutExpression = null, [CallerArgumentExpression(nameof(pollingInterval))] string? pollingIntervalExpression = null) { - return source.WaitsFor(assertionBuilder, timeout, pollingInterval, timeoutExpression, pollingIntervalExpression); + return source.WaitsFor(assertionBuilder, timeout, pollingInterval, cancellationToken, timeoutExpression, pollingIntervalExpression); } private static Action GetActionFromDelegate(DelegateAssertion source) diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt index 82b841f008..fc2d114091 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet10_0.verified.txt @@ -2279,7 +2279,7 @@ namespace .Conditions public static class ValueTaskAssertionExtensions { } public class WaitsForAssertion : . { - public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default) { } + public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default) { } public override . AssertAsync() { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } @@ -2674,7 +2674,7 @@ namespace .Extensions where TCollection : .<.> where TKey : notnull { } public static . EqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } [("Use Length() instead, which provides all numeric assertion methods. Example: Asse" + "(str).Length().IsGreaterThan(5)")] public static ..LengthWrapper HasLength(this . source) { } @@ -2803,7 +2803,7 @@ namespace .Extensions public static . ThrowsException(this . source) where TException : { } public static . ThrowsNothing(this . source) { } - public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } public static ..WhenParsedIntoAssertion WhenParsedInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this . source) { } public static . WithInnerException(this . source) where TException : diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt index 1c52015ff5..8783b78802 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -2262,7 +2262,7 @@ namespace .Conditions public static class ValueTaskAssertionExtensions { } public class WaitsForAssertion : . { - public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default) { } + public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default) { } public override . AssertAsync() { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } @@ -2653,7 +2653,7 @@ namespace .Extensions where TCollection : .<.> where TKey : notnull { } public static . EqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } [("Use Length() instead, which provides all numeric assertion methods. Example: Asse" + "(str).Length().IsGreaterThan(5)")] public static ..LengthWrapper HasLength(this . source) { } @@ -2768,7 +2768,7 @@ namespace .Extensions public static . ThrowsException(this . source) where TException : { } public static . ThrowsNothing(this . source) { } - public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } public static ..WhenParsedIntoAssertion WhenParsedInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this . source) { } public static . WithInnerException(this . source) where TException : diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt index 53f5d2824a..ed5f733562 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -2279,7 +2279,7 @@ namespace .Conditions public static class ValueTaskAssertionExtensions { } public class WaitsForAssertion : . { - public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default) { } + public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default) { } public override . AssertAsync() { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } @@ -2674,7 +2674,7 @@ namespace .Extensions where TCollection : .<.> where TKey : notnull { } public static . EqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } [("Use Length() instead, which provides all numeric assertion methods. Example: Asse" + "(str).Length().IsGreaterThan(5)")] public static ..LengthWrapper HasLength(this . source) { } @@ -2803,7 +2803,7 @@ namespace .Extensions public static . ThrowsException(this . source) where TException : { } public static . ThrowsNothing(this . source) { } - public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } public static ..WhenParsedIntoAssertion WhenParsedInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this . source) { } public static . WithInnerException(this . source) where TException : diff --git a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt index d4b8c212ba..b29afe65f8 100644 --- a/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt +++ b/TUnit.PublicAPI/Tests.Assertions_Library_Has_No_API_Changes.Net4_7.verified.txt @@ -2032,7 +2032,7 @@ namespace .Conditions public static class ValueTaskAssertionExtensions { } public class WaitsForAssertion : . { - public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default) { } + public WaitsForAssertion(. context, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default) { } public override . AssertAsync() { } protected override .<.> CheckAsync(. metadata) { } protected override string GetExpectation() { } @@ -2389,7 +2389,7 @@ namespace .Extensions where TCollection : .<.> where TKey : notnull { } public static . EqualTo(this . source, TValue? expected, [.("expected")] string? expression = null) { } - public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . Eventually(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } [("Use Length() instead, which provides all numeric assertion methods. Example: Asse" + "(str).Length().IsGreaterThan(5)")] public static ..LengthWrapper HasLength(this . source) { } @@ -2482,7 +2482,7 @@ namespace .Extensions public static . ThrowsException(this . source) where TException : { } public static . ThrowsNothing(this . source) { } - public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static . WaitsFor(this . source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } public static ..WhenParsedIntoAssertion WhenParsedInto(this . source) { } public static . WithInnerException(this . source) where TException : diff --git a/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet10_0.verified.txt b/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet10_0.verified.txt index 2a0e8751d2..fd438f3bd7 100644 --- a/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet10_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet10_0.verified.txt @@ -293,7 +293,7 @@ namespace . public static ..ShouldAssertion BeOfType(this ..IShouldSource source, expectedType, [.("expectedType")] string? expression = null) { } public static ..ShouldAssertion BeParsableInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this ..IShouldSource source) { } public static ..ShouldAssertion EqualTo(this ..IShouldSource source, TValue? expected, [.("expected")] string? expression = null) { } - public static ..ShouldAssertion Eventually(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static ..ShouldAssertion Eventually(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } [("Use Length().IsEqualTo(expectedLength) instead.")] public static ..ShouldAssertion HaveLength(this ..IShouldSource source, int expectedLength, [.("expectedLength")] string? expression = null) { } public static ..ShouldAssertion HaveMessage(this ..IShouldSource source, string expectedMessage, [.("expectedMessage")] string? expression = null) @@ -313,7 +313,7 @@ namespace . public static ..ShouldAssertion NotBeNull(this ..IShouldSource source) where TValue : class { } public static ..ShouldAssertion NotBeParsableInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this ..IShouldSource source) { } - public static ..ShouldAssertion WaitFor(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static ..ShouldAssertion WaitFor(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } public static ..ShouldAssertion WithInnerException(this ..IShouldSource source) where TException : where TInnerException : { } diff --git a/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet8_0.verified.txt b/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet8_0.verified.txt index 2d73b79a88..b0e518b5e6 100644 --- a/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet8_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet8_0.verified.txt @@ -293,7 +293,7 @@ namespace . public static ..ShouldAssertion BeOfType(this ..IShouldSource source, expectedType, [.("expectedType")] string? expression = null) { } public static ..ShouldAssertion BeParsableInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this ..IShouldSource source) { } public static ..ShouldAssertion EqualTo(this ..IShouldSource source, TValue? expected, [.("expected")] string? expression = null) { } - public static ..ShouldAssertion Eventually(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static ..ShouldAssertion Eventually(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } [("Use Length().IsEqualTo(expectedLength) instead.")] public static ..ShouldAssertion HaveLength(this ..IShouldSource source, int expectedLength, [.("expectedLength")] string? expression = null) { } public static ..ShouldAssertion HaveMessage(this ..IShouldSource source, string expectedMessage, [.("expectedMessage")] string? expression = null) @@ -313,7 +313,7 @@ namespace . public static ..ShouldAssertion NotBeNull(this ..IShouldSource source) where TValue : class { } public static ..ShouldAssertion NotBeParsableInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this ..IShouldSource source) { } - public static ..ShouldAssertion WaitFor(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static ..ShouldAssertion WaitFor(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } public static ..ShouldAssertion WithInnerException(this ..IShouldSource source) where TException : where TInnerException : { } diff --git a/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet9_0.verified.txt b/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet9_0.verified.txt index 32e1c434cb..4b0f89743b 100644 --- a/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet9_0.verified.txt +++ b/TUnit.PublicAPI/Tests.Should_Library_Has_No_API_Changes.DotNet9_0.verified.txt @@ -293,7 +293,7 @@ namespace . public static ..ShouldAssertion BeOfType(this ..IShouldSource source, expectedType, [.("expectedType")] string? expression = null) { } public static ..ShouldAssertion BeParsableInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this ..IShouldSource source) { } public static ..ShouldAssertion EqualTo(this ..IShouldSource source, TValue? expected, [.("expected")] string? expression = null) { } - public static ..ShouldAssertion Eventually(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static ..ShouldAssertion Eventually(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } [("Use Length().IsEqualTo(expectedLength) instead.")] public static ..ShouldAssertion HaveLength(this ..IShouldSource source, int expectedLength, [.("expectedLength")] string? expression = null) { } public static ..ShouldAssertion HaveMessage(this ..IShouldSource source, string expectedMessage, [.("expectedMessage")] string? expression = null) @@ -313,7 +313,7 @@ namespace . public static ..ShouldAssertion NotBeNull(this ..IShouldSource source) where TValue : class { } public static ..ShouldAssertion NotBeParsableInto<[.(..None | ..PublicMethods | ..Interfaces)] T>(this ..IShouldSource source) { } - public static ..ShouldAssertion WaitFor(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } + public static ..ShouldAssertion WaitFor(this ..IShouldSource source, <., .> assertionBuilder, timeout, ? pollingInterval = default, .CancellationToken cancellationToken = default, [.("timeout")] string? timeoutExpression = null, [.("pollingInterval")] string? pollingIntervalExpression = null) { } public static ..ShouldAssertion WithInnerException(this ..IShouldSource source) where TException : where TInnerException : { }