| // 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 <ChromeWebView/ChromeWebView.h> |
| #import <Foundation/Foundation.h> |
| |
| #include "base/strings/stringprintf.h" |
| #include "base/strings/sys_string_conversions.h" |
| #import "base/test/ios/wait_util.h" |
| #import "ios/web_view/test/web_view_inttest_base.h" |
| #import "ios/web_view/test/web_view_test_util.h" |
| #import "net/base/mac/url_conversions.h" |
| #include "net/test/embedded_test_server/embedded_test_server.h" |
| #include "testing/gtest_mac.h" |
| #import "third_party/ocmock/OCMock/OCMock.h" |
| #include "url/gurl.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| using base::test::ios::kWaitForActionTimeout; |
| using base::test::ios::WaitUntilConditionOrTimeout; |
| |
| namespace ios_web_view { |
| |
| namespace { |
| NSString* const kTestFormName = @"FormName"; |
| NSString* const kTestFormID = @"FormID"; |
| NSString* const kTestFieldName = @"FieldName"; |
| NSString* const kTestFieldID = @"FieldID"; |
| NSString* const kTestFieldType = @"text"; |
| NSString* const kTestFieldValue = @"FieldValue"; |
| NSString* const kTestSubmitID = @"SubmitID"; |
| NSString* const kTestFormHtml = |
| [NSString stringWithFormat: |
| // Direct form to about:blank to avoid unnecessary navigation. |
| @"<form action='about:blank' name='%@' id='%@'>" |
| "<input type='text' name='%@' id='%@'/>" |
| "<input type='submit' id='%@'/>" |
| "</form>", |
| kTestFormName, |
| kTestFormID, |
| kTestFieldName, |
| kTestFieldID, |
| kTestSubmitID]; |
| } // namespace |
| |
| // Tests autofill features in CWVWebViews. |
| class WebViewAutofillTest : public WebViewInttestBase { |
| protected: |
| WebViewAutofillTest() : autofill_controller_(web_view_.autofillController) {} |
| |
| bool LoadTestPage() WARN_UNUSED_RESULT { |
| std::string html = base::SysNSStringToUTF8(kTestFormHtml); |
| main_frame_id_ = nil; |
| GURL url = GetUrlForPageWithHtmlBody(html); |
| return test::LoadUrl(web_view_, net::NSURLWithGURL(url)); |
| } |
| |
| bool SubmitForm() WARN_UNUSED_RESULT { |
| NSString* submit_script = |
| [NSString stringWithFormat:@"document.getElementById('%@').click();", |
| kTestSubmitID]; |
| NSError* submit_error = nil; |
| test::EvaluateJavaScript(web_view_, submit_script, &submit_error); |
| return !submit_error; |
| } |
| |
| bool SetFormFieldValue(NSString* value) WARN_UNUSED_RESULT { |
| NSString* set_value_script = [NSString |
| stringWithFormat:@"document.getElementById('%@').value = '%@';", |
| kTestFieldID, value]; |
| NSError* set_value_error = nil; |
| test::EvaluateJavaScript(web_view_, set_value_script, &set_value_error); |
| return !set_value_error; |
| } |
| |
| NSArray<CWVAutofillSuggestion*>* FetchSuggestions() { |
| __block bool suggestions_fetched = false; |
| __block NSArray<CWVAutofillSuggestion*>* fetched_suggestions = nil; |
| [autofill_controller_ |
| fetchSuggestionsForFormWithName:kTestFormName |
| fieldName:kTestFieldName |
| fieldIdentifier:kTestFieldID |
| fieldType:kTestFieldType |
| frameID:GetMainFrameId() |
| completionHandler:^( |
| NSArray<CWVAutofillSuggestion*>* suggestions) { |
| fetched_suggestions = suggestions; |
| suggestions_fetched = true; |
| }]; |
| EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { |
| return suggestions_fetched; |
| })); |
| return fetched_suggestions; |
| } |
| |
| NSString* GetMainFrameId() { |
| if (main_frame_id_) { |
| return main_frame_id_; |
| } |
| NSString* main_frame_id_script = @"__gCrWeb.message.getFrameId();"; |
| NSError* main_frame_id_error = nil; |
| main_frame_id_ = test::EvaluateJavaScript(web_view_, main_frame_id_script, |
| &main_frame_id_error); |
| return main_frame_id_; |
| } |
| |
| CWVAutofillController* autofill_controller_; |
| NSString* main_frame_id_ = nil; |
| }; |
| |
| // Tests that CWVAutofillControllerDelegate receives callbacks. |
| TEST_F(WebViewAutofillTest, TestDelegateCallbacks) { |
| ASSERT_TRUE(test_server_->Start()); |
| ASSERT_TRUE(LoadTestPage()); |
| ASSERT_TRUE(SetFormFieldValue(kTestFieldValue)); |
| |
| id delegate = OCMProtocolMock(@protocol(CWVAutofillControllerDelegate)); |
| autofill_controller_.delegate = delegate; |
| |
| [[delegate expect] autofillController:autofill_controller_ |
| didFocusOnFieldWithName:kTestFieldName |
| fieldIdentifier:kTestFieldID |
| fieldType:kTestFieldType |
| formName:kTestFormName |
| frameID:[OCMArg any] |
| value:kTestFieldValue]; |
| NSString* focus_script = [NSString |
| stringWithFormat:@"document.getElementById('%@').focus();", kTestFieldID]; |
| NSError* focus_error = nil; |
| test::EvaluateJavaScript(web_view_, focus_script, &focus_error); |
| ASSERT_NSEQ(nil, focus_error); |
| [delegate verifyWithDelay:kWaitForActionTimeout]; |
| |
| [[delegate expect] autofillController:autofill_controller_ |
| didBlurOnFieldWithName:kTestFieldName |
| fieldIdentifier:kTestFieldID |
| fieldType:kTestFieldType |
| formName:kTestFormName |
| frameID:[OCMArg any] |
| value:kTestFieldValue]; |
| NSString* blur_script = |
| [NSString stringWithFormat: |
| @"var event = new Event('blur', {bubbles:true});" |
| "document.getElementById('%@').dispatchEvent(event);", |
| kTestFieldID]; |
| NSError* blur_error = nil; |
| test::EvaluateJavaScript(web_view_, blur_script, &blur_error); |
| ASSERT_NSEQ(nil, blur_error); |
| [delegate verifyWithDelay:kWaitForActionTimeout]; |
| |
| [[delegate expect] autofillController:autofill_controller_ |
| didInputInFieldWithName:kTestFieldName |
| fieldIdentifier:kTestFieldID |
| fieldType:kTestFieldType |
| formName:kTestFormName |
| frameID:[OCMArg any] |
| value:kTestFieldValue]; |
| // The 'input' event listener defined in form.js is only called during the |
| // bubbling phase. |
| NSString* input_script = |
| [NSString stringWithFormat: |
| @"var event = new Event('input', {'bubbles': true});" |
| "document.getElementById('%@').dispatchEvent(event);", |
| kTestFieldID]; |
| NSError* input_error = nil; |
| test::EvaluateJavaScript(web_view_, input_script, &input_error); |
| ASSERT_NSEQ(nil, input_error); |
| [delegate verifyWithDelay:kWaitForActionTimeout]; |
| |
| [[delegate expect] autofillController:autofill_controller_ |
| didSubmitFormWithName:kTestFormName |
| userInitiated:NO |
| isMainFrame:YES]; |
| // The 'submit' event listener defined in form.js is only called during the |
| // bubbling phase. |
| NSString* submit_script = |
| [NSString stringWithFormat: |
| @"var event = new Event('submit', {'bubbles': true});" |
| "document.getElementById('%@').dispatchEvent(event);", |
| kTestFormID]; |
| NSError* submit_error = nil; |
| test::EvaluateJavaScript(web_view_, submit_script, &submit_error); |
| ASSERT_NSEQ(nil, submit_error); |
| [delegate verifyWithDelay:kWaitForActionTimeout]; |
| } |
| |
| // Tests that CWVAutofillController can fetch, fill, and clear suggestions. |
| TEST_F(WebViewAutofillTest, TestSuggestionFetchFillClear) { |
| ASSERT_TRUE(test_server_->Start()); |
| ASSERT_TRUE(LoadTestPage()); |
| ASSERT_TRUE(SetFormFieldValue(kTestFieldValue)); |
| ASSERT_TRUE(SubmitForm()); |
| ASSERT_TRUE(LoadTestPage()); |
| |
| NSArray<CWVAutofillSuggestion*>* fetched_suggestions = FetchSuggestions(); |
| EXPECT_EQ(1U, fetched_suggestions.count); |
| CWVAutofillSuggestion* fetched_suggestion = fetched_suggestions.firstObject; |
| EXPECT_NSEQ(kTestFieldValue, fetched_suggestion.value); |
| EXPECT_NSEQ(kTestFormName, fetched_suggestion.formName); |
| EXPECT_NSEQ(kTestFieldName, fetched_suggestion.fieldName); |
| EXPECT_NSEQ(GetMainFrameId(), fetched_suggestion.frameID); |
| |
| // The input element needs to be focused before it can be filled or cleared. |
| NSString* focus_script = [NSString |
| stringWithFormat:@"document.getElementById('%@').focus()", kTestFieldID]; |
| NSError* focus_error = nil; |
| test::EvaluateJavaScript(web_view_, focus_script, &focus_error); |
| ASSERT_NSEQ(nil, focus_error); |
| |
| [autofill_controller_ fillSuggestion:fetched_suggestion |
| completionHandler:nil]; |
| NSString* filled_script = [NSString |
| stringWithFormat:@"document.getElementById('%@').value", kTestFieldID]; |
| __block NSError* filled_error = nil; |
| EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { |
| NSString* filled_value = |
| test::EvaluateJavaScript(web_view_, filled_script, &filled_error); |
| // If there is an error, early return so the ASSERT catch the error. |
| if (filled_error) |
| return true; |
| return [fetched_suggestion.value isEqualToString:filled_value]; |
| })); |
| ASSERT_NSEQ(nil, filled_error); |
| [autofill_controller_ clearFormWithName:kTestFormName |
| fieldIdentifier:kTestFieldID |
| frameID:GetMainFrameId() |
| completionHandler:nil]; |
| NSString* cleared_script = [NSString |
| stringWithFormat:@"document.getElementById('%@').value", kTestFieldID]; |
| __block NSError* cleared_error = nil; |
| EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { |
| NSString* current_value = |
| test::EvaluateJavaScript(web_view_, cleared_script, &cleared_error); |
| // If there is an error, early return so the ASSERT catch the error. |
| if (cleared_error) |
| return true; |
| return [current_value isEqualToString:@""]; |
| })); |
| ASSERT_NSEQ(nil, cleared_error); |
| } |
| |
| // Tests that CWVAutofillController can remove a suggestion. |
| TEST_F(WebViewAutofillTest, TestSuggestionFetchRemoveFetch) { |
| ASSERT_TRUE(test_server_->Start()); |
| ASSERT_TRUE(LoadTestPage()); |
| ASSERT_TRUE(SetFormFieldValue(kTestFieldValue)); |
| ASSERT_TRUE(SubmitForm()); |
| ASSERT_TRUE(LoadTestPage()); |
| |
| NSArray* fetched_suggestions_after_creating = FetchSuggestions(); |
| EXPECT_EQ(1U, fetched_suggestions_after_creating.count); |
| |
| CWVAutofillSuggestion* suggestion_to_remove = |
| fetched_suggestions_after_creating.firstObject; |
| [autofill_controller_ removeSuggestion:suggestion_to_remove]; |
| |
| NSArray* fetched_suggestions_after_removing = FetchSuggestions(); |
| EXPECT_EQ(0U, fetched_suggestions_after_removing.count); |
| } |
| |
| } // namespace ios_web_view |