| // Copyright 2018 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 <memory> |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "base/callback.h" |
| #include "base/optional.h" |
| #include "base/threading/platform_thread.h" |
| #include "cobalt/bindings/testing/utils.h" |
| #include "cobalt/css_parser/parser.h" |
| #include "cobalt/cssom/viewport_size.h" |
| #include "cobalt/dom/global_stats.h" |
| #include "cobalt/dom/local_storage_database.h" |
| #include "cobalt/dom/testing/gtest_workarounds.h" |
| #include "cobalt/dom/testing/stub_environment_settings.h" |
| #include "cobalt/dom/window.h" |
| #include "cobalt/dom_parser/parser.h" |
| #include "cobalt/loader/fetcher_factory.h" |
| #include "cobalt/loader/loader_factory.h" |
| #include "cobalt/script/global_environment.h" |
| #include "cobalt/script/javascript_engine.h" |
| #include "cobalt/script/source_code.h" |
| #include "starboard/window.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| using cobalt::cssom::ViewportSize; |
| using testing::InSequence; |
| using testing::Mock; |
| |
| namespace cobalt { |
| namespace dom { |
| |
| class MockErrorCallback |
| : public base::Callback<void(const base::Optional<std::string>&)> { |
| public: |
| MOCK_METHOD1(Run, void(const base::Optional<std::string>&)); |
| }; |
| |
| class OnScreenKeyboardMockBridge : public OnScreenKeyboardBridge { |
| public: |
| void Show(const char* input_text, int ticket) override { |
| ShowMock(input_text); |
| last_ticket_ = ticket; |
| shown_ = true; |
| script::Handle<script::Promise<void>> promise = |
| LookupPromiseForShowTicket(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kPending); |
| DCHECK(window_); |
| window_->on_screen_keyboard()->DispatchShowEvent(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kFulfilled); |
| last_ticket_ = -1; |
| } |
| |
| void Hide(int ticket) override { |
| HideMock(); |
| last_ticket_ = ticket; |
| shown_ = false; |
| |
| script::Handle<script::Promise<void>> promise = |
| LookupPromiseForHideTicket(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kPending); |
| DCHECK(window_); |
| window_->on_screen_keyboard()->DispatchHideEvent(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kFulfilled); |
| last_ticket_ = -1; |
| } |
| |
| void Focus(int ticket) override { |
| FocusMock(); |
| last_ticket_ = ticket; |
| script::Handle<script::Promise<void>> promise = |
| LookupPromiseForFocusTicket(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kPending); |
| DCHECK(window_); |
| window_->on_screen_keyboard()->DispatchFocusEvent(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kFulfilled); |
| last_ticket_ = -1; |
| } |
| |
| void Blur(int ticket) override { |
| BlurMock(); |
| last_ticket_ = ticket; |
| script::Handle<script::Promise<void>> promise = |
| LookupPromiseForBlurTicket(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kPending); |
| DCHECK(window_); |
| window_->on_screen_keyboard()->DispatchBlurEvent(last_ticket_); |
| EXPECT_TRUE(promise->State() == cobalt::script::PromiseState::kFulfilled); |
| last_ticket_ = -1; |
| } |
| |
| bool SuggestionsSupported() const override { |
| // TODO: implement and test this. |
| SB_NOTIMPLEMENTED(); |
| return false; |
| } |
| |
| void UpdateSuggestions(const script::Sequence<std::string>& suggestions, |
| int ticket) override { |
| // TODO: implement and test this. |
| SB_NOTIMPLEMENTED(); |
| } |
| |
| bool IsShown() const override { return shown_; } |
| |
| scoped_refptr<DOMRect> BoundingRect() const override { |
| return BoundingRectMock(); |
| } |
| |
| bool IsValidTicket(int ticket) const override { |
| // The mock bridge will always dispatch events immediately once the |
| // show/hide/focus/blur function has been called, meaning we will never need |
| // to check the validity of a ticket that was not the last one generated. |
| // This method will always return false when called outside one of the |
| // show/hide/focus/blur methods. |
| return ticket != -1 && ticket == last_ticket_; |
| } |
| |
| void SetKeepFocus(bool keep_focus) override { SetKeepFocusMock(keep_focus); } |
| |
| MOCK_METHOD1(ShowMock, void(std::string)); |
| MOCK_METHOD0(HideMock, void()); |
| MOCK_METHOD0(BlurMock, void()); |
| MOCK_METHOD0(FocusMock, void()); |
| MOCK_CONST_METHOD0(BoundingRectMock, scoped_refptr<DOMRect>()); |
| MOCK_METHOD1(SetKeepFocusMock, void(bool)); |
| |
| // We shortcut the event dispatching and handling for tests. |
| dom::Window* window_; |
| |
| private: |
| // OnScreenKeyboardMockBridge needs to be friends with dom::OnScreenKeyboard |
| // to implement these functions. |
| script::Handle<script::Promise<void>> LookupPromiseForShowTicket(int ticket) { |
| DCHECK(window_); |
| const auto& map = |
| window_->on_screen_keyboard()->ticket_to_show_promise_map_; |
| auto it = map.find(ticket); |
| DCHECK(it != map.end()); |
| return script::Handle<script::Promise<void>>(*it->second); |
| } |
| |
| script::Handle<script::Promise<void>> LookupPromiseForHideTicket(int ticket) { |
| DCHECK(window_); |
| const auto& map = |
| window_->on_screen_keyboard()->ticket_to_hide_promise_map_; |
| auto it = map.find(ticket); |
| DCHECK(it != map.end()); |
| return script::Handle<script::Promise<void>>(*it->second); |
| } |
| |
| script::Handle<script::Promise<void>> LookupPromiseForFocusTicket( |
| int ticket) { |
| DCHECK(window_); |
| const auto& map = |
| window_->on_screen_keyboard()->ticket_to_focus_promise_map_; |
| auto it = map.find(ticket); |
| DCHECK(it != map.end()); |
| return script::Handle<script::Promise<void>>(*it->second); |
| } |
| |
| script::Handle<script::Promise<void>> LookupPromiseForBlurTicket(int ticket) { |
| DCHECK(window_); |
| const auto& map = |
| window_->on_screen_keyboard()->ticket_to_blur_promise_map_; |
| auto it = map.find(ticket); |
| DCHECK(it != map.end()); |
| return script::Handle<script::Promise<void>>(*it->second); |
| } |
| |
| bool shown_ = false; |
| int last_ticket_ = -1; |
| }; |
| |
| namespace { |
| |
| class OnScreenKeyboardTest : public ::testing::Test { |
| public: |
| OnScreenKeyboardTest() |
| : environment_settings_(new testing::StubEnvironmentSettings), |
| message_loop_(base::MessageLoop::TYPE_DEFAULT), |
| css_parser_(css_parser::Parser::Create()), |
| dom_parser_(new dom_parser::Parser(mock_error_callback_)), |
| fetcher_factory_(new loader::FetcherFactory(NULL)), |
| loader_factory_(new loader::LoaderFactory( |
| "Test", fetcher_factory_.get(), NULL, null_debugger_hooks_, 0, |
| base::ThreadPriority::DEFAULT)), |
| local_storage_database_(NULL), |
| url_("about:blank"), |
| engine_(script::JavaScriptEngine::CreateEngine()), |
| global_environment_(engine_->CreateGlobalEnvironment()), |
| on_screen_keyboard_bridge_(new OnScreenKeyboardMockBridge()), |
| window_(new Window( |
| environment_settings_.get(), ViewportSize(1920, 1080), |
| base::kApplicationStateStarted, css_parser_.get(), |
| dom_parser_.get(), fetcher_factory_.get(), loader_factory_.get(), |
| NULL, NULL, NULL, NULL, NULL, NULL, &local_storage_database_, NULL, |
| NULL, NULL, NULL, |
| global_environment_ |
| ->script_value_factory() /* script_value_factory */, |
| NULL, NULL, url_, "", "en-US", "en", |
| base::Callback<void(const GURL&)>(), |
| base::Bind(&MockErrorCallback::Run, |
| base::Unretained(&mock_error_callback_)), |
| NULL, network_bridge::PostSender(), csp::kCSPRequired, |
| kCspEnforcementEnable, base::Closure() /* csp_policy_changed */, |
| base::Closure() /* ran_animation_frame_callbacks */, |
| dom::Window::CloseCallback() /* window_close */, |
| base::Closure() /* window_minimize */, |
| on_screen_keyboard_bridge_.get(), NULL, |
| dom::Window::OnStartDispatchEventCallback(), |
| dom::Window::OnStopDispatchEventCallback(), |
| dom::ScreenshotManager::ProvideScreenshotFunctionCallback(), |
| NULL)) { |
| global_environment_->CreateGlobalObject(window_, |
| environment_settings_.get()); |
| on_screen_keyboard_bridge_->window_ = window_; |
| } |
| |
| ~OnScreenKeyboardTest() { |
| global_environment_->SetReportEvalCallback(base::Closure()); |
| global_environment_->SetReportErrorCallback( |
| script::GlobalEnvironment::ReportErrorCallback()); |
| window_->DispatchEvent(new dom::Event(base::Tokens::unload())); |
| |
| // TODO: figure out how to destruct OSK before global environment. |
| window_->ReleaseOnScreenKeyboard(); |
| |
| EXPECT_TRUE(Mock::VerifyAndClearExpectations(on_screen_keyboard_bridge())); |
| |
| on_screen_keyboard_bridge_.reset(); |
| window_ = nullptr; |
| global_environment_ = nullptr; |
| EXPECT_TRUE(GlobalStats::GetInstance()->CheckNoLeaks()); |
| } |
| |
| bool EvaluateScript(const std::string& js_code, std::string* result); |
| |
| script::GlobalEnvironment* global_environment() const { |
| return global_environment_.get(); |
| } |
| |
| OnScreenKeyboardMockBridge* on_screen_keyboard_bridge() const { |
| return on_screen_keyboard_bridge_.get(); |
| } |
| |
| Window* window() const { return window_.get(); } |
| |
| private: |
| const std::unique_ptr<testing::StubEnvironmentSettings> environment_settings_; |
| base::NullDebuggerHooks null_debugger_hooks_; |
| base::MessageLoop message_loop_; |
| MockErrorCallback mock_error_callback_; |
| std::unique_ptr<css_parser::Parser> css_parser_; |
| std::unique_ptr<dom_parser::Parser> dom_parser_; |
| std::unique_ptr<loader::FetcherFactory> fetcher_factory_; |
| std::unique_ptr<loader::LoaderFactory> loader_factory_; |
| dom::LocalStorageDatabase local_storage_database_; |
| GURL url_; |
| |
| std::unique_ptr<script::JavaScriptEngine> engine_; |
| scoped_refptr<script::GlobalEnvironment> global_environment_; |
| std::unique_ptr<OnScreenKeyboardMockBridge> on_screen_keyboard_bridge_; |
| scoped_refptr<Window> window_; |
| }; |
| |
| // TODO: refactor this into reusable test utility. |
| bool OnScreenKeyboardTest::EvaluateScript(const std::string& js_code, |
| std::string* result) { |
| DCHECK(global_environment_); |
| scoped_refptr<script::SourceCode> source_code = |
| script::SourceCode::CreateSourceCode( |
| js_code, base::SourceLocation(__FILE__, __LINE__, 1)); |
| |
| global_environment_->EnableEval(); |
| global_environment_->SetReportEvalCallback(base::Closure()); |
| bool succeeded = global_environment_->EvaluateScript(source_code, result); |
| return succeeded; |
| } |
| |
| } // namespace |
| |
| #if SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| |
| bool SkipLocale() { |
| #if SB_API_VERSION >= 12 |
| bool skipTests = !SbWindowOnScreenKeyboardIsSupported(); |
| if (skipTests) { |
| SB_LOG(INFO) << "On screen keyboard not supported. Test skipped."; |
| } |
| return skipTests; |
| #else |
| return false; |
| #endif |
| } |
| |
| TEST_F(OnScreenKeyboardTest, ObjectExists) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard;", &result)); |
| |
| EXPECT_TRUE(bindings::testing::IsAcceptablePrototypeString("OnScreenKeyboard", |
| result)); |
| |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.show;", &result)); |
| EXPECT_PRED_FORMAT2(::testing::IsSubstring, "function show()", |
| result.c_str()); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.hide;", &result)); |
| EXPECT_PRED_FORMAT2(::testing::IsSubstring, "function hide()", |
| result.c_str()); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.focus;", &result)); |
| EXPECT_PRED_FORMAT2(::testing::IsSubstring, "function focus()", |
| result.c_str()); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.blur;", &result)); |
| EXPECT_PRED_FORMAT2(::testing::IsSubstring, "function blur()", |
| result.c_str()); |
| |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.keepFocus;", &result)); |
| EXPECT_STREQ("false", result.c_str()); |
| |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.data;", &result)); |
| EXPECT_STREQ("", result.c_str()); |
| |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.onshow;", &result)); |
| EXPECT_STREQ("null", result.c_str()); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.onhide;", &result)); |
| EXPECT_STREQ("null", result.c_str()); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.onblur;", &result)); |
| EXPECT_STREQ("null", result.c_str()); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.onfocus;", &result)); |
| EXPECT_STREQ("null", result.c_str()); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, ShowAndHide) { |
| if (SkipLocale()) return; |
| |
| // Not shown. |
| std::string result; |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.shown;", &result)); |
| EXPECT_EQ("false", result); |
| |
| { |
| InSequence seq; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), |
| ShowMock(window()->on_screen_keyboard()->data())); |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), HideMock()); |
| } |
| // Show. |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.show();", &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.shown;", &result)); |
| EXPECT_EQ("true", result); |
| |
| // Hide. |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.hide();", &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.shown;", &result)); |
| EXPECT_EQ("false", result); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, ShowAndHideMultipleTimes) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| { |
| InSequence seq; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), |
| ShowMock(window()->on_screen_keyboard()->data())) |
| .Times(3); |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), HideMock()).Times(3); |
| } |
| |
| // Show multiple times. |
| const char show_script[] = R"( |
| window.onScreenKeyboard.show(); |
| window.onScreenKeyboard.show(); |
| window.onScreenKeyboard.show(); |
| )"; |
| EXPECT_TRUE(EvaluateScript(show_script, &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| |
| // Hide multiple times. |
| const char hide_script[] = R"( |
| window.onScreenKeyboard.hide(); |
| window.onScreenKeyboard.hide(); |
| window.onScreenKeyboard.hide(); |
| )"; |
| EXPECT_TRUE(EvaluateScript(hide_script, &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, Data) { |
| if (SkipLocale()) return; |
| |
| std::string result = "(empty)"; |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.data;", &result)); |
| EXPECT_EQ("", result); |
| |
| std::string utf8_str = u8"z\u6c34\U0001d10b"; |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.data = '" + utf8_str + |
| "';" |
| "window.onScreenKeyboard.data", |
| &result)); |
| EXPECT_EQ(utf8_str, result); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, FocusAndBlur) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| |
| { |
| InSequence seq; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), FocusMock()); |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), BlurMock()); |
| } |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.focus();", &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.blur();", &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| } |
| TEST_F(OnScreenKeyboardTest, FocusAndBlurMultipleTimes) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| { |
| InSequence seq; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), FocusMock()).Times(3); |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), BlurMock()).Times(3); |
| } |
| |
| const char focus_script[] = R"( |
| window.onScreenKeyboard.focus(); |
| window.onScreenKeyboard.focus(); |
| window.onScreenKeyboard.focus(); |
| )"; |
| EXPECT_TRUE(EvaluateScript(focus_script, &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| const char blur_script[] = R"( |
| window.onScreenKeyboard.blur(); |
| window.onScreenKeyboard.blur(); |
| window.onScreenKeyboard.blur(); |
| )"; |
| EXPECT_TRUE(EvaluateScript(blur_script, &result)); |
| EXPECT_TRUE( |
| bindings::testing::IsAcceptablePrototypeString("Object", result) || |
| bindings::testing::IsAcceptablePrototypeString("Promise", result)); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, ShowEventAttribute) { |
| if (SkipLocale()) return; |
| |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), |
| ShowMock(window()->on_screen_keyboard()->data())) |
| .Times(3); |
| const char let_script[] = R"( |
| let promise; |
| let logString; |
| )"; |
| EXPECT_TRUE(EvaluateScript(let_script, NULL)); |
| const char event_script[] = R"( |
| logString = '(empty)'; |
| window.onScreenKeyboard.onshow = function() { |
| logString = 'show'; |
| }; |
| promise = window.onScreenKeyboard.show(); |
| logString; |
| )"; |
| for (int i = 0; i < 3; ++i) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript(event_script, &result)); |
| EXPECT_EQ("show", result); |
| } |
| } |
| |
| TEST_F(OnScreenKeyboardTest, ShowEventListeners) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), |
| ShowMock(window()->on_screen_keyboard()->data())); |
| const char script[] = R"( |
| let logString1 = '(empty)'; |
| let logString2 = '(empty)'; |
| window.onScreenKeyboard.addEventListener('show', |
| function() { |
| logString1 = 'show1'; |
| }); |
| window.onScreenKeyboard.addEventListener('show', |
| function() { |
| logString2 = 'show2'; |
| }); |
| let promise = window.onScreenKeyboard.show(); |
| logString1; |
| )"; |
| EXPECT_TRUE(EvaluateScript(script, &result)); |
| EXPECT_EQ("show1", result); |
| EXPECT_TRUE(EvaluateScript("logString2", &result)); |
| EXPECT_EQ(result, "show2"); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, HideEventAttribute) { |
| if (SkipLocale()) return; |
| |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), HideMock()).Times(3); |
| const char let_script[] = R"( |
| let promise; |
| let logString; |
| )"; |
| EXPECT_TRUE(EvaluateScript(let_script, NULL)); |
| const char event_script[] = R"( |
| logString = '(empty)'; |
| window.onScreenKeyboard.onhide = function() { |
| logString = 'hide'; |
| }; |
| promise = window.onScreenKeyboard.hide(); |
| logString; |
| )"; |
| for (int i = 0; i < 3; ++i) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript(event_script, &result)); |
| EXPECT_EQ("hide", result); |
| } |
| } |
| |
| TEST_F(OnScreenKeyboardTest, HideEventListeners) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), HideMock()); |
| const char script[] = R"( |
| let logString1 = '(empty)'; |
| let logString2 = '(empty)'; |
| window.onScreenKeyboard.addEventListener('hide', |
| function() { |
| logString1 = 'hide1'; |
| }); |
| window.onScreenKeyboard.addEventListener('hide', |
| function() { |
| logString2 = 'hide2'; |
| }); |
| let promise = window.onScreenKeyboard.hide(); |
| logString1; |
| )"; |
| EXPECT_TRUE(EvaluateScript(script, &result)); |
| EXPECT_EQ("hide1", result); |
| EXPECT_TRUE(EvaluateScript("logString2", &result)); |
| EXPECT_EQ(result, "hide2"); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, FocusEventAttribute) { |
| if (SkipLocale()) return; |
| |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), FocusMock()).Times(3); |
| const char let_script[] = R"( |
| let promise; |
| let logString; |
| )"; |
| EXPECT_TRUE(EvaluateScript(let_script, NULL)); |
| const char event_script[] = R"( |
| logString = '(empty)'; |
| window.onScreenKeyboard.onfocus = function() { |
| logString = 'focus'; |
| }; |
| promise = window.onScreenKeyboard.focus(); |
| logString; |
| )"; |
| for (int i = 0; i < 3; ++i) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript(event_script, &result)); |
| EXPECT_EQ("focus", result); |
| } |
| } |
| |
| TEST_F(OnScreenKeyboardTest, FocusEventListeners) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), FocusMock()); |
| const char script[] = R"( |
| let logString1 = '(empty)'; |
| let logString2 = '(empty)'; |
| window.onScreenKeyboard.addEventListener('focus', |
| function() { |
| logString1 = 'focus1'; |
| }); |
| window.onScreenKeyboard.addEventListener('focus', |
| function() { |
| logString2 = 'focus2'; |
| }); |
| let promise = window.onScreenKeyboard.focus(); |
| logString1; |
| )"; |
| EXPECT_TRUE(EvaluateScript(script, &result)); |
| EXPECT_EQ("focus1", result); |
| EXPECT_TRUE(EvaluateScript("logString2", &result)); |
| EXPECT_EQ("focus2", result); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, BlurEventAttribute) { |
| if (SkipLocale()) return; |
| |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), BlurMock()).Times(3); |
| const char let_script[] = R"( |
| let promise; |
| let logString; |
| )"; |
| EXPECT_TRUE(EvaluateScript(let_script, NULL)); |
| const char event_script[] = R"( |
| logString = '(empty)'; |
| window.onScreenKeyboard.onblur = function() { |
| logString = 'blur'; |
| }; |
| promise = window.onScreenKeyboard.blur(); |
| logString; |
| )"; |
| for (int i = 0; i < 3; ++i) { |
| std::string result; |
| EXPECT_TRUE(EvaluateScript(event_script, &result)); |
| EXPECT_EQ("blur", result); |
| } |
| } |
| |
| TEST_F(OnScreenKeyboardTest, BlurEventListeners) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), BlurMock()); |
| const char script[] = R"( |
| let logString1 = '(empty)'; |
| let logString2 = '(empty)'; |
| window.onScreenKeyboard.addEventListener('blur', |
| function() { |
| logString1 = 'blur1'; |
| }); |
| window.onScreenKeyboard.addEventListener('blur', |
| function() { |
| logString2 = 'blur2'; |
| }); |
| let promise = window.onScreenKeyboard.blur(); |
| logString1; |
| )"; |
| EXPECT_TRUE(EvaluateScript(script, &result)); |
| EXPECT_EQ("blur1", result); |
| EXPECT_TRUE(EvaluateScript("logString2", &result)); |
| EXPECT_EQ(result, "blur2"); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, BoundingRect) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), BoundingRectMock()) |
| .WillOnce(::testing::Return(nullptr)); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.boundingRect;", &result)); |
| EXPECT_EQ("null", result); |
| } |
| |
| TEST_F(OnScreenKeyboardTest, KeepFocus) { |
| if (SkipLocale()) return; |
| |
| std::string result; |
| { |
| InSequence seq; |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), SetKeepFocusMock(true)); |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), SetKeepFocusMock(false)); |
| EXPECT_CALL(*(on_screen_keyboard_bridge()), SetKeepFocusMock(true)); |
| } |
| |
| // Check initialization. |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard.keepFocus;", &result)); |
| EXPECT_EQ("false", result); |
| |
| const char script[] = R"( |
| window.onScreenKeyboard.keepFocus = true; |
| window.onScreenKeyboard.keepFocus = false; |
| window.onScreenKeyboard.keepFocus = true; |
| )"; |
| EXPECT_TRUE(EvaluateScript(script, NULL)); |
| } |
| #else // SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| TEST_F(OnScreenKeyboardTest, ObjectDoesntExist) { |
| std::string result; |
| |
| EXPECT_TRUE( |
| EvaluateScript("window.hasOwnProperty('onScreenKeyboard');", &result)); |
| EXPECT_EQ("false", result); |
| EXPECT_TRUE(EvaluateScript("window.onScreenKeyboard;", &result)); |
| EXPECT_FALSE(bindings::testing::IsAcceptablePrototypeString( |
| "OnScreenKeyboard", result)); |
| EXPECT_TRUE(EvaluateScript("typeof window.onScreenKeyboard === 'undefined';", |
| &result)); |
| EXPECT_EQ("true", result); |
| |
| // We should be able to assign anything we like to window.onScreenKeyboard. |
| const char number_script[] = R"( |
| window.onScreenKeyboard = 42; |
| window.onScreenKeyboard; |
| )"; |
| EXPECT_TRUE(EvaluateScript(number_script, &result)); |
| EXPECT_EQ("42", result); |
| |
| const char object_script[] = R"( |
| window.onScreenKeyboard = {foo: 'bar'}; |
| window.onScreenKeyboard.hasOwnProperty('foo'); |
| )"; |
| EXPECT_TRUE(EvaluateScript(object_script, &result)); |
| EXPECT_EQ("true", result); |
| } |
| #endif // SB_API_VERSION >= 12 || SB_HAS(ON_SCREEN_KEYBOARD) |
| |
| } // namespace dom |
| } // namespace cobalt |