mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-29 12:19:54 +00:00
Tests: Replace load-reference-page
debug action with internals method
WPT reference tests can add metadata to tests to instruct the test runner how to interpret the results. Because of this, it is not enough to have an action that starts loading the (mis)match reference: we need the test runner to receive the metadata so it can act accordingly. This sets our test runner up for potentially supporting multiple (mis)match references, and fuzzy rendering matches - the latter will be implemented in the following commit.
This commit is contained in:
parent
0f642ecb5c
commit
e4b2253b63
Notes:
github-actions[bot]
2025-07-17 12:00:33 +00:00
Author: https://github.com/gmta
Commit: e4b2253b63
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/5470
Reviewed-by: https://github.com/tcl3 ✅
12 changed files with 87 additions and 44 deletions
|
@ -1,9 +1,11 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <AK/JsonObject.h>
|
||||
#include <LibJS/Runtime/Date.h>
|
||||
#include <LibJS/Runtime/VM.h>
|
||||
#include <LibUnicode/TimeZone.h>
|
||||
|
@ -12,6 +14,7 @@
|
|||
#include <LibWeb/DOM/Document.h>
|
||||
#include <LibWeb/DOM/Event.h>
|
||||
#include <LibWeb/DOM/EventTarget.h>
|
||||
#include <LibWeb/DOM/NodeList.h>
|
||||
#include <LibWeb/DOMURL/DOMURL.h>
|
||||
#include <LibWeb/HTML/HTMLElement.h>
|
||||
#include <LibWeb/HTML/Window.h>
|
||||
|
@ -19,7 +22,6 @@
|
|||
#include <LibWeb/Page/InputEvent.h>
|
||||
#include <LibWeb/Page/Page.h>
|
||||
#include <LibWeb/Painting/PaintableBox.h>
|
||||
#include <LibWeb/Painting/ViewportPaintable.h>
|
||||
|
||||
namespace Web::Internals {
|
||||
|
||||
|
@ -50,6 +52,39 @@ void Internals::set_test_timeout(double milliseconds)
|
|||
page().client().page_did_set_test_timeout(milliseconds);
|
||||
}
|
||||
|
||||
// https://web-platform-tests.org/writing-tests/reftests.html#components-of-a-reftest
|
||||
WebIDL::ExceptionOr<void> Internals::load_reference_test_metadata()
|
||||
{
|
||||
auto& vm = this->vm();
|
||||
auto& page = this->page();
|
||||
|
||||
auto* document = page.top_level_browsing_context().active_document();
|
||||
if (!document)
|
||||
return vm.throw_completion<JS::InternalError>("No active document available"sv);
|
||||
|
||||
JsonObject metadata;
|
||||
|
||||
// Collect all <link rel="match"> and <link rel="mismatch"> references.
|
||||
auto collect_references = [&vm, &document](StringView type) -> WebIDL::ExceptionOr<JsonArray> {
|
||||
JsonArray references;
|
||||
auto reference_nodes = TRY(document->query_selector_all(MUST(String::formatted("link[rel={}]", type))));
|
||||
for (size_t i = 0; i < reference_nodes->length(); ++i) {
|
||||
auto const* reference_node = reference_nodes->item(i);
|
||||
auto href = as<DOM::Element>(reference_node)->get_attribute_value(HTML::AttributeNames::href);
|
||||
auto url = document->encoding_parse_url(href);
|
||||
if (!url.has_value())
|
||||
return vm.throw_completion<JS::InternalError>(MUST(String::formatted("Failed to construct URL for '{}'", href)));
|
||||
references.must_append(url->to_string());
|
||||
}
|
||||
return references;
|
||||
};
|
||||
metadata.set("match_references"sv, TRY(collect_references("match"sv)));
|
||||
metadata.set("mismatch_references"sv, TRY(collect_references("mismatch"sv)));
|
||||
|
||||
page.client().page_did_receive_reference_test_metadata(metadata);
|
||||
return {};
|
||||
}
|
||||
|
||||
void Internals::gc()
|
||||
{
|
||||
vm().heap().collect_garbage();
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
|
||||
void signal_test_is_done(String const& text);
|
||||
void set_test_timeout(double milliseconds);
|
||||
WebIDL::ExceptionOr<void> load_reference_test_metadata();
|
||||
|
||||
WebIDL::ExceptionOr<String> set_time_zone(StringView time_zone);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ interface Internals {
|
|||
|
||||
undefined signalTestIsDone(DOMString text);
|
||||
undefined setTestTimeout(double milliseconds);
|
||||
undefined loadReferenceTestMetadata();
|
||||
|
||||
DOMString setTimeZone(DOMString timeZone);
|
||||
|
||||
|
|
|
@ -388,6 +388,7 @@ public:
|
|||
|
||||
virtual void page_did_finish_test([[maybe_unused]] String const& text) { }
|
||||
virtual void page_did_set_test_timeout([[maybe_unused]] double milliseconds) { }
|
||||
virtual void page_did_receive_reference_test_metadata(JsonValue) { }
|
||||
|
||||
virtual void page_did_set_browser_zoom([[maybe_unused]] double factor) { }
|
||||
|
||||
|
|
|
@ -224,6 +224,7 @@ public:
|
|||
Function<void(Web::DragEvent const&)> on_finish_handling_drag_event;
|
||||
Function<void(String const&)> on_test_finish;
|
||||
Function<void(double milliseconds)> on_set_test_timeout;
|
||||
Function<void(JsonValue)> on_reference_test_metadata;
|
||||
Function<void(double factor)> on_set_browser_zoom;
|
||||
Function<void(size_t current_match_index, Optional<size_t> const& total_match_count)> on_find_in_page;
|
||||
Function<void(Gfx::Color)> on_theme_color_change;
|
||||
|
|
|
@ -132,6 +132,14 @@ void WebContentClient::did_set_test_timeout(u64 page_id, double milliseconds)
|
|||
}
|
||||
}
|
||||
|
||||
void WebContentClient::did_receive_reference_test_metadata(u64 page_id, JsonValue metadata)
|
||||
{
|
||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||
if (view->on_reference_test_metadata)
|
||||
view->on_reference_test_metadata(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
void WebContentClient::did_set_browser_zoom(u64 page_id, double factor)
|
||||
{
|
||||
if (auto view = view_for_page_id(page_id); view.has_value()) {
|
||||
|
|
|
@ -129,6 +129,7 @@ private:
|
|||
virtual void did_finish_handling_input_event(u64 page_id, Web::EventResult event_result) override;
|
||||
virtual void did_finish_test(u64 page_id, String text) override;
|
||||
virtual void did_set_test_timeout(u64 page_id, double milliseconds) override;
|
||||
virtual void did_receive_reference_test_metadata(u64 page_id, JsonValue) override;
|
||||
virtual void did_set_browser_zoom(u64 page_id, double factor) override;
|
||||
virtual void did_find_in_page(u64 page_id, size_t current_match_index, Optional<size_t> total_match_count) override;
|
||||
virtual void did_change_theme_color(u64 page_id, Gfx::Color color) override;
|
||||
|
|
|
@ -398,43 +398,6 @@ void ConnectionFromClient::debug_request(u64 page_id, ByteString request, ByteSt
|
|||
return;
|
||||
}
|
||||
|
||||
if (request == "load-reference-page") {
|
||||
if (auto* document = page->page().top_level_browsing_context().active_document()) {
|
||||
auto has_mismatch_selector = false;
|
||||
|
||||
auto maybe_link = [&]() -> Web::WebIDL::ExceptionOr<GC::Ptr<Web::DOM::Element>> {
|
||||
auto maybe_link = document->query_selector("link[rel=match]"sv);
|
||||
if (maybe_link.is_error() || maybe_link.value())
|
||||
return maybe_link;
|
||||
|
||||
auto maybe_mismatch_link = document->query_selector("link[rel=mismatch]"sv);
|
||||
if (maybe_mismatch_link.is_error() || maybe_mismatch_link.value()) {
|
||||
has_mismatch_selector = maybe_mismatch_link.value();
|
||||
return maybe_mismatch_link;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}();
|
||||
|
||||
if (maybe_link.is_error() || !maybe_link.value()) {
|
||||
// To make sure that we fail the ref-test if the link is missing, load the error page->
|
||||
load_html(page_id, "<h1>Failed to find <link rel="match" /> or <link rel="mismatch" /> in ref test page!</h1> Make sure you added it.");
|
||||
} else {
|
||||
auto link = maybe_link.release_value();
|
||||
auto url = document->encoding_parse_url(link->get_attribute_value(Web::HTML::AttributeNames::href));
|
||||
if (url->query().has_value() && !url->query()->is_empty()) {
|
||||
load_html(page_id, "<h1>Invalid ref test link - query string must be empty</h1>");
|
||||
return;
|
||||
}
|
||||
if (has_mismatch_selector)
|
||||
url->set_query("mismatch"_string);
|
||||
|
||||
load_url(page_id, *url);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (request == "navigator-compatibility-mode") {
|
||||
Web::NavigatorCompatibilityMode compatibility_mode;
|
||||
if (argument == "chrome") {
|
||||
|
|
|
@ -333,6 +333,11 @@ void PageClient::page_did_set_test_timeout(double milliseconds)
|
|||
client().async_did_set_test_timeout(m_id, milliseconds);
|
||||
}
|
||||
|
||||
void PageClient::page_did_receive_reference_test_metadata(JsonValue metadata)
|
||||
{
|
||||
client().async_did_receive_reference_test_metadata(m_id, metadata);
|
||||
}
|
||||
|
||||
void PageClient::page_did_set_browser_zoom(double factor)
|
||||
{
|
||||
auto traversable = page().top_level_traversable();
|
||||
|
|
|
@ -164,6 +164,7 @@ private:
|
|||
virtual void page_did_request_select_dropdown(Web::CSSPixelPoint content_position, Web::CSSPixels minimum_width, Vector<Web::HTML::SelectItem> items) override;
|
||||
virtual void page_did_finish_test(String const& text) override;
|
||||
virtual void page_did_set_test_timeout(double milliseconds) override;
|
||||
virtual void page_did_receive_reference_test_metadata(JsonValue) override;
|
||||
virtual void page_did_set_browser_zoom(double factor) override;
|
||||
virtual void page_did_change_theme_color(Gfx::Color color) override;
|
||||
virtual void page_did_insert_clipboard_entry(Web::Clipboard::SystemClipboardRepresentation const&, StringView presentation_style) override;
|
||||
|
|
|
@ -114,6 +114,7 @@ endpoint WebContentClient
|
|||
|
||||
did_finish_test(u64 page_id, String text) =|
|
||||
did_set_test_timeout(u64 page_id, double milliseconds) =|
|
||||
did_receive_reference_test_metadata(u64 page_id, JsonValue result) =|
|
||||
|
||||
did_set_browser_zoom(u64 page_id, double factor) =|
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
* Copyright (c) 2023-2025, Tim Flynn <trflynn89@ladybird.org>
|
||||
* Copyright (c) 2023, Andreas Kling <andreas@ladybird.org>
|
||||
* Copyright (c) 2023-2024, Sam Atkins <sam@ladybird.org>
|
||||
* Copyright (c) 2025, Jelle Raaijmakers <jelle@ladybird.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
@ -28,6 +29,7 @@
|
|||
#include <LibGfx/Bitmap.h>
|
||||
#include <LibGfx/ImageFormats/PNGWriter.h>
|
||||
#include <LibGfx/SystemTheme.h>
|
||||
#include <LibURL/Parser.h>
|
||||
#include <LibURL/URL.h>
|
||||
#include <LibWeb/HTML/SelectedFile.h>
|
||||
#include <LibWebView/Utilities.h>
|
||||
|
@ -425,25 +427,48 @@ static void run_ref_test(TestWebView& view, Test& test, URL::URL const& url, int
|
|||
|
||||
view.on_test_finish = [&view, &test, on_test_complete = move(on_test_complete)](auto const&) {
|
||||
if (test.actual_screenshot) {
|
||||
if (view.url().query().has_value() && view.url().query()->equals_ignoring_ascii_case("mismatch"sv)) {
|
||||
test.ref_test_expectation_type = RefTestExpectationType::Mismatch;
|
||||
} else {
|
||||
test.ref_test_expectation_type = RefTestExpectationType::Match;
|
||||
}
|
||||
// The reference has finished loading; take another screenshot and move on to handling the result.
|
||||
view.take_screenshot()->when_resolved([&view, &test, on_test_complete = move(on_test_complete)](RefPtr<Gfx::Bitmap const> screenshot) {
|
||||
test.expectation_screenshot = move(screenshot);
|
||||
view.reset_zoom();
|
||||
on_test_complete();
|
||||
});
|
||||
} else {
|
||||
// When the test initially finishes, we take a screenshot and request the reference test metadata.
|
||||
view.take_screenshot()->when_resolved([&view, &test](RefPtr<Gfx::Bitmap const> screenshot) {
|
||||
test.actual_screenshot = move(screenshot);
|
||||
view.reset_zoom();
|
||||
view.debug_request("load-reference-page");
|
||||
view.run_javascript("internals.loadReferenceTestMetadata();"_string);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
view.on_reference_test_metadata = [&view, &test](JsonValue const& metadata) {
|
||||
auto metadata_object = metadata.as_object();
|
||||
|
||||
auto match_references = metadata_object.get_array("match_references"sv);
|
||||
auto mismatch_references = metadata_object.get_array("mismatch_references"sv);
|
||||
VERIFY(!match_references->is_empty() || !mismatch_references->is_empty());
|
||||
|
||||
// Read (mis)match reference tests to load.
|
||||
// FIXME: Currently we only support single match or mismatch reference.
|
||||
String reference_to_load;
|
||||
if (!match_references->is_empty()) {
|
||||
if (match_references->size() > 1)
|
||||
dbgln("FIXME: Only a single ref test match reference is supported");
|
||||
|
||||
test.ref_test_expectation_type = RefTestExpectationType::Match;
|
||||
reference_to_load = match_references->at(0).as_string();
|
||||
} else {
|
||||
if (mismatch_references->size() > 1)
|
||||
dbgln("FIXME: Only a single ref test mismatch reference is supported");
|
||||
|
||||
test.ref_test_expectation_type = RefTestExpectationType::Mismatch;
|
||||
reference_to_load = mismatch_references->at(0).as_string();
|
||||
}
|
||||
view.load(URL::Parser::basic_parse(reference_to_load).release_value());
|
||||
};
|
||||
|
||||
view.on_set_test_timeout = [timer, timeout_in_milliseconds](double milliseconds) {
|
||||
if (milliseconds <= timeout_in_milliseconds)
|
||||
return;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue