blob: 47423e9ed30411a1016653fa929f41208f847d7c [file] [log] [blame]
// 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