OLD | NEW |
(Empty) | |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. |
| 4 |
| 5 #import <XCTest/XCTest.h> |
| 6 |
| 7 #include "base/strings/sys_string_conversions.h" |
| 8 #include "components/strings/grit/components_strings.h" |
| 9 #include "ios/chrome/browser/ui/ui_util.h" |
| 10 #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" |
| 11 #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" |
| 12 #import "ios/chrome/test/earl_grey/chrome_matchers.h" |
| 13 #import "ios/chrome/test/earl_grey/chrome_test_case.h" |
| 14 #import "ios/testing/earl_grey/disabled_test_macros.h" |
| 15 #import "ios/web/public/test/http_server.h" |
| 16 #include "ios/web/public/test/http_server_util.h" |
| 17 |
| 18 namespace { |
| 19 |
| 20 const char* kHistoryTestUrl = |
| 21 "http://ios/testing/data/http_server_files/history.html"; |
| 22 const char* kNonPushedUrl = |
| 23 "http://ios/testing/data/http_server_files/pony.html"; |
| 24 const char* kReplaceStateHashWithObjectURL = |
| 25 "http://ios/testing/data/http_server_files/history.html#replaceWithObject"; |
| 26 const char* kPushStateHashStringURL = |
| 27 "http://ios/testing/data/http_server_files/history.html#string"; |
| 28 const char* kReplaceStateHashStringURL = |
| 29 "http://ios/testing/data/http_server_files/history.html#replace"; |
| 30 const char* kPushStatePathURL = |
| 31 "http://ios/testing/data/http_server_files/path"; |
| 32 const char* kReplaceStateRootPathSpaceURL = "http://ios/rep lace"; |
| 33 |
| 34 // Matcher for the navigate forward button. |
| 35 id<GREYMatcher> forwardButton() { |
| 36 return chrome_test_util::buttonWithAccessibilityLabelId(IDS_ACCNAME_FORWARD); |
| 37 } |
| 38 // Matcher for the navigate backward button. |
| 39 id<GREYMatcher> backButton() { |
| 40 return chrome_test_util::buttonWithAccessibilityLabelId(IDS_ACCNAME_BACK); |
| 41 } |
| 42 } // namespace |
| 43 |
| 44 // Tests for pushState/replaceState navigations. |
| 45 @interface PushAndReplaceStateNavigationTestCase : ChromeTestCase |
| 46 @end |
| 47 |
| 48 @implementation PushAndReplaceStateNavigationTestCase |
| 49 |
| 50 // Tests calling history.pushState() multiple times and navigating back/forward. |
| 51 - (void)testHtml5HistoryPushStateThenGoBackAndForward { |
| 52 const GURL pushStateHashWithObjectURL = web::test::HttpServer::MakeUrl( |
| 53 "http://ios/testing/data/http_server_files/history.html#pushWithObject"); |
| 54 const GURL pushStateRootPathURL = |
| 55 web::test::HttpServer::MakeUrl("http://ios/rootpath"); |
| 56 const GURL pushStatePathSpaceURL = |
| 57 web::test::HttpServer::MakeUrl("http://ios/pa%20th"); |
| 58 web::test::SetUpFileBasedHttpServer(); |
| 59 [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kHistoryTestUrl)]; |
| 60 |
| 61 // Push 3 URLs. Verify that the URL changed and the status was updated. |
| 62 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateHashWithObject"]; |
| 63 [self assertStatusText:@"pushStateHashWithObject" |
| 64 withURL:pushStateHashWithObjectURL |
| 65 pageLoaded:NO]; |
| 66 |
| 67 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateRootPath"]; |
| 68 [self assertStatusText:@"pushStateRootPath" |
| 69 withURL:pushStateRootPathURL |
| 70 pageLoaded:NO]; |
| 71 |
| 72 [ChromeEarlGrey tapWebViewElementWithID:@"pushStatePathSpace"]; |
| 73 [self assertStatusText:@"pushStatePathSpace" |
| 74 withURL:pushStatePathSpaceURL |
| 75 pageLoaded:NO]; |
| 76 |
| 77 // Go back and check that the page doesn't load and the status text is updated |
| 78 // by the popstate event. |
| 79 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 80 [self assertStatusText:@"pushStateRootPath" |
| 81 withURL:pushStateRootPathURL |
| 82 pageLoaded:NO]; |
| 83 |
| 84 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 85 [self assertStatusText:@"pushStateHashWithObject" |
| 86 withURL:pushStateHashWithObjectURL |
| 87 pageLoaded:NO]; |
| 88 |
| 89 [ChromeEarlGrey tapWebViewElementWithID:@"goBack"]; |
| 90 const GURL historyTestURL = web::test::HttpServer::MakeUrl(kHistoryTestUrl); |
| 91 [self assertStatusText:NULL withURL:historyTestURL pageLoaded:NO]; |
| 92 |
| 93 // Go forward 2 pages and check that the page doesn't load and the status text |
| 94 // is updated by the popstate event. |
| 95 [ChromeEarlGrey tapWebViewElementWithID:@"goForward2"]; |
| 96 [self assertStatusText:@"pushStateRootPath" |
| 97 withURL:pushStateRootPathURL |
| 98 pageLoaded:NO]; |
| 99 } |
| 100 |
| 101 // Tests that calling replaceState() changes the current history entry. |
| 102 - (void)testHtml5HistoryReplaceStateThenGoBackAndForward { |
| 103 web::test::SetUpFileBasedHttpServer(); |
| 104 const GURL initialURL = web::test::HttpServer::MakeUrl(kNonPushedUrl); |
| 105 [ChromeEarlGrey loadURL:initialURL]; |
| 106 [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kHistoryTestUrl)]; |
| 107 |
| 108 // Replace the URL and go back then forward. |
| 109 const GURL replaceStateHashWithObjectURL = |
| 110 web::test::HttpServer::MakeUrl(kReplaceStateHashWithObjectURL); |
| 111 [ChromeEarlGrey tapWebViewElementWithID:@"replaceStateHashWithObject"]; |
| 112 [self assertStatusText:@"replaceStateHashWithObject" |
| 113 withURL:replaceStateHashWithObjectURL |
| 114 pageLoaded:NO]; |
| 115 |
| 116 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 117 [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText( |
| 118 initialURL.GetContent())] |
| 119 assertWithMatcher:grey_notNil()]; |
| 120 |
| 121 [[EarlGrey selectElementWithMatcher:forwardButton()] |
| 122 performAction:grey_tap()]; |
| 123 [self assertStatusText:@"replaceStateHashWithObject" |
| 124 withURL:replaceStateHashWithObjectURL |
| 125 pageLoaded:YES]; |
| 126 |
| 127 // Push URL then replace it. Do this twice. |
| 128 const GURL pushStateHashStringURL = |
| 129 web::test::HttpServer::MakeUrl(kPushStateHashStringURL); |
| 130 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateHashString"]; |
| 131 [self assertStatusText:@"pushStateHashString" |
| 132 withURL:pushStateHashStringURL |
| 133 pageLoaded:NO]; |
| 134 |
| 135 const GURL replaceStateHashStringURL = |
| 136 web::test::HttpServer::MakeUrl(kReplaceStateHashStringURL); |
| 137 [ChromeEarlGrey tapWebViewElementWithID:@"replaceStateHashString"]; |
| 138 [self assertStatusText:@"replaceStateHashString" |
| 139 withURL:replaceStateHashStringURL |
| 140 pageLoaded:NO]; |
| 141 |
| 142 const GURL pushStatePathURL = |
| 143 web::test::HttpServer::MakeUrl(kPushStatePathURL); |
| 144 [ChromeEarlGrey tapWebViewElementWithID:@"pushStatePath"]; |
| 145 [self assertStatusText:@"pushStatePath" |
| 146 withURL:pushStatePathURL |
| 147 pageLoaded:NO]; |
| 148 |
| 149 const GURL replaceStateRootPathSpaceURL = |
| 150 web::test::HttpServer::MakeUrl(kReplaceStateRootPathSpaceURL); |
| 151 [ChromeEarlGrey tapWebViewElementWithID:@"replaceStateRootPathSpace"]; |
| 152 [self assertStatusText:@"replaceStateRootPathSpace" |
| 153 withURL:replaceStateRootPathSpaceURL |
| 154 pageLoaded:NO]; |
| 155 |
| 156 // Go back and check URLs. |
| 157 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 158 [self assertStatusText:@"replaceStateHashString" |
| 159 withURL:replaceStateHashStringURL |
| 160 pageLoaded:NO]; |
| 161 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 162 [self assertStatusText:@"replaceStateHashWithObject" |
| 163 withURL:replaceStateHashWithObjectURL |
| 164 pageLoaded:NO]; |
| 165 |
| 166 // Go forward and check URL. |
| 167 [ChromeEarlGrey tapWebViewElementWithID:@"goForward2"]; |
| 168 [self assertStatusText:@"replaceStateRootPathSpace" |
| 169 withURL:replaceStateRootPathSpaceURL |
| 170 pageLoaded:NO]; |
| 171 } |
| 172 |
| 173 // Tests that page loads occur when navigating to or past a non-pushed URL. |
| 174 - (void)testHtml5HistoryNavigatingPastNonPushedURL { |
| 175 GURL nonPushedURL = web::test::HttpServer::MakeUrl(kNonPushedUrl); |
| 176 web::test::SetUpFileBasedHttpServer(); |
| 177 const GURL historyTestURL = web::test::HttpServer::MakeUrl(kHistoryTestUrl); |
| 178 [ChromeEarlGrey loadURL:historyTestURL]; |
| 179 |
| 180 // Push same URL twice. Verify that URL changed and the status was updated. |
| 181 const GURL pushStateHashStringURL = |
| 182 web::test::HttpServer::MakeUrl(kPushStateHashStringURL); |
| 183 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateHashString"]; |
| 184 [self assertStatusText:@"pushStateHashString" |
| 185 withURL:pushStateHashStringURL |
| 186 pageLoaded:NO]; |
| 187 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateHashString"]; |
| 188 [self assertStatusText:@"pushStateHashString" |
| 189 withURL:pushStateHashStringURL |
| 190 pageLoaded:NO]; |
| 191 |
| 192 // Load a non-pushed URL. |
| 193 [ChromeEarlGrey loadURL:nonPushedURL]; |
| 194 |
| 195 // Load history.html and push another URL. |
| 196 [ChromeEarlGrey loadURL:historyTestURL]; |
| 197 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateHashString"]; |
| 198 [self assertStatusText:@"pushStateHashString" |
| 199 withURL:pushStateHashStringURL |
| 200 pageLoaded:NO]; |
| 201 |
| 202 // At this point the history looks like this: |
| 203 // [NTP, history.html, #string, #string, nonPushedURL, history.html, #string] |
| 204 |
| 205 // Go back (to second history.html) and verify page did not load. |
| 206 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 207 [self assertStatusText:nil withURL:historyTestURL pageLoaded:NO]; |
| 208 |
| 209 // Go back twice (to second #string) and verify page did load. |
| 210 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 211 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 212 [self assertStatusText:nil withURL:pushStateHashStringURL pageLoaded:YES]; |
| 213 |
| 214 // Go back once (to first #string) and verify page did not load. |
| 215 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 216 [self assertStatusText:@"pushStateHashString" |
| 217 withURL:pushStateHashStringURL |
| 218 pageLoaded:NO]; |
| 219 |
| 220 // Go forward 4 entries at once (to third #string) and verify page did load. |
| 221 [ChromeEarlGrey tapWebViewElementWithID:@"goForward4"]; |
| 222 |
| 223 [self assertStatusText:nil withURL:pushStateHashStringURL pageLoaded:YES]; |
| 224 |
| 225 // Go back 4 entries at once (to first #string) and verify page did load. |
| 226 [ChromeEarlGrey tapWebViewElementWithID:@"goBack4"]; |
| 227 |
| 228 [self assertStatusText:NULL withURL:pushStateHashStringURL pageLoaded:YES]; |
| 229 } |
| 230 |
| 231 // Tests calling pushState with unicode characters. |
| 232 - (void)testHtml5HistoryPushUnicodeCharacters { |
| 233 const GURL pushStateUnicodeURLEncoded = web::test::HttpServer::MakeUrl( |
| 234 "http://ios/testing/data/http_server_files/" |
| 235 "history.html#unicode%E1%84%91"); |
| 236 const GURL pushStateUnicode2URLEncoded = web::test::HttpServer::MakeUrl( |
| 237 "http://ios/testing/data/http_server_files/" |
| 238 "history.html#unicode2%E2%88%A2"); |
| 239 std::string pushStateUnicodeLabel = "Action: pushStateUnicodeᄑ"; |
| 240 NSString* pushStateUnicodeStatus = @"pushStateUnicodeᄑ"; |
| 241 std::string pushStateUnicode2Label = "Action: pushStateUnicode2∢"; |
| 242 NSString* pushStateUnicode2Status = @"pushStateUnicode2∢"; |
| 243 |
| 244 web::test::SetUpFileBasedHttpServer(); |
| 245 [ChromeEarlGrey loadURL:web::test::HttpServer::MakeUrl(kHistoryTestUrl)]; |
| 246 |
| 247 // TODO(crbug.com/643458): The fact that the URL shows %-escaped is due to |
| 248 // NSURL escaping to make UIWebView/JS happy. See if it's possible to |
| 249 // represent differently such that it displays unescaped. |
| 250 // Do 2 push states with unicode characters. |
| 251 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateUnicode"]; |
| 252 [[EarlGrey |
| 253 selectElementWithMatcher:chrome_test_util::omniboxText( |
| 254 pushStateUnicodeURLEncoded.GetContent())] |
| 255 assertWithMatcher:grey_notNil()]; |
| 256 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText( |
| 257 pushStateUnicodeLabel)] |
| 258 assertWithMatcher:grey_notNil()]; |
| 259 |
| 260 [ChromeEarlGrey tapWebViewElementWithID:@"pushStateUnicode2"]; |
| 261 [[EarlGrey |
| 262 selectElementWithMatcher:chrome_test_util::omniboxText( |
| 263 pushStateUnicode2URLEncoded.GetContent())] |
| 264 assertWithMatcher:grey_notNil()]; |
| 265 [[EarlGrey selectElementWithMatcher:chrome_test_util::webViewContainingText( |
| 266 pushStateUnicode2Label)] |
| 267 assertWithMatcher:grey_notNil()]; |
| 268 |
| 269 // Do a push state without a unicode character. |
| 270 const GURL pushStatePathURL = |
| 271 web::test::HttpServer::MakeUrl(kPushStatePathURL); |
| 272 [ChromeEarlGrey tapWebViewElementWithID:@"pushStatePath"]; |
| 273 |
| 274 [self assertStatusText:@"pushStatePath" |
| 275 withURL:pushStatePathURL |
| 276 pageLoaded:NO]; |
| 277 |
| 278 // Go back and check the unicode in the URL and status. |
| 279 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 280 [self assertStatusText:pushStateUnicode2Status |
| 281 withURL:pushStateUnicode2URLEncoded |
| 282 pageLoaded:NO]; |
| 283 |
| 284 [[EarlGrey selectElementWithMatcher:backButton()] performAction:grey_tap()]; |
| 285 [self assertStatusText:pushStateUnicodeStatus |
| 286 withURL:pushStateUnicodeURLEncoded |
| 287 pageLoaded:NO]; |
| 288 } |
| 289 |
| 290 // Tests that pushState/replaceState handling properly handles <base>. |
| 291 - (void)testHtml5HistoryWithBase { |
| 292 std::map<GURL, std::string> responses; |
| 293 GURL originURL = |
| 294 web::test::HttpServer::MakeUrl("http://foo.com/foo/bar.html"); |
| 295 GURL pushResultURL = originURL.GetOrigin().Resolve("pushed/relative/url"); |
| 296 GURL replaceResultURL = |
| 297 originURL.GetOrigin().Resolve("replaced/relative/url"); |
| 298 |
| 299 // A simple HTML page with a base tag that makes all relative URLs |
| 300 // domain-relative, a button to trigger a relative pushState, and a button |
| 301 // to trigger a relative replaceState. |
| 302 NSString* baseTag = @"<base href=\"/\">"; |
| 303 NSString* pushAndReplaceButtons = |
| 304 @"<input type=\"button\" value=\"pushState\" " |
| 305 "id=\"pushState\" onclick=\"history.pushState(" |
| 306 "{}, 'Foo', './pushed/relative/url');\"><br>" |
| 307 "<input type=\"button\" value=\"replaceState\" " |
| 308 "id=\"replaceState\" onclick=\"history.replaceState(" |
| 309 "{}, 'Foo', './replaced/relative/url');\"><br>"; |
| 310 NSString* simplePage = |
| 311 @"<!doctype html><html><head>%@</head><body>%@</body></html>"; |
| 312 responses[originURL] = base::SysNSStringToUTF8( |
| 313 [NSString stringWithFormat:simplePage, baseTag, pushAndReplaceButtons]); |
| 314 web::test::SetUpSimpleHttpServer(responses); |
| 315 |
| 316 [ChromeEarlGrey loadURL:originURL]; |
| 317 [ChromeEarlGrey tapWebViewElementWithID:@"pushState"]; |
| 318 [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText( |
| 319 pushResultURL.GetContent())] |
| 320 assertWithMatcher:grey_notNil()]; |
| 321 |
| 322 [ChromeEarlGrey tapWebViewElementWithID:@"replaceState"]; |
| 323 [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText( |
| 324 replaceResultURL.GetContent())] |
| 325 assertWithMatcher:grey_notNil()]; |
| 326 } |
| 327 |
| 328 #pragma mark - Utility methods |
| 329 |
| 330 // Assert that status text |status| is displayed in the webview, that "onloaded" |
| 331 // text is displayed if pageLoaded is YES, and that the URL is as expected. |
| 332 - (void)assertStatusText:(NSString*)status |
| 333 withURL:(const GURL&)urlToVerify |
| 334 pageLoaded:(BOOL)pageLoaded { |
| 335 id<GREYMatcher> pageLoadedMatcher = |
| 336 pageLoaded ? chrome_test_util::webViewContainingText("onload") |
| 337 : chrome_test_util::webViewNotContainingText("onload"); |
| 338 [[EarlGrey selectElementWithMatcher:pageLoadedMatcher] |
| 339 assertWithMatcher:grey_notNil()]; |
| 340 |
| 341 if (status != NULL) { |
| 342 NSString* statusLabel = [NSString stringWithFormat:@"Action: %@", status]; |
| 343 [[EarlGrey |
| 344 selectElementWithMatcher:chrome_test_util::webViewContainingText( |
| 345 base::SysNSStringToUTF8(statusLabel))] |
| 346 assertWithMatcher:grey_notNil()]; |
| 347 } |
| 348 |
| 349 [[EarlGrey selectElementWithMatcher:chrome_test_util::omniboxText( |
| 350 urlToVerify.GetContent())] |
| 351 assertWithMatcher:grey_notNil()]; |
| 352 } |
| 353 |
| 354 @end |
OLD | NEW |