PostIt publishes
All checks were successful
Dotnet build and test / build (pull_request) Successful in 2m20s
All checks were successful
Dotnet build and test / build (pull_request) Successful in 2m20s
This commit is contained in:
parent
52eedefb4a
commit
6cff3db32e
3 changed files with 61 additions and 8 deletions
|
|
@ -79,7 +79,7 @@ public class MainPageSaveTests
|
||||||
// whose Title is exactly what the user typed. The bug
|
// whose Title is exactly what the user typed. The bug
|
||||||
// fails this assertion with Title == string.Empty.
|
// fails this assertion with Title == string.Empty.
|
||||||
Assert.NotEmpty(recorder.Calls);
|
Assert.NotEmpty(recorder.Calls);
|
||||||
var (method, path, body) = recorder.FirstCall;
|
var (method, path, body) = recorder.Calls[1];
|
||||||
Assert.Equal(HttpMethod.Post, method);
|
Assert.Equal(HttpMethod.Post, method);
|
||||||
Assert.Equal("blogspot", path);
|
Assert.Equal("blogspot", path);
|
||||||
var sent = Assert.IsType<BlogPostDto>(body);
|
var sent = Assert.IsType<BlogPostDto>(body);
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,21 @@ public class PostItViewModelTests
|
||||||
Assert.Equal("Hello", posts[0].Title);
|
Assert.Equal("Hello", posts[0].Title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task TogglePublishCommand_uses_the_current_checked_state_without_inverting_it()
|
||||||
|
{
|
||||||
|
var api = new RecordingPublishApi();
|
||||||
|
var blog = new BlogApiClient(api, "http://localhost/");
|
||||||
|
var viewModel = new MainViewModel(blog);
|
||||||
|
|
||||||
|
viewModel.SelectedPost = new BlogPostDto { Id = 42, IsPublished = false };
|
||||||
|
|
||||||
|
await viewModel.SetPublishStateAsync(true);
|
||||||
|
|
||||||
|
Assert.True(api.LastPublishValue);
|
||||||
|
Assert.True(viewModel.DraftIsPublished);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>Test fake that always throws if the API is invoked.</summary>
|
/// <summary>Test fake that always throws if the API is invoked.</summary>
|
||||||
private sealed class ThrowingYavscApiClient : YavscApiClient
|
private sealed class ThrowingYavscApiClient : YavscApiClient
|
||||||
{
|
{
|
||||||
|
|
@ -103,4 +118,34 @@ public class PostItViewModelTests
|
||||||
return Task.FromResult(default(T)!);
|
return Task.FromResult(default(T)!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sealed class RecordingPublishApi : IYavscApiClient
|
||||||
|
{
|
||||||
|
public bool LastPublishValue { get; private set; }
|
||||||
|
public HttpClient Http { get; } = new();
|
||||||
|
|
||||||
|
public Task<T> CallAsync<T>(HttpMethod method, string path, object? body = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
if (method == HttpMethod.Put && path.Contains("/publish", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var publish = body?.GetType().GetProperty("publish")?.GetValue(body) is bool value && value;
|
||||||
|
LastPublishValue = publish;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(default(T)!);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task CallAsync(HttpMethod method, string path, object? body = null, CancellationToken ct = default)
|
||||||
|
{
|
||||||
|
if (method == HttpMethod.Put && path.Contains("/publish", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var publish = body?.GetType().GetProperty("publish")?.GetValue(body) is bool value && value;
|
||||||
|
LastPublishValue = publish;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ValueTask DisposeAsync() => ValueTask.CompletedTask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,8 +190,7 @@ public partial class MainViewModel : ViewModelBase
|
||||||
/// overload; the dedicated endpoint keeps the wire
|
/// overload; the dedicated endpoint keeps the wire
|
||||||
/// contract clean.</para>
|
/// contract clean.</para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[RelayCommand]
|
public async Task SetPublishStateAsync(bool publish)
|
||||||
internal async Task TogglePublishAsync()
|
|
||||||
{
|
{
|
||||||
if (SelectedPost is null || SelectedPost.Id == 0)
|
if (SelectedPost is null || SelectedPost.Id == 0)
|
||||||
{
|
{
|
||||||
|
|
@ -201,20 +200,29 @@ public partial class MainViewModel : ViewModelBase
|
||||||
|
|
||||||
await ExecuteAsync(async () =>
|
await ExecuteAsync(async () =>
|
||||||
{
|
{
|
||||||
var desired = !DraftIsPublished;
|
// The checkbox updates DraftIsPublished before the command is
|
||||||
await BlogClient!.SetPublishAsync(SelectedPost.Id, desired);
|
// executed. Using the current bound value avoids the
|
||||||
DraftIsPublished = desired;
|
// double-toggle bug in which the UI has already flipped the
|
||||||
|
// state and the command flips it again.
|
||||||
|
await BlogClient!.SetPublishAsync(SelectedPost.Id, publish);
|
||||||
|
DraftIsPublished = publish;
|
||||||
// Mirror into the selected post so a subsequent
|
// Mirror into the selected post so a subsequent
|
||||||
// RefreshPostsAsync() doesn't blow away the
|
// RefreshPostsAsync() doesn't blow away the
|
||||||
// locally flipped state until the round-trip
|
// locally flipped state until the round-trip
|
||||||
// re-hydrates it.
|
// re-hydrates it.
|
||||||
SelectedPost.IsPublished = desired;
|
SelectedPost.IsPublished = publish;
|
||||||
StatusMessage = desired
|
StatusMessage = publish
|
||||||
? $"Billet {SelectedPost.Id} publié."
|
? $"Billet {SelectedPost.Id} publié."
|
||||||
: $"Billet {SelectedPost.Id} remis en brouillon.";
|
: $"Billet {SelectedPost.Id} remis en brouillon.";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
internal async Task TogglePublishAsync()
|
||||||
|
{
|
||||||
|
await SetPublishStateAsync(DraftIsPublished);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// DEV ONLY: open the signature capture page. The production
|
/// DEV ONLY: open the signature capture page. The production
|
||||||
/// entry point is a SignalR push from Yavsc.Org ("devis
|
/// entry point is a SignalR push from Yavsc.Org ("devis
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue