Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
41 changes: 41 additions & 0 deletions src/Alba.Testing/Acceptance/specs_against_aspnet_core_app.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net.Http.Headers;
using System.Text;
using System.Net.Mime;
using Shouldly;
using WebApp;
Expand Down Expand Up @@ -112,6 +113,46 @@ public async Task repeated_reads_of_the_response_async()
person.LastName.ShouldBe("Miller");
}

[Fact]
public async Task read_the_response_as_bytes()
{
var expectedJson = "{\"firstName\":\"Jeremy\",\"lastName\":\"Miller\"}";
var result = await run(_ =>
{
_.Get.Url("/api/json");
_.Body.TextIs(expectedJson);
});

result.ReadAsBytes().ShouldBe(Encoding.UTF8.GetBytes(expectedJson));
}

[Fact]
public async Task read_the_response_as_bytes_async()
{
var expectedJson = "{\"firstName\":\"Jeremy\",\"lastName\":\"Miller\"}";
var result = await run(_ =>
{
_.Get.Url("/api/json");
_.Body.TextIs(expectedJson);
});

(await result.ReadAsBytesAsync()).ShouldBe(Encoding.UTF8.GetBytes(expectedJson));
}

[Fact]
public async Task reading_as_bytes_does_not_consume_the_response()
{
var expectedJson = "{\"firstName\":\"Jeremy\",\"lastName\":\"Miller\"}";
var result = await run(_ =>
{
_.Get.Url("/api/json");
_.Body.TextIs(expectedJson);
});

result.ReadAsBytes().Length.ShouldBe(Encoding.UTF8.GetByteCount(expectedJson));
result.ReadAsJson<Person>().FirstName.ShouldBe("Jeremy");
}

[Fact]
public async Task Bug_92_repeated_reads_of_the_response()
{
Expand Down
14 changes: 14 additions & 0 deletions src/Alba/IScenarioResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ public interface IScenarioResult
/// <returns></returns>
Task<string> ReadAsTextAsync();

/// <summary>
/// Read the contents of the HttpResponse.Body as raw bytes, for binary payloads
/// such as files or images that would be corrupted by reading them as text
/// </summary>
/// <returns></returns>
byte[] ReadAsBytes();

/// <summary>
/// Read the contents of the HttpResponse.Body as raw bytes, for binary payloads
/// such as files or images that would be corrupted by reading them as text
/// </summary>
/// <returns></returns>
Task<byte[]> ReadAsBytesAsync();

/// <summary>
/// Read the contents of the HttpResponse.Body into an XmlDocument object
/// </summary>
Expand Down
22 changes: 22 additions & 0 deletions src/Alba/ScenarioResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,28 @@ public Task<string> ReadAsTextAsync()
return ReadAsync(s => s.ReadAllTextAsync());
}

/// <inheritdoc />
public byte[] ReadAsBytes()
{
return Read(s =>
{
var buffer = new MemoryStream();
s.CopyTo(buffer);
return buffer.ToArray();
});
}

/// <inheritdoc />
public Task<byte[]> ReadAsBytesAsync()
{
return ReadAsync(async s =>
{
var buffer = new MemoryStream();
await s.CopyToAsync(buffer);
return buffer.ToArray();
});
}

/// <inheritdoc />
public XmlDocument? ReadAsXml()
{
Expand Down
4 changes: 4 additions & 0 deletions v9_CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,10 @@ happen to contain the text "Error" now parse successfully.
## New features

- **Server-sent events support.** See the [docs page](https://github.com/JasperFx/alba/blob/master/docs/scenarios/sse.md)
- **Binary response reads.** `IScenarioResult.ReadAsBytes()` and `ReadAsBytesAsync()` return the
response body as `byte[]`, for endpoints that return files, images or other payloads that
`ReadAsText()` would corrupt. Like the other readers they leave the body readable, so a scenario
can assert on the bytes and still call `ReadAsJson<T>()` afterwards.
- **HTTP QUERY support.** Scenarios can issue HTTP QUERY requests via `Scenario.Query`, matching
the existing verb properties (`x.Query.Url("/api/query")`).
- **Time-travel testing with `TimeProviderOverride`.** A `FakeTimeProvider`-based extension that
Expand Down