From 45196e022b76391cdc7162618f9bc82d9696bcb9 Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Sat, 28 Feb 2026 19:08:58 +0800 Subject: [PATCH] Add a "wpt" dump mode Adds a not-documented "wpt" mode to --dump which outputs a formatted report.cases. This is meant to make working on a single WPT test case easier, particularly with some coding tool. Claude recommended this output for its own use. Instead of telling claude to start the browser in serve mode, then run the wptrunner, and merge the two outputs (and then stop the server), you can do: zig build run -- fetch --dump wpt "http://localhost:8000/dom/nodes/CharacterData-appendChild.html" (you still need the wpt server up) --- src/Config.zig | 1 + src/lightpanda.zig | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/Config.zig b/src/Config.zig index 2fb59dfc..1e5cc9ab 100644 --- a/src/Config.zig +++ b/src/Config.zig @@ -185,6 +185,7 @@ pub const Serve = struct { pub const DumpFormat = enum { html, markdown, + wpt, }; pub const Fetch = struct { diff --git a/src/lightpanda.zig b/src/lightpanda.zig index ca105ce5..5a30c5ff 100644 --- a/src/lightpanda.zig +++ b/src/lightpanda.zig @@ -105,11 +105,62 @@ pub fn fetch(app: *App, url: [:0]const u8, opts: FetchOpts) !void { switch (mode) { .html => try dump.root(page.window._document, opts.dump, writer, page), .markdown => try markdown.dump(page.window._document.asNode(), .{}, writer, page), + .wpt => try dumpWPT(page, writer), } } try writer.flush(); } +fn dumpWPT(page: *Page, writer: *std.Io.Writer) !void { + var ls: js.Local.Scope = undefined; + page.js.localScope(&ls); + defer ls.deinit(); + + var try_catch: js.TryCatch = undefined; + try_catch.init(&ls.local); + defer try_catch.deinit(); + + // return the detailed result. + const dump_script = + \\ JSON.stringify((() => { + \\ const statuses = ['Pass', 'Fail', 'Timeout', 'Not Run', 'Optional Feature Unsupported']; + \\ const parse = (raw) => { + \\ for (const status of statuses) { + \\ const idx = raw.indexOf('|' + status); + \\ if (idx !== -1) { + \\ const name = raw.slice(0, idx); + \\ const rest = raw.slice(idx + status.length + 1); + \\ const message = rest.length > 0 && rest[0] === '|' ? rest.slice(1) : null; + \\ return { name, status, message }; + \\ } + \\ } + \\ return { name: raw, status: 'Unknown', message: null }; + \\ }; + \\ const cases = Object.values(report.cases).map(parse); + \\ return { + \\ url: window.location.href, + \\ status: report.status, + \\ message: report.message, + \\ summary: { + \\ total: cases.length, + \\ passed: cases.filter(c => c.status === 'Pass').length, + \\ failed: cases.filter(c => c.status === 'Fail').length, + \\ timeout: cases.filter(c => c.status === 'Timeout').length, + \\ notrun: cases.filter(c => c.status === 'Not Run').length, + \\ unsupported: cases.filter(c => c.status === 'Optional Feature Unsupported').length + \\ }, + \\ cases + \\ }; + \\ })(), null, 2) + ; + const value = ls.local.exec(dump_script, "dump_script") catch |err| { + const caught = try_catch.caughtOrError(page.call_arena, err); + return writer.print("Caught error trying to access WPT's report: {f}\n", .{caught}); + }; + try writer.writeAll("== WPT Results==\n"); + try writer.writeAll(try value.toStringSliceWithAlloc(page.call_arena)); +} + pub inline fn assert(ok: bool, comptime ctx: []const u8, args: anytype) void { if (!ok) { if (comptime IS_DEBUG) {