test-web.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. /*
  2. * Copyright (c) 2020-2021, the SerenityOS developers.
  3. *
  4. * SPDX-License-Identifier: BSD-2-Clause
  5. */
  6. #include <AK/URL.h>
  7. #include <LibGUI/Application.h>
  8. #include <LibGUI/BoxLayout.h>
  9. #include <LibGUI/Widget.h>
  10. #include <LibGUI/Window.h>
  11. #include <LibTest/JavaScriptTestRunner.h>
  12. #include <LibWeb/Bindings/MainThreadVM.h>
  13. #include <LibWeb/HTML/Parser/HTMLParser.h>
  14. #include <LibWeb/InProcessWebView.h>
  15. #include <LibWeb/Loader/ResourceLoader.h>
  16. using namespace Test::JS;
  17. TEST_ROOT("Userland/Libraries/LibWeb/Tests");
  18. RefPtr<Web::InProcessWebView> g_page_view;
  19. RefPtr<GUI::Application> g_app;
  20. Optional<URL> next_page_to_load;
  21. Vector<Function<void(JS::Object&)>> after_initial_load_hooks;
  22. Vector<Function<void(JS::Object&)>> before_initial_load_hooks;
  23. TESTJS_MAIN_HOOK()
  24. {
  25. g_vm = Web::Bindings::main_thread_vm();
  26. g_app = GUI::Application::construct(g_test_argc, g_test_argv);
  27. auto window = GUI::Window::construct();
  28. auto& main_widget = window->set_main_widget<GUI::Widget>();
  29. main_widget.set_fill_with_background_color(true);
  30. main_widget.set_layout<GUI::VerticalBoxLayout>();
  31. auto& view = main_widget.add<Web::InProcessWebView>();
  32. view.set_document(Web::DOM::Document::create());
  33. g_page_view = view;
  34. }
  35. TESTJS_GLOBAL_FUNCTION(load_local_page, loadLocalPage)
  36. {
  37. auto name = vm.argument(0).to_string(global_object);
  38. if (vm.exception())
  39. return {};
  40. // Clear the hooks
  41. before_initial_load_hooks.clear();
  42. after_initial_load_hooks.clear();
  43. // Set the load URL
  44. if (name.starts_with('/'))
  45. next_page_to_load = URL::create_with_file_protocol(name);
  46. else
  47. next_page_to_load = URL::create_with_file_protocol(LexicalPath::join(g_test_root, "Pages", name).string());
  48. return JS::js_undefined();
  49. }
  50. TESTJS_GLOBAL_FUNCTION(after_initial_page_load, afterInitialPageLoad)
  51. {
  52. auto function = vm.argument(0);
  53. if (!function.is_function()) {
  54. dbgln("afterInitialPageLoad argument is not a function");
  55. vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAnObjectOfType, "Function");
  56. return {};
  57. }
  58. after_initial_load_hooks.append([fn = JS::make_handle(&function.as_function()), &vm](auto& page_object) {
  59. [[maybe_unused]] auto unused = vm.call(const_cast<JS::FunctionObject&>(*fn.cell()), JS::js_undefined(), &page_object);
  60. });
  61. return JS::js_undefined();
  62. }
  63. TESTJS_GLOBAL_FUNCTION(before_initial_page_load, beforeInitialPageLoad)
  64. {
  65. auto function = vm.argument(0);
  66. if (!function.is_function()) {
  67. dbgln("beforeInitialPageLoad argument is not a function");
  68. vm.throw_exception<JS::TypeError>(global_object, JS::ErrorType::NotAnObjectOfType, "Function");
  69. return {};
  70. }
  71. before_initial_load_hooks.append([fn = JS::make_handle(&function.as_function()), &vm](auto& page_object) {
  72. [[maybe_unused]] auto unused = vm.call(const_cast<JS::FunctionObject&>(*fn.cell()), JS::js_undefined(), &page_object);
  73. });
  74. return JS::js_undefined();
  75. }
  76. TESTJS_GLOBAL_FUNCTION(wait_for_page_to_load, waitForPageToLoad)
  77. {
  78. // Create a new parser and immediately get its document to replace the old interpreter.
  79. auto document = Web::DOM::Document::create();
  80. // Run the "before" hooks
  81. for (auto& entry : before_initial_load_hooks)
  82. entry(document->interpreter().global_object());
  83. // Set the load hook
  84. Web::LoadRequest request;
  85. request.set_url(next_page_to_load.value());
  86. auto& loader = Web::ResourceLoader::the();
  87. loader.load_sync(
  88. request,
  89. [&](auto data, auto&, auto) {
  90. Web::HTML::HTMLParser parser(document, data, "utf-8");
  91. // Now parse the HTML page.
  92. parser.run(next_page_to_load.value());
  93. g_page_view->set_document(&parser.document());
  94. if (vm.exception()) {
  95. // FIXME: Should we do something about this? the document itself threw unhandled exceptions...
  96. vm.clear_exception();
  97. }
  98. // Run the "after" hooks
  99. for (auto& entry : after_initial_load_hooks) {
  100. entry(document->interpreter().global_object());
  101. if (vm.exception())
  102. break;
  103. }
  104. },
  105. [&](auto&, auto) {
  106. dbgln("Load of resource {} failed", next_page_to_load.value());
  107. vm.throw_exception<JS::TypeError>(global_object, "Resource load failed");
  108. });
  109. return JS::js_undefined();
  110. }