IntegrationTestPlugin.m 3.16 KB
Newer Older
1 2 3 4
// 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.

5 6
#import "IntegrationTestPlugin.h"

7 8
@import UIKit;

9 10
static NSString *const kIntegrationTestPluginChannel = @"plugins.flutter.io/integration_test";
static NSString *const kMethodTestFinished = @"allTestsFinished";
11 12 13
static NSString *const kMethodScreenshot = @"captureScreenshot";
static NSString *const kMethodConvertSurfaceToImage = @"convertFlutterSurfaceToImage";
static NSString *const kMethodRevertImage = @"revertFlutterImage";
14 15 16 17 18

@interface IntegrationTestPlugin ()

@property(nonatomic, readwrite) NSDictionary<NSString *, NSString *> *testResults;

19 20
- (instancetype)init NS_DESIGNATED_INITIALIZER;

21 22 23 24
@end

@implementation IntegrationTestPlugin {
  NSDictionary<NSString *, NSString *> *_testResults;
25
  NSMutableDictionary<NSString *, UIImage *> *_capturedScreenshotsByName;
26 27
}

28
+ (instancetype)instance {
29 30 31 32 33 34 35 36 37
  static dispatch_once_t onceToken;
  static IntegrationTestPlugin *sInstance;
  dispatch_once(&onceToken, ^{
    sInstance = [[IntegrationTestPlugin alloc] initForRegistration];
  });
  return sInstance;
}

- (instancetype)initForRegistration {
38 39 40 41 42 43 44
  return [self init];
}

- (instancetype)init {
  self = [super init];
  _capturedScreenshotsByName = [NSMutableDictionary new];
  return self;
45 46 47
}

+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
48 49 50
  FlutterMethodChannel *channel = [FlutterMethodChannel methodChannelWithName:kIntegrationTestPluginChannel
                                                              binaryMessenger:registrar.messenger];
  [registrar addMethodCallDelegate:[self instance] channel:channel];
51 52 53
}

- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
54
  if ([call.method isEqualToString:kMethodTestFinished]) {
55 56
    self.testResults = call.arguments[@"results"];
    result(nil);
57 58 59 60
  } else if ([call.method isEqualToString:kMethodScreenshot]) {
    // If running as a native Xcode test, attach to test.
    UIImage *screenshot = [self capturePngScreenshot];
    NSString *name = call.arguments[@"name"];
61
    _capturedScreenshotsByName[name] = screenshot;
62 63 64 65 66 67 68 69

    // Also pass back along the channel for the driver to handle.
    NSData *pngData = UIImagePNGRepresentation(screenshot);
    result([FlutterStandardTypedData typedDataWithBytes:pngData]);
  } else if ([call.method isEqualToString:kMethodConvertSurfaceToImage]
             || [call.method isEqualToString:kMethodRevertImage]) {
    // Android only, no-op on iOS.
    result(nil);
70 71 72 73 74
  } else {
    result(FlutterMethodNotImplemented);
  }
}

75 76 77 78 79 80
- (UIImage *)capturePngScreenshot {
  UIWindow *window = [UIApplication.sharedApplication.windows
                      filteredArrayUsingPredicate:[NSPredicate predicateWithFormat:@"keyWindow = YES"]].firstObject;
  CGRect screenshotBounds = window.bounds;
  UIImage *image;

81
  UIGraphicsImageRenderer *renderer = [[UIGraphicsImageRenderer alloc] initWithBounds:screenshotBounds];
82

83
  image = [renderer imageWithActions:^(UIGraphicsImageRendererContext *rendererContext) {
84
    [window drawViewHierarchyInRect:screenshotBounds afterScreenUpdates:YES];
85
  }];
86 87 88 89

  return image;
}

90
@end