| // Copyright 2020 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #import "ios/chrome/browser/sharing/ui_bundled/sharing_coordinator.h" |
| |
| #import <MaterialComponents/MaterialSnackbar.h> |
| #import <UIKit/UIKit.h> |
| |
| #import "base/ios/block_types.h" |
| #import "base/strings/sys_string_conversions.h" |
| #import "base/test/ios/wait_util.h" |
| #import "base/values.h" |
| #import "components/bookmarks/browser/bookmark_node.h" |
| #import "components/bookmarks/test/bookmark_test_helpers.h" |
| #import "ios/chrome/browser/bookmarks/model/bookmark_ios_unit_test_support.h" |
| #import "ios/chrome/browser/download/model/download_manager_tab_helper.h" |
| #import "ios/chrome/browser/shared/model/browser/test/test_browser.h" |
| #import "ios/chrome/browser/shared/model/profile/profile_ios.h" |
| #import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h" |
| #import "ios/chrome/browser/shared/model/web_state_list/web_state_opener.h" |
| #import "ios/chrome/browser/shared/public/commands/bookmarks_commands.h" |
| #import "ios/chrome/browser/shared/public/commands/command_dispatcher.h" |
| #import "ios/chrome/browser/shared/public/commands/generate_qr_code_command.h" |
| #import "ios/chrome/browser/shared/public/commands/help_commands.h" |
| #import "ios/chrome/browser/shared/public/commands/qr_generation_commands.h" |
| #import "ios/chrome/browser/shared/public/commands/snackbar_commands.h" |
| #import "ios/chrome/browser/shared/ui/table_view/table_view_navigation_controller.h" |
| #import "ios/chrome/browser/sharing/ui_bundled/activity_services/activity_service_presentation.h" |
| #import "ios/chrome/browser/sharing/ui_bundled/activity_services/canonical_url_retriever.h" |
| #import "ios/chrome/browser/sharing/ui_bundled/sharing_params.h" |
| #import "ios/chrome/browser/sharing/ui_bundled/sharing_positioner.h" |
| #import "ios/chrome/test/scoped_key_window.h" |
| #import "ios/web/public/test/fakes/fake_navigation_manager.h" |
| #import "ios/web/public/test/fakes/fake_web_frame.h" |
| #import "ios/web/public/test/fakes/fake_web_frames_manager.h" |
| #import "ios/web/public/test/fakes/fake_web_state.h" |
| #import "ios/web/public/test/web_task_environment.h" |
| #import "ios/web/public/web_state.h" |
| #import "testing/gmock/include/gmock/gmock.h" |
| #import "testing/gtest/include/gtest/gtest.h" |
| #import "testing/gtest_mac.h" |
| #import "testing/platform_test.h" |
| #import "third_party/ocmock/OCMock/OCMock.h" |
| #import "third_party/ocmock/gtest_support.h" |
| #import "url/gurl.h" |
| |
| using base::test::ios::kWaitForActionTimeout; |
| using base::test::ios::WaitUntilConditionOrTimeout; |
| using bookmarks::BookmarkNode; |
| |
| // Test fixture for testing SharingCoordinator. |
| class SharingCoordinatorTest : public BookmarkIOSUnitTestSupport { |
| protected: |
| SharingCoordinatorTest() |
| : base_view_controller_([[UIViewController alloc] init]), |
| fake_origin_view_([[UIView alloc] init]), |
| test_scenario_(SharingScenario::TabShareButton) { |
| [scoped_key_window_.Get() setRootViewController:base_view_controller_]; |
| } |
| |
| void SetUp() override { |
| BookmarkIOSUnitTestSupport::SetUp(); |
| snackbar_handler_ = OCMStrictProtocolMock(@protocol(SnackbarCommands)); |
| [browser_->GetCommandDispatcher() |
| startDispatchingToTarget:snackbar_handler_ |
| forProtocol:@protocol(SnackbarCommands)]; |
| |
| [browser_->GetCommandDispatcher() |
| startDispatchingToTarget:OCMStrictProtocolMock( |
| @protocol(BookmarksCommands)) |
| forProtocol:@protocol(BookmarksCommands)]; |
| [browser_->GetCommandDispatcher() |
| startDispatchingToTarget:OCMStrictProtocolMock(@protocol(HelpCommands)) |
| forProtocol:@protocol(HelpCommands)]; |
| } |
| |
| void AppendNewWebState(std::unique_ptr<web::FakeWebState> web_state) { |
| browser_->GetWebStateList()->InsertWebState( |
| std::move(web_state), |
| WebStateList::InsertionParams::Automatic().Activate()); |
| } |
| |
| ScopedKeyWindow scoped_key_window_; |
| UIViewController* base_view_controller_; |
| UIView* fake_origin_view_; |
| id snackbar_handler_; |
| SharingScenario test_scenario_; |
| }; |
| |
| // Tests that the start method shares the current page and ends up presenting |
| // a UIActivityViewController. |
| TEST_F(SharingCoordinatorTest, Start_ShareCurrentPage) { |
| // Create a test web state. |
| GURL test_url = GURL("https://example.com"); |
| base::Value url_value = base::Value(test_url.spec()); |
| auto test_web_state = std::make_unique<web::FakeWebState>(); |
| test_web_state->SetNavigationManager( |
| std::make_unique<web::FakeNavigationManager>()); |
| test_web_state->SetCurrentURL(test_url); |
| test_web_state->SetBrowserState(browser_->GetProfile()); |
| DownloadManagerTabHelper::CreateForWebState(test_web_state.get()); |
| |
| auto frames_manager = std::make_unique<web::FakeWebFramesManager>(); |
| web::FakeWebFramesManager* frames_manager_ptr = frames_manager.get(); |
| test_web_state->SetWebFramesManager(std::move(frames_manager)); |
| |
| auto main_frame = web::FakeWebFrame::CreateMainWebFrame(test_url); |
| web::FakeWebFrame* main_frame_ptr = main_frame.get(); |
| frames_manager_ptr->AddWebFrame(std::move(main_frame)); |
| |
| main_frame_ptr->AddResultForExecutedJs( |
| &url_value, activity_services::kCanonicalURLScript); |
| |
| AppendNewWebState(std::move(test_web_state)); |
| |
| SharingParams* params = |
| [[SharingParams alloc] initWithScenario:test_scenario_]; |
| |
| SharingCoordinator* coordinator = [[SharingCoordinator alloc] |
| initWithBaseViewController:base_view_controller_ |
| browser:browser_.get() |
| params:params |
| originView:fake_origin_view_]; |
| |
| __block bool completion_handler_called = false; |
| id vc_partial_mock = OCMPartialMock(base_view_controller_); |
| [[vc_partial_mock expect] |
| presentViewController:[OCMArg checkWithBlock:^BOOL( |
| UIViewController* viewController) { |
| if ([viewController isKindOfClass:[UIActivityViewController class]]) { |
| completion_handler_called = true; |
| return YES; |
| } |
| return NO; |
| }] |
| animated:YES |
| completion:nil]; |
| |
| [coordinator start]; |
| |
| EXPECT_TRUE(WaitUntilConditionOrTimeout(kWaitForActionTimeout, ^bool { |
| base::RunLoop().RunUntilIdle(); |
| return completion_handler_called; |
| })); |
| |
| // Verify that the positioning is correct. |
| auto activityHandler = |
| static_cast<id<SharingPositioner, ActivityServicePresentation>>( |
| coordinator); |
| EXPECT_EQ(fake_origin_view_, activityHandler.sourceView); |
| EXPECT_TRUE( |
| CGRectEqualToRect(fake_origin_view_.bounds, activityHandler.sourceRect)); |
| |
| [activityHandler activityServiceDidEndPresenting]; |
| |
| EXPECT_OCMOCK_VERIFY(vc_partial_mock); |
| [coordinator stop]; |
| } |
| |
| // Tests that the coordinator handles the QRGenerationCommands protocol. |
| TEST_F(SharingCoordinatorTest, GenerateQRCode) { |
| SharingParams* params = |
| [[SharingParams alloc] initWithScenario:test_scenario_]; |
| SharingCoordinator* coordinator = [[SharingCoordinator alloc] |
| initWithBaseViewController:base_view_controller_ |
| browser:browser_.get() |
| params:params |
| originView:fake_origin_view_]; |
| |
| id vc_partial_mock = OCMPartialMock(base_view_controller_); |
| [[vc_partial_mock expect] presentViewController:[OCMArg any] |
| animated:YES |
| completion:nil]; |
| |
| auto handler = static_cast<id<QRGenerationCommands>>(coordinator); |
| [handler showQRCode:[[GenerateQRCodeCommand alloc] |
| initWithURL:GURL("https://example.com") |
| title:@"Some Title"]]; |
| |
| EXPECT_OCMOCK_VERIFY(vc_partial_mock); |
| |
| [[vc_partial_mock expect] dismissViewControllerAnimated:YES completion:nil]; |
| |
| [handler hideQRCode]; |
| |
| EXPECT_OCMOCK_VERIFY(vc_partial_mock); |
| [coordinator stop]; |
| } |
| |
| // Tests that the start method shares the given URL and ends up presenting |
| // a UIActivityViewController. |
| TEST_F(SharingCoordinatorTest, Start_ShareURL) { |
| GURL testURL = GURL("https://example.com"); |
| NSString* testTitle = @"Some title"; |
| SharingParams* params = [[SharingParams alloc] initWithURL:testURL |
| title:testTitle |
| scenario:test_scenario_]; |
| SharingCoordinator* coordinator = [[SharingCoordinator alloc] |
| initWithBaseViewController:base_view_controller_ |
| browser:browser_.get() |
| params:params |
| originView:fake_origin_view_]; |
| |
| id vc_partial_mock = OCMPartialMock(base_view_controller_); |
| [[vc_partial_mock expect] |
| presentViewController:[OCMArg checkWithBlock:^BOOL( |
| UIViewController* viewController) { |
| if ([viewController isKindOfClass:[UIActivityViewController class]]) { |
| return YES; |
| } |
| return NO; |
| }] |
| animated:YES |
| completion:nil]; |
| |
| [coordinator start]; |
| |
| EXPECT_OCMOCK_VERIFY(vc_partial_mock); |
| |
| // Make sure share sheet finishes it's init (which means calling |
| // canPerformWithActivityItems and reading prefs) before the |
| // WebTaskEnvironment is shut down. |
| base::RunLoop().RunUntilIdle(); |
| [coordinator stop]; |
| } |