93 lines
4.4 KiB
C#
93 lines
4.4 KiB
C#
using System.Net;
|
|
using System.Net.Http.Json;
|
|
using ItWorx.KnowledgeHub.Contracts.Knowledge;
|
|
using ItWorx.KnowledgeHub.IntegrationTests.Infrastructure;
|
|
|
|
namespace ItWorx.KnowledgeHub.IntegrationTests.Knowledge;
|
|
|
|
/// <summary>Autosaved drafts survive navigation/restart without overwriting a newer
|
|
/// server revision (docs/27-acceptance-matrix.md, M2-A04).</summary>
|
|
[Collection(PostgresTestGroup.Name)]
|
|
public sealed class DraftAutosaveTests(PostgresContainerFixture postgres) : OwnerSetupTestBase(postgres)
|
|
{
|
|
[Fact]
|
|
public async Task A_saved_draft_can_be_retrieved_later_as_if_after_a_browser_restart()
|
|
{
|
|
using var writer = Factory.CreateClient();
|
|
await SetupHelper.LoginAsync(writer, OwnerEmail, OwnerPassword);
|
|
|
|
var draftKey = $"new-page-{Guid.NewGuid():N}";
|
|
var saveResponse = await SetupHelper.PutWithCsrfAsync(
|
|
writer, $"/api/v1/drafts/{draftKey}", new SaveDraftRequest(null, null, "Concepttitel", "Conceptinhoud"));
|
|
Assert.Equal(HttpStatusCode.OK, saveResponse.StatusCode);
|
|
|
|
// A brand new HttpClient with its own (empty) cookie jar, logging in again —
|
|
// simulating the browser having fully restarted.
|
|
using var afterRestart = Factory.CreateClient();
|
|
await SetupHelper.LoginAsync(afterRestart, OwnerEmail, OwnerPassword);
|
|
|
|
var fetched = await afterRestart.GetFromJsonAsync<DraftResponse>($"/api/v1/drafts/{draftKey}");
|
|
Assert.NotNull(fetched);
|
|
Assert.Equal("Concepttitel", fetched.Title);
|
|
Assert.Equal("Conceptinhoud", fetched.Markdown);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Saving_a_draft_against_an_outdated_base_revision_is_flagged_as_stale_not_silently_accepted()
|
|
{
|
|
using var client = Factory.CreateClient();
|
|
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
|
|
|
var createResponse = await SetupHelper.PostWithCsrfAsync(
|
|
client, "/api/v1/pages", new CreatePageRequest(null, "Concepttest pagina", "WikiPage", "Origineel", null));
|
|
var page = await createResponse.Content.ReadFromJsonAsync<PageDetail>();
|
|
Assert.NotNull(page);
|
|
|
|
// A draft is started against revision 1...
|
|
var draftKey = page.Id.ToString();
|
|
await SetupHelper.PutWithCsrfAsync(
|
|
client, $"/api/v1/drafts/{draftKey}", new SaveDraftRequest(page.Id, page.CurrentRevisionNumber, page.Title, "Conceptwijziging"));
|
|
|
|
// ...but someone else (or another tab) publishes revision 2 in the meantime.
|
|
await SetupHelper.PutWithCsrfAsync(
|
|
client,
|
|
$"/api/v1/pages/{page.Id}",
|
|
new UpdatePageRequest("Gepubliceerde titel", "Gepubliceerde inhoud", "WikiPage", "Active", null),
|
|
page.ETag);
|
|
|
|
// Saving the draft again must surface that its base revision is now stale,
|
|
// rather than silently proceeding as if nothing happened.
|
|
var staleSave = await SetupHelper.PutWithCsrfAsync(
|
|
client, $"/api/v1/drafts/{draftKey}", new SaveDraftRequest(page.Id, page.CurrentRevisionNumber, page.Title, "Nog een conceptwijziging"));
|
|
var staleDraft = await staleSave.Content.ReadFromJsonAsync<DraftResponse>();
|
|
|
|
Assert.NotNull(staleDraft);
|
|
Assert.True(staleDraft.BaseRevisionIsStale);
|
|
|
|
// Crucially, the published page itself was never overwritten by the draft.
|
|
var currentPage = await client.GetFromJsonAsync<PageDetail>($"/api/v1/pages/{page.Id}");
|
|
Assert.NotNull(currentPage);
|
|
Assert.Equal("Gepubliceerde titel", currentPage.Title);
|
|
}
|
|
|
|
[Fact]
|
|
public async Task Discarding_a_draft_removes_it()
|
|
{
|
|
using var client = Factory.CreateClient();
|
|
await SetupHelper.LoginAsync(client, OwnerEmail, OwnerPassword);
|
|
|
|
var draftKey = $"discard-me-{Guid.NewGuid():N}";
|
|
await SetupHelper.PutWithCsrfAsync(
|
|
client, $"/api/v1/drafts/{draftKey}", new SaveDraftRequest(null, null, "Weg te gooien", "Inhoud"));
|
|
|
|
var csrf = await SetupHelper.GetCsrfTokenAsync(client);
|
|
using var request = new HttpRequestMessage(HttpMethod.Delete, $"/api/v1/drafts/{draftKey}");
|
|
request.Headers.Add(csrf.HeaderName, csrf.Value);
|
|
using var deleteResponse = await client.SendAsync(request);
|
|
Assert.Equal(HttpStatusCode.OK, deleteResponse.StatusCode);
|
|
|
|
var getResponse = await client.GetAsync($"/api/v1/drafts/{draftKey}");
|
|
Assert.Equal(HttpStatusCode.NotFound, getResponse.StatusCode);
|
|
}
|
|
}
|