910e62b5创建于 1月15日历史提交
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/renderer/api/feedback_private_hooks_delegate.h"

#include "extensions/common/extension.h"
#include "extensions/common/extension_builder.h"
#include "extensions/common/mojom/context_type.mojom.h"
#include "extensions/common/mojom/frame.mojom.h"
#include "extensions/renderer/bindings/api_binding_test_util.h"
#include "extensions/renderer/native_extension_bindings_system.h"
#include "extensions/renderer/native_extension_bindings_system_test_base.h"
#include "extensions/renderer/script_context.h"

namespace extensions {

using FeedbackPrivateHooksDelegateTest = NativeExtensionBindingsSystemUnittest;

// Tests that the result modifier used in the sendFeedback handle request hook
// results in callback-based calls getting a response with multiple arguments
// and promise-based calls getting a response with a single object.
// TODO(crbug.com/40243802): Disabled on ASAN due to bot failures caused by an
// underlying gin issue.
#if defined(ADDRESS_SANITIZER)
#define MAYBE_SendFeedback DISABLED_SendFeedback
#else
#define MAYBE_SendFeedback SendFeedback
#endif
TEST_F(FeedbackPrivateHooksDelegateTest, MAYBE_SendFeedback) {
  // Initialize bindings system.
  bindings_system()->api_system()->RegisterHooksDelegate(
      "feedbackPrivate", std::make_unique<FeedbackPrivateHooksDelegate>());

  // The feedbackPrivate API is restricted to allowlisted extensions and WebUI,
  // so create a WebUI context to test on.
  v8::HandleScope handle_scope(isolate());
  v8::Local<v8::Context> context = MainContext();
  ScriptContext* script_context =
      CreateScriptContext(context, nullptr, mojom::ContextType::kWebUi);
  script_context->set_url(GURL("chrome://feedback"));
  bindings_system()->UpdateBindingsForContext(script_context);

  constexpr char kFakeAPIResponse[] =
      R"([{"status": "success", "landingPageType": "normal"}])";

  // Calling sendFeedback without a callback should return a promise that gets
  // fulfilled with an object with the results as properties on it.
  {
    v8::Local<v8::Function> func = FunctionFromString(
        context,
        "(function() { return "
        "chrome.feedbackPrivate.sendFeedback({description: 'foo'}); })");
    v8::Local<v8::Value> result = RunFunction(func, context, 0, nullptr);
    v8::Local<v8::Promise> promise;
    ASSERT_TRUE(GetValueAs(result, &promise));
    EXPECT_EQ(v8::Promise::kPending, promise->State());

    bindings_system()->HandleResponse(last_params().request_id,
                                      /*success=*/true,
                                      ListValueFromString(kFakeAPIResponse),
                                      /*error=*/std::string());

    EXPECT_EQ(v8::Promise::kFulfilled, promise->State());
    // Note: properties end up alphabetized here.
    EXPECT_EQ(R"({"landingPageType":"normal","status":"success"})",
              V8ToString(promise->Result(), context));
  }

  // Calling sendFeedback with a callback should end up with the callback being
  // called with multiple parameters rather than a single object.
  {
    constexpr char kFunctionCall[] =
        R"((function(api) {
             let info = {description: 'foo'};
             chrome.feedbackPrivate.sendFeedback(info, (...args) => {
               this.callbackArguments = args;
             });
           }))";
    v8::Local<v8::Function> func = FunctionFromString(context, kFunctionCall);
    RunFunctionOnGlobal(func, context, 0, nullptr);

    bindings_system()->HandleResponse(last_params().request_id,
                                      /*success=*/true,
                                      ListValueFromString(kFakeAPIResponse),
                                      /*error=*/std::string());

    EXPECT_EQ(R"(["success","normal"])",
              GetStringPropertyFromObject(context->Global(), context,
                                          "callbackArguments"));
  }
}

}  // namespace extensions