IntegrationTests.m 6.94 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
Dan Field's avatar
Dan Field committed
2 3 4 5 6 7 8
// 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"
9
#import "../ios_add2app/DualFlutterViewController.h"
Dan Field's avatar
Dan Field committed
10
#import "../ios_add2app/FullScreenViewController.h"
11 12 13
#import "../ios_add2app/MainViewController.h"
#import "../ios_add2app/HybridViewController.h"

Dan Field's avatar
Dan Field committed
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
@interface FlutterTests : XCTestCase
@end

@implementation FlutterTests {
  int _flutterWarmEngineTaps;
}

- (instancetype)init {
  self = [super init];

  if (self) {
    _flutterWarmEngineTaps = 0;
  }

  return self;
}

31 32 33 34 35 36
- (void)expectSemanticsNotification:(FlutterViewController*)viewController {
  [self expectationForNotification:FlutterSemanticsUpdateNotification object:viewController handler:nil];
  [viewController.engine ensureSemanticsEnabled];
  [self waitForExpectationsWithTimeout:30.0 handler:nil];
}

Dan Field's avatar
Dan Field committed
37 38
- (void)testFullScreenCanPop {
  [[EarlGrey selectElementWithMatcher:grey_keyWindow()]
39
      assertWithMatcher:grey_sufficientlyVisible()];
Dan Field's avatar
Dan Field committed
40 41

  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Full Screen (Cold)")]
42
      performAction:grey_tap()];
Dan Field's avatar
Dan Field committed
43

44
  __weak FlutterViewController *weakViewController;
Dan Field's avatar
Dan Field committed
45
  @autoreleasepool {
46 47 48 49
    UINavigationController *navController =
        (UINavigationController *)((AppDelegate *)
                                       [[UIApplication sharedApplication]
                                           delegate])
Dan Field's avatar
Dan Field committed
50 51
            .window.rootViewController;
    weakViewController =
52
        (FullScreenViewController *)navController.visibleViewController;
53
    [self expectSemanticsNotification:weakViewController];
54 55
    GREYAssertNotNil(weakViewController,
                     @"Expected non-nil FullScreenViewController.");
Dan Field's avatar
Dan Field committed
56 57
  }

58 59 60 61 62 63 64 65 66
  [[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--;
  }
Dan Field's avatar
Dan Field committed
67 68
  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Native iOS View")]
      assertWithMatcher:grey_sufficientlyVisible()];
69 70
  GREYAssertNil(weakViewController,
                @"Expected FullScreenViewController to be deallocated.");
Dan Field's avatar
Dan Field committed
71 72 73 74
}

- (void)testDualFlutterView {
  [[EarlGrey selectElementWithMatcher:grey_keyWindow()]
75
      assertWithMatcher:grey_sufficientlyVisible()];
Dan Field's avatar
Dan Field committed
76

77 78 79
  [[EarlGrey
      selectElementWithMatcher:grey_buttonTitle(@"Dual Flutter View (Cold)")]
      performAction:grey_tap()];
Dan Field's avatar
Dan Field committed
80

81 82 83 84 85 86 87 88 89 90
  @autoreleasepool {
    UINavigationController *navController =
        (UINavigationController *)((AppDelegate *)
                                       [[UIApplication sharedApplication]
                                           delegate])
            .window.rootViewController;
    DualFlutterViewController *viewController =
        (DualFlutterViewController *)navController.visibleViewController;
    GREYAssertNotNil(viewController,
                     @"Expected non-nil DualFlutterViewController.");
91 92
    [self expectSemanticsNotification:viewController.topFlutterViewController];
    [self expectSemanticsNotification:viewController.bottomFlutterViewController];
93
  }
Dan Field's avatar
Dan Field committed
94 95

  // Verify that there are two Flutter views with the expected marquee text.
96 97 98 99 100 101
  [[[EarlGrey
      selectElementWithMatcher:grey_accessibilityLabel(@"This is Marquee")]
      atIndex:0] assertWithMatcher:grey_notNil()];
  [[[EarlGrey
      selectElementWithMatcher:grey_accessibilityLabel(@"This is Marquee")]
      atIndex:1] assertWithMatcher:grey_notNil()];
Dan Field's avatar
Dan Field committed
102

103 104
  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Back")]
      performAction:grey_tap()];
Dan Field's avatar
Dan Field committed
105 106 107 108 109 110 111

  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Native iOS View")]
      assertWithMatcher:grey_sufficientlyVisible()];
}

- (void)testHybridView {
  [[EarlGrey selectElementWithMatcher:grey_keyWindow()]
112
      assertWithMatcher:grey_sufficientlyVisible()];
Dan Field's avatar
Dan Field committed
113

114 115
  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Hybrid View (Warm)")]
      performAction:grey_tap()];
Dan Field's avatar
Dan Field committed
116

117 118 119 120 121 122 123 124 125 126
  @autoreleasepool {
    UINavigationController *navController =
        (UINavigationController *)((AppDelegate *)
                                       [[UIApplication sharedApplication]
                                           delegate])
            .window.rootViewController;
    HybridViewController *viewController =
        (HybridViewController *)navController.visibleViewController;
    GREYAssertNotNil(viewController.flutterViewController,
                     @"Expected non-nil FlutterViewController.");
127
    [self expectSemanticsNotification:viewController.flutterViewController];
128
  }
Dan Field's avatar
Dan Field committed
129 130 131 132 133 134 135

  [self validateCountsFlutter:@"Platform" count:0];
  [self validateCountsPlatform:@"Flutter" count:_flutterWarmEngineTaps];

  static const int platformTapCount = 4;
  static const int flutterTapCount = 6;

136 137 138 139 140
  for (int i = _flutterWarmEngineTaps; i < flutterTapCount;
       i++, _flutterWarmEngineTaps++) {
    [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(
                                            @"Increment via Flutter")]
        performAction:grey_tap()];
Dan Field's avatar
Dan Field committed
141 142 143 144 145 146
  }

  [self validateCountsFlutter:@"Platform" count:0];
  [self validateCountsPlatform:@"Flutter" count:_flutterWarmEngineTaps];

  for (int i = 0; i < platformTapCount; i++) {
147 148 149
    [[EarlGrey
        selectElementWithMatcher:grey_accessibilityLabel(@"Increment via iOS")]
        performAction:grey_tap()];
Dan Field's avatar
Dan Field committed
150 151 152 153 154
  }

  [self validateCountsFlutter:@"Platform" count:platformTapCount];
  [self validateCountsPlatform:@"Flutter" count:_flutterWarmEngineTaps];

155 156
  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Back")]
      performAction:grey_tap()];
Dan Field's avatar
Dan Field committed
157
  [[EarlGrey selectElementWithMatcher:grey_buttonTitle(@"Native iOS View")]
158
      assertWithMatcher:grey_sufficientlyVisible()];
Dan Field's avatar
Dan Field committed
159 160
}

161 162 163 164 165 166
/** 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];
Dan Field's avatar
Dan Field committed
167

168 169 170
  // 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.
Dan Field's avatar
Dan Field committed
171 172 173 174
  [[EarlGrey selectElementWithMatcher:grey_accessibilityLabel(flutterCountStr)]
      assertWithMatcher:grey_sufficientlyVisible()];
}

175 176 177 178 179
- (void)validateCountsPlatform:(NSString *)labelPrefix
                         count:(int)platformCount {
  NSString *platformCountStr =
      [NSString stringWithFormat:@"%@ button tapped %d times.", labelPrefix,
                                 platformCount];
Dan Field's avatar
Dan Field committed
180 181

  [[[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"counter_on_iOS")]
182 183
      assertWithMatcher:grey_text(platformCountStr)]
      assertWithMatcher:grey_sufficientlyVisible()];
Dan Field's avatar
Dan Field committed
184 185 186
}

@end