XCUIApplication+FBAlert.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. /**
  2. * Copyright (c) 2015-present, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. */
  9. #import "XCUIApplication+FBAlert.h"
  10. #import "FBMacros.h"
  11. #import "FBXCElementSnapshotWrapper+Helpers.h"
  12. #import "FBXCodeCompatibility.h"
  13. #import "XCUIElement+FBUtilities.h"
  14. #define MAX_CENTER_DELTA 10.0
  15. NSString *const FB_SAFARI_APP_NAME = @"Safari";
  16. @implementation XCUIApplication (FBAlert)
  17. - (nullable XCUIElement *)fb_alertElementFromSafariWithScrollView:(XCUIElement *)scrollView
  18. viewSnapshot:(id<FBXCElementSnapshot>)viewSnapshot
  19. {
  20. CGRect appFrame = viewSnapshot.frame;
  21. NSPredicate *dstViewMatchPredicate = [NSPredicate predicateWithBlock:^BOOL(id<FBXCElementSnapshot> snapshot, NSDictionary *bindings) {
  22. CGRect curFrame = snapshot.frame;
  23. if (!CGRectEqualToRect(appFrame, curFrame)
  24. && curFrame.origin.x > 0 && curFrame.size.width < appFrame.size.width) {
  25. CGFloat possibleCenterX = (appFrame.size.width - curFrame.size.width) / 2;
  26. return fabs(possibleCenterX - curFrame.origin.x) < MAX_CENTER_DELTA;
  27. }
  28. return NO;
  29. }];
  30. NSPredicate *dstViewContainPredicate1 = [NSPredicate predicateWithFormat:@"elementType == %lu", XCUIElementTypeTextView];
  31. NSPredicate *dstViewContainPredicate2 = [NSPredicate predicateWithFormat:@"elementType == %lu", XCUIElementTypeButton];
  32. // Find the first XCUIElementTypeOther which is the grandchild of the web view
  33. // and is horizontally aligned to the center of the screen
  34. XCUIElement *candidate = [[[[[[scrollView descendantsMatchingType:XCUIElementTypeAny]
  35. matchingIdentifier:@"WebView"]
  36. descendantsMatchingType:XCUIElementTypeOther]
  37. matchingPredicate:dstViewMatchPredicate]
  38. containingPredicate:dstViewContainPredicate1]
  39. containingPredicate:dstViewContainPredicate2].allElementsBoundByIndex.firstObject;
  40. if (nil == candidate) {
  41. return nil;
  42. }
  43. // ...and contains one to two buttons
  44. // and conatins at least one text view
  45. __block NSUInteger buttonsCount = 0;
  46. __block NSUInteger textViewsCount = 0;
  47. id<FBXCElementSnapshot> snapshot = candidate.fb_cachedSnapshot ?: [candidate fb_customSnapshot];
  48. [snapshot enumerateDescendantsUsingBlock:^(id<FBXCElementSnapshot> descendant) {
  49. XCUIElementType curType = descendant.elementType;
  50. if (curType == XCUIElementTypeButton) {
  51. buttonsCount++;
  52. } else if (curType == XCUIElementTypeTextView) {
  53. textViewsCount++;
  54. }
  55. }];
  56. return (buttonsCount >= 1 && buttonsCount <= 2 && textViewsCount > 0) ? candidate : nil;
  57. }
  58. - (XCUIElement *)fb_alertElement
  59. {
  60. NSPredicate *alertCollectorPredicate = [NSPredicate predicateWithFormat:@"elementType IN {%lu,%lu,%lu}",
  61. XCUIElementTypeAlert, XCUIElementTypeSheet, XCUIElementTypeScrollView];
  62. XCUIElement *alert = [[self descendantsMatchingType:XCUIElementTypeAny]
  63. matchingPredicate:alertCollectorPredicate].allElementsBoundByIndex.firstObject;
  64. if (nil == alert) {
  65. return nil;
  66. }
  67. id<FBXCElementSnapshot> alertSnapshot = alert.fb_cachedSnapshot ?: [alert fb_customSnapshot];
  68. if (alertSnapshot.elementType == XCUIElementTypeAlert) {
  69. return alert;
  70. }
  71. if (alertSnapshot.elementType == XCUIElementTypeSheet) {
  72. if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone) {
  73. return alert;
  74. }
  75. // In case of iPad we want to check if sheet isn't contained by popover.
  76. // In that case we ignore it.
  77. id<FBXCElementSnapshot> ancestor = alertSnapshot.parent;
  78. while (nil != ancestor) {
  79. if (nil != ancestor.identifier && [ancestor.identifier isEqualToString:@"PopoverDismissRegion"]) {
  80. return nil;
  81. }
  82. ancestor = ancestor.parent;
  83. }
  84. return alert;
  85. }
  86. if (alertSnapshot.elementType == XCUIElementTypeScrollView) {
  87. id<FBXCElementSnapshot> app = [[FBXCElementSnapshotWrapper ensureWrapped:alertSnapshot] fb_parentMatchingType:XCUIElementTypeApplication];
  88. if (nil != app && [app.label isEqualToString:FB_SAFARI_APP_NAME]) {
  89. // Check alert presence in Safari web view
  90. return [self fb_alertElementFromSafariWithScrollView:alert viewSnapshot:alertSnapshot];
  91. }
  92. }
  93. return nil;
  94. }
  95. @end