| // Copyright 2018 The Chromium Authors | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 |  | 
 | #import <XCTest/XCTest.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_matchers.h" | 
 | #import "ios/chrome/test/earl_grey/chrome_test_case.h" | 
 | #import "ios/testing/earl_grey/earl_grey_test.h" | 
 | #import "ios/web/public/test/element_selector.h" | 
 | #import "net/test/embedded_test_server/embedded_test_server.h" | 
 |  | 
 | using chrome_test_util::OpenLinkInNewTabButton; | 
 | using chrome_test_util::WebViewMatcher; | 
 |  | 
 | namespace { | 
 |  | 
 | // This test uses test pages from in //ios/testing/data/http_server_files/. | 
 |  | 
 | // URL for a test page that contains a link. | 
 | const char kLinksTestURL1[] = "/links.html"; | 
 |  | 
 | // Some text in `kLinksTestURL1`. | 
 | const char kLinksTestURL1Text[] = "Normal Link"; | 
 |  | 
 | // ID of the <a> link in `kLinksTestURL1`. | 
 | const char kLinkSelectorID[] = "normal-link"; | 
 |  | 
 | // URL for a different test page. | 
 | const char kLinksTestURL2[] = "/destination.html"; | 
 |  | 
 | // Some text in `kLinksTestURL2`. | 
 | const char kLinksTestURL2Text[] = "arrived"; | 
 |  | 
 | }  // namespace | 
 |  | 
 | // Tests the order in which new tabs are created. | 
 | @interface TabOrderTestCase : ChromeTestCase | 
 | @end | 
 |  | 
 | @implementation TabOrderTestCase | 
 |  | 
 | // Tests that new tabs are always inserted after their parent tab. | 
 | - (void)testChildTabOrdering { | 
 |   GREYAssertTrue(self.testServer->Start(), @"Test server failed to start."); | 
 |   const GURL URL1 = self.testServer->GetURL(kLinksTestURL1); | 
 |  | 
 |   // Create a tab that will act as the parent tab. | 
 |   [ChromeEarlGrey loadURL:URL1]; | 
 |   [ChromeEarlGrey waitForWebStateContainingText:kLinksTestURL1Text]; | 
 |   NSString* parentTabID = [ChromeEarlGrey currentTabID]; | 
 |   // Child tab should be inserted after the parent. | 
 |   [[EarlGrey selectElementWithMatcher:WebViewMatcher()] | 
 |       performAction:chrome_test_util::LongPressElementForContextMenu( | 
 |                         [ElementSelector selectorWithElementID:kLinkSelectorID], | 
 |                         true /* menu should appear */)]; | 
 |   [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()] | 
 |       performAction:grey_tap()]; | 
 |   [ChromeEarlGrey waitForMainTabCount:2U]; | 
 |   NSString* childTab1ID = [ChromeEarlGrey nextTabID]; | 
 |  | 
 |   // New child tab should be inserted after the tab with `childTab1ID`. | 
 |   [[EarlGrey selectElementWithMatcher:WebViewMatcher()] | 
 |       performAction:chrome_test_util::LongPressElementForContextMenu( | 
 |                         [ElementSelector selectorWithElementID:kLinkSelectorID], | 
 |                         true /* menu should appear */)]; | 
 |   [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()] | 
 |       performAction:grey_tap()]; | 
 |   [ChromeEarlGrey waitForMainTabCount:3U]; | 
 |   GREYAssertEqualObjects(childTab1ID, [ChromeEarlGrey nextTabID], | 
 |                          @"Unexpected next tab"); | 
 |  | 
 |   // Navigate the parent tab away and again to `kLinksTestURL1` to break | 
 |   // grouping with the current child tabs. Total number of tabs should not | 
 |   // change. | 
 |   const GURL URL2 = self.testServer->GetURL(kLinksTestURL2); | 
 |   [ChromeEarlGrey loadURL:URL2]; | 
 |   [ChromeEarlGrey waitForWebStateContainingText:kLinksTestURL2Text]; | 
 |   GREYAssertEqual(3U, [ChromeEarlGrey mainTabCount], | 
 |                   @"Unexpected number of tabs"); | 
 |  | 
 |   [ChromeEarlGrey loadURL:URL1]; | 
 |   [ChromeEarlGrey waitForWebStateContainingText:kLinksTestURL1Text]; | 
 |   GREYAssertEqual(3U, [ChromeEarlGrey mainTabCount], | 
 |                   @"Unexpected number of tabs"); | 
 |  | 
 |   // New child tab should be inserted before the tab with `childTab1ID`. | 
 |   [[EarlGrey selectElementWithMatcher:WebViewMatcher()] | 
 |       performAction:chrome_test_util::LongPressElementForContextMenu( | 
 |                         [ElementSelector selectorWithElementID:kLinkSelectorID], | 
 |                         true /* menu should appear */)]; | 
 |   [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()] | 
 |       performAction:grey_tap()]; | 
 |   [ChromeEarlGrey waitForMainTabCount:4U]; | 
 |   NSString* childTab3ID = [ChromeEarlGrey nextTabID]; | 
 |  | 
 |   GREYAssertNotEqualObjects(childTab1ID, childTab3ID, @"Unexpected next tab"); | 
 |  | 
 |   // New child tab should be inserted after the tab with `childTab3ID`. | 
 |   [[EarlGrey selectElementWithMatcher:WebViewMatcher()] | 
 |       performAction:chrome_test_util::LongPressElementForContextMenu( | 
 |                         [ElementSelector selectorWithElementID:kLinkSelectorID], | 
 |                         true /* menu should appear */)]; | 
 |   [[EarlGrey selectElementWithMatcher:OpenLinkInNewTabButton()] | 
 |       performAction:grey_tap()]; | 
 |   [ChromeEarlGrey waitForMainTabCount:5U]; | 
 |   GREYAssertEqualObjects(childTab3ID, [ChromeEarlGrey nextTabID], | 
 |                          @"Unexpected next web state"); | 
 |  | 
 |   // Verify that tab with `childTab1ID` is now at index 3. | 
 |   [ChromeEarlGrey selectTabAtIndex:3]; | 
 |   GREYAssertEqualObjects(childTab1ID, [ChromeEarlGrey currentTabID], | 
 |                          @"Unexpected current web state"); | 
 |  | 
 |   // Add a non-owned tab. It should be added at the end and marked as the | 
 |   // current web state. Next web state should wrap back to index 0, the original | 
 |   // parent web state. | 
 |   [ChromeEarlGrey openNewTab]; | 
 |   [ChromeEarlGrey waitForMainTabCount:6U]; | 
 |   GREYAssertEqualObjects(parentTabID, [ChromeEarlGrey nextTabID], | 
 |                          @"Unexpected next web state"); | 
 |  | 
 |   // Verify that tab with `anotherTabID` is at index 5. | 
 |   NSString* anotherTabID = [ChromeEarlGrey currentTabID]; | 
 |   [ChromeEarlGrey selectTabAtIndex:5]; | 
 |   GREYAssertEqualObjects(anotherTabID, [ChromeEarlGrey currentTabID], | 
 |                          @"Unexpected current web state"); | 
 | } | 
 |  | 
 | @end |