FBResponsePayload.m 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  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. id<FBResponsePayload> FBResponseWithCachedElement(XCUIElement *element, FBElementCache *elementCache, BOOL compact)
  32. {
  33. BOOL useNativeCachingStrategy = nil == FBSession.activeSession
  34. ? YES
  35. : FBSession.activeSession.useNativeCachingStrategy;
  36. [elementCache storeElement:(useNativeCachingStrategy ? element : element.fb_stableInstance)];
  37. return FBResponseWithStatus([FBCommandStatus okWithValue:FBDictionaryResponseWithElement(element, compact)]);
  38. }
  39. id<FBResponsePayload> FBResponseWithCachedElements(NSArray<XCUIElement *> *elements, FBElementCache *elementCache, BOOL compact)
  40. {
  41. NSMutableArray *elementsResponse = [NSMutableArray array];
  42. BOOL useNativeCachingStrategy = nil == FBSession.activeSession
  43. ? YES
  44. : FBSession.activeSession.useNativeCachingStrategy;
  45. for (XCUIElement *element in elements) {
  46. [elementCache storeElement:(useNativeCachingStrategy ? element : element.fb_stableInstance)];
  47. [elementsResponse addObject:FBDictionaryResponseWithElement(element, compact)];
  48. }
  49. return FBResponseWithStatus([FBCommandStatus okWithValue:elementsResponse]);
  50. }
  51. id<FBResponsePayload> FBResponseWithUnknownError(NSError *error)
  52. {
  53. return FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:error.description traceback:nil]);
  54. }
  55. id<FBResponsePayload> FBResponseWithUnknownErrorFormat(NSString *format, ...)
  56. {
  57. va_list argList;
  58. va_start(argList, format);
  59. NSString *errorMessage = [[NSString alloc] initWithFormat:format arguments:argList];
  60. id<FBResponsePayload> payload = FBResponseWithStatus([FBCommandStatus unknownErrorWithMessage:errorMessage
  61. traceback:nil]);
  62. va_end(argList);
  63. return payload;
  64. }
  65. id<FBResponsePayload> FBResponseWithStatus(FBCommandStatus *status)
  66. {
  67. NSMutableDictionary* response = [NSMutableDictionary dictionary];
  68. response[@"sessionId"] = [FBSession activeSession].identifier ?: NSNull.null;
  69. if (nil == status.error) {
  70. response[@"value"] = status.value ?: NSNull.null;
  71. } else {
  72. response[@"value"] = @{
  73. @"error": (id)status.error,
  74. @"message": status.message ?: @"",
  75. @"traceback": status.traceback ?: @""
  76. };
  77. }
  78. return [[FBResponseJSONPayload alloc] initWithDictionary:response.copy
  79. httpStatusCode:status.statusCode];
  80. }
  81. inline NSDictionary *FBDictionaryResponseWithElement(XCUIElement *element, BOOL compact)
  82. {
  83. id<FBXCElementSnapshot> snapshot = nil;
  84. if (nil != element.query.rootElementSnapshot) {
  85. snapshot = element.fb_cachedSnapshot;
  86. }
  87. if (nil == snapshot) {
  88. snapshot = element.lastSnapshot ?: element.fb_takeSnapshot;
  89. }
  90. NSDictionary *compactResult = FBToElementDict((NSString *)[FBXCElementSnapshotWrapper wdUIDWithSnapshot:snapshot]);
  91. if (compact) {
  92. return compactResult;
  93. }
  94. NSMutableDictionary *result = compactResult.mutableCopy;
  95. FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot];
  96. NSArray *fields = [FBConfiguration.elementResponseAttributes componentsSeparatedByString:@","];
  97. for (NSString *field in fields) {
  98. // 'name' here is the w3c-approved identifier for what we mean by 'type'
  99. if ([field isEqualToString:@"name"] || [field isEqualToString:@"type"]) {
  100. result[field] = wrappedSnapshot.wdType;
  101. } else if ([field isEqualToString:@"text"]) {
  102. result[field] = FBFirstNonEmptyValue(wrappedSnapshot.wdValue, wrappedSnapshot.wdLabel) ?: [NSNull null];
  103. } else if ([field isEqualToString:@"rect"]) {
  104. result[field] = wrappedSnapshot.wdRect;
  105. } else if ([field isEqualToString:@"enabled"]) {
  106. result[field] = @(wrappedSnapshot.wdEnabled);
  107. } else if ([field isEqualToString:@"displayed"]) {
  108. result[field] = @(wrappedSnapshot.wdVisible);
  109. } else if ([field isEqualToString:@"selected"]) {
  110. result[field] = @(wrappedSnapshot.wdSelected);
  111. } else if ([field isEqualToString:@"label"]) {
  112. result[field] = wrappedSnapshot.wdLabel ?: [NSNull null];
  113. } else if ([field hasPrefix:arbitraryAttrPrefix]) {
  114. NSString *attributeName = [field substringFromIndex:[arbitraryAttrPrefix length]];
  115. result[field] = [wrappedSnapshot fb_valueForWDAttributeName:attributeName] ?: [NSNull null];
  116. }
  117. }
  118. return result.copy;
  119. }