mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-10-29 07:03:29 +00:00
htmlRunner for ReadableStream tests, fix ReadableStream enqueue
This commit is contained in:
@@ -173,166 +173,5 @@ pub fn _getReader(self: *ReadableStream, _options: ?GetReaderOptions) !ReadableS
|
||||
|
||||
const testing = @import("../../testing.zig");
|
||||
test "streams: ReadableStream" {
|
||||
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" });
|
||||
defer runner.deinit();
|
||||
|
||||
try runner.testCases(&.{
|
||||
.{ "var readResult;", "undefined" },
|
||||
.{
|
||||
\\ const stream = new ReadableStream({
|
||||
\\ start(controller) {
|
||||
\\ controller.enqueue("hello");
|
||||
\\ controller.enqueue("world");
|
||||
\\ controller.close();
|
||||
\\ }
|
||||
\\ });
|
||||
,
|
||||
undefined,
|
||||
},
|
||||
.{
|
||||
\\ const reader = stream.getReader();
|
||||
\\ (async function () { readResult = await reader.read() }());
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
.{ "reader", "[object ReadableStreamDefaultReader]" },
|
||||
.{ "readResult.value", "hello" },
|
||||
.{ "readResult.done", "false" },
|
||||
}, .{});
|
||||
}
|
||||
|
||||
test "streams: ReadableStream cancel and close" {
|
||||
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io" });
|
||||
defer runner.deinit();
|
||||
try runner.testCases(&.{
|
||||
.{ "var readResult; var cancelResult; var closeResult;", "undefined" },
|
||||
|
||||
// Test 1: Stream with controller.close()
|
||||
.{
|
||||
\\ const stream1 = new ReadableStream({
|
||||
\\ start(controller) {
|
||||
\\ controller.enqueue("first");
|
||||
\\ controller.enqueue("second");
|
||||
\\ controller.close();
|
||||
\\ }
|
||||
\\ });
|
||||
,
|
||||
undefined,
|
||||
},
|
||||
.{ "const reader1 = stream1.getReader();", undefined },
|
||||
.{
|
||||
\\ (async function () {
|
||||
\\ readResult = await reader1.read();
|
||||
\\ }());
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
.{ "readResult.value", "first" },
|
||||
.{ "readResult.done", "false" },
|
||||
|
||||
// Read second chunk
|
||||
.{
|
||||
\\ (async function () {
|
||||
\\ readResult = await reader1.read();
|
||||
\\ }());
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
.{ "readResult.value", "second" },
|
||||
.{ "readResult.done", "false" },
|
||||
|
||||
// Read after close - should get done: true
|
||||
.{
|
||||
\\ (async function () {
|
||||
\\ readResult = await reader1.read();
|
||||
\\ }());
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
.{ "readResult.value", "undefined" },
|
||||
.{ "readResult.done", "true" },
|
||||
|
||||
// Test 2: Stream with reader.cancel()
|
||||
.{
|
||||
\\ const stream2 = new ReadableStream({
|
||||
\\ start(controller) {
|
||||
\\ controller.enqueue("data1");
|
||||
\\ controller.enqueue("data2");
|
||||
\\ controller.enqueue("data3");
|
||||
\\ },
|
||||
\\ cancel(reason) {
|
||||
\\ closeResult = `Stream cancelled: ${reason}`;
|
||||
\\ }
|
||||
\\ });
|
||||
,
|
||||
undefined,
|
||||
},
|
||||
.{ "const reader2 = stream2.getReader();", undefined },
|
||||
|
||||
// Read one chunk before canceling
|
||||
.{
|
||||
\\ (async function () {
|
||||
\\ readResult = await reader2.read();
|
||||
\\ }());
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
.{ "readResult.value", "data1" },
|
||||
.{ "readResult.done", "false" },
|
||||
|
||||
// Cancel the stream
|
||||
.{
|
||||
\\ (async function () {
|
||||
\\ cancelResult = await reader2.cancel("user requested");
|
||||
\\ }());
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
.{ "cancelResult", "undefined" },
|
||||
.{ "closeResult", "Stream cancelled: user requested" },
|
||||
|
||||
// Try to read after cancel - should throw or return done
|
||||
.{
|
||||
\\ try {
|
||||
\\ (async function () {
|
||||
\\ readResult = await reader2.read();
|
||||
\\ }());
|
||||
\\ } catch(e) {
|
||||
\\ readResult = { error: e.name };
|
||||
\\ }
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
|
||||
// Test 3: Cancel without reason
|
||||
.{
|
||||
\\ const stream3 = new ReadableStream({
|
||||
\\ start(controller) {
|
||||
\\ controller.enqueue("test");
|
||||
\\ },
|
||||
\\ cancel(reason) {
|
||||
\\ closeResult = reason === undefined ? "no reason" : reason;
|
||||
\\ }
|
||||
\\ });
|
||||
,
|
||||
undefined,
|
||||
},
|
||||
.{ "const reader3 = stream3.getReader();", undefined },
|
||||
.{
|
||||
\\ (async function () {
|
||||
\\ await reader3.cancel();
|
||||
\\ }());
|
||||
\\ false;
|
||||
,
|
||||
"false",
|
||||
},
|
||||
.{ "closeResult", "no reason" },
|
||||
}, .{});
|
||||
try testing.htmlRunner("streams/readable_stream.html");
|
||||
}
|
||||
|
||||
@@ -59,13 +59,15 @@ pub fn _enqueue(self: *ReadableStreamDefaultController, chunk: []const u8, page:
|
||||
return error.TypeError;
|
||||
}
|
||||
|
||||
const duped_chunk = try page.arena.dupe(u8, chunk);
|
||||
|
||||
if (self.stream.reader_resolver) |*rr| {
|
||||
defer rr.deinit();
|
||||
try rr.resolve(ReadableStreamReadResult{ .value = .{ .data = chunk }, .done = false });
|
||||
try rr.resolve(ReadableStreamReadResult{ .value = .{ .data = duped_chunk }, .done = false });
|
||||
self.stream.reader_resolver = null;
|
||||
}
|
||||
|
||||
try self.stream.queue.append(page.arena, chunk);
|
||||
try self.stream.queue.append(page.arena, duped_chunk);
|
||||
try self.stream.pullIf();
|
||||
}
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ pub fn _read(self: *const ReadableStreamDefaultReader, page: *Page) !Env.Promise
|
||||
if (stream.queue.items.len > 0) {
|
||||
const data = self.stream.queue.orderedRemove(0);
|
||||
const resolver = page.main_context.createPromiseResolver();
|
||||
|
||||
try resolver.resolve(ReadableStreamReadResult{ .value = .{ .data = data }, .done = false });
|
||||
try self.stream.pullIf();
|
||||
return resolver.promise();
|
||||
|
||||
117
src/tests/streams/readable_stream.html
Normal file
117
src/tests/streams/readable_stream.html
Normal file
@@ -0,0 +1,117 @@
|
||||
<script src="../testing.js"></script>
|
||||
|
||||
<script id=readable_stream>
|
||||
const stream = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("hello");
|
||||
controller.enqueue("world");
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
|
||||
const reader = stream.getReader();
|
||||
|
||||
testing.async(reader.read(), (data) => {
|
||||
testing.expectEqual("hello", data.value);
|
||||
testing.expectEqual(false, data.done);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=readable_stream_close>
|
||||
var closeResult;
|
||||
|
||||
const stream1 = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("first");
|
||||
controller.enqueue("second");
|
||||
controller.close();
|
||||
}
|
||||
});
|
||||
|
||||
const reader1 = stream1.getReader();
|
||||
|
||||
testing.async(reader1.read(), (data) => {
|
||||
testing.expectEqual("first", data.value);
|
||||
testing.expectEqual(false, data.done);
|
||||
});
|
||||
|
||||
testing.async(reader1.read(), (data) => {
|
||||
testing.expectEqual("second", data.value);
|
||||
testing.expectEqual(false, data.done);
|
||||
});
|
||||
|
||||
testing.async(reader1.read(), (data) => {
|
||||
testing.expectEqual(undefined, data.value);
|
||||
testing.expectEqual(true, data.done);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=readable_stream_cancel>
|
||||
var readResult;
|
||||
var cancelResult;
|
||||
var closeResult;
|
||||
|
||||
const stream2 = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("data1");
|
||||
controller.enqueue("data2");
|
||||
controller.enqueue("data3");
|
||||
},
|
||||
cancel(reason) {
|
||||
closeResult = `Stream cancelled: ${reason}`;
|
||||
}
|
||||
});
|
||||
|
||||
const reader2 = stream2.getReader();
|
||||
|
||||
testing.async(reader2.read(), (data) => {
|
||||
testing.expectEqual("data1", data.value);
|
||||
testing.expectEqual(false, data.done);
|
||||
});
|
||||
|
||||
testing.async(reader2.cancel("user requested"), (result) => {
|
||||
testing.expectEqual(undefined, result);
|
||||
testing.expectEqual("Stream cancelled: user requested", closeResult);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=readable_stream_cancel_no_reason>
|
||||
var closeResult2;
|
||||
|
||||
const stream3 = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("test");
|
||||
},
|
||||
cancel(reason) {
|
||||
closeResult2 = reason === undefined ? "no reason" : reason;
|
||||
}
|
||||
});
|
||||
|
||||
const reader3 = stream3.getReader();
|
||||
|
||||
testing.async(reader3.cancel(), (result) => {
|
||||
testing.expectEqual(undefined, result);
|
||||
testing.expectEqual("no reason", closeResult2);
|
||||
});
|
||||
</script>
|
||||
|
||||
<script id=readable_stream_read_after_cancel>
|
||||
var readAfterCancelResult;
|
||||
|
||||
const stream4 = new ReadableStream({
|
||||
start(controller) {
|
||||
controller.enqueue("before_cancel");
|
||||
},
|
||||
});
|
||||
|
||||
const reader4 = stream4.getReader();
|
||||
|
||||
testing.async(reader4.cancel("test cancel"), (cancelResult) => {
|
||||
testing.expectEqual(undefined, cancelResult);
|
||||
});
|
||||
|
||||
testing.async(reader4.read(), (data) => {
|
||||
testing.expectEqual(undefined, data.value);
|
||||
testing.expectEqual(true, data.done);
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user