From 6d58d20676a2fd1c47d0b5135f6e3927d9ef7051 Mon Sep 17 00:00:00 2001 From: Mykola Mokhnach Date: Tue, 2 Sep 2025 21:12:32 +0200 Subject: [PATCH] feat: Add process and bundle identifiers to the application node in the XML source --- WebDriverAgentLib/Utilities/FBXPath.m | 65 +++++++++++++++---- .../FBXPathIntegrationTests.m | 15 +++++ 2 files changed, 67 insertions(+), 13 deletions(-) diff --git a/WebDriverAgentLib/Utilities/FBXPath.m b/WebDriverAgentLib/Utilities/FBXPath.m index 15e943c7c..3b730c2d9 100644 --- a/WebDriverAgentLib/Utilities/FBXPath.m +++ b/WebDriverAgentLib/Utilities/FBXPath.m @@ -17,12 +17,15 @@ #import "FBXMLGenerationOptions.h" #import "FBXCElementSnapshotWrapper+Helpers.h" #import "NSString+FBXMLSafeString.h" +#import "XCUIApplication.h" #import "XCUIElement.h" #import "XCUIElement+FBCaching.h" #import "XCUIElement+FBUtilities.h" #import "XCUIElement+FBWebDriverAttributes.h" #import "XCTestPrivateSymbols.h" #import "FBElementHelpers.h" +#import "FBXCAXClientProxy.h" +#import "FBXCAccessibilityElement.h" @interface FBElementAttribute : NSObject @@ -33,6 +36,7 @@ + (nonnull NSString *)name; + (nullable NSString *)valueForElement:(id)element; + (int)recordWithWriter:(xmlTextWriterPtr)writer forElement:(id)element; ++ (int)recordWithWriter:(xmlTextWriterPtr)writer forValue:(nullable NSString *)value; + (NSArray *)supportedAttributes; @@ -98,7 +102,13 @@ @interface FBInternalIndexAttribute : FBElementAttribute @property (nonatomic, nonnull, readonly) NSString* indexValue; -+ (int)recordWithWriter:(xmlTextWriterPtr)writer forValue:(NSString *)value; +@end + +@interface FBApplicationBundleIdAttribute : FBElementAttribute + +@end + +@interface FBApplicationPidAttribute : FBElementAttribute @end @@ -472,6 +482,27 @@ + (int)recordElementAttributes:(xmlTextWriterPtr)writer // index path is the special case return [FBInternalIndexAttribute recordWithWriter:writer forValue:indexPath]; } + if (element.elementType == XCUIElementTypeApplication) { + // only record process identifier and bundle identifier for the application element + int pid = [element.accessibilityElement processIdentifier]; + if (pid > 0) { + int rc = [FBApplicationPidAttribute recordWithWriter:writer + forValue:[NSString stringWithFormat:@"%d", pid]]; + if (rc < 0) { + return rc; + } + XCUIApplication *app = [[FBXCAXClientProxy sharedClient] + monitoredApplicationWithProcessIdentifier:pid]; + NSString *bundleID = [app bundleID]; + if (nil != bundleID) { + rc = [FBApplicationBundleIdAttribute recordWithWriter:writer + forValue:bundleID]; + if (rc < 0) { + return rc; + } + } + } + } return 0; } @@ -585,6 +616,11 @@ + (NSString *)valueForElement:(id)element + (int)recordWithWriter:(xmlTextWriterPtr)writer forElement:(id)element { NSString *value = [self valueForElement:element]; + return [self recordWithWriter:writer forValue:value]; +} + ++ (int)recordWithWriter:(xmlTextWriterPtr)writer forValue:(nullable NSString *)value +{ if (nil == value) { // Skip the attribute if the value equals to nil return 0; @@ -830,22 +866,25 @@ + (NSString *)name return kXMLIndexPathKey; } -+ (int)recordWithWriter:(xmlTextWriterPtr)writer forValue:(NSString *)value +@end + +@implementation FBApplicationBundleIdAttribute : FBElementAttribute + ++ (NSString *)name { - if (nil == value) { - // Skip the attribute if the value equals to nil - return 0; - } - int rc = xmlTextWriterWriteAttribute(writer, - (xmlChar *)[[FBXPath safeXmlStringWithString:[self name]] UTF8String], - (xmlChar *)[[FBXPath safeXmlStringWithString:value] UTF8String]); - if (rc < 0) { - [FBLogger logFmt:@"Failed to invoke libxml2>xmlTextWriterWriteAttribute(%@='%@'). Error code: %d", [self name], value, rc]; - } - return rc; + return @"bundleId"; } + @end +@implementation FBApplicationPidAttribute : FBElementAttribute + ++ (NSString *)name +{ + return @"processId"; +} + +@end @implementation FBPlaceholderValueAttribute diff --git a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m index 7ed7ee7d5..3694d7e3d 100644 --- a/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m +++ b/WebDriverAgentTests/IntegrationTests/FBXPathIntegrationTests.m @@ -13,9 +13,11 @@ #import "FBMacros.h" #import "FBTestMacros.h" #import "FBXPath.h" +#import "FBXCAccessibilityElement.h" #import "FBXCodeCompatibility.h" #import "FBXCElementSnapshotWrapper+Helpers.h" #import "FBXMLGenerationOptions.h" +#import "XCUIApplication.h" #import "XCUIElement.h" #import "XCUIElement+FBFind.h" #import "XCUIElement+FBUtilities.h" @@ -50,6 +52,19 @@ - (void)setUp return snapshot; } +- (void)testApplicationNodeXMLRepresentation +{ + id snapshot = [self.testedApplication fb_customSnapshot]; + snapshot.children = @[]; + FBXCElementSnapshotWrapper *wrappedSnapshot = [FBXCElementSnapshotWrapper ensureWrapped:snapshot]; + NSString *xmlStr = [FBXPath xmlStringWithRootElement:wrappedSnapshot + options:nil]; + int pid = [snapshot.accessibilityElement processIdentifier]; + XCTAssertNotNil(xmlStr); + NSString *expectedXml = [NSString stringWithFormat:@"\n<%@ type=\"%@\" name=\"%@\" label=\"%@\" enabled=\"%@\" visible=\"%@\" accessible=\"%@\" x=\"%@\" y=\"%@\" width=\"%@\" height=\"%@\" index=\"%lu\" traits=\"%@\" processId=\"%d\" bundleId=\"%@\"/>\n", wrappedSnapshot.wdType, wrappedSnapshot.wdType, wrappedSnapshot.wdName, wrappedSnapshot.wdLabel, FBBoolToString(wrappedSnapshot.wdEnabled), FBBoolToString(wrappedSnapshot.wdVisible), FBBoolToString(wrappedSnapshot.wdAccessible), [wrappedSnapshot.wdRect[@"x"] stringValue], [wrappedSnapshot.wdRect[@"y"] stringValue], [wrappedSnapshot.wdRect[@"width"] stringValue], [wrappedSnapshot.wdRect[@"height"] stringValue], wrappedSnapshot.wdIndex, wrappedSnapshot.wdTraits, pid, [self.testedApplication bundleID]]; + XCTAssertEqualObjects(xmlStr, expectedXml); +} + - (void)testSingleDescendantXMLRepresentation { id snapshot = self.destinationSnapshot;