FBResponsePayload.m 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  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 "FBResponsePayload.h"
  10. #import "FBElementCache.h"
  11. #import "FBResponseJSONPayload.h"
  12. #import "FBSession.h"
  13. #import "FBMathUtils.h"
  14. #import "FBConfiguration.h"
  15. #import "FBMacros.h"
  16. #import "FBProtocolHelpers.h"
  17. #import "XCUIElementQuery.h"
  18. #import "XCUIElement+FBResolve.h"
  19. #import "XCUIElement+FBUID.h"
  20. #import "XCUIElement+FBUtilities.h"
  21. #import "XCUIElement+FBWebDriverAttributes.h"
  22. NSString *arbitraryAttrPrefix = @"attribute/";
  23. id<FBResponsePayload> FBResponseWithOK(void)
  24. {
  25. return FBResponseWithStatus(FBCommandStatus.ok);
  26. }
  27. id<FBResponsePayload> FBResponseWithObject(id object)
  28. {
  29. return FBResponseWithStatus([FBCommandStatus okWithValue:object]);
  30. }
  31. XCUIElement *maybeStable(XCUIElement *element)
  32. {
  33. BOOL useNativeCachingStrategy = nil == FBSession.activeSession
  34. ? YES
  35. : FBSession.activeSession.useNativeCachingStrategy;
  36. if (useNativeCachingStrategy) {
  37. return element;
  38. }
  39. XCUIElement *result = element;
  40. id<FBXCElementSnapshot> snapshot = element.lastSnapshot
  41. ?: element.fb_cachedSnapshot
  42. ?: [element fb_standardSnapshot];
  43. NSString *uid = [FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot];
  44. if (nil != uid) {
  45. result = [element fb_stableInstanceWithUid:uid];
  46. }
  47. return result;
  48. }
  49. id<FBResponsePayload> FBResponseWithCachedElement(XCUIElement *element, FBElementCache *elementCache, BOOL compact)
  50. {
  51. [elementCache storeElement:maybeStable(element)];
  52. NSDictionary *response = FBDictionaryResponseWithElement(element, compact);
  53. element.lastSnapshot = nil;
  54. return FBResponseWithStatus([FBCommandStatus okWithValue:response]);
  55. }
  56. id<FBResponsePayload> FBResponseWithCachedElements(NSArray<XCUIElement *> *elements, FBElementCache *elementCache, BOOL compact)
  57. {
  58. NSMutableArray *elementsResponse = [NSMutableArray array];
  59. for (XCUIElement *element in elements) {
  60. [elementCache storeElement:maybeStable(element)];
  61. [elementsResponse addObject:FBDictionaryResponseWithElement(element, compact)];
  62. element.lastSnapshot = nil;
  63. }
  64. return FBResponseWithStatus([FBCommandStatus okWithValue:elementsResponse]);
  65. }
  66. id<FBResponsePayload> FBResponseWithUnknownError(NSError *error)
  67. {
  68. return FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:error.description traceback:nil]);
  69. }
  70. id<FBResponsePayload> FBResponseWithUnknownErrorFormat(NSString *format, ...)
  71. {
  72. va_list argList;
  73. va_start(argList, format);
  74. NSString *errorMessage = [[NSString alloc] initWithFormat:format arguments:argList];
  75. id<FBResponsePayload> payload = FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:errorMessage
  76. traceback:nil]);
  77. va_end(argList);
  78. return payload;
  79. }
  80. id<FBResponsePayload> FBResponseWithStatus(FBCommandStatus *status)
  81. {
  82. NSMutableDictionary* response = [NSMutableDictionary dictionary];
  83. response[@"sessionId"] = [FBSession activeSession].identifier ?: NSNull.null;
  84. if (nil == status.error) {
  85. response[@"value"] = status.value ?: NSNull.null;
  86. } else {
  87. response[@"value"] = @{
  88. @"error": (id)status.error,
  89. @"message": status.message ?: @"",
  90. @"traceback": status.traceback ?: @""
  91. };
  92. }
  93. return [[FBResponseJSONPayload alloc] initWithDictionary:response.copy
  94. httpStatusCode:status.statusCode];
  95. }
  96. inline NSDictionary *FBDictionaryResponseWithElement(XCUIElement *element, BOOL compact)
  97. {
  98. __block NSDictionary *elementResponse = nil;
  99. @autoreleasepool {
  100. id<FBXCElementSnapshot> snapshot = element.lastSnapshot
  101. ?: element.fb_cachedSnapshot
  102. ?: [element fb_customSnapshot];
  103. NSDictionary *compactResult = FBToElementDict((NSString *)[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]);
  104. if (compact) {
  105. elementResponse = compactResult;
  106. return elementResponse;
  107. }
  108. NSMutableDictionary *result = compactResult.mutableCopy;
  109. FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot];
  110. NSArray *fields = [FBConfiguration.elementResponseAttributes componentsSeparatedByString:@","];
  111. for (NSString *field in fields) {
  112. // 'name' here is the w3c-approved identifier for what we mean by 'type'
  113. if ([field isEqualToString:@"name"] || [field isEqualToString:@"type"]) {
  114. result[field] = wrappedSnapshot.wdType;
  115. } else if ([field isEqualToString:@"text"]) {
  116. result[field] = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel) ?: [NSNull null];
  117. } else if ([field isEqualToString:@"rect"]) {
  118. result[field] = wrappedSnapshot.wdRect;
  119. } else if ([field isEqualToString:@"enabled"]) {
  120. result[field] = @(wrappedSnapshot.wdEnabled);
  121. } else if ([field isEqualToString:@"displayed"]) {
  122. result[field] = @(wrappedSnapshot.wdVisible);
  123. } else if ([field isEqualToString:@"selected"]) {
  124. result[field] = @(wrappedSnapshot.wdSelected);
  125. } else if ([field isEqualToString:@"label"]) {
  126. result[field] = wrappedSnapshot.wdLabel ?: [NSNull null];
  127. } else if ([field hasPrefix:arbitraryAttrPrefix]) {
  128. NSString *attributeName = [field substringFromIndex:[arbitraryAttrPrefix length]];
  129. result[field] = [wrappedSnapshot fb_valueForWDAttributeName:attributeName] ?: [NSNull null];
  130. }
  131. }
  132. elementResponse = result.copy;
  133. }
  134. return elementResponse;
  135. }