| // Copyright 2022 The Cobalt Authors. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "cobalt/worker/worker_global_scope.h" |
| |
| #include <memory> |
| #include <tuple> |
| |
| #include "cobalt/base/tokens.h" |
| #include "cobalt/bindings/testing/utils.h" |
| #include "cobalt/script/testing/fake_script_value.h" |
| #include "cobalt/web/error_event.h" |
| #include "cobalt/web/message_event.h" |
| #include "cobalt/web/testing/mock_event_listener.h" |
| #include "cobalt/worker/testing/test_with_javascript.h" |
| |
| namespace cobalt { |
| namespace worker { |
| |
| using script::testing::FakeScriptValue; |
| |
| class WorkerGlobalScopeTestBase { |
| protected: |
| WorkerGlobalScopeTestBase() { |
| fake_event_listener_ = web::testing::MockEventListener::Create(); |
| } |
| |
| virtual ~WorkerGlobalScopeTestBase() {} |
| |
| std::unique_ptr<web::testing::MockEventListener> fake_event_listener_; |
| }; |
| |
| class WorkerGlobalScopeTest : public WorkerGlobalScopeTestBase, |
| public testing::TestWorkersWithJavaScript {}; |
| |
| TEST_P(WorkerGlobalScopeTest, SelfIsExpectedWorkerGlobalScope) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript("self", &result)); |
| if (GetGlobalScopeTypeId() == base::GetTypeId<DedicatedWorkerGlobalScope>()) { |
| EXPECT_TRUE(bindings::testing::IsAcceptablePrototypeString( |
| "DedicatedWorkerGlobalScope", result)); |
| } else if (GetGlobalScopeTypeId() == |
| base::GetTypeId<ServiceWorkerGlobalScope>()) { |
| EXPECT_TRUE(bindings::testing::IsAcceptablePrototypeString( |
| "ServiceWorkerGlobalScope", result)); |
| } else { |
| FAIL() << "Unknown worker type with global scope : " << result; |
| } |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, LocationIsObject) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.location", &result)); |
| EXPECT_EQ("object", result); |
| |
| // Note: Due the stringifier of URLUtils.href implemented by this attribute, |
| // the prototype is not recognized as type Location, and the href is returned. |
| EXPECT_TRUE(EvaluateScript("self.location", &result)); |
| EXPECT_EQ("about:blank", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, NavigatorIsWorkerNavigator) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.navigator", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript("self.navigator", &result)); |
| EXPECT_TRUE(bindings::testing::IsAcceptablePrototypeString("WorkerNavigator", |
| result)); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, ImportScriptsIsFunction) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.importScripts", &result)); |
| EXPECT_EQ("function", result); |
| |
| EXPECT_TRUE(EvaluateScript("self.importScripts", &result)); |
| EXPECT_EQ("function importScripts() { [native code] }", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, MessageEvent) { |
| worker_global_scope()->AddEventListener( |
| "message", |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall("message", worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::MessageEvent("message")); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnMessageEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.onmessage", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.onmessage = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new Event('message')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, MessageErrorEvent) { |
| worker_global_scope()->AddEventListener( |
| "messageerror", |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall("messageerror", |
| worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::MessageEvent("messageerror")); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnMessageErrorEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.onmessageerror", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.onmessageerror = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new Event('messageerror')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, ErrorEvent) { |
| worker_global_scope()->AddEventListener( |
| "error", FakeScriptValue<web::EventListener>(fake_event_listener_.get()), |
| true); |
| fake_event_listener_->ExpectHandleEventCall("error", worker_global_scope()); |
| worker_global_scope()->DispatchEvent( |
| new web::ErrorEvent(/*environment_settings=*/nullptr)); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnErrorEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.onerror", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.onerror = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new ErrorEvent('error')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, LanguagechangeEvent) { |
| worker_global_scope()->AddEventListener( |
| "languagechange", |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall("languagechange", |
| worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event("languagechange")); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnLanguagechangeEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.onlanguagechange", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.onlanguagechange = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new Event('languagechange')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| // Test that when Worker's network status change callbacks are triggered, |
| // corresponding online and offline events are fired to listeners. |
| TEST_P(WorkerGlobalScopeTest, OfflineEvent) { |
| worker_global_scope()->AddEventListener( |
| "offline", |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall("offline", worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event(base::Tokens::offline())); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OfflineEventDispatch) { |
| worker_global_scope()->AddEventListener( |
| "offline", |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall("offline", worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event("offline")); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnOfflineEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.onoffline", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.onoffline = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new Event('offline')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnlineEvent) { |
| worker_global_scope()->AddEventListener( |
| "online", FakeScriptValue<web::EventListener>(fake_event_listener_.get()), |
| true); |
| fake_event_listener_->ExpectHandleEventCall("online", worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event(base::Tokens::online())); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnlineEventDispatch) { |
| worker_global_scope()->AddEventListener( |
| "online", FakeScriptValue<web::EventListener>(fake_event_listener_.get()), |
| true); |
| fake_event_listener_->ExpectHandleEventCall("online", worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event("online")); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnOnlineEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.ononline", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.ononline = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new Event('online')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, RejectionhandledEvent) { |
| worker_global_scope()->AddEventListener( |
| "rejectionhandled", |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall("rejectionhandled", |
| worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event("rejectionhandled")); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnRejectionhandledEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.onrejectionhandled", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.onrejectionhandled = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new Event('rejectionhandled')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, UnhandledrejectionEvent) { |
| worker_global_scope()->AddEventListener( |
| "unhandledrejection", |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall("unhandledrejection", |
| worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event("unhandledrejection")); |
| } |
| |
| TEST_P(WorkerGlobalScopeTest, OnUnhandledrejectionEvent) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("typeof self.onunhandledrejection", &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE(EvaluateScript(R"( |
| logString = '(empty)'; |
| self.onunhandledrejection = function() { |
| logString = 'handled'; |
| }; |
| self.dispatchEvent(new Event('unhandledrejection')); |
| logString; |
| )", |
| &result)); |
| EXPECT_EQ("handled", result); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| WorkerGlobalScopeTests, WorkerGlobalScopeTest, |
| ::testing::ValuesIn(testing::TestWorkersWithJavaScript::GetWorkerTypes()), |
| testing::TestWorkersWithJavaScript::GetTypeName); |
| |
| class GetGlobalScopeTypeIdWithParamTuple |
| : public ::testing::TestWithParam<std::tuple<base::TypeId, const char*>> { |
| public: |
| base::TypeId GetGlobalScopeTypeId() const { return std::get<0>(GetParam()); } |
| }; |
| |
| namespace { |
| class WorkerGlobalScopeTestEventTest : public WorkerGlobalScopeTestBase, |
| public testing::TestWithJavaScriptBase< |
| GetGlobalScopeTypeIdWithParamTuple> { |
| }; |
| |
| std::string GetEventName( |
| ::testing::TestParamInfo<std::tuple<base::TypeId, const char*>> info) { |
| std::string name; |
| name.append( |
| testing::TestWorkersWithJavaScript::GetName(std::get<0>(info.param))); |
| name.push_back('_'); |
| name.append(std::get<1>(info.param)); |
| return name; |
| } |
| |
| const char* events[] = {"languagechange", "offline", "online", |
| "rejectionhandled", "unhandledrejection"}; |
| } // namespace |
| |
| TEST_P(WorkerGlobalScopeTestEventTest, AddEventListener) { |
| const char* event_name = std::get<1>(GetParam()); |
| worker_global_scope()->AddEventListener( |
| event_name, |
| FakeScriptValue<web::EventListener>(fake_event_listener_.get()), true); |
| fake_event_listener_->ExpectHandleEventCall(event_name, |
| worker_global_scope()); |
| worker_global_scope()->DispatchEvent(new web::Event(event_name)); |
| } |
| |
| TEST_P(WorkerGlobalScopeTestEventTest, OnEvent) { |
| const char* event_name = std::get<1>(GetParam()); |
| std::string result; |
| EXPECT_TRUE(EvaluateScript(base::StringPrintf("typeof this.on%s", event_name), |
| &result)); |
| EXPECT_EQ("object", result); |
| |
| EXPECT_TRUE( |
| EvaluateScript(base::StringPrintf(R"( |
| logString = '(empty)'; |
| self.on%s = function() { |
| logString = '%s'; |
| }; |
| self.dispatchEvent(new Event('%s')); |
| logString; |
| )", |
| event_name, event_name, event_name), |
| &result)); |
| EXPECT_EQ(event_name, result); |
| } |
| |
| INSTANTIATE_TEST_SUITE_P( |
| WorkerGlobalScopeTest, WorkerGlobalScopeTestEventTest, |
| ::testing::Combine( |
| ::testing::ValuesIn( |
| testing::TestWorkersWithJavaScript::GetWorkerTypes()), |
| ::testing::ValuesIn(events)), |
| GetEventName); |
| |
| } // namespace worker |
| } // namespace cobalt |