Replace CreateClientControlledShellSurface With ShellSurfaceBuilder

This replaces all the occurrences of CreateClientControlledShellSurface
to ShellSurfaceBuilder to make the instantiation of
ClientControlledShellSurface simpler.

BUG=b:236939804
Test=exo_unittests

Change-Id: Ieda0566cb8036180349627be15efec02d550ab67
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3721951
Commit-Queue: Kazuki Takise <takise@chromium.org>
Reviewed-by: Mitsuru Oshima <oshima@chromium.org>
Auto-Submit: Kazuki Takise <takise@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1019941}
diff --git a/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc
index 01a391f..af7b0bd6 100644
--- a/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc
+++ b/chrome/browser/ash/arc/accessibility/accessibility_info_data_wrapper_unittest.cc
@@ -11,8 +11,9 @@
 #include "chrome/browser/ash/arc/accessibility/arc_accessibility_test_util.h"
 #include "chrome/browser/ash/arc/accessibility/arc_accessibility_util.h"
 #include "chrome/browser/ash/arc/accessibility/ax_tree_source_arc.h"
+#include "components/exo/client_controlled_shell_surface.h"
 #include "components/exo/surface.h"
-#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wm_helper_chromeos.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -63,18 +64,14 @@
  public:
   AccessibilityInfoDataWrapperTest() = default;
 
-  exo::test::ExoTestHelper exo_test_helper;
-
   std::unique_ptr<exo::WMHelper> wm_helper =
       std::make_unique<exo::WMHelperChromeOS>();
 };
 
 TEST_F(AccessibilityInfoDataWrapperTest, NonRootNodeBounds) {
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface =
-      exo_test_helper.CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 200, 200));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(10, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper root(&tree_source);
@@ -94,11 +91,9 @@
 TEST_F(AccessibilityInfoDataWrapperTest, RootNodeBounds) {
   UpdateDisplay("400x400");
 
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface =
-      exo_test_helper.CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 200, 200));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(10, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
@@ -114,11 +109,9 @@
 TEST_F(AccessibilityInfoDataWrapperTest, RootNodeBoundsOnExternalDisplay) {
   UpdateDisplay("400x400,500x500");
 
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface =
-      exo_test_helper.CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(410, 10, 200, 200));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(410, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
@@ -136,12 +129,10 @@
 
   // With default_scale_cancellation, Android has default (1x) scale factor.
   wm_helper->SetDefaultScaleCancellation(true);
-
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface = exo_test_helper.CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/true);
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 100, 100));  // DIP
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder()
+                           .SetGeometry(gfx::Rect(10, 10, 100, 100))
+                           .EnableDefaultScaleCancellation()
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
@@ -159,12 +150,9 @@
 
   // Without default_scale_cancellation, Android use the same (2x) scale factor.
   wm_helper->SetDefaultScaleCancellation(false);
-
-  auto surface = std::make_unique<exo::Surface>();
-  auto shell_surface = exo_test_helper.CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
-  shell_surface->SetGeometry(gfx::Rect(10, 10, 100, 100));  // DIP
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetGeometry(gfx::Rect(10, 10, 200, 200))
+                           .BuildClientControlledShellSurface();
 
   TestTreeSource tree_source(shell_surface->GetWidget()->GetNativeWindow());
   TestAccessibilityInfoDataWrapper data(&tree_source);
diff --git a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
index f09467a2..6134c53 100644
--- a/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
+++ b/chrome/browser/ash/arc/accessibility/arc_accessibility_helper_bridge_browsertest.cc
@@ -29,7 +29,7 @@
 #include "components/exo/shell_surface.h"
 #include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
-#include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wm_helper.h"
 #include "components/exo/wm_helper_chromeos.h"
 #include "components/viz/common/features.h"
@@ -47,12 +47,6 @@
 
 namespace {
 
-struct TestWindow {
-  std::unique_ptr<exo::Buffer> buffer;
-  std::unique_ptr<exo::Surface> surface;
-  std::unique_ptr<exo::ClientControlledShellSurface> shell_surface;
-};
-
 class MockAutomationEventRouter
     : public extensions::AutomationEventRouterInterface {
  public:
@@ -129,32 +123,15 @@
  protected:
   // Create and initialize a window for this test, i.e. an Arc++-specific
   // version of ExoTestHelper::CreateWindow.
-  TestWindow MakeTestArcWindow(std::string name) {
-    TestWindow ret = MakeNonArcTestWindow();
-
-    // Forcefully set task_id for each window.
-    ret.surface->SetApplicationId(name.c_str());
-
-    // CreateClientControlledShellSurface doesn't set AppType so do it here.
-    ret.shell_surface->GetWidget()->GetNativeWindow()->SetProperty(
-        aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP));
-
-    return ret;
+  std::unique_ptr<exo::ClientControlledShellSurface> MakeTestArcWindow(
+      std::string name) {
+    return exo::test::ShellSurfaceBuilder({640, 480})
+        .SetApplicationId(name)
+        .BuildClientControlledShellSurface();
   }
 
-  TestWindow MakeNonArcTestWindow() {
-    TestWindow ret;
-    exo::test::ExoTestHelper helper;
-
-    ret.surface = std::make_unique<exo::Surface>();
-    ret.buffer = std::make_unique<exo::Buffer>(
-        helper.CreateGpuMemoryBuffer(gfx::Size(640, 480)));
-    ret.shell_surface = helper.CreateClientControlledShellSurface(
-        ret.surface.get(), /*is_modal=*/false);
-    ret.surface->Attach(ret.buffer.get());
-    ret.surface->Commit();
-
-    return ret;
+  std::unique_ptr<exo::ShellSurface> MakeNonArcTestWindow() {
+    return exo::test::ShellSurfaceBuilder({640, 480}).BuildShellSurface();
   }
 
   std::unique_ptr<FakeAccessibilityHelperInstance>
@@ -168,21 +145,19 @@
             fake_accessibility_helper_instance_->filter_type());
   EXPECT_FALSE(fake_accessibility_helper_instance_->explore_by_touch_enabled());
 
-  TestWindow test_window_1 = MakeTestArcWindow("org.chromium.arc.1");
-  TestWindow test_window_2 = MakeTestArcWindow("org.chromium.arc.2");
+  auto shell_surface1 = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface2 = MakeTestArcWindow("org.chromium.arc.2");
 
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow());
-  ASSERT_EQ(test_window_1.shell_surface->GetWidget()->GetNativeWindow(),
+      shell_surface1->GetWidget()->GetNativeWindow());
+  ASSERT_EQ(shell_surface1->GetWidget()->GetNativeWindow(),
             activation_client->GetActiveWindow());
-  ASSERT_FALSE(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
-  ASSERT_FALSE(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  ASSERT_FALSE(shell_surface1->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
+  ASSERT_FALSE(shell_surface2->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
   AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
@@ -191,14 +166,13 @@
             fake_accessibility_helper_instance_->filter_type());
 
   // Use ChromeVox by default. Touch exploration pass through is still false.
-  EXPECT_FALSE(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  EXPECT_FALSE(shell_surface1->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
   ArcAccessibilityHelperBridge* bridge =
       ArcAccessibilityHelperBridge::GetForBrowserContext(browser()->profile());
 
-  // Enable TalkBack. Touch exploration pass through of test_window_1
+  // Enable TalkBack. Touch exploration pass through of shell_surface1
   // (current active window) would become true.
   bridge->SetNativeChromeVoxArcSupport(
       false,
@@ -206,36 +180,34 @@
           [](extensions::api::accessibility_private::SetNativeChromeVoxResponse
                  response) {}));
 
-  EXPECT_TRUE(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  EXPECT_TRUE(shell_surface1->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
-  // Activate test_window_2 and confirm that it still be false.
+  // Activate shell_surface2 and confirm that it still be false.
   activation_client->ActivateWindow(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow());
-  ASSERT_EQ(test_window_2.shell_surface->GetWidget()->GetNativeWindow(),
+      shell_surface2->GetWidget()->GetNativeWindow());
+  ASSERT_EQ(shell_surface2->GetWidget()->GetNativeWindow(),
             activation_client->GetActiveWindow());
-  EXPECT_FALSE(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow()->GetProperty(
-          aura::client::kAccessibilityTouchExplorationPassThrough));
+  EXPECT_FALSE(shell_surface2->GetWidget()->GetNativeWindow()->GetProperty(
+      aura::client::kAccessibilityTouchExplorationPassThrough));
 
   EXPECT_TRUE(fake_accessibility_helper_instance_->explore_by_touch_enabled());
 }
 
 IN_PROC_BROWSER_TEST_F(ArcAccessibilityHelperBridgeBrowserTest,
                        RequestTreeSyncOnWindowIdChange) {
-  TestWindow test_window_1 = MakeTestArcWindow("org.chromium.arc.1");
-  TestWindow test_window_2 = MakeTestArcWindow("org.chromium.arc.2");
+  auto shell_surface1 = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface2 = MakeTestArcWindow("org.chromium.arc.2");
 
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow());
+      shell_surface1->GetWidget()->GetNativeWindow());
 
   AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
   exo::SetShellClientAccessibilityId(
-      test_window_1.shell_surface->GetWidget()->GetNativeWindow(), 10);
+      shell_surface1->GetWidget()->GetNativeWindow(), 10);
 
   EXPECT_TRUE(
       fake_accessibility_helper_instance_->last_requested_tree_window_key()
@@ -245,14 +217,14 @@
                ->get_window_id());
 
   exo::SetShellClientAccessibilityId(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow(), 20);
+      shell_surface2->GetWidget()->GetNativeWindow(), 20);
 
   EXPECT_EQ(
       20U, fake_accessibility_helper_instance_->last_requested_tree_window_key()
                ->get_window_id());
 
   exo::SetShellClientAccessibilityId(
-      test_window_2.shell_surface->GetWidget()->GetNativeWindow(), 21);
+      shell_surface2->GetWidget()->GetNativeWindow(), 21);
 
   EXPECT_EQ(
       21U, fake_accessibility_helper_instance_->last_requested_tree_window_key()
@@ -280,11 +252,11 @@
                        FocusHighlight) {
   AccessibilityManager::Get()->SetFocusHighlightEnabled(true);
 
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
+      shell_surface->GetWidget()->GetNativeWindow());
 
   const gfx::Rect node_rect1 = gfx::Rect(50, 50, 50, 50);
 
@@ -345,7 +317,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ArcAccessibilityHelperBridgeBrowserTest, PerformAction) {
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   AccessibilityManager::Get()->EnableSpokenFeedback(true);
 
   ArcAccessibilityHelperBridge* bridge =
@@ -385,7 +357,7 @@
 
 IN_PROC_BROWSER_TEST_F(ArcAccessibilityHelperBridgeBrowserTest,
                        GetTextLocation) {
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   AccessibilityManager::Get()->SetSelectToSpeakEnabled(true);
 
   ArcAccessibilityHelperBridge* bridge =
@@ -432,16 +404,16 @@
   base::HistogramTester histogram_tester;
 
   // Prepare ARC and non-ARC windows
-  TestWindow test_window = MakeTestArcWindow("org.chromium.arc.1");
+  auto arc_shell_surface = MakeTestArcWindow("org.chromium.arc.1");
   wm::ActivationClient* activation_client =
       ash::Shell::Get()->activation_client();
 
-  TestWindow non_arc_window = MakeNonArcTestWindow();
+  auto non_arc_shell_surface = MakeNonArcTestWindow();
 
   // Turn on and off a feature while an ARC window is focused and then it will
   // be counted.
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
+      arc_shell_surface->GetWidget()->GetNativeWindow());
   histogram_tester.ExpectBucketCount("Arc.Accessibility.WindowCount", 1, 0);
   ash::MagnificationManager::Get()->SetMagnifierEnabled(true);
   histogram_tester.ExpectBucketCount("Arc.Accessibility.WindowCount", 1, 1);
@@ -456,23 +428,23 @@
   // Focus on an ARC window and focus on a non-ARC window while a feature is on
   // and then it will be counted.
   activation_client->ActivateWindow(
-      non_arc_window.shell_surface->GetWidget()->GetNativeWindow());
+      non_arc_shell_surface->GetWidget()->GetNativeWindow());
   ash::MagnificationManager::Get()->SetMagnifierEnabled(true);
   histogram_tester.ExpectBucketCount("Arc.Accessibility.WindowCount", 1, 2);
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
+      arc_shell_surface->GetWidget()->GetNativeWindow());
   histogram_tester.ExpectTotalCount(
       "Arc.Accessibility.ActiveTime.FullscreenMagnifier", 1);
   activation_client->ActivateWindow(
-      non_arc_window.shell_surface->GetWidget()->GetNativeWindow());
+      non_arc_shell_surface->GetWidget()->GetNativeWindow());
   histogram_tester.ExpectTotalCount(
       "Arc.Accessibility.ActiveTime.FullscreenMagnifier", 2);
 
   // Close the focused ARC window while a feature is on and then it will be
   // counted.
   activation_client->ActivateWindow(
-      test_window.shell_surface->GetWidget()->GetNativeWindow());
-  test_window.surface.reset();
+      arc_shell_surface->GetWidget()->GetNativeWindow());
+  arc_shell_surface.reset();
   histogram_tester.ExpectTotalCount(
       "Arc.Accessibility.ActiveTime.FullscreenMagnifier", 3);
 
diff --git a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc
index 134addf..a1ed859 100644
--- a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc
+++ b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.cc
@@ -5,6 +5,7 @@
 #include "chrome/browser/ash/arc/input_overlay/test/arc_test_window.h"
 #include "ash/constants/app_types.h"
 #include "ash/public/cpp/window_properties.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/display/screen.h"
 
@@ -15,22 +16,14 @@
 ArcTestWindow::ArcTestWindow(exo::test::ExoTestHelper* helper,
                              aura::Window* root,
                              const std::string& package_name) {
-  surface_ = std::make_unique<exo::Surface>();
-  buffer_ = std::make_unique<exo::Buffer>(
-      helper->CreateGpuMemoryBuffer(gfx::Size(100, 100)));
-  shell_surface_ =
-      helper->CreateClientControlledShellSurface(surface_.get(), false);
-  surface_->Attach(buffer_.get());
-
+  shell_surface_ = exo::test::ShellSurfaceBuilder({100, 100})
+                       .SetApplicationId(package_name.c_str())
+                       .BuildClientControlledShellSurface();
   auto display_id =
       display::Screen::GetScreen()->GetDisplayNearestWindow(root).id();
   shell_surface_->SetBounds(display_id, gfx::Rect(10, 10, 100, 100));
+  surface_ = shell_surface_->root_surface();
   surface_->Commit();
-  shell_surface_->GetWidget()->Show();
-  shell_surface_->GetWidget()->Activate();
-  surface_->SetApplicationId(package_name.c_str());
-  shell_surface_->GetWidget()->GetNativeWindow()->SetProperty(
-      aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP));
   shell_surface_->GetWidget()->GetNativeWindow()->SetProperty(
       ash::kArcPackageNameKey, package_name);
 }
diff --git a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h
index 26afa72e..5f644ae 100644
--- a/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h
+++ b/chrome/browser/ash/arc/input_overlay/test/arc_test_window.h
@@ -29,8 +29,7 @@
   void SetBounds(display::Display& display, gfx::Rect bounds);
 
  private:
-  std::unique_ptr<exo::Buffer> buffer_;
-  std::unique_ptr<exo::Surface> surface_;
+  exo::Surface* surface_;
   std::unique_ptr<exo::ClientControlledShellSurface> shell_surface_;
 };
 
diff --git a/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc b/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc
index 1b61065..9ba9772 100644
--- a/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc
+++ b/chrome/browser/ui/ash/shelf/arc_app_shelf_browsertest.cc
@@ -710,12 +710,12 @@
                                         kTestLogicalWindow};
   // Create windows that will be associated with the tasks. Without this,
   // GetAppMenuItems() will only return an empty list.
-  std::vector<std::unique_ptr<exo::ShellSurface>> test_windows;
+  std::vector<std::unique_ptr<exo::ClientControlledShellSurface>> test_windows;
 
   for (int task_id = 1; task_id <= 7; task_id++) {
     test_windows.push_back(exo::test::ShellSurfaceBuilder({640, 480})
                                .SetCentered()
-                               .BuildShellSurface());
+                               .BuildClientControlledShellSurface());
 
     aura::Window* aura_window =
         test_windows[task_id - 1]->GetWidget()->GetNativeWindow();
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc
index 85392bc..0166279 100644
--- a/components/exo/client_controlled_shell_surface_unittest.cc
+++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -52,6 +52,7 @@
 #include "components/exo/surface.h"
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/test/exo_test_helper.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wm_helper.h"
 #include "third_party/skia/include/utils/SkNoDrawCanvas.h"
 #include "ui/aura/client/aura_constants.h"
@@ -126,16 +127,8 @@
 }  // namespace
 
 TEST_F(ClientControlledShellSurfaceTest, SetPinned) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
 
   shell_surface->SetPinned(chromeos::WindowPinType::kTrustedPinned);
   EXPECT_TRUE(IsWidgetPinned(shell_surface->GetWidget()));
@@ -151,14 +144,8 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetSystemUiVisibility) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
 
   shell_surface->SetSystemUiVisibility(true);
   EXPECT_TRUE(
@@ -172,15 +159,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetTopInset) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ASSERT_TRUE(window);
@@ -191,36 +172,12 @@
   EXPECT_EQ(top_inset_height, window->GetProperty(aura::client::kTopViewInset));
 }
 
-TEST_F(ClientControlledShellSurfaceTest, ModalWindowDefaultActive) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
-
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(10, 10, 100, 100));
-  ASSERT_FALSE(shell_surface->GetWidget());
-  shell_surface->SetSystemModal(true);
-  surface->Commit();
-
-  EXPECT_TRUE(ash::Shell::IsSystemModalWindowOpen());
-  EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
-}
-
 TEST_F(ClientControlledShellSurfaceTest, UpdateModalWindow) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/true);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetUseSystemModalContainer()
+                           .SetInputRegion(cc::Region())
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(ash::Shell::IsSystemModalWindowOpen());
   EXPECT_FALSE(shell_surface->GetWidget()->IsActive());
 
@@ -232,7 +189,7 @@
       new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
   child->Attach(child_buffer.get());
   std::unique_ptr<SubSurface> sub_surface(
-      display->CreateSubSurface(child.get(), surface.get()));
+      display->CreateSubSurface(child.get(), surface));
   surface->SetSubSurfacePosition(child.get(), gfx::PointF(10, 10));
   child->Commit();
   surface->Commit();
@@ -278,14 +235,12 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        ModalWindowSetSystemModalBeforeCommit) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/true);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetUseSystemModalContainer()
+                           .SetInputRegion(cc::Region())
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Set SetSystemModal before any commit happens. Widget is not created at
   // this time.
@@ -306,33 +261,19 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        NonSystemModalContainerCantChangeModality) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false);
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(cc::Region());
-
-  shell_surface->SetSystemModal(true);
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetInputRegion(cc::Region())
+                           .EnableSystemModal()
+                           .BuildClientControlledShellSurface();
   // It is expected that a non system modal container is unable to set a system
   // modal.
   EXPECT_FALSE(ash::Shell::IsSystemModalWindowOpen());
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SurfaceShadow) {
-  gfx::Size buffer_size(128, 128);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({128, 128})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
 
   // 1) Initial state, no shadow (SurfaceFrameType is NONE);
@@ -340,12 +281,8 @@
   std::unique_ptr<Display> display(new Display);
 
   // 2) Just creating a sub surface won't create a shadow.
-  std::unique_ptr<Surface> child = display->CreateSurface();
-  std::unique_ptr<Buffer> child_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  child->Attach(child_buffer.get());
-  std::unique_ptr<SubSurface> sub_surface(
-      display->CreateSubSurface(child.get(), surface.get()));
+  auto* child =
+      test::ShellSurfaceBuilder::AddChildSurface(surface, {0, 0, 128, 128});
   surface->Commit();
 
   EXPECT_FALSE(wm::ShadowController::GetShadowForWindow(window));
@@ -394,20 +331,13 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ShadowWithStateChange) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Postion the widget at 10,10 so that we get non zero offset.
   const gfx::Size content_size(100, 100);
-  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
+  // Position the widget at 10,10 so that we get non zero offset.
+  auto shell_surface = exo::test::ShellSurfaceBuilder(content_size)
+                           .SetGeometry({gfx::Point(10, 10), content_size})
+                           .SetFrame(SurfaceFrameType::SHADOW)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // In parent coordinates.
   const gfx::Rect shadow_bounds(gfx::Point(-10, -10), content_size);
@@ -448,21 +378,13 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ShadowWithTransform) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Postion the widget at 10,10 so that we get non zero offset.
   const gfx::Size content_size(100, 100);
-  const gfx::Rect original_bounds(gfx::Point(10, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
-
+  // Position the widget at 10,10 so that we get non zero offset.
+  auto shell_surface = exo::test::ShellSurfaceBuilder(content_size)
+                           .SetGeometry({gfx::Point(10, 10), content_size})
+                           .SetFrame(SurfaceFrameType::SHADOW)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ui::Shadow* shadow = wm::ShadowController::GetShadowForWindow(window);
 
@@ -480,19 +402,12 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ShadowStartMaximized) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::SHADOW);
-  surface->Commit();
-
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetFrame(SurfaceFrameType::SHADOW)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   views::Widget* widget = shell_surface->GetWidget();
   aura::Window* window = widget->GetNativeWindow();
 
@@ -516,30 +431,24 @@
 TEST_F(ClientControlledShellSurfaceTest, Frame) {
   UpdateDisplay("800x600");
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
-  display::DisplayManager* display_manager =
-      ash::Shell::Get()->display_manager();
-
-  std::unique_ptr<Surface> surface(new Surface);
-
   gfx::Rect client_bounds(20, 50, 300, 200);
   gfx::Rect fullscreen_bounds(0, 0, 800, 600);
   // The window bounds is the client bounds + frame size.
   gfx::Rect normal_window_bounds(20, 18, 300, 232);
 
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({client_bounds.size()})
+                           .SetGeometry(client_bounds)
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   shell_surface->SetSystemUiVisibility(true);  // disable shelf.
-
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(client_bounds);
-  surface->SetFrame(SurfaceFrameType::NORMAL);
   surface->Commit();
 
+  int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
+  display::DisplayManager* display_manager =
+      ash::Shell::Get()->display_manager();
+
   views::Widget* widget = shell_surface->GetWidget();
   ash::NonClientFrameViewAsh* frame_view =
       static_cast<ash::NonClientFrameViewAsh*>(
@@ -681,20 +590,14 @@
 TEST_F(ClientControlledShellSurfaceTest, NoSynthesizedEventOnFrameChange) {
   UpdateDisplay("800x600");
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
-  std::unique_ptr<Surface> surface = std::make_unique<Surface>();
-
-  gfx::Rect fullscreen_bounds(0, 0, 800, 600);
-
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetWindowState(chromeos::WindowStateType::kNormal)
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Maximized
+  gfx::Rect fullscreen_bounds(0, 0, 800, 600);
   shell_surface->SetMaximized();
   shell_surface->SetGeometry(fullscreen_bounds);
   surface->Commit();
@@ -721,13 +624,10 @@
        NoSynthesizedEventsForPixelCoordinates) {
   TestEventHandler event_handler;
 
-  gfx::Size buffer_size(400, 400);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  auto surface = std::make_unique<Surface>();
-  surface->Attach(buffer.get());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({400, 400})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   // Pixel coordinates add a transform to the underlying layer.
   shell_surface->set_client_submits_surfaces_in_pixel_coordinates(true);
 
@@ -760,24 +660,21 @@
 
 TEST_F(ClientControlledShellSurfaceTest, CompositorLockInRotation) {
   UpdateDisplay("800x600");
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+
   ash::Shell* shell = ash::Shell::Get();
   shell->tablet_mode_controller()->SetEnabledForTest(true);
-
-  // Start in maximized.
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
-  surface->Commit();
-
   gfx::Rect maximum_bounds =
       display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
-  shell_surface->SetGeometry(maximum_bounds);
+
+  // Start in maximized.
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({800, 600})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetGeometry(maximum_bounds)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
   shell_surface->SetOrientation(Orientation::LANDSCAPE);
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   ui::Compositor* compositor =
@@ -800,15 +697,8 @@
 // key while shell surface is active.
 TEST_F(ClientControlledShellSurfaceTest,
        KeyboardNavigationWithUnifiedSystemTray) {
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({800, 600})
+                           .BuildClientControlledShellSurface();
 
   EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
 
@@ -832,15 +722,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, Maximize) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(HasBackdrop());
   shell_surface->SetMaximized();
   EXPECT_FALSE(HasBackdrop());
@@ -876,15 +760,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, Restore) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(HasBackdrop());
   // Note: Remove contents to avoid issues with maximize animations in tests.
   shell_surface->SetMaximized();
@@ -899,16 +777,11 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetFullscreen) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  shell_surface->SetFullscreen(true);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetWindowState(chromeos::WindowStateType::kFullscreen)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_TRUE(HasBackdrop());
 
   // We always show backdrop becaues the window can be cropped.
@@ -933,15 +806,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ToggleFullscreen) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(HasBackdrop());
 
   shell_surface->SetMaximized();
@@ -968,16 +835,9 @@
   int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
   display::SetInternalDisplayIds({display_id});
 
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), false /* is_modal */,
-      true /* default_scale_cancelation */));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .EnableDefaultScaleCancellation()
+                           .BuildClientControlledShellSurface();
   gfx::Transform transform;
   transform.Scale(1.0 / scale, 1.0 / scale);
 
@@ -1014,15 +874,8 @@
   display_manager->OnNativeDisplaysChanged(display_info_list);
   display_manager->UpdateInternalManagedDisplayModeListForTest();
 
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .BuildClientControlledShellSurface();
 
   gfx::Transform transform;
   transform.Scale(1.0 / scale, 1.0 / scale);
@@ -1033,17 +886,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, MouseAndTouchTarget) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-
-  const gfx::Rect original_bounds(0, 0, 256, 256);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetGeometry({0, 0, 256, 256})
+                           .BuildClientControlledShellSurface();
 
   EXPECT_TRUE(shell_surface->CanResize());
 
@@ -1083,15 +928,9 @@
 // The shell surface in SystemModal container should be unresizable.
 TEST_F(ClientControlledShellSurfaceTest,
        ShellSurfaceInSystemModalIsUnresizable) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetUseSystemModalContainer()
+                           .BuildClientControlledShellSurface();
 
   EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
 }
@@ -1099,20 +938,12 @@
 // The shell surface in SystemModal container should be a target
 // at the edge.
 TEST_F(ClientControlledShellSurfaceTest, ShellSurfaceInSystemModalHitTest) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
   display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
-
-  gfx::Size desktop_size(640, 480);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(desktop_size)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(0, 0, 0, 0));
-  shell_surface->SetGeometry(display.bounds());
-  surface->Commit();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 480})
+                           .SetUseSystemModalContainer()
+                           .SetGeometry(display.bounds())
+                           .SetInputRegion(gfx::Rect(0, 0, 0, 0))
+                           .BuildClientControlledShellSurface();
   EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   aura::Window* root = window->GetRootWindow();
@@ -1130,18 +961,11 @@
   UpdateDisplay("807x607");
   ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(true);
 
-  const gfx::Size buffer_size(800, 600);
-  std::unique_ptr<Buffer> buffer1(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface1(new Surface);
   auto shell_surface1 =
-      exo_test_helper()->CreateClientControlledShellSurface(surface1.get());
-  // Start in maximized.
-  shell_surface1->SetGeometry(gfx::Rect(0, 0, 800, 600));
-  shell_surface1->SetMaximized();
-  surface1->Attach(buffer1.get());
-  surface1->Commit();
-
+      exo::test::ShellSurfaceBuilder({800, 600})
+          .SetGeometry({0, 0, 800, 600})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .BuildClientControlledShellSurface();
   aura::Window* window1 = shell_surface1->GetWidget()->GetNativeWindow();
   ash::WindowState* window_state1 = ash::WindowState::Get(window1);
   ash::ClientControlledState* state1 = static_cast<ash::ClientControlledState*>(
@@ -1181,17 +1005,10 @@
 // The shell surface in SystemModal container should not become target
 // at the edge.
 TEST_F(ClientControlledShellSurfaceTest, ClientIniatedResize) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
   display::Display display = display::Screen::GetScreen()->GetPrimaryDisplay();
-
-  gfx::Size window_size(100, 100);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
-  surface->Attach(desktop_buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(window_size));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({100, 100})
+                           .SetGeometry(gfx::Rect({0, 0, 100, 100}))
+                           .BuildClientControlledShellSurface();
   EXPECT_TRUE(shell_surface->GetWidget()->widget_delegate()->CanResize());
   shell_surface->StartDrag(HTTOP, gfx::PointF(0, 0));
 
@@ -1217,16 +1034,15 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, ResizabilityAndSizeConstraints) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetMinimumSize(gfx::Size(0, 0));
-  shell_surface->SetMaximumSize(gfx::Size(0, 0));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder()
+                           .SetMinimumSize(gfx::Size(0, 0))
+                           .SetMaximumSize(gfx::Size(0, 0))
+                           .BuildClientControlledShellSurface();
   EXPECT_FALSE(shell_surface->GetWidget()->widget_delegate()->CanResize());
 
   shell_surface->SetMinimumSize(gfx::Size(400, 400));
   shell_surface->SetMaximumSize(gfx::Size(0, 0));
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
   EXPECT_TRUE(shell_surface->GetWidget()->widget_delegate()->CanResize());
 
@@ -1284,17 +1100,9 @@
 // Test that when a shell surface is destroyed during its dragging, its window
 // delegate should be reset properly.
 TEST_F(ClientControlledShellSurfaceTest, CloseWindowWhenDraggingTest) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  const gfx::Rect original_bounds(0, 0, 256, 256);
-  shell_surface->SetGeometry(original_bounds);
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetGeometry({0, 0, 256, 256})
+                           .BuildClientControlledShellSurface();
 
   // Press on the edge of the window and start dragging.
   gfx::Point touch_location(256, 150);
@@ -1362,16 +1170,13 @@
   UpdateDisplay("800x600");
   ash::Shell* shell = ash::Shell::Get();
   shell->tablet_mode_controller()->SetEnabledForTest(true);
-  std::unique_ptr<Surface> surface(new Surface());
-  const gfx::Size window_size(800, 552);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
+
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(window_size));
-  surface->Commit();
+      exo::test::ShellSurfaceBuilder({800, 552})
+          .SetGeometry({0, 0, 800, 552})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ASSERT_TRUE(ash::WindowState::Get(window)->IsMaximized());
@@ -1499,21 +1304,16 @@
 TEST_F(ClientControlledShellSurfaceDisplayTest, MoveToAnotherDisplayByDrag) {
   UpdateDisplay("800x600,800x600");
   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
 
-  gfx::Size window_size(200, 200);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
-  surface->Attach(desktop_buffer.get());
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
   gfx::Rect initial_bounds(-150, 10, 200, 200);
   shell_surface->SetBounds(primary_display.id(), initial_bounds);
   surface->Commit();
-  shell_surface->GetWidget()->Show();
 
   EXPECT_EQ(initial_bounds,
             shell_surface->GetWidget()->GetWindowBoundsInScreen());
@@ -1560,14 +1360,9 @@
        MoveToAnotherDisplayByShortcut) {
   UpdateDisplay("400x600,800x600*2");
   aura::Window::Windows root_windows = ash::Shell::GetAllRootWindows();
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  gfx::Size window_size(200, 200);
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(window_size)));
-  surface->Attach(desktop_buffer.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({200, 200})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
@@ -1615,15 +1410,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, CaptionButtonModel) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  surface->Attach(desktop_buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(0, 0, 64, 64));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(gfx::Rect(0, 0, 64, 64))
+                           .BuildClientControlledShellSurface();
 
   constexpr views::CaptionButtonIcon kAllButtons[] = {
       views::CAPTION_BUTTON_ICON_MINIMIZE,
@@ -1686,14 +1475,9 @@
 // should still be set (for overview mode, accessibility, etc.). When the debug
 // text is set, the window frame should paint it.
 TEST_F(ClientControlledShellSurfaceTest, SetExtraTitle) {
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(640, 64))));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({640, 64})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   const std::u16string window_title(u"title");
   shell_surface->SetTitle(window_title);
@@ -1737,19 +1521,14 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, WideFrame) {
-  std::unique_ptr<Surface> surface(new Surface);
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(0, 0, 64, 64));
-  shell_surface->SetGeometry(gfx::Rect(100, 0, 64, 64));
-  shell_surface->SetMaximized();
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
-
+      exo::test::ShellSurfaceBuilder({64, 64})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetGeometry(gfx::Rect(100, 0, 64, 64))
+          .SetInputRegion(gfx::Rect(0, 0, 64, 64))
+          .SetFrame(SurfaceFrameType::NORMAL)
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ash::Shelf* shelf = ash::Shelf::ForWindow(window);
   shelf->SetAlignment(ash::ShelfAlignment::kLeft);
@@ -1891,16 +1670,12 @@
 
 // Tests that a WideFrameView is created for an unparented ARC task and that the
 TEST_F(ClientControlledShellSurfaceTest, NoFrameOnModalContainer) {
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get(),
-                                                            /*is_modal=*/true);
-
-  std::unique_ptr<Buffer> desktop_buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  surface->Attach(desktop_buffer.get());
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetUseSystemModalContainer()
+                           .SetGeometry(gfx::Rect(100, 0, 64, 64))
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   EXPECT_FALSE(shell_surface->frame_enabled());
   surface->SetFrame(SurfaceFrameType::AUTOHIDE);
   surface->Commit();
@@ -1910,22 +1685,13 @@
 TEST_F(ClientControlledShellSurfaceTest,
        SetGeometryReparentsToDisplayOnFirstCommit) {
   UpdateDisplay("100x200,100x200");
-
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
   const auto* screen = display::Screen::GetScreen();
 
   {
-    std::unique_ptr<Surface> surface(new Surface);
-    auto shell_surface =
-        exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
     gfx::Rect geometry(16, 16, 32, 32);
-    shell_surface->SetGeometry(geometry);
-    surface->Attach(buffer.get());
-    surface->Commit();
+    auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                             .SetGeometry(geometry)
+                             .BuildClientControlledShellSurface();
     EXPECT_EQ(geometry, shell_surface->GetWidget()->GetWindowBoundsInScreen());
 
     display::Display primary_display = screen->GetPrimaryDisplay();
@@ -1935,14 +1701,10 @@
   }
 
   {
-    std::unique_ptr<Surface> surface(new Surface);
-    auto shell_surface =
-        exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
     gfx::Rect geometry(116, 16, 32, 32);
-    shell_surface->SetGeometry(geometry);
-    surface->Attach(buffer.get());
-    surface->Commit();
+    auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                             .SetGeometry(geometry)
+                             .BuildClientControlledShellSurface();
     EXPECT_EQ(geometry, shell_surface->GetWidget()->GetWindowBoundsInScreen());
 
     auto root_windows = ash::Shell::GetAllRootWindows();
@@ -1957,22 +1719,16 @@
 TEST_F(ClientControlledShellSurfaceTest, SetBoundsReparentsToDisplay) {
   UpdateDisplay("100x200,100x200");
 
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
   const auto* screen = display::Screen::GetScreen();
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  gfx::Rect geometry(16, 16, 32, 32);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(geometry)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   display::Display primary_display = screen->GetPrimaryDisplay();
-  gfx::Rect geometry(16, 16, 32, 32);
-
   // Move to primary display with bounds inside display.
   shell_surface->SetBounds(primary_display.id(), geometry);
-  surface->Attach(buffer.get());
   surface->Commit();
   EXPECT_EQ(geometry, shell_surface->GetWidget()->GetWindowBoundsInScreen());
 
@@ -2043,9 +1799,12 @@
     {
       // Set display id, bounds origin, bounds size at the same time via
       // SetBounds method.
-      std::unique_ptr<Surface> surface(new Surface);
-      auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
-          surface.get(), /*is_modal=*/false, default_scale_cancellation));
+      auto builder = exo::test::ShellSurfaceBuilder();
+      if (default_scale_cancellation)
+        builder.EnableDefaultScaleCancellation();
+      auto shell_surface =
+          builder.SetNoCommit().BuildClientControlledShellSurface();
+      auto* surface = shell_surface->root_surface();
 
       // When display doesn't change, scale stays the same
       shell_surface->SetScale(kOriginalScale);
@@ -2077,9 +1836,12 @@
       // method, and set bounds size separately.
       const auto bounds_to_set =
           default_scale_cancellation ? bounds_dp : bounds_px_for_4x;
-      std::unique_ptr<Surface> surface(new Surface);
-      auto shell_surface(exo_test_helper()->CreateClientControlledShellSurface(
-          surface.get(), /*is_modal=*/false, default_scale_cancellation));
+      auto builder = exo::test::ShellSurfaceBuilder();
+      if (default_scale_cancellation)
+        builder.EnableDefaultScaleCancellation();
+      auto shell_surface =
+          builder.SetNoCommit().BuildClientControlledShellSurface();
+      auto* surface = shell_surface->root_surface();
 
       shell_surface->SetScale(kOriginalScale);
       shell_surface->SetBoundsOrigin(primary_display_id,
@@ -2103,16 +1865,10 @@
   ash::ScreenOrientationController* controller =
       ash::Shell::Get()->screen_orientation_controller();
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  shell_surface->SetMaximized();
-  surface->Commit();
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .BuildClientControlledShellSurface();
 
   shell_surface->SetOrientationLock(
       chromeos::OrientationType::kLandscapePrimary);
@@ -2128,17 +1884,13 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetClientAccessibilityId) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   EXPECT_FALSE(shell_surface->GetWidget());
   shell_surface->SetClientAccessibilityId(0);
-
-  surface->Attach(buffer.get());
   surface->Commit();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   EXPECT_EQ(0, *GetShellClientAccessibilityId(window));
@@ -2152,18 +1904,14 @@
 // Tests adjust bounds locally should also request remote client bounds update.
 TEST_F(ClientControlledShellSurfaceTest, AdjustBoundsLocally) {
   UpdateDisplay("800x600");
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64))));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  gfx::Rect client_bounds(900, 0, 200, 300);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(client_bounds)
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  gfx::Rect client_bounds(900, 0, 200, 300);
-  shell_surface->SetGeometry(client_bounds);
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   views::Widget* widget = shell_surface->GetWidget();
@@ -2179,16 +1927,11 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SnappedInTabletMode) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* window = shell_surface->GetWidget()->GetNativeWindow();
   auto* window_state = ash::WindowState::Get(window);
 
@@ -2209,15 +1952,9 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, PipWindowCannotBeActivated) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   EXPECT_TRUE(shell_surface->GetWidget()->IsActive());
   EXPECT_TRUE(shell_surface->GetWidget()->CanActivate());
@@ -2239,15 +1976,11 @@
 
 TEST_F(ClientControlledShellSurfaceDisplayTest,
        NoBoundsChangeEventInMinimized) {
-  gfx::Size buffer_size(100, 100);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Commit();
+  gfx::Rect client_bounds(100, 100);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
@@ -2303,18 +2036,17 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, SetPipWindowBoundsAnimates) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
   shell_surface->GetWidget()->Show();
+  auto* surface = shell_surface->root_surface();
+
+  // Making an extra commit may set the next bounds change animation type
+  // wrongly.
+  surface->Commit();
 
   ui::ScopedAnimationDurationScaleMode animation_scale_mode(
       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION);
@@ -2327,18 +2059,11 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, PipWindowDragDoesNotAnimate) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(client_bounds.size())
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   EXPECT_EQ(gfx::Rect(8, 8, 256, 256), window->layer()->GetTargetBounds());
@@ -2355,18 +2080,12 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        PipWindowDragDoesNotAnimateWithExtraCommit) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  shell_surface->SetGeometry(gfx::Rect(buffer_size));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
+  gfx::Rect client_bounds(256, 256);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({client_bounds.size()})
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(client_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Making an extra commit may set the next bounds change animation type
   // wrongly.
@@ -2395,19 +2114,10 @@
   EXPECT_FALSE(split_view_controller->InSplitViewMode());
 
   // Create a PIP window:
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto window_left = CreateTestWindow();
   auto window_right = CreateTestWindow();
 
@@ -2432,19 +2142,10 @@
   EXPECT_FALSE(split_view_controller->InSplitViewMode());
 
   // Create a PIP window:
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-  shell_surface->SetPip();
-  surface->Commit();
-  shell_surface->GetWidget()->Show();
-
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto window_left = CreateTestWindow();
   auto window_right = CreateTestWindow();
 
@@ -2478,42 +2179,29 @@
 };
 
 TEST_F(ClientControlledShellSurfaceTest, DoNotReplayWindowStateRequest) {
-  gfx::Size buffer_size(64, 64);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
+      exo::test::ShellSurfaceBuilder({64, 64})
+          .SetWindowState(chromeos::WindowStateType::kMinimized)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   shell_surface->set_delegate(
       std::make_unique<NoStateChangeDelegate>(shell_surface.get()));
-
-  shell_surface->SetMinimized();
-  surface->Attach(buffer.get());
   surface->Commit();
 }
 
 TEST_F(ClientControlledShellSurfaceDisplayTest,
        RequestBoundsChangeOnceWithStateTransition) {
-  gfx::Size buffer_size(64, 64);
-  auto buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(buffer_size));
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  auto* widget = shell_surface->GetWidget();
-  const gfx::Rect original_bounds(gfx::Point(20, 20), buffer_size);
-  shell_surface->SetGeometry(original_bounds);
-  widget->Restore();
-  surface->Commit();
+  constexpr gfx::Size buffer_size(64, 64);
+  constexpr gfx::Rect original_bounds({20, 20}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kNormal)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-
   shell_surface->SetPip();
   surface->Commit();
 
@@ -2523,25 +2211,17 @@
 TEST_F(ClientControlledShellSurfaceTest,
        DoNotSavePipBoundsAcrossMultiplePipTransition) {
   // Create a PIP window:
-  const gfx::Size content_size(100, 100);
-  auto buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(content_size));
-
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  constexpr gfx::Size buffer_size(100, 100);
+  constexpr gfx::Rect original_bounds({8, 10}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
-
-  const gfx::Rect original_bounds(gfx::Point(8, 10), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  shell_surface->SetPip();
-  surface->Commit();
   EXPECT_EQ(gfx::Rect(8, 10, 100, 100), window->bounds());
-  shell_surface->GetWidget()->Show();
 
-  const gfx::Rect moved_bounds(gfx::Point(8, 20), content_size);
+  const gfx::Rect moved_bounds(gfx::Point(8, 20), buffer_size);
   shell_surface->SetGeometry(moved_bounds);
   surface->Commit();
   EXPECT_EQ(gfx::Rect(8, 20, 100, 100), window->bounds());
@@ -2567,17 +2247,13 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        DoNotApplyCollisionDetectionWhileDragged) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  surface->Attach(buffer.get());
-  shell_surface->SetGeometry(gfx::Rect(gfx::Point(8, 50), buffer_size));
-  shell_surface->SetPip();
-  surface->Commit();
+  constexpr gfx::Size buffer_size(256, 256);
+  constexpr gfx::Rect original_bounds({8, 50}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ash::WindowState* window_state = ash::WindowState::Get(window);
   EXPECT_EQ(gfx::Rect(8, 50, 256, 256), window->bounds());
@@ -2594,26 +2270,15 @@
 }
 
 TEST_F(ClientControlledShellSurfaceTest, EnteringPipSavesPipSnapFraction) {
-  const gfx::Size content_size(100, 100);
-  auto buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(content_size));
-
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  constexpr gfx::Size buffer_size(100, 100);
+  constexpr gfx::Rect original_bounds({8, 50}, buffer_size);
+  auto shell_surface = exo::test::ShellSurfaceBuilder(buffer_size)
+                           .SetWindowState(chromeos::WindowStateType::kPip)
+                           .SetGeometry(original_bounds)
+                           .BuildClientControlledShellSurface();
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   ash::WindowState* window_state = ash::WindowState::Get(window);
-
-  // Put the PIP window off the top edge as snap fraction has more likely to
-  // have an error vertically.
-  const gfx::Rect original_bounds(gfx::Point(8, 50), content_size);
-  shell_surface->SetGeometry(original_bounds);
-  shell_surface->SetPip();
-  surface->Commit();
   EXPECT_EQ(gfx::Rect(8, 50, 100, 100), window->bounds());
-  shell_surface->GetWidget()->Show();
 
   // Ensure the correct value is saved to pip snap fraction.
   EXPECT_TRUE(ash::PipPositioner::HasSnapFraction(window_state));
@@ -2623,9 +2288,9 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        ShadowBoundsChangedIsResetAfterCommit) {
-  auto surface = std::make_unique<Surface>();
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+      exo::test::ShellSurfaceBuilder().BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   surface->SetFrame(SurfaceFrameType::SHADOW);
   shell_surface->SetShadowBounds(gfx::Rect(10, 10, 100, 100));
   EXPECT_TRUE(shell_surface->get_shadow_bounds_changed_for_testing());
@@ -2652,16 +2317,13 @@
 TEST_F(ClientControlledShellSurfaceScaleTest, ScaleSetOnInitialCommit) {
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({20, 20})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  surface->Attach(buffer.get());
   surface->Commit();
 
   EXPECT_EQ(2.f, 1.f / shell_surface->GetClientToDpScale());
@@ -2673,21 +2335,18 @@
        DeferScaleCommitForRestoredWindow) {
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  gfx::Rect initial_native_bounds(100, 100, 100, 100);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({20, 20})
+                           .SetWindowState(chromeos::WindowStateType::kNormal)
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  shell_surface->SetRestored();
-  surface->Attach(buffer.get());
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_native_bounds(100, 100, 100, 100);
   shell_surface->SetBounds(primary_display.id(), initial_native_bounds);
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   EXPECT_EQ(2.f, 1.f / shell_surface->GetClientToDpScale());
@@ -2717,20 +2376,18 @@
        CommitScaleChangeImmediatelyForMaximizedWindow) {
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  gfx::Rect initial_native_bounds(100, 100, 100, 100);
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({20, 20})
+          .SetWindowState(chromeos::WindowStateType::kMaximized)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  shell_surface->SetMaximized();
-  surface->Attach(buffer.get());
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_native_bounds(100, 100, 100, 100);
   shell_surface->SetBounds(primary_display.id(), initial_native_bounds);
   surface->Commit();
 
@@ -2751,21 +2408,18 @@
   EnableTabletMode(true);
   UpdateDisplay("1200x800*2.0");
 
-  const gfx::Size buffer_size(20, 20);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface());
-  auto shell_surface = exo_test_helper()->CreateClientControlledShellSurface(
-      surface.get(), /*is_modal=*/false, /*default_scale_cancellation=*/false);
+  gfx::Rect initial_native_bounds(100, 100, 100, 100);
+  auto shell_surface =
+      exo::test::ShellSurfaceBuilder({20, 20})
+          .SetWindowState(chromeos::WindowStateType::kSecondarySnapped)
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-  surface->Attach(buffer.get());
-
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_native_bounds(100, 100, 100, 100);
   shell_surface->SetBounds(primary_display.id(), initial_native_bounds);
-  shell_surface->SetSnappedToSecondary();
   surface->Commit();
 
   EXPECT_EQ(2.f, 1.f / shell_surface->GetClientToDpScale());
@@ -2791,13 +2445,10 @@
 TEST_F(ClientControlledShellSurfaceTest, SnappedClientBounds) {
   UpdateDisplay("800x600");
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Clear insets so that it won't affects the bounds.
   shell_surface->SetSystemUiVisibility(true);
@@ -2807,8 +2458,6 @@
 
   auto* delegate =
       TestClientControlledShellSurfaceDelegate::SetUp(shell_surface.get());
-
-  surface->Attach(buffer.get());
   surface->Commit();
   views::Widget* widget = shell_surface->GetWidget();
   aura::Window* window = widget->GetNativeWindow();
@@ -2854,29 +2503,31 @@
 // The shell surface with resize lock on should be unresizable.
 TEST_F(ClientControlledShellSurfaceTest,
        ShellSurfaceWithResizeLockOnIsUnresizable) {
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
+
+  EXPECT_TRUE(shell_surface->CanResize());
+
+  shell_surface->SetResizeLockType(
+      ash::ArcResizeLockType::RESIZE_DISABLED_TOGGLABLE);
   surface->Commit();
+  EXPECT_FALSE(shell_surface->CanResize());
+
+  shell_surface->SetResizeLockType(
+      ash::ArcResizeLockType::RESIZE_ENABLED_TOGGLABLE);
+  surface->Commit();
+  EXPECT_TRUE(shell_surface->CanResize());
 }
 
 TEST_F(ClientControlledShellSurfaceTest, OverlayShadowBounds) {
-  gfx::Size buffer_size(1, 1);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Attach(buffer.get());
-  surface->Commit();
+  gfx::Rect initial_bounds(150, 10, 200, 200);
+  auto shell_surface = exo::test::ShellSurfaceBuilder({1, 1})
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   display::Display primary_display =
       display::Screen::GetScreen()->GetPrimaryDisplay();
-  gfx::Rect initial_bounds(150, 10, 200, 200);
   shell_surface->SetBounds(primary_display.id(), initial_bounds);
   shell_surface->OnSetFrame(SurfaceFrameType::NORMAL);
   surface->Commit();
@@ -2899,18 +2550,12 @@
 // WideFrameView follows its respective surface when it is eventually parented.
 // See crbug.com/1223135.
 TEST_F(ClientControlledShellSurfaceTest, WideframeForUnparentedTasks) {
-  auto surface = std::make_unique<Surface>();
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  // Create a non-wide frame shell surface.
-  auto desktop_buffer = std::make_unique<Buffer>(
-      exo_test_helper()->CreateGpuMemoryBuffer(gfx::Size(64, 64)));
-  surface->Attach(desktop_buffer.get());
-  surface->SetInputRegion(gfx::Rect(0, 0, 64, 64));
-  shell_surface->SetGeometry(gfx::Rect(100, 0, 64, 64));
-  surface->SetFrame(SurfaceFrameType::NORMAL);
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({64, 64})
+                           .SetGeometry(gfx::Rect(100, 0, 64, 64))
+                           .SetInputRegion(gfx::Rect(0, 0, 64, 64))
+                           .SetFrame(SurfaceFrameType::NORMAL)
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* wide_frame = shell_surface->wide_frame_for_test();
   ASSERT_FALSE(wide_frame);
 
@@ -2945,10 +2590,8 @@
 
 TEST_F(ClientControlledShellSurfaceTest,
        InitializeWindowStateGrantsPermissionToActivate) {
-  auto surface = std::make_unique<Surface>();
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  surface->Commit();
+      exo::test::ShellSurfaceBuilder().BuildClientControlledShellSurface();
 
   aura::Window* window = shell_surface->GetWidget()->GetNativeWindow();
   auto* permission = window->GetProperty(kPermissionKey);
diff --git a/components/exo/server/arc_overlay_manager_unittest.cc b/components/exo/server/arc_overlay_manager_unittest.cc
index 59aef6f..cac7e4a 100644
--- a/components/exo/server/arc_overlay_manager_unittest.cc
+++ b/components/exo/server/arc_overlay_manager_unittest.cc
@@ -8,6 +8,7 @@
 #include "components/exo/sub_surface.h"
 #include "components/exo/surface.h"
 #include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/base/class_property.h"
 
@@ -20,23 +21,16 @@
 };
 
 TEST_F(ArcOverlayManagerTest, Basic) {
-  gfx::Size buffer_size(256, 256);
-
-  std::unique_ptr<Surface> surface1(new Surface);
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface1.get()));
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetNoCommit()
+                           .BuildClientControlledShellSurface();
+  auto* surface1 = shell_surface->root_surface();
 
   // Create Widget
   shell_surface->SetSystemUiVisibility(false);
 
-  std::unique_ptr<Surface> surface2(new Surface);
-  auto sub_surface =
-      std::make_unique<SubSurface>(surface2.get(), surface1.get());
-
-  std::unique_ptr<Buffer> buffer2(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  surface2->Attach(buffer2.get());
+  auto* surface2 =
+      test::ShellSurfaceBuilder::AddChildSurface(surface1, {0, 0, 128, 128});
 
   // Make
   surface2->Commit();
diff --git a/components/exo/shell_surface_util_unittest.cc b/components/exo/shell_surface_util_unittest.cc
index 8329554..d492bf54 100644
--- a/components/exo/shell_surface_util_unittest.cc
+++ b/components/exo/shell_surface_util_unittest.cc
@@ -78,23 +78,18 @@
                               shell_surface->GetWidget()->GetNativeWindow()));
 }
 
+// No explicit verifications are needed for this test as this test just tries to
+// catch potential crashes.
 TEST_F(ShellSurfaceUtilTest, ClientControlledTargetForKeyboardFocus) {
   Display display;
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .BuildClientControlledShellSurface();
 
-  gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  surface->Attach(buffer.get());
-  surface->Commit();
-
-  auto shell_surface(
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get()));
   shell_surface->set_delegate(
       std::make_unique<test::ClientControlledShellSurfaceDelegate>(
           shell_surface.get(), true));
   shell_surface->SetMinimized();
+  auto* surface = shell_surface->root_surface();
   surface->Commit();
 
   shell_surface->GetWidget()->Hide();
diff --git a/components/exo/test/exo_test_helper.cc b/components/exo/test/exo_test_helper.cc
index c92e2c3..ed53413 100644
--- a/components/exo/test/exo_test_helper.cc
+++ b/components/exo/test/exo_test_helper.cc
@@ -136,27 +136,6 @@
                               gpu::kNullSurfaceHandle, nullptr);
 }
 
-std::unique_ptr<ClientControlledShellSurface>
-ExoTestHelper::CreateClientControlledShellSurface(
-    Surface* surface,
-    bool is_modal,
-    bool default_scale_cancellation) {
-  int container = is_modal ? ash::kShellWindowId_SystemModalContainer
-                           : ash::desks_util::GetActiveDeskContainerId();
-  auto shell_surface = Display().CreateOrGetClientControlledShellSurface(
-      surface, container,
-      WMHelper::GetInstance()->GetDefaultDeviceScaleFactor(),
-      default_scale_cancellation);
-  shell_surface->SetApplicationId("arc");
-  // ARC's default min size is non-empty.
-  shell_surface->SetMinimumSize(gfx::Size(1, 1));
-  shell_surface->set_delegate(
-      std::make_unique<ClientControlledShellSurfaceDelegate>(
-          shell_surface.get()));
-
-  return shell_surface;
-}
-
 std::unique_ptr<InputMethodSurface> ExoTestHelper::CreateInputMethodSurface(
     Surface* surface,
     InputMethodSurfaceManager* surface_manager,
diff --git a/components/exo/test/shell_surface_builder.cc b/components/exo/test/shell_surface_builder.cc
index cd03f31..6eb8596 100644
--- a/components/exo/test/shell_surface_builder.cc
+++ b/components/exo/test/shell_surface_builder.cc
@@ -6,6 +6,7 @@
 
 #include <tuple>
 
+#include "ash/constants/app_types.h"
 #include "ash/wm/desks/desks_util.h"
 #include "ash/wm/window_positioning_utils.h"
 #include "components/exo/buffer.h"
@@ -15,6 +16,7 @@
 #include "components/exo/test/exo_test_base.h"
 #include "components/exo/xdg_shell_surface.h"
 #include "gpu/command_buffer/client/gpu_memory_buffer_manager.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 
 #include "base/logging.h"
@@ -34,7 +36,7 @@
                       absl::optional<gfx::BufferFormat> buffer_format) {
     auto surface = std::make_unique<exo::Surface>();
     std::unique_ptr<exo::Buffer> buffer;
-    if (buffer_format) {
+    if (!size.IsEmpty() && buffer_format) {
       buffer = std::make_unique<exo::Buffer>(
           aura::Env::GetInstance()
               ->context_factory()
@@ -135,6 +137,12 @@
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::EnableSystemModal() {
+  DCHECK(!built_);
+  system_modal_ = true;
+  return *this;
+}
+
 ShellSurfaceBuilder& ShellSurfaceBuilder::SetNoCommit() {
   DCHECK(!built_);
   commit_on_build_ = false;
@@ -161,6 +169,33 @@
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetGeometry(
+    const gfx::Rect& geometry) {
+  DCHECK(!built_);
+  geometry_ = geometry;
+  return *this;
+}
+
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetInputRegion(
+    const cc::Region& region) {
+  DCHECK(!built_);
+  input_region_ = region;
+  return *this;
+}
+
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetFrame(SurfaceFrameType type) {
+  DCHECK(!built_);
+  type_ = type;
+  return *this;
+}
+
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetApplicationId(
+    const std::string& application_id) {
+  DCHECK(!built_);
+  application_id_ = application_id;
+  return *this;
+}
+
 ShellSurfaceBuilder& ShellSurfaceBuilder::SetDisableMovement() {
   DCHECK(!built_);
   disable_movement_ = true;
@@ -185,12 +220,26 @@
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetWindowState(
+    chromeos::WindowStateType window_state) {
+  DCHECK(!built_);
+  window_state_ = window_state;
+  return *this;
+}
+
 ShellSurfaceBuilder& ShellSurfaceBuilder::EnableDefaultScaleCancellation() {
   DCHECK(!built_);
   default_scale_cancellation_ = true;
   return *this;
 }
 
+ShellSurfaceBuilder& ShellSurfaceBuilder::SetDelegate(
+    std::unique_ptr<ClientControlledShellSurface::Delegate> delegate) {
+  DCHECK(!built_);
+  delegate_ = std::move(delegate);
+  return *this;
+}
+
 // static
 void ShellSurfaceBuilder::DestroyRootSurface(ShellSurfaceBase* shell_surface) {
   Holder* holder =
@@ -244,21 +293,62 @@
   shell_surface->host_window()->SetProperty(kBuilderResourceHolderKey, holder);
 
   // Set the properties specific to ClientControlledShellSurface.
-  shell_surface->SetApplicationId("arc");
+  shell_surface->SetApplicationId(!application_id_.empty()
+                                      ? application_id_.c_str()
+                                      : "org.chromium.arc.1");
   // ARC's default min size is non-empty.
   if (!min_size_.has_value())
     shell_surface->SetMinimumSize(gfx::Size(1, 1));
-  shell_surface->set_delegate(
-      std::make_unique<ClientControlledShellSurfaceDelegate>(
-          shell_surface.get()));
+  if (delegate_) {
+    shell_surface->set_delegate(std::move(delegate_));
+  } else {
+    shell_surface->set_delegate(
+        std::make_unique<ClientControlledShellSurfaceDelegate>(
+            shell_surface.get()));
+  }
+  if (window_state_.has_value()) {
+    switch (window_state_.value()) {
+      case chromeos::WindowStateType::kDefault:
+      case chromeos::WindowStateType::kNormal:
+        shell_surface->SetRestored();
+        break;
+      case chromeos::WindowStateType::kMaximized:
+        shell_surface->SetMaximized();
+        break;
+      case chromeos::WindowStateType::kMinimized:
+        shell_surface->SetMinimized();
+        break;
+      case chromeos::WindowStateType::kFullscreen:
+        shell_surface->SetFullscreen(/*fullscreen=*/true);
+        break;
+      case chromeos::WindowStateType::kPrimarySnapped:
+        shell_surface->SetSnappedToPrimary();
+        break;
+      case chromeos::WindowStateType::kSecondarySnapped:
+        shell_surface->SetSnappedToSecondary();
+        break;
+      case chromeos::WindowStateType::kPip:
+        shell_surface->SetPip();
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
 
   SetCommonPropertiesAndCommitIfNecessary(shell_surface.get());
 
+  // The widget becomes available after the first commit.
+  if (shell_surface->GetWidget()) {
+    shell_surface->GetWidget()->GetNativeWindow()->SetProperty(
+        aura::client::kAppType, static_cast<int>(ash::AppType::ARC_APP));
+  }
+
   return shell_surface;
 }
 
 bool ShellSurfaceBuilder::isConfigurationValidForShellSurface() {
-  return !default_scale_cancellation_;
+  return !default_scale_cancellation_ && !window_state_.has_value() &&
+         !delegate_;
 }
 
 bool ShellSurfaceBuilder::
@@ -277,6 +367,21 @@
   if (min_size_.has_value())
     shell_surface->SetMinimumSize(min_size_.value());
 
+  if (geometry_.has_value())
+    shell_surface->SetGeometry(geometry_.value());
+
+  if (input_region_.has_value()) {
+    shell_surface->root_surface()->SetInputRegion(input_region_.value());
+  }
+
+  if (type_.has_value()) {
+    shell_surface->root_surface()->SetFrame(type_.value());
+  }
+
+  if (system_modal_) {
+    shell_surface->SetSystemModal(true);
+  }
+
   if (commit_on_build_) {
     shell_surface->root_surface()->Commit();
     if (centered_)
diff --git a/components/exo/test/shell_surface_builder.h b/components/exo/test/shell_surface_builder.h
index c4e8580..dd89dc0 100644
--- a/components/exo/test/shell_surface_builder.h
+++ b/components/exo/test/shell_surface_builder.h
@@ -7,6 +7,8 @@
 
 #include <memory>
 
+#include "cc/base/region.h"
+#include "components/exo/client_controlled_shell_surface.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/base/class_property.h"
 #include "ui/gfx/buffer_types.h"
@@ -27,7 +29,7 @@
 // destroyed when the shell surface is destroyed.
 class ShellSurfaceBuilder {
  public:
-  ShellSurfaceBuilder(const gfx::Size& buffer_size);
+  explicit ShellSurfaceBuilder(const gfx::Size& buffer_size = {0, 0});
   ShellSurfaceBuilder(ShellSurfaceBuilder& other) = delete;
   ShellSurfaceBuilder& operator=(ShellSurfaceBuilder& other) = delete;
   ~ShellSurfaceBuilder();
@@ -37,10 +39,17 @@
   ShellSurfaceBuilder& SetRootBufferFormat(gfx::BufferFormat buffer_format);
   ShellSurfaceBuilder& SetOrigin(const gfx::Point& origin);
   ShellSurfaceBuilder& SetUseSystemModalContainer();
+  ShellSurfaceBuilder& EnableSystemModal();
+  // When set true, some properties such as kAppType may not be set by this
+  // builder as they need the widget created in the commit process.
   ShellSurfaceBuilder& SetNoCommit();
   ShellSurfaceBuilder& SetCanMinimize(bool can_minimize);
   ShellSurfaceBuilder& SetMaximumSize(const gfx::Size& size);
   ShellSurfaceBuilder& SetMinimumSize(const gfx::Size& size);
+  ShellSurfaceBuilder& SetGeometry(const gfx::Rect& geometry);
+  ShellSurfaceBuilder& SetInputRegion(const cc::Region& region);
+  ShellSurfaceBuilder& SetFrame(SurfaceFrameType type);
+  ShellSurfaceBuilder& SetApplicationId(const std::string& application_id);
   ShellSurfaceBuilder& SetDisableMovement();
   ShellSurfaceBuilder& SetCentered();
 
@@ -49,7 +58,10 @@
   ShellSurfaceBuilder& SetAsPopup();
 
   // Sets parameters defined in ClientControlledShellSurface.
+  ShellSurfaceBuilder& SetWindowState(chromeos::WindowStateType window_state);
   ShellSurfaceBuilder& EnableDefaultScaleCancellation();
+  ShellSurfaceBuilder& SetDelegate(
+      std::unique_ptr<ClientControlledShellSurface::Delegate> delegate);
 
   // Must be called only once for either of the below and the object cannot
   // be used to create multiple windows.
@@ -74,7 +86,12 @@
   gfx::Point origin_;
   absl::optional<gfx::Size> max_size_;
   absl::optional<gfx::Size> min_size_;
+  absl::optional<gfx::Rect> geometry_;
+  absl::optional<cc::Region> input_region_;
+  absl::optional<SurfaceFrameType> type_;
+  std::string application_id_;
   bool use_system_modal_container_ = false;
+  bool system_modal_ = false;
   bool commit_on_build_ = true;
   bool can_minimize_ = true;
   bool disable_movement_ = false;
@@ -86,7 +103,9 @@
   bool popup_ = false;
 
   // ClientControlledShellSurface-specific parameters.
+  absl::optional<chromeos::WindowStateType> window_state_;
   bool default_scale_cancellation_ = false;
+  std::unique_ptr<ClientControlledShellSurface::Delegate> delegate_;
 };
 
 }  // namespace test
diff --git a/components/exo/wayland/zcr_remote_shell_impl_unittest.cc b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
index 22201aae..16cdd7e 100644
--- a/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
+++ b/components/exo/wayland/zcr_remote_shell_impl_unittest.cc
@@ -16,7 +16,9 @@
 #include "base/bind.h"
 #include "base/posix/unix_domain_socket.h"
 #include "components/exo/display.h"
+#include "components/exo/shell_surface.h"
 #include "components/exo/test/exo_test_base.h"
+#include "components/exo/test/shell_surface_builder.h"
 #include "components/exo/wayland/server_util.h"
 #include "ui/display/display.h"
 #include "ui/display/screen.h"
@@ -71,6 +73,9 @@
     wl_shell_resource_.reset(wl_resource_create(wl_client_.get(),
                                                 &zcr_remote_shell_v2_interface,
                                                 /*version=*/1, /*id=*/0));
+    wl_remote_surface_resource_.reset(
+        wl_resource_create(wl_client(), &zcr_remote_surface_v2_interface,
+                           /*version=*/1, /*id=*/0));
 
     display_ = std::make_unique<Display>();
     shell_ = std::make_unique<WaylandRemoteShell>(
@@ -91,6 +96,11 @@
     ash::Shell::Get()->tablet_mode_controller()->SetEnabledForTest(enable);
   }
 
+  std::unique_ptr<ClientControlledShellSurface::Delegate> CreateDelegate() {
+    return shell()->CreateShellSurfaceDelegate(
+        wl_remote_surface_resource_.get());
+  }
+
   void ResetEventRecords() {
     remote_shell_event_sequence_.clear();
     remote_shell_requested_bounds_changes_.clear();
@@ -100,6 +110,8 @@
 
   wl_client* wl_client() { return wl_client_.get(); }
 
+  wl_resource* wl_remote_surface() { return wl_remote_surface_resource_.get(); }
+
   static std::vector<RemoteShellEventType> remote_shell_event_sequence() {
     return remote_shell_event_sequence_;
   }
@@ -118,6 +130,7 @@
   ScopedWlDisplay wl_display_;
   ScopedWlClient wl_client_;
   ScopedWlResource wl_shell_resource_;
+  ScopedWlResource wl_remote_surface_resource_;
 
   std::unique_ptr<WaylandRemoteShell> shell_;
 
@@ -212,22 +225,10 @@
 // Test that all bounds change requests are deferred while the tablet transition
 // is happening until it's finished.
 TEST_F(WaylandRemoteShellTest, TabletTransition) {
-  // Setup buffer/surface/window.
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-
-  surface->Attach(buffer.get());
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder({256, 256})
+                           .SetDelegate(CreateDelegate())
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
   auto* const widget = shell_surface->GetWidget();
   auto* const window = widget->GetNativeWindow();
 
@@ -255,27 +256,18 @@
 // proper values and in proper order when display zoom happens. A bounds change
 // event must be triggered only for PIP.
 TEST_F(WaylandRemoteShellTest, DisplayZoom) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
+  // Test a restored window first.
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  auto* const window = shell_surface->GetWidget()->GetNativeWindow();
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetDelegate(CreateDelegate())
+          .SetWindowState(chromeos::WindowStateType::kNormal)
+          .SetGeometry({100, 100, kDefaultWindowLength, kDefaultWindowLength})
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
+  auto* window = shell_surface->GetWidget()->GetNativeWindow();
   const display::Display& display =
       display::Screen::GetScreen()->GetDisplayNearestWindow(window);
 
-  // Test a restored window.
-  shell_surface->SetRestored();
-  shell_surface->SetGeometry(
-      gfx::Rect(100, 100, kDefaultWindowLength, kDefaultWindowLength));
-  surface->Commit();
   ResetEventRecords();
   ash::Shell::Get()->display_manager()->ZoomDisplay(display.id(), /*up=*/true);
   task_environment()->RunUntilIdle();
@@ -326,27 +318,18 @@
 // proper values and in proper order when display rotation happens. A bounds
 // change event must be triggered only for PIP.
 TEST_F(WaylandRemoteShellTest, DisplayRotation) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
+  // Test a restored window first.
   auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  surface->Attach(buffer.get());
-  surface->Commit();
-  auto* const window = shell_surface->GetWidget()->GetNativeWindow();
+      exo::test::ShellSurfaceBuilder({256, 256})
+          .SetDelegate(CreateDelegate())
+          .SetWindowState(chromeos::WindowStateType::kNormal)
+          .SetGeometry({100, 100, kDefaultWindowLength, kDefaultWindowLength})
+          .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
+  auto* window = shell_surface->GetWidget()->GetNativeWindow();
   const display::Display& display =
       display::Screen::GetScreen()->GetDisplayNearestWindow(window);
 
-  // Test a restored window.
-  shell_surface->SetRestored();
-  shell_surface->SetGeometry(
-      gfx::Rect(100, 100, kDefaultWindowLength, kDefaultWindowLength));
-  surface->Commit();
   ResetEventRecords();
   ash::Shell::Get()->display_manager()->SetDisplayRotation(
       display.id(), display::Display::ROTATE_90,
@@ -411,21 +394,11 @@
 // and workspace info events are triggered with proper values and in
 // proper order.
 TEST_F(WaylandRemoteShellTest, DisplayRemovalAddition) {
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  surface->Attach(buffer.get());
-  shell_surface->SetRestored();
-  shell_surface->SetGeometry(
-      gfx::Rect(100, 100, kDefaultWindowLength, kDefaultWindowLength));
-  surface->Commit();
+  auto shell_surface = exo::test::ShellSurfaceBuilder(
+                           {kDefaultWindowLength, kDefaultWindowLength})
+                           .SetDelegate(CreateDelegate())
+                           .BuildClientControlledShellSurface();
+  auto* surface = shell_surface->root_surface();
 
   // Add secondary display with a different scale factor.
   UpdateDisplay("800x600,800x600*2");
@@ -496,31 +469,25 @@
 // Test that the desktop focus state event is called with the proper value in
 // response to window focus change.
 TEST_F(WaylandRemoteShellTest, DesktopFocusState) {
-  // Setup buffer/surface/window.
-  const gfx::Size buffer_size(256, 256);
-  std::unique_ptr<Buffer> buffer(
-      new Buffer(exo_test_helper()->CreateGpuMemoryBuffer(buffer_size)));
-
-  std::unique_ptr<Surface> surface(new Surface);
-  auto shell_surface =
-      exo_test_helper()->CreateClientControlledShellSurface(surface.get());
-
-  ScopedWlResource wl_res(wl_resource_create(
-      wl_client(), &zcr_remote_surface_v2_interface, /*version=*/1, /*id=*/0));
-  shell_surface->set_delegate(
-      shell()->CreateShellSurfaceDelegate(wl_res.get()));
-  SetSurfaceResource(surface.get(), wl_res.get());
-
-  surface->Attach(buffer.get());
+  auto client_controlled_shell_surface =
+      exo::test::ShellSurfaceBuilder(
+          {kDefaultWindowLength, kDefaultWindowLength})
+          .SetDelegate(CreateDelegate())
+          .SetNoCommit()
+          .BuildClientControlledShellSurface();
+  auto* surface = client_controlled_shell_surface->root_surface();
+  SetSurfaceResource(surface, wl_remote_surface());
   surface->Commit();
   EXPECT_EQ(last_desktop_focus_state(), 2);
 
-  shell_surface->SetMinimized();
+  client_controlled_shell_surface->SetMinimized();
   surface->Commit();
   EXPECT_EQ(last_desktop_focus_state(), 1);
 
-  auto* other_client_window =
-      CreateTestWindowInShellWithBounds(gfx::Rect(0, 0, 100, 100));
+  auto shell_surface = exo::test::ShellSurfaceBuilder(
+                           {kDefaultWindowLength, kDefaultWindowLength})
+                           .BuildShellSurface();
+  auto* other_client_window = shell_surface->GetWidget()->GetNativeWindow();
   other_client_window->Show();
   other_client_window->Focus();
   EXPECT_EQ(last_desktop_focus_state(), 3);