Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
<PackageVersion Include="Nullean.Snapshots" Version="0.4.0" />
<PackageVersion Include="Nullean.Snapshots.AwesomeAssertions" Version="0.4.0" />
<PackageVersion Include="Nullean.Snapshots.Html" Version="0.4.0" />
<PackageVersion Include="Nullean.Snapshots.Http" Version="0.4.0" />
<PackageVersion Include="Nullean.Snapshots.Http.Assertions" Version="0.4.0" />
<PackageVersion Include="Nullean.Snapshots.Json" Version="0.4.0" />
<PackageVersion Include="Nullean.Snapshots.Yaml" Version="0.4.0" />
<PackageVersion Include="Nullean.Snapshots.TUnit" Version="0.4.0" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Mcp.Remote.IntegrationTests</_Parameter1>
</AssemblyAttribute>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Mcp.Remote.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
## valid feedback is stored: PUT /docs/_api/v1/page-feedback/{{$guid}}
status: 204 No Content

## a thumbs down needs a reason: PUT /docs/_api/v1/page-feedback/{{$guid}}
status: 400 Bad Request

## feedback is deleted: DELETE /docs/_api/v1/page-feedback/{{$guid}}
status: 204 No Content
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
<PackageReference Include="Elastic.Transport.VirtualizedCluster" />
<PackageReference Include="FakeItEasy" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Testing" />
<PackageReference Include="Nullean.Snapshots.Http" />
<PackageReference Include="Nullean.Snapshots.Http.Assertions" />
<PackageReference Include="OpenTelemetry.Exporter.InMemory" />
<PackageReference Include="WireMock.Net" />
</ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
using Elastic.Documentation.Api.PageFeedback;
using Elastic.Documentation.Api.Tests.Fixtures;
using FakeItEasy;
using Nullean.Snapshots;
using Nullean.Snapshots.Http;
using Nullean.Snapshots.Json;
using Nullean.Snapshots.TUnit;

namespace Elastic.Documentation.Api.Tests;

Expand All @@ -30,12 +34,34 @@ public static void DisposeSharedFactory()
SharedFactory.Value.Dispose();
}

// The id is replaced by its own text, so a record stored under another id than the request's fails the snapshot.
private static SnapshotOptions ScrubFeedbackId(Guid feedbackId) =>
new SnapshotOptions().Scrub(text => text.Replace(feedbackId.ToString(), "{feedback-id}", StringComparison.OrdinalIgnoreCase));

private static HttpClient CreateClient(IPageFeedbackService feedbackService)
{
FeedbackService.Current = feedbackService;
return SharedFactory.Value.CreateClient();
}

// The requests and the responses they must get are in http/page-feedback.http. The service accepts everything, so
// what the file shows is the endpoint's own validation and status codes.
[Test]
[HttpFiles("http")]
public async Task Run(SnapshotFile file)
{
var feedbackService = A.Fake<IPageFeedbackService>();
A.CallTo(() => feedbackService.UpsertFeedbackAsync(A<PageFeedbackRecord>._, A<CancellationToken>._)).Returns(Task.FromResult(true));
A.CallTo(() => feedbackService.DeleteFeedbackAsync(A<Guid>._, A<CancellationToken>._)).Returns(Task.FromResult(true));
using var client = CreateClient(feedbackService);

await HttpFileTest.RunAsync(
file,
new HttpFileSnapshotOptions { Client = client },
TestContext.Current!.Execution.CancellationToken
);
}

[Test]
public async Task Put_ValidFeedback_RecordsFeedbackWithEuid()
{
Expand All @@ -54,13 +80,23 @@ public async Task Put_ValidFeedback_RecordsFeedbackWithEuid()

response.StatusCode.Should().Be(HttpStatusCode.NoContent);
recorded.Should().NotBeNull();
recorded.FeedbackId.Should().Be(feedbackId);
recorded.PageUrl.Should().Be("/docs/test-page");
recorded.Reaction.Should().Be(PageFeedbackReaction.ThumbsUp);
recorded.Reasons.Should().ContainSingle(r => r == PageFeedbackReason.Accurate);
recorded.ReasonSetVersion.Should().Be(2);
recorded.Comment.Should().Be("Useful page");
recorded.Euid.Should().Be("test-euid");
recorded.Should().MatchInlineJsonSnapshot(
"""
{
"FeedbackId": "{feedback-id}",
"PageUrl": "/docs/test-page",
"PageTitle": "Test page",
"Reaction": "thumbsUp",
"Reasons": [
"accurate"
],
"ReasonSetVersion": 2,
"Comment": "Useful page",
"Euid": "test-euid"
}
""",
options: ScrubFeedbackId(feedbackId)
);
}

[Test]
Expand All @@ -81,15 +117,28 @@ public async Task Put_ReactionOnly_RecordsFeedbackWithoutDetails()
"reaction": "thumbsDown"
}
""";
using var request = CreateRequest(Guid.NewGuid(), payload);
var feedbackId = Guid.NewGuid();
using var request = CreateRequest(feedbackId, payload);

using var response = await client.SendAsync(request, TestContext.Current!.Execution.CancellationToken);

response.StatusCode.Should().Be(HttpStatusCode.NoContent);
recorded.Should().NotBeNull();
recorded.Reasons.Should().BeNull();
recorded.ReasonSetVersion.Should().BeNull();
recorded.Comment.Should().BeNull();
recorded.Should().MatchInlineJsonSnapshot(
"""
{
"FeedbackId": "{feedback-id}",
"PageUrl": "/docs/test-page",
"PageTitle": "Test page",
"Reaction": "thumbsDown",
"Reasons": null,
"ReasonSetVersion": null,
"Comment": null,
"Euid": null
}
""",
options: ScrubFeedbackId(feedbackId)
);
}

[Test]
Expand All @@ -112,13 +161,31 @@ public async Task Put_MultipleReasons_RecordsAllReasons()
"reasonSetVersion": 2
}
""";
using var request = CreateRequest(Guid.NewGuid(), payload);
var feedbackId = Guid.NewGuid();
using var request = CreateRequest(feedbackId, payload);

using var response = await client.SendAsync(request, TestContext.Current!.Execution.CancellationToken);

response.StatusCode.Should().Be(HttpStatusCode.NoContent);
recorded.Should().NotBeNull();
recorded.Reasons.Should().BeEquivalentTo([PageFeedbackReason.Inaccurate, PageFeedbackReason.OutOfDate]);
recorded.Should().MatchInlineJsonSnapshot(
"""
{
"FeedbackId": "{feedback-id}",
"PageUrl": "/docs/test-page",
"PageTitle": "Test page",
"Reaction": "thumbsDown",
"Reasons": [
"inaccurate",
"outOfDate"
],
"ReasonSetVersion": 2,
"Comment": null,
"Euid": null
}
""",
options: ScrubFeedbackId(feedbackId)
);
}

[Test]
Expand Down
27 changes: 27 additions & 0 deletions tests/Elastic.Documentation.Api.Tests/http/page-feedback.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
### valid feedback is stored
PUT /docs/_api/v1/page-feedback/{{$guid}}
Content-Type: application/json
Cookie: euid=test-euid

{
"pageUrl": "/docs/test-page",
"pageTitle": "Test page",
"reaction": "thumbsUp",
"reasons": ["accurate"],
"reasonSetVersion": 2,
"comment": " Useful page "
}

### a thumbs down needs a reason
PUT /docs/_api/v1/page-feedback/{{$guid}}
Content-Type: application/json

{
"pageUrl": "/docs/test-page",
"pageTitle": "Test page",
"reaction": "thumbsDown",
"comment": "Missing a required reason"
}

### feedback is deleted
DELETE /docs/_api/v1/page-feedback/{{$guid}}
Loading
Loading