1 | /* |
2 | * Copyright (C) 2011 Igalia S.L. |
3 | * Copyright (C) 2014 Collabora Ltd. |
4 | * |
5 | * This library is free software; you can redistribute it and/or |
6 | * modify it under the terms of the GNU Lesser General Public |
7 | * License as published by the Free Software Foundation; either |
8 | * version 2,1 of the License, or (at your option) any later version. |
9 | * |
10 | * This library is distributed in the hope that it will be useful, |
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
13 | * Library General Public License for more details. |
14 | * |
15 | * You should have received a copy of the GNU Library General Public License |
16 | * along with this library; see the file COPYING.LIB. If not, write to |
17 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
18 | * Boston, MA 02110-1301, USA. |
19 | */ |
20 | |
21 | #include "config.h" |
22 | #include "WebKitTestServer.h" |
23 | #include "WebViewTest.h" |
24 | #include <glib/gstdio.h> |
25 | #include <wtf/glib/GRefPtr.h> |
26 | |
27 | class IsPlayingAudioWebViewTest : public WebViewTest { |
28 | public: |
29 | MAKE_GLIB_TEST_FIXTURE(IsPlayingAudioWebViewTest); |
30 | |
31 | static void isPlayingAudioChanged(GObject*, GParamSpec*, IsPlayingAudioWebViewTest* test) |
32 | { |
33 | g_signal_handlers_disconnect_by_func(test->m_webView, reinterpret_cast<void*>(isPlayingAudioChanged), test); |
34 | g_main_loop_quit(test->m_mainLoop); |
35 | } |
36 | |
37 | void waitUntilIsPlayingAudioChanged() |
38 | { |
39 | g_signal_connect(m_webView, "notify::is-playing-audio" , G_CALLBACK(isPlayingAudioChanged), this); |
40 | g_main_loop_run(m_mainLoop); |
41 | } |
42 | }; |
43 | |
44 | static WebKitTestServer* gServer; |
45 | |
46 | static void testWebViewWebContext(WebViewTest* test, gconstpointer) |
47 | { |
48 | g_assert_true(webkit_web_view_get_context(test->m_webView) == test->m_webContext.get()); |
49 | g_assert_true(webkit_web_context_get_default() != test->m_webContext.get()); |
50 | |
51 | // Check that a web view created with g_object_new has the default context. |
52 | auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW, |
53 | #if PLATFORM(WPE) |
54 | "backend" , Test::createWebViewBackend(), |
55 | #endif |
56 | nullptr)); |
57 | g_assert_true(webkit_web_view_get_context(webView.get()) == webkit_web_context_get_default()); |
58 | |
59 | // Check that a web view created with a related view has the related view context. |
60 | webView = Test::adoptView(Test::createWebView(test->m_webView)); |
61 | g_assert_true(webkit_web_view_get_context(webView.get()) == test->m_webContext.get()); |
62 | |
63 | // Check that a web context given as construct parameter is ignored if a related view is also provided. |
64 | webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW, |
65 | #if PLATFORM(WPE) |
66 | "backend" , Test::createWebViewBackend(), |
67 | #endif |
68 | "web-context" , webkit_web_context_get_default(), |
69 | "related-view" , test->m_webView, |
70 | nullptr)); |
71 | g_assert_true(webkit_web_view_get_context(webView.get()) == test->m_webContext.get()); |
72 | } |
73 | |
74 | static void testWebViewWebContextLifetime(WebViewTest* test, gconstpointer) |
75 | { |
76 | WebKitWebContext* webContext = webkit_web_context_new(); |
77 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webContext)); |
78 | |
79 | auto* webView = Test::createWebView(webContext); |
80 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView)); |
81 | |
82 | #if PLATFORM(GTK) |
83 | g_object_ref_sink(webView); |
84 | #endif |
85 | g_object_unref(webContext); |
86 | |
87 | // Check that the web view still has a valid context. |
88 | WebKitWebContext* tmpContext = webkit_web_view_get_context(WEBKIT_WEB_VIEW(webView)); |
89 | g_assert_true(WEBKIT_IS_WEB_CONTEXT(tmpContext)); |
90 | g_object_unref(webView); |
91 | |
92 | WebKitWebContext* webContext2 = webkit_web_context_new(); |
93 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webContext2)); |
94 | |
95 | auto* webView2 = Test::createWebView(webContext2); |
96 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView2)); |
97 | |
98 | #if PLATFORM(GTK) |
99 | g_object_ref_sink(webView2); |
100 | #endif |
101 | g_object_unref(webView2); |
102 | |
103 | // Check that the context is still valid. |
104 | g_assert_true(WEBKIT_IS_WEB_CONTEXT(webContext2)); |
105 | g_object_unref(webContext2); |
106 | } |
107 | |
108 | static void testWebViewCloseQuickly(WebViewTest* test, gconstpointer) |
109 | { |
110 | auto webView = Test::adoptView(Test::createWebView()); |
111 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView.get())); |
112 | g_idle_add([](gpointer userData) -> gboolean { |
113 | static_cast<WebViewTest*>(userData)->quitMainLoop(); |
114 | return G_SOURCE_REMOVE; |
115 | }, test); |
116 | g_main_loop_run(test->m_mainLoop); |
117 | webView = nullptr; |
118 | } |
119 | |
120 | #if PLATFORM(WPE) |
121 | static void testWebViewWebBackend(Test* test, gconstpointer) |
122 | { |
123 | static struct wpe_view_backend_interface s_testingInterface = { |
124 | // create |
125 | [](void*, struct wpe_view_backend*) -> void* { return nullptr; }, |
126 | // destroy |
127 | [](void*) { }, |
128 | // initialize |
129 | [](void*) { }, |
130 | // get_renderer_host_fd |
131 | [](void*) -> int { return -1; }, |
132 | // padding |
133 | nullptr, |
134 | nullptr, |
135 | nullptr, |
136 | nullptr |
137 | }; |
138 | |
139 | // User provided backend with default deleter (we don't have a way to check the backend will be actually freed). |
140 | GRefPtr<WebKitWebView> webView = adoptGRef(webkit_web_view_new(webkit_web_view_backend_new(wpe_view_backend_create_with_backend_interface(&s_testingInterface, nullptr), nullptr, nullptr))); |
141 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView.get())); |
142 | auto* viewBackend = webkit_web_view_get_backend(webView.get()); |
143 | g_assert_nonnull(viewBackend); |
144 | auto* wpeBackend = webkit_web_view_backend_get_wpe_backend(viewBackend); |
145 | g_assert_nonnull(wpeBackend); |
146 | webView = nullptr; |
147 | |
148 | // User provided backend with destroy notify. |
149 | wpeBackend = wpe_view_backend_create_with_backend_interface(&s_testingInterface, nullptr); |
150 | webView = adoptGRef(webkit_web_view_new(webkit_web_view_backend_new(wpeBackend, [](gpointer userData) { |
151 | auto* backend = *static_cast<struct wpe_view_backend**>(userData); |
152 | wpe_view_backend_destroy(backend); |
153 | *static_cast<struct wpe_view_backend**>(userData) = nullptr; |
154 | }, &wpeBackend))); |
155 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView.get())); |
156 | webView = nullptr; |
157 | g_assert_null(wpeBackend); |
158 | |
159 | // User provided backend owned by another object with destroy notify. |
160 | static bool hasInstance = false; |
161 | struct BackendOwner { |
162 | BackendOwner(struct wpe_view_backend* backend) |
163 | : backend(backend) |
164 | { |
165 | hasInstance = true; |
166 | } |
167 | |
168 | ~BackendOwner() |
169 | { |
170 | wpe_view_backend_destroy(backend); |
171 | hasInstance = false; |
172 | } |
173 | |
174 | struct wpe_view_backend* backend; |
175 | }; |
176 | auto* owner = new BackendOwner(wpe_view_backend_create_with_backend_interface(&s_testingInterface, nullptr)); |
177 | g_assert_true(hasInstance); |
178 | webView = adoptGRef(webkit_web_view_new(webkit_web_view_backend_new(owner->backend, [](gpointer userData) { |
179 | delete static_cast<BackendOwner*>(userData); |
180 | }, owner))); |
181 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView.get())); |
182 | g_assert_true(hasInstance); |
183 | webView = nullptr; |
184 | g_assert_false(hasInstance); |
185 | } |
186 | #endif // PLATFORM(WPE) |
187 | |
188 | static void ephemeralViewloadChanged(WebKitWebView* webView, WebKitLoadEvent loadEvent, WebViewTest* test) |
189 | { |
190 | if (loadEvent != WEBKIT_LOAD_FINISHED) |
191 | return; |
192 | g_signal_handlers_disconnect_by_func(webView, reinterpret_cast<void*>(ephemeralViewloadChanged), test); |
193 | test->quitMainLoop(); |
194 | } |
195 | |
196 | static void testWebViewEphemeral(WebViewTest* test, gconstpointer) |
197 | { |
198 | g_assert_false(webkit_web_view_is_ephemeral(test->m_webView)); |
199 | g_assert_false(webkit_web_context_is_ephemeral(webkit_web_view_get_context(test->m_webView))); |
200 | auto* manager = webkit_web_context_get_website_data_manager(test->m_webContext.get()); |
201 | g_assert_false(webkit_website_data_manager_is_ephemeral(manager)); |
202 | g_assert_true(webkit_web_view_get_website_data_manager(test->m_webView) == manager); |
203 | webkit_website_data_manager_clear(manager, WEBKIT_WEBSITE_DATA_DISK_CACHE, 0, nullptr, [](GObject* manager, GAsyncResult* result, gpointer userData) { |
204 | webkit_website_data_manager_clear_finish(WEBKIT_WEBSITE_DATA_MANAGER(manager), result, nullptr); |
205 | static_cast<WebViewTest*>(userData)->quitMainLoop(); |
206 | }, test); |
207 | g_main_loop_run(test->m_mainLoop); |
208 | |
209 | // A WebView on a non ephemeral context can be ephemeral. |
210 | auto webView = Test::adoptView(g_object_new(WEBKIT_TYPE_WEB_VIEW, |
211 | #if PLATFORM(WPE) |
212 | "backend" , Test::createWebViewBackend(), |
213 | #endif |
214 | "web-context" , webkit_web_view_get_context(test->m_webView), |
215 | "is-ephemeral" , TRUE, |
216 | nullptr)); |
217 | g_assert_true(webkit_web_view_is_ephemeral(webView.get())); |
218 | g_assert_false(webkit_web_context_is_ephemeral(webkit_web_view_get_context(webView.get()))); |
219 | g_assert_true(webkit_web_view_get_website_data_manager(webView.get()) != manager); |
220 | |
221 | g_signal_connect(webView.get(), "load-changed" , G_CALLBACK(ephemeralViewloadChanged), test); |
222 | webkit_web_view_load_uri(webView.get(), gServer->getURIForPath("/" ).data()); |
223 | g_main_loop_run(test->m_mainLoop); |
224 | |
225 | // Disk cache delays the storing of initial resources for 1 second to avoid |
226 | // affecting early page load. So, wait 1 second here to make sure resources |
227 | // have already been stored. |
228 | test->wait(1); |
229 | |
230 | webkit_website_data_manager_fetch(manager, WEBKIT_WEBSITE_DATA_DISK_CACHE, nullptr, [](GObject* manager, GAsyncResult* result, gpointer userData) { |
231 | auto* test = static_cast<WebViewTest*>(userData); |
232 | g_assert_null(webkit_website_data_manager_fetch_finish(WEBKIT_WEBSITE_DATA_MANAGER(manager), result, nullptr)); |
233 | test->quitMainLoop(); |
234 | }, test); |
235 | g_main_loop_run(test->m_mainLoop); |
236 | } |
237 | |
238 | static void testWebViewCustomCharset(WebViewTest* test, gconstpointer) |
239 | { |
240 | test->loadURI(gServer->getURIForPath("/" ).data()); |
241 | test->waitUntilLoadFinished(); |
242 | g_assert_null(webkit_web_view_get_custom_charset(test->m_webView)); |
243 | webkit_web_view_set_custom_charset(test->m_webView, "utf8" ); |
244 | // Changing the charset reloads the page, so wait until reloaded. |
245 | test->waitUntilLoadFinished(); |
246 | g_assert_cmpstr(webkit_web_view_get_custom_charset(test->m_webView), ==, "utf8" ); |
247 | |
248 | // Go back to the default charset and wait until reloaded. |
249 | webkit_web_view_set_custom_charset(test->m_webView, nullptr); |
250 | test->waitUntilLoadFinished(); |
251 | g_assert_null(webkit_web_view_get_custom_charset(test->m_webView)); |
252 | } |
253 | |
254 | static void testWebViewSettings(WebViewTest* test, gconstpointer) |
255 | { |
256 | WebKitSettings* defaultSettings = webkit_web_view_get_settings(test->m_webView); |
257 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(defaultSettings)); |
258 | g_assert_nonnull(defaultSettings); |
259 | g_assert_true(webkit_settings_get_enable_javascript(defaultSettings)); |
260 | |
261 | GRefPtr<WebKitSettings> newSettings = adoptGRef(webkit_settings_new()); |
262 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings.get())); |
263 | g_object_set(G_OBJECT(newSettings.get()), "enable-javascript" , FALSE, NULL); |
264 | webkit_web_view_set_settings(test->m_webView, newSettings.get()); |
265 | |
266 | WebKitSettings* settings = webkit_web_view_get_settings(test->m_webView); |
267 | g_assert_true(settings != defaultSettings); |
268 | g_assert_false(webkit_settings_get_enable_javascript(settings)); |
269 | |
270 | auto webView2 = Test::adoptView(Test::createWebView()); |
271 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView2.get())); |
272 | webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView2.get()), settings); |
273 | g_assert_true(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView2.get())) == settings); |
274 | |
275 | GRefPtr<WebKitSettings> newSettings2 = adoptGRef(webkit_settings_new()); |
276 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(newSettings2.get())); |
277 | webkit_web_view_set_settings(WEBKIT_WEB_VIEW(webView2.get()), newSettings2.get()); |
278 | settings = webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView2.get())); |
279 | g_assert_true(settings == newSettings2.get()); |
280 | g_assert_true(webkit_settings_get_enable_javascript(settings)); |
281 | |
282 | auto webView3 = Test::adoptView(Test::createWebView(newSettings2.get())); |
283 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webView3.get())); |
284 | g_assert_true(webkit_web_view_get_settings(WEBKIT_WEB_VIEW(webView3.get())) == newSettings2.get()); |
285 | } |
286 | |
287 | static void testWebViewZoomLevel(WebViewTest* test, gconstpointer) |
288 | { |
289 | g_assert_cmpfloat(webkit_web_view_get_zoom_level(test->m_webView), ==, 1); |
290 | webkit_web_view_set_zoom_level(test->m_webView, 2.5); |
291 | g_assert_cmpfloat(webkit_web_view_get_zoom_level(test->m_webView), ==, 2.5); |
292 | |
293 | webkit_settings_set_zoom_text_only(webkit_web_view_get_settings(test->m_webView), TRUE); |
294 | // The zoom level shouldn't change when zoom-text-only setting changes. |
295 | g_assert_cmpfloat(webkit_web_view_get_zoom_level(test->m_webView), ==, 2.5); |
296 | } |
297 | |
298 | static void testWebViewRunJavaScript(WebViewTest* test, gconstpointer) |
299 | { |
300 | static const char* html = "<html><body><a id='WebKitLink' href='http://www.webkitgtk.org/' title='WebKitGTK+ Title'>WebKitGTK+ Website</a></body></html>" ; |
301 | test->loadHtml(html, 0); |
302 | test->waitUntilLoadFinished(); |
303 | |
304 | GUniqueOutPtr<GError> error; |
305 | WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.getElementById('WebKitLink').title;" , &error.outPtr()); |
306 | g_assert_nonnull(javascriptResult); |
307 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
308 | g_assert_no_error(error.get()); |
309 | GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult)); |
310 | g_assert_cmpstr(valueString.get(), ==, "WebKitGTK+ Title" ); |
311 | |
312 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.getElementById('WebKitLink').href;" , &error.outPtr()); |
313 | g_assert_nonnull(javascriptResult); |
314 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
315 | g_assert_no_error(error.get()); |
316 | valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
317 | g_assert_cmpstr(valueString.get(), ==, "http://www.webkitgtk.org/" ); |
318 | |
319 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("window.document.getElementById('WebKitLink').textContent" , &error.outPtr()); |
320 | g_assert_nonnull(javascriptResult); |
321 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
322 | g_assert_no_error(error.get()); |
323 | valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
324 | g_assert_cmpstr(valueString.get(), ==, "WebKitGTK+ Website" ); |
325 | |
326 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = 25;" , &error.outPtr()); |
327 | g_assert_nonnull(javascriptResult); |
328 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
329 | g_assert_no_error(error.get()); |
330 | g_assert_cmpfloat(WebViewTest::javascriptResultToNumber(javascriptResult), ==, 25); |
331 | |
332 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = 2.5;" , &error.outPtr()); |
333 | g_assert_nonnull(javascriptResult); |
334 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
335 | g_assert_no_error(error.get()); |
336 | g_assert_cmpfloat(WebViewTest::javascriptResultToNumber(javascriptResult), ==, 2.5); |
337 | |
338 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = true" , &error.outPtr()); |
339 | g_assert_nonnull(javascriptResult); |
340 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
341 | g_assert_no_error(error.get()); |
342 | g_assert_true(WebViewTest::javascriptResultToBoolean(javascriptResult)); |
343 | |
344 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = false" , &error.outPtr()); |
345 | g_assert_nonnull(javascriptResult); |
346 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
347 | g_assert_no_error(error.get()); |
348 | g_assert_false(WebViewTest::javascriptResultToBoolean(javascriptResult)); |
349 | |
350 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("a = null" , &error.outPtr()); |
351 | g_assert_nonnull(javascriptResult); |
352 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
353 | g_assert_no_error(error.get()); |
354 | g_assert_true(WebViewTest::javascriptResultIsNull(javascriptResult)); |
355 | |
356 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("function Foo() { a = 25; } Foo();" , &error.outPtr()); |
357 | g_assert_nonnull(javascriptResult); |
358 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
359 | g_assert_no_error(error.get()); |
360 | g_assert_true(WebViewTest::javascriptResultIsUndefined(javascriptResult)); |
361 | |
362 | javascriptResult = test->runJavaScriptFromGResourceAndWaitUntilFinished("/org/webkit/glib/tests/link-title.js" , &error.outPtr()); |
363 | g_assert_nonnull(javascriptResult); |
364 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
365 | g_assert_no_error(error.get()); |
366 | valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
367 | g_assert_cmpstr(valueString.get(), ==, "WebKitGTK+ Title" ); |
368 | |
369 | javascriptResult = test->runJavaScriptFromGResourceAndWaitUntilFinished("/wrong/path/to/resource.js" , &error.outPtr()); |
370 | g_assert_null(javascriptResult); |
371 | g_assert_error(error.get(), G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND); |
372 | |
373 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("foo();" , &error.outPtr()); |
374 | g_assert_null(javascriptResult); |
375 | g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED); |
376 | |
377 | // Values of the main world are not available in the isolated one. |
378 | javascriptResult = test->runJavaScriptInWorldAndWaitUntilFinished("a" , "WebExtensionTestScriptWorld" , &error.outPtr()); |
379 | g_assert_null(javascriptResult); |
380 | g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED); |
381 | |
382 | javascriptResult = test->runJavaScriptInWorldAndWaitUntilFinished("a = 50" , "WebExtensionTestScriptWorld" , &error.outPtr()); |
383 | g_assert_nonnull(javascriptResult); |
384 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
385 | g_assert_no_error(error.get()); |
386 | g_assert_cmpfloat(WebViewTest::javascriptResultToNumber(javascriptResult), ==, 50); |
387 | |
388 | // Values of the isolated world are not available in the normal one. |
389 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("a" , &error.outPtr()); |
390 | g_assert_nonnull(javascriptResult); |
391 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(webkit_javascript_result_get_js_value(javascriptResult))); |
392 | g_assert_no_error(error.get()); |
393 | g_assert_cmpfloat(WebViewTest::javascriptResultToNumber(javascriptResult), ==, 25); |
394 | |
395 | // Running a script in a world that doesn't exist should fail. |
396 | javascriptResult = test->runJavaScriptInWorldAndWaitUntilFinished("a" , "InvalidScriptWorld" , &error.outPtr()); |
397 | g_assert_null(javascriptResult); |
398 | g_assert_error(error.get(), WEBKIT_JAVASCRIPT_ERROR, WEBKIT_JAVASCRIPT_ERROR_SCRIPT_FAILED); |
399 | } |
400 | |
401 | class FullScreenClientTest: public WebViewTest { |
402 | public: |
403 | MAKE_GLIB_TEST_FIXTURE(FullScreenClientTest); |
404 | |
405 | enum FullScreenEvent { |
406 | None, |
407 | Enter, |
408 | Leave |
409 | }; |
410 | |
411 | static gboolean viewEnterFullScreenCallback(WebKitWebView*, FullScreenClientTest* test) |
412 | { |
413 | test->m_event = Enter; |
414 | g_main_loop_quit(test->m_mainLoop); |
415 | return FALSE; |
416 | } |
417 | |
418 | static gboolean viewLeaveFullScreenCallback(WebKitWebView*, FullScreenClientTest* test) |
419 | { |
420 | test->m_event = Leave; |
421 | g_main_loop_quit(test->m_mainLoop); |
422 | return FALSE; |
423 | } |
424 | |
425 | FullScreenClientTest() |
426 | : m_event(None) |
427 | { |
428 | webkit_settings_set_enable_fullscreen(webkit_web_view_get_settings(m_webView), TRUE); |
429 | g_signal_connect(m_webView, "enter-fullscreen" , G_CALLBACK(viewEnterFullScreenCallback), this); |
430 | g_signal_connect(m_webView, "leave-fullscreen" , G_CALLBACK(viewLeaveFullScreenCallback), this); |
431 | } |
432 | |
433 | ~FullScreenClientTest() |
434 | { |
435 | g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); |
436 | } |
437 | |
438 | void requestFullScreenAndWaitUntilEnteredFullScreen() |
439 | { |
440 | m_event = None; |
441 | webkit_web_view_run_javascript(m_webView, "document.documentElement.webkitRequestFullScreen();" , 0, 0, 0); |
442 | g_main_loop_run(m_mainLoop); |
443 | } |
444 | |
445 | static gboolean leaveFullScreenIdle(FullScreenClientTest* test) |
446 | { |
447 | // FIXME: Implement key strokes in WPE |
448 | #if PLATFORM(GTK) |
449 | test->keyStroke(GDK_KEY_Escape); |
450 | #endif |
451 | return FALSE; |
452 | } |
453 | |
454 | void leaveFullScreenAndWaitUntilLeftFullScreen() |
455 | { |
456 | m_event = None; |
457 | g_idle_add(reinterpret_cast<GSourceFunc>(leaveFullScreenIdle), this); |
458 | g_main_loop_run(m_mainLoop); |
459 | } |
460 | |
461 | FullScreenEvent m_event; |
462 | }; |
463 | |
464 | #if ENABLE(FULLSCREEN_API) |
465 | static void testWebViewFullScreen(FullScreenClientTest* test, gconstpointer) |
466 | { |
467 | #if PLATFORM(GTK) |
468 | test->showInWindowAndWaitUntilMapped(); |
469 | #endif |
470 | test->loadHtml("<html><body>FullScreen test</body></html>" , 0); |
471 | test->waitUntilLoadFinished(); |
472 | test->requestFullScreenAndWaitUntilEnteredFullScreen(); |
473 | g_assert_cmpint(test->m_event, ==, FullScreenClientTest::Enter); |
474 | test->leaveFullScreenAndWaitUntilLeftFullScreen(); |
475 | g_assert_cmpint(test->m_event, ==, FullScreenClientTest::Leave); |
476 | } |
477 | #endif |
478 | |
479 | static void testWebViewCanShowMIMEType(WebViewTest* test, gconstpointer) |
480 | { |
481 | // Supported MIME types. |
482 | g_assert_true(webkit_web_view_can_show_mime_type(test->m_webView, "text/html" )); |
483 | g_assert_true(webkit_web_view_can_show_mime_type(test->m_webView, "text/plain" )); |
484 | g_assert_true(webkit_web_view_can_show_mime_type(test->m_webView, "image/jpeg" )); |
485 | |
486 | // Unsupported MIME types. |
487 | g_assert_false(webkit_web_view_can_show_mime_type(test->m_webView, "text/vcard" )); |
488 | g_assert_false(webkit_web_view_can_show_mime_type(test->m_webView, "application/zip" )); |
489 | g_assert_false(webkit_web_view_can_show_mime_type(test->m_webView, "application/octet-stream" )); |
490 | |
491 | #if ENABLE(NETSCAPE_PLUGIN_API) |
492 | // Plugins are only supported when enabled. |
493 | webkit_web_context_set_additional_plugins_directory(webkit_web_view_get_context(test->m_webView), WEBKIT_TEST_PLUGIN_DIR); |
494 | g_assert_true(webkit_web_view_can_show_mime_type(test->m_webView, "application/x-webkit-test-netscape" )); |
495 | webkit_settings_set_enable_plugins(webkit_web_view_get_settings(test->m_webView), FALSE); |
496 | g_assert_false(webkit_web_view_can_show_mime_type(test->m_webView, "application/x-webkit-test-netscape" )); |
497 | #endif |
498 | } |
499 | |
500 | #if PLATFORM(GTK) |
501 | class FormClientTest: public WebViewTest { |
502 | public: |
503 | MAKE_GLIB_TEST_FIXTURE(FormClientTest); |
504 | |
505 | static void submitFormCallback(WebKitWebView*, WebKitFormSubmissionRequest* request, FormClientTest* test) |
506 | { |
507 | test->submitForm(request); |
508 | } |
509 | |
510 | FormClientTest() |
511 | : m_submitPositionX(0) |
512 | , m_submitPositionY(0) |
513 | { |
514 | g_signal_connect(m_webView, "submit-form" , G_CALLBACK(submitFormCallback), this); |
515 | } |
516 | |
517 | ~FormClientTest() |
518 | { |
519 | g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); |
520 | } |
521 | |
522 | void submitForm(WebKitFormSubmissionRequest* request) |
523 | { |
524 | assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request)); |
525 | m_request = request; |
526 | webkit_form_submission_request_submit(request); |
527 | quitMainLoop(); |
528 | } |
529 | |
530 | GHashTable* getTextFieldsAsHashTable() |
531 | { |
532 | #pragma GCC diagnostic push |
533 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" |
534 | return webkit_form_submission_request_get_text_fields(m_request.get()); |
535 | #pragma GCC diagnostic pop |
536 | } |
537 | |
538 | GPtrArray* getTextFieldNames() |
539 | { |
540 | GPtrArray* names; |
541 | webkit_form_submission_request_list_text_fields(m_request.get(), &names, nullptr); |
542 | return names; |
543 | } |
544 | |
545 | GPtrArray* getTextFieldValues() |
546 | { |
547 | GPtrArray* values; |
548 | webkit_form_submission_request_list_text_fields(m_request.get(), nullptr, &values); |
549 | return values; |
550 | } |
551 | |
552 | static gboolean doClickIdleCallback(FormClientTest* test) |
553 | { |
554 | test->clickMouseButton(test->m_submitPositionX, test->m_submitPositionY, 1); |
555 | return FALSE; |
556 | } |
557 | |
558 | void submitFormAtPosition(int x, int y) |
559 | { |
560 | m_submitPositionX = x; |
561 | m_submitPositionY = y; |
562 | g_idle_add(reinterpret_cast<GSourceFunc>(doClickIdleCallback), this); |
563 | g_main_loop_run(m_mainLoop); |
564 | } |
565 | |
566 | int m_submitPositionX; |
567 | int m_submitPositionY; |
568 | GRefPtr<WebKitFormSubmissionRequest> m_request; |
569 | }; |
570 | |
571 | static void testWebViewSubmitForm(FormClientTest* test, gconstpointer) |
572 | { |
573 | test->showInWindowAndWaitUntilMapped(); |
574 | |
575 | const char* formHTML = |
576 | "<html><body>" |
577 | " <form action='#'>" |
578 | " <input type='text' name='text1' value='value1'>" |
579 | " <input type='text' name='text2' value='value2'>" |
580 | " <input type='text' value='value3'>" |
581 | " <input type='text' name='text2'>" |
582 | " <input type='password' name='password' value='secret'>" |
583 | " <textarea cols='5' rows='5' name='textarea'>Text</textarea>" |
584 | " <input type='hidden' name='hidden1' value='hidden1'>" |
585 | " <input type='submit' value='Submit' style='position:absolute; left:1; top:1' size='10'>" |
586 | " </form>" |
587 | "</body></html>" ; |
588 | |
589 | test->loadHtml(formHTML, "file:///" ); |
590 | test->waitUntilLoadFinished(); |
591 | |
592 | test->submitFormAtPosition(5, 5); |
593 | GHashTable* tableValues = test->getTextFieldsAsHashTable(); |
594 | g_assert_nonnull(tableValues); |
595 | g_assert_cmpuint(g_hash_table_size(tableValues), ==, 4); |
596 | g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(tableValues, "text1" )), ==, "value1" ); |
597 | g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(tableValues, "" )), ==, "value3" ); |
598 | g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(tableValues, "text2" )), ==, "" ); |
599 | g_assert_cmpstr(static_cast<char*>(g_hash_table_lookup(tableValues, "password" )), ==, "secret" ); |
600 | |
601 | GPtrArray* names = test->getTextFieldNames(); |
602 | g_assert_nonnull(names); |
603 | g_assert_cmpuint(names->len, ==, 5); |
604 | g_assert_cmpstr(static_cast<char*>(names->pdata[0]), ==, "text1" ); |
605 | g_assert_cmpstr(static_cast<char*>(names->pdata[1]), ==, "text2" ); |
606 | g_assert_cmpstr(static_cast<char*>(names->pdata[2]), ==, "" ); |
607 | g_assert_cmpstr(static_cast<char*>(names->pdata[3]), ==, "text2" ); |
608 | g_assert_cmpstr(static_cast<char*>(names->pdata[4]), ==, "password" ); |
609 | |
610 | GPtrArray* values = test->getTextFieldValues(); |
611 | g_assert_nonnull(values); |
612 | g_assert_cmpuint(values->len, ==, 5); |
613 | g_assert_cmpstr(static_cast<char*>(values->pdata[0]), ==, "value1" ); |
614 | g_assert_cmpstr(static_cast<char*>(values->pdata[1]), ==, "value2" ); |
615 | g_assert_cmpstr(static_cast<char*>(values->pdata[2]), ==, "value3" ); |
616 | g_assert_cmpstr(static_cast<char*>(values->pdata[3]), ==, "" ); |
617 | g_assert_cmpstr(static_cast<char*>(values->pdata[4]), ==, "secret" ); |
618 | } |
619 | #endif // PLATFORM(GTK) |
620 | |
621 | class SaveWebViewTest: public WebViewTest { |
622 | public: |
623 | MAKE_GLIB_TEST_FIXTURE(SaveWebViewTest); |
624 | |
625 | SaveWebViewTest() |
626 | : m_tempDirectory(g_dir_make_tmp("WebKit2SaveViewTest-XXXXXX" , 0)) |
627 | { |
628 | } |
629 | |
630 | ~SaveWebViewTest() |
631 | { |
632 | if (G_IS_FILE(m_file.get())) |
633 | g_file_delete(m_file.get(), 0, 0); |
634 | |
635 | if (G_IS_INPUT_STREAM(m_inputStream.get())) |
636 | g_input_stream_close(m_inputStream.get(), 0, 0); |
637 | |
638 | if (m_tempDirectory) |
639 | g_rmdir(m_tempDirectory.get()); |
640 | } |
641 | |
642 | static void webViewSavedToStreamCallback(GObject* object, GAsyncResult* result, SaveWebViewTest* test) |
643 | { |
644 | GUniqueOutPtr<GError> error; |
645 | test->m_inputStream = adoptGRef(webkit_web_view_save_finish(test->m_webView, result, &error.outPtr())); |
646 | g_assert_true(G_IS_INPUT_STREAM(test->m_inputStream.get())); |
647 | g_assert_no_error(error.get()); |
648 | |
649 | test->quitMainLoop(); |
650 | } |
651 | |
652 | static void webViewSavedToFileCallback(GObject* object, GAsyncResult* result, SaveWebViewTest* test) |
653 | { |
654 | GUniqueOutPtr<GError> error; |
655 | g_assert_true(webkit_web_view_save_to_file_finish(test->m_webView, result, &error.outPtr())); |
656 | g_assert_no_error(error.get()); |
657 | |
658 | test->quitMainLoop(); |
659 | } |
660 | |
661 | void saveAndWaitForStream() |
662 | { |
663 | webkit_web_view_save(m_webView, WEBKIT_SAVE_MODE_MHTML, 0, reinterpret_cast<GAsyncReadyCallback>(webViewSavedToStreamCallback), this); |
664 | g_main_loop_run(m_mainLoop); |
665 | } |
666 | |
667 | void saveAndWaitForFile() |
668 | { |
669 | m_saveDestinationFilePath.reset(g_build_filename(m_tempDirectory.get(), "testWebViewSaveResult.mht" , NULL)); |
670 | m_file = adoptGRef(g_file_new_for_path(m_saveDestinationFilePath.get())); |
671 | webkit_web_view_save_to_file(m_webView, m_file.get(), WEBKIT_SAVE_MODE_MHTML, 0, reinterpret_cast<GAsyncReadyCallback>(webViewSavedToFileCallback), this); |
672 | g_main_loop_run(m_mainLoop); |
673 | } |
674 | |
675 | GUniquePtr<char> m_tempDirectory; |
676 | GUniquePtr<char> m_saveDestinationFilePath; |
677 | GRefPtr<GInputStream> m_inputStream; |
678 | GRefPtr<GFile> m_file; |
679 | }; |
680 | |
681 | static void testWebViewSave(SaveWebViewTest* test, gconstpointer) |
682 | { |
683 | test->loadHtml("<html>" |
684 | "<body>" |
685 | " <p>A paragraph with plain text</p>" |
686 | " <p>" |
687 | " A red box: <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYWDTMVwnSZnwAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFklEQVQI12P8z8DAwMDAxMDAwMDAAAANHQEDK+mmyAAAAABJRU5ErkJggg=='></br>" |
688 | " A blue box: <img src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3AYWDTMvBHhALQAAAB1pVFh0Q29tbWVudAAAAAAAQ3JlYXRlZCB3aXRoIEdJTVBkLmUHAAAAFklEQVQI12Nk4PnPwMDAxMDAwMDAAAALrwEPPIs1pgAAAABJRU5ErkJggg=='>" |
689 | " </p>" |
690 | "</body>" |
691 | "</html>" , 0); |
692 | test->waitUntilLoadFinished(); |
693 | |
694 | // Write to a file and to an input stream. |
695 | test->saveAndWaitForFile(); |
696 | test->saveAndWaitForStream(); |
697 | |
698 | // We should have exactly the same amount of bytes in the file |
699 | // than those coming from the GInputStream. We don't compare the |
700 | // strings read since the 'Date' field and the boundaries will be |
701 | // different on each case. MHTML functionality will be tested by |
702 | // Layout tests, so checking the amount of bytes is enough. |
703 | GUniqueOutPtr<GError> error; |
704 | gchar buffer[512] = { 0 }; |
705 | gssize readBytes = 0; |
706 | gssize totalBytesFromStream = 0; |
707 | while ((readBytes = g_input_stream_read(test->m_inputStream.get(), &buffer, 512, 0, &error.outPtr()))) { |
708 | g_assert_no_error(error.get()); |
709 | totalBytesFromStream += readBytes; |
710 | } |
711 | |
712 | // Check that the file exists and that it contains the same amount of bytes. |
713 | GRefPtr<GFileInfo> fileInfo = adoptGRef(g_file_query_info(test->m_file.get(), G_FILE_ATTRIBUTE_STANDARD_SIZE, static_cast<GFileQueryInfoFlags>(0), 0, 0)); |
714 | g_assert_cmpint(g_file_info_get_size(fileInfo.get()), ==, totalBytesFromStream); |
715 | } |
716 | |
717 | // To test page visibility API. Currently only 'visible', 'hidden' and 'prerender' states are implemented fully in WebCore. |
718 | // See also http://www.w3.org/TR/2011/WD-page-visibility-20110602/ and https://developers.google.com/chrome/whitepapers/pagevisibility |
719 | static void testWebViewPageVisibility(WebViewTest* test, gconstpointer) |
720 | { |
721 | test->loadHtml("<html><title></title>" |
722 | "<body><p>Test Web Page Visibility</p>" |
723 | "<script>" |
724 | "document.addEventListener(\"visibilitychange\", onVisibilityChange, false);" |
725 | "function onVisibilityChange() {" |
726 | " document.title = document.visibilityState;" |
727 | "}" |
728 | "</script>" |
729 | "</body></html>" , |
730 | 0); |
731 | |
732 | // Wait until the page is loaded. Initial visibility should be 'prerender'. |
733 | test->waitUntilLoadFinished(); |
734 | |
735 | GUniqueOutPtr<GError> error; |
736 | WebKitJavascriptResult* javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.visibilityState;" , &error.outPtr()); |
737 | g_assert_nonnull(javascriptResult); |
738 | g_assert_no_error(error.get()); |
739 | GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult)); |
740 | g_assert_cmpstr(valueString.get(), ==, "prerender" ); |
741 | |
742 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.hidden;" , &error.outPtr()); |
743 | g_assert_nonnull(javascriptResult); |
744 | g_assert_no_error(error.get()); |
745 | g_assert_true(WebViewTest::javascriptResultToBoolean(javascriptResult)); |
746 | |
747 | // Show the page. The visibility should be updated to 'visible'. |
748 | test->showInWindow(); |
749 | test->waitUntilTitleChanged(); |
750 | |
751 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.visibilityState;" , &error.outPtr()); |
752 | g_assert_nonnull(javascriptResult); |
753 | g_assert_no_error(error.get()); |
754 | valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
755 | g_assert_cmpstr(valueString.get(), ==, "visible" ); |
756 | |
757 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.hidden;" , &error.outPtr()); |
758 | g_assert_nonnull(javascriptResult); |
759 | g_assert_no_error(error.get()); |
760 | g_assert_false(WebViewTest::javascriptResultToBoolean(javascriptResult)); |
761 | |
762 | // Hide the page. The visibility should be updated to 'hidden'. |
763 | test->hideView(); |
764 | test->waitUntilTitleChanged(); |
765 | |
766 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.visibilityState;" , &error.outPtr()); |
767 | g_assert_nonnull(javascriptResult); |
768 | g_assert_no_error(error.get()); |
769 | valueString.reset(WebViewTest::javascriptResultToCString(javascriptResult)); |
770 | g_assert_cmpstr(valueString.get(), ==, "hidden" ); |
771 | |
772 | javascriptResult = test->runJavaScriptAndWaitUntilFinished("document.hidden;" , &error.outPtr()); |
773 | g_assert_nonnull(javascriptResult); |
774 | g_assert_no_error(error.get()); |
775 | g_assert_true(WebViewTest::javascriptResultToBoolean(javascriptResult)); |
776 | } |
777 | |
778 | #if PLATFORM(GTK) |
779 | class SnapshotWebViewTest: public WebViewTest { |
780 | public: |
781 | MAKE_GLIB_TEST_FIXTURE(SnapshotWebViewTest); |
782 | |
783 | static void onSnapshotCancelledReady(WebKitWebView* web_view, GAsyncResult* res, SnapshotWebViewTest* test) |
784 | { |
785 | GUniqueOutPtr<GError> error; |
786 | test->m_surface = webkit_web_view_get_snapshot_finish(web_view, res, &error.outPtr()); |
787 | g_assert_null(test->m_surface); |
788 | g_assert_error(error.get(), G_IO_ERROR, G_IO_ERROR_CANCELLED); |
789 | test->quitMainLoop(); |
790 | } |
791 | |
792 | gboolean getSnapshotAndCancel() |
793 | { |
794 | if (m_surface) |
795 | cairo_surface_destroy(m_surface); |
796 | m_surface = 0; |
797 | GRefPtr<GCancellable> cancellable = adoptGRef(g_cancellable_new()); |
798 | webkit_web_view_get_snapshot(m_webView, WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE, cancellable.get(), reinterpret_cast<GAsyncReadyCallback>(onSnapshotCancelledReady), this); |
799 | g_cancellable_cancel(cancellable.get()); |
800 | g_main_loop_run(m_mainLoop); |
801 | |
802 | return true; |
803 | } |
804 | |
805 | }; |
806 | |
807 | static void testWebViewSnapshot(SnapshotWebViewTest* test, gconstpointer) |
808 | { |
809 | test->loadHtml("<html><head><style>html { width: 200px; height: 100px; } ::-webkit-scrollbar { display: none; }</style></head><body><p>Whatever</p></body></html>" , nullptr); |
810 | test->waitUntilLoadFinished(); |
811 | |
812 | // WEBKIT_SNAPSHOT_REGION_VISIBLE returns a null surface when the view is not visible. |
813 | cairo_surface_t* surface1 = test->getSnapshotAndWaitUntilReady(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE); |
814 | g_assert_null(surface1); |
815 | |
816 | // WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT works even if the window is not visible. |
817 | surface1 = test->getSnapshotAndWaitUntilReady(WEBKIT_SNAPSHOT_REGION_FULL_DOCUMENT, WEBKIT_SNAPSHOT_OPTIONS_NONE); |
818 | g_assert_nonnull(surface1); |
819 | g_assert_cmpuint(cairo_surface_get_type(surface1), ==, CAIRO_SURFACE_TYPE_IMAGE); |
820 | g_assert_cmpint(cairo_image_surface_get_width(surface1), ==, 200); |
821 | g_assert_cmpint(cairo_image_surface_get_height(surface1), ==, 100); |
822 | |
823 | // Show the WebView in a popup widow of 50x50 and try again with WEBKIT_SNAPSHOT_REGION_VISIBLE. |
824 | test->showInWindowAndWaitUntilMapped(GTK_WINDOW_POPUP, 50, 50); |
825 | surface1 = cairo_surface_reference(test->getSnapshotAndWaitUntilReady(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE)); |
826 | g_assert_nonnull(surface1); |
827 | g_assert_cmpuint(cairo_surface_get_type(surface1), ==, CAIRO_SURFACE_TYPE_IMAGE); |
828 | g_assert_cmpint(cairo_image_surface_get_width(surface1), ==, 50); |
829 | g_assert_cmpint(cairo_image_surface_get_height(surface1), ==, 50); |
830 | |
831 | // Select all text in the WebView, request a snapshot ignoring selection. |
832 | test->selectAll(); |
833 | cairo_surface_t* surface2 = test->getSnapshotAndWaitUntilReady(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_NONE); |
834 | g_assert_nonnull(surface2); |
835 | g_assert_true(Test::cairoSurfacesEqual(surface1, surface2)); |
836 | |
837 | // Request a new snapshot, including the selection this time. The size should be the same but the result |
838 | // must be different to the one previously obtained. |
839 | surface2 = test->getSnapshotAndWaitUntilReady(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_INCLUDE_SELECTION_HIGHLIGHTING); |
840 | g_assert_cmpuint(cairo_surface_get_type(surface2), ==, CAIRO_SURFACE_TYPE_IMAGE); |
841 | g_assert_cmpint(cairo_image_surface_get_width(surface1), ==, cairo_image_surface_get_width(surface2)); |
842 | g_assert_cmpint(cairo_image_surface_get_height(surface1), ==, cairo_image_surface_get_height(surface2)); |
843 | g_assert_false(Test::cairoSurfacesEqual(surface1, surface2)); |
844 | |
845 | // Get a snpashot with a transparent background, the result must be different. |
846 | surface2 = test->getSnapshotAndWaitUntilReady(WEBKIT_SNAPSHOT_REGION_VISIBLE, WEBKIT_SNAPSHOT_OPTIONS_TRANSPARENT_BACKGROUND); |
847 | g_assert_cmpuint(cairo_surface_get_type(surface2), ==, CAIRO_SURFACE_TYPE_IMAGE); |
848 | g_assert_cmpint(cairo_image_surface_get_width(surface1), ==, cairo_image_surface_get_width(surface2)); |
849 | g_assert_cmpint(cairo_image_surface_get_height(surface1), ==, cairo_image_surface_get_height(surface2)); |
850 | g_assert_false(Test::cairoSurfacesEqual(surface1, surface2)); |
851 | cairo_surface_destroy(surface1); |
852 | |
853 | // Test that cancellation works. |
854 | g_assert_true(test->getSnapshotAndCancel()); |
855 | } |
856 | #endif // PLATFORM(GTK) |
857 | |
858 | #if ENABLE(NOTIFICATIONS) |
859 | class NotificationWebViewTest: public WebViewTest { |
860 | public: |
861 | MAKE_GLIB_TEST_FIXTURE_WITH_SETUP_TEARDOWN(NotificationWebViewTest, setup, teardown); |
862 | |
863 | static void setup() |
864 | { |
865 | WebViewTest::shouldInitializeWebViewInConstructor = false; |
866 | } |
867 | |
868 | static void teardown() |
869 | { |
870 | WebViewTest::shouldInitializeWebViewInConstructor = true; |
871 | } |
872 | |
873 | enum NotificationEvent { |
874 | None, |
875 | Permission, |
876 | Shown, |
877 | Clicked, |
878 | OnClicked, |
879 | Closed, |
880 | OnClosed, |
881 | }; |
882 | |
883 | static gboolean permissionRequestCallback(WebKitWebView*, WebKitPermissionRequest *request, NotificationWebViewTest* test) |
884 | { |
885 | g_assert_true(WEBKIT_IS_NOTIFICATION_PERMISSION_REQUEST(request)); |
886 | g_assert_true(test->m_isExpectingPermissionRequest); |
887 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(request)); |
888 | |
889 | test->m_event = Permission; |
890 | |
891 | webkit_permission_request_allow(request); |
892 | |
893 | g_main_loop_quit(test->m_mainLoop); |
894 | |
895 | return TRUE; |
896 | } |
897 | |
898 | static gboolean notificationClosedCallback(WebKitNotification* notification, NotificationWebViewTest* test) |
899 | { |
900 | g_assert_true(test->m_notification == notification); |
901 | test->m_notification = nullptr; |
902 | test->m_event = Closed; |
903 | if (g_main_loop_is_running(test->m_mainLoop)) |
904 | g_main_loop_quit(test->m_mainLoop); |
905 | return TRUE; |
906 | } |
907 | |
908 | static gboolean notificationClickedCallback(WebKitNotification* notification, NotificationWebViewTest* test) |
909 | { |
910 | g_assert_true(test->m_notification == notification); |
911 | test->m_event = Clicked; |
912 | return TRUE; |
913 | } |
914 | |
915 | static gboolean showNotificationCallback(WebKitWebView*, WebKitNotification* notification, NotificationWebViewTest* test) |
916 | { |
917 | g_assert_null(test->m_notification); |
918 | test->assertObjectIsDeletedWhenTestFinishes(G_OBJECT(notification)); |
919 | test->m_notification = notification; |
920 | g_signal_connect(notification, "closed" , G_CALLBACK(notificationClosedCallback), test); |
921 | g_signal_connect(notification, "clicked" , G_CALLBACK(notificationClickedCallback), test); |
922 | test->m_event = Shown; |
923 | g_main_loop_quit(test->m_mainLoop); |
924 | return TRUE; |
925 | } |
926 | |
927 | static void notificationsMessageReceivedCallback(WebKitUserContentManager* userContentManager, WebKitJavascriptResult* javascriptResult, NotificationWebViewTest* test) |
928 | { |
929 | GUniquePtr<char> valueString(WebViewTest::javascriptResultToCString(javascriptResult)); |
930 | |
931 | if (g_str_equal(valueString.get(), "clicked" )) |
932 | test->m_event = OnClicked; |
933 | else if (g_str_equal(valueString.get(), "closed" )) |
934 | test->m_event = OnClosed; |
935 | |
936 | g_main_loop_quit(test->m_mainLoop); |
937 | } |
938 | |
939 | void initialize() |
940 | { |
941 | initializeWebView(); |
942 | g_signal_connect(m_webView, "permission-request" , G_CALLBACK(permissionRequestCallback), this); |
943 | g_signal_connect(m_webView, "show-notification" , G_CALLBACK(showNotificationCallback), this); |
944 | webkit_user_content_manager_register_script_message_handler(m_userContentManager.get(), "notifications" ); |
945 | g_signal_connect(m_userContentManager.get(), "script-message-received::notifications" , G_CALLBACK(notificationsMessageReceivedCallback), this); |
946 | } |
947 | |
948 | ~NotificationWebViewTest() |
949 | { |
950 | g_signal_handlers_disconnect_matched(m_webView, G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); |
951 | g_signal_handlers_disconnect_matched(m_userContentManager.get(), G_SIGNAL_MATCH_DATA, 0, 0, 0, 0, this); |
952 | webkit_user_content_manager_unregister_script_message_handler(m_userContentManager.get(), "notifications" ); |
953 | } |
954 | |
955 | bool hasPermission() |
956 | { |
957 | auto* result = runJavaScriptAndWaitUntilFinished("Notification.permission;" , nullptr); |
958 | g_assert_nonnull(result); |
959 | GUniquePtr<char> value(javascriptResultToCString(result)); |
960 | return !g_strcmp0(value.get(), "granted" ); |
961 | } |
962 | |
963 | void requestPermissionAndWaitUntilGiven() |
964 | { |
965 | m_event = None; |
966 | m_isExpectingPermissionRequest = true; |
967 | webkit_web_view_run_javascript(m_webView, "Notification.requestPermission();" , nullptr, nullptr, nullptr); |
968 | g_main_loop_run(m_mainLoop); |
969 | } |
970 | |
971 | void requestNotificationAndWaitUntilShown(const char* title, const char* body) |
972 | { |
973 | m_event = None; |
974 | |
975 | GUniquePtr<char> jscode(g_strdup_printf("n = new Notification('%s', { body: '%s'});" , title, body)); |
976 | webkit_web_view_run_javascript(m_webView, jscode.get(), nullptr, nullptr, nullptr); |
977 | |
978 | g_main_loop_run(m_mainLoop); |
979 | } |
980 | |
981 | void requestNotificationAndWaitUntilShown(const char* title, const char* body, const char* tag) |
982 | { |
983 | m_event = None; |
984 | |
985 | GUniquePtr<char> jscode(g_strdup_printf("n = new Notification('%s', { body: '%s', tag: '%s'});" , title, body, tag)); |
986 | webkit_web_view_run_javascript(m_webView, jscode.get(), nullptr, nullptr, nullptr); |
987 | |
988 | g_main_loop_run(m_mainLoop); |
989 | } |
990 | |
991 | void clickNotificationAndWaitUntilClicked() |
992 | { |
993 | m_event = None; |
994 | runJavaScriptAndWaitUntilFinished("n.onclick = function() { window.webkit.messageHandlers.notifications.postMessage('clicked'); }" , nullptr); |
995 | webkit_notification_clicked(m_notification); |
996 | g_assert_cmpint(m_event, ==, Clicked); |
997 | g_main_loop_run(m_mainLoop); |
998 | } |
999 | |
1000 | void closeNotificationAndWaitUntilClosed() |
1001 | { |
1002 | m_event = None; |
1003 | webkit_web_view_run_javascript(m_webView, "n.close()" , nullptr, nullptr, nullptr); |
1004 | g_main_loop_run(m_mainLoop); |
1005 | } |
1006 | |
1007 | void closeNotificationAndWaitUntilOnClosed() |
1008 | { |
1009 | g_assert_nonnull(m_notification); |
1010 | m_event = None; |
1011 | runJavaScriptAndWaitUntilFinished("n.onclose = function() { window.webkit.messageHandlers.notifications.postMessage('closed'); }" , nullptr); |
1012 | webkit_notification_close(m_notification); |
1013 | g_assert_cmpint(m_event, ==, Closed); |
1014 | g_main_loop_run(m_mainLoop); |
1015 | } |
1016 | |
1017 | NotificationEvent m_event { None }; |
1018 | WebKitNotification* m_notification { nullptr }; |
1019 | bool m_isExpectingPermissionRequest { false }; |
1020 | bool m_hasPermission { false }; |
1021 | }; |
1022 | |
1023 | static void testWebViewNotification(NotificationWebViewTest* test, gconstpointer) |
1024 | { |
1025 | test->initialize(); |
1026 | |
1027 | // Notifications don't work with local or special schemes. |
1028 | test->loadURI(gServer->getURIForPath("/" ).data()); |
1029 | test->waitUntilLoadFinished(); |
1030 | g_assert_false(test->hasPermission()); |
1031 | |
1032 | test->requestPermissionAndWaitUntilGiven(); |
1033 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::Permission); |
1034 | g_assert_true(test->hasPermission()); |
1035 | |
1036 | static const char* title = "This is a notification" ; |
1037 | static const char* body = "This is the body." ; |
1038 | static const char* tag = "This is the tag." ; |
1039 | test->requestNotificationAndWaitUntilShown(title, body, tag); |
1040 | |
1041 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::Shown); |
1042 | g_assert_nonnull(test->m_notification); |
1043 | g_assert_cmpstr(webkit_notification_get_title(test->m_notification), ==, title); |
1044 | g_assert_cmpstr(webkit_notification_get_body(test->m_notification), ==, body); |
1045 | g_assert_cmpstr(webkit_notification_get_tag(test->m_notification), ==, tag); |
1046 | |
1047 | test->clickNotificationAndWaitUntilClicked(); |
1048 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::OnClicked); |
1049 | |
1050 | test->closeNotificationAndWaitUntilClosed(); |
1051 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::Closed); |
1052 | |
1053 | test->requestNotificationAndWaitUntilShown(title, body); |
1054 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::Shown); |
1055 | g_assert_cmpstr(webkit_notification_get_tag(test->m_notification), ==, nullptr); |
1056 | |
1057 | test->closeNotificationAndWaitUntilOnClosed(); |
1058 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::OnClosed); |
1059 | |
1060 | // The first notification should be closed automatically because the tag is |
1061 | // the same. It will crash in showNotificationCallback on failure. |
1062 | test->requestNotificationAndWaitUntilShown(title, body, tag); |
1063 | test->requestNotificationAndWaitUntilShown(title, body, tag); |
1064 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::Shown); |
1065 | } |
1066 | |
1067 | static void setInitialNotificationPermissionsAllowedCallback(WebKitWebContext* context, NotificationWebViewTest* test) |
1068 | { |
1069 | GUniquePtr<char> baseURI(soup_uri_to_string(gServer->baseURI(), FALSE)); |
1070 | GList* allowedOrigins = g_list_prepend(nullptr, webkit_security_origin_new_for_uri(baseURI.get())); |
1071 | webkit_web_context_initialize_notification_permissions(test->m_webContext.get(), allowedOrigins, nullptr); |
1072 | g_list_free_full(allowedOrigins, reinterpret_cast<GDestroyNotify>(webkit_security_origin_unref)); |
1073 | } |
1074 | |
1075 | static void setInitialNotificationPermissionsDisallowedCallback(WebKitWebContext* context, NotificationWebViewTest* test) |
1076 | { |
1077 | GUniquePtr<char> baseURI(soup_uri_to_string(gServer->baseURI(), FALSE)); |
1078 | GList* disallowedOrigins = g_list_prepend(nullptr, webkit_security_origin_new_for_uri(baseURI.get())); |
1079 | webkit_web_context_initialize_notification_permissions(test->m_webContext.get(), nullptr, disallowedOrigins); |
1080 | g_list_free_full(disallowedOrigins, reinterpret_cast<GDestroyNotify>(webkit_security_origin_unref)); |
1081 | } |
1082 | |
1083 | static void testWebViewNotificationInitialPermissionAllowed(NotificationWebViewTest* test, gconstpointer) |
1084 | { |
1085 | g_signal_connect(test->m_webContext.get(), "initialize-notification-permissions" , G_CALLBACK(setInitialNotificationPermissionsAllowedCallback), test); |
1086 | test->initialize(); |
1087 | |
1088 | test->loadURI(gServer->getURIForPath("/" ).data()); |
1089 | test->waitUntilLoadFinished(); |
1090 | g_assert_true(test->hasPermission()); |
1091 | |
1092 | test->requestNotificationAndWaitUntilShown("This is a notification" , "This is the body." ); |
1093 | g_assert_cmpint(test->m_event, ==, NotificationWebViewTest::Shown); |
1094 | } |
1095 | |
1096 | static void testWebViewNotificationInitialPermissionDisallowed(NotificationWebViewTest* test, gconstpointer) |
1097 | { |
1098 | g_signal_connect(test->m_webContext.get(), "initialize-notification-permissions" , G_CALLBACK(setInitialNotificationPermissionsDisallowedCallback), test); |
1099 | test->initialize(); |
1100 | |
1101 | test->loadURI(gServer->getURIForPath("/" ).data()); |
1102 | test->waitUntilLoadFinished(); |
1103 | g_assert_false(test->hasPermission()); |
1104 | } |
1105 | #endif // ENABLE(NOTIFICATIONS) |
1106 | |
1107 | static void testWebViewIsPlayingAudio(IsPlayingAudioWebViewTest* test, gconstpointer) |
1108 | { |
1109 | #if PLATFORM(GTK) |
1110 | // The web view must be realized for the video to start playback and |
1111 | // trigger changes in WebKitWebView::is-playing-audio. |
1112 | test->showInWindowAndWaitUntilMapped(GTK_WINDOW_TOPLEVEL); |
1113 | #endif |
1114 | |
1115 | // Initially, web views should always report no audio being played. |
1116 | g_assert_false(webkit_web_view_is_playing_audio(test->m_webView)); |
1117 | |
1118 | GUniquePtr<char> resourcePath(g_build_filename(Test::getResourcesDir(Test::WebKit2Resources).data(), "file-with-video.html" , nullptr)); |
1119 | GUniquePtr<char> resourceURL(g_filename_to_uri(resourcePath.get(), nullptr, nullptr)); |
1120 | webkit_web_view_load_uri(test->m_webView, resourceURL.get()); |
1121 | test->waitUntilLoadFinished(); |
1122 | g_assert_false(webkit_web_view_is_playing_audio(test->m_webView)); |
1123 | |
1124 | test->runJavaScriptAndWaitUntilFinished("playVideo();" , nullptr); |
1125 | if (!webkit_web_view_is_playing_audio(test->m_webView)) |
1126 | test->waitUntilIsPlayingAudioChanged(); |
1127 | g_assert_true(webkit_web_view_is_playing_audio(test->m_webView)); |
1128 | |
1129 | // Pause the video, and check again. |
1130 | test->runJavaScriptAndWaitUntilFinished("document.getElementById('test-video').pause();" , nullptr); |
1131 | if (webkit_web_view_is_playing_audio(test->m_webView)) |
1132 | test->waitUntilIsPlayingAudioChanged(); |
1133 | g_assert_false(webkit_web_view_is_playing_audio(test->m_webView)); |
1134 | } |
1135 | |
1136 | static void testWebViewBackgroundColor(WebViewTest* test, gconstpointer) |
1137 | { |
1138 | #if PLATFORM(GTK) |
1139 | #define ColorType GdkRGBA |
1140 | #elif PLATFORM(WPE) |
1141 | #define ColorType WebKitColor |
1142 | #endif |
1143 | |
1144 | // White is the default background. |
1145 | ColorType rgba; |
1146 | webkit_web_view_get_background_color(test->m_webView, &rgba); |
1147 | g_assert_cmpfloat(rgba.red, ==, 1); |
1148 | g_assert_cmpfloat(rgba.green, ==, 1); |
1149 | g_assert_cmpfloat(rgba.blue, ==, 1); |
1150 | g_assert_cmpfloat(rgba.alpha, ==, 1); |
1151 | |
1152 | // Set a different (semi-transparent red). |
1153 | rgba.red = 1; |
1154 | rgba.green = 0; |
1155 | rgba.blue = 0; |
1156 | rgba.alpha = 0.5; |
1157 | webkit_web_view_set_background_color(test->m_webView, &rgba); |
1158 | g_assert_cmpfloat(rgba.red, ==, 1); |
1159 | g_assert_cmpfloat(rgba.green, ==, 0); |
1160 | g_assert_cmpfloat(rgba.blue, ==, 0); |
1161 | g_assert_cmpfloat(rgba.alpha, ==, 0.5); |
1162 | |
1163 | #if PLATFORM(WPE) |
1164 | ColorType color; |
1165 | g_assert(webkit_color_parse(&color, "red" )); |
1166 | g_assert_cmpfloat(color.red, ==, 1); |
1167 | webkit_web_view_set_background_color(test->m_webView, &color); |
1168 | webkit_web_view_get_background_color(test->m_webView, &rgba); |
1169 | g_assert_cmpfloat(rgba.red, ==, 1); |
1170 | g_assert_cmpfloat(rgba.green, ==, 0); |
1171 | g_assert_cmpfloat(rgba.blue, ==, 0); |
1172 | g_assert_cmpfloat(rgba.alpha, ==, 1); |
1173 | #endif |
1174 | |
1175 | // The actual rendering can't be tested using unit tests, use |
1176 | // MiniBrowser --bg-color="<color-value>" for manually testing this API. |
1177 | } |
1178 | |
1179 | #if PLATFORM(GTK) |
1180 | static void testWebViewPreferredSize(WebViewTest* test, gconstpointer) |
1181 | { |
1182 | test->loadHtml("<html style='width: 325px; height: 615px'></html>" , nullptr); |
1183 | test->waitUntilLoadFinished(); |
1184 | test->showInWindowAndWaitUntilMapped(); |
1185 | GtkRequisition minimunSize, naturalSize; |
1186 | gtk_widget_get_preferred_size(GTK_WIDGET(test->m_webView), &minimunSize, &naturalSize); |
1187 | g_assert_cmpint(minimunSize.width, ==, 0); |
1188 | g_assert_cmpint(minimunSize.height, ==, 0); |
1189 | g_assert_cmpint(naturalSize.width, ==, 325); |
1190 | g_assert_cmpint(naturalSize.height, ==, 615); |
1191 | } |
1192 | #endif |
1193 | |
1194 | class WebViewTitleTest: public WebViewTest { |
1195 | public: |
1196 | MAKE_GLIB_TEST_FIXTURE(WebViewTitleTest); |
1197 | |
1198 | static void titleChangedCallback(WebKitWebView* view, GParamSpec*, WebViewTitleTest* test) |
1199 | { |
1200 | test->m_webViewTitles.append(webkit_web_view_get_title(view)); |
1201 | } |
1202 | |
1203 | WebViewTitleTest() |
1204 | { |
1205 | g_signal_connect(m_webView, "notify::title" , G_CALLBACK(titleChangedCallback), this); |
1206 | } |
1207 | |
1208 | Vector<CString> m_webViewTitles; |
1209 | }; |
1210 | |
1211 | static void testWebViewTitleChange(WebViewTitleTest* test, gconstpointer) |
1212 | { |
1213 | g_assert_cmpint(test->m_webViewTitles.size(), ==, 0); |
1214 | |
1215 | test->loadHtml("<head><title>Page Title</title></head>" , nullptr); |
1216 | test->waitUntilLoadFinished(); |
1217 | g_assert_cmpint(test->m_webViewTitles.size(), ==, 1); |
1218 | g_assert_cmpstr(test->m_webViewTitles[0].data(), ==, "Page Title" ); |
1219 | |
1220 | test->loadHtml("<head><title>Another Page Title</title></head>" , nullptr); |
1221 | test->waitUntilLoadFinished(); |
1222 | g_assert_cmpint(test->m_webViewTitles.size(), ==, 3); |
1223 | /* Page title should be immediately unset when loading a new page. */ |
1224 | g_assert_cmpstr(test->m_webViewTitles[1].data(), ==, "" ); |
1225 | g_assert_cmpstr(test->m_webViewTitles[2].data(), ==, "Another Page Title" ); |
1226 | |
1227 | test->loadHtml("<p>This page has no title!</p>" , nullptr); |
1228 | test->waitUntilLoadFinished(); |
1229 | g_assert_cmpint(test->m_webViewTitles.size(), ==, 4); |
1230 | g_assert_cmpstr(test->m_webViewTitles[3].data(), ==, "" ); |
1231 | |
1232 | test->loadHtml("<script>document.title = 'one'; document.title = 'two'; document.title = 'three';</script>" , nullptr); |
1233 | test->waitUntilLoadFinished(); |
1234 | g_assert_cmpint(test->m_webViewTitles.size(), ==, 7); |
1235 | g_assert_cmpstr(test->m_webViewTitles[4].data(), ==, "one" ); |
1236 | g_assert_cmpstr(test->m_webViewTitles[5].data(), ==, "two" ); |
1237 | g_assert_cmpstr(test->m_webViewTitles[6].data(), ==, "three" ); |
1238 | } |
1239 | |
1240 | #if PLATFORM(WPE) |
1241 | class FrameDisplayedTest: public WebViewTest { |
1242 | public: |
1243 | MAKE_GLIB_TEST_FIXTURE(FrameDisplayedTest); |
1244 | |
1245 | static void titleChangedCallback(WebKitWebView* view, GParamSpec*, WebViewTitleTest* test) |
1246 | { |
1247 | test->m_webViewTitles.append(webkit_web_view_get_title(view)); |
1248 | } |
1249 | |
1250 | FrameDisplayedTest() |
1251 | : m_id(webkit_web_view_add_frame_displayed_callback(m_webView, [](WebKitWebView*, gpointer userData) { |
1252 | auto* test = static_cast<FrameDisplayedTest*>(userData); |
1253 | if (!test->m_maxFrames) |
1254 | return; |
1255 | |
1256 | if (++test->m_frameCounter == test->m_maxFrames) |
1257 | RunLoop::main().dispatch([test] { test->quitMainLoop(); }); |
1258 | }, this, nullptr)) |
1259 | { |
1260 | g_assert_cmpuint(m_id, >, 0); |
1261 | } |
1262 | |
1263 | ~FrameDisplayedTest() |
1264 | { |
1265 | webkit_web_view_remove_frame_displayed_callback(m_webView, m_id); |
1266 | } |
1267 | |
1268 | void waitUntilFramesDisplayed(unsigned framesCount = 1) |
1269 | { |
1270 | m_maxFrames = framesCount; |
1271 | m_frameCounter = 0; |
1272 | g_main_loop_run(m_mainLoop); |
1273 | } |
1274 | |
1275 | unsigned m_id { 0 }; |
1276 | unsigned m_frameCounter { 0 }; |
1277 | unsigned m_maxFrames { 0 }; |
1278 | }; |
1279 | |
1280 | static void testWebViewFrameDisplayed(FrameDisplayedTest* test, gconstpointer) |
1281 | { |
1282 | test->showInWindow(); |
1283 | |
1284 | test->loadHtml("<html></html>" , nullptr); |
1285 | test->waitUntilFramesDisplayed(); |
1286 | |
1287 | test->loadHtml("<html><head><style>@keyframes fadeIn { from { opacity: 0; } }</style></head><p style='animation: fadeIn 1s infinite alternate;'>Foo</p></html>" , nullptr); |
1288 | test->waitUntilFramesDisplayed(10); |
1289 | |
1290 | bool secondCallbackCalled = false; |
1291 | auto id = webkit_web_view_add_frame_displayed_callback(test->m_webView, [](WebKitWebView*, gpointer userData) { |
1292 | auto* secondCallbackCalled = static_cast<bool*>(userData); |
1293 | *secondCallbackCalled = true; |
1294 | }, &secondCallbackCalled, nullptr); |
1295 | test->waitUntilFramesDisplayed(); |
1296 | g_assert_true(secondCallbackCalled); |
1297 | |
1298 | secondCallbackCalled = false; |
1299 | webkit_web_view_remove_frame_displayed_callback(test->m_webView, id); |
1300 | test->waitUntilFramesDisplayed(); |
1301 | g_assert_false(secondCallbackCalled); |
1302 | |
1303 | id = webkit_web_view_add_frame_displayed_callback(test->m_webView, [](WebKitWebView* webView, gpointer userData) { |
1304 | auto* id = static_cast<unsigned*>(userData); |
1305 | webkit_web_view_remove_frame_displayed_callback(webView, *id); |
1306 | }, &id, [](gpointer userData) { |
1307 | auto* id = static_cast<unsigned*>(userData); |
1308 | *id = 0; |
1309 | }); |
1310 | test->waitUntilFramesDisplayed(); |
1311 | g_assert_cmpuint(id, ==, 0); |
1312 | |
1313 | auto id2 = webkit_web_view_add_frame_displayed_callback(test->m_webView, [](WebKitWebView* webView, gpointer userData) { |
1314 | auto* id = static_cast<unsigned*>(userData); |
1315 | if (*id) { |
1316 | webkit_web_view_remove_frame_displayed_callback(webView, *id); |
1317 | *id = 0; |
1318 | } |
1319 | }, &id, nullptr); |
1320 | |
1321 | secondCallbackCalled = false; |
1322 | id = webkit_web_view_add_frame_displayed_callback(test->m_webView, [](WebKitWebView* webView, gpointer userData) { |
1323 | auto* secondCallbackCalled = static_cast<bool*>(userData); |
1324 | *secondCallbackCalled = true; |
1325 | }, &secondCallbackCalled, nullptr); |
1326 | test->waitUntilFramesDisplayed(); |
1327 | g_assert_cmpuint(id, ==, 0); |
1328 | g_assert_false(secondCallbackCalled); |
1329 | |
1330 | webkit_web_view_remove_frame_displayed_callback(test->m_webView, id2); |
1331 | } |
1332 | #endif |
1333 | |
1334 | static void serverCallback(SoupServer* server, SoupMessage* message, const char* path, GHashTable*, SoupClientContext*, gpointer) |
1335 | { |
1336 | if (message->method != SOUP_METHOD_GET) { |
1337 | soup_message_set_status(message, SOUP_STATUS_NOT_IMPLEMENTED); |
1338 | return; |
1339 | } |
1340 | |
1341 | if (g_str_equal(path, "/" )) { |
1342 | soup_message_set_status(message, SOUP_STATUS_OK); |
1343 | soup_message_body_complete(message->response_body); |
1344 | } else |
1345 | soup_message_set_status(message, SOUP_STATUS_NOT_FOUND); |
1346 | } |
1347 | |
1348 | void beforeAll() |
1349 | { |
1350 | gServer = new WebKitTestServer(); |
1351 | gServer->run(serverCallback); |
1352 | |
1353 | WebViewTest::add("WebKitWebView" , "web-context" , testWebViewWebContext); |
1354 | WebViewTest::add("WebKitWebView" , "web-context-lifetime" , testWebViewWebContextLifetime); |
1355 | WebViewTest::add("WebKitWebView" , "close-quickly" , testWebViewCloseQuickly); |
1356 | #if PLATFORM(WPE) |
1357 | Test::add("WebKitWebView" , "backend" , testWebViewWebBackend); |
1358 | #endif |
1359 | WebViewTest::add("WebKitWebView" , "ephemeral" , testWebViewEphemeral); |
1360 | WebViewTest::add("WebKitWebView" , "custom-charset" , testWebViewCustomCharset); |
1361 | WebViewTest::add("WebKitWebView" , "settings" , testWebViewSettings); |
1362 | WebViewTest::add("WebKitWebView" , "zoom-level" , testWebViewZoomLevel); |
1363 | WebViewTest::add("WebKitWebView" , "run-javascript" , testWebViewRunJavaScript); |
1364 | #if ENABLE(FULLSCREEN_API) |
1365 | FullScreenClientTest::add("WebKitWebView" , "fullscreen" , testWebViewFullScreen); |
1366 | #endif |
1367 | WebViewTest::add("WebKitWebView" , "can-show-mime-type" , testWebViewCanShowMIMEType); |
1368 | // FIXME: implement mouse clicks in WPE. |
1369 | #if PLATFORM(GTK) |
1370 | FormClientTest::add("WebKitWebView" , "submit-form" , testWebViewSubmitForm); |
1371 | #endif |
1372 | SaveWebViewTest::add("WebKitWebView" , "save" , testWebViewSave); |
1373 | // FIXME: View is initially visible in WPE and has a fixed hardcoded size. |
1374 | #if PLATFORM(GTK) |
1375 | SnapshotWebViewTest::add("WebKitWebView" , "snapshot" , testWebViewSnapshot); |
1376 | #endif |
1377 | WebViewTest::add("WebKitWebView" , "page-visibility" , testWebViewPageVisibility); |
1378 | #if ENABLE(NOTIFICATIONS) |
1379 | NotificationWebViewTest::add("WebKitWebView" , "notification" , testWebViewNotification); |
1380 | NotificationWebViewTest::add("WebKitWebView" , "notification-initial-permission-allowed" , testWebViewNotificationInitialPermissionAllowed); |
1381 | NotificationWebViewTest::add("WebKitWebView" , "notification-initial-permission-disallowed" , testWebViewNotificationInitialPermissionDisallowed); |
1382 | #endif |
1383 | IsPlayingAudioWebViewTest::add("WebKitWebView" , "is-playing-audio" , testWebViewIsPlayingAudio); |
1384 | WebViewTest::add("WebKitWebView" , "background-color" , testWebViewBackgroundColor); |
1385 | #if PLATFORM(GTK) |
1386 | WebViewTest::add("WebKitWebView" , "preferred-size" , testWebViewPreferredSize); |
1387 | #endif |
1388 | WebViewTitleTest::add("WebKitWebView" , "title-change" , testWebViewTitleChange); |
1389 | #if PLATFORM(WPE) |
1390 | FrameDisplayedTest::add("WebKitWebView" , "frame-displayed" , testWebViewFrameDisplayed); |
1391 | #endif |
1392 | } |
1393 | |
1394 | void afterAll() |
1395 | { |
1396 | } |
1397 | |