| // Copyright 2014 The Flutter 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 <EarlGrey/EarlGrey.h> |
| #import <XCTest/XCTest.h> |
| |
| #import "../ios_add2app/AppDelegate.h" |
| #import "../ios_add2app/DualFlutterViewController.h" |
| #import "../ios_add2app/FullScreenViewController.h" |
| #import "../ios_add2app/MainViewController.h" |
| #import "../ios_add2app/HybridViewController.h" |
| |
| @interface FlutterTests : XCTestCase |
| @end |
| |
| @implementation FlutterTests { |
| int _flutterWarmEngineTaps; |
| } |
| |
| - (instancetype)init { |
| self = [super init]; |
| |
| if (self) { |
| _flutterWarmEngineTaps = 0; |
| } |
| |
| return self; |
| } |
| |
| - (void)expectSemanticsNotification:(FlutterViewController*)viewController { |
| [self expectationForNotification:FlutterSemanticsUpdateNotification object:viewController handler:nil]; |
| [viewController.engine ensureSemanticsEnabled]; |
| [self waitForExpectationsWithTimeout:30.0 handler:nil]; |
| } |
| |
| - (void)testFullScreenCanPop { |
| [[EarlGrey selectElementWithMatcher:grey_keyWindow()] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| |
| [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Full Screen (Cold)")] |
| performAction:grey_tap()]; |
| |
| __weak FlutterViewController *weakViewController; |
| @autoreleasepool { |
| UINavigationController *navController = |
| (UINavigationController *)((AppDelegate *) |
| [[UIApplication sharedApplication] |
| delegate]) |
| .window.rootViewController; |
| weakViewController = |
| (FullScreenViewController *)navController.visibleViewController; |
| [self expectSemanticsNotification:weakViewController]; |
| GREYAssertNotNil(weakViewController, |
| @"Expected non-nil FullScreenViewController."); |
| } |
| |
| [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(@"POP")] |
| performAction:grey_tap()]; |
| // EarlGrey v1 isn't good at detecting this yet - 2.0 will be able to do it |
| int tries = 10; |
| double delay = 1.0; |
| while (weakViewController != nil && tries != 0) { |
| CFRunLoopRunInMode(kCFRunLoopDefaultMode, delay, false); |
| tries--; |
| } |
| [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Native iOS View")] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| GREYAssertNil(weakViewController, |
| @"Expected FullScreenViewController to be deallocated."); |
| } |
| |
| - (void)testDualFlutterView { |
| [[EarlGrey selectElementWithMatcher:grey_keyWindow()] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| |
| [[EarlGrey |
| selectElementWithMatcher:grey_buttonTitle(@"Dual Flutter View (Cold)")] |
| performAction:grey_tap()]; |
| |
| @autoreleasepool { |
| UINavigationController *navController = |
| (UINavigationController *)((AppDelegate *) |
| [[UIApplication sharedApplication] |
| delegate]) |
| .window.rootViewController; |
| DualFlutterViewController *viewController = |
| (DualFlutterViewController *)navController.visibleViewController; |
| GREYAssertNotNil(viewController, |
| @"Expected non-nil DualFlutterViewController."); |
| [self expectSemanticsNotification:viewController.topFlutterViewController]; |
| [self expectSemanticsNotification:viewController.bottomFlutterViewController]; |
| } |
| |
| // Verify that there are two Flutter views with the expected marquee text. |
| [[[EarlGrey |
| selectElementWithMatcher:grey_accessibilityLabel(@"This is Marquee")] |
| atIndex:0] assertWithMatcher:grey_notNil()]; |
| [[[EarlGrey |
| selectElementWithMatcher:grey_accessibilityLabel(@"This is Marquee")] |
| atIndex:1] assertWithMatcher:grey_notNil()]; |
| |
| [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Back")] |
| performAction:grey_tap()]; |
| |
| [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Native iOS View")] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| - (void)testHybridView { |
| [[EarlGrey selectElementWithMatcher:grey_keyWindow()] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| |
| [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Hybrid View (Warm)")] |
| performAction:grey_tap()]; |
| |
| @autoreleasepool { |
| UINavigationController *navController = |
| (UINavigationController *)((AppDelegate *) |
| [[UIApplication sharedApplication] |
| delegate]) |
| .window.rootViewController; |
| HybridViewController *viewController = |
| (HybridViewController *)navController.visibleViewController; |
| GREYAssertNotNil(viewController.flutterViewController, |
| @"Expected non-nil FlutterViewController."); |
| [self expectSemanticsNotification:viewController.flutterViewController]; |
| } |
| |
| [self validateCountsFlutter:@"Platform" count:0]; |
| [self validateCountsPlatform:@"Flutter" count:_flutterWarmEngineTaps]; |
| |
| static const int platformTapCount = 4; |
| static const int flutterTapCount = 6; |
| |
| for (int i = _flutterWarmEngineTaps; i < flutterTapCount; |
| i++, _flutterWarmEngineTaps++) { |
| [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel( |
| @"Increment via Flutter")] |
| performAction:grey_tap()]; |
| } |
| |
| [self validateCountsFlutter:@"Platform" count:0]; |
| [self validateCountsPlatform:@"Flutter" count:_flutterWarmEngineTaps]; |
| |
| for (int i = 0; i < platformTapCount; i++) { |
| [[EarlGrey |
| selectElementWithMatcher:grey_accessibilityLabel(@"Increment via iOS")] |
| performAction:grey_tap()]; |
| } |
| |
| [self validateCountsFlutter:@"Platform" count:platformTapCount]; |
| [self validateCountsPlatform:@"Flutter" count:_flutterWarmEngineTaps]; |
| |
| [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Back")] |
| performAction:grey_tap()]; |
| [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Native iOS View")] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| /** Validates that the text labels showing the number of button taps match the |
| * expected counts. */ |
| - (void)validateCountsFlutter:(NSString *)labelPrefix count:(int)flutterCount { |
| NSString *flutterCountStr = |
| [NSString stringWithFormat:@"%@ button tapped %d times.", labelPrefix, |
| flutterCount]; |
| |
| // TODO(https://github.com/flutter/flutter/issues/17988): Flutter doesn't |
| // expose accessibility IDs, so the best we can do is to search for an element |
| // with the text we expect. |
| [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(flutterCountStr)] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| - (void)validateCountsPlatform:(NSString *)labelPrefix |
| count:(int)platformCount { |
| NSString *platformCountStr = |
| [NSString stringWithFormat:@"%@ button tapped %d times.", labelPrefix, |
| platformCount]; |
| |
| [[[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"counter_on_iOS")] |
| assertWithMatcher:grey_text(platformCountStr)] |
| assertWithMatcher:grey_sufficientlyVisible()]; |
| } |
| |
| @end |