blob: c86bd3e1249042b3163bd02a2e32ca359e161219 [file] [log] [blame]
// 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 "chrome/renderer/extensions/api/identity_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 IdentityHooksDelegateTest = NativeExtensionBindingsSystemUnittest;
// Tests that the result modifier used in the getAuthToken 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.
TEST_F(IdentityHooksDelegateTest, GetAuthToken) {
// Initialize bindings system.
bindings_system()->api_system()->RegisterHooksDelegate(
"identity", std::make_unique<IdentityHooksDelegate>());
// Register extension.
scoped_refptr<const Extension> extension = ExtensionBuilder("testExtension")
.AddAPIPermission("identity")
.Build();
RegisterExtension(extension);
v8::HandleScope handle_scope(isolate());
v8::Local<v8::Context> context = MainContext();
ScriptContext* script_context = CreateScriptContext(
context, extension.get(), mojom::ContextType::kPrivilegedExtension);
script_context->set_url(extension->url());
bindings_system()->UpdateBindingsForContext(script_context);
constexpr char kFakeAPIResponse[] =
R"([{"token": "foo", "grantedScopes": ["bar"]}])";
// Calling getAuthToken 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.identity.getAuthToken(); })");
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 that the object here differs slightly from the response, in that it
// is not array wrapped and the keys become alphabetized.
EXPECT_EQ(R"({"grantedScopes":["bar"],"token":"foo"})",
V8ToString(promise->Result(), context));
}
// Calling getAuthToken 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) {
chrome.identity.getAuthToken((token, grantedScopes) => {
this.argument1 = token;
this.argument2 = grantedScopes;
});
}))";
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"("foo")", GetStringPropertyFromObject(context->Global(),
context, "argument1"));
EXPECT_EQ(R"(["bar"])", GetStringPropertyFromObject(context->Global(),
context, "argument2"));
}
}
} // namespace extensions