| // Copyright 2018 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. |
| |
| #include "base/bind.h" |
| #import "base/test/ios/wait_util.h" |
| #include "ios/chrome/browser/chrome_url_constants.h" |
| #include "ios/chrome/grit/ios_strings.h" |
| #import "ios/chrome/test/earl_grey/chrome_actions.h" |
| #import "ios/chrome/test/earl_grey/chrome_earl_grey.h" |
| #import "ios/chrome/test/earl_grey/chrome_earl_grey_ui.h" |
| #import "ios/chrome/test/earl_grey/chrome_matchers.h" |
| #import "ios/chrome/test/earl_grey/chrome_test_case.h" |
| #import "ios/chrome/test/scoped_eg_synchronization_disabler.h" |
| #import "ios/testing/earl_grey/app_launch_configuration.h" |
| #import "ios/testing/earl_grey/earl_grey_test.h" |
| #include "ios/testing/embedded_test_server_handlers.h" |
| #include "ios/web/common/features.h" |
| #include "ios/web/public/test/element_selector.h" |
| #include "net/test/embedded_test_server/http_request.h" |
| #include "net/test/embedded_test_server/http_response.h" |
| #include "net/test/embedded_test_server/request_handler_util.h" |
| #include "ui/base/l10n/l10n_util_mac.h" |
| |
| #if !defined(__has_feature) || !__has_feature(objc_arc) |
| #error "This file requires ARC support." |
| #endif |
| |
| using chrome_test_util::ButtonWithAccessibilityLabelId; |
| using chrome_test_util::OpenLinkInNewTabButton; |
| using chrome_test_util::WebViewMatcher; |
| |
| namespace { |
| |
| // Matcher for "Download" button on Download Manager UI. |
| id<GREYMatcher> DownloadButton() { |
| return ButtonWithAccessibilityLabelId(IDS_IOS_DOWNLOAD_MANAGER_DOWNLOAD); |
| } |
| |
| // Provides downloads landing page with download link. |
| std::unique_ptr<net::test_server::HttpResponse> GetResponse( |
| const net::test_server::HttpRequest& request) { |
| auto result = std::make_unique<net::test_server::BasicHttpResponse>(); |
| result->set_code(net::HTTP_OK); |
| result->set_content( |
| "<a id='download' href='/download-example?50000'>Download</a>"); |
| return result; |
| } |
| |
| // Provides test page for downloads with content disposition |
| std::unique_ptr<net::test_server::HttpResponse> GetContentDispositionResponse( |
| const net::test_server::HttpRequest& request) { |
| auto result = std::make_unique<net::test_server::BasicHttpResponse>(); |
| result->set_code(net::HTTP_OK); |
| result->set_content( |
| "<a id='pdf' download='test.pdf' href='/single_page_wide.pdf'>PDF</a>"); |
| result->set_content_type("attachment; filename='filename.pdf'"); |
| return result; |
| } |
| |
| // Waits until Open in... button is shown. |
| [[nodiscard]] bool WaitForOpenInButton() { |
| // These downloads usually take longer and need a longer timeout. |
| const NSTimeInterval kLongDownloadTimeout = 60; |
| return base::test::ios::WaitUntilConditionOrTimeout(kLongDownloadTimeout, ^{ |
| NSError* error = nil; |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::OpenInButton()] |
| assertWithMatcher:grey_interactable() |
| error:&error]; |
| return (error == nil); |
| }); |
| } |
| |
| // Waits until Download button is shown. |
| [[nodiscard]] bool WaitForDownloadButton() { |
| return base::test::ios::WaitUntilConditionOrTimeout( |
| base::test::ios::kWaitForPageLoadTimeout, ^{ |
| NSError* error = nil; |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| assertWithMatcher:grey_interactable() |
| error:&error]; |
| return (error == nil); |
| }); |
| } |
| |
| // Waits until Open in Downloads button is shown. |
| [[nodiscard]] bool WaitForOpenInDownloadsButton() { |
| return base::test::ios::WaitUntilConditionOrTimeout( |
| base::test::ios::kWaitForUIElementTimeout, ^{ |
| NSError* error = nil; |
| [[EarlGrey selectElementWithMatcher:grey_text(l10n_util::GetNSString( |
| IDS_IOS_OPEN_IN_DOWNLOADS))] |
| assertWithMatcher:grey_interactable() |
| error:&error]; |
| return (error == nil); |
| }); |
| } |
| |
| } // namespace |
| |
| // Tests critical user journeys for Download Manager using old download code |
| // paths. |
| @interface DownloadManagerTestCase : ChromeTestCase |
| @end |
| |
| @implementation DownloadManagerTestCase |
| |
| - (void)setUp { |
| [super setUp]; |
| |
| self.testServer->RegisterRequestHandler( |
| base::BindRepeating(&net::test_server::HandlePrefixedRequest, "/", |
| base::BindRepeating(&GetResponse))); |
| |
| self.testServer->RegisterRequestHandler(base::BindRepeating( |
| &net::test_server::HandlePrefixedRequest, "/content-disposition", |
| base::BindRepeating(&GetContentDispositionResponse))); |
| |
| self.testServer->RegisterRequestHandler(base::BindRepeating( |
| &net::test_server::HandlePrefixedRequest, "/download-example", |
| base::BindRepeating(&testing::HandleDownload))); |
| |
| GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); |
| } |
| |
| // Tests successful download up to the point where "Open in..." button is |
| // presented. EarlGrey does not allow testing "Open in..." dialog, because it |
| // is run in a separate process. |
| - (void)testSuccessfulDownload { |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"download"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| } |
| |
| // Tests successful download up to the point where "Open in..." button is |
| // presented. EarlGrey does not allow testing "Open in..." dialog, because it |
| // is run in a separate process. Performs download in Incognito. |
| #if !TARGET_IPHONE_SIMULATOR |
| // TODO(crbug.com/1059320): Test consistently failing on device. |
| #define MAYBE_testSucessfullDownloadInIncognito \ |
| DISABLED_testSucessfullDownloadInIncognito |
| #else |
| #define MAYBE_testSucessfullDownloadInIncognito \ |
| testSucessfullDownloadInIncognito |
| #endif |
| - (void)MAYBE_testSucessfullDownloadInIncognito { |
| [ChromeEarlGrey openNewIncognitoTab]; |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"download"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| } |
| |
| // Tests cancelling download UI. |
| - (void)testCancellingDownload { |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"download"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| assertWithMatcher:grey_notNil()]; |
| |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::CloseButton()] |
| performAction:grey_tap()]; |
| |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| assertWithMatcher:grey_nil()]; |
| } |
| |
| // Tests sucessfull download up to the point where "Open in..." button is |
| // presented. EarlGrey does not allow testing "Open in..." dialog, because it |
| // is run in a separate process. After tapping Download this test opens a |
| // separate tabs and loads the URL there. Then closes the tab and waits for |
| // the download completion. |
| - (void)testDownloadWhileBrowsing { |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"download"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| { |
| // In order to open a new Tab, disable EG synchronization so the framework |
| // does not wait until the download progress bar becomes idle (which will |
| // not happen until the download is complete). |
| ScopedSynchronizationDisabler disabler; |
| [ChromeEarlGrey openNewTab]; |
| } |
| |
| // Load a URL in a separate Tab and close that tab. |
| [ChromeEarlGrey loadURL:GURL(kChromeUITermsURL)]; |
| const char kTermsText[] = "Terms of Service"; |
| [ChromeEarlGrey waitForWebStateContainingText:kTermsText]; |
| [ChromeEarlGrey closeCurrentTab]; |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| } |
| |
| // Tests "Open in New Tab" on download link. |
| - (void)testDownloadInNewTab { |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| |
| // Open context menu for download link. |
| [[EarlGrey selectElementWithMatcher:WebViewMatcher()] |
| performAction:chrome_test_util::LongPressElementForContextMenu( |
| [ElementSelector selectorWithElementID:"download"], |
| /*menu_should_appear=*/true)]; |
| |
| // Tap "Open In New Tab". |
| [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()] |
| assertWithMatcher:grey_notNil()]; |
| [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()] |
| performAction:grey_tap()]; |
| |
| // Wait until the new tab is open and switch to that tab. |
| [ChromeEarlGrey waitForMainTabCount:2]; |
| [ChromeEarlGrey selectTabAtIndex:1U]; |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| |
| // Proceed with download. |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| } |
| |
| // Tests accessibility on Download Manager UI when download is not started. |
| - (void)testAccessibilityOnNotStartedDownloadToolbar { |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"download"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| assertWithMatcher:grey_notNil()]; |
| |
| [ChromeEarlGrey verifyAccessibilityForCurrentScreen]; |
| } |
| |
| // Tests accessibility on Download Manager UI when download is complete. |
| - (void)testAccessibilityOnCompletedDownloadToolbar { |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"download"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| |
| [ChromeEarlGrey verifyAccessibilityForCurrentScreen]; |
| } |
| |
| // Tests that filename label and "Open in Downloads" button are showing. |
| - (void)testVisibleFileNameAndOpenInDownloads { |
| // Apple is hiding UIActivityViewController's contents from the host app on |
| // iPad. |
| if ([ChromeEarlGrey isIPadIdiom]) |
| EARL_GREY_TEST_SKIPPED(@"Test skipped on iPad."); |
| |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"Download"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"download"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| [[EarlGrey selectElementWithMatcher:chrome_test_util::OpenInButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInDownloadsButton(), |
| @"Open in Downloads button did not show up"); |
| |
| // Tests filename label. |
| [[EarlGrey |
| selectElementWithMatcher:grey_allOf(grey_text(@"download-example"), |
| grey_sufficientlyVisible(), nil)] |
| assertWithMatcher:grey_notNil()]; |
| } |
| |
| @end |
| |
| // Tests critical user journeys for Download Manager using new download code |
| // paths. Once support for old download API is removed (i.e. once the new |
| // API is launched and iOS 14 support is dropped) this class needs |
| // to be merged with DownloadManagerTestCase. |
| @interface DownloadManagerNewAPITestCase : DownloadManagerTestCase |
| @end |
| |
| @implementation DownloadManagerNewAPITestCase |
| |
| - (AppLaunchConfiguration)appConfigurationForTestCase { |
| AppLaunchConfiguration config; |
| return config; |
| } |
| |
| - (void)setUp { |
| [super setUp]; |
| } |
| |
| // Tests successful download up to the point where "Open in..." button is |
| // presented. EarlGrey does not allow testing "Open in..." dialog, because it |
| // is run in a separate process. |
| - (void)testSuccessfulDownload { |
| [super testSuccessfulDownload]; |
| } |
| |
| // Tests successful blob download. This also checks that a file can be |
| // downloaded and saved locally while an anchor tag has the download attribute. |
| - (void)testSucessfulBlobDownload { |
| if (@available(iOS 15.0, *)) { |
| [ChromeEarlGrey |
| loadURL:self.testServer->GetURL("/download_test_page.html")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"BlobURL"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"blob"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| } |
| } |
| |
| // Tests that a pdf can be downloaded. This also checks that a file can be |
| // downloaded and saved locally while an anchor tag has the download attribute. |
| - (void)testSucessfulPDFDownload { |
| if (@available(iOS 15.0, *)) { |
| [ChromeEarlGrey |
| loadURL:self.testServer->GetURL("/download_test_page.html")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"PDF"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"pdf"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| } |
| } |
| |
| // Tests that a file is downloaded successfully even if it is renderable by the |
| // browser. |
| - (void)testSucessfulDownloadWithContentDisposition { |
| if (@available(iOS 15.0, *)) { |
| [ChromeEarlGrey loadURL:self.testServer->GetURL("/content-disposition")]; |
| [ChromeEarlGrey waitForWebStateContainingText:"PDF"]; |
| [ChromeEarlGrey tapWebStateElementWithID:@"pdf"]; |
| |
| GREYAssert(WaitForDownloadButton(), @"Download button did not show up"); |
| [[EarlGrey selectElementWithMatcher:DownloadButton()] |
| performAction:grey_tap()]; |
| |
| GREYAssert(WaitForOpenInButton(), @"Open in... button did not show up"); |
| } |
| } |
| |
| // Tests successful download up to the point where "Open in..." button is |
| // presented. EarlGrey does not allow testing "Open in..." dialog, because it |
| // is run in a separate process. Performs download in Incognito. |
| #if !TARGET_IPHONE_SIMULATOR |
| // TODO(crbug.com/1059320): Test consistently failing on device. |
| #define MAYBE_testSucessfullDownloadInIncognito \ |
| DISABLED_testSucessfullDownloadInIncognito |
| #else |
| #define MAYBE_testSucessfullDownloadInIncognito \ |
| testSucessfullDownloadInIncognito |
| #endif |
| - (void)MAYBE_testSucessfullDownloadInIncognito { |
| [super MAYBE_testSucessfullDownloadInIncognito]; |
| } |
| |
| // Tests cancelling download UI. |
| - (void)testCancellingDownload { |
| [super testCancellingDownload]; |
| } |
| |
| // Tests sucessfull download up to the point where "Open in..." button is |
| // presented. EarlGrey does not allow testing "Open in..." dialog, because it |
| // is run in a separate process. After tapping Download this test opens a |
| // separate tabs and loads the URL there. Then closes the tab and waits for |
| // the download completion. |
| - (void)testDownloadWhileBrowsing { |
| [super testDownloadWhileBrowsing]; |
| } |
| |
| // Tests "Open in New Tab" on download link. |
| - (void)testDownloadInNewTab { |
| [super testDownloadInNewTab]; |
| } |
| |
| // Tests accessibility on Download Manager UI when download is not started. |
| - (void)testAccessibilityOnNotStartedDownloadToolbar { |
| [super testAccessibilityOnNotStartedDownloadToolbar]; |
| } |
| |
| // Tests accessibility on Download Manager UI when download is complete. |
| - (void)testAccessibilityOnCompletedDownloadToolbar { |
| [super testAccessibilityOnCompletedDownloadToolbar]; |
| } |
| |
| // Tests that filename label and "Open in Downloads" button are showing. |
| - (void)testVisibleFileNameAndOpenInDownloads { |
| [super testVisibleFileNameAndOpenInDownloads]; |
| } |
| |
| @end |