summaryrefslogtreecommitdiffstats
path: root/chrome_frame/test/chrome_frame_unittests.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chrome_frame/test/chrome_frame_unittests.cc')
-rw-r--r--chrome_frame/test/chrome_frame_unittests.cc229
1 files changed, 198 insertions, 31 deletions
diff --git a/chrome_frame/test/chrome_frame_unittests.cc b/chrome_frame/test/chrome_frame_unittests.cc
index 14eb757..1d6dfe3 100644
--- a/chrome_frame/test/chrome_frame_unittests.cc
+++ b/chrome_frame/test/chrome_frame_unittests.cc
@@ -14,7 +14,6 @@
#include "base/file_version_info.h"
#include "base/file_util.h"
#include "base/scoped_bstr_win.h"
-#include "base/scoped_comptr_win.h"
#include "base/scoped_variant_win.h"
#include "base/sys_info.h"
#include "gmock/gmock.h"
@@ -64,6 +63,15 @@ _ATL_FUNC_INFO WebBrowserEventSink::kBeforeNavigate2Info = {
}
};
+_ATL_FUNC_INFO WebBrowserEventSink::kNewWindow3Info = {
+ CC_STDCALL, VT_EMPTY, 5, {
+ VT_DISPATCH | VT_BYREF,
+ VT_BOOL | VT_BYREF,
+ VT_UINT,
+ VT_BSTR,
+ VT_BSTR
+ }
+};
void ChromeFrameTestWithWebServer::SetUp() {
@@ -830,7 +838,7 @@ template <> struct RunnableMethodTraits<ChromeFrameAutomationClient> {
struct TimedMsgLoop {
public:
void RunFor(int seconds) {
- loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, 1000 * seconds);
+ QuitAfter(seconds);
loop_.MessageLoop::Run();
}
@@ -838,6 +846,10 @@ struct TimedMsgLoop {
loop_.PostTask(FROM_HERE, new MessageLoop::QuitTask);
}
+ void QuitAfter(int seconds) {
+ loop_.PostDelayedTask(FROM_HERE, new MessageLoop::QuitTask, 1000 * seconds);
+ }
+
MessageLoopForUI loop_;
};
@@ -852,6 +864,9 @@ template <> struct RunnableMethodTraits<TimedMsgLoop> {
#define QUIT_LOOP(loop) testing::InvokeWithoutArgs(\
CreateFunctor(&loop, &TimedMsgLoop::Quit))
+#define QUIT_LOOP_SOON(loop, seconds) testing::InvokeWithoutArgs(\
+ CreateFunctor(&loop, &TimedMsgLoop::QuitAfter, seconds))
+
// We mock ChromeFrameDelegate only. The rest is with real AutomationProxy
TEST(CFACWithChrome, CreateTooFast) {
MockCFDelegate cfd;
@@ -1280,7 +1295,9 @@ HRESULT LaunchIEAsComServer(IWebBrowser2** web_browser) {
return hr;
}
-TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) {
+// WebBrowserEventSink member defines
+HRESULT WebBrowserEventSink::LaunchIEAndNavigate(
+ const std::wstring& navigate_url, _IDispEvent* sink) {
int major_version = 0;
int minor_version = 0;
int bugfix_version = 0;
@@ -1290,54 +1307,204 @@ TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) {
if (major_version > 5) {
DLOG(INFO) << __FUNCTION__ << " Not running test on Windows version: "
<< major_version;
- return;
+ return S_FALSE;
}
IEVersion ie_version = GetIEVersion();
if (ie_version == IE_8) {
DLOG(INFO) << __FUNCTION__ << " Not running test on IE8";
- return;
+ return S_FALSE;
}
- HRESULT hr = CoInitialize(NULL);
- bool should_uninit = SUCCEEDED(hr);
-
- ScopedComPtr<IWebBrowser2> web_browser2;
- EXPECT_TRUE(S_OK == LaunchIEAsComServer(web_browser2.Receive()));
- web_browser2->put_Visible(VARIANT_TRUE);
+ EXPECT_TRUE(S_OK == LaunchIEAsComServer(web_browser2_.Receive()));
+ web_browser2_->put_Visible(VARIANT_TRUE);
- CComObject<WebBrowserEventSink>* web_browser_sink = NULL;
- CComObject<WebBrowserEventSink>::CreateInstance(&web_browser_sink);
-
- // Pass the main thread id to the browser sink so that it can notify
- // us about test completion.
- web_browser_sink->set_main_thread_id(GetCurrentThreadId());
-
- hr = web_browser_sink->DispEventAdvise(web_browser2,
- &DIID_DWebBrowserEvents2);
+ HRESULT hr = sink->DispEventAdvise(web_browser2_,
+ &DIID_DWebBrowserEvents2);
EXPECT_TRUE(hr == S_OK);
VARIANT empty = ScopedVariant::kEmptyVariant;
ScopedVariant url;
- url.Set(L"cf:file:///C:/");
+ url.Set(navigate_url.c_str());
+ hr = web_browser2_->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty);
+ EXPECT_TRUE(hr == S_OK);
+ return hr;
+}
+
+const int kChromeFrameLongNavigationTimeoutInSeconds = 10;
+
+// This class provides functionality to add expectations to IE full tab mode
+// tests.
+class MockWebBrowserEventSink : public WebBrowserEventSink {
+ public:
+ // Needed to support PostTask.
+ static bool ImplementsThreadSafeReferenceCounting() {
+ return true;
+ }
+
+ MOCK_METHOD7_WITH_CALLTYPE(__stdcall, OnBeforeNavigate2,
+ HRESULT (IDispatch* dispatch,
+ VARIANT* url,
+ VARIANT* flags,
+ VARIANT* target_frame_name,
+ VARIANT* post_data,
+ VARIANT* headers,
+ VARIANT_BOOL* cancel));
+
+ MOCK_METHOD2_WITH_CALLTYPE(__stdcall, OnNavigateComplete2,
+ void (IDispatch* dispatch, VARIANT* url));
+
+ MOCK_METHOD5_WITH_CALLTYPE(__stdcall, OnNewWindow3,
+ void (IDispatch** dispatch,
+ VARIANT_BOOL* Cancel,
+ DWORD flags,
+ BSTR url_context,
+ BSTR url));
+
+ MOCK_METHOD5_WITH_CALLTYPE(__stdcall, OnNavigateError,
+ void (IDispatch* dispatch,
+ VARIANT* url,
+ VARIANT* frame_name,
+ VARIANT* status_code,
+ VARIANT* cancel));
+};
+
+using testing::_;
+
+const wchar_t kChromeFrameFileUrl[] = L"cf:file:///C:/";
+
+TEST(ChromeFrameTest, FullTabModeIE_DisallowedUrls) {
TimedMsgLoop loop;
+ // If a navigation fails then IE issues a navigation to an interstitial
+ // page. Catch this to track navigation errors as the NavigateError
+ // notification does not seem to fire reliably.
+ CComObjectStackEx<MockWebBrowserEventSink> mock;
+
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kChromeFrameFileUrl)),
+ _, _, _, _, _))
+ .Times(1)
+ .WillOnce(testing::Return(S_OK));
- hr = web_browser2->Navigate2(url.AsInput(), &empty, &empty, &empty, &empty);
- EXPECT_TRUE(hr == S_OK);
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StartsWith(L"res:")),
+ _, _, _, _, _))
+ .Times(1)
+ .WillOnce(testing::DoAll(
+ QUIT_LOOP(loop),
+ testing::Return(S_OK)));
- loop.RunFor(10);
+ HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFileUrl, &mock);
+ ASSERT_HRESULT_SUCCEEDED(hr);
+ if (hr == S_FALSE)
+ return;
- EXPECT_TRUE(web_browser_sink->navigation_failed());
+ ASSERT_TRUE(mock.web_browser2() != NULL);
- hr = web_browser_sink->DispEventUnadvise(web_browser2);
- EXPECT_TRUE(hr == S_OK);
+ loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
- web_browser2.Release();
+ mock.Uninitialize();
chrome_frame_test::CloseAllIEWindows();
+}
- if (should_uninit) {
- CoUninitialize();
- }
+const wchar_t kChromeFrameFullTabWindowOpenTestUrl[] =
+ L"http://localhost:1337/files/chrome_frame_window_open.html";
+
+const wchar_t kChromeFrameFullTabWindowOpenPopupUrl[] =
+ L"http://localhost:1337/files/chrome_frame_window_open_popup.html";
+
+// This test checks if window.open calls issued by a full tab mode ChromeFrame
+// instance make it back to IE and then transitions back to Chrome as the
+// window.open target page is supposed to render within Chrome.
+TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_WindowOpen) {
+ TimedMsgLoop loop;
+
+ CComObjectStackEx<MockWebBrowserEventSink> mock;
+
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(
+ _, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kChromeFrameFullTabWindowOpenTestUrl)),
+ _, _, _, _, _))
+ .Times(1)
+ .WillOnce(testing::Return(S_OK));
+
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(
+ _, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kChromeFrameFullTabWindowOpenPopupUrl)),
+ _, _, _, _, _))
+ .Times(1)
+ .WillOnce(testing::DoAll(
+ QUIT_LOOP_SOON(loop, 2),
+ testing::Return(S_OK)));
+
+ HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameFullTabWindowOpenTestUrl,
+ &mock);
+ ASSERT_HRESULT_SUCCEEDED(hr);
+ if (hr == S_FALSE)
+ return;
+
+ ASSERT_TRUE(mock.web_browser2() != NULL);
+
+ loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
+
+ ASSERT_TRUE(CheckResultFile(L"ChromeFrameWindowOpenPopup", "OK"));
+
+ mock.Uninitialize();
+ chrome_frame_test::CloseAllIEWindows();
+}
+
+const wchar_t kChromeFrameAboutBlankUrl[] =
+ L"cf:about:blank";
+
+const wchar_t kChromeFrameAboutVersion[] =
+ L"cf:about:version";
+
+// This test launches chrome frame in full tab mode in IE by having IE navigate
+// to cf:about:blank. It then looks for the chrome renderer window and posts
+// the WM_RBUTTONDOWN/WM_RBUTTONUP messages to it, which bring up the context
+// menu. This is followed by keyboard messages sent via SendInput to select
+// the About chrome frame menu option, which would then bring up a new window
+// with the chrome revision. The test finally checks for success by comparing
+// the URL of the window being opened with cf:about:version, which indicates
+// that the operation succeeded.
+TEST_F(ChromeFrameTestWithWebServer, FullTabModeIE_AboutChromeFrame) {
+ TimedMsgLoop loop;
+
+ CComObjectStackEx<MockWebBrowserEventSink> mock;
+
+ EXPECT_CALL(mock,
+ OnBeforeNavigate2(_, testing::Field(&VARIANT::bstrVal,
+ testing::StrCaseEq(kChromeFrameAboutBlankUrl)),
+ _, _, _, _, _))
+ .Times(1)
+ .WillOnce(testing::Return(S_OK));
+
+ EXPECT_CALL(mock, OnNavigateComplete2(_, _))
+ .Times(1)
+ .WillOnce(testing::InvokeWithoutArgs(
+ &chrome_frame_test::ShowChromeFrameContextMenu));
+
+ EXPECT_CALL(mock,
+ OnNewWindow3(_, _, _, _,
+ testing::StrCaseEq(kChromeFrameAboutVersion)))
+ .Times(1)
+ .WillOnce(QUIT_LOOP(loop));
+
+ HRESULT hr = mock.LaunchIEAndNavigate(kChromeFrameAboutBlankUrl, &mock);
+ ASSERT_HRESULT_SUCCEEDED(hr);
+ if (hr == S_FALSE)
+ return;
+
+ ASSERT_TRUE(mock.web_browser2() != NULL);
+
+ loop.RunFor(kChromeFrameLongNavigationTimeoutInSeconds);
+
+ mock.Uninitialize();
+ chrome_frame_test::CloseAllIEWindows();
}