1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "base/command_line.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "base/run_loop.h" 8 #include "chrome/browser/printing/print_preview_dialog_controller.h" 9 #include "chrome/browser/ui/browser.h" 10 #include "chrome/browser/ui/browser_commands.h" 11 #include "chrome/browser/ui/tabs/tab_strip_model.h" 12 #include "chrome/common/chrome_switches.h" 13 #include "chrome/common/print_messages.h" 14 #include "chrome/common/url_constants.h" 15 #include "chrome/test/base/in_process_browser_test.h" 16 #include "chrome/test/base/ui_test_utils.h" 17 #include "content/public/browser/notification_service.h" 18 #include "content/public/browser/notification_types.h" 19 #include "content/public/browser/web_contents_observer.h" 20 #include "url/gurl.h" 21 #include "ipc/ipc_message_macros.h" 22 23 using content::WebContents; 24 using content::WebContentsObserver; 25 26 class RequestPrintPreviewObserver : public WebContentsObserver { 27 public: 28 explicit RequestPrintPreviewObserver(WebContents* dialog) 29 : WebContentsObserver(dialog) { 30 } 31 virtual ~RequestPrintPreviewObserver() {} 32 33 void set_quit_closure(const base::Closure& quit_closure) { 34 quit_closure_ = quit_closure; 35 } 36 37 private: 38 // content::WebContentsObserver implementation. 39 virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE { 40 IPC_BEGIN_MESSAGE_MAP(RequestPrintPreviewObserver, message) 41 IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview, 42 OnRequestPrintPreview) 43 IPC_MESSAGE_UNHANDLED(break;) 44 IPC_END_MESSAGE_MAP(); 45 return false; // Report not handled so the real handler receives it. 46 } 47 48 void OnRequestPrintPreview( 49 const PrintHostMsg_RequestPrintPreview_Params& /* params */) { 50 base::MessageLoop::current()->PostTask(FROM_HERE, quit_closure_); 51 } 52 53 base::Closure quit_closure_; 54 55 DISALLOW_COPY_AND_ASSIGN(RequestPrintPreviewObserver); 56 }; 57 58 class PrintPreviewDialogClonedObserver : public WebContentsObserver { 59 public: 60 explicit PrintPreviewDialogClonedObserver(WebContents* dialog) 61 : WebContentsObserver(dialog) { 62 } 63 virtual ~PrintPreviewDialogClonedObserver() {} 64 65 RequestPrintPreviewObserver* request_preview_dialog_observer() { 66 return request_preview_dialog_observer_.get(); 67 } 68 69 private: 70 // content::WebContentsObserver implementation. 71 virtual void DidCloneToNewWebContents( 72 WebContents* old_web_contents, 73 WebContents* new_web_contents) OVERRIDE { 74 request_preview_dialog_observer_.reset( 75 new RequestPrintPreviewObserver(new_web_contents)); 76 } 77 78 scoped_ptr<RequestPrintPreviewObserver> request_preview_dialog_observer_; 79 80 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogClonedObserver); 81 }; 82 83 class PrintPreviewDialogDestroyedObserver : public WebContentsObserver { 84 public: 85 explicit PrintPreviewDialogDestroyedObserver(WebContents* dialog) 86 : WebContentsObserver(dialog), 87 dialog_destroyed_(false) { 88 } 89 virtual ~PrintPreviewDialogDestroyedObserver() {} 90 91 bool dialog_destroyed() const { return dialog_destroyed_; } 92 93 private: 94 // content::WebContentsObserver implementation. 95 virtual void WebContentsDestroyed(WebContents* contents) OVERRIDE { 96 dialog_destroyed_ = true; 97 } 98 99 bool dialog_destroyed_; 100 101 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogDestroyedObserver); 102 }; 103 104 class PrintPreviewDialogControllerBrowserTest : public InProcessBrowserTest { 105 public: 106 PrintPreviewDialogControllerBrowserTest() : initiator_(NULL) {} 107 virtual ~PrintPreviewDialogControllerBrowserTest() {} 108 109 WebContents* initiator() { 110 return initiator_; 111 } 112 113 void PrintPreview() { 114 base::RunLoop run_loop; 115 request_preview_dialog_observer()->set_quit_closure(run_loop.QuitClosure()); 116 chrome::Print(browser()); 117 run_loop.Run(); 118 } 119 120 WebContents* GetPrintPreviewDialog() { 121 printing::PrintPreviewDialogController* dialog_controller = 122 printing::PrintPreviewDialogController::GetInstance(); 123 return dialog_controller->GetPrintPreviewForContents(initiator_); 124 } 125 126 private: 127 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 128 #if !defined(GOOGLE_CHROME_BUILD) 129 command_line->AppendSwitch(switches::kEnablePrintPreview); 130 #endif 131 } 132 133 virtual void SetUpOnMainThread() OVERRIDE { 134 WebContents* first_tab = 135 browser()->tab_strip_model()->GetActiveWebContents(); 136 ASSERT_TRUE(first_tab); 137 138 // Open a new tab so |cloned_tab_observer_| can see it first and attach a 139 // RequestPrintPreviewObserver to it before the real 140 // PrintPreviewMessageHandler gets created. Thus enabling 141 // RequestPrintPreviewObserver to get messages first for the purposes of 142 // this test. 143 cloned_tab_observer_.reset(new PrintPreviewDialogClonedObserver(first_tab)); 144 chrome::DuplicateTab(browser()); 145 146 initiator_ = browser()->tab_strip_model()->GetActiveWebContents(); 147 ASSERT_TRUE(initiator_); 148 ASSERT_NE(first_tab, initiator_); 149 } 150 151 virtual void CleanUpOnMainThread() OVERRIDE { 152 cloned_tab_observer_.reset(); 153 initiator_ = NULL; 154 } 155 156 RequestPrintPreviewObserver* request_preview_dialog_observer() { 157 return cloned_tab_observer_->request_preview_dialog_observer(); 158 } 159 160 scoped_ptr<PrintPreviewDialogClonedObserver> cloned_tab_observer_; 161 WebContents* initiator_; 162 163 DISALLOW_COPY_AND_ASSIGN(PrintPreviewDialogControllerBrowserTest); 164 }; 165 166 // Test to verify that when a initiator navigates, we can create a new preview 167 // dialog for the new tab contents. 168 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest, 169 NavigateFromInitiatorTab) { 170 // print for the first time. 171 PrintPreview(); 172 173 // Get the preview dialog for the initiator tab. 174 WebContents* preview_dialog = GetPrintPreviewDialog(); 175 176 // Check a new print preview dialog got created. 177 ASSERT_TRUE(preview_dialog); 178 ASSERT_NE(initiator(), preview_dialog); 179 180 // Navigate in the initiator tab. Make sure navigating destroys the print 181 // preview dialog. 182 PrintPreviewDialogDestroyedObserver dialog_destroyed_observer(preview_dialog); 183 ui_test_utils::NavigateToURL(browser(), GURL(chrome::kChromeUINewTabURL)); 184 ASSERT_TRUE(dialog_destroyed_observer.dialog_destroyed()); 185 186 // Try printing again. 187 PrintPreview(); 188 189 // Get the print preview dialog for the initiator tab. 190 WebContents* new_preview_dialog = GetPrintPreviewDialog(); 191 192 // Check a new preview dialog got created. 193 EXPECT_TRUE(new_preview_dialog); 194 } 195 196 // Test to verify that after reloading the initiator, it creates a new print 197 // preview dialog. 198 IN_PROC_BROWSER_TEST_F(PrintPreviewDialogControllerBrowserTest, 199 ReloadInitiatorTab) { 200 // print for the first time. 201 PrintPreview(); 202 203 WebContents* preview_dialog = GetPrintPreviewDialog(); 204 205 // Check a new print preview dialog got created. 206 ASSERT_TRUE(preview_dialog); 207 ASSERT_NE(initiator(), preview_dialog); 208 209 // Reload the initiator. Make sure reloading destroys the print preview 210 // dialog. 211 PrintPreviewDialogDestroyedObserver dialog_destroyed_observer(preview_dialog); 212 content::WindowedNotificationObserver notification_observer( 213 content::NOTIFICATION_LOAD_STOP, 214 content::NotificationService::AllSources()); 215 chrome::Reload(browser(), CURRENT_TAB); 216 notification_observer.Wait(); 217 ASSERT_TRUE(dialog_destroyed_observer.dialog_destroyed()); 218 219 // Try printing again. 220 PrintPreview(); 221 222 // Create a preview dialog for the initiator tab. 223 WebContents* new_preview_dialog = GetPrintPreviewDialog(); 224 EXPECT_TRUE(new_preview_dialog); 225 } 226