migrate more tests to htmlRunner

This commit is contained in:
Karl Seguin
2025-09-11 12:07:17 +08:00
parent 31fe2807aa
commit ede35718ae
26 changed files with 602 additions and 631 deletions

View File

@@ -138,44 +138,6 @@ const TimeoutCallback = struct {
};
const testing = @import("../../testing.zig");
test "Browser.HTML.AbortController" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "var called = 0", null },
.{ "var a1 = new AbortController()", null },
.{ "var s1 = a1.signal", null },
.{ "s1.throwIfAborted()", "undefined" },
.{ "s1.reason", "undefined" },
.{ "var target;", null },
.{
\\ s1.addEventListener('abort', (e) => {
\\ called += 1;
\\ target = e.target;
\\
\\ });
,
null,
},
.{ "a1.abort()", null },
.{ "s1.aborted", "true" },
.{ "target == s1", "true" },
.{ "s1.reason", "AbortError" },
.{ "called", "1" },
}, .{});
try runner.testCases(&.{
.{ "var s2 = AbortSignal.abort('over 9000')", null },
.{ "s2.aborted", "true" },
.{ "s2.reason", "over 9000" },
.{ "AbortSignal.abort().reason", "AbortError" },
}, .{});
try runner.testCases(&.{
.{ "var s3 = AbortSignal.timeout(10)", null },
.{ "s3.aborted", "true" },
.{ "s3.reason", "TimeoutError" },
.{ "try { s3.throwIfAborted() } catch (e) { e }", "Error: TimeoutError" },
}, .{});
test "Browser: HTML.AbortController" {
try testing.htmlRunner("html/abort_controller.html");
}

View File

@@ -76,22 +76,6 @@ fn normalize(allocator: Allocator, name: []const u8) ![]const u8 {
}
const testing = @import("../../testing.zig");
test "Browser.HTML.DataSet" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html = "" });
defer runner.deinit();
try runner.testCases(&.{
.{ "let el1 = document.createElement('div')", null },
.{ "el1.dataset.x", "undefined" },
.{ "el1.dataset.x = '123'", "123" },
.{ "delete el1.dataset.x", "true" },
.{ "el1.dataset.x", "undefined" },
.{ "delete el1.dataset.other", "true" }, // yes, this is right
.{ "let ds1 = el1.dataset", null },
.{ "ds1.helloWorld = 'yes'", null },
.{ "el1.getAttribute('data-hello-world')", "yes" },
.{ "el1.setAttribute('data-this-will-work', 'positive')", null },
.{ "ds1.thisWillWork", "positive" },
}, .{});
test "Browser: HTML.DataSet" {
try testing.htmlRunner("html/dataset.html");
}

View File

@@ -314,116 +314,7 @@ pub const HTMLDocument = struct {
}
};
// Tests
// -----
const testing = @import("../../testing.zig");
test "Browser.HTML.Document" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "document.__proto__.constructor.name", "HTMLDocument" },
.{ "document.__proto__.__proto__.constructor.name", "Document" },
.{ "document.body.localName == 'body'", "true" },
}, .{});
try runner.testCases(&.{
.{ "document.domain", "lightpanda.io" },
.{ "document.referrer", "" },
.{ "document.title", "" },
.{ "document.body.localName", "body" },
.{ "document.head.localName", "head" },
.{ "document.images.length", "0" },
.{ "document.embeds.length", "0" },
.{ "document.plugins.length", "0" },
.{ "document.scripts.length", "0" },
.{ "document.forms.length", "0" },
.{ "document.links.length", "1" },
.{ "document.applets.length", "0" },
.{ "document.anchors.length", "0" },
.{ "document.all.length", "8" },
.{ "document.currentScript", "null" },
}, .{});
try runner.testCases(&.{
.{ "document.title = 'foo'", "foo" },
.{ "document.title", "foo" },
.{ "document.title = ''", "" },
}, .{});
try runner.testCases(&.{
.{ "document.getElementById('link').setAttribute('name', 'foo')", "undefined" },
.{ "let list = document.getElementsByName('foo')", "undefined" },
.{ "list.length", "1" },
}, .{});
try runner.testCases(&.{
.{ "document.cookie", "" },
.{ "document.cookie = 'name=Oeschger; SameSite=None; Secure'", "name=Oeschger; SameSite=None; Secure" },
.{ "document.cookie = 'favorite_food=tripe; SameSite=None; Secure'", "favorite_food=tripe; SameSite=None; Secure" },
.{ "document.cookie", "name=Oeschger; favorite_food=tripe" },
.{ "document.cookie = 'IgnoreMy=Ghost; HttpOnly'", null }, // "" should be returned, but the framework overrules it atm
.{ "document.cookie", "name=Oeschger; favorite_food=tripe" },
}, .{});
try runner.testCases(&.{
.{ "document.elementFromPoint(0.5, 0.5)", "null" }, // Return null since we only return element s when they have previously been localized
.{ "document.elementsFromPoint(0.5, 0.5)", "" },
.{
\\ let div1 = document.createElement('div');
\\ document.body.appendChild(div1);
\\ div1.getClientRects();
,
null,
},
.{ "document.elementFromPoint(0.5, 0.5)", "[object HTMLDivElement]" },
.{ "let elems = document.elementsFromPoint(0.5, 0.5)", null },
.{ "elems.length", "3" },
.{ "elems[0]", "[object HTMLDivElement]" },
.{ "elems[1]", "[object HTMLBodyElement]" },
.{ "elems[2]", "[object HTMLHtmlElement]" },
}, .{});
try runner.testCases(&.{
.{
\\ let a = document.createElement('a');
\\ a.href = "https://lightpanda.io";
\\ document.body.appendChild(a);
\\ a.getClientRects();
, // Note this will be placed after the div of previous test
null,
},
.{ "let a_again = document.elementFromPoint(1.5, 0.5)", null },
.{ "a_again", "[object HTMLAnchorElement]" },
.{ "a_again.href", "https://lightpanda.io" },
.{ "let a_agains = document.elementsFromPoint(1.5, 0.5)", null },
.{ "a_agains[0].href", "https://lightpanda.io" },
}, .{});
try runner.testCases(&.{
.{ "!document.all", "true" },
.{ "!!document.all", "false" },
.{ "document.all(5)", "[object HTMLParagraphElement]" },
.{ "document.all('content')", "[object HTMLDivElement]" },
}, .{});
try runner.testCases(&.{
.{ "document.defaultView.document == document", "true" },
}, .{});
try runner.testCases(&.{
.{ "document.readyState", "loading" },
}, .{});
try HTMLDocument.documentIsLoaded(runner.page.window.document, runner.page);
try runner.testCases(&.{
.{ "document.readyState", "interactive" },
}, .{});
try HTMLDocument.documentIsComplete(runner.page.window.document, runner.page);
try runner.testCases(&.{
.{ "document.readyState", "complete" },
}, .{});
test "Browser: HTML.Document" {
try testing.htmlRunner("html/document.html");
}

View File

@@ -1285,336 +1285,35 @@ pub fn toInterfaceFromTag(comptime T: type, e: *parser.Element, tag: parser.Tag)
}
const testing = @import("../../testing.zig");
test "Browser.HTML.Element" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "let link = document.getElementById('link')", "undefined" },
.{ "link.target", "" },
.{ "link.target = '_blank'", "_blank" },
.{ "link.target", "_blank" },
.{ "link.target = ''", "" },
.{ "link.href", "foo" },
.{ "link.href = 'https://lightpanda.io/'", "https://lightpanda.io/" },
.{ "link.href", "https://lightpanda.io/" },
.{ "link.origin", "https://lightpanda.io" },
.{ "link.host = 'lightpanda.io:443'", "lightpanda.io:443" },
.{ "link.host", "lightpanda.io:443" },
.{ "link.port", "443" },
.{ "link.hostname", "lightpanda.io" },
.{ "link.host = 'lightpanda.io'", "lightpanda.io" },
.{ "link.host", "lightpanda.io" },
.{ "link.port", "" },
.{ "link.hostname", "lightpanda.io" },
.{ "link.host", "lightpanda.io" },
.{ "link.hostname", "lightpanda.io" },
.{ "link.hostname = 'foo.bar'", "foo.bar" },
.{ "link.href", "https://foo.bar/" },
.{ "link.search", "" },
.{ "link.search = 'q=bar'", "q=bar" },
.{ "link.search", "?q=bar" },
.{ "link.href", "https://foo.bar/?q=bar" },
.{ "link.hash", "" },
.{ "link.hash = 'frag'", "frag" },
.{ "link.hash", "#frag" },
.{ "link.href", "https://foo.bar/?q=bar#frag" },
.{ "link.port", "" },
.{ "link.port = '443'", "443" },
.{ "link.host", "foo.bar:443" },
.{ "link.hostname", "foo.bar" },
.{ "link.href", "https://foo.bar:443/?q=bar#frag" },
.{ "link.port = null", "null" },
.{ "link.href", "https://foo.bar/?q=bar#frag" },
.{ "link.href = 'foo'", "foo" },
.{ "link.type", "" },
.{ "link.type = 'text/html'", "text/html" },
.{ "link.type", "text/html" },
.{ "link.type = ''", "" },
.{ "link.text", "OK" },
.{ "link.text = 'foo'", "foo" },
.{ "link.text", "foo" },
.{ "link.text = 'OK'", "OK" },
}, .{});
try runner.testCases(&.{
.{ "let script = document.createElement('script')", "undefined" },
.{ "script.src = 'foo.bar'", "foo.bar" },
.{ "script.async = true", "true" },
.{ "script.async", "true" },
.{ "script.async = false", "false" },
.{ "script.async", "false" },
}, .{});
try runner.testCases(&.{
.{ "const backup = document.getElementById('content')", "undefined" },
.{ "document.getElementById('content').innerText = 'foo';", "foo" },
.{ "document.getElementById('content').innerText", "foo" },
.{ "document.getElementById('content').innerHTML = backup; true;", "true" },
}, .{});
try runner.testCases(&.{
.{ "let click_count = 0;", "undefined" },
.{ "let clickCbk = function() { click_count++ }", "undefined" },
.{ "document.getElementById('content').addEventListener('click', clickCbk);", "undefined" },
.{ "document.getElementById('content').click()", "undefined" },
.{ "click_count", "1" },
}, .{});
try runner.testCases(&.{
.{ "let style = document.getElementById('content').style", "undefined" },
.{ "style.cssText = 'color: red; font-size: 12px; margin: 5px !important;'", "color: red; font-size: 12px; margin: 5px !important;" },
.{ "style.length", "3" },
.{ "style.setProperty('background-color', 'blue')", "undefined" },
.{ "style.getPropertyValue('background-color')", "blue" },
.{ "style.length", "4" },
}, .{});
// Image
try runner.testCases(&.{
// Testing constructors
.{ "(new Image).width", "0" },
.{ "(new Image).height", "0" },
.{ "(new Image(4)).width", "4" },
.{ "(new Image(4, 6)).height", "6" },
// Testing ulong property
.{ "let fruit = new Image", null },
.{ "fruit.width", "0" },
.{ "fruit.width = 5", "5" },
.{ "fruit.width", "5" },
.{ "fruit.width = '15'", "15" },
.{ "fruit.width", "15" },
.{ "fruit.width = 'apple'", "apple" },
.{ "fruit.width;", "0" },
// Testing string property
.{ "let lyric = new Image", null },
.{ "lyric.src", "" },
.{ "lyric.src = 'okay'", "okay" },
.{ "lyric.src", "okay" },
.{ "lyric.src = 15", "15" },
.{ "lyric.src", "15" },
}, .{});
try runner.testCases(&.{
.{ "let a = document.createElement('a');", null },
.{ "a.href", "" },
.{ "a.host", "" },
.{ "a.href = 'about'", null },
.{ "a.href", "https://lightpanda.io/opensource-browser/about" },
}, .{});
// detached node cannot be focused
try runner.testCases(&.{
.{ "const focused = document.activeElement", null },
.{ "document.createElement('a').focus()", null },
.{ "document.activeElement === focused", "true" },
}, .{});
try runner.testCases(&.{
.{ "let l2 = document.createElement('link');", null },
.{ "l2.href", "" },
.{ "l2.href = 'https://lightpanda.io/opensource-browser/15'", null },
.{ "l2.href", "https://lightpanda.io/opensource-browser/15" },
.{ "l2.href = '/over/9000'", null },
.{ "l2.href", "https://lightpanda.io/over/9000" },
}, .{});
test "Browser: HTML.Element" {
try testing.htmlRunner("html/element.html");
}
test "Browser.HTML.Element.DataSet" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html = "<div id=x data-power='over 9000' data-empty data-some-long-key=ok></div>" });
defer runner.deinit();
try runner.testCases(&.{ .{ "let div = document.getElementById('x')", null }, .{ "div.dataset.nope", "undefined" }, .{ "div.dataset.power", "over 9000" }, .{ "div.dataset.empty", "" }, .{ "div.dataset.someLongKey", "ok" }, .{ "delete div.dataset.power", "true" }, .{ "div.dataset.power", "undefined" } }, .{});
test "Browser: HTML.HtmlLinkElement" {
try testing.htmlRunner("html/link.html");
}
test "Browser.HTML.HtmlInputElement.properties" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .url = "https://lightpanda.io/noslashattheend" });
defer runner.deinit();
var alloc = std.heap.ArenaAllocator.init(runner.allocator);
defer alloc.deinit();
const arena = alloc.allocator();
try runner.testCases(&.{.{ "let elem_input = document.createElement('input')", null }}, .{});
try runner.testCases(&.{.{ "elem_input.form", "null" }}, .{}); // Initial value
// Valid input.form is tested separately :Browser.HTML.HtmlInputElement.propeties.form
try testProperty(arena, &runner, "elem_input.form", "null", &.{.{ .input = "'foo'" }}); // Invalid
try runner.testCases(&.{.{ "elem_input.accept", "" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.accept", null, &str_valids); // Valid
try runner.testCases(&.{.{ "elem_input.alt", "" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.alt", null, &str_valids); // Valid
try runner.testCases(&.{.{ "elem_input.disabled", "false" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.disabled", null, &bool_valids); // Valid
try runner.testCases(&.{.{ "elem_input.maxLength", "-1" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.maxLength", null, &.{.{ .input = "5" }}); // Valid
try testProperty(arena, &runner, "elem_input.maxLength", "0", &.{.{ .input = "'banana'" }}); // Invalid
try runner.testCases(&.{.{ "try { elem_input.maxLength = -45 } catch(e) {e}", "Error: NegativeValueNotAllowed" }}, .{}); // Error
try runner.testCases(&.{.{ "elem_input.name", "" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.name", null, &str_valids); // Valid
try runner.testCases(&.{.{ "elem_input.readOnly", "false" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.readOnly", null, &bool_valids); // Valid
try runner.testCases(&.{.{ "elem_input.size", "20" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.size", null, &.{.{ .input = "5" }}); // Valid
try testProperty(arena, &runner, "elem_input.size", "20", &.{.{ .input = "-26" }}); // Invalid
try runner.testCases(&.{.{ "try { elem_input.size = 0 } catch(e) {e}", "Error: ZeroNotAllowed" }}, .{}); // Error
try runner.testCases(&.{.{ "try { elem_input.size = 'banana' } catch(e) {e}", "Error: ZeroNotAllowed" }}, .{}); // Error
try runner.testCases(&.{.{ "elem_input.src", "" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.src", null, &.{
.{ .input = "'foo'", .expected = "https://lightpanda.io/foo" }, // TODO stitch should work with spaces -> %20
.{ .input = "-3", .expected = "https://lightpanda.io/-3" },
.{ .input = "''", .expected = "https://lightpanda.io/noslashattheend" },
});
try runner.testCases(&.{.{ "elem_input.type", "text" }}, .{}); // Initial value
try testProperty(arena, &runner, "elem_input.type", null, &.{.{ .input = "'checkbox'", .expected = "checkbox" }}); // Valid
try testProperty(arena, &runner, "elem_input.type", "text", &.{.{ .input = "'5'" }}); // Invalid
// Properties that are related
try runner.testCases(&.{
.{ "let input_checked = document.createElement('input')", null },
.{ "input_checked.defaultChecked", "false" },
.{ "input_checked.checked", "false" },
.{ "input_checked.defaultChecked = true", "true" },
.{ "input_checked.defaultChecked", "true" },
.{ "input_checked.checked", "true" }, // Also perceived as true
.{ "input_checked.checked = false", "false" },
.{ "input_checked.defaultChecked", "true" },
.{ "input_checked.checked", "false" },
.{ "input_checked.defaultChecked = true", "true" },
.{ "input_checked.checked", "false" }, // Still false
}, .{});
try runner.testCases(&.{
.{ "let input_value = document.createElement('input')", null },
.{ "input_value.defaultValue", "" },
.{ "input_value.value", "" },
.{ "input_value.defaultValue = 3.1", "3.1" },
.{ "input_value.defaultValue", "3.1" },
.{ "input_value.value", "3.1" }, // Also perceived as 3.1
.{ "input_value.value = 'mango'", "mango" },
.{ "input_value.defaultValue", "3.1" },
.{ "input_value.value", "mango" },
.{ "input_value.defaultValue = true", "true" },
.{ "input_value.value", "mango" }, // Still mango
}, .{});
test "Browser: HTML.HtmlImageElement" {
try testing.htmlRunner("html/image.html");
}
test "Browser.HTML.HtmlInputElement.properties.form" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html =
\\ <form action="test.php" target="_blank">
\\ <p>
\\ <label>First name: <input type="text" name="first-name" /></label>
\\ </p>
\\ </form>
});
defer runner.deinit();
try runner.testCases(&.{
.{ "let elem_input = document.querySelector('input')", null },
.{ "elem_input.form", "[object HTMLFormElement]" }, // Initial value
.{ "elem_input.form = 'foo'", null },
.{ "elem_input.form", "[object HTMLFormElement]" }, // Invalid
}, .{});
test "Browser: HTML.HtmlInputElement" {
try testing.htmlRunner("html/input.html");
}
test "Browser.HTML.HTMLTemplateElement" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html = "<div id=c></div>" });
defer runner.deinit();
try runner.testCases(&.{
.{ "let t = document.createElement('template')", null },
.{ "let d = document.createElement('div')", null },
.{ "d.id = 'abc'", null },
.{ "t.content.append(d)", null },
.{ "document.getElementById('abc')", "null" },
.{ "document.getElementById('c').appendChild(t.content.cloneNode(true))", null },
.{ "document.getElementById('abc').id", "abc" },
.{ "t.innerHTML = '<span>over</span><p>9000!</p>';", null },
.{ "t.content.childNodes.length", "2" },
.{ "t.content.childNodes[0].tagName", "SPAN" },
.{ "t.content.childNodes[0].innerHTML", "over" },
.{ "t.content.childNodes[1].tagName", "P" },
.{ "t.content.childNodes[1].innerHTML", "9000!" },
}, .{});
test "Browser: HTML.HtmlTemplateElement" {
try testing.htmlRunner("html/template.html");
}
test "Browser.HTML.HTMLStyleElement" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html = "" });
defer runner.deinit();
try runner.testCases(&.{
.{ "let s = document.createElement('style')", null },
.{ "s.sheet.type", "text/css" },
.{ "s.sheet == s.sheet", "true" },
.{ "document.createElement('style').sheet == s.sheet", "false" },
}, .{});
test "Browser: HTML.HtmlStyleElement" {
try testing.htmlRunner("html/style.html");
}
test "Browser: HTML.HTMLScriptElement" {
test "Browser: HTML.HtmlScriptElement" {
try testing.htmlRunner("html/script/script.html");
try testing.htmlRunner("html/script/inline_defer.html");
}
test "Browser: HTML.HTMLSlotElement" {
try testing.htmlRunner("html/html_slot_element.html");
}
const Check = struct {
input: []const u8,
expected: ?[]const u8 = null, // Needed when input != expected
};
const bool_valids = [_]Check{
.{ .input = "true" },
.{ .input = "''", .expected = "false" },
.{ .input = "13.5", .expected = "true" },
};
const str_valids = [_]Check{
.{ .input = "'foo'", .expected = "foo" },
.{ .input = "5", .expected = "5" },
.{ .input = "''", .expected = "" },
.{ .input = "document", .expected = "[object HTMLDocument]" },
};
// .{ "elem.type = '5'", "5" },
// .{ "elem.type", "text" },
fn testProperty(
arena: std.mem.Allocator,
runner: *testing.JsRunner,
elem_dot_prop: []const u8,
always: ?[]const u8, // Ignores checks' expected if set
checks: []const Check,
) !void {
for (checks) |check| {
try runner.testCases(&.{
.{ try std.mem.concat(arena, u8, &.{ elem_dot_prop, " = ", check.input }), null },
.{ elem_dot_prop, always orelse check.expected orelse check.input },
}, .{});
}
test "Browser: HTML.HtmlSlotElement" {
try testing.htmlRunner("html/slot.html");
}

View File

@@ -87,34 +87,7 @@ pub const History = struct {
}
};
// Tests
// -----
const testing = @import("../../testing.zig");
test "Browser.HTML.History" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "history.scrollRestoration", "auto" },
.{ "history.scrollRestoration = 'manual'", "manual" },
.{ "history.scrollRestoration = 'foo'", "foo" },
.{ "history.scrollRestoration", "manual" },
.{ "history.scrollRestoration = 'auto'", "auto" },
.{ "history.scrollRestoration", "auto" },
.{ "history.state", "null" },
.{ "history.pushState({}, null, '')", "undefined" },
.{ "history.replaceState({}, null, '')", "undefined" },
.{ "history.go()", "undefined" },
.{ "history.go(1)", "undefined" },
.{ "history.go(-1)", "undefined" },
.{ "history.forward()", "undefined" },
.{ "history.back()", "undefined" },
}, .{});
test "Browser: HTML.History" {
try testing.htmlRunner("html/history.html");
}

View File

@@ -87,20 +87,6 @@ pub const Location = struct {
};
const testing = @import("../../testing.zig");
test "Browser.HTML.Location" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "location.href", "https://lightpanda.io/opensource-browser/" },
.{ "document.location.href", "https://lightpanda.io/opensource-browser/" },
.{ "location.host", "lightpanda.io" },
.{ "location.hostname", "lightpanda.io" },
.{ "location.origin", "https://lightpanda.io" },
.{ "location.pathname", "/opensource-browser/" },
.{ "location.hash", "" },
.{ "location.port", "" },
.{ "location.search", "" },
}, .{});
test "Browser: HTML.Location" {
try testing.htmlRunner("html/location.html");
}

View File

@@ -80,17 +80,7 @@ pub const Navigator = struct {
}
};
// Tests
// -----
const testing = @import("../../testing.zig");
test "Browser.HTML.Navigator" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "navigator.userAgent", "Lightpanda/1.0" },
.{ "navigator.appVersion", "1.0" },
.{ "navigator.language", "en-US" },
}, .{});
test "Browser: HTML.Navigator" {
try testing.htmlRunner("html/navigator.html");
}

View File

@@ -199,80 +199,6 @@ pub const HTMLOptionsCollection = struct {
};
const testing = @import("../../testing.zig");
test "Browser.HTML.Select" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{ .html =
\\ <form id=f1>
\\ <select id=s1 name=s1><option>o1<option>o2</select>
\\ </form>
\\ <select id=s2></select>
});
defer runner.deinit();
try runner.testCases(&.{
.{ "const s = document.getElementById('s1');", null },
.{ "s.form", "[object HTMLFormElement]" },
.{ "document.getElementById('s2').form", "null" },
.{ "s.disabled", "false" },
.{ "s.disabled = true", null },
.{ "s.disabled", "true" },
.{ "s.disabled = false", null },
.{ "s.disabled", "false" },
.{ "s.multiple", "false" },
.{ "s.multiple = true", null },
.{ "s.multiple", "true" },
.{ "s.multiple = false", null },
.{ "s.multiple", "false" },
.{ "s.name;", "s1" },
.{ "s.name = 'sel1';", null },
.{ "s.name", "sel1" },
.{ "s.length;", "2" },
.{ "s.selectedIndex", "0" },
.{ "s.selectedIndex = 2", null }, // out of range
.{ "s.selectedIndex", "-1" },
.{ "s.selectedIndex = -1", null },
.{ "s.selectedIndex", "-1" },
.{ "s.selectedIndex = 0", null },
.{ "s.selectedIndex", "0" },
.{ "s.selectedIndex = 1", null },
.{ "s.selectedIndex", "1" },
.{ "s.selectedIndex = -323", null },
.{ "s.selectedIndex", "-1" },
.{ "let options = s.options", null },
.{ "options.length", "2" },
.{ "options.item(1).value", "o2" },
.{ "options.selectedIndex", "-1" },
.{ "let o3 = document.createElement('option');", null },
.{ "o3.value = 'o3';", null },
.{ "options.add(o3)", null },
.{ "options.length", "3" },
.{ "options.item(2).value", "o3" },
.{ "let o4 = document.createElement('option');", null },
.{ "o4.value = 'o4';", null },
.{ "options.add(o4, 1)", null },
.{ "options.length", "4" },
.{ "options.item(1).value", "o4" },
.{ "let o5 = document.createElement('option');", null },
.{ "o5.value = 'o5';", null },
.{ "options.add(o5, o3)", null },
.{ "options.length", "5" },
.{ "options.item(3).value", "o5" },
.{ "options.remove(3)", null },
.{ "options.length", "4" },
.{ "options.item(3).value", "o3" },
}, .{});
test "Browser: HTML.Select" {
try testing.htmlRunner("html/select.html");
}

View File

@@ -31,11 +31,6 @@ pub const SVGElement = struct {
};
const testing = @import("../../testing.zig");
test "Browser.HTML.SVGElement" {
var runner = try testing.jsRunner(testing.tracking_allocator, .{});
defer runner.deinit();
try runner.testCases(&.{
.{ "'AString' instanceof SVGElement", "false" },
}, .{});
test "Browser: HTML.SVGElement" {
try testing.htmlRunner("html/svg.html");
}

View File

@@ -0,0 +1,40 @@
<script src="../testing.js"></script>
<script id=abortController>
var a1 = new AbortController();
var s1 = a1.signal;
testing.expectEqual(undefined, s1.throwIfAborted());
testing.expectEqual(undefined, s1.reason);
let target;;
let called = 0;
s1.addEventListener('abort', (e) => {
called += 1;
target = e.target;
});
a1.abort();
testing.expectEqual(true, s1.aborted)
testing.expectEqual(s1, target)
testing.expectEqual('AbortError', s1.reason)
testing.expectEqual(1, called)
</script>
<script id=abort>
var s2 = AbortSignal.abort('over 9000');
testing.expectEqual(true, s2.aborted);
testing.expectEqual('over 9000', s2.reason);
testing.expectEqual('AbortError', AbortSignal.abort().reason);
</script>
<script id=timeout>
var s3 = AbortSignal.timeout(10);
testing.eventually(() => {
testing.expectEqual(true, s3.aborted);
testing.expectEqual('TimeoutError', s3.reason);
testing.expectError('Error: TimeoutError', () => {
s3.throwIfAborted()
});
});
</script>

View File

@@ -0,0 +1,29 @@
<script src="../testing.js"></script>
<div id=x data-power="over 9000" data-empty data-some-long-key=ok></div>
<script id=dataset>
let el1 = document.createElement('div');
testing.expectEqual(undefined, el1.dataset.x);
el1.dataset.x = '123';
testing.expectEqual(true, delete el1.dataset.x);
testing.expectEqual(undefined, el1.dataset.x);
// yes, this is right
testing.expectEqual(true, delete el1.dataset.other);
let ds1 = el1.dataset;
ds1.helloWorld = 'yes';
testing.expectEqual('yes', el1.getAttribute('data-hello-world'));
el1.setAttribute('data-this-will-work', 'positive');
testing.expectEqual('positive', ds1.thisWillWork);
</script>
<script id=element>
let div = $('#x');
testing.expectEqual(undefined, div.dataset.nope);
testing.expectEqual('over 9000', div.dataset.power);
testing.expectEqual('', div.dataset.empty);
testing.expectEqual('ok', div.dataset.someLongKey);
testing.expectEqual(true, delete div.dataset.power);
testing.expectEqual(undefined, div.dataset.power);
</script>

View File

@@ -0,0 +1,84 @@
<html>
<body>
<div id=content><a id=link href=#></a></div>
</body>
</html>
<script src="../testing.js"></script>
<script id=document>
testing.expectEqual('HTMLDocument', document.__proto__.constructor.name);
testing.expectEqual('Document', document.__proto__.__proto__.constructor.name);
testing.expectEqual('body', document.body.localName);
testing.expectEqual('localhost:9582', document.domain);
testing.expectEqual('', document.referrer);
testing.expectEqual('', document.title);
testing.expectEqual('body', document.body.localName);
testing.expectEqual('head', document.head.localName);
testing.expectEqual(0, document.images.length);
testing.expectEqual(0, document.embeds.length);
testing.expectEqual(0, document.plugins.length);
testing.expectEqual(2, document.scripts.length);
testing.expectEqual(0, document.forms.length);
testing.expectEqual(1, document.links.length);
testing.expectEqual(0, document.applets.length);
testing.expectEqual(0, document.anchors.length);
testing.expectEqual(7, document.all.length);
testing.expectEqual('document', document.currentScript.id);
document.title = 'foo';
testing.expectEqual('foo', document.title);
document.title = '';
document.getElementById('link').setAttribute('name', 'foo');
let list = document.getElementsByName('foo');
testing.expectEqual(1, list.length);
testing.expectEqual('', document.cookie);
document.cookie = 'name=Oeschger;';
document.cookie = 'favorite_food=tripe;';
testing.expectEqual('name=Oeschger; favorite_food=tripe', document.cookie);
// "" should be returned, but the framework overrules it atm
document.cookie = 'IgnoreMy=Ghost; HttpOnly';
testing.expectEqual('name=Oeschger; favorite_food=tripe', document.cookie);
// Return null since we only return elements when they have previously been localized
testing.expectEqual(null, document.elementFromPoint(0.5, 0.5));
testing.expectEqual([], document.elementsFromPoint(0.5, 0.5));
let div1 = document.createElement('div');
document.body.appendChild(div1);
div1.getClientRects(); // clal this to position it
testing.expectEqual('[object HTMLDivElement]', document.elementFromPoint(0.5, 0.5).toString());
let elems = document.elementsFromPoint(0.5, 0.5);
testing.expectEqual(3, elems.length);
testing.expectEqual('[object HTMLDivElement]', elems[0].toString());
testing.expectEqual('[object HTMLBodyElement]', elems[1].toString());
testing.expectEqual('[object HTMLHtmlElement]', elems[2].toString());
let a = document.createElement('a');
a.href = "https://lightpanda.io";
document.body.appendChild(a);
// Note this will be placed after the div of previous test
a.getClientRects();
let a_again = document.elementFromPoint(1.5, 0.5);
testing.expectEqual('[object HTMLAnchorElement]', a_again.toString());
testing.expectEqual('https://lightpanda.io', a_again.href);
let a_agains = document.elementsFromPoint(1.5, 0.5);
testing.expectEqual('https://lightpanda.io', a_agains[0].href);
testing.expectEqual(true, !document.all);
testing.expectEqual(false, !!document.all);
testing.expectEqual('[object HTMLScriptElement]', document.all(5).toString());
testing.expectEqual('[object HTMLDivElement]', document.all('content').toString());
testing.expectEqual(document, document.defaultView.document );
testing.expectEqual('loading', document.readyState);
</script>

View File

@@ -0,0 +1,52 @@
<script src="../testing.js"></script>
<div id=content>a<strong>b</strong>cc</div>
<script id=inner>
const content = $('#content');
testing.expectEqual('a<strong>b</strong>cc', content.innerHTML);
testing.expectEqual('abcc', content.innerText);
content. innerText = 'foo';
testing.expectEqual('foo', content.innerHTML);
testing.expectEqual('foo', content.innerText);
</script>
<script id=addEventListene>
let click_count = 0;
content.addEventListener('click', function() { click_count++ });
content.click()
testing.expectEqual(1, click_count);
</script>
<script id=style>
let style = content.style;
style.cssText = 'color: red; font-size: 12px; margin: 5px !important';
testing.expectEqual(3, style.length);
style.setProperty('background-color', 'blue')
testing.expectEqual('blue', style.getPropertyValue('background-color'));
testing.expectEqual(4, style.length);
</script>
<script id=a>
let a = document.createElement('a');
testing.expectEqual('', a.href);
testing.expectEqual('', a.host);
a.href = 'about';
testing.expectEqual('http://localhost:9582/src/tests/html/about', a.href);
</script>
<script id=focus>
// detached node cannot be focused
const focused = document.activeElement;
document.createElement('a').focus();
testing.expectEqual(focused, document.activeElement);
</script>
<script id=link>
let l2 = document.createElement('link');
testing.expectEqual('', l2.href);
l2.href = 'https://lightpanda.io/opensource-browser/15';
testing.expectEqual('https://lightpanda.io/opensource-browser/15', l2.href);
l2.href = '/over/9000';
testing.expectEqual('http://localhost:9582/over/9000', l2.href);
</script>

View File

@@ -22,8 +22,3 @@
testing.expectEqual(8999, e2.colno);
testing.expectEqual('under 9000!', e2.error);
</script>
<script id=ErrorEvent>
let e3 = new ErrorEvent('err3')
e3.addEventListener('change', () => {});
</script>

View File

@@ -0,0 +1,23 @@
<script src="../testing.js"></script>
<script id=history>
testing.expectEqual('auto', history.scrollRestoration);
history.scrollRestoration = 'manual';
history.scrollRestoration = 'foo';
testing.expectEqual('manual', history.scrollRestoration);
history.scrollRestoration = 'auto';
testing.expectEqual('auto', history.scrollRestoration);
testing.expectEqual(null, history.state)
history.pushState({}, null, '');
history.replaceState({}, null, '');
testing.expectEqual(undefined, history.go());
testing.expectEqual(undefined, history.go(1));
testing.expectEqual(undefined, history.go(-1));
testing.expectEqual(undefined, history.forward());
testing.expectEqual(undefined, history.back());
</script>

31
src/tests/html/image.html Normal file
View File

@@ -0,0 +1,31 @@
<script src="../testing.js"></script>
<script id=image>
img = new Image();
testing.expectEqual(0, img.width);
testing.expectEqual(0, img.height);
img = new Image(4);
testing.expectEqual(4, img.width);
testing.expectEqual(0, img.height);
img = new Image(5, 6);
testing.expectEqual(5, img.width);
testing.expectEqual(6, img.height);
let fruit = new Image
testing.expectEqual(0, fruit.width);
fruit.width = 5;
testing.expectEqual(5, fruit.width);
fruit.width = '15';
testing.expectEqual(15, fruit.width);
fruit.width = 'apple';
testing.expectEqual(0, fruit.width);
let lyric = new Image
testing.expectEqual('', lyric.src);
lyric.src = 'okay';
testing.expectEqual('okay', lyric.src);
lyric.src = 15;
testing.expectEqual('15', lyric.src);
</script>

110
src/tests/html/input.html Normal file
View File

@@ -0,0 +1,110 @@
<script src="../testing.js"></script>
<form action="test.php" target="_blank" id=form>
<p>
<label>First name: <input type="text" name="first-name" id=input /></label>
</p>
</form>
<script id=input_properties>
let input = document.createElement('input');
testing.expectEqual(null, input.form);
input.form = 'foo';
testing.expectEqual(null, input.form);
testing.expectEqual('', input.name);
input.name = 'leto';
testing.expectEqual('leto', input.name);
testing.expectEqual('', input.accept);
input.accept = 'anything';
testing.expectEqual('anything', input.accept);
testing.expectEqual('', input.alt);
input.alt = 'x1';
testing.expectEqual('x1', input.alt);
testing.expectEqual(false, input.disabled);
input.disabled = true;
testing.expectEqual(true, input.disabled);
input.disabled = false;
testing.expectEqual(false, input.disabled);
testing.expectEqual(false, input.readOnly);
input.readOnly = true;
testing.expectEqual(true, input.readOnly);
input.readOnly = false;
testing.expectEqual(false, input.readOnly);
testing.expectEqual(-1, input.maxLength);
input.maxLength = 5;
testing.expectEqual(5, input.maxLength);
input.maxLength = 'banana';
testing.expectEqual(0, input.maxLength);
testing.expectError('Error: NegativeValueNotAllowed', () => { input.maxLength = -45;});
testing.expectEqual(20, input.size);
input.size = 5;
testing.expectEqual(5, input.size);
input.size = -449;
testing.expectEqual(20, input.size);
testing.expectError('Error: ZeroNotAllowed', () => { input.size = 0; });
testing.expectEqual('', input.src);
input.src = 'foo'
testing.expectEqual('http://localhost:9582/src/tests/html/foo', input.src);
input.src = '-3'
testing.expectEqual('http://localhost:9582/src/tests/html/-3', input.src);
input.src = ''
testing.expectEqual('http://localhost:9582/src/tests/html/input.html', input.src);
testing.expectEqual('text', input.type);
input.type = 'checkbox';
testing.expectEqual('checkbox', input.type);
input.type = '5';
testing.expectEqual('text', input.type);
</script>
<script id=related>
let input_checked = document.createElement('input')
testing.expectEqual(false, input_checked.defaultChecked);
testing.expectEqual(false, input_checked.checked);
input_checked.defaultChecked = true;
testing.expectEqual(true, input_checked.defaultChecked);
testing.expectEqual(true, input_checked.checked);
input_checked.checked = false;
testing.expectEqual(true, input_checked.defaultChecked);
testing.expectEqual(false, input_checked.checked);
input_checked.defaultChecked = true;
testing.expectEqual(false, input_checked.checked);
</script>
<script id=defaultValue>
testing.expectEqual('', input.defaultValue);
testing.expectEqual('', input.value);
input.defaultValue = 3.1;
testing.expectEqual('3.1', input.defaultValue);
testing.expectEqual('3.1', input.value)
input.value = 'mango';
testing.expectEqual('3.1', input.defaultValue);
testing.expectEqual('mango', input.value);
input.defaultValue = true;
testing.expectEqual('mango', input.value);
</script>
<script id=form>
const form = $('#form');
input = $('#input');
testing.expectEqual(form, input.form);
// invalid
input.form = 'foo';
testing.expectEqual(form, input.form);
</script>

59
src/tests/html/link.html Normal file
View File

@@ -0,0 +1,59 @@
<script src="../testing.js"></script>
<a id=link href=foo>OK</a>
<script id=link>
let link = $('#link');
testing.expectEqual('', link.target);
link.target = '_blank';
testing.expectEqual('_blank', link.target);
link.target = '';
testing.expectEqual('foo', link.href);
link.href = 'https://lightpanda.io/';
testing.expectEqual('https://lightpanda.io/', link.href);
testing.expectEqual('https://lightpanda.io', link.origin);
link.host = 'lightpanda.io:443';
testing.expectEqual('lightpanda.io:443', link.host);
testing.expectEqual('443', link.port);
testing.expectEqual('lightpanda.io', link.hostname);
link.host = 'lightpanda.io';
testing.expectEqual('lightpanda.io', link.host);
testing.expectEqual('', link.port);
testing.expectEqual('lightpanda.io', link.hostname);
testing.expectEqual('lightpanda.io', link.host);
testing.expectEqual('lightpanda.io', link.hostname);
link.hostname = 'foo.bar';
testing.expectEqual('https://foo.bar/', link.href);
testing.expectEqual('', link.search);
link.search = 'q=bar';
testing.expectEqual('?q=bar', link.search);
testing.expectEqual('https://foo.bar/?q=bar', link.href);
testing.expectEqual('', link.hash);
link.hash = 'frag';
testing.expectEqual('#frag', link.hash);
testing.expectEqual('https://foo.bar/?q=bar#frag', link.href);
testing.expectEqual('', link.port);
link.port = '443';
testing.expectEqual('foo.bar:443', link.host);
testing.expectEqual('foo.bar', link.hostname);
testing.expectEqual('https://foo.bar:443/?q=bar#frag', link.href);
link.port = null;
testing.expectEqual('https://foo.bar/?q=bar#frag', link.href);
testing.expectEqual('foo', link.href = 'foo');
testing.expectEqual('', link.type);
link.type = 'text/html';
testing.expectEqual('text/html', link.type);
testing.expectEqual('OK', link.text);
link.text = 'foo';
testing.expectEqual('foo', link.text);
</script>

View File

@@ -0,0 +1,14 @@
<script src="../testing.js"></script>
<script id=location>
testing.expectEqual('http://localhost:9582/src/tests/html/location.html', location.href);
testing.expectEqual('http://localhost:9582/src/tests/html/location.html', document.location.href);
testing.expectEqual("localhost:9582", location.host);
testing.expectEqual("localhost", location.hostname);
testing.expectEqual("http://localhost:9582", location.origin);
testing.expectEqual("/src/tests/html/location.html", location.pathname);
testing.expectEqual("", location.hash);
testing.expectEqual("9582", location.port);
testing.expectEqual("", location.search);
</script>

View File

@@ -0,0 +1,7 @@
<script src="../testing.js"></script>
<script id=navigator>
testing.expectEqual('Lightpanda/1.0', navigator.userAgent);
testing.expectEqual('1.0', navigator.appVersion);
testing.expectEqual('en-US', navigator.language);
</script>

View File

@@ -0,0 +1,14 @@
<script src="../../testing.js"></script>
<script id=script>
let script = document.createElement('script')
script.src = 'foo.bar';
script.async = true;
testing.expectEqual(true, script.async);
script.async = false;
testing.expectEqual(false, script.async);
script.defer = true;
testing.expectEqual(true, script.defer);
</script>

View File

@@ -0,0 +1,74 @@
<script src="../testing.js"></script>
<form id=f1>
<select id=s1 name=s1><option>o1<option>o2</select>
</form>
<select id=s2></select>
<script id=select>
const s = document.getElementById('s1');
testing.expectEqual('[object HTMLFormElement]', s.form.toString());
testing.expectEqual(null, document.getElementById('s2').form);
testing.expectEqual(false, s.disabled);
s.disabled = true;
testing.expectEqual(true, s.disabled);
s.disabled = false;
testing.expectEqual(false, s.disabled);
testing.expectEqual(false, s.multiple);
s.multiple = true;
testing.expectEqual(true, s.multiple);
s.multiple = false;
testing.expectEqual(false, s.multiple);
testing.expectEqual('s1', s.name);
s.name = 'sel1';
testing.expectEqual('sel1', s.name);
testing.expectEqual(2, s.length);
testing.expectEqual(0, s.selectedIndex);
s.selectedIndex = 2; // out of range
testing.expectEqual(-1, s.selectedIndex);
s.selectedIndex = -1;
testing.expectEqual(-1, s.selectedIndex);
s.selectedIndex = 0;
testing.expectEqual(0, s.selectedIndex);
s.selectedIndex = 1;
testing.expectEqual(1, s.selectedIndex);
s.selectedIndex = -323;
testing.expectEqual(-1, s.selectedIndex);
let options = s.options;
testing.expectEqual(2, options.length);
testing.expectEqual('o2', options.item(1).value);
testing.expectEqual(-1, options.selectedIndex);
let o3 = document.createElement('option');
o3.value = 'o3';
options.add(o3)
testing.expectEqual(3, options.length);
testing.expectEqual('o3', options.item(2).value);
let o4 = document.createElement('option');
o4.value = 'o4';
options.add(o4, 1);
testing.expectEqual(4, options.length);
testing.expectEqual('o4', options.item(1).value);
let o5 = document.createElement('option');
o5.value = 'o5';
options.add(o5, o3)
testing.expectEqual(5, options.length);
testing.expectEqual('o5', options.item(3).value);
options.remove(3)
testing.expectEqual(4, options.length);
testing.expectEqual('o3', options.item(3).value);
</script>

View File

@@ -0,0 +1,7 @@
<script src="../testing.js"></script>
<script id=style>
let s = document.createElement('style');
testing.expectEqual('text/css', s.sheet.type);
testing.expectEqual(false, document.createElement('style').sheet == s.sheet);
</script>

5
src/tests/html/svg.html Normal file
View File

@@ -0,0 +1,5 @@
<script src="../testing.js"></script>
<script id=svg>
testing.expectEqual(false, 'AString' instanceof SVGElement);
</script>

View File

@@ -0,0 +1,21 @@
<script src="../testing.js"></script>
<div id=c></div>
<script id=template>
let t = document.createElement('template');
let d = document.createElement('div');
d.id = 'abc';
t.content.append(d);
testing.expectEqual(null, document.getElementById('abc'));
document.getElementById('c').appendChild(t.content.cloneNode(true));
testing.expectEqual('abc', document.getElementById('abc').id);
t.innerHTML = '<span>over</span><p>9000!</p>';
testing.expectEqual(2, t.content.childNodes.length);
testing.expectEqual('SPAN', t.content.childNodes[0].tagName);
testing.expectEqual('over', t.content.childNodes[0].innerHTML);
testing.expectEqual('P', t.content.childNodes[1].tagName);
testing.expectEqual('9000!', t.content.childNodes[1].innerHTML);
</script>