-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Make OnNavigateAsync EventCallback and cancel previous navigation #25011
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e1d9133 to
0880c8a
Compare
0880c8a to
39914ac
Compare
| } | ||
| Assert.True(false, "OnUpdateDisplay called more than once."); | ||
| }; | ||
| _router.OnNavigateAsync = OnNavigateAsync; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will be good to capture the new behavior of OnUpdateDisplay, I imagine that this has changed since we are removing it.
I would suggest we capture on an integer, the number of times it is being called and check against how many times we expect it to be called. That will help catch regressions if in the future we make a change to the implementation that results in a subtle change in the rendering sequence.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this.
| [Fact] | ||
| public async Task CanHandleSingleCancelledOnNavigateAsync() | ||
| { | ||
| // Arrange | ||
| async Task OnNavigateAsync(NavigationContext args) | ||
| { | ||
| var tcs = new TaskCompletionSource<int>(); | ||
| tcs.TrySetCanceled(); | ||
| await tcs.Task; | ||
| } | ||
| _renderer.OnUpdateDisplay = (renderBatch) => Assert.True(false, "OnUpdateDisplay called more than once."); | ||
| _router.OnNavigateAsync = OnNavigateAsync; | ||
|
|
||
| // Act | ||
| await _renderer.Dispatcher.InvokeAsync(() => _router.RunOnNavigateWithRefreshAsync("http://example.com/jan", false)); | ||
|
|
||
| // Assert | ||
| Assert.Single(_renderer.HandledExceptions); | ||
| var unhandledException = _renderer.HandledExceptions[0]; | ||
| Assert.Equal("OnNavigateAsync can only be cancelled via NavigateContext.CancellationToken.", unhandledException.Message); | ||
| } | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of removing this test, can we capture the new behavior? (Canceled OnNavigate invocations will result in a new render)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure.
| } | ||
|
|
||
| [Fact] | ||
| public async Task CanHandleSingleFailedOnNavigateAsync() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why are we removing coverage for this? Shouldn't we still test what happens when an exception is thrown from the handler?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have an E2E test that validates this scenario here so I removed this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's fair, for future reference I would suggest you consider keeping the unit test and the E2E test. They complement each other.
The unit test validates the component and helps catch regressions faster while the E2E test validates the integration. Figuring out a regression with a failing E2E test is much harder than with a unit test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out that doing this in the E2E tests is the only option I have. There isn't a super nice way to create an EventCallback with the Router component instantiated with the tests (hence why we use new EventCallback(null, action). This exercises the execution of the async action but doesn't exercise the renderer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I do know how to do this, but it requires a bit of changes. It involves:
- Creating a parent component.
- Attaching the instance to the renderer.
- Setting properties on the parent component instance.
- Triggering a render from the parent component.
There are a lot of samples in the Renderer tests, but it is a bit more involved.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll let you use your best judgement here.
| called = true; | ||
| await Task.CompletedTask; | ||
| throw new Exception("This is an uncaught exception."); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Orthogonal to this change: We should test what happens when this throws synchronously and asynchronously. For example:
Task OnNavigateAsync(NavigationContext args)
{
called = true;
throw new Exception("This is an uncaught exception.");
return Task.CompletedTask;
}Which throws synchronously VS the method above. (Which also throws synchronously, but the async machinery will transform it into a failed task).
For throwing asynchronously we actually need to go async
async Task OnNavigateAsync(NavigationContext args)
{
called = true;
await Task.Delay(1000); // Or better than this, a task completion source
throw new Exception("This is an uncaught exception.");
}There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added an E2E test for this. E2E tests work a little bit better here because there isn't a good way to attach the event callback the router component in the unit tests.
javiercn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, I have made a few comments about the tests, but other than that it looks good.
javiercn
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signing-off, but please address the test questions/changes before merging
531fdf6 to
7162fba
Compare
OnNavigateAsynctype toEventCallbackRunOnNavigateAsyncWithRefreshAddresses #24215