Merge branch 'mjog/558-webkit-shared-process-redux' into 'mainline'

Webkit shared process redux

See merge request GNOME/geary!565
This commit is contained in:
Michael Gratton 2020-10-13 08:27:01 +00:00
commit fac257a273
34 changed files with 1512 additions and 666 deletions

View file

@ -6,35 +6,42 @@
*/
public abstract class ClientWebViewTestCase<V> : TestCase {
public abstract class Components.WebViewTestCase<V> : TestCase {
protected V? test_view = null;
protected Application.Configuration? config = null;
protected ClientWebViewTestCase(string name) {
protected WebViewTestCase(string name) {
base(name);
}
public override void set_up() {
this.config = new Application.Configuration(Application.Client.SCHEMA_ID);
this.config.enable_debug = true;
ClientWebView.init_web_context(
WebView.init_web_context(
this.config,
File.new_for_path(_BUILD_ROOT_DIR).get_child("src"),
File.new_for_path("/tmp") // XXX use something better here
);
try {
ClientWebView.load_resources(GLib.File.new_for_path("/tmp"));
WebView.load_resources(GLib.File.new_for_path("/tmp"));
} catch (GLib.Error err) {
GLib.assert_not_reached();
}
this.test_view = set_up_test_view();
}
public override void set_up() {
this.test_view = set_up_test_view();
protected override void tear_down() {
this.config = null;
this.test_view = null;
}
protected abstract V set_up_test_view();
protected virtual void load_body_fixture(string html = "") {
ClientWebView client_view = (ClientWebView) this.test_view;
WebView client_view = (WebView) this.test_view;
client_view.load_html(html);
while (!client_view.is_content_loaded) {
Gtk.main_iteration();
@ -42,7 +49,7 @@ public abstract class ClientWebViewTestCase<V> : TestCase {
}
protected WebKit.JavascriptResult run_javascript(string command) throws Error {
ClientWebView view = (ClientWebView) this.test_view;
WebView view = (WebView) this.test_view;
view.run_javascript.begin(command, null, this.async_completion);
return view.run_javascript.end(async_result());
}

View file

@ -5,10 +5,10 @@
* (version 2.1 or later). See the COPYING file in this distribution.
*/
public class ClientWebViewTest : TestCase {
public class Components.WebViewTest : TestCase {
public ClientWebViewTest() {
base("ClientWebViewTest");
public WebViewTest() {
base("Components.WebViewTest");
add_test("init_web_context", init_web_context);
add_test("load_resources", load_resources);
}
@ -18,7 +18,7 @@ public class ClientWebViewTest : TestCase {
Application.Client.SCHEMA_ID
);
config.enable_debug = true;
ClientWebView.init_web_context(
WebView.init_web_context(
config,
File.new_for_path(_BUILD_ROOT_DIR).get_child("src"),
File.new_for_path("/tmp") // XXX use something better here
@ -27,7 +27,7 @@ public class ClientWebViewTest : TestCase {
public void load_resources() throws GLib.Error {
try {
ClientWebView.load_resources(GLib.File.new_for_path("/tmp"));
WebView.load_resources(GLib.File.new_for_path("/tmp"));
} catch (GLib.Error err) {
assert_not_reached();
}

View file

@ -5,7 +5,7 @@
* (version 2.1 or later). See the COPYING file in this distribution.
*/
public class Composer.WebViewTest : ClientWebViewTestCase<Composer.WebView> {
public class Composer.WebViewTest : Components.WebViewTestCase<Composer.WebView> {
public WebViewTest() {

View file

@ -1,5 +1,5 @@
/*
* Copyright 2017 Michael Gratton <mike@vee.net>
* Copyright © 2017-2020 Michael Gratton <mike@vee.net>
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
@ -7,18 +7,152 @@
public class Util.JS.Test : TestCase {
private JSC.Context? context = null;
public Test() {
base("Util.JS.Test");
add_test("escape_string", escape_string);
add_test("to_variant", to_variant);
add_test("to_value", to_value);
}
public void escape_string() throws GLib.Error {
assert(Util.JS.escape_string("\n") == """\n""");
assert(Util.JS.escape_string("\r") == """\r""");
assert(Util.JS.escape_string("\t") == """\t""");
assert(Util.JS.escape_string("\'") == """\'""");
assert(Util.JS.escape_string("\"") == """\"""");
public override void set_up() throws GLib.Error {
this.context = new JSC.Context();
}
assert(Util.JS.escape_string("something…\n") == """something…\n""");
public override void tear_down() throws GLib.Error {
this.context = null;
}
public void to_variant() throws GLib.Error {
assert_equal(
value_to_variant(new JSC.Value.null(this.context)).print(true),
"@mv nothing"
);
assert_equal(
value_to_variant(new JSC.Value.string(this.context, "test")).print(true),
"'test'"
);
assert_equal(
value_to_variant(new JSC.Value.number(this.context, 1.0)).print(true),
"1.0"
);
assert_equal(
value_to_variant(new JSC.Value.boolean(this.context, true)).print(true),
"true"
);
assert_equal(
value_to_variant(new JSC.Value.boolean(this.context, false)).print(true),
"false"
);
var value = new JSC.Value.array_from_garray(this.context, null);
assert_equal(
value_to_variant(value).print(true),
"()"
);
var array = new GLib.GenericArray<JSC.Value>();
array.add(new JSC.Value.string(this.context, "test"));
value = new JSC.Value.array_from_garray(this.context, array);
assert_equal(
value_to_variant(value).print(true),
"['test']"
);
array = new GLib.GenericArray<JSC.Value>();
array.add(new JSC.Value.string(this.context, "test1"));
array.add(new JSC.Value.string(this.context, "test2"));
value = new JSC.Value.array_from_garray(this.context, array);
assert_equal(
value_to_variant(value).print(true),
"['test1', 'test2']"
);
array = new GLib.GenericArray<JSC.Value>();
array.add(new JSC.Value.string(this.context, "test"));
array.add(new JSC.Value.boolean(this.context, true));
value = new JSC.Value.array_from_garray(this.context, array);
assert_equal(
value_to_variant(value).print(true),
"('test', true)"
);
value = new JSC.Value.object(this.context, null, null);
assert_equal(
value_to_variant(value).print(true),
"@a{sv} {}"
);
value.object_set_property(
"test", new JSC.Value.boolean(this.context, true)
);
assert_equal(
value_to_variant(value).print(true),
"{'test': <true>}"
);
}
public void to_value() throws GLib.Error {
var variant = new GLib.Variant.maybe(GLib.VariantType.STRING, null);
var value = variant_to_value(this.context, variant);
assert_true(value.is_null(), variant.print(true));
variant = new GLib.Variant.string("test");
value = variant_to_value(this.context, variant);
assert_true(value.is_string(), variant.print(true));
assert_equal(value.to_string(), "test", variant.print(true));
variant = new GLib.Variant.int32(42);
value = variant_to_value(this.context, variant);
assert_true(value.is_number(), variant.print(true));
assert_equal<int32?>(value.to_int32(), 42, variant.print(true));
variant = new GLib.Variant.double(42.0);
value = variant_to_value(this.context, variant);
assert_true(value.is_number(), variant.print(true));
assert_within(value.to_double(), 42.0, 0.0000001, variant.print(true));
variant = new GLib.Variant.boolean(true);
value = variant_to_value(this.context, variant);
assert_true(value.is_boolean(), variant.print(true));
assert_true(value.to_boolean(), variant.print(true));
variant = new GLib.Variant.boolean(false);
value = variant_to_value(this.context, variant);
assert_true(value.is_boolean(), variant.print(true));
assert_false(value.to_boolean(), variant.print(true));
variant = new GLib.Variant.strv({"test"});
value = variant_to_value(this.context, variant);
assert_true(value.is_array(), variant.print(true));
assert_true(
value.object_get_property_at_index(0).is_string(),
variant.print(true)
);
assert_equal(
value.object_get_property_at_index(0).to_string(),
"test",
variant.print(true)
);
var dict = new GLib.VariantDict();
variant = dict.end();
value = variant_to_value(this.context, variant);
assert_true(value.is_object(), variant.print(true));
dict = new GLib.VariantDict();
dict.insert_value("test", new GLib.Variant.boolean(true));
variant = dict.end();
value = variant_to_value(this.context, variant);
assert_true(value.is_object(), variant.print(true));
assert_true(
value.object_get_property("test").is_boolean(),
value.to_string()
);
assert_true(
value.object_get_property("test").to_boolean(),
value.to_string()
);
}
}

View file

@ -1,63 +0,0 @@
/*
* Copyright 2017 Michael Gratton <mike@vee.net>
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
class ClientPageStateTest : ClientWebViewTestCase<ClientWebView> {
private class TestClientWebView : ClientWebView {
public TestClientWebView(Application.Configuration config) {
base(config);
}
}
public ClientPageStateTest() {
base("ClientPageStateTest");
add_test("content_loaded", content_loaded);
try {
ClientWebView.load_resources(GLib.File.new_for_path("/tmp"));
} catch (GLib.Error err) {
GLib.assert_not_reached();
}
}
public void content_loaded() throws Error {
bool content_loaded_triggered = false;
this.test_view.content_loaded.connect(() => {
content_loaded_triggered = true;
});
assert(!this.test_view.is_content_loaded);
// XXX sketchy - this call will never return if the thing we
// are testing does not work
load_body_fixture("OHHAI");
assert(this.test_view.is_content_loaded);
assert(content_loaded_triggered);
}
protected override ClientWebView set_up_test_view() {
WebKit.UserScript test_script;
test_script = new WebKit.UserScript(
"var geary = new PageState()",
WebKit.UserContentInjectedFrames.TOP_FRAME,
WebKit.UserScriptInjectionTime.START,
null,
null
);
ClientWebView view = new TestClientWebView(this.config);
view.get_user_content_manager().add_script(test_script);
return view;
}
}

View file

@ -0,0 +1,168 @@
/*
* Copyright 2017 Michael Gratton <mike@vee.net>
*
* This software is licensed under the GNU Lesser General Public License
* (version 2.1 or later). See the COPYING file in this distribution.
*/
class Components.PageStateTest : WebViewTestCase<WebView> {
private class TestWebView : Components.WebView {
public TestWebView(Application.Configuration config) {
base(config);
}
public new async void call_void(Util.JS.Callable callable)
throws GLib.Error {
yield base.call_void(callable, null);
}
public new async string call_returning(Util.JS.Callable callable)
throws GLib.Error {
return yield base.call_returning<string>(callable, null);
}
}
public PageStateTest() {
base("Components.PageStateTest");
add_test("content_loaded", content_loaded);
add_test("call_void", call_void);
add_test("call_void_throws", call_void_throws);
add_test("call_returning", call_returning);
add_test("call_returning_throws", call_returning_throws);
try {
WebView.load_resources(GLib.File.new_for_path("/tmp"));
} catch (GLib.Error err) {
GLib.assert_not_reached();
}
}
public void content_loaded() throws Error {
bool content_loaded_triggered = false;
this.test_view.content_loaded.connect(() => {
content_loaded_triggered = true;
});
assert(!this.test_view.is_content_loaded);
// XXX sketchy - this call will never return if the thing we
// are testing does not work
load_body_fixture("OHHAI");
assert(this.test_view.is_content_loaded);
assert(content_loaded_triggered);
}
public void call_void() throws GLib.Error {
load_body_fixture("OHHAI");
var test_article = this.test_view as TestWebView;
test_article.call_void.begin(
new Util.JS.Callable("testVoid"), this.async_completion
);
test_article.call_void.end(this.async_result());
assert_test_result("void");
}
public void call_void_throws() throws GLib.Error {
load_body_fixture("OHHAI");
var test_article = this.test_view as TestWebView;
try {
test_article.call_void.begin(
new Util.JS.Callable("testThrow").string("void message"),
this.async_completion
);
test_article.call_void.end(this.async_result());
assert_not_reached();
} catch (Util.JS.Error.EXCEPTION err) {
assert_string(
err.message
).contains(
"testThrow"
// WebKitGTK doesn't actually pass any details through:
// https://bugs.webkit.org/show_bug.cgi?id=215877
// ).contains(
// "Error"
// ).contains(
// "void message"
// ).contains(
// "components-web-view.js"
);
assert_test_result("void message");
}
}
public void call_returning() throws GLib.Error {
load_body_fixture("OHHAI");
var test_article = this.test_view as TestWebView;
test_article.call_returning.begin(
new Util.JS.Callable("testReturn").string("check 1-2"),
this.async_completion
);
string ret = test_article.call_returning.end(this.async_result());
assert_equal(ret, "check 1-2");
assert_test_result("check 1-2");
}
public void call_returning_throws() throws GLib.Error {
load_body_fixture("OHHAI");
var test_article = this.test_view as TestWebView;
try {
test_article.call_returning.begin(
new Util.JS.Callable("testThrow").string("return message"),
this.async_completion
);
test_article.call_returning.end(this.async_result());
assert_not_reached();
} catch (Util.JS.Error.EXCEPTION err) {
assert_string(
err.message
).contains(
"testThrow"
// WebKitGTK doesn't actually pass any details through:
// https://bugs.webkit.org/show_bug.cgi?id=215877
// ).contains(
// "Error"
// ).contains(
// "return message"
// ).contains(
// "components-web-view.js"
);
assert_test_result("return message");
}
}
protected override WebView set_up_test_view() {
WebKit.UserScript test_script;
test_script = new WebKit.UserScript(
"var geary = new PageState()",
WebKit.UserContentInjectedFrames.TOP_FRAME,
WebKit.UserScriptInjectionTime.START,
null,
null
);
WebView view = new TestWebView(this.config);
view.get_user_content_manager().add_script(test_script);
return view;
}
private void assert_test_result(string expected)
throws GLib.Error {
string? result = Util.JS.to_string(
run_javascript("geary.testResult")
.get_js_value()
);
assert_equal(result, expected);
}
}

View file

@ -5,13 +5,13 @@
* (version 2.1 or later). See the COPYING file in this distribution.
*/
class Composer.PageStateTest : ClientWebViewTestCase<Composer.WebView> {
class Composer.PageStateTest : Components.WebViewTestCase<Composer.WebView> {
public const string COMPLETE_BODY_TEMPLATE =
"""<div id="geary-body" dir="auto">%s<div><br></div><div><br></div></div><div id="geary-signature" dir="auto"></div>""";
public const string DIRTY_BODY_TEMPLATE =
"""
<div id="geary-body" dir="auto" class="geary-focus" contenteditable="true">%s<div><br></div><div><br></div></div>
<div id="geary-body" dir="auto" contenteditable="true">%s<div><br></div><div><br></div></div>
<div id="geary-signature" class="geary-no-display" dir="auto" contenteditable="true"></div>
""";
public const string CLEAN_BODY_TEMPLATE = """<div id="geary-body" dir="auto">%s<div><br></div><div><br></div></div>""";
@ -227,7 +227,7 @@ some text
}
}
public void clean_content() throws Error {
public void clean_content() throws GLib.Error {
// XXX split these up into multiple tests
load_body_fixture("""
http://example1.com
@ -257,20 +257,12 @@ unknown://example6.com
I can send email through smtp.gmail.com:587 or through <a href="https://www.gmail.com/">https://www.gmail.com/</a>
""";
try {
run_javascript("geary.cleanContent();");
string result = Util.JS.to_string(
run_javascript("window.document.body.innerHTML;")
.get_js_value()
);
assert(result == DIRTY_BODY_TEMPLATE.printf(expected));
} catch (Util.JS.Error err) {
print("Util.JS.Error: %s\n", err.message);
assert_not_reached();
} catch (Error err) {
print("WKError: %s\n", err.message);
assert_not_reached();
}
run_javascript("geary.cleanContent();");
string result = Util.JS.to_string(
run_javascript("window.document.body.innerHTML;")
.get_js_value()
);
assert_equal(result, DIRTY_BODY_TEMPLATE.printf(expected));
}
public void get_html() throws Error {

View file

@ -5,7 +5,7 @@
* (version 2.1 or later). See the COPYING file in this distribution.
*/
class ConversationPageStateTest : ClientWebViewTestCase<ConversationWebView> {
class ConversationPageStateTest : Components.WebViewTestCase<ConversationWebView> {
public ConversationPageStateTest() {
base("ConversationPageStateTest");

View file

@ -82,9 +82,9 @@ test_client_sources = [
'client/application/application-certificate-manager-test.vala',
'client/application/application-client-test.vala',
'client/application/application-configuration-test.vala',
'client/components/client-web-view-test.vala',
'client/components/client-web-view-test-case.vala',
'client/components/components-validator-test.vala',
'client/components/components-web-view-test-case.vala',
'client/components/components-web-view-test.vala',
'client/composer/composer-web-view-test.vala',
'client/composer/composer-widget-test.vala',
'client/util/util-avatar-test.vala',
@ -92,7 +92,7 @@ test_client_sources = [
'client/util/util-email-test.vala',
'client/util/util-js-test.vala',
'js/client-page-state-test.vala',
'js/components-page-state-test.vala',
'js/composer-page-state-test.vala',
'js/conversation-page-state-test.vala',

View file

@ -53,10 +53,10 @@ int main(string[] args) {
client.add_suite(new Application.CertificateManagerTest().suite);
client.add_suite(new Application.ClientTest().suite);
client.add_suite(new Application.ConfigurationTest().suite);
client.add_suite(new ClientWebViewTest().suite);
client.add_suite(new Components.WebViewTest().suite);
client.add_suite(new Components.ValidatorTest().suite);
client.add_suite(new Composer.WebViewTest().suite);
client.add_suite(new Composer.WidgetTest().suite);
client.add_suite(new Components.ValidatorTest().suite);
client.add_suite(new Util.Avatar.Test().suite);
client.add_suite(new Util.Cache.Test().suite);
client.add_suite(new Util.Email.Test().suite);
@ -64,7 +64,7 @@ int main(string[] args) {
TestSuite js = new TestSuite("js");
js.add_suite(new ClientPageStateTest().suite);
js.add_suite(new Components.PageStateTest().suite);
js.add_suite(new Composer.PageStateTest().suite);
js.add_suite(new ConversationPageStateTest().suite);