diff options
author | Luke <luke.wilde@live.co.uk> | 2020-07-24 21:24:11 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2020-07-25 12:35:15 +0200 |
commit | 08221139a57ddf941d9ba44f9a700d22e33d6665 (patch) | |
tree | 7708ece0e2c0f4b498c5bb3aa6a7aa70a77b57c2 | |
parent | 1d6a3a5e8fd418c2f36bb002282a2c6192b75f79 (diff) | |
download | serenity-08221139a57ddf941d9ba44f9a700d22e33d6665.zip |
test-web: Add ability to change page mid-test
This allows you to not have to write a separate test file
for the same thing but in a different situation.
This doesn't handle when you change the page with location.href
however.
Changes the name of the page load handlers to prevent confusion
with this.
-rw-r--r-- | Base/res/html/misc/blank-no-doctype.html | 7 | ||||
-rw-r--r-- | Libraries/LibWeb/Parser/HTMLDocumentParser.cpp | 6 | ||||
-rw-r--r-- | Libraries/LibWeb/Parser/HTMLDocumentParser.h | 1 | ||||
-rw-r--r-- | Libraries/LibWeb/Tests/Document/Doctype.js | 11 | ||||
-rw-r--r-- | Libraries/LibWeb/Tests/Window/Base64.js | 2 | ||||
-rw-r--r-- | Libraries/LibWeb/Tests/test-common.js | 22 | ||||
-rw-r--r-- | Userland/test-web.cpp | 96 |
7 files changed, 126 insertions, 19 deletions
diff --git a/Base/res/html/misc/blank-no-doctype.html b/Base/res/html/misc/blank-no-doctype.html new file mode 100644 index 0000000000..25f1d14c0e --- /dev/null +++ b/Base/res/html/misc/blank-no-doctype.html @@ -0,0 +1,7 @@ +<html> +<head> +<title>Blank</title> +</head> +<body> +</body> +</html> diff --git a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp index 83df56146b..1ab8f14d1e 100644 --- a/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp +++ b/Libraries/LibWeb/Parser/HTMLDocumentParser.cpp @@ -117,6 +117,12 @@ HTMLDocumentParser::HTMLDocumentParser(const StringView& input, const String& en m_document = adopt(*new Document); } +HTMLDocumentParser::HTMLDocumentParser(const StringView& input, const String& encoding, Document& existing_document) + : m_tokenizer(input, encoding) + , m_document(existing_document) +{ +} + HTMLDocumentParser::~HTMLDocumentParser() { } diff --git a/Libraries/LibWeb/Parser/HTMLDocumentParser.h b/Libraries/LibWeb/Parser/HTMLDocumentParser.h index 82f78160d4..dae251fb65 100644 --- a/Libraries/LibWeb/Parser/HTMLDocumentParser.h +++ b/Libraries/LibWeb/Parser/HTMLDocumentParser.h @@ -64,6 +64,7 @@ RefPtr<Document> parse_html_document(const StringView&, const URL&, const String class HTMLDocumentParser { public: HTMLDocumentParser(const StringView& input, const String& encoding); + HTMLDocumentParser(const StringView& input, const String& encoding, Document& existing_document); ~HTMLDocumentParser(); void run(const URL&); diff --git a/Libraries/LibWeb/Tests/Document/Doctype.js b/Libraries/LibWeb/Tests/Document/Doctype.js index 49f67e460b..161da491a3 100644 --- a/Libraries/LibWeb/Tests/Document/Doctype.js +++ b/Libraries/LibWeb/Tests/Document/Doctype.js @@ -1,11 +1,18 @@ loadPage("file:///res/html/misc/blank.html"); -afterPageLoad(() => { +afterInitialPageLoad(() => { test("Basic functionality", () => { expect(document.compatMode).toBe("CSS1Compat"); - expect(document.doctype).toBeDefined(); + expect(document.doctype).not.toBe(null); expect(document.doctype.name).toBe("html"); expect(document.doctype.publicId).toBe(""); expect(document.doctype.systemId).toBe(""); }); + + libweb_tester.changePage("file:///res/html/misc/blank-no-doctype.html"); + + test("Quirks mode", () => { + expect(document.compatMode).toBe("BackCompat"); + expect(document.doctype).toBe(null); + }); }); diff --git a/Libraries/LibWeb/Tests/Window/Base64.js b/Libraries/LibWeb/Tests/Window/Base64.js index 2cc12ea741..c272d70b74 100644 --- a/Libraries/LibWeb/Tests/Window/Base64.js +++ b/Libraries/LibWeb/Tests/Window/Base64.js @@ -1,6 +1,6 @@ loadPage("file:///res/html/misc/blank.html"); -afterPageLoad(() => { +afterInitialPageLoad(() => { test("atob", () => { expect(atob("YQ==")).toBe("a"); expect(atob("YWE=")).toBe("aa"); diff --git a/Libraries/LibWeb/Tests/test-common.js b/Libraries/LibWeb/Tests/test-common.js index 7add466d52..54d0b830c6 100644 --- a/Libraries/LibWeb/Tests/test-common.js +++ b/Libraries/LibWeb/Tests/test-common.js @@ -1,28 +1,32 @@ // NOTE: The tester loads in LibJS's test-common to prevent duplication. +// NOTE: "window.libweb_tester" is set to a special tester object. +// The object currently provides the following functions: +// - changePage(url) - change page to given URL. Everything afterwards will refer to the new page. + let __PageToLoad__; // This tells the tester which page to load. // This will only be checked when we look at which page the test wants to use. -// Subsequent calls to loadPage in before/after load will be ignored. +// Subsequent calls to loadPage in before/after initial load will be ignored. let loadPage; -let __BeforePageLoad__ = () => {}; +let __BeforeInitialPageLoad__ = () => {}; -// This function will be run just before loading the page. +// This function will be called just before loading the initial page. // This is useful for injecting event listeners. // Defaults to an empty function. -let beforePageLoad; +let beforeInitialPageLoad; -let __AfterPageLoad__ = () => {}; +let __AfterInitialPageLoad__ = () => {}; -// This function will be run just after loading the page. +// This function will be called just after loading the initial page. // This is where the main bulk of the tests should be. // Defaults to an empty function. -let afterPageLoad; +let afterInitialPageLoad; (() => { loadPage = (page) => __PageToLoad__ = page; - beforePageLoad = (callback) => __BeforePageLoad__ = callback; - afterPageLoad = (callback) => __AfterPageLoad__ = callback; + beforeInitialPageLoad = (callback) => __BeforeInitialPageLoad__ = callback; + afterInitialPageLoad = (callback) => __AfterInitialPageLoad__ = callback; })(); diff --git a/Userland/test-web.cpp b/Userland/test-web.cpp index 3378812d2c..f340d5e736 100644 --- a/Userland/test-web.cpp +++ b/Userland/test-web.cpp @@ -25,6 +25,7 @@ */ #include <AK/URL.h> +#include <AK/Function.h> #include <AK/JsonValue.h> #include <AK/JsonObject.h> #include <AK/QuickSort.h> @@ -92,6 +93,47 @@ struct JSTestRunnerCounts { int files_total { 0 }; }; +Function<void(const URL&)> g_on_page_change; + +class TestRunnerObject final : public JS::Object { + JS_OBJECT(TestRunnerObject, JS::Object); + +public: + explicit TestRunnerObject(JS::GlobalObject&); + virtual void initialize(JS::GlobalObject&) override; + virtual ~TestRunnerObject() override; + +private: + JS_DECLARE_NATIVE_FUNCTION(change_page); +}; + +TestRunnerObject::TestRunnerObject(JS::GlobalObject& global_object) + : Object(*global_object.object_prototype()) +{ +} + +void TestRunnerObject::initialize(JS::GlobalObject& global_object) +{ + Object::initialize(global_object); + define_native_function("changePage", change_page, 1); +} + +TestRunnerObject::~TestRunnerObject() +{ +} + +JS_DEFINE_NATIVE_FUNCTION(TestRunnerObject::change_page) +{ + auto url = interpreter.argument(0).to_string(interpreter); + if (interpreter.exception()) + return {}; + + if (g_on_page_change) + g_on_page_change(url); + + return JS::js_undefined(); +} + class TestRunner { public: TestRunner(String web_test_root, String js_test_root, Web::PageView& page_view, bool print_times) @@ -163,6 +205,33 @@ Vector<String> get_test_paths(const String& test_root) void TestRunner::run() { size_t progress_counter = 0; auto test_paths = get_test_paths(m_web_test_root); + + g_on_page_change = [this](auto& page_to_load) { + if (!page_to_load.is_valid()) { + printf("Invalid page URL (%s) on page change", page_to_load.to_string().characters()); + exit(1); + } + + ASSERT(m_page_view->document()); + + // We want to keep the same document since the interpreter is tied to the document, + // and we don't want to lose the test state. So, we just clear the document and + // give a new parser the existing document to work on. + m_page_view->document()->remove_all_children(); + + Web::ResourceLoader::the().load_sync( + page_to_load, + [&](auto data, auto&) { + Web::HTMLDocumentParser parser(data, "utf-8", *m_page_view->document()); + parser.run(page_to_load); + }, + [page_to_load](auto error) { + printf("Failed to load test page: %s (%s)", page_to_load.to_string().characters(), error.characters()); + exit(1); + } + ); + }; + for (auto& path : test_paths) { ++progress_counter; print_file_result(run_file_test(path)); @@ -260,21 +329,26 @@ JSFileResult TestRunner::run_file_test(const String& test_path) Web::HTMLDocumentParser parser(data, "utf-8"); auto& new_interpreter = parser.document().interpreter(); - // Setup the test environment and call "__BeforePageLoad__" + // Setup the test environment and call "__BeforeInitialPageLoad__" + new_interpreter.global_object().define_property( + "libweb_tester", + new_interpreter.heap().allocate<TestRunnerObject>(new_interpreter.global_object(), new_interpreter.global_object()), + JS::Attribute::Enumerable | JS::Attribute::Configurable + ); new_interpreter.run(new_interpreter.global_object(), *m_js_test_common); new_interpreter.run(new_interpreter.global_object(), *m_web_test_common); new_interpreter.run(new_interpreter.global_object(), *file_program.value()); - auto& before_page_load = new_interpreter.get_variable("__BeforePageLoad__", new_interpreter.global_object()).as_function(); - new_interpreter.call(before_page_load, JS::js_undefined()); + auto& before_initial_page_load = new_interpreter.get_variable("__BeforeInitialPageLoad__", new_interpreter.global_object()).as_function(); + new_interpreter.call(before_initial_page_load, JS::js_undefined()); // Now parse the HTML page. parser.run(page_to_load); m_page_view->set_document(&parser.document()); - // Finally run the test by calling "__AfterPageLoad__" - auto& after_page_load = new_interpreter.get_variable("__AfterPageLoad__", new_interpreter.global_object()).as_function(); - new_interpreter.call(after_page_load, JS::js_undefined()); + // Finally run the test by calling "__AfterInitialPageLoad__" + auto& after_initial_page_load = new_interpreter.get_variable("__AfterInitialPageLoad__", new_interpreter.global_object()).as_function(); + new_interpreter.call(after_initial_page_load, JS::js_undefined()); auto test_json = get_test_results(new_interpreter); if (!test_json.has_value()) { @@ -340,7 +414,7 @@ JSFileResult TestRunner::run_file_test(const String& test_path) m_total_elapsed_time_in_ms += file_result.time_taken; }, [page_to_load](auto error) { - dbg() << "Failed to load test page: " << error << " (" << page_to_load << ")"; + printf("Failed to load test page: %s (%s)", page_to_load.to_string().characters(), error.characters()); exit(1); } ); @@ -555,9 +629,11 @@ void TestRunner::print_test_results() const int main(int argc, char** argv) { bool print_times = false; + bool show_window = false; Core::ArgsParser args_parser; args_parser.add_option(print_times, "Show duration of each test", "show-time", 't'); + args_parser.add_option(show_window, "Show window while running tests", "window", 'w'); args_parser.parse(argc, argv); auto app = GUI::Application::construct(argc, argv); @@ -569,6 +645,12 @@ int main(int argc, char** argv) view.set_document(adopt(*new Web::Document)); + if (show_window) { + window->set_title("LibWeb Test Window"); + window->set_rect(100, 100, 640, 480); + window->show(); + } + #ifdef __serenity__ TestRunner("/home/anon/web-tests", "/home/anon/js-tests", view, print_times).run(); #else |