blob: 9e5266a85908a78beb5338ff35d664eb3ac3de29 [file] [log] [blame]
Avi Drissman4a8573c2022-09-09 19:35:541// Copyright 2021 The Chromium Authors
Peter Kvitek6e5bfc222021-11-12 23:33:292// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Peter Kvitek16f010c2022-04-29 05:02:395#include "chrome/browser/headless/headless_mode_browsertest.h"
Peter Kvitek6e5bfc222021-11-12 23:33:296
Peter Kvitek2754d7e2021-12-13 21:03:537#include "build/build_config.h"
8
Peter Kvitekd64628e2022-02-04 22:46:329// Native headless is currently available on Linux, Windows and Mac platforms.
Peter Kvitek2754d7e2021-12-13 21:03:5310// More platforms will be added later, so avoid function level clutter by
11// providing a compile time condition over the entire file.
Peter Kvitekd64628e2022-02-04 22:46:3212#if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
Peter Kvitek2754d7e2021-12-13 21:03:5313
Peter Kvitek6e5bfc222021-11-12 23:33:2914#include <string>
15
Peter Kvitek4dbcf1c2024-09-24 22:43:2616#include "base/check_deref.h"
Peter Kvitek6e5bfc222021-11-12 23:33:2917#include "base/command_line.h"
Peter Kvitekb95e2232021-12-10 00:40:0818#include "base/files/file.h"
Peter Kvitek5f51f5a2023-07-19 00:45:3819#include "base/functional/bind.h"
20#include "base/logging.h"
Peter Kvitek4dbcf1c2024-09-24 22:43:2621#include "base/path_service.h"
Peter Kvitek5f51f5a2023-07-19 00:45:3822#include "base/run_loop.h"
Peter Kvitekb95e2232021-12-10 00:40:0823#include "base/test/task_environment.h"
24#include "base/test/test_timeouts.h"
Peter Kvitek2cd1a9b2023-01-31 19:34:4525#include "base/threading/thread_restrictions.h"
Peter Kvitekc42c83d2024-06-11 21:24:2226#include "build/branding_buildflags.h"
Peter Kvitekc39a59962024-01-08 23:22:1627#include "chrome/browser/headless/headless_mode_browsertest_utils.h"
Peter Kvitek16f010c2022-04-29 05:02:3928#include "chrome/browser/headless/headless_mode_util.h"
Peter Kvitekc42c83d2024-06-11 21:24:2229#include "chrome/browser/infobars/confirm_infobar_creator.h"
Peter Kvitekb95e2232021-12-10 00:40:0830#include "chrome/browser/process_singleton.h"
Peter Kvitek2cd1a9b2023-01-31 19:34:4531#include "chrome/browser/profiles/profile.h"
Peter Kvitek6e5bfc222021-11-12 23:33:2932#include "chrome/browser/ui/browser.h"
Peter Kvitek69907fc2023-01-31 18:07:4933#include "chrome/browser/ui/browser_window.h"
Peter Kvitekdbdb4d22023-12-01 00:39:5334#include "chrome/browser/ui/views/frame/app_menu_button.h"
35#include "chrome/browser/ui/views/frame/browser_view.h"
36#include "chrome/browser/ui/views/frame/toolbar_button_provider.h"
Peter Kvitek4dbcf1c2024-09-24 22:43:2637#include "chrome/common/chrome_paths.h"
Peter Kvitekb95e2232021-12-10 00:40:0838#include "chrome/common/chrome_switches.h"
Peter Kvitek49a1e142023-11-30 18:32:2339#include "components/headless/clipboard/headless_clipboard.h" // nogncheck
40#include "components/infobars/content/content_infobar_manager.h" // nogncheck
Peter Kvitekc42c83d2024-06-11 21:24:2241#include "components/infobars/core/confirm_infobar_delegate.h"
42#include "components/infobars/core/infobar.h"
43#include "components/infobars/core/infobars_switches.h"
Peter Kvitek5f51f5a2023-07-19 00:45:3844#include "content/public/browser/browser_context.h"
45#include "content/public/browser/browser_task_traits.h"
46#include "content/public/browser/browser_thread.h"
47#include "content/public/browser/navigation_controller.h"
48#include "content/public/browser/web_contents.h"
Peter Kvitek7dd69b9c2022-05-13 19:24:0849#include "content/public/common/content_switches.h"
Peter Kvitekb95e2232021-12-10 00:40:0850#include "content/public/test/browser_task_environment.h"
Peter Kvitek6e5bfc222021-11-12 23:33:2951#include "content/public/test/browser_test_utils.h"
Peter Kvitek17836682023-01-18 07:24:3752#include "net/test/embedded_test_server/embedded_test_server.h"
Peter Kvitek6e5bfc222021-11-12 23:33:2953#include "testing/gmock/include/gmock/gmock.h"
Peter Kvitekf6a06c62023-02-07 18:06:0054#include "ui/base/clipboard/clipboard.h"
Peter Kvitek22202802023-09-22 21:07:3455#include "ui/base/clipboard/clipboard_non_backed.h"
Peter Kvitekf6a06c62023-02-07 18:06:0056#include "ui/base/clipboard/clipboard_sequence_number_token.h"
57#include "ui/base/clipboard/scoped_clipboard_writer.h"
Peter Kvitekdbdb4d22023-12-01 00:39:5358#include "ui/base/models/dialog_model.h"
Peter Kvitek2a2b92a2023-03-01 23:22:3959#include "ui/display/display_switches.h"
Mitsuru Oshima195405d2025-09-17 03:21:4660#include "ui/gfx/native_ui_types.h"
Peter Kvitek6e5bfc222021-11-12 23:33:2961#include "ui/gfx/switches.h"
Peter Kvitekdbdb4d22023-12-01 00:39:5362#include "ui/views/bubble/bubble_dialog_model_host.h"
63#include "ui/views/view.h"
Peter Kvitekf3c187af72023-11-28 00:53:2264#include "ui/views/widget/widget.h"
Peter Kvitek5f51f5a2023-07-19 00:45:3865#include "url/gurl.h"
Peter Kvitek6e5bfc222021-11-12 23:33:2966
Peter Kvitekdbdb4d22023-12-01 00:39:5367using views::Widget;
Peter Kvitekf3c187af72023-11-28 00:53:2268
Peter Kvitek1034c08d2023-01-24 17:54:0769namespace headless {
70
Peter Kvitek3a91cb82023-01-24 01:41:2671namespace switches {
72// This switch runs tests in headful mode, intended for experiments only because
73// not all tests are expected to pass in headful mode.
74static const char kHeadfulMode[] = "headful-mode";
75} // namespace switches
76
Peter Kvitek17836682023-01-18 07:24:3777HeadlessModeBrowserTest::HeadlessModeBrowserTest() {
78 base::FilePath test_data(
79 FILE_PATH_LITERAL("chrome/browser/headless/test/data"));
80 embedded_test_server()->AddDefaultHandlers(test_data);
81}
82
Peter Kvitek36fc29102025-08-21 02:06:2183HeadlessModeBrowserTest::~HeadlessModeBrowserTest() = default;
84
Peter Kvitek16f010c2022-04-29 05:02:3985void HeadlessModeBrowserTest::SetUpCommandLine(
86 base::CommandLine* command_line) {
Peter Kvitek2cd1a9b2023-01-31 19:34:4587 AppendHeadlessCommandLineSwitches(command_line);
88}
Peter Kvitek6e5bfc222021-11-12 23:33:2989
Peter Kvitek2cd1a9b2023-01-31 19:34:4590void HeadlessModeBrowserTest::SetUpOnMainThread() {
91 InProcessBrowserTest::SetUpOnMainThread();
92
93 ASSERT_TRUE(headless::IsHeadlessMode() || headful_mode());
94}
95
Andrey Kosyakov43c18832024-02-15 17:24:3596bool HeadlessModeBrowserTest::IsIncognito() {
97 return false;
98}
99
Peter Kvitek2cd1a9b2023-01-31 19:34:45100void HeadlessModeBrowserTest::AppendHeadlessCommandLineSwitches(
101 base::CommandLine* command_line) {
Andrey Kosyakov43c18832024-02-15 17:24:35102 if (IsIncognito()) {
103 command_line->AppendSwitch(::switches::kIncognito);
104 }
Peter Kvitek3a91cb82023-01-24 01:41:26105 if (command_line->HasSwitch(switches::kHeadfulMode)) {
106 headful_mode_ = true;
107 } else {
Peter Kvitek1f76f9d32025-05-02 18:34:23108 command_line->AppendSwitch(::switches::kHeadless);
Peter Kvitek36fc29102025-08-21 02:06:21109 auto init_headless_mode = headless::InitHeadlessMode();
110 CHECK(init_headless_mode.has_value()) << init_headless_mode.error();
111 headless_mode_handle_ = std::move(headless::InitHeadlessMode().value());
Peter Kvitek3a91cb82023-01-24 01:41:26112 }
Peter Kvitek16f010c2022-04-29 05:02:39113}
Peter Kvitek6e5bfc222021-11-12 23:33:29114
Peter Kvitek49a1e142023-11-30 18:32:23115content::WebContents* HeadlessModeBrowserTest::GetActiveWebContents() {
116 return browser()->tab_strip_model()->GetActiveWebContents();
117}
118
Peter Kvitek7dd69b9c2022-05-13 19:24:08119void HeadlessModeBrowserTestWithStartWindowMode::SetUpCommandLine(
120 base::CommandLine* command_line) {
121 HeadlessModeBrowserTest::SetUpCommandLine(command_line);
122
123 switch (start_window_mode()) {
124 case kStartWindowNormal:
125 break;
126 case kStartWindowMaximized:
Peter Kvitek1034c08d2023-01-24 17:54:07127 command_line->AppendSwitch(::switches::kStartMaximized);
Peter Kvitek7dd69b9c2022-05-13 19:24:08128 break;
129 case kStartWindowFullscreen:
Peter Kvitek1034c08d2023-01-24 17:54:07130 command_line->AppendSwitch(::switches::kStartFullscreen);
Peter Kvitek7dd69b9c2022-05-13 19:24:08131 break;
132 }
133}
134
Peter Kvitek1034c08d2023-01-24 17:54:07135namespace {
136
Peter Kvitek2cd1a9b2023-01-31 19:34:45137// Miscellaneous tests -------------------------------------------------------
138
Peter Kvitek69907fc2023-01-31 18:07:49139IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTest, BrowserWindowIsActive) {
140 EXPECT_TRUE(browser()->window()->IsActive());
141}
142
Peter Kvitekc42c83d2024-06-11 21:24:22143// Infobar tests -------------------------------------------------------------
144
145class TestInfoBarDelegate : public ConfirmInfoBarDelegate {
146 public:
147 TestInfoBarDelegate(const TestInfoBarDelegate&) = delete;
148 TestInfoBarDelegate& operator=(const TestInfoBarDelegate&) = delete;
149
150 static void Create(infobars::ContentInfoBarManager* infobar_manager,
151 int buttons) {
152 infobar_manager->AddInfoBar(
153 CreateConfirmInfoBar(std::unique_ptr<ConfirmInfoBarDelegate>(
154 new TestInfoBarDelegate(buttons))));
155 }
156
157 // ConfirmInfoBarDelegate:
158 infobars::InfoBarDelegate::InfoBarIdentifier GetIdentifier() const override {
159 return TEST_INFOBAR;
160 }
161 std::u16string GetMessageText() const override {
162 return buttons_ ? u"BUTTON" : u"";
163 }
164 int GetButtons() const override { return buttons_; }
165
166 private:
167 explicit TestInfoBarDelegate(int buttons) : buttons_(buttons) {}
168 ~TestInfoBarDelegate() override = default;
169
170 int buttons_;
171};
172
173class HeadlessModeInfobarBrowserTest
174 : public HeadlessModeBrowserTest,
175 public testing::WithParamInterface<bool> {
176 public:
177 HeadlessModeInfobarBrowserTest() = default;
178 ~HeadlessModeInfobarBrowserTest() override = default;
179
180 void SetUpCommandLine(base::CommandLine* command_line) override {
181 HeadlessModeBrowserTest::SetUpCommandLine(command_line);
182 if (disable_infobars()) {
183 command_line->AppendSwitch(::switches::kDisableInfoBars);
184 }
185 }
186
187 bool disable_infobars() const { return GetParam(); }
188};
189
190INSTANTIATE_TEST_SUITE_P(/* no prefix */,
191 HeadlessModeInfobarBrowserTest,
192 ::testing::Bool());
193
194IN_PROC_BROWSER_TEST_P(HeadlessModeInfobarBrowserTest, InfoBarsCanBeDisabled) {
Peter Kvitek49a1e142023-11-30 18:32:23195 content::WebContents* web_contents = GetActiveWebContents();
196 ASSERT_TRUE(web_contents);
197
198 infobars::ContentInfoBarManager* infobar_manager =
199 infobars::ContentInfoBarManager::FromWebContents(web_contents);
200 ASSERT_TRUE(infobar_manager);
201
Peter Kvitekc42c83d2024-06-11 21:24:22202#if BUILDFLAG(CHROME_FOR_TESTING)
203 // Chrome for Testing shows its disclaimer infobar upon start.
204 infobar_manager->RemoveAllInfoBars(/*animate=*/false);
205#endif
Peter Kvitek49a1e142023-11-30 18:32:23206
Peter Kvitekc42c83d2024-06-11 21:24:22207 ASSERT_THAT(infobar_manager->infobars(), testing::IsEmpty());
208
209 TestInfoBarDelegate::Create(infobar_manager,
210 ConfirmInfoBarDelegate::BUTTON_NONE);
211 TestInfoBarDelegate::Create(infobar_manager,
212 ConfirmInfoBarDelegate::BUTTON_OK);
213
214 // The infobar with a button should appear even if infobars are disabled.
215 EXPECT_THAT(infobar_manager->infobars(),
216 testing::SizeIs(disable_infobars() ? 1 : 2));
Peter Kvitek49a1e142023-11-30 18:32:23217}
218
219// UserAgent tests -----------------------------------------------------------
220
Peter Kvitek5f51f5a2023-07-19 00:45:38221class HeadlessModeUserAgentBrowserTest : public HeadlessModeBrowserTest {
222 public:
223 HeadlessModeUserAgentBrowserTest() = default;
224 ~HeadlessModeUserAgentBrowserTest() override = default;
225
226 void SetUp() override {
227 embedded_test_server()->RegisterRequestHandler(
228 base::BindRepeating(&HeadlessModeUserAgentBrowserTest::RequestHandler,
229 base::Unretained(this)));
230
231 ASSERT_TRUE(embedded_test_server()->Start());
232
233 HeadlessModeBrowserTest::SetUp();
234 }
235
236 protected:
237 std::unique_ptr<net::test_server::HttpResponse> RequestHandler(
238 const net::test_server::HttpRequest& request) {
239 if (request.relative_url == "/page.html") {
240 headers_ = request.headers;
241
242 content::GetUIThreadTaskRunner({})->PostTask(
243 FROM_HERE,
244 base::BindOnce(&HeadlessModeUserAgentBrowserTest::FinishTest,
245 base::Unretained(this)));
246
247 auto response = std::make_unique<net::test_server::BasicHttpResponse>();
248 response->set_code(net::HTTP_OK);
249 response->set_content_type("text/html");
250 response->set_content(R"(<div>Hi, I'm headless!</div>)");
251
252 return response;
253 }
254
255 return nullptr;
256 }
257
258 void RunLoop() {
259 if (!test_complete_) {
260 run_loop_ = std::make_unique<base::RunLoop>();
261 run_loop_->Run();
262 run_loop_.reset();
263 }
264 }
265
266 void FinishTest() {
267 test_complete_ = true;
268 if (run_loop_) {
269 run_loop_->Quit();
270 }
271 }
272
273 bool test_complete_ = false;
274 std::unique_ptr<base::RunLoop> run_loop_;
275 net::test_server::HttpRequest::HeaderMap headers_;
276};
277
278IN_PROC_BROWSER_TEST_F(HeadlessModeUserAgentBrowserTest, UserAgentHasHeadless) {
279 content::BrowserContext* browser_context = browser()->profile();
280 DCHECK(browser_context);
281
282 content::WebContents::CreateParams create_params(browser_context);
283 std::unique_ptr<content::WebContents> web_contents =
284 content::WebContents::Create(create_params);
285 DCHECK(web_contents);
286
287 GURL url = embedded_test_server()->GetURL("/page.html");
288 content::NavigationController::LoadURLParams params(url);
289 web_contents->GetController().LoadURLWithParams(params);
290
291 RunLoop();
292
293 web_contents->Close();
294 web_contents.reset();
295
296 base::RunLoop().RunUntilIdle();
297
298 EXPECT_THAT(headers_.at("User-Agent"), testing::HasSubstr("HeadlessChrome/"));
299}
300
Peter Kvitek2cd1a9b2023-01-31 19:34:45301// Incognito mode tests ------------------------------------------------------
302
Peter Kvitek71c320d2025-05-02 19:26:02303IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTest, StartNonIncognito) {
304 // HeadlessModeBrowserTest class is derived from InProcessBrowserTest which
305 // guarantees that tests are running with a unique user data dir, so expect to
306 // start in non incognito mode which is the default when user data dir is
307 // specified.
Peter Kvitek2cd1a9b2023-01-31 19:34:45308 EXPECT_FALSE(browser()->profile()->IsOffTheRecord());
309}
310
Peter Kvitek71c320d2025-05-02 19:26:02311class HeadlessModeBrowserTestWithIncognito : public HeadlessModeBrowserTest {
Peter Kvitek2cd1a9b2023-01-31 19:34:45312 public:
Peter Kvitek71c320d2025-05-02 19:26:02313 HeadlessModeBrowserTestWithIncognito() = default;
314 ~HeadlessModeBrowserTestWithIncognito() override = default;
Peter Kvitek2cd1a9b2023-01-31 19:34:45315
316 void SetUpCommandLine(base::CommandLine* command_line) override {
Peter Kvitek71c320d2025-05-02 19:26:02317 HeadlessModeBrowserTest::SetUpCommandLine(command_line);
Peter Kvitek2cd1a9b2023-01-31 19:34:45318 command_line->AppendSwitch(::switches::kIncognito);
319 }
320};
321
Peter Kvitek71c320d2025-05-02 19:26:02322IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTestWithIncognito,
323 StartWithIncognito) {
Peter Kvitek2cd1a9b2023-01-31 19:34:45324 // With user data dir and incognito expect to start in incognito mode.
325 EXPECT_TRUE(browser()->profile()->IsOffTheRecord());
326}
327
Peter Kvitekf6a06c62023-02-07 18:06:00328// Clipboard tests -----------------------------------------------------------
329
330IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTest, HeadlessClipboardInstalled) {
Peter Kvitek22202802023-09-22 21:07:34331 ui::Clipboard* clipboard = ui::ClipboardNonBacked::GetForCurrentThread();
Peter Kvitekf6a06c62023-02-07 18:06:00332 ASSERT_TRUE(clipboard);
333
334 ui::ClipboardBuffer buffer = ui::ClipboardBuffer::kCopyPaste;
335 ASSERT_TRUE(ui::Clipboard::IsSupportedClipboardBuffer(buffer));
336
337 // Expect sequence number to be incremented. This confirms that the headless
338 // clipboard implementation is being used.
339 int request_counter = GetSequenceNumberRequestCounterForTesting();
340 clipboard->GetSequenceNumber(buffer);
341 EXPECT_GT(GetSequenceNumberRequestCounterForTesting(), request_counter);
342}
343
344IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTest, HeadlessClipboardCopyPaste) {
345 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
346 ASSERT_TRUE(clipboard);
347
Peter Kvitek22202802023-09-22 21:07:34348 static const struct ClipboardBufferInfo {
349 ui::ClipboardBuffer buffer;
350 std::u16string paste_text;
351 } clipboard_buffers[] = {
352 {ui::ClipboardBuffer::kCopyPaste, u"kCopyPaste"},
353 {ui::ClipboardBuffer::kSelection, u"kSelection"},
354 {ui::ClipboardBuffer::kDrag, u"kDrag"},
355 };
Peter Kvitekf6a06c62023-02-07 18:06:00356
Peter Kvitek22202802023-09-22 21:07:34357 // Check basic write/read ops into each buffer type.
358 for (const auto& [buffer, paste_text] : clipboard_buffers) {
359 if (!ui::Clipboard::IsSupportedClipboardBuffer(buffer)) {
360 continue;
361 }
362 {
363 ui::ScopedClipboardWriter writer(buffer);
364 writer.WriteText(paste_text);
365 }
366 std::u16string copy_text;
367 clipboard->ReadText(buffer, /* data_dst = */ nullptr, &copy_text);
368 EXPECT_EQ(paste_text, copy_text);
369 }
Peter Kvitekf6a06c62023-02-07 18:06:00370
Peter Kvitek22202802023-09-22 21:07:34371 // Verify that different clipboard buffer data is independent.
372 for (const auto& [buffer, paste_text] : clipboard_buffers) {
373 if (!ui::Clipboard::IsSupportedClipboardBuffer(buffer)) {
374 continue;
375 }
376 std::u16string copy_text;
377 clipboard->ReadText(buffer, /* data_dst = */ nullptr, &copy_text);
378 EXPECT_EQ(paste_text, copy_text);
379 }
Peter Kvitekf6a06c62023-02-07 18:06:00380}
381
Peter Kvitekdbdb4d22023-12-01 00:39:53382// Bubble tests --------------------------------------------------------------
383
384class TestBubbleDelegate : public ui::DialogModelDelegate {
385 public:
386 TestBubbleDelegate() = default;
387 ~TestBubbleDelegate() override = default;
388
389 void OnOkButton() { dialog_model()->host()->Close(); }
390};
391
392Widget* ShowTestBubble(Browser* browser) {
393 views::View* anchor_view = BrowserView::GetBrowserViewForBrowser(browser)
394 ->toolbar_button_provider()
395 ->GetAppMenuButton();
396
397 auto bubble_delegate = std::make_unique<TestBubbleDelegate>();
398 TestBubbleDelegate* bubble_delegate_ptr = bubble_delegate.get();
399
400 ui::DialogModel::Builder dialog_builder(std::move(bubble_delegate));
Peter Boström8c07ba02023-12-19 21:02:43401 dialog_builder.SetTitle(u"Test bubble")
402 .AddParagraph(ui::DialogModelLabel(u"Test bubble text"))
403 .AddOkButton(base::BindOnce(&TestBubbleDelegate::OnOkButton,
404 base::Unretained(bubble_delegate_ptr)),
405 ui::DialogModel::Button::Params().SetLabel(u"OK"));
Peter Kvitekdbdb4d22023-12-01 00:39:53406
407 auto bubble = std::make_unique<views::BubbleDialogModelHost>(
408 dialog_builder.Build(), anchor_view, views::BubbleBorder::TOP_RIGHT);
409
410 Widget* widget = views::BubbleDialogDelegate::CreateBubble(std::move(bubble));
411 widget->Show();
412
413 return widget;
414}
415
416IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTest, HeadlessBubbleVisibility) {
Peter Kvitekdbdb4d22023-12-01 00:39:53417 Widget* bubble_widget = ShowTestBubble(browser());
Peter Kvitekdbdb4d22023-12-01 00:39:53418
419#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
420 // On Windows and Mac in headless mode we still have actual platform
421 // windows which are always hidden, so verify that they are not visible.
Peter Kvitekc39a59962024-01-08 23:22:16422 EXPECT_FALSE(test::IsPlatformWindowVisible(bubble_widget));
Peter Kvitekdbdb4d22023-12-01 00:39:53423#elif BUILDFLAG(IS_LINUX)
424 // On Linux headless mode uses Ozone/Headless where platform windows are not
425 // backed up by any real windows, so verify that their visibility state
426 // matches the widget's visibility state.
Peter Kvitekc39a59962024-01-08 23:22:16427 EXPECT_EQ(test::IsPlatformWindowVisible(bubble_widget),
428 bubble_widget->IsVisible());
Peter Kvitekdbdb4d22023-12-01 00:39:53429#else
430#error Unsupported platform
431#endif
432}
433
Peter Kvitekc39a59962024-01-08 23:22:16434IN_PROC_BROWSER_TEST_F(HeadlessModeBrowserTest, HeadlessBubbleSize) {
435 Widget* bubble_widget = ShowTestBubble(browser());
Peter Kvitekc39a59962024-01-08 23:22:16436 gfx::Rect bounds = test::GetPlatformWindowExpectedBounds(bubble_widget);
437 EXPECT_FALSE(bounds.IsEmpty());
438}
439
Peter Kvitek1034c08d2023-01-24 17:54:07440} // namespace
441
442} // namespace headless
443
Peter Kvitekd64628e2022-02-04 22:46:32444#endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)