From 15628d9b07e1d2d6671b8f2db3a80eec8021bfdc Mon Sep 17 00:00:00 2001 From: Karl Seguin Date: Mon, 8 Sep 2025 18:40:59 +0800 Subject: [PATCH] migrate more tests to htmlRunner --- src/browser/dom/event_target.zig | 132 +--------------------------- src/browser/dom/exceptions.zig | 45 +--------- src/browser/dom/html_collection.zig | 50 +---------- src/tests/dom/event_target.html | 115 ++++++++++++++++++++++++ src/tests/dom/exceptions.html | 39 ++++++++ src/tests/dom/html_collection.html | 59 +++++++++++++ src/tests/testing.js | 8 +- vendor/netsurf/libdom | 2 +- 8 files changed, 224 insertions(+), 226 deletions(-) create mode 100644 src/tests/dom/event_target.html create mode 100644 src/tests/dom/exceptions.html create mode 100644 src/tests/dom/html_collection.html diff --git a/src/browser/dom/event_target.zig b/src/browser/dom/event_target.zig index 8e76c39d..3d239629 100644 --- a/src/browser/dom/event_target.zig +++ b/src/browser/dom/event_target.zig @@ -154,134 +154,6 @@ pub const EventTarget = struct { }; const testing = @import("../../testing.zig"); -test "Browser.DOM.EventTarget" { - var runner = try testing.jsRunner(testing.tracking_allocator, .{}); - defer runner.deinit(); - - try runner.testCases(&.{ - .{ "new EventTarget()", "[object EventTarget]" }, - }, .{}); - - try runner.testCases(&.{ - .{ "let content = document.getElementById('content')", "undefined" }, - .{ "let para = document.getElementById('para')", "undefined" }, - // NOTE: as some event properties will change during the event dispatching phases - // we need to copy thoses values in order to check them afterwards - .{ - \\ var nb = 0; var evt; var phase; var cur; - \\ function cbk(event) { - \\ evt = event; - \\ phase = event.eventPhase; - \\ cur = event.currentTarget; - \\ nb ++; - \\ } - , - "undefined", - }, - }, .{}); - - try runner.testCases(&.{ - .{ "content.addEventListener('basic', cbk)", "undefined" }, - .{ "content.dispatchEvent(new Event('basic'))", "true" }, - .{ "nb", "1" }, - .{ "evt instanceof Event", "true" }, - .{ "evt.type", "basic" }, - .{ "phase", "2" }, - .{ "cur.getAttribute('id')", "content" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0; evt = undefined; phase = undefined; cur = undefined", "undefined" }, - .{ "para.dispatchEvent(new Event('basic'))", "true" }, - .{ "nb", "0" }, // handler is not called, no capture, not the target, no bubbling - .{ "evt === undefined", "true" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0", "0" }, - .{ "content.addEventListener('basic', cbk)", "undefined" }, - .{ "content.dispatchEvent(new Event('basic'))", "true" }, - .{ "nb", "1" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0", "0" }, - .{ "content.addEventListener('basic', cbk, true)", "undefined" }, - .{ "content.dispatchEvent(new Event('basic'))", "true" }, - .{ "nb", "2" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0", "0" }, - .{ "content.removeEventListener('basic', cbk)", "undefined" }, - .{ "content.dispatchEvent(new Event('basic'))", "true" }, - .{ "nb", "1" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0", "0" }, - .{ "content.removeEventListener('basic', cbk, {capture: true})", "undefined" }, - .{ "content.dispatchEvent(new Event('basic'))", "true" }, - .{ "nb", "0" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0; evt = undefined; phase = undefined; cur = undefined", "undefined" }, - .{ "content.addEventListener('capture', cbk, true)", "undefined" }, - .{ "content.dispatchEvent(new Event('capture'))", "true" }, - .{ "nb", "1" }, - .{ "evt instanceof Event", "true" }, - .{ "evt.type", "capture" }, - .{ "phase", "2" }, - .{ "cur.getAttribute('id')", "content" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0; evt = undefined; phase = undefined; cur = undefined", "undefined" }, - .{ "para.dispatchEvent(new Event('capture'))", "true" }, - .{ "nb", "1" }, - .{ "evt instanceof Event", "true" }, - .{ "evt.type", "capture" }, - .{ "phase", "1" }, - .{ "cur.getAttribute('id')", "content" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0; evt = undefined; phase = undefined; cur = undefined", "undefined" }, - .{ "content.addEventListener('bubbles', cbk)", "undefined" }, - .{ "content.dispatchEvent(new Event('bubbles', {bubbles: true}))", "true" }, - .{ "nb", "1" }, - .{ "evt instanceof Event", "true" }, - .{ "evt.type", "bubbles" }, - .{ "evt.bubbles", "true" }, - .{ "phase", "2" }, - .{ "cur.getAttribute('id')", "content" }, - }, .{}); - - try runner.testCases(&.{ - .{ "nb = 0; evt = undefined; phase = undefined; cur = undefined", "undefined" }, - .{ "para.dispatchEvent(new Event('bubbles', {bubbles: true}))", "true" }, - .{ "nb", "1" }, - .{ "evt instanceof Event", "true" }, - .{ "evt.type", "bubbles" }, - .{ "phase", "3" }, - .{ "cur.getAttribute('id')", "content" }, - }, .{}); - - try runner.testCases(&.{ - .{ "const obj1 = {calls: 0, handleEvent: function() { this.calls += 1; } };", null }, - .{ "content.addEventListener('he', obj1);", null }, - .{ "content.dispatchEvent(new Event('he'));", null }, - .{ "obj1.calls", "1" }, - - .{ "content.removeEventListener('he', obj1);", null }, - .{ "content.dispatchEvent(new Event('he'));", null }, - .{ "obj1.calls", "1" }, - }, .{}); - - // doesn't crash on null receiver - try runner.testCases(&.{ - .{ "content.addEventListener('he2', null);", null }, - .{ "content.dispatchEvent(new Event('he2'));", null }, - }, .{}); +test "Browser: DOM.EventTarget" { + try testing.htmlRunner("dom/event_target.html"); } diff --git a/src/browser/dom/exceptions.zig b/src/browser/dom/exceptions.zig index bfba2f7b..1a56792b 100644 --- a/src/browser/dom/exceptions.zig +++ b/src/browser/dom/exceptions.zig @@ -219,47 +219,6 @@ pub const DOMException = struct { }; const testing = @import("../../testing.zig"); -test "Browser.DOM.Exception" { - var runner = try testing.jsRunner(testing.tracking_allocator, .{}); - defer runner.deinit(); - - const err = "Failed to execute 'appendChild' on 'Node': The new child element contains the parent."; - try runner.testCases(&.{ - .{ "let content = document.getElementById('content')", "undefined" }, - .{ "let link = document.getElementById('link')", "undefined" }, - // HierarchyRequestError - .{ - \\ var he; - \\ try { link.appendChild(content) } catch (error) { he = error} - \\ he.name - , - "HierarchyRequestError", - }, - .{ "he.code", "3" }, - .{ "he.message", err }, - .{ "he.toString()", "HierarchyRequestError: " ++ err }, - .{ "he instanceof DOMException", "true" }, - .{ "he instanceof Error", "true" }, - }, .{}); - - // Test DOMException constructor - try runner.testCases(&.{ - .{ "let exc0 = new DOMException()", "undefined" }, - .{ "exc0.name", "Error" }, - .{ "exc0.code", "0" }, - .{ "exc0.message", "" }, - .{ "exc0.toString()", "Error" }, - - .{ "let exc1 = new DOMException('Sandwich malfunction')", "undefined" }, - .{ "exc1.name", "Error" }, - .{ "exc1.code", "0" }, - .{ "exc1.message", "Sandwich malfunction" }, - .{ "exc1.toString()", "Error: Sandwich malfunction" }, - - .{ "let exc2 = new DOMException('Caterpillar turned into a butterfly', 'NoModificationAllowedError')", "undefined" }, - .{ "exc2.name", "NoModificationAllowedError" }, - .{ "exc2.code", "7" }, - .{ "exc2.message", "Caterpillar turned into a butterfly" }, - .{ "exc2.toString()", "NoModificationAllowedError: Caterpillar turned into a butterfly" }, - }, .{}); +test "Browser: DOM.Exceptions" { + try testing.htmlRunner("dom/exceptions.html"); } diff --git a/src/browser/dom/html_collection.zig b/src/browser/dom/html_collection.zig index 37e4e0db..11dd4158 100644 --- a/src/browser/dom/html_collection.zig +++ b/src/browser/dom/html_collection.zig @@ -462,52 +462,6 @@ pub const HTMLCollection = struct { }; const testing = @import("../../testing.zig"); -test "Browser.DOM.HTMLCollection" { - var runner = try testing.jsRunner(testing.tracking_allocator, .{}); - defer runner.deinit(); - - try runner.testCases(&.{ - .{ "let getElementsByTagName = document.getElementsByTagName('p')", "undefined" }, - .{ "getElementsByTagName.length", "2" }, - .{ "let getElementsByTagNameCI = document.getElementsByTagName('P')", "undefined" }, - .{ "getElementsByTagNameCI.length", "2" }, - .{ "getElementsByTagName.item(0).localName", "p" }, - .{ "getElementsByTagName.item(1).localName", "p" }, - .{ "let getElementsByTagNameAll = document.getElementsByTagName('*')", "undefined" }, - .{ "getElementsByTagNameAll.length", "8" }, - .{ "getElementsByTagNameAll.item(0).localName", "html" }, - .{ "getElementsByTagNameAll.item(0).localName", "html" }, - .{ "getElementsByTagNameAll.item(1).localName", "head" }, - .{ "getElementsByTagNameAll.item(0).localName", "html" }, - .{ "getElementsByTagNameAll.item(2).localName", "body" }, - .{ "getElementsByTagNameAll.item(3).localName", "div" }, - .{ "getElementsByTagNameAll.item(7).localName", "p" }, - .{ "getElementsByTagNameAll.namedItem('para-empty-child').localName", "span" }, - - // array like - .{ "getElementsByTagNameAll[0].localName", "html" }, - .{ "getElementsByTagNameAll[7].localName", "p" }, - .{ "getElementsByTagNameAll[8]", "undefined" }, - .{ "getElementsByTagNameAll['para-empty-child'].localName", "span" }, - .{ "getElementsByTagNameAll['foo']", "undefined" }, - - .{ "document.getElementById('content').getElementsByTagName('*').length", "4" }, - .{ "document.getElementById('content').getElementsByTagName('p').length", "2" }, - .{ "document.getElementById('content').getElementsByTagName('div').length", "0" }, - - .{ "document.children.length", "1" }, - .{ "document.getElementById('content').children.length", "3" }, - - // check liveness - .{ "let content = document.getElementById('content')", "undefined" }, - .{ "let pe = document.getElementById('para-empty')", "undefined" }, - .{ "let p = document.createElement('p')", "undefined" }, - .{ "p.textContent = 'OK live'", "OK live" }, - .{ "getElementsByTagName.item(1).textContent", " And" }, - .{ "content.appendChild(p) != undefined", "true" }, - .{ "getElementsByTagName.length", "3" }, - .{ "getElementsByTagName.item(2).textContent", "OK live" }, - .{ "content.insertBefore(p, pe) != undefined", "true" }, - .{ "getElementsByTagName.item(0).textContent", "OK live" }, - }, .{}); +test "Browser: DOM.HTMLCollection" { + try testing.htmlRunner("dom/html_collection.html"); } diff --git a/src/tests/dom/event_target.html b/src/tests/dom/event_target.html new file mode 100644 index 00000000..bbb22e60 --- /dev/null +++ b/src/tests/dom/event_target.html @@ -0,0 +1,115 @@ + + +

+ + diff --git a/src/tests/dom/exceptions.html b/src/tests/dom/exceptions.html new file mode 100644 index 00000000..73048abf --- /dev/null +++ b/src/tests/dom/exceptions.html @@ -0,0 +1,39 @@ + + +
+ OK +
+ + + + diff --git a/src/tests/dom/html_collection.html b/src/tests/dom/html_collection.html new file mode 100644 index 00000000..0f65c715 --- /dev/null +++ b/src/tests/dom/html_collection.html @@ -0,0 +1,59 @@ + +
+ OK +

+ +

+

And

+ +
+ + + + diff --git a/src/tests/testing.js b/src/tests/testing.js index 39894095..faa9f123 100644 --- a/src/tests/testing.js +++ b/src/tests/testing.js @@ -50,7 +50,6 @@ function getStatus() { // if we're already in a fail state, return fail, nothing can recover this if (testing._status === 'fail') return 'fail'; - // run any eventually's that we've captured for (const ev of testing._eventually) { testing._captured = ev[1]; @@ -70,7 +69,8 @@ if (!id) { continue; } - if (!testing._executed_scripts[id]) { + + if (!testing._executed_scripts.has(id)) { console.warn(`Failed to execute any expectations for `), testing._status = 'fail'; } @@ -99,7 +99,7 @@ testing._status = 'ok'; const script_id = testing._captured?.script_id || document.currentScript.id; - testing._executed_scripts[script_id] = true; + testing._executed_scripts.add(script_id); _registerErrorCallback(); } @@ -158,7 +158,7 @@ window.testing = { _status: 'empty', _eventually: [], - _executed_scripts: {}, + _executed_scripts: new Set(), _captured: null, skip: skip, getStatus: getStatus, diff --git a/vendor/netsurf/libdom b/vendor/netsurf/libdom index c0df4581..120717ba 160000 --- a/vendor/netsurf/libdom +++ b/vendor/netsurf/libdom @@ -1 +1 @@ -Subproject commit c0df458132162aba136d57ce1ba2179122a9e717 +Subproject commit 120717bad4e46c3fee559aff9728a5c0dbc9c8f2