Skip to content

Conversation

@captainsafia
Copy link
Member

@captainsafia captainsafia commented Aug 18, 2020

  • Change OnNavigateAsync type to EventCallback
  • Remove conditional rendering logic in RunOnNavigateAsyncWithRefresh
  • Remove check for OperationCancelledException (CallStateHasChangedWhenAsyncTaskFinished ignores this)

Addresses #24215

@captainsafia captainsafia requested review from a team and SteveSandersonMS as code owners August 18, 2020 18:44
@ghost ghost added the area-blazor Includes: Blazor, Razor Components label Aug 18, 2020
@captainsafia captainsafia marked this pull request as draft August 18, 2020 18:44
@captainsafia captainsafia removed request for a team and SteveSandersonMS August 18, 2020 18:44
@captainsafia captainsafia marked this pull request as ready for review August 19, 2020 15:54
@pranavkm pranavkm added this to the 5.0.0-rc1 milestone Aug 19, 2020
}
Assert.True(false, "OnUpdateDisplay called more than once.");
};
_router.OnNavigateAsync = OnNavigateAsync;
Copy link
Member

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.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this.

Comment on lines 120 to 141
[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);
}

Copy link
Member

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)

Copy link
Member Author

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()
Copy link
Member

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?

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member Author

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.

Copy link
Member

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.

Copy link
Member

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.");
}
Copy link
Member

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.");
            }

Copy link
Member Author

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.

Copy link
Member

@javiercn javiercn left a 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.

Copy link
Member

@javiercn javiercn left a 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

@captainsafia captainsafia merged commit 8fc1419 into release/5.0 Aug 20, 2020
@captainsafia captainsafia deleted the safia/event-callback branch August 20, 2020 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-blazor Includes: Blazor, Razor Components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants