| // Copyright 2016 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 "ios/web/public/test/web_test_with_web_state.h" |
| |
| #include "base/run_loop.h" |
| #include "base/strings/sys_string_conversions.h" |
| #import "base/test/ios/wait_util.h" |
| #import "ios/web/navigation/navigation_manager_impl.h" |
| #include "ios/web/public/web_state/url_verification_constants.h" |
| #include "ios/web/public/web_state/web_state_observer.h" |
| #import "ios/web/web_state/ui/crw_web_controller.h" |
| #import "ios/web/web_state/web_state_impl.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| namespace { |
| // Returns CRWWebController for the given |web_state|. |
| CRWWebController* GetWebController(web::WebState* web_state) { |
| web::WebStateImpl* web_state_impl = |
| static_cast<web::WebStateImpl*>(web_state); |
| return web_state_impl->GetWebController(); |
| } |
| } // namespace |
| |
| namespace web { |
| |
| WebTestWithWebState::WebTestWithWebState() {} |
| |
| WebTestWithWebState::~WebTestWithWebState() {} |
| |
| void WebTestWithWebState::SetUp() { |
| WebTest::SetUp(); |
| web::WebState::CreateParams params(GetBrowserState()); |
| web_state_ = web::WebState::Create(params); |
| web_state_->SetWebUsageEnabled(true); |
| |
| // Force generation of child views; necessary for some tests. |
| [GetWebController(web_state()) triggerPendingLoad]; |
| } |
| |
| void WebTestWithWebState::TearDown() { |
| DestroyWebState(); |
| WebTest::TearDown(); |
| } |
| |
| void WebTestWithWebState::AddPendingItem(const GURL& url, |
| ui::PageTransition transition) { |
| GetWebController(web_state()) |
| .webStateImpl->GetNavigationManagerImpl() |
| .AddPendingItem(url, Referrer(), transition, |
| web::NavigationInitiationType::USER_INITIATED, |
| web::NavigationManager::UserAgentOverrideOption::INHERIT); |
| } |
| |
| void WebTestWithWebState::LoadHtml(NSString* html, const GURL& url) { |
| // Sets MIME type to "text/html" once navigation is committed. |
| class MimeTypeUpdater : public WebStateObserver { |
| public: |
| explicit MimeTypeUpdater(WebState* web_state) |
| : WebStateObserver(web_state) {} |
| // WebStateObserver overrides: |
| void NavigationItemCommitted(const LoadCommittedDetails&) override { |
| // loadHTML:forURL: does not notify web view delegate about received |
| // response, so web controller does not get a chance to properly update |
| // MIME type and it should be set manually after navigation is committed |
| // but before WebState signal load completion and clients will start |
| // checking if MIME type is in fact HTML. |
| static_cast<WebStateImpl*>(web_state())->SetContentsMimeType("text/html"); |
| } |
| }; |
| MimeTypeUpdater mime_type_updater(web_state()); |
| |
| // Initiate asynchronous HTML load. |
| CRWWebController* web_controller = GetWebController(web_state()); |
| ASSERT_EQ(PAGE_LOADED, web_controller.loadPhase); |
| [web_controller loadHTML:html forURL:url]; |
| ASSERT_EQ(LOAD_REQUESTED, web_controller.loadPhase); |
| |
| // Wait until the page is loaded. |
| base::test::ios::WaitUntilCondition(^{ |
| return web_controller.loadPhase == PAGE_LOADED; |
| }); |
| |
| // Reload the page if script execution is not possible. |
| if (![ExecuteJavaScript(@"0;") isEqual:@0]) { |
| LoadHtml(html, url); |
| } |
| } |
| |
| void WebTestWithWebState::LoadHtml(NSString* html) { |
| GURL url("https://chromium.test/"); |
| LoadHtml(html, url); |
| } |
| |
| void WebTestWithWebState::LoadHtml(const std::string& html) { |
| LoadHtml(base::SysUTF8ToNSString(html)); |
| } |
| |
| void WebTestWithWebState::WaitForBackgroundTasks() { |
| // Because tasks can add new tasks to either queue, the loop continues until |
| // the first pass where no activity is seen from either queue. |
| bool activitySeen = false; |
| base::MessageLoop* messageLoop = base::MessageLoop::current(); |
| messageLoop->AddTaskObserver(this); |
| do { |
| activitySeen = false; |
| |
| // Yield to the iOS message queue, e.g. [NSObject performSelector:] events. |
| if (CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0, true) == |
| kCFRunLoopRunHandledSource) |
| activitySeen = true; |
| |
| // Yield to the Chromium message queue, e.g. WebThread::PostTask() |
| // events. |
| processed_a_task_ = false; |
| base::RunLoop().RunUntilIdle(); |
| if (processed_a_task_) // Set in TaskObserver method. |
| activitySeen = true; |
| |
| } while (activitySeen); |
| messageLoop->RemoveTaskObserver(this); |
| } |
| |
| void WebTestWithWebState::WaitForCondition(ConditionBlock condition) { |
| base::test::ios::WaitUntilCondition(condition, true, |
| base::TimeDelta::FromSeconds(10)); |
| } |
| |
| id WebTestWithWebState::ExecuteJavaScript(NSString* script) { |
| __block id executionResult; |
| __block bool executionCompleted = false; |
| [GetWebController(web_state()) |
| executeJavaScript:script |
| completionHandler:^(id result, NSError* error) { |
| executionResult = [result copy]; |
| executionCompleted = true; |
| }]; |
| base::test::ios::WaitUntilCondition(^{ |
| return executionCompleted; |
| }); |
| return executionResult; |
| } |
| |
| void WebTestWithWebState::DestroyWebState() { |
| web_state_.reset(); |
| } |
| |
| std::string WebTestWithWebState::BaseUrl() const { |
| web::URLVerificationTrustLevel unused_level; |
| return web_state()->GetCurrentURL(&unused_level).spec(); |
| } |
| |
| web::WebState* WebTestWithWebState::web_state() { |
| return web_state_.get(); |
| } |
| |
| const web::WebState* WebTestWithWebState::web_state() const { |
| return web_state_.get(); |
| } |
| |
| void WebTestWithWebState::WillProcessTask(const base::PendingTask&) { |
| // Nothing to do. |
| } |
| |
| void WebTestWithWebState::DidProcessTask(const base::PendingTask&) { |
| processed_a_task_ = true; |
| } |
| |
| } // namespace web |