| Index: ios/chrome/browser/passwords/credential_manager_js_unittest.mm
|
| diff --git a/ios/chrome/browser/passwords/credential_manager_js_unittest.mm b/ios/chrome/browser/passwords/credential_manager_js_unittest.mm
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..42382ba88d9a8f448d173d1d471e0d81d10f7f8e
|
| --- /dev/null
|
| +++ b/ios/chrome/browser/passwords/credential_manager_js_unittest.mm
|
| @@ -0,0 +1,510 @@
|
| +// Copyright 2015 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include <memory>
|
| +
|
| +#include "base/mac/foundation_util.h"
|
| +#import "base/mac/scoped_nsobject.h"
|
| +#include "base/strings/utf_string_conversions.h"
|
| +#include "base/values.h"
|
| +#import "ios/chrome/browser/passwords/js_credential_manager.h"
|
| +#include "ios/web/public/web_state/credential.h"
|
| +#import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
|
| +#import "ios/web/public/web_state/web_state.h"
|
| +#include "ios/web/public/web_state/web_state_observer.h"
|
| +#import "ios/web/public/test/web_test_with_web_state.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +#include "testing/gtest_mac.h"
|
| +#include "url/gurl.h"
|
| +
|
| +namespace {
|
| +
|
| +using ::testing::_;
|
| +
|
| +// Matcher to match web::Credential.
|
| +MATCHER_P(IsEqualTo, value, "") {
|
| + return arg.type == value.type && arg.id == value.id &&
|
| + arg.name == value.name && arg.avatar_url == value.avatar_url &&
|
| + arg.password == value.password &&
|
| + arg.federation_origin.Serialize() ==
|
| + value.federation_origin.Serialize();
|
| +}
|
| +
|
| +// A mock WebStateObserver for testing the Credential Manager API.
|
| +class MockWebStateObserver : public web::WebStateObserver {
|
| + public:
|
| + explicit MockWebStateObserver(web::WebState* web_state)
|
| + : web::WebStateObserver(web_state) {}
|
| + ~MockWebStateObserver() override {}
|
| +
|
| + MOCK_METHOD5(
|
| + CredentialsRequested,
|
| + void(int, const GURL&, bool, const std::vector<std::string>&, bool));
|
| + MOCK_METHOD3(SignedIn, void(int, const GURL&, const web::Credential&));
|
| + MOCK_METHOD2(SignedIn, void(int, const GURL&));
|
| + MOCK_METHOD2(SignedOut, void(int, const GURL&));
|
| + MOCK_METHOD3(SignInFailed, void(int, const GURL&, const web::Credential&));
|
| + MOCK_METHOD2(SignInFailed, void(int, const GURL&));
|
| +
|
| + private:
|
| + DISALLOW_COPY_AND_ASSIGN(MockWebStateObserver);
|
| +};
|
| +
|
| +// Unit tests for the Credential Manager JavaScript and associated plumbing.
|
| +class CredentialManagerJsTest : public web::WebTestWithWebState {
|
| + public:
|
| + CredentialManagerJsTest() {}
|
| +
|
| + void SetUp() override {
|
| + web::WebTestWithWebState::SetUp();
|
| + js_credential_manager_.reset(base::mac::ObjCCastStrict<JSCredentialManager>(
|
| + [[web_state()->GetJSInjectionReceiver()
|
| + instanceOfClass:[JSCredentialManager class]] retain]));
|
| + observer_.reset(new MockWebStateObserver(web_state()));
|
| + }
|
| +
|
| + // Sets up a web page and injects the JSCredentialManager. Must be called
|
| + // before any interaction with the page.
|
| + void Inject() {
|
| + LoadHtml(@"");
|
| + [js_credential_manager_ inject];
|
| + }
|
| +
|
| + // Returns the mock observer.
|
| + MockWebStateObserver& observer() { return *observer_; }
|
| +
|
| + // Returns a string that creates a Credential object for JavaScript testing.
|
| + NSString* test_credential_js() {
|
| + return @"new PasswordCredential('bob', 'bobiscool', 'Bob Boblaw',"
|
| + @"'https://bobboblawslawblog.com/bob.jpg')";
|
| + }
|
| +
|
| + // Returns a Credential to match the one returned by |test_credential_js()|.
|
| + web::Credential test_credential() {
|
| + web::Credential test_credential;
|
| + test_credential.type = web::CredentialType::CREDENTIAL_TYPE_PASSWORD;
|
| + test_credential.id = base::ASCIIToUTF16("bob");
|
| + test_credential.password = base::ASCIIToUTF16("bobiscool");
|
| + test_credential.name = base::ASCIIToUTF16("Bob Boblaw");
|
| + test_credential.avatar_url = GURL("https://bobboblawslawblog.com/bob.jpg");
|
| + return test_credential;
|
| + }
|
| +
|
| + // Adds handlers for resolving and rejecting the promise returned by
|
| + // executing the code in |promise|.
|
| + void PrepareResolverAndRejecter(NSString* promise) {
|
| + EvaluateJavaScriptAsString(
|
| + [NSString stringWithFormat:@"var resolved = false; "
|
| + @"var rejected = false; "
|
| + @"var resolvedCredential = null; "
|
| + @"var rejectedError = null; "
|
| + @"function resolve(credential) { "
|
| + @" resolved = true; "
|
| + @" resolvedCredential = credential;"
|
| + @"} "
|
| + @"function reject(error) { "
|
| + @" rejected = true; "
|
| + @" rejectedError = error; "
|
| + @"} "
|
| + @"%@.then(resolve, reject); ",
|
| + promise]);
|
| + // Wait until the promise executor has executed.
|
| + WaitForCondition(^bool {
|
| + return [EvaluateJavaScriptAsString(
|
| + @"Object.keys(__gCrWeb.credentialManager.resolvers_).length > 0")
|
| + isEqualToString:@"true"];
|
| + });
|
| + }
|
| +
|
| + // Checks that the Credential returned to the resolve handler in JavaScript
|
| + // matches the structure of |test_credential()|.
|
| + void CheckResolvedCredentialMatchesTestCredential() {
|
| + EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"resolved"));
|
| + EXPECT_NSEQ(
|
| + @"PasswordCredential",
|
| + EvaluateJavaScriptAsString(@"resolvedCredential.constructor.name"));
|
| + EXPECT_NSEQ(@"bob", EvaluateJavaScriptAsString(@"resolvedCredential.id"));
|
| + EXPECT_NSEQ(@"bobiscool",
|
| + EvaluateJavaScriptAsString(@"resolvedCredential.password_"));
|
| + EXPECT_NSEQ(@"Bob Boblaw",
|
| + EvaluateJavaScriptAsString(@"resolvedCredential.name"));
|
| + EXPECT_NSEQ(@"https://bobboblawslawblog.com/bob.jpg",
|
| + EvaluateJavaScriptAsString(@"resolvedCredential.avatarURL"));
|
| + }
|
| +
|
| + // Checks that the promise set up by |PrepareResolverAndRejecter| was resolved
|
| + // without a credential.
|
| + void CheckResolvedWithoutCredential() {
|
| + EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"resolved"));
|
| + EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"!!resolvedCredential"));
|
| + }
|
| +
|
| + // Checks that the promise set up by |PrepareResolverAndRejecter| was rejected
|
| + // with an error with name |error_name| and |message|.
|
| + void CheckRejected(NSString* error_name, NSString* message) {
|
| + EXPECT_NSEQ(@"true", EvaluateJavaScriptAsString(@"rejected"));
|
| + EXPECT_NSEQ(error_name, EvaluateJavaScriptAsString(@"rejectedError.name"));
|
| + EXPECT_NSEQ(message, EvaluateJavaScriptAsString(@"rejectedError.message"));
|
| + }
|
| +
|
| + // Waits until the promise set up by |PrepareResolverAndRejecter| has been
|
| + // either resolved or rejected.
|
| + void WaitUntilPromiseResolvedOrRejected() {
|
| + WaitForCondition(^bool {
|
| + return [EvaluateJavaScriptAsString(@"resolved || rejected")
|
| + isEqualToString:@"true"];
|
| + });
|
| + }
|
| +
|
| + // Resolves the promise set up by |PrepareResolverAndRejecter| and associated
|
| + // with |request_id| with |test_credential()|.
|
| + void ResolvePromiseWithTestCredential(int request_id) {
|
| + __block bool finished = false;
|
| + [js_credential_manager() resolvePromiseWithRequestID:request_id
|
| + credential:test_credential()
|
| + completionHandler:^(BOOL success) {
|
| + EXPECT_TRUE(success);
|
| + finished = true;
|
| + }];
|
| + WaitForCondition(^bool {
|
| + return finished;
|
| + });
|
| + WaitUntilPromiseResolvedOrRejected();
|
| + }
|
| +
|
| + // Resolves the promise set up by |PrepareResolverAndRejecter| and associated
|
| + // with |request_id| without a credential.
|
| + void ResolvePromiseWithoutCredential(int request_id) {
|
| + __block bool finished = false;
|
| + [js_credential_manager() resolvePromiseWithRequestID:request_id
|
| + completionHandler:^(BOOL success) {
|
| + EXPECT_TRUE(success);
|
| + finished = true;
|
| + }];
|
| + WaitForCondition(^bool {
|
| + return finished;
|
| + });
|
| + WaitUntilPromiseResolvedOrRejected();
|
| + }
|
| +
|
| + // Rejects the promise set up by |PrepareResolverAndRejecter| and associated
|
| + // with |request_id| with an error of type |error_type| and |message|.
|
| + void RejectPromise(int request_id, NSString* error_type, NSString* message) {
|
| + __block bool finished = false;
|
| + [js_credential_manager() rejectPromiseWithRequestID:request_id
|
| + errorType:error_type
|
| + message:message
|
| + completionHandler:^(BOOL success) {
|
| + EXPECT_TRUE(success);
|
| + finished = true;
|
| + }];
|
| + WaitForCondition(^bool {
|
| + return finished;
|
| + });
|
| + WaitUntilPromiseResolvedOrRejected();
|
| + }
|
| +
|
| + // Tests that the promise set up by |PrepareResolverAndRejecter| wasn't
|
| + // rejected.
|
| + void CheckNeverRejected() {
|
| + EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"rejected"));
|
| + }
|
| +
|
| + // Tests that the promise set up by |PrepareResolverAndRejecter| wasn't
|
| + // resolved.
|
| + void CheckNeverResolved() {
|
| + EXPECT_NSEQ(@"false", EvaluateJavaScriptAsString(@"resolved"));
|
| + }
|
| +
|
| + // Returns the JSCredentialManager for testing.
|
| + JSCredentialManager* js_credential_manager() {
|
| + return js_credential_manager_;
|
| + }
|
| +
|
| + // Tests that resolving the promise returned by |promise| and associated with
|
| + // |request_id| with |test_credential()| correctly forwards that credential
|
| + // to the client.
|
| + void TestPromiseResolutionWithCredential(int request_id, NSString* promise) {
|
| + PrepareResolverAndRejecter(promise);
|
| + ResolvePromiseWithTestCredential(request_id);
|
| + CheckResolvedCredentialMatchesTestCredential();
|
| + CheckNeverRejected();
|
| + }
|
| +
|
| + // Tests that resolving the promise returned by |promise| and associated with
|
| + // |request_id| without a credential correctly invokes the client.
|
| + void TestPromiseResolutionWithoutCredential(int request_id,
|
| + NSString* promise) {
|
| + PrepareResolverAndRejecter(promise);
|
| + ResolvePromiseWithoutCredential(request_id);
|
| + CheckResolvedWithoutCredential();
|
| + CheckNeverRejected();
|
| + }
|
| +
|
| + // Tests that rejecting the promise returned by |promise| and associated with
|
| + // |request_id| with an error of type |error| and message |message| correctly
|
| + // forwards that error to the client.
|
| + void TestPromiseRejection(int request_id,
|
| + NSString* error,
|
| + NSString* message,
|
| + NSString* promise) {
|
| + PrepareResolverAndRejecter(promise);
|
| + RejectPromise(request_id, error, message);
|
| + CheckRejected(error, message);
|
| + CheckNeverResolved();
|
| + }
|
| +
|
| + private:
|
| + // Manager for injected credential manager JavaScript.
|
| + base::scoped_nsobject<JSCredentialManager> js_credential_manager_;
|
| +
|
| + // Mock observer for testing.
|
| + std::unique_ptr<MockWebStateObserver> observer_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(CredentialManagerJsTest);
|
| +};
|
| +
|
| +// Tests that navigator.credentials calls use distinct request identifiers.
|
| +TEST_F(CredentialManagerJsTest, RequestIdentifiersDiffer) {
|
| + Inject();
|
| + EXPECT_CALL(observer(), CredentialsRequested(0, _, _, _, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.request()");
|
| + EXPECT_CALL(observer(), SignInFailed(1, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.notifyFailedSignIn()");
|
| + EXPECT_CALL(observer(), SignInFailed(2, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.notifyFailedSignIn()");
|
| + EXPECT_CALL(observer(), SignedIn(3, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedIn()");
|
| + EXPECT_CALL(observer(), SignedOut(4, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedOut()");
|
| + EXPECT_CALL(observer(), CredentialsRequested(5, _, _, _, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.request()");
|
| +}
|
| +
|
| +// Tests that navigator.credentials.request() creates and forwards the right
|
| +// arguments to the app side.
|
| +// TODO(rohitrao): Fails after merge r376674. https://crbug.com/588706.
|
| +TEST_F(CredentialManagerJsTest, DISABLED_RequestToApp) {
|
| + Inject();
|
| + std::vector<std::string> empty_federations;
|
| + std::vector<std::string> nonempty_federations;
|
| + nonempty_federations.push_back("foo");
|
| + nonempty_federations.push_back("bar");
|
| +
|
| + EXPECT_CALL(observer(),
|
| + CredentialsRequested(0, _, false, empty_federations, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.request()");
|
| +
|
| + EXPECT_CALL(observer(),
|
| + CredentialsRequested(1, _, false, empty_federations, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.request({})");
|
| +
|
| + EXPECT_CALL(observer(),
|
| + CredentialsRequested(2, _, true, empty_federations, _));
|
| + EvaluateJavaScriptAsString(
|
| + @"navigator.credentials.request({suppressUI: true})");
|
| +
|
| + EXPECT_CALL(observer(),
|
| + CredentialsRequested(3, _, false, nonempty_federations, _));
|
| + EvaluateJavaScriptAsString(
|
| + @"navigator.credentials.request({federations: ['foo', 'bar']})");
|
| +
|
| + EXPECT_CALL(observer(),
|
| + CredentialsRequested(4, _, true, nonempty_federations, _));
|
| + EvaluateJavaScriptAsString(
|
| + @"navigator.credentials.request("
|
| + @" { suppressUI: true, federations: ['foo', 'bar'] })");
|
| +
|
| + EXPECT_CALL(observer(),
|
| + CredentialsRequested(5, _, false, empty_federations, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.request("
|
| + @" { suppressUI: false, federations: [] })");
|
| +}
|
| +
|
| +// Tests that navigator.credentials.notifySignedIn() creates and forwards the
|
| +// right arguments to the app side.
|
| +TEST_F(CredentialManagerJsTest, NotifySignedInToApp) {
|
| + Inject();
|
| + EXPECT_CALL(observer(), SignedIn(0, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedIn()");
|
| +
|
| + EXPECT_CALL(observer(), SignedIn(1, _, IsEqualTo(test_credential())));
|
| + EvaluateJavaScriptAsString(
|
| + [NSString stringWithFormat:@"navigator.credentials.notifySignedIn(%@)",
|
| + test_credential_js()]);
|
| +}
|
| +
|
| +// Tests that navigator.credentials.notifySignedOut() creates and forwards the
|
| +// right arguments to the app side.
|
| +TEST_F(CredentialManagerJsTest, NotifySignedOutToApp) {
|
| + Inject();
|
| + EXPECT_CALL(observer(), SignedOut(0, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.notifySignedOut()");
|
| +}
|
| +
|
| +// Tests that navigator.credentials.notifyFailedSignIn() creates and forwards
|
| +// the right arguments to the app side.
|
| +TEST_F(CredentialManagerJsTest, NotifyFailedSignInToApp) {
|
| + Inject();
|
| + EXPECT_CALL(observer(), SignInFailed(0, _));
|
| + EvaluateJavaScriptAsString(@"navigator.credentials.notifyFailedSignIn()");
|
| +
|
| + EXPECT_CALL(observer(), SignInFailed(1, _, IsEqualTo(test_credential())));
|
| + EvaluateJavaScriptAsString([NSString
|
| + stringWithFormat:@"navigator.credentials.notifyFailedSignIn(%@)",
|
| + test_credential_js()]);
|
| +}
|
| +
|
| +// Tests that resolving the promise returned by a call to
|
| +// navigator.credentials.request() with a credential correctly forwards that
|
| +// credential to the client.
|
| +TEST_F(CredentialManagerJsTest, ResolveRequestPromiseWithCredential) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), CredentialsRequested(request_id, _, _, _, _));
|
| + TestPromiseResolutionWithCredential(request_id,
|
| + @"navigator.credentials.request()");
|
| +}
|
| +
|
| +// Tests that resolving the promise returned by a call to
|
| +// navigator.credentials.request() without a credential correctly invokes the
|
| +// client handler.
|
| +TEST_F(CredentialManagerJsTest, ResolveRequestPromiseWithoutCredential) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), CredentialsRequested(request_id, _, _, _, _));
|
| + TestPromiseResolutionWithoutCredential(request_id,
|
| + @"navigator.credentials.request()");
|
| +}
|
| +
|
| +// Tests that resolving the promise returned by a call to
|
| +// navigator.credentials.notifySignedIn() without a credential correctly invokes
|
| +// the client handler.
|
| +TEST_F(CredentialManagerJsTest, ResolveNotifySignedInPromiseWithoutCredential) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignedIn(request_id, _));
|
| + TestPromiseResolutionWithoutCredential(
|
| + request_id, @"navigator.credentials.notifySignedIn()");
|
| +}
|
| +
|
| +// Tests that resolving the promise returned by a call to
|
| +// navigator.credentials.notifyFailedSignIn() without a credential correctly
|
| +// invokes the client handler.
|
| +TEST_F(CredentialManagerJsTest,
|
| + ResolveNotifyFailedSignInPromiseWithoutCredential) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignInFailed(request_id, _));
|
| + TestPromiseResolutionWithoutCredential(
|
| + request_id, @"navigator.credentials.notifyFailedSignIn()");
|
| +}
|
| +
|
| +// Tests that resolving the promise returned by a call to
|
| +// navigator.credentials.notifyFailedSignIn() without a credential correctly
|
| +// invokes the client handler.
|
| +TEST_F(CredentialManagerJsTest,
|
| + ResolveNotifySignedOutPromiseWithoutCredential) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignedOut(request_id, _));
|
| + TestPromiseResolutionWithoutCredential(
|
| + request_id, @"navigator.credentials.notifySignedOut()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.request() with a InvalidStateError correctly forwards
|
| +// that error to the client.
|
| +TEST_F(CredentialManagerJsTest, RejectRequestPromiseWithInvalidStateError) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), CredentialsRequested(request_id, _, _, _, _));
|
| + TestPromiseRejection(request_id, @"InvalidStateError", @"foo",
|
| + @"navigator.credentials.request()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.notifySignedIn() with a InvalidStateError correctly
|
| +// forwards that error to the client.
|
| +TEST_F(CredentialManagerJsTest,
|
| + RejectNotifySignedInPromiseWithInvalidStateError) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignedIn(request_id, _));
|
| + TestPromiseRejection(request_id, @"InvalidStateError", @"foo",
|
| + @"navigator.credentials.notifySignedIn()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.notifyFailedSignIn() with a InvalidStateError correctly
|
| +// forwards that error to the client.
|
| +TEST_F(CredentialManagerJsTest,
|
| + RejectNotifyFailedSignInPromiseWithInvalidStateError) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignInFailed(request_id, _));
|
| + TestPromiseRejection(request_id, @"InvalidStateError", @"foo",
|
| + @"navigator.credentials.notifyFailedSignIn()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.notifySignedOut() with a InvalidStateError correctly
|
| +// forwards that error to the client.
|
| +TEST_F(CredentialManagerJsTest,
|
| + RejectNotifySignedOutPromiseWithInvalidStateError) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignedOut(request_id, _));
|
| + TestPromiseRejection(request_id, @"InvalidStateError", @"foo",
|
| + @"navigator.credentials.notifySignedOut()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.request() with a SecurityError correctly forwards that
|
| +// error to the client.
|
| +TEST_F(CredentialManagerJsTest, RejectRequestPromiseWithSecurityError) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), CredentialsRequested(request_id, _, _, _, _));
|
| + TestPromiseRejection(request_id, @"SecurityError", @"foo",
|
| + @"navigator.credentials.request()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.notifySignedIn() with a SecurityError correctly
|
| +// forwards that error to the client.
|
| +TEST_F(CredentialManagerJsTest, RejectNotifySignedInPromiseWithSecurityError) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignedIn(request_id, _));
|
| + TestPromiseRejection(request_id, @"SecurityError", @"foo",
|
| + @"navigator.credentials.notifySignedIn()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.notifyFailedSignIn() with a SecurityError correctly
|
| +// forwards that error to the client.
|
| +TEST_F(CredentialManagerJsTest,
|
| + RejectPromiseWithSecurityError_notifyFailedSignIn) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignInFailed(request_id, _));
|
| + TestPromiseRejection(request_id, @"SecurityError", @"foo",
|
| + @"navigator.credentials.notifyFailedSignIn()");
|
| +}
|
| +
|
| +// Tests that rejecting the promise returned by a call to
|
| +// navigator.credentials.notifySignedOut() with a SecurityError correctly
|
| +// forwards that error to the client.
|
| +TEST_F(CredentialManagerJsTest,
|
| + RejectPromiseWithSecurityError_notifySignedOut) {
|
| + Inject();
|
| + const int request_id = 0;
|
| + EXPECT_CALL(observer(), SignedOut(request_id, _));
|
| + TestPromiseRejection(request_id, @"SecurityError", @"foo",
|
| + @"navigator.credentials.notifySignedOut()");
|
| +}
|
| +
|
| +} // namespace
|
|
|