Commit b6bb0f23 authored by Maria Kazinova's avatar Maria Kazinova Committed by Commit Bot

Removing CredentialManager API on iOS. Part 1: removing tests.

Deleting the API and its tests, as the kCredentialManager feature was
never launched and there is no plan to launch it in the future.

Bug: 435048
Change-Id: Id295c436a8583d50aaa7cb727555f4888fd69a8b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2401042Reviewed-by: default avatarVasilii Sukhanov <vasilii@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Commit-Queue: Maria Kazinova <kazinova@google.com>
Cr-Commit-Position: refs/heads/master@{#806287}
parent f5e796e7
......@@ -64,7 +64,6 @@ source_set("unit_tests") {
testonly = true
sources = [
"account_select_fill_data_unittest.cc",
"credential_manager_util_unittest.cc",
"password_form_helper_unittest.mm",
"shared_password_controller_unittest.mm",
]
......
......@@ -171,10 +171,8 @@ source_set("unit_tests") {
configs += [ "//build/config/compiler:enable_arc" ]
testonly = true
sources = [
"credential_manager_unittest.mm",
"ios_chrome_password_check_manager_unittest.mm",
"ios_chrome_password_manager_client_unittest.mm",
"js_credential_manager_unittest.mm",
"password_controller_js_unittest.mm",
"password_controller_unittest.mm",
"well_known_change_password_tab_helper_unittest.mm",
......@@ -196,13 +194,10 @@ source_set("unit_tests") {
"//components/prefs",
"//components/prefs:test_support",
"//components/safe_browsing/core/common:safe_browsing_prefs",
"//components/security_state/ios",
"//components/ukm:test_support",
"//google_apis",
"//ios/chrome/browser/autofill",
"//ios/chrome/browser/browser_state:test_support",
"//ios/chrome/browser/passwords/test",
"//ios/chrome/browser/ssl",
"//ios/chrome/browser/ui/autofill/form_input_accessory",
"//ios/chrome/browser/ui/commands",
"//ios/chrome/browser/web:test_support",
......@@ -210,7 +205,6 @@ source_set("unit_tests") {
"//ios/testing:ocmock_support",
"//ios/web",
"//ios/web/public/js_messaging",
"//ios/web/public/security",
"//ios/web/public/test",
"//ios/web/public/test/fakes",
"//net:test_support",
......@@ -228,10 +222,8 @@ source_set("eg2_tests") {
"//build/config/ios:xctest_config",
]
testonly = true
sources = [ "credential_manager_egtest.mm" ]
deps = [
":eg_test_support+eg2",
":feature_flags",
"//base",
"//base/test:test_support",
"//components/password_manager/core/common",
......
// Copyright 2017 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.
#import <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#include <memory>
#include "base/bind.h"
#include "base/strings/utf_string_conversions.h"
#import "base/test/ios/wait_util.h"
#include "base/test/scoped_feature_list.h"
#include "components/password_manager/core/common/password_manager_pref_names.h"
#import "ios/chrome/browser/passwords/password_manager_app_interface.h"
#include "ios/chrome/browser/passwords/password_manager_features.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_app_interface.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/testing/earl_grey/app_launch_configuration.h"
#import "ios/testing/earl_grey/disabled_test_macros.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "ios/web/public/test/http_server/http_server.h"
#include "ios/web/public/test/http_server/http_server_util.h"
#include "net/test/embedded_test_server/embedded_test_server.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
#if defined(CHROME_EARL_GREY_2)
// TODO(crbug.com/1015113): The EG2 macro is breaking indexing for some reason
// without the trailing semicolon. For now, disable the extra semi warning
// so Xcode indexing works for the egtest.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wc++98-compat-extra-semi"
GREY_STUB_CLASS_IN_APP_MAIN_QUEUE(PasswordManagerAppInterface);
#endif // defined(CHROME_EARL_GREY_2)
namespace {
// Notification should be displayed for 3 seconds. 4 should be safe to check.
constexpr CFTimeInterval kDisappearanceTimeout = 4;
// Provides basic response for example page.
std::unique_ptr<net::test_server::HttpResponse> StandardResponse(
const net::test_server::HttpRequest& request) {
std::unique_ptr<net::test_server::BasicHttpResponse> http_response =
std::make_unique<net::test_server::BasicHttpResponse>();
http_response->set_code(net::HTTP_OK);
http_response->set_content(
"<head><title>Example website</title></head>"
"<body>You are here.</body>");
return std::move(http_response);
}
} // namespace
// This class tests UI behavior for Credential Manager.
// TODO(crbug.com/435048): Add EG test for save/update password prompt.
// TODO(crbug.com/435048): When account chooser and first run experience dialog
// are implemented, test them too.
@interface CredentialManagerEGTest : ChromeTestCase
@end
@implementation CredentialManagerEGTest {
base::test::ScopedFeatureList _featureList;
}
- (void)setUp {
_featureList.InitAndEnableFeature(features::kCredentialManager);
[super setUp];
// Set up server.
self.testServer->RegisterRequestHandler(base::Bind(&StandardResponse));
GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
}
- (void)tearDown {
[PasswordManagerAppInterface clearCredentials];
[super tearDown];
}
- (AppLaunchConfiguration)appConfigurationForTestCase {
AppLaunchConfiguration config;
config.features_enabled.push_back(features::kCredentialManager);
return config;
}
#pragma mark - Utils
// Loads simple page on localhost and stores an example PasswordCredential.
- (void)loadSimplePageAndStoreACredential {
// Loads simple page. It is on localhost so it is considered a secure context.
const GURL URL = self.testServer->GetURL("/example");
[ChromeEarlGrey loadURL:URL];
[ChromeEarlGrey waitForWebStateContainingText:"You are here."];
NSError* error = [PasswordManagerAppInterface
storeCredentialWithUsername:@"johndoe@example.com"
password:@"ilovejanedoe123"];
GREYAssertNil(error, error.localizedDescription);
}
#pragma mark - Tests
// Tests that notification saying "Signing is as ..." appears on auto sign-in.
- (void)testNotificationAppearsOnAutoSignIn {
// TODO(crbug.com/786960): re-enable when fixed. Tests may pass on EG2
#if defined(CHROME_EARL_GREY_1)
EARL_GREY_TEST_DISABLED(@"Fails on iOS 11.0.");
#endif
// Set Autosignin preferences
[ChromeEarlGrey setBoolValue:YES
forUserPref:password_manager::prefs::
kWasAutoSignInFirstRunExperienceShown];
[ChromeEarlGrey
setBoolValue:YES
forUserPref:password_manager::prefs::kCredentialsEnableAutosignin];
[self loadSimplePageAndStoreACredential];
// Call get() from JavaScript.
NSError* error = nil;
NSString* result = [ChromeEarlGreyAppInterface
executeJavaScript:@"typeof navigator.credentials.get({password: true})"
error:&error];
GREYAssertTrue([result isEqual:@"object"],
@"Unexpected error occurred when executing JavaScript.");
GREYAssertTrue(!error,
@"Unexpected error occurred when executing JavaScript.");
// Matches the UILabel by its accessibilityLabel.
id<GREYMatcher> matcher =
grey_allOf(grey_accessibilityLabel(@"Signing in as johndoe@example.com"),
grey_accessibilityTrait(UIAccessibilityTraitStaticText), nil);
// Wait for notification to appear.
ConditionBlock waitForAppearance = ^{
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:matcher] assertWithMatcher:grey_notNil()
error:&error];
return error == nil;
};
// Gives some time for the notification to appear.
GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, waitForAppearance),
@"Notification did not appear");
// Wait for the notification to disappear.
ConditionBlock waitForDisappearance = ^{
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:matcher]
assertWithMatcher:grey_sufficientlyVisible()
error:&error];
return error == nil;
};
// Ensures that notification disappears after time limit.
GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(kDisappearanceTimeout,
waitForDisappearance),
@"Notification did not disappear");
}
// Tests that when navigator.credentials.get() was called from inactive tab, the
// autosign-in notification appears once tab becomes active.
- (void)testNotificationAppearsWhenTabIsActive {
// TODO(crbug.com/786960): re-enable when fixed. Tests may pass on EG2
#if defined(CHROME_EARL_GREY_1)
EARL_GREY_TEST_DISABLED(@"Fails on iOS 11.0.");
#endif
// Set Autosignin preferences
[ChromeEarlGrey setBoolValue:YES
forUserPref:password_manager::prefs::
kWasAutoSignInFirstRunExperienceShown];
[ChromeEarlGrey
setBoolValue:YES
forUserPref:password_manager::prefs::kCredentialsEnableAutosignin];
[self loadSimplePageAndStoreACredential];
// Open new tab.
[ChromeEarlGreyUI openNewTab];
[ChromeEarlGrey waitForMainTabCount:2];
[PasswordManagerAppInterface getCredentialsInTabAtIndex:0];
// Matches the UILabel by its accessibilityLabel.
id<GREYMatcher> matcher = chrome_test_util::StaticTextWithAccessibilityLabel(
@"Signing in as johndoe@example.com");
// Wait for notification to appear.
ConditionBlock waitForAppearance = ^{
NSError* error = nil;
[[EarlGrey selectElementWithMatcher:matcher]
assertWithMatcher:grey_sufficientlyVisible()
error:&error];
return error == nil;
};
// Check that notification doesn't appear in current tab.
GREYAssertFalse(
base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, waitForAppearance),
@"Notification appeared in wrong tab");
// Switch to previous tab.
[ChromeEarlGrey selectTabAtIndex:0];
// Check that the notification has appeared.
GREYAssert(base::test::ios::WaitUntilConditionOrTimeout(
base::test::ios::kWaitForUIElementTimeout, waitForAppearance),
@"Notification did not appear");
}
@end
// Copyright 2017 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 "ios/chrome/browser/passwords/js_credential_manager.h"
#include "base/strings/sys_string_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "ios/web/public/test/web_js_test.h"
#include "ios/web/public/test/web_test_with_web_state.h"
#include "url/origin.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
constexpr char kTestIconUrl[] = "https://www.google.com/favicon.ico";
constexpr char kTestWebOrigin[] = "https://example.com";
} // namespace
// Tests for js_credential_manager.mm file. Its functions
// RejectCredentialPromiseWith* and ResolveCredentialPromiseWith* are tested as
// follows: 1. |credential_manager| early script is injected to the page. 2. A
// Promise is created. Depending on a test, it's |resolve| or |reject|
// function is expected to be called. That function stores the result or error
// in variable(s) with test_* prefix.
// 3. To check if JavaScript executed by JsCredentialManager was correct, we
// check the values of test_* variable(s).
class JsCredentialManagerTest
: public web::WebJsTest<web::WebTestWithWebState> {
public:
JsCredentialManagerTest()
: web::WebJsTest<web::WebTestWithWebState>(@[ @"credential_manager" ]) {}
void SetUp() override {
WebTestWithWebState::SetUp();
// Load empty HTML and inject |credential_manager| early script.
LoadHtmlAndInject(@"<html></html>");
}
DISALLOW_COPY_AND_ASSIGN(JsCredentialManagerTest);
};
// Tests that ResolveCredentialPromiseWithCredentialInfo resolves the promise
// with JavaScript PasswordCredential object containing correct values.
TEST_F(JsCredentialManagerTest, ResolveWithPasswordCredential) {
// Let requestId be 3.
ExecuteJavaScript(
@"__gCrWeb.credentialManager.createPromise_(3)."
"then(function(result) {"
" test_credential_ = result;"
"});");
password_manager::CredentialInfo credential;
credential.type = password_manager::CredentialType::CREDENTIAL_TYPE_PASSWORD;
credential.id = base::ASCIIToUTF16("test@google.com");
credential.name = base::ASCIIToUTF16("Test User");
credential.icon = GURL(base::ASCIIToUTF16(kTestIconUrl));
credential.password = base::ASCIIToUTF16("32njk \\4 s3cr3t \\n' 1");
ResolveCredentialPromiseWithCredentialInfo(web_state(), 3, credential);
// Wait for Promise to be resolved before checking the values.
WaitForCondition(^{
return static_cast<bool>(
[@"object" isEqual:ExecuteJavaScript(@"typeof test_credential_")]);
});
EXPECT_NSEQ(@"password", ExecuteJavaScript(@"test_credential_.type"));
EXPECT_NSEQ(@"test@google.com", ExecuteJavaScript(@"test_credential_.id"));
EXPECT_NSEQ(@"Test User", ExecuteJavaScript(@"test_credential_.name"));
EXPECT_NSEQ(base::SysUTF16ToNSString(base::ASCIIToUTF16(kTestIconUrl)),
ExecuteJavaScript(@"test_credential_.iconURL"));
EXPECT_NSEQ(@"32njk \\4 s3cr3t \\n' 1",
ExecuteJavaScript(@"test_credential_.password"));
}
// Tests that ResolveCredentialPromiseWithCredentialInfo resolves the promise
// with JavaScript FederatedCredential object containing correct values.
TEST_F(JsCredentialManagerTest, ResolveWithFederatedCredential) {
// Let requestId be 3.
ExecuteJavaScript(
@"__gCrWeb.credentialManager.createPromise_(3)."
"then(function(result) {"
" test_credential_ = result;"
"});");
password_manager::CredentialInfo credential;
credential.type = password_manager::CredentialType::CREDENTIAL_TYPE_FEDERATED;
credential.id = base::ASCIIToUTF16("test@google.com");
credential.name = base::ASCIIToUTF16("Test User");
credential.icon = GURL(base::ASCIIToUTF16(kTestIconUrl));
credential.federation = url::Origin::Create(GURL(kTestWebOrigin));
ResolveCredentialPromiseWithCredentialInfo(web_state(), 3, credential);
// Wait for Promise to be resolved before checking the values.
WaitForCondition(^{
return static_cast<bool>(
[@"object" isEqual:ExecuteJavaScript(@"typeof test_credential_")]);
});
EXPECT_NSEQ(@"federated", ExecuteJavaScript(@"test_credential_.type"));
EXPECT_NSEQ(@"test@google.com", ExecuteJavaScript(@"test_credential_.id"));
EXPECT_NSEQ(@"Test User", ExecuteJavaScript(@"test_credential_.name"));
EXPECT_NSEQ(base::SysUTF16ToNSString(base::ASCIIToUTF16(kTestIconUrl)),
ExecuteJavaScript(@"test_credential_.iconURL"));
EXPECT_NSEQ(base::SysUTF16ToNSString(base::ASCIIToUTF16(kTestWebOrigin)),
ExecuteJavaScript(@"test_credential_.provider"));
}
// Tests that ResolveCredentialPromiseWithCredentialInfo resolves the promise
// with void when optional CredentialInfo is null.
TEST_F(JsCredentialManagerTest, ResolveWithNullCredential) {
// Let requestId be 3.
ExecuteJavaScript(
@"__gCrWeb.credentialManager.createPromise_(3)."
"then(function(result) {"
" test_result_ = (result == undefined);"
"});");
base::Optional<password_manager::CredentialInfo> null_credential;
ResolveCredentialPromiseWithCredentialInfo(web_state(), 3, null_credential);
// Wait for Promise to be resolved before checking the values.
WaitForCondition(^{
return static_cast<bool>(
[@"boolean" isEqual:ExecuteJavaScript(@"typeof test_result_")]);
});
EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_"));
}
// Tests that ResolveCredentialPromiseWithUndefined resolves the promise with no
// value.
TEST_F(JsCredentialManagerTest, ResolveWithUndefined) {
// Let requestId be equal 5.
// Only when the promise is resolved with undefined, will the
// |test_result_| be true.
ExecuteJavaScript(
@"__gCrWeb.credentialManager.createPromise_(5)."
"then(function(result) {"
" test_result_ = (result == undefined);"
"});");
ResolveCredentialPromiseWithUndefined(web_state(), 5);
// Wait for Promise to be resolved before checking the values.
WaitForCondition(^{
return static_cast<bool>(
[@"boolean" isEqual:ExecuteJavaScript(@"typeof test_result_")]);
});
EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_"));
}
// Tests that RejectCredentialPromiseWithTypeError rejects the promise with
// TypeError and correct message.
TEST_F(JsCredentialManagerTest, RejectWithTypeError) {
// Let requestId be equal 100.
ExecuteJavaScript(
@"__gCrWeb.credentialManager.createPromise_(100)."
"catch(function(reason) {"
" test_result_valid_type_ = (reason instanceof TypeError);"
" test_result_message_ = reason.message;"
"});");
RejectCredentialPromiseWithTypeError(
web_state(), 100, base::ASCIIToUTF16("message with \"quotation\" marks"));
// Wait for Promise to be rejected before checking the values.
WaitForCondition(^{
return static_cast<bool>(
[@"string" isEqual:ExecuteJavaScript(@"typeof test_result_message_")]);
});
EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_valid_type_"));
EXPECT_NSEQ(@"message with \"quotation\" marks",
ExecuteJavaScript(@"test_result_message_"));
}
// Tests that RejectCredentialPromiseWithInvalidStateError rejects the promise
// with DOMException(message, INVALID_STATE_ERR), where |message| is correct
// message taken as argument.
TEST_F(JsCredentialManagerTest, RejectWithInvalidState) {
// Let requestId be 0.
ExecuteJavaScript(
@"__gCrWeb.credentialManager.createPromise_(0)."
"catch(function(reason) {"
" test_result_valid_type_ ="
" (reason.name == DOMException.INVALID_STATE_ERR);"
" test_result_message_ = reason.message;"
"});");
RejectCredentialPromiseWithInvalidStateError(
web_state(), 0, base::ASCIIToUTF16("A 'get()' request is pending"));
// Wait for Promise to be rejected before checking the values.
WaitForCondition(^{
return static_cast<bool>(
[@"string" isEqual:ExecuteJavaScript(@"typeof test_result_message_")]);
});
EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_valid_type_"));
EXPECT_NSEQ(@"A 'get()' request is pending",
ExecuteJavaScript(@"test_result_message_"));
}
// Tests that RejectCredentialPromiseWithNotSupportedError rejects the promise
// with DOMException(message, NOT_SUPPORTED_ERR), where |message| is correct
// message taken as argument.
TEST_F(JsCredentialManagerTest, RejectWithNotSupportedError) {
// Let requestId be 0.
ExecuteJavaScript(
@"__gCrWeb.credentialManager.createPromise_(0)."
"catch(function(reason) {"
" test_result_valid_type_ ="
" (reason.name == DOMException.NOT_SUPPORTED_ERR);"
" test_result_message_ = reason.message;"
"});");
RejectCredentialPromiseWithNotSupportedError(
web_state(), 0,
base::ASCIIToUTF16(
"An error occured while talking to the credential manager."));
// Wait for Promise to be rejected before checking the values.
WaitForCondition(^{
return static_cast<bool>(
[@"string" isEqual:ExecuteJavaScript(@"typeof test_result_message_")]);
});
EXPECT_NSEQ(@YES, ExecuteJavaScript(@"test_result_valid_type_"));
EXPECT_NSEQ(@"An error occured while talking to the credential manager.",
ExecuteJavaScript(@"test_result_message_"));
}
......@@ -22,7 +22,6 @@
#include "components/strings/grit/components_strings.h"
#include "ios/chrome/browser/browser_state/test_chrome_browser_state.h"
#include "ios/chrome/browser/chrome_url_constants.h"
#include "ios/chrome/browser/passwords/password_manager_features.h"
#import "ios/chrome/browser/safe_browsing/safe_browsing_blocking_page.h"
#import "ios/chrome/browser/safe_browsing/safe_browsing_error.h"
#import "ios/chrome/browser/safe_browsing/safe_browsing_unsafe_resource_container.h"
......@@ -176,29 +175,6 @@ TEST_F(ChromeWebClientTest, WKWebViewEarlyPageScriptAutofillController) {
web_view, @"typeof __gCrWeb.autofill"));
}
// Tests that ChromeWebClient provides credential manager script for WKWebView
// if and only if the feature is enabled.
TEST_F(ChromeWebClientTest, WKWebViewEarlyPageScriptCredentialManager) {
// Chrome scripts rely on __gCrWeb object presence.
WKWebView* web_view = web::BuildWKWebView(CGRectZero, browser_state());
web::test::ExecuteJavaScript(web_view, @"__gCrWeb = {};");
web::ScopedTestingWebClient web_client(std::make_unique<ChromeWebClient>());
NSString* script =
web_client.Get()->GetDocumentStartScriptForMainFrame(browser_state());
web::test::ExecuteJavaScript(web_view, script);
EXPECT_NSEQ(@"undefined", web::test::ExecuteJavaScript(
web_view, @"typeof navigator.credentials"));
base::test::ScopedFeatureList feature_list;
feature_list.InitAndEnableFeature(features::kCredentialManager);
script =
web_client.Get()->GetDocumentStartScriptForMainFrame(browser_state());
web::test::ExecuteJavaScript(web_view, script);
EXPECT_NSEQ(@"object", web::test::ExecuteJavaScript(
web_view, @"typeof navigator.credentials"));
}
// Tests PrepareErrorPage wth non-post, not Off The Record error.
TEST_F(ChromeWebClientTest, PrepareErrorPageNonPostNonOtr) {
ChromeWebClient web_client;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment