REGRESSION(r226396) DataInteractionTests: ContentEditableToContentEditable and Conten...
[WebKit-https.git] / Tools / TestWebKitAPI / Tests / ios / WKWebViewAutofillTests.mm
1 /*
2  * Copyright (C) 2017 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if WK_API_ENABLED && PLATFORM(IOS)
29
30 #import "PlatformUtilities.h"
31 #import "TestWKWebView.h"
32 #import "UIKitSPI.h"
33 #import <WebKit/WKWebViewPrivate.h>
34 #import <WebKit/_WKFocusedElementInfo.h>
35 #import <WebKit/_WKInputDelegate.h>
36 #import <wtf/BlockPtr.h>
37
38 #if !__has_include(<UIKit/UITextAutofillSuggestion.h>)
39 // FIXME: This can be safely removed once <rdar://problem/34583628> lands in the SDK.
40 @implementation UITextAutofillSuggestion
41 - (instancetype)initWithUsername:(NSString *)username password:(NSString *)password
42 {
43     self = [super init];
44     if (self) {
45         _username = username;
46         _password = password;
47     }
48     return self;
49 }
50
51 + (instancetype)autofillSuggestionWithUsername:(NSString *)username password:(NSString *)password
52 {
53     return [[self alloc] initWithUsername:username password:password];
54 }
55 @end
56 #endif
57
58 typedef UIView <UITextInputTraits_Private_Proposed_SPI_34583628> AutofillInputView;
59
60 @interface TestInputDelegate : NSObject <_WKInputDelegate>
61 @property (nonatomic) BOOL inputSessionRequiresUserInteraction;
62 @end
63
64 @implementation TestInputDelegate
65
66 - (instancetype)init
67 {
68     if (self = [super init])
69         _inputSessionRequiresUserInteraction = NO;
70
71     return self;
72 }
73
74 - (BOOL)_webView:(WKWebView *)webView focusShouldStartInputSession:(id <_WKFocusedElementInfo>)info
75 {
76     return !self.inputSessionRequiresUserInteraction || info.userInitiated;
77 }
78
79 @end
80
81 @interface AutofillTestView : TestWKWebView
82 @end
83
84 @implementation AutofillTestView {
85     RetainPtr<TestInputDelegate> _testDelegate;
86 }
87
88 - (instancetype)initWithFrame:(CGRect)frame
89 {
90     if (!(self = [super initWithFrame:frame]))
91         return nil;
92
93     _testDelegate = adoptNS([[TestInputDelegate alloc] init]);
94     self._inputDelegate = _testDelegate.get();
95     return self;
96 }
97
98 - (AutofillInputView *)_autofillInputView
99 {
100     return (AutofillInputView *)self.textInputContentView;
101 }
102
103 - (BOOL)textInputHasAutofillContext
104 {
105     [self waitForNextPresentationUpdate];
106     NSURL *url = [self._autofillInputView._autofillContext objectForKey:@"_WebViewURL"];
107     if (![url isKindOfClass:[NSURL class]])
108         return NO;
109
110     EXPECT_WK_STREQ([self stringByEvaluatingJavaScript:@"document.URL"], url.absoluteString);
111     return YES;
112 }
113
114 @end
115
116 namespace TestWebKitAPI {
117
118 TEST(WKWebViewAutofillTests, UsernameAndPasswordField)
119 {
120     auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
121     [webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input id='password' type='password'>"];
122     [webView stringByEvaluatingJavaScript:@"user.focus()"];
123     EXPECT_TRUE([webView textInputHasAutofillContext]);
124
125     [webView stringByEvaluatingJavaScript:@"password.focus()"];
126     EXPECT_TRUE([webView textInputHasAutofillContext]);
127
128     auto credentialSuggestion = [UITextAutofillSuggestion autofillSuggestionWithUsername:@"frederik" password:@"famos"];
129     [[webView _autofillInputView] insertTextSuggestion:credentialSuggestion];
130
131     EXPECT_WK_STREQ("famos", [webView stringByEvaluatingJavaScript:@"password.value"]);
132
133     [webView stringByEvaluatingJavaScript:@"document.activeElement.blur()"];
134     EXPECT_FALSE([webView textInputHasAutofillContext]);
135 }
136
137 TEST(WKWebViewAutofillTests, UsernameAndPasswordFieldSeparatedByRadioButton)
138 {
139     auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
140     [webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input type='radio' name='radio_button' value='radio'><input id='password' type='password'>"];
141     [webView stringByEvaluatingJavaScript:@"user.focus()"];
142     EXPECT_TRUE([webView textInputHasAutofillContext]);
143
144     [webView stringByEvaluatingJavaScript:@"password.focus()"];
145     EXPECT_TRUE([webView textInputHasAutofillContext]);
146
147     auto credentialSuggestion = [UITextAutofillSuggestion autofillSuggestionWithUsername:@"frederik" password:@"famos"];
148     [[webView _autofillInputView] insertTextSuggestion:credentialSuggestion];
149
150     EXPECT_WK_STREQ("frederik", [webView stringByEvaluatingJavaScript:@"user.value"]);
151     EXPECT_WK_STREQ("famos", [webView stringByEvaluatingJavaScript:@"password.value"]);
152
153     [webView stringByEvaluatingJavaScript:@"document.activeElement.blur()"];
154     EXPECT_FALSE([webView textInputHasAutofillContext]);
155 }
156
157 TEST(WKWebViewAutofillTests, TwoTextFields)
158 {
159     auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
160     [webView synchronouslyLoadHTMLString:@"<input id='text1' type='email'><input id='text2' type='text'>"];
161     [webView stringByEvaluatingJavaScript:@"text1.focus()"];
162     EXPECT_FALSE([webView textInputHasAutofillContext]);
163
164     [webView stringByEvaluatingJavaScript:@"text2.focus()"];
165     EXPECT_FALSE([webView textInputHasAutofillContext]);
166 }
167
168 TEST(WKWebViewAutofillTests, StandalonePasswordField)
169 {
170     auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
171     [webView synchronouslyLoadHTMLString:@"<input id='password' type='password'>"];
172     [webView stringByEvaluatingJavaScript:@"password.focus()"];
173     EXPECT_TRUE([webView textInputHasAutofillContext]);
174
175     auto credentialSuggestion = [UITextAutofillSuggestion autofillSuggestionWithUsername:@"frederik" password:@"famos"];
176     [[webView _autofillInputView] insertTextSuggestion:credentialSuggestion];
177
178     EXPECT_WK_STREQ("famos", [webView stringByEvaluatingJavaScript:@"password.value"]);
179
180     [webView stringByEvaluatingJavaScript:@"document.activeElement.blur()"];
181     EXPECT_FALSE([webView textInputHasAutofillContext]);
182 }
183
184 TEST(WKWebViewAutofillTests, StandaloneTextField)
185 {
186     auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
187     [webView synchronouslyLoadHTMLString:@"<input id='textfield' type='text'>"];
188     [webView stringByEvaluatingJavaScript:@"textfield.focus()"];
189     EXPECT_FALSE([webView textInputHasAutofillContext]);
190 }
191
192 TEST(WKWebViewAutofillTests, AccountCreationPage)
193 {
194     auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
195     [webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input id='password' type='password'><input id='confirm_password' type='password'>"];
196     [webView stringByEvaluatingJavaScript:@"user.focus()"];
197     EXPECT_FALSE([webView textInputHasAutofillContext]);
198
199     [webView stringByEvaluatingJavaScript:@"password.focus()"];
200     EXPECT_FALSE([webView textInputHasAutofillContext]);
201
202     [webView stringByEvaluatingJavaScript:@"confirm_password.focus()"];
203     EXPECT_FALSE([webView textInputHasAutofillContext]);
204 }
205
206 TEST(WKWebViewAutofillTests, AutofillRequiresInputSession)
207 {
208     auto webView = adoptNS([[AutofillTestView alloc] initWithFrame:CGRectMake(0, 0, 320, 500)]);
209     [(TestInputDelegate *)[webView _inputDelegate] setInputSessionRequiresUserInteraction:YES];
210     [webView synchronouslyLoadHTMLString:@"<input id='user' type='email'><input id='password' type='password'>"];
211     [webView stringByEvaluatingJavaScript:@"user.focus()"];
212
213     EXPECT_FALSE([webView textInputHasAutofillContext]);
214 }
215
216 } // namespace TestWebKitAPI
217
218 #endif // WK_API_ENABLED && PLATFORM(IOS)