diff options
Diffstat (limited to 'chrome_frame/test')
-rw-r--r-- | chrome_frame/test/chrome_frame_test_utils.cc | 6 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_unittests.cc | 218 | ||||
-rw-r--r-- | chrome_frame/test/chrome_frame_unittests.h | 21 |
3 files changed, 227 insertions, 18 deletions
diff --git a/chrome_frame/test/chrome_frame_test_utils.cc b/chrome_frame/test/chrome_frame_test_utils.cc index 2cce441..8777651 100644 --- a/chrome_frame/test/chrome_frame_test_utils.cc +++ b/chrome_frame/test/chrome_frame_test_utils.cc @@ -472,7 +472,7 @@ void SetKeyboardFocusToWindow(HWND window, int x, int y) { } void SendInputToWindow(HWND window, const std::string& input_string) { - SetKeyboardFocusToWindow(window, 100, 100); + const unsigned long kIntervalBetweenInput = 100; for (size_t index = 0; index < input_string.length(); index++) { bool is_upper_case = isupper(input_string[index]); @@ -481,18 +481,20 @@ void SendInputToWindow(HWND window, const std::string& input_string) { input.ki.wVk = VK_SHIFT; input.ki.dwFlags = 0; SendInput(1, &input, sizeof(input)); - Sleep(200); + Sleep(kIntervalBetweenInput); } // The WM_KEYDOWN and WM_KEYUP messages for characters always contain // the uppercase character codes. SendVirtualKey(toupper(input_string[index]), false); + Sleep(kIntervalBetweenInput); if (is_upper_case) { INPUT input = { INPUT_KEYBOARD }; input.ki.wVk = VK_SHIFT; input.ki.dwFlags = KEYEVENTF_KEYUP; SendInput(1, &input, sizeof(input)); + Sleep(kIntervalBetweenInput); } } } diff --git a/chrome_frame/test/chrome_frame_unittests.cc b/chrome_frame/test/chrome_frame_unittests.cc index 92ba2d0..cf7e6a0 100644 --- a/chrome_frame/test/chrome_frame_unittests.cc +++ b/chrome_frame/test/chrome_frame_unittests.cc @@ -848,6 +848,11 @@ struct TimedMsgLoop { loop_.MessageLoop::Run(); } + void PostDelayedTask( + const tracked_objects::Location& from_here, Task* task, int64 delay_ms) { + loop_.PostDelayedTask(from_here, task, delay_ms); + } + void Quit() { loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask); } @@ -1221,6 +1226,15 @@ HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) { } // WebBrowserEventSink member defines +void WebBrowserEventSink::Uninitialize() { + chrome_frame_ = NULL; + if (web_browser2_.get()) { + DispEventUnadvise(web_browser2_); + web_browser2_->Quit(); + web_browser2_.Release(); + } +} + STDMETHODIMP WebBrowserEventSink::OnBeforeNavigate2Internal( IDispatch* dispatch, VARIANT* url, VARIANT* flags, VARIANT* target_frame_name, VARIANT* post_data, VARIANT* headers, @@ -1282,6 +1296,15 @@ HRESULT WebBrowserEventSink::Navigate(const std::wstring& navigate_url) { return hr; } +void WebBrowserEventSink::SetFocusToChrome() { + chrome_frame_test::SetKeyboardFocusToWindow(GetChromeRendererWindow(), 1, 1); +} + +void WebBrowserEventSink::SendInputToChrome( + const std::string& input_string) { + chrome_frame_test::SendInputToWindow(GetChromeRendererWindow(), input_string); +} + void WebBrowserEventSink::ConnectToChromeFrame() { DCHECK(web_browser2_); ScopedComPtr<IShellBrowser> shell_browser; @@ -1307,6 +1330,28 @@ void WebBrowserEventSink::ConnectToChromeFrame() { } } +HWND WebBrowserEventSink::GetChromeRendererWindow() { + DCHECK(chrome_frame_); + HWND renderer_window = NULL; + ScopedComPtr<IOleWindow> ole_window; + ole_window.QueryFrom(chrome_frame_); + EXPECT_TRUE(ole_window.get()); + + if (ole_window) { + HWND activex_window = NULL; + ole_window->GetWindow(&activex_window); + EXPECT_TRUE(IsWindow(activex_window)); + + // chrome tab window is the first (and the only) child of activex + HWND chrome_tab_window = GetWindow(activex_window, GW_CHILD); + EXPECT_TRUE(IsWindow(chrome_tab_window)); + renderer_window = GetWindow(chrome_tab_window, GW_CHILD); + } + + DCHECK(IsWindow(renderer_window)); + return renderer_window; +} + const int kChromeFrameLaunchDelay = 5; const int kChromeFrameLongNavigationTimeoutInSeconds = 10; @@ -1508,6 +1553,7 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ChromeFrameKeyboardTest) { HWND renderer_window = chrome_frame_test::GetChromeRendererWindow(); EXPECT_TRUE(IsWindow(renderer_window)); + chrome_frame_test::SetKeyboardFocusToWindow(renderer_window, 1, 1); chrome_frame_test::SendInputToWindow(renderer_window, "Chrome"); loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); @@ -1600,7 +1646,12 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { EXPECT_CALL(mock, OnNavigateComplete2(_, _)) .WillOnce(testing::Return()); EXPECT_CALL(mock, OnLoad(testing::StrEq(kSubFrameUrl1))) - .WillOnce(QUIT_LOOP_SOON(loop, 2)); + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &WebBrowserEventSink::Uninitialize)), + testing::IgnoreResult(testing::InvokeWithoutArgs( + &chrome_frame_test::CloseAllIEWindows)), + QUIT_LOOP_SOON(loop, 2))); HRESULT hr = mock.LaunchIEAndNavigate(kSubFrameUrl1); ASSERT_HRESULT_SUCCEEDED(hr); @@ -1608,13 +1659,10 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForward) { return; ASSERT_TRUE(mock.web_browser2() != NULL); - loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); - - mock.Uninitialize(); - chrome_frame_test::CloseAllIEWindows(); } + const wchar_t kChromeFrameAboutBlankUrl[] = L"cf:about:blank"; TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ChromeFrameFocusTest) { @@ -1641,3 +1689,163 @@ TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_ChromeFrameFocusTest) { chrome_frame_test::CloseAllIEWindows(); } +const wchar_t kAnchorUrl[] = L"http://localhost:1337/files/anchor.html"; +const wchar_t kAnchor1Url[] = L"http://localhost:1337/files/anchor.html#a1"; +const wchar_t kAnchor2Url[] = L"http://localhost:1337/files/anchor.html#a2"; +const wchar_t kAnchor3Url[] = L"http://localhost:1337/files/anchor.html#a3"; + +// Full tab mode back/forward test +// Launch and navigate chrome frame to a set of URLs and test back forward +TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_BackForwardAnchor) { + const char tab_enter_keystrokes[] = { VK_TAB, VK_RETURN, 0 }; + static const std::string tab_enter(tab_enter_keystrokes); + TimedMsgLoop loop; + CComObjectStackEx<MockWebBrowserEventSink> mock; + ::testing::InSequence sequence; // Everything in sequence + + // Back/Forward state at this point: + // Back: 0 + // Forward: 0 + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchorUrl)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // Navigate to anchor 1: + // - First set focus to chrome renderer window + // Call WebBrowserEventSink::SetFocusToChrome only once + // in the beginning. Calling it again will change focus from the + // current location to an element near the simulated mouse.click. + // - Then send keyboard input of TAB + ENTER to cause navigation. + // It's better to send input as PostDelayedTask since the Activex + // message loop on the other side might be blocked when we get + // called in Onload. + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchorUrl))) + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &WebBrowserEventSink::SetFocusToChrome)), + testing::InvokeWithoutArgs(CreateFunctor(&loop, + &TimedMsgLoop::PostDelayedTask, FROM_HERE, NewRunnableMethod( + &mock, &WebBrowserEventSink::SendInputToChrome, + std::string(tab_enter)), 0)))); + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchor1Url)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // Navigate to anchor 2 after the previous navigation is complete + // Back/Forward state at this point: + // Back: 1 (kAnchorUrl) + // Forward: 0 + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor1Url))) + .WillOnce(testing::InvokeWithoutArgs( + CreateFunctor(&loop, &TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableMethod(&mock, &WebBrowserEventSink::SendInputToChrome, + std::string(tab_enter)), 0))); + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchor2Url)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // Navigate to anchor 3 after the previous navigation is complete + // Back/Forward state at this point: + // Back: 2 (kAnchorUrl, kAnchor1Url) + // Forward: 0 + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor2Url))) + .WillOnce(testing::InvokeWithoutArgs( + CreateFunctor(&loop, &TimedMsgLoop::PostDelayedTask, FROM_HERE, + NewRunnableMethod(&mock, &WebBrowserEventSink::SendInputToChrome, + std::string(tab_enter)), 0))); + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchor3Url)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // We will reach anchor 3 once the navigation is complete, + // then go back to anchor 2 + // Back/Forward state at this point: + // Back: 3 (kAnchorUrl, kAnchor1Url, kAnchor2Url) + // Forward: 0 + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor3Url))) + .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( + CreateFunctor(ReceivePointer(mock.web_browser2_), + &IWebBrowser::GoBack)))); + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchor2Url)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // We will reach anchor 2 once the navigation is complete, + // then go back to anchor 1 + // Back/Forward state at this point: + // Back: 3 (kAnchorUrl, kAnchor1Url, kAnchor2Url) + // Forward: 1 (kAnchor3Url) + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor2Url))) + .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( + CreateFunctor(ReceivePointer(mock.web_browser2_), + &IWebBrowser::GoBack)))); + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchor1Url)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // We will reach anchor 1 once the navigation is complete, + // now go forward to anchor 2 + // Back/Forward state at this point: + // Back: 2 (kAnchorUrl, kAnchor1Url) + // Forward: 2 (kAnchor2Url, kAnchor3Url) + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor1Url))) + .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( + CreateFunctor(ReceivePointer(mock.web_browser2_), + &IWebBrowser::GoForward)))); + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchor2Url)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // We have reached anchor 2, go forward to anchor 3 again + // Back/Forward state at this point: + // Back: 3 (kAnchorUrl, kAnchor1Url, kAnchor2Url) + // Forward: 1 (kAnchor3Url) + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor2Url))) + .WillOnce(testing::IgnoreResult(testing::InvokeWithoutArgs( + CreateFunctor(ReceivePointer(mock.web_browser2_), + &IWebBrowser::GoForward)))); + EXPECT_CALL(mock, OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal, + testing::StrCaseEq(kAnchor3Url)), + _, _, _, _, _)) + .WillOnce(testing::Return(S_OK)); + EXPECT_CALL(mock, OnNavigateComplete2(_, _)) + .WillOnce(testing::Return()); + + // We have gone a few steps back and forward, this should be enough for now. + EXPECT_CALL(mock, OnLoad(testing::StrEq(kAnchor3Url))) + .WillOnce(testing::DoAll( + testing::InvokeWithoutArgs(CreateFunctor(&mock, + &WebBrowserEventSink::Uninitialize)), + testing::IgnoreResult(testing::InvokeWithoutArgs( + &chrome_frame_test::CloseAllIEWindows)), + QUIT_LOOP_SOON(loop, 2))); + + HRESULT hr = mock.LaunchIEAndNavigate(kAnchorUrl); + ASSERT_HRESULT_SUCCEEDED(hr); + if (hr == S_FALSE) + return; + + ASSERT_TRUE(mock.web_browser2() != NULL); + loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds); +} diff --git a/chrome_frame/test/chrome_frame_unittests.h b/chrome_frame/test/chrome_frame_unittests.h index 7ecdf50..c39058b 100644 --- a/chrome_frame/test/chrome_frame_unittests.h +++ b/chrome_frame/test/chrome_frame_unittests.h @@ -128,16 +128,7 @@ class WebBrowserEventSink Uninitialize(); } - void Uninitialize() { - chrome_frame_ = NULL; - if (web_browser2_.get()) { - DispEventUnadvise(web_browser2_); - web_browser2_->Quit(); - web_browser2_.Release(); - // Give IE some time to quit and release our references - Sleep(1000); - } - } + void Uninitialize(); // Helper function to launch IE and navigate to a URL. // Returns S_OK on success, S_FALSE if the test was not run, other @@ -146,6 +137,13 @@ class WebBrowserEventSink HRESULT Navigate(const std::wstring& navigate_url); + // Set input focus to chrome frame window. + void SetFocusToChrome(); + + // Send keyboard input to the renderer window hosted in chrome using + // SendInput API + void SendInputToChrome(const std::string& input_string); + BEGIN_COM_MAP(WebBrowserEventSink) END_COM_MAP() @@ -212,7 +210,8 @@ END_SINK_MAP() HRESULT OnLoadErrorInternal(const VARIANT* param); HRESULT OnMessageInternal(const VARIANT* param); - void ConnectToChromeFrame(); + void ConnectToChromeFrame(); + HWND GetChromeRendererWindow(); public: ScopedComPtr<IWebBrowser2> web_browser2_; |