| 12
 3
 4
 5
 6
 7
 8
 9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 
 | // Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/extensions/api/page_capture/page_capture_api.h"
#include <memory>
#include "base/test/values_test_util.h"
#include "chrome/browser/extensions/extension_service_test_base.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/base/test_browser_window.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/web_contents_tester.h"
#include "extensions/browser/api_test_utils.h"
#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "url/gurl.h"
namespace extensions {
class PageCaptureApiUnitTest : public ExtensionServiceTestBase {
 protected:
  void SetUp() override {
    ExtensionServiceTestBase::SetUp();
    InitializeEmptyExtensionService();
    auto browser_window = std::make_unique<TestBrowserWindow>();
    Browser::CreateParams params(profile(), true);
    params.type = Browser::TYPE_NORMAL;
    params.window = browser_window.release();
    browser_ = Browser::DeprecatedCreateOwnedForTesting(params);
  }
  void TearDown() override {
    browser_.reset();
    ExtensionServiceTestBase::TearDown();
  }
  Browser* browser() { return browser_.get(); }
 private:
  std::unique_ptr<Browser> browser_;
};
// Tests that if a page navigates during a call to pageCature.saveAsMHTML(), the
// API call will result in an error.
TEST_F(PageCaptureApiUnitTest, PageNavigationDuringSaveAsMHTML) {
  scoped_refptr<const Extension> extension =
      ExtensionBuilder("Page Capture").AddAPIPermission("pageCapture").Build();
  auto function = base::MakeRefCounted<PageCaptureSaveAsMHTMLFunction>();
  function->set_extension(extension.get());
  // Add a visible tab.
  std::unique_ptr<content::WebContents> web_contents =
      content::WebContentsTester::CreateTestWebContents(profile(), nullptr);
  content::WebContentsTester* web_contents_tester =
      content::WebContentsTester::For(web_contents.get());
  browser()->tab_strip_model()->AppendWebContents(std::move(web_contents),
                                                  /*foreground=*/true);
  web_contents_tester->NavigateAndCommit(GURL("https://www.google.com"));
  const int tab_id = ExtensionTabUtil::GetTabId(
      browser()->tab_strip_model()->GetWebContentsAt(0));
  // To capture the page as MHTML, the extension function needs to hop from the
  // UI thread to the IO thread to create the temporary file, then back to the
  // UI thread to actually save the page contents. Since the URL access is only
  // checked initially and a navigation could happen during the thread hops, the
  // extension function should result in an error if a navigation happens
  // between the initial check and the actual capture. To simulate this we start
  // the extension function running, then trigger a synchronous navigation
  // using the WebContentsTester immediately which will happen before the
  // messaging between threads finishes.
  // Regression test for crbug.com/1494490
  function->SetBrowserContextForTesting(profile());
  function->SetArgs(
      base::Value::List().Append(base::Value::Dict().Set("tabId", tab_id)));
  api_test_utils::SendResponseHelper response_helper(function.get());
  function->RunWithValidation().Execute();
  web_contents_tester->NavigateAndCommit(GURL("https://www.chromium.org"));
  response_helper.WaitForResponse();
  const base::Value::List* results = function->GetResultListForTest();
  ASSERT_TRUE(results);
  EXPECT_TRUE(results->empty()) << "Did not expect a result";
  CHECK(function->response_type());
  EXPECT_EQ(ExtensionFunction::ResponseType::kFailed,
            *function->response_type());
  EXPECT_EQ("Tab navigated before capture could complete.",
            function->GetError());
  // Clean up.
  browser()->tab_strip_model()->CloseAllTabs();
}
}  // namespace extensions
 |